- 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.
This commit is contained in:
Krzysztof Foltman 2005-03-11 10:24:56 +00:00 committed by Alexandre Julliard
parent 8971f06225
commit 898068f3ce
5 changed files with 189 additions and 14 deletions

View File

@ -274,25 +274,151 @@ static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM
return 0; 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) static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
{ {
RTF_Info parser; RTF_Info parser;
ME_Style *style; ME_Style *style;
int from, to, to2, nUndoMode;
ME_UndoItem *pUI;
TRACE("%p %p\n", stream, editor->hWnd); TRACE("%p %p\n", stream, editor->hWnd);
ME_GetSelection(editor, &from, &to);
if (format & SFF_SELECTION) { if (format & SFF_SELECTION) {
style = ME_GetSelectionInsertStyle(editor); style = ME_GetSelectionInsertStyle(editor);
SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
ME_InternalDeleteText(editor, from, to-from);
} }
else { else {
style = editor->pBuffer->pDefaultStyle; style = editor->pBuffer->pDefaultStyle;
ME_AddRefStyle(style); ME_AddRefStyle(style);
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
SetWindowTextA(editor->hWnd, ""); ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
from = to = 0;
ME_ClearTempStyle(editor); ME_ClearTempStyle(editor);
} }
nUndoMode = editor->nUndoMode;
editor->nUndoMode = umIgnore;
if (format & SF_RTF) { if (format & SF_RTF) {
/* setup the RTF parser */ /* setup the RTF parser */
memset(&parser, 0, sizeof parser); memset(&parser, 0, sizeof parser);
@ -301,6 +427,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
parser.hwndEdit = editor->hWnd; parser.hwndEdit = editor->hWnd;
WriterInit(&parser); WriterInit(&parser);
RTFInit(&parser); RTFInit(&parser);
RTFSetReadHook(&parser, ME_RTFReadHook);
BeginFile(&parser); BeginFile(&parser);
/* do the parsing */ /* do the parsing */
@ -311,6 +438,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
ME_StreamInText(editor, format, stream, style); ME_StreamInText(editor, format, stream, style);
else else
ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n"); ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
ME_GetSelection(editor, &to, &to2);
/* put the cursor at the top */ /* put the cursor at the top */
if (!(format & SFF_SELECTION)) if (!(format & SFF_SELECTION))
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0); SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
@ -318,6 +446,16 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
{ {
/* FIXME where to put cursor now ? */ /* 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); ME_ReleaseStyle(style);
return 0; return 0;

View File

@ -40,6 +40,7 @@
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
#include "rtf.h" #include "rtf.h"
@ -3590,6 +3591,16 @@ BeginFile (RTF_Info *info )
return (1); 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 * Write out a character. rtfMajor contains the input character, rtfMinor
@ -3597,10 +3608,13 @@ BeginFile (RTF_Info *info )
* *
* If the input character isn't in the charset map, try to print some * If the input character isn't in the charset map, try to print some
* representation of it. * 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
*/ */
#if 0
static void static void
TextClass (RTF_Info *info) TextClass_orig (RTF_Info *info)
{ {
char buf[rtfBufSiz]; char buf[rtfBufSiz];
@ -3612,13 +3626,15 @@ TextClass (RTF_Info *info)
PutStdChar (info, info->rtfMinor); PutStdChar (info, info->rtfMinor);
else else
{ {
if (info->rtfMajor < 128) /* in ASCII range */ if (info->rtfMajor < 256) /* in ASCII range */
sprintf (buf, "[[%c]]", info->rtfMajor); PutLitChar(info, info->rtfMajor);
else else {
sprintf (buf, "[[\\'%02x]]", info->rtfMajor); sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
PutLitStr (info, buf); PutLitStr (info, buf);
}
} }
} }
#endif
static void static void
@ -3763,10 +3779,16 @@ void PutLitChar (RTF_Info *info, int c)
info->OutputBuffer[info->dwOutputCount++] = c; 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 ) void RTFFlushOutputBuffer( RTF_Info *info )
{ {
info->OutputBuffer[info->dwOutputCount] = 0; info->OutputBuffer[info->dwOutputCount] = 0;
SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer ); RTFOutputANSIString(info, info->OutputBuffer, info->dwOutputCount);
info->dwOutputCount = 0; info->dwOutputCount = 0;
} }
@ -3778,7 +3800,7 @@ static void PutLitStr (RTF_Info *info, char *str )
RTFFlushOutputBuffer( info ); 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; return;
} }
strcpy( &info->OutputBuffer[info->dwOutputCount], str ); strcpy( &info->OutputBuffer[info->dwOutputCount], str );

View File

@ -302,8 +302,10 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
assert(pItem->type == diRun || pItem->type == diUndoInsertRun); assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL); pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
pUI->nStart = nCharOfs; if (pUI) {
pUI->nLen = pItem->member.run.strText->nLen; pUI->nStart = nCharOfs;
pUI->nLen = pItem->member.run.strText->nLen;
}
ME_CursorFromCharOfs(editor, nCharOfs, &tmp); ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
if (tmp.nOffset) { if (tmp.nOffset) {
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);

View File

@ -54,7 +54,7 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
if (f->dwMask & CFM_FACE) if (f->dwMask & CFM_FACE)
MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName)); MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
/* copy the rest of the 2A structure to 2W */ /* 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); to->cbSize = sizeof(CHARFORMAT2W);
return to; return to;
} }

View File

@ -26,6 +26,9 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
{ {
ME_DisplayItem *p, *pNext; ME_DisplayItem *p, *pNext;
if (editor->nUndoMode == umIgnore)
return;
TRACE("Emptying undo stack\n"); TRACE("Emptying undo stack\n");
p = editor->pUndoStack; p = editor->pUndoStack;
@ -121,6 +124,10 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte
} }
void ME_CommitUndo(ME_TextEditor *editor) { void ME_CommitUndo(ME_TextEditor *editor) {
if (editor->nUndoMode == umIgnore)
return;
assert(editor->nUndoMode == umAddToUndo); assert(editor->nUndoMode == umAddToUndo);
/* no transactions, no need to commit */ /* no transactions, no need to commit */
@ -140,6 +147,8 @@ void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
{ {
ME_UndoItem *pUItem = (ME_UndoItem *)pItem; ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
if (editor->nUndoMode == umIgnore)
return;
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type)); TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
switch(pItem->type) switch(pItem->type)
@ -202,6 +211,8 @@ void ME_Undo(ME_TextEditor *editor) {
ME_DisplayItem *p; ME_DisplayItem *p;
ME_UndoMode nMode = editor->nUndoMode; ME_UndoMode nMode = editor->nUndoMode;
if (editor->nUndoMode == umIgnore)
return;
assert(nMode == umAddToUndo || nMode == umIgnore); assert(nMode == umAddToUndo || nMode == umIgnore);
/* no undo items ? */ /* no undo items ? */
@ -235,6 +246,8 @@ void ME_Redo(ME_TextEditor *editor) {
assert(nMode == umAddToUndo || nMode == umIgnore); assert(nMode == umAddToUndo || nMode == umIgnore);
if (editor->nUndoMode == umIgnore)
return;
/* no redo items ? */ /* no redo items ? */
if (!editor->pRedoStack) if (!editor->pRedoStack)
return; return;