RICHEDIT: better RTF import+bugfiles
Krzysztof Foltman
kfoltman at portal.onet.pl
Thu Mar 10 14:27:54 CST 2005
ChangeLog:
* EM_STREAMIN can now deal with undo in a reasonable manner (no
multiple undo actions in one EM_STREAMIN)
* Related changes to undo code (umIgnore mode is now handled correctly)
* Numerous improvements in the RTF reader: it reads some character
attributes now (you will have proper small print in license agreements now)
* Fixed a memory overwrite bug in conversion from CHARFORMAT2A to
CHARFORMAT2W
Is there any important reason to keep the reader.c use hard tabs instead
of spaces ? It's completely different than the rest of the editor this
way, and it isn't really comfortable to have different TAB settings for
different files of the same component.
Krzysztof
-------------- next part --------------
Index: editor.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/editor.c,v
retrieving revision 1.9
diff -u -r1.9 editor.c
--- editor.c 9 Mar 2005 18:43:18 -0000 1.9
+++ editor.c 10 Mar 2005 20:23:15 -0000
@@ -274,25 +274,151 @@
return 0;
}
+void ME_RTFCharAttrHook(RTF_Info *info)
+{
+ CHARFORMAT2A fmt;
+ fmt.cbSize = sizeof(fmt);
+ fmt.dwMask = 0;
+
+ switch(info->rtfMinor)
+ {
+ case rtfBold:
+ fmt.dwMask = CFM_BOLD;
+ fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+ break;
+ case rtfItalic:
+ fmt.dwMask = CFM_ITALIC;
+ fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+ break;
+ case rtfUnderline:
+ fmt.dwMask = CFM_UNDERLINE;
+ fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+ break;
+ case rtfStrikeThru:
+ fmt.dwMask = CFM_STRIKEOUT;
+ fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+ break;
+ case rtfBackColor:
+ fmt.dwMask = CFM_BACKCOLOR;
+ fmt.dwEffects = 0;
+ if (info->rtfParam == 0)
+ fmt.dwEffects = CFE_AUTOBACKCOLOR;
+ else if (info->rtfParam != rtfNoParam)
+ {
+ RTFColor *c = RTFGetColor(info, info->rtfParam);
+ fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
+ }
+ break;
+ case rtfForeColor:
+ fmt.dwMask = CFM_COLOR;
+ fmt.dwEffects = 0;
+ if (info->rtfParam == 0)
+ fmt.dwEffects = CFE_AUTOCOLOR;
+ else if (info->rtfParam != rtfNoParam)
+ {
+ RTFColor *c = RTFGetColor(info, info->rtfParam);
+ fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
+ }
+ break;
+ case rtfFontNum:
+ if (info->rtfParam != rtfNoParam)
+ {
+ RTFFont *f = RTFGetFont(info, info->rtfParam);
+ if (f)
+ {
+ strncpy(fmt.szFaceName, f->rtfFName, sizeof(fmt.szFaceName)-1);
+ fmt.szFaceName[sizeof(fmt.szFaceName)-1] = '\0';
+ fmt.dwMask = CFM_FACE;
+ }
+ }
+ break;
+ case rtfFontSize:
+ fmt.dwMask = CFM_SIZE;
+ if (info->rtfParam != rtfNoParam)
+ fmt.yHeight = info->rtfParam*10;
+ break;
+ }
+ if (fmt.dwMask) {
+ RTFFlushOutputBuffer(info);
+ SendMessageW(info->hwndEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&fmt);
+ }
+}
+
+void ME_RTFParAttrHook(RTF_Info *info)
+{
+ PARAFORMAT2 fmt;
+ fmt.cbSize = sizeof(fmt);
+ fmt.dwMask = 0;
+
+ switch(info->rtfMinor)
+ {
+ case rtfParDef: /* I'm not 100% sure what does it do, but I guess it restores default paragraph attributes */
+ fmt.dwMask = PFM_ALIGNMENT;
+ fmt.wAlignment = PFA_LEFT;
+ break;
+ case rtfQuadLeft:
+ case rtfQuadJust:
+ fmt.dwMask = PFM_ALIGNMENT;
+ fmt.wAlignment = PFA_LEFT;
+ break;
+ case rtfQuadRight:
+ fmt.dwMask = PFM_ALIGNMENT;
+ fmt.wAlignment = PFA_RIGHT;
+ break;
+ case rtfQuadCenter:
+ fmt.dwMask = PFM_ALIGNMENT;
+ fmt.wAlignment = PFA_CENTER;
+ break;
+ }
+ if (fmt.dwMask) {
+ RTFFlushOutputBuffer(info);
+ SendMessageW(info->hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt);
+ }
+}
+
+void ME_RTFReadHook(RTF_Info *info) {
+ switch(info->rtfClass)
+ {
+ case rtfControl:
+ switch(info->rtfMajor)
+ {
+ case rtfCharAttr:
+ ME_RTFCharAttrHook(info);
+ break;
+ case rtfParAttr:
+ ME_RTFParAttrHook(info);
+ break;
+ }
+ break;
+ }
+}
+
static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
{
RTF_Info parser;
ME_Style *style;
+ int from, to, to2, nUndoMode;
+ ME_UndoItem *pUI;
TRACE("%p %p\n", stream, editor->hWnd);
+ ME_GetSelection(editor, &from, &to);
if (format & SFF_SELECTION) {
style = ME_GetSelectionInsertStyle(editor);
- SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
+
+ ME_InternalDeleteText(editor, from, to-from);
}
else {
style = editor->pBuffer->pDefaultStyle;
ME_AddRefStyle(style);
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
- SetWindowTextA(editor->hWnd, "");
+ ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
+ from = to = 0;
ME_ClearTempStyle(editor);
}
-
+
+ nUndoMode = editor->nUndoMode;
+ editor->nUndoMode = umIgnore;
if (format & SF_RTF) {
/* setup the RTF parser */
memset(&parser, 0, sizeof parser);
@@ -301,6 +427,7 @@
parser.hwndEdit = editor->hWnd;
WriterInit(&parser);
RTFInit(&parser);
+ RTFSetReadHook(&parser, ME_RTFReadHook);
BeginFile(&parser);
/* do the parsing */
@@ -311,6 +438,7 @@
ME_StreamInText(editor, format, stream, style);
else
ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
+ ME_GetSelection(editor, &to, &to2);
/* put the cursor at the top */
if (!(format & SFF_SELECTION))
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
@@ -318,6 +446,16 @@
{
/* FIXME where to put cursor now ? */
}
+
+ editor->nUndoMode = nUndoMode;
+ pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
+ FIXME("from %d to %d\n", from, to);
+ if (pUI && from < to)
+ {
+ pUI->nStart = from;
+ pUI->nLen = to-from;
+ }
+ ME_CommitUndo(editor);
ME_ReleaseStyle(style);
return 0;
Index: reader.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/reader.c,v
retrieving revision 1.2
diff -u -r1.2 reader.c
--- reader.c 8 Mar 2005 19:01:25 -0000 1.2
+++ reader.c 10 Mar 2005 20:23:15 -0000
@@ -40,6 +40,7 @@
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <assert.h>
#include "rtf.h"
@@ -1297,16 +1298,16 @@
TRACE("\n");
- if (info->rtfFormat == SF_TEXT) {
- info->rtfMajor = GetChar (info);
- info->rtfMinor = rtfSC_nothing;
- info->rtfParam = rtfNoParam;
- info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
- if (info->rtfMajor == EOF)
- info->rtfClass = rtfEOF;
- else
- info->rtfClass = rtfText;
- return;
+ if (info->rtfFormat == SF_TEXT) {
+ info->rtfMajor = GetChar (info);
+ info->rtfMinor = rtfSC_nothing;
+ info->rtfParam = rtfNoParam;
+ info->rtfTextBuf[info->rtfTextLen = 0] = '\0';
+ if (info->rtfMajor == EOF)
+ info->rtfClass = rtfEOF;
+ else
+ info->rtfClass = rtfText;
+ return;
}
/* first check for pushed token from RTFUngetToken() */
@@ -1989,8 +1990,8 @@
else if (info->rtfClass == rtfText) /* font name */
{
bp = buf;
- while (info->rtfClass == rtfText
- && !RTFCheckCM (info, rtfText, ';'))
+ while (info->rtfClass == rtfText
+ && !RTFCheckCM (info, rtfText, ';'))
{
*bp++ = info->rtfMajor;
(void) RTFGetToken (info);
@@ -3590,6 +3591,16 @@
return (1);
}
+/*
+ * Write out a character. Seems to work for the default ANSI codepage,
+ * contrary to TextClass_orig.
+ */
+
+static void
+TextClass (RTF_Info *info)
+{
+ PutLitChar (info, info->rtfMajor);
+}
/*
* Write out a character. rtfMajor contains the input character, rtfMinor
@@ -3597,10 +3608,13 @@
*
* If the input character isn't in the charset map, try to print some
* representation of it.
+ *
+ * I'm not removing it, because it may be helpful if someone else decides
+ * to rewrite the character handler in a i18n-friendly way
*/
static void
-TextClass (RTF_Info *info)
+TextClass_orig (RTF_Info *info)
{
char buf[rtfBufSiz];
@@ -3612,11 +3626,12 @@
PutStdChar (info, info->rtfMinor);
else
{
- if (info->rtfMajor < 128) /* in ASCII range */
- sprintf (buf, "[[%c]]", info->rtfMajor);
- else
+ if (info->rtfMajor < 256) /* in ASCII range */
+ PutLitChar(info, info->rtfMajor);
+ else {
sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
- PutLitStr (info, buf);
+ PutLitStr (info, buf);
+ }
}
}
@@ -3763,10 +3778,16 @@
info->OutputBuffer[info->dwOutputCount++] = c;
}
+void RTFOutputANSIString( RTF_Info *info, char *str, int len )
+{
+ assert(str[len] == '\0');
+ if (len) SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str);
+}
+
void RTFFlushOutputBuffer( RTF_Info *info )
{
info->OutputBuffer[info->dwOutputCount] = 0;
- SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer );
+ RTFOutputANSIString(info, info->OutputBuffer, info->dwOutputCount);
info->dwOutputCount = 0;
}
@@ -3776,9 +3797,9 @@
if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer )
RTFFlushOutputBuffer( info );
- if( ( len + 1 ) >= sizeof info->OutputBuffer )
+ if( ( len + 1 ) >= sizeof info->OutputBuffer )
{
- SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str );
+ RTFOutputANSIString(info, str, len);
return;
}
strcpy( &info->OutputBuffer[info->dwOutputCount], str );
Index: run.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/run.c,v
retrieving revision 1.4
diff -u -r1.4 run.c
--- run.c 9 Mar 2005 18:43:18 -0000 1.4
+++ run.c 10 Mar 2005 20:23:15 -0000
@@ -302,8 +302,10 @@
assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
- pUI->nStart = nCharOfs;
- pUI->nLen = pItem->member.run.strText->nLen;
+ if (pUI) {
+ pUI->nStart = nCharOfs;
+ pUI->nLen = pItem->member.run.strText->nLen;
+ }
ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
if (tmp.nOffset) {
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
Index: style.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/style.c,v
retrieving revision 1.2
diff -u -r1.2 style.c
--- style.c 8 Mar 2005 16:26:23 -0000 1.2
+++ style.c 10 Mar 2005 20:23:15 -0000
@@ -54,7 +54,7 @@
if (f->dwMask & CFM_FACE)
MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
/* copy the rest of the 2A structure to 2W */
- CopyMemory(1+((CHARFORMATW *)from), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
+ CopyMemory(1+((CHARFORMATW *)to), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
to->cbSize = sizeof(CHARFORMAT2W);
return to;
}
Index: undo.c
===================================================================
RCS file: /home/wine/wine/dlls/riched20/undo.c,v
retrieving revision 1.1
diff -u -r1.1 undo.c
--- undo.c 5 Mar 2005 11:19:14 -0000 1.1
+++ undo.c 10 Mar 2005 20:23:15 -0000
@@ -26,6 +26,9 @@
{
ME_DisplayItem *p, *pNext;
+ if (editor->nUndoMode == umIgnore)
+ return;
+
TRACE("Emptying undo stack\n");
p = editor->pUndoStack;
@@ -121,6 +124,10 @@
}
void ME_CommitUndo(ME_TextEditor *editor) {
+
+ if (editor->nUndoMode == umIgnore)
+ return;
+
assert(editor->nUndoMode == umAddToUndo);
/* no transactions, no need to commit */
@@ -140,6 +147,8 @@
{
ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
+ if (editor->nUndoMode == umIgnore)
+ return;
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
switch(pItem->type)
@@ -202,6 +211,8 @@
ME_DisplayItem *p;
ME_UndoMode nMode = editor->nUndoMode;
+ if (editor->nUndoMode == umIgnore)
+ return;
assert(nMode == umAddToUndo || nMode == umIgnore);
/* no undo items ? */
@@ -235,6 +246,8 @@
assert(nMode == umAddToUndo || nMode == umIgnore);
+ if (editor->nUndoMode == umIgnore)
+ return;
/* no redo items ? */
if (!editor->pRedoStack)
return;
More information about the wine-patches
mailing list