1 /* 2 * RichEdit - Basic operations on double linked lists. 3 * 4 * Copyright 2004 by Krzysztof Foltman 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 22 #include "editor.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists); 25 26 void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) 27 { 28 diWhat->next = diWhere; 29 diWhat->prev = diWhere->prev; 30 31 diWhere->prev->next = diWhat; 32 diWhat->next->prev = diWhat; 33 } 34 35 void ME_Remove(ME_DisplayItem *diWhere) 36 { 37 ME_DisplayItem *diNext = diWhere->next; 38 ME_DisplayItem *diPrev = diWhere->prev; 39 assert(diNext); 40 assert(diPrev); 41 diPrev->next = diNext; 42 diNext->prev = diPrev; 43 } 44 45 static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass) 46 { 47 switch (nTypeOrClass) 48 { 49 case diRunOrParagraph: 50 return type == diRun || type == diParagraph; 51 case diRunOrStartRow: 52 return type == diRun || type == diStartRow; 53 case diParagraphOrEnd: 54 return type == diTextEnd || type == diParagraph; 55 case diStartRowOrParagraph: 56 return type == diStartRow || type == diParagraph; 57 case diStartRowOrParagraphOrEnd: 58 return type == diStartRow || type == diParagraph || type == diTextEnd; 59 case diRunOrParagraphOrEnd: 60 return type == diRun || type == diParagraph || type == diTextEnd; 61 default: 62 return type == nTypeOrClass; 63 } 64 } 65 66 /* Modifies run pointer to point to the next run. 67 * If all_para is FALSE constrain the search to the current para, 68 * otherwise modify the paragraph pointer if moving into the next paragraph. 69 * 70 * Returns TRUE if next run is found, otherwise returns FALSE. */ 71 BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para) 72 { 73 ME_DisplayItem *p = (*run)->next; 74 while (p->type != diTextEnd) 75 { 76 if (p->type == diParagraph) { 77 if (!all_para) return FALSE; 78 *para = p; 79 } else if (p->type == diRun) { 80 *run = p; 81 return TRUE; 82 } 83 p = p->next; 84 } 85 return FALSE; 86 } 87 88 /* Modifies run pointer to point to the previous run. 89 * If all_para is FALSE constrain the search to the current para, 90 * otherwise modify the paragraph pointer if moving into the previous paragraph. 91 * 92 * Returns TRUE if previous run is found, otherwise returns FALSE. */ 93 BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para) 94 { 95 ME_DisplayItem *p = (*run)->prev; 96 while (p->type != diTextStart) 97 { 98 if (p->type == diParagraph) { 99 if (!all_para) return FALSE; 100 if (p->member.para.prev_para->type == diParagraph) 101 *para = p->member.para.prev_para; 102 } else if (p->type == diRun) { 103 *run = p; 104 return TRUE; 105 } 106 p = p->prev; 107 } 108 return FALSE; 109 } 110 111 ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) 112 { 113 if (!di) 114 return NULL; 115 di = di->prev; 116 while(di!=NULL) { 117 if (ME_DITypesEqual(di->type, nTypeOrClass)) 118 return di; 119 di = di->prev; 120 } 121 return NULL; 122 } 123 124 ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass) 125 { 126 while(di!=NULL) { 127 if (ME_DITypesEqual(di->type, nTypeOrClass)) 128 return di; 129 di = di->prev; 130 } 131 return NULL; 132 } 133 134 ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) 135 { 136 if (!di) return NULL; 137 di = di->next; 138 while(di!=NULL) { 139 if (ME_DITypesEqual(di->type, nTypeOrClass)) 140 return di; 141 di = di->next; 142 } 143 return NULL; 144 } 145 146 static const char *ME_GetDITypeName(ME_DIType type) 147 { 148 switch(type) 149 { 150 case diParagraph: return "diParagraph"; 151 case diRun: return "diRun"; 152 case diCell: return "diCell"; 153 case diTextStart: return "diTextStart"; 154 case diTextEnd: return "diTextEnd"; 155 case diStartRow: return "diStartRow"; 156 default: return "?"; 157 } 158 } 159 160 void ME_DestroyDisplayItem(ME_DisplayItem *item) 161 { 162 if (0) 163 TRACE("type=%s\n", ME_GetDITypeName(item->type)); 164 if (item->type==diParagraph) 165 { 166 ME_DestroyString(item->member.para.text); 167 para_num_clear( &item->member.para.para_num ); 168 } 169 170 if (item->type==diRun) 171 { 172 if (item->member.run.ole_obj) ME_DeleteReObject(item->member.run.ole_obj); 173 heap_free( item->member.run.glyphs ); 174 heap_free( item->member.run.clusters ); 175 ME_ReleaseStyle(item->member.run.style); 176 } 177 heap_free(item); 178 } 179 180 ME_DisplayItem *ME_MakeDI(ME_DIType type) 181 { 182 ME_DisplayItem *item = heap_alloc_zero(sizeof(*item)); 183 184 item->type = type; 185 item->prev = item->next = NULL; 186 return item; 187 } 188 189 void ME_DumpDocument(ME_TextBuffer *buffer) 190 { 191 /* FIXME this is useless, */ 192 ME_DisplayItem *pItem = buffer->pFirst; 193 TRACE("DOCUMENT DUMP START\n"); 194 while(pItem) { 195 switch(pItem->type) 196 { 197 case diTextStart: 198 TRACE("Start\n"); 199 break; 200 case diCell: 201 TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel, 202 !pItem->member.cell.next_cell ? ", END" : 203 (!pItem->member.cell.prev_cell ? ", START" :"")); 204 break; 205 case diParagraph: 206 TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs); 207 if (pItem->member.para.nFlags & MEPF_ROWSTART) 208 TRACE(" - (Table Row Start)\n"); 209 if (pItem->member.para.nFlags & MEPF_ROWEND) 210 TRACE(" - (Table Row End)\n"); 211 break; 212 case diStartRow: 213 TRACE(" - StartRow\n"); 214 break; 215 case diRun: 216 TRACE(" - Run(%s, %d, flags=%x)\n", debugstr_run( &pItem->member.run ), 217 pItem->member.run.nCharOfs, pItem->member.run.nFlags); 218 break; 219 case diTextEnd: 220 TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs); 221 break; 222 default: 223 break; 224 } 225 pItem = pItem->next; 226 } 227 TRACE("DOCUMENT DUMP END\n"); 228 } 229