else
return TRUE;
ME_CommitUndo(editor);
+ ME_UpdateSelectionLinkAttribute(editor);
ME_UpdateRepaint(editor);
ME_SendRequestResize(editor, FALSE);
return TRUE;
TRACE("WM_SETTEXT - NULL\n");
if (editor->AutoURLDetect_bEnable)
{
- int cMin = 0, cMax = -1;
- while (ME_FindNextURLCandidate(editor, cMin, cMax, &cMin, &cMax))
- {
- if (ME_IsCandidateAnURL(editor, cMin, cMax)) {
- CHARFORMAT2W link;
- link.cbSize = sizeof(link);
- link.dwMask = CFM_LINK;
- link.dwEffects = CFE_LINK;
- ME_SetCharFormat(editor, cMin, cMax - cMin, &link);
- }
- cMin = cMax;
- cMax = -1;
- }
+ ME_UpdateLinkAttribute(editor, 0, -1);
}
ME_SetSelection(editor, 0, 0);
editor->nModifyStep = 0;
CHAR charA = wParam;
MultiByteToWideChar(CP_ACP, 0, &charA, 1, &wstr, 1);
}
- if (editor->AutoURLDetect_bEnable)
- ME_AutoURLDetect(editor, wstr);
-
+
switch (wstr)
{
case 1: /* Ctrl-A */
ME_ReleaseStyle(style);
ME_CommitUndo(editor);
}
+
+ if (editor->AutoURLDetect_bEnable) ME_UpdateSelectionLinkAttribute(editor);
+
ME_UpdateRepaint(editor);
}
return 0;
if (bufferW != NULL) heap_free(bufferW);
return FALSE;
}
+
+/**
+ * This proc walks through the indicated selection and evaluates whether each
+ * section identified by ME_FindNextURLCandidate and in-between sections have
+ * their proper CFE_LINK attributes set or unset. If the CFE_LINK attribute is
+ * not what it is supposed to be, this proc sets or unsets it as appropriate.
+ *
+ * Returns TRUE if at least one section was modified.
+ */
+BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_max)
+{
+ BOOL modified = FALSE;
+ int cMin, cMax;
+
+ if (sel_max == -1) sel_max = ME_GetTextLength(editor);
+ do
+ {
+ int beforeURL[2];
+ int inURL[2];
+ CHARFORMAT2W link;
+
+ if (ME_FindNextURLCandidate(editor, sel_min, sel_max, &cMin, &cMax))
+ {
+ /* Section before candidate is not an URL */
+ beforeURL[0] = sel_min;
+ beforeURL[1] = cMin;
+
+ if (ME_IsCandidateAnURL(editor, cMin, cMax))
+ {
+ inURL[0] = cMin; inURL[1] = cMax;
+ }
+ else
+ {
+ beforeURL[1] = cMax;
+ inURL[0] = inURL[1] = -1;
+ }
+ sel_min = cMax;
+ }
+ else
+ {
+ /* No more candidates until end of selection */
+ beforeURL[0] = sel_min;
+ beforeURL[1] = sel_max;
+ inURL[0] = inURL[1] = -1;
+ sel_min = sel_max;
+ }
+
+ if (beforeURL[0] < beforeURL[1])
+ {
+ /* CFE_LINK effect should be consistently unset */
+ link.cbSize = sizeof(link);
+ ME_GetCharFormat(editor, beforeURL[0], beforeURL[1], &link);
+ /* FIXME: Workaround for what looks like a bug - ME_GetCharFormat does not
+ clear the CFM_LINK flag when selection spans text without CFE_LINK,
+ followed by CFE_LINK set. This needs a test for EM_GETCHARFORMAT */
+#if 0
+ if (!(link.dwMask & CFM_LINK) || (link.dwEffects & CFE_LINK))
+ {
+#endif
+ /* CFE_LINK must be unset from this range */
+ memset(&link, 0, sizeof(CHARFORMAT2W));
+ link.cbSize = sizeof(link);
+ link.dwMask = CFM_LINK;
+ link.dwEffects = 0;
+ ME_SetCharFormat(editor, beforeURL[0], beforeURL[1] - beforeURL[0], &link);
+ modified = TRUE;
+#if 0
+ }
+#endif
+ }
+ if (inURL[0] < inURL[1])
+ {
+ /* CFE_LINK effect should be consistently set */
+ link.cbSize = sizeof(link);
+ ME_GetCharFormat(editor, inURL[0], inURL[1], &link);
+ if (!(link.dwMask & CFM_LINK) || !(link.dwEffects & CFE_LINK))
+ {
+ /* CFE_LINK must be set on this range */
+ memset(&link, 0, sizeof(CHARFORMAT2W));
+ link.cbSize = sizeof(link);
+ link.dwMask = CFM_LINK;
+ link.dwEffects = CFE_LINK;
+ ME_SetCharFormat(editor, inURL[0], inURL[1] - inURL[0], &link);
+ modified = TRUE;
+ }
+ }
+ } while (sel_min < sel_max);
+ return modified;
+}
+
+void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor)
+{
+ ME_DisplayItem * startPara, * endPara;
+ ME_DisplayItem * item;
+ int dummy;
+ int from, to;
+
+ ME_GetSelection(editor, &from, &to);
+ if (from > to) from ^= to, to ^=from, from ^= to;
+ startPara = NULL; endPara = NULL;
+
+ /* Find paragraph previous to the one that contains start cursor */
+ item = ME_FindItemAtOffset(editor, diRun, from, &dummy);
+ if (item) {
+ startPara = ME_FindItemBack(item, diParagraph);
+ item = ME_FindItemBack(startPara, diParagraph);
+ if (item) startPara = item;
+ }
+
+ /* Find paragraph that contains end cursor */
+ item = ME_FindItemAtOffset(editor, diRun, to, &dummy);
+ if (item) {
+ endPara = ME_FindItemFwd(item, diParagraph);
+ }
+
+ if (startPara && endPara) {
+ ME_UpdateLinkAttribute(editor,
+ startPara->member.para.nCharOfs,
+ endPara->member.para.nCharOfs);
+ } else if (startPara) {
+ ME_UpdateLinkAttribute(editor,
+ startPara->member.para.nCharOfs,
+ -1);
+ }
+}
"This is some text with X\\ on it",
};
char buffer[1024];
+ MSG msg;
parent = new_static_wnd(NULL);
hwndRichEdit = new_richedit(parent);
hwndRichEdit = NULL;
}
+#define INSERT_CR \
+ do { \
+ keybd_event('\r', 0x1c, 0, 0); \
+ keybd_event('\r', 0x1c, KEYEVENTF_KEYUP, 0); \
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
+ TranslateMessage(&msg); \
+ DispatchMessage(&msg); \
+ } \
+ } while (0)
+
+#define INSERT_BS \
+ do { \
+ keybd_event(0x08, 0x0e, 0, 0); \
+ keybd_event(0x08, 0x0e, KEYEVENTF_KEYUP, 0); \
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
+ TranslateMessage(&msg); \
+ DispatchMessage(&msg); \
+ } \
+ } while (0)
+
+ /* Test detection of URLs within normal text - WM_CHAR case. */
+ for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
+ hwndRichEdit = new_richedit(parent);
+
+ for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) {
+ char * at_pos;
+ int at_offset;
+ int end_offset;
+ int u, v;
+
+ at_pos = strchr(templates_delim[j], 'X');
+ at_offset = at_pos - templates_delim[j];
+ end_offset = at_offset + strlen(urls[i].text);
+
+ SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
+ SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+ for (u = 0; templates_delim[j][u]; u++) {
+ if (templates_delim[j][u] == '\r') {
+ INSERT_CR;
+ } else if (templates_delim[j][u] != 'X') {
+ SendMessage(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1);
+ } else {
+ for (v = 0; urls[i].text[v]; v++) {
+ SendMessage(hwndRichEdit, WM_CHAR, urls[i].text[v], 1);
+ }
+ }
+ }
+ SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
+ trace("Using template: %s\n", templates_delim[j]);
+
+ /* This assumes no templates start with the URL itself, and that they
+ have at least two characters before the URL text */
+ ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
+
+ if (urls[i].is_url)
+ {
+ ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
+ "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
+ ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
+ "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
+ }
+ else
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
+ }
+ if (buffer[end_offset] != '\0')
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
+ if (buffer[end_offset +1] != '\0')
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
+ }
+ }
+
+ /* The following will insert a paragraph break after the first character
+ of the URL candidate, thus breaking the URL. It is expected that the
+ CFE_LINK attribute should break across both pieces of the URL */
+ SendMessage(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1);
+ INSERT_CR;
+ SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
+
+ ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
+
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
+ /* end_offset moved because of paragraph break */
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer);
+ if (buffer[end_offset+1] != '\0')
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer);
+ if (buffer[end_offset +2] != '\0')
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
+ }
+ }
+
+ /* The following will remove the just-inserted paragraph break, thus
+ restoring the URL */
+ SendMessage(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2);
+ INSERT_BS;
+ SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
+
+ ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
+
+ if (urls[i].is_url)
+ {
+ ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
+ "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
+ ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
+ "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
+ }
+ else
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
+ }
+ if (buffer[end_offset] != '\0')
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
+ if (buffer[end_offset +1] != '\0')
+ {
+ ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
+ "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
+ }
+ }
+ }
+ DestroyWindow(hwndRichEdit);
+ hwndRichEdit = NULL;
+ }
+
DestroyWindow(parent);
}