[RICHED20]
[reactos.git] / reactos / dll / win32 / riched20 / list.c
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 #include "editor.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists);
24
25 void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat)
26 {
27 diWhat->next = diWhere;
28 diWhat->prev = diWhere->prev;
29
30 diWhere->prev->next = diWhat;
31 diWhat->next->prev = diWhat;
32 }
33
34 void ME_Remove(ME_DisplayItem *diWhere)
35 {
36 ME_DisplayItem *diNext = diWhere->next;
37 ME_DisplayItem *diPrev = diWhere->prev;
38 assert(diNext);
39 assert(diPrev);
40 diPrev->next = diNext;
41 diNext->prev = diPrev;
42 }
43
44 static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass)
45 {
46 switch (nTypeOrClass)
47 {
48 case diRunOrParagraph:
49 return type == diRun || type == diParagraph;
50 case diRunOrStartRow:
51 return type == diRun || type == diStartRow;
52 case diParagraphOrEnd:
53 return type == diTextEnd || type == diParagraph;
54 case diStartRowOrParagraph:
55 return type == diStartRow || type == diParagraph;
56 case diStartRowOrParagraphOrEnd:
57 return type == diStartRow || type == diParagraph || type == diTextEnd;
58 case diRunOrParagraphOrEnd:
59 return type == diRun || type == diParagraph || type == diTextEnd;
60 default:
61 return type == nTypeOrClass;
62 }
63 }
64
65 /* Modifies run pointer to point to the next run, and modify the
66 * paragraph pointer if moving into the next paragraph.
67 *
68 * Returns TRUE if next run is found, otherwise returns FALSE. */
69 BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run)
70 {
71 ME_DisplayItem *p = (*run)->next;
72 while (p->type != diTextEnd)
73 {
74 if (p->type == diParagraph) {
75 *para = p;
76 } else if (p->type == diRun) {
77 *run = p;
78 return TRUE;
79 }
80 p = p->next;
81 }
82 return FALSE;
83 }
84
85 /* Modifies run pointer to point to the previous run, and modify the
86 * paragraph pointer if moving into the previous paragraph.
87 *
88 * Returns TRUE if previous run is found, otherwise returns FALSE. */
89 BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run)
90 {
91 ME_DisplayItem *p = (*run)->prev;
92 while (p->type != diTextStart)
93 {
94 if (p->type == diParagraph) {
95 if (p->member.para.prev_para->type == diParagraph)
96 *para = p->member.para.prev_para;
97 } else if (p->type == diRun) {
98 *run = p;
99 return TRUE;
100 }
101 p = p->prev;
102 }
103 return FALSE;
104 }
105
106 ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass)
107 {
108 if (!di)
109 return NULL;
110 di = di->prev;
111 while(di!=NULL) {
112 if (ME_DITypesEqual(di->type, nTypeOrClass))
113 return di;
114 di = di->prev;
115 }
116 return NULL;
117 }
118
119 ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass)
120 {
121 while(di!=NULL) {
122 if (ME_DITypesEqual(di->type, nTypeOrClass))
123 return di;
124 di = di->prev;
125 }
126 return NULL;
127 }
128
129 ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass)
130 {
131 if (!di) return NULL;
132 di = di->next;
133 while(di!=NULL) {
134 if (ME_DITypesEqual(di->type, nTypeOrClass))
135 return di;
136 di = di->next;
137 }
138 return NULL;
139 }
140
141 void ME_DestroyDisplayItem(ME_DisplayItem *item)
142 {
143 /* TRACE("type=%s\n", ME_GetDITypeName(item->type)); */
144 if (item->type==diParagraph)
145 {
146 FREE_OBJ(item->member.para.pFmt);
147 ME_DestroyString(item->member.para.text);
148 }
149
150 if (item->type==diRun)
151 {
152 if (item->member.run.ole_obj) ME_DeleteReObject(item->member.run.ole_obj);
153 ME_ReleaseStyle(item->member.run.style);
154 }
155 FREE_OBJ(item);
156 }
157
158 ME_DisplayItem *ME_MakeDI(ME_DIType type)
159 {
160 ME_DisplayItem *item = ALLOC_OBJ(ME_DisplayItem);
161 ZeroMemory(item, sizeof(ME_DisplayItem));
162 item->type = type;
163 item->prev = item->next = NULL;
164 if (type == diParagraph)
165 {
166 item->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
167 ME_SetDefaultParaFormat(item->member.para.pFmt);
168 item->member.para.nFlags = MEPF_REWRAP;
169 }
170
171 return item;
172 }
173
174 const char *ME_GetDITypeName(ME_DIType type)
175 {
176 switch(type)
177 {
178 case diParagraph: return "diParagraph";
179 case diRun: return "diRun";
180 case diCell: return "diCell";
181 case diTextStart: return "diTextStart";
182 case diTextEnd: return "diTextEnd";
183 case diStartRow: return "diStartRow";
184 default: return "?";
185 }
186 }
187
188 void ME_DumpDocument(ME_TextBuffer *buffer)
189 {
190 /* FIXME this is useless, */
191 ME_DisplayItem *pItem = buffer->pFirst;
192 TRACE("DOCUMENT DUMP START\n");
193 while(pItem) {
194 switch(pItem->type)
195 {
196 case diTextStart:
197 TRACE("Start\n");
198 break;
199 case diCell:
200 TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel,
201 !pItem->member.cell.next_cell ? ", END" :
202 (!pItem->member.cell.prev_cell ? ", START" :""));
203 break;
204 case diParagraph:
205 TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs);
206 if (pItem->member.para.nFlags & MEPF_ROWSTART)
207 TRACE(" - (Table Row Start)\n");
208 if (pItem->member.para.nFlags & MEPF_ROWEND)
209 TRACE(" - (Table Row End)\n");
210 break;
211 case diStartRow:
212 TRACE(" - StartRow\n");
213 break;
214 case diRun:
215 TRACE(" - Run(%s, %d, flags=%x)\n", debugstr_run( &pItem->member.run ),
216 pItem->member.run.nCharOfs, pItem->member.run.nFlags);
217 break;
218 case diTextEnd:
219 TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs);
220 break;
221 default:
222 break;
223 }
224 pItem = pItem->next;
225 }
226 TRACE("DOCUMENT DUMP END\n");
227 }