|  | /* | 
|  | * RichEdit - Basic operations on double linked lists. | 
|  | * | 
|  | * Copyright 2004 by Krzysztof Foltman | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "editor.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists); | 
|  |  | 
|  | void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) | 
|  | { | 
|  | diWhat->next = diWhere; | 
|  | diWhat->prev = diWhere->prev; | 
|  |  | 
|  | diWhere->prev->next = diWhat; | 
|  | diWhat->next->prev = diWhat; | 
|  | } | 
|  |  | 
|  | void ME_Remove(ME_DisplayItem *diWhere) | 
|  | { | 
|  | ME_DisplayItem *diNext = diWhere->next; | 
|  | ME_DisplayItem *diPrev = diWhere->prev; | 
|  | assert(diNext); | 
|  | assert(diPrev); | 
|  | diPrev->next = diNext; | 
|  | diNext->prev = diPrev; | 
|  | } | 
|  |  | 
|  | static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass) | 
|  | { | 
|  | switch (nTypeOrClass) | 
|  | { | 
|  | case diRunOrParagraph: | 
|  | return type == diRun || type == diParagraph; | 
|  | case diRunOrStartRow: | 
|  | return type == diRun || type == diStartRow; | 
|  | case diParagraphOrEnd: | 
|  | return type == diTextEnd || type == diParagraph; | 
|  | case diStartRowOrParagraph: | 
|  | return type == diStartRow || type == diParagraph; | 
|  | case diStartRowOrParagraphOrEnd: | 
|  | return type == diStartRow || type == diParagraph || type == diTextEnd; | 
|  | case diRunOrParagraphOrEnd: | 
|  | return type == diRun || type == diParagraph || type == diTextEnd; | 
|  | default: | 
|  | return type == nTypeOrClass; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Modifies run pointer to point to the next run, and modify the | 
|  | * paragraph pointer if moving into the next paragraph. | 
|  | * | 
|  | * Returns TRUE if next run is found, otherwise returns FALSE. */ | 
|  | BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run) | 
|  | { | 
|  | ME_DisplayItem *p = (*run)->next; | 
|  | while (p->type != diTextEnd) | 
|  | { | 
|  | if (p->type == diParagraph) { | 
|  | *para = p; | 
|  | } else if (p->type == diRun) { | 
|  | *run = p; | 
|  | return TRUE; | 
|  | } | 
|  | p = p->next; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Modifies run pointer to point to the previous run, and modify the | 
|  | * paragraph pointer if moving into the previous paragraph. | 
|  | * | 
|  | * Returns TRUE if previous run is found, otherwise returns FALSE. */ | 
|  | BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run) | 
|  | { | 
|  | ME_DisplayItem *p = (*run)->prev; | 
|  | while (p->type != diTextStart) | 
|  | { | 
|  | if (p->type == diParagraph) { | 
|  | if (p->member.para.prev_para->type == diParagraph) | 
|  | *para = p->member.para.prev_para; | 
|  | } else if (p->type == diRun) { | 
|  | *run = p; | 
|  | return TRUE; | 
|  | } | 
|  | p = p->prev; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) | 
|  | { | 
|  | if (!di) | 
|  | return NULL; | 
|  | di = di->prev; | 
|  | while(di!=NULL) { | 
|  | if (ME_DITypesEqual(di->type, nTypeOrClass)) | 
|  | return di; | 
|  | di = di->prev; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass) | 
|  | { | 
|  | while(di!=NULL) { | 
|  | if (ME_DITypesEqual(di->type, nTypeOrClass)) | 
|  | return di; | 
|  | di = di->prev; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) | 
|  | { | 
|  | if (!di) return NULL; | 
|  | di = di->next; | 
|  | while(di!=NULL) { | 
|  | if (ME_DITypesEqual(di->type, nTypeOrClass)) | 
|  | return di; | 
|  | di = di->next; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | void ME_DestroyDisplayItem(ME_DisplayItem *item) { | 
|  | /*  TRACE("type=%s\n", ME_GetDITypeName(item->type)); */ | 
|  | if (item->type==diParagraph || item->type == diUndoSetParagraphFormat) { | 
|  | FREE_OBJ(item->member.para.pFmt); | 
|  | } | 
|  | if (item->type==diRun || item->type == diUndoInsertRun) { | 
|  | if (item->member.run.ole_obj) ME_DeleteReObject(item->member.run.ole_obj); | 
|  | ME_ReleaseStyle(item->member.run.style); | 
|  | ME_DestroyString(item->member.run.strText); | 
|  | } | 
|  | if (item->type==diUndoSetCharFormat) { | 
|  | ME_ReleaseStyle(item->member.ustyle); | 
|  | } | 
|  | if (item->type==diUndoSplitParagraph) { | 
|  | FREE_OBJ(item->member.para.pFmt); | 
|  | FREE_OBJ(item->member.para.pCell); | 
|  | } | 
|  | FREE_OBJ(item); | 
|  | } | 
|  |  | 
|  | ME_DisplayItem *ME_MakeDI(ME_DIType type) { | 
|  | ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem); | 
|  | ZeroMemory(item, sizeof(ME_DisplayItem)); | 
|  | item->type = type; | 
|  | item->prev = item->next = NULL; | 
|  | if (type == diParagraph || type == diUndoSplitParagraph) { | 
|  | item->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2); | 
|  | ME_SetDefaultParaFormat(item->member.para.pFmt); | 
|  | item->member.para.nFlags = MEPF_REWRAP; | 
|  | } | 
|  |  | 
|  | return item; | 
|  | } | 
|  |  | 
|  | const char *ME_GetDITypeName(ME_DIType type) | 
|  | { | 
|  | switch(type) | 
|  | { | 
|  | case diParagraph: return "diParagraph"; | 
|  | case diRun: return "diRun"; | 
|  | case diCell: return "diCell"; | 
|  | case diTextStart: return "diTextStart"; | 
|  | case diTextEnd: return "diTextEnd"; | 
|  | case diStartRow: return "diStartRow"; | 
|  | case diUndoEndTransaction: return "diUndoEndTransaction"; | 
|  | case diUndoPotentialEndTransaction: return "diUndoPotentialEndTransaction"; | 
|  | case diUndoSetParagraphFormat: return "diUndoSetParagraphFormat"; | 
|  | case diUndoSetCharFormat: return "diUndoSetCharFormat"; | 
|  | case diUndoInsertRun: return "diUndoInsertRun"; | 
|  | case diUndoDeleteRun: return "diUndoDeleteRun"; | 
|  | case diUndoJoinParagraphs: return "diJoinParagraphs"; | 
|  | case diUndoSplitParagraph: return "diSplitParagraph"; | 
|  | default: return "?"; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ME_DumpDocument(ME_TextBuffer *buffer) | 
|  | { | 
|  | /* FIXME this is useless, */ | 
|  | ME_DisplayItem *pItem = buffer->pFirst; | 
|  | TRACE("DOCUMENT DUMP START\n"); | 
|  | while(pItem) { | 
|  | switch(pItem->type) | 
|  | { | 
|  | case diTextStart: | 
|  | TRACE("Start\n"); | 
|  | break; | 
|  | case diCell: | 
|  | TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel, | 
|  | !pItem->member.cell.next_cell ? ", END" : | 
|  | (!pItem->member.cell.prev_cell ? ", START" :"")); | 
|  | break; | 
|  | case diParagraph: | 
|  | TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs); | 
|  | if (pItem->member.para.nFlags & MEPF_ROWSTART) | 
|  | TRACE(" - (Table Row Start)\n"); | 
|  | if (pItem->member.para.nFlags & MEPF_ROWEND) | 
|  | TRACE(" - (Table Row End)\n"); | 
|  | break; | 
|  | case diStartRow: | 
|  | TRACE(" - StartRow\n"); | 
|  | break; | 
|  | case diRun: | 
|  | TRACE(" - Run(\"%s\", %d, flags=%x)\n", debugstr_w(pItem->member.run.strText->szData), | 
|  | pItem->member.run.nCharOfs, pItem->member.run.nFlags); | 
|  | break; | 
|  | case diTextEnd: | 
|  | TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | pItem = pItem->next; | 
|  | } | 
|  | TRACE("DOCUMENT DUMP END\n"); | 
|  | } |