diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 28c779a..5ebd0ee 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -482,6 +482,7 @@ static void ME_RTFParAttrHook(RTF_Info *info) * table anymore. */ info->tableDef->tableRowStart = NULL; + info->canInheritInTbl = FALSE; } } } else { /* v1.0 - v3.0 */ @@ -489,13 +490,42 @@ static void ME_RTFParAttrHook(RTF_Info *info) fmt.wEffects &= ~PFE_TABLE; } break; + case rtfNestLevel: + if (!info->editor->bEmulateVersion10) /* v4.1 */ + { + while (info->rtfParam > info->nestingLevel) { + RTFTable *tableDef = ALLOC_OBJ(RTFTable); + ZeroMemory(tableDef, sizeof(RTFTable)); + tableDef->parent = info->tableDef; + info->tableDef = tableDef; + + RTFFlushOutputBuffer(info); + if (tableDef->tableRowStart && + tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) + { + ME_DisplayItem *para = tableDef->tableRowStart; + para = para->member.para.next_para; + para = ME_InsertTableRowStartAtParagraph(info->editor, para); + tableDef->tableRowStart = para; + } else { + ME_Cursor cursor; + WCHAR endl = '\r'; + cursor = info->editor->pCursors[0]; + if (cursor.nOffset || cursor.pRun->member.run.nCharOfs) + ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style); + tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor); + } + + info->nestingLevel++; + } + info->canInheritInTbl = FALSE; + } + break; case rtfInTable: { - ME_Cursor cursor; if (!info->editor->bEmulateVersion10) /* v4.1 */ { - if (!info->tableDef || !info->tableDef->tableRowStart || - info->tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) + if (info->nestingLevel < 1) { RTFTable *tableDef; if (!info->tableDef) @@ -505,19 +535,23 @@ static void ME_RTFParAttrHook(RTF_Info *info) } tableDef = info->tableDef; RTFFlushOutputBuffer(info); - if (!tableDef->tableRowStart) + if (tableDef->tableRowStart && + tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) { + ME_DisplayItem *para = tableDef->tableRowStart; + para = para->member.para.next_para; + para = ME_InsertTableRowStartAtParagraph(info->editor, para); + tableDef->tableRowStart = para; + } else { + ME_Cursor cursor; WCHAR endl = '\r'; cursor = info->editor->pCursors[0]; if (cursor.nOffset || cursor.pRun->member.run.nCharOfs) ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style); + tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor); } - - /* FIXME: Remove the following condition once nested tables are supported */ - if (ME_GetParagraph(info->editor->pCursors[0].pRun)->member.para.pCell) - break; - - tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor); + info->nestingLevel = 1; + info->canInheritInTbl = TRUE; } return; } else { /* v1.0 - v3.0 */ @@ -763,6 +797,10 @@ static void ME_RTFSpecialCharHook(RTF_Info *info) RTFTable *tableDef = info->tableDef; switch (info->rtfMinor) { + case rtfNestCell: + if (info->editor->bEmulateVersion10) /* v1.0 - v3.0 */ + break; + /* else fall through since v4.1 treats rtfNestCell and rtfCell the same */ case rtfCell: if (!tableDef) break; @@ -770,12 +808,14 @@ static void ME_RTFSpecialCharHook(RTF_Info *info) if (!info->editor->bEmulateVersion10) { /* v4.1 */ if (tableDef->tableRowStart) { - if (tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) + if (!info->nestingLevel && + tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) { ME_DisplayItem *para = tableDef->tableRowStart; para = para->member.para.next_para; para = ME_InsertTableRowStartAtParagraph(info->editor, para); tableDef->tableRowStart = para; + info->nestingLevel = 1; } ME_InsertTableCellFromCursor(info->editor); } @@ -791,6 +831,10 @@ static void ME_RTFSpecialCharHook(RTF_Info *info) } } break; + case rtfNestRow: + if (info->editor->bEmulateVersion10) /* v1.0 - v3.0 */ + break; + /* else fall through since v4.1 treats rtfNestRow and rtfRow the same */ case rtfRow: { ME_DisplayItem *para, *cell, *run; @@ -802,12 +846,14 @@ static void ME_RTFSpecialCharHook(RTF_Info *info) if (!info->editor->bEmulateVersion10) { /* v4.1 */ if (!tableDef->tableRowStart) break; - if (tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) + if (!info->nestingLevel && + tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) { para = tableDef->tableRowStart; para = para->member.para.next_para; para = ME_InsertTableRowStartAtParagraph(info->editor, para); tableDef->tableRowStart = para; + info->nestingLevel++; } para = tableDef->tableRowStart; cell = ME_FindItemFwd(para, diCell); @@ -855,7 +901,23 @@ static void ME_RTFSpecialCharHook(RTF_Info *info) ME_InternalDeleteText(info->editor, nOfs, nChars, TRUE); } - tableDef->tableRowStart = ME_InsertTableRowEndFromCursor(info->editor); + para = ME_InsertTableRowEndFromCursor(info->editor); + info->nestingLevel--; + if (!info->nestingLevel) + { + if (info->canInheritInTbl) { + tableDef->tableRowStart = para; + } else { + while (info->tableDef) { + tableDef = info->tableDef; + info->tableDef = tableDef->parent; + heap_free(tableDef); + } + } + } else { + info->tableDef = tableDef->parent; + heap_free(tableDef); + } } else { /* v1.0 - v3.0 */ WCHAR endl = '\r'; ME_DisplayItem *para = ME_GetParagraph(info->editor->pCursors[0].pRun); @@ -1276,6 +1338,8 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre RTFSetReadHook(&parser, ME_RTFReadHook); RTFSetDestinationCallback(&parser, rtfPict, ME_RTFReadPictGroup); RTFSetDestinationCallback(&parser, rtfObject, ME_RTFReadObjectGroup); + if (!parser.editor->bEmulateVersion10) /* v4.1 */ + RTFSetDestinationCallback(&parser, rtfNoNestTables, RTFSkipGroup); BeginFile(&parser); /* do the parsing */ @@ -1295,8 +1359,15 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre * By doing it this way we will have the current paragraph format set * properly to reflect that is not in the complete table, and undo items * will be added for this change to the current paragraph format. */ - ME_RTFSpecialCharHook(&parser); - if (para->member.para.nFlags & MEPF_ROWEND) + if (parser.nestingLevel > 0) + { + while (parser.nestingLevel--) + ME_RTFSpecialCharHook(&parser); + } else if (parser.canInheritInTbl) { + ME_RTFSpecialCharHook(&parser); + } + if (parser.tableDef && parser.tableDef->tableRowStart && + para->member.para.nFlags & MEPF_ROWEND) { para = para->member.para.next_para; } diff --git a/dlls/riched20/reader.c b/dlls/riched20/reader.c index 82038f6..66b8ef7 100644 --- a/dlls/riched20/reader.c +++ b/dlls/riched20/reader.c @@ -169,10 +169,11 @@ RTFDestroy(RTF_Info *info) } RTFDestroyAttrs(info); heap_free(info->cpOutputBuffer); - if (info->tableDef) + while (info->tableDef) { - heap_free(info->tableDef); - info->tableDef = NULL; + RTFTable *tableDef = info->tableDef; + info->tableDef = tableDef->parent; + heap_free(tableDef); } } @@ -244,6 +245,8 @@ void RTFInit(RTF_Info *info) if (info->tableDef) ZeroMemory(info->tableDef, sizeof(info->tableDef)); info->tableDef = NULL; + info->nestingLevel = 0; + info->canInheritInTbl = FALSE; } /* @@ -1447,6 +1450,8 @@ static RTFKey rtfKey[] = /* is this valid? */ { rtfSpecialChar, rtfCurHeadPict, "chpict", 0 }, { rtfSpecialChar, rtfUnicode, "u", 0 }, + { rtfSpecialChar, rtfNestCell, "nestcell", 0 }, + { rtfSpecialChar, rtfNestRow, "nestrow", 0 }, /* * Character formatting attributes @@ -1610,6 +1615,7 @@ static RTFKey rtfKey[] = { rtfParAttr, rtfDarkDiagHatchBgPat, "bgdkdcross", 0 }, { rtfParAttr, rtfBgPatLineColor, "cfpat", 0 }, { rtfParAttr, rtfBgPatColor, "cbpat", 0 }, + { rtfParAttr, rtfNestLevel, "itap", 0 }, /* * Section formatting attributes @@ -1912,6 +1918,8 @@ static RTFKey rtfKey[] = { rtfDestination, rtfIndexRange, "rxe", 0 }, { rtfDestination, rtfTOC, "tc", 0 }, { rtfDestination, rtfNeXTGraphic, "NeXTGraphic", 0 }, + { rtfDestination, rtfNestTableProps, "nesttableprops", 0 }, + { rtfDestination, rtfNoNestTables, "nonesttables", 0 }, /* * Font families diff --git a/dlls/riched20/rtf.h b/dlls/riched20/rtf.h index 0425bf6..d18d259 100644 --- a/dlls/riched20/rtf.h +++ b/dlls/riched20/rtf.h @@ -182,7 +182,9 @@ # define rtfTOC 72 # define rtfNeXTGraphic 73 # define rtfGenerator 74 -# define rtfMaxDestination 75 /* highest dest + 1 */ +# define rtfNestTableProps 75 +# define rtfNoNestTables 76 +# define rtfMaxDestination 77 /* highest dest + 1 */ # define rtfFontFamily 4 # define rtfFFNil 0 @@ -261,6 +263,8 @@ # define rtfCurHeadPict 57 /* valid? */ /*# define rtfCurAnnot 58*/ /* apparently not used */ # define rtfUnicode 58 /* no better category*/ +# define rtfNestCell 59 +# define rtfNestRow 60 # define rtfStyleAttr 7 # define rtfAdditive 0 /* new in 1.10 */ @@ -551,6 +555,7 @@ # define rtfDarkDiagHatchBgPat 101 # define rtfBgPatLineColor 102 # define rtfBgPatColor 103 +# define rtfNestLevel 104 # define rtfCharAttr 12 # define rtfPlain 0 @@ -1020,7 +1025,10 @@ struct RTFTable /* tableRowStart may be the start row paragraph of the table row, * or it may store the end of the previous row if it may still be * continued, otherwise NULL is stored. */ - ME_DisplayItem *tableRowStart; + ME_DisplayItem *tableRowStart; + + /* Table definitions are stored as a stack to support nested tables. */ + RTFTable *parent; }; /* @@ -1129,6 +1137,8 @@ struct _RTF_Info { LPRICHEDITOLE lpRichEditOle; RTFTable *tableDef; + int nestingLevel; + BOOL canInheritInTbl; }; diff --git a/dlls/riched20/writer.c b/dlls/riched20/writer.c index 512dbce..742adda 100644 --- a/dlls/riched20/writer.c +++ b/dlls/riched20/writer.c @@ -334,6 +334,8 @@ ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream, if (!editor->bEmulateVersion10) { /* v4.1 */ if (pStream->nNestingLevel > 0) strcat(props, "\\intbl"); + if (pStream->nNestingLevel > 1) + sprintf(props + strlen(props), "\\itap%d", pStream->nNestingLevel); } else { /* v1.0 - 3.0 */ if (fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE) strcat(props, "\\intbl"); @@ -715,12 +717,23 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC if (!editor->bEmulateVersion10) { /* v4.1 */ if (p->member.para.nFlags & MEPF_ROWSTART) { pStream->nNestingLevel++; - if (!ME_StreamOutRTFTableProps(editor, pStream, p)) - return FALSE; + if (pStream->nNestingLevel == 1) { + if (!ME_StreamOutRTFTableProps(editor, pStream, p)) + return FALSE; + } } else if (p->member.para.nFlags & MEPF_ROWEND) { pStream->nNestingLevel--; - if (!ME_StreamOutPrint(pStream, "\\row \r\n")) - return FALSE; + if (pStream->nNestingLevel > 1) { + if (!ME_StreamOutPrint(pStream, "{\\*\\nesttableprops")) + return FALSE; + if (!ME_StreamOutRTFTableProps(editor, pStream, p)) + return FALSE; + if (!ME_StreamOutPrint(pStream, "\\nestrow}{\\nonesttables\\par}\r\n")) + return FALSE; + } else { + if (!ME_StreamOutPrint(pStream, "\\row \r\n")) + return FALSE; + } } else if (!ME_StreamOutRTFParaProps(editor, pStream, p)) { return FALSE; } @@ -757,8 +770,13 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC return FALSE; } } else if (p->member.run.nFlags & MERF_ENDCELL) { - if (!ME_StreamOutPrint(pStream, "\\cell ")) - return FALSE; + if (pStream->nNestingLevel > 1) { + if (!ME_StreamOutPrint(pStream, "\\nestcell ")) + return FALSE; + } else { + if (!ME_StreamOutPrint(pStream, "\\cell ")) + return FALSE; + } nChars--; } else if (p->member.run.nFlags & MERF_ENDPARA) { if (pPara->member.para.pFmt->dwMask & PFM_TABLE &&