- 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:
parent
8971f06225
commit
898068f3ce
|
@ -274,25 +274,151 @@ static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM
|
|||
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 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
|||
parser.hwndEdit = editor->hWnd;
|
||||
WriterInit(&parser);
|
||||
RTFInit(&parser);
|
||||
RTFSetReadHook(&parser, ME_RTFReadHook);
|
||||
BeginFile(&parser);
|
||||
|
||||
/* do the parsing */
|
||||
|
@ -311,6 +438,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
|||
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 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
|||
{
|
||||
/* 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;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rtf.h"
|
||||
|
||||
|
@ -3590,6 +3591,16 @@ BeginFile (RTF_Info *info )
|
|||
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 @@ BeginFile (RTF_Info *info )
|
|||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static void
|
||||
TextClass (RTF_Info *info)
|
||||
TextClass_orig (RTF_Info *info)
|
||||
{
|
||||
char buf[rtfBufSiz];
|
||||
|
||||
|
@ -3612,13 +3626,15 @@ TextClass (RTF_Info *info)
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
|
@ -3763,10 +3779,16 @@ void PutLitChar (RTF_Info *info, int 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 )
|
||||
{
|
||||
info->OutputBuffer[info->dwOutputCount] = 0;
|
||||
SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer );
|
||||
RTFOutputANSIString(info, info->OutputBuffer, info->dwOutputCount);
|
||||
info->dwOutputCount = 0;
|
||||
}
|
||||
|
||||
|
@ -3778,7 +3800,7 @@ static void PutLitStr (RTF_Info *info, char *str )
|
|||
RTFFlushOutputBuffer( info );
|
||||
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 );
|
||||
|
|
|
@ -302,8 +302,10 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
|
|||
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);
|
||||
|
|
|
@ -54,7 +54,7 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
|
|||
{
|
||||
ME_DisplayItem *p, *pNext;
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
|
||||
TRACE("Emptying undo stack\n");
|
||||
|
||||
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) {
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
|
||||
assert(editor->nUndoMode == umAddToUndo);
|
||||
|
||||
/* 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;
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
|
||||
|
||||
switch(pItem->type)
|
||||
|
@ -202,6 +211,8 @@ void ME_Undo(ME_TextEditor *editor) {
|
|||
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 @@ void ME_Redo(ME_TextEditor *editor) {
|
|||
|
||||
assert(nMode == umAddToUndo || nMode == umIgnore);
|
||||
|
||||
if (editor->nUndoMode == umIgnore)
|
||||
return;
|
||||
/* no redo items ? */
|
||||
if (!editor->pRedoStack)
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue