Rev 5291 | Rev 5464 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4777 | avox | 1 | //FIXME: this include must go to sctextstruct.h ! |
2 | #include <qvaluelist.h> |
||
5105 | mrdocs | 3 | #include <cassert> //added to make Fedora-5 happy |
4669 | avox | 4 | #include "fpoint.h" |
5 | #include "sctextstruct.h" |
||
6 | #include "storytext.h" |
||
7 | #include "scribus.h" |
||
8 | #include "scfonts.h" |
||
5184 | avox | 9 | #include "util.h" |
4669 | avox | 10 | |
11 | //FIXME: move to proper place |
||
12 | const QString CharStyle::NOCOLOR; // cf. sctextstruct.h |
||
13 | |||
14 | |||
15 | QChar SpecialChars::OBJECT = QChar(25); |
||
16 | QChar SpecialChars::TAB = QChar(9); |
||
17 | QChar SpecialChars::PARSEP = QChar(13); |
||
18 | QChar SpecialChars::LINEBREAK = QChar(28); |
||
19 | QChar SpecialChars::COLBREAK = QChar(26); |
||
20 | QChar SpecialChars::FRAMEBREAK = QChar(27); |
||
21 | QChar SpecialChars::SHYPHEN; |
||
22 | QChar SpecialChars::NBHYPHEN = QChar(24); |
||
23 | QChar SpecialChars::NBSPACE = QChar(29); |
||
24 | QChar SpecialChars::ZWNBSPACE; |
||
25 | QChar SpecialChars::ZWSPACE; |
||
26 | //QChar SpecialChars::SPACE = QChar(32); |
||
27 | |||
28 | |||
29 | |||
30 | StoryText::StoryText(ScribusDoc * doc_) : doc(doc_) |
||
31 | { |
||
32 | clear(); |
||
33 | } |
||
34 | |||
4706 | avox | 35 | StoryText::StoryText(const StoryText & other) : QPtrList<ScText>(other), doc(other.doc) |
4669 | avox | 36 | { |
4706 | avox | 37 | selFirst = 0; |
38 | selLast = -1; |
||
39 | |||
40 | firstFrameItem = 0; |
||
41 | lastFrameItem = -1; |
||
42 | |||
4669 | avox | 43 | invalidateLayout(); |
44 | } |
||
45 | |||
46 | StoryText::~StoryText() |
||
47 | { |
||
48 | } |
||
49 | |||
50 | StoryText& StoryText::operator= (const StoryText & other) |
||
51 | { |
||
4706 | avox | 52 | selFirst = 0; |
53 | selLast = -1; |
||
54 | |||
55 | firstFrameItem = 0; |
||
56 | lastFrameItem = -1; |
||
57 | |||
4669 | avox | 58 | invalidateLayout(); |
59 | return *this; |
||
60 | } |
||
61 | |||
62 | |||
63 | void StoryText::clear() |
||
64 | { |
||
65 | selFirst = 0; |
||
66 | selLast = -1; |
||
67 | |||
68 | firstFrameItem = 0; |
||
69 | lastFrameItem = -1; |
||
70 | |||
4749 | avox | 71 | for (ScText *it = first(); it != 0; it = next()) |
72 | { |
||
73 | if ((it->ch == SpecialChars::OBJECT) && (it->cembedded != 0)) { |
||
74 | doc->FrameItems.remove(it->cembedded); |
||
5184 | avox | 75 | delete it->cembedded; |
4749 | avox | 76 | it->cembedded = 0; |
77 | } |
||
78 | } |
||
79 | |||
4687 | avox | 80 | QPtrList<ScText>::clear(); |
4669 | avox | 81 | invalidateAll(); |
82 | } |
||
83 | |||
84 | |||
85 | void StoryText::removeChars(int pos, uint len) |
||
86 | { |
||
87 | if (pos < 0) |
||
88 | pos += length(); |
||
89 | |||
90 | assert( len > 0 ); |
||
91 | assert( pos >= 0 ); |
||
92 | assert( pos + static_cast<int>(len) <= length() ); |
||
4749 | avox | 93 | |
4752 | avox | 94 | for ( uint i=0; i < len; ++i ) |
4749 | avox | 95 | { |
96 | ScText *it = take(i); |
||
97 | if ((it->ch == SpecialChars::OBJECT) && (it->cembedded != 0)) { |
||
98 | doc->FrameItems.remove(it->cembedded); |
||
99 | it->cembedded = 0; |
||
100 | } |
||
101 | delete it; |
||
102 | } |
||
103 | invalidate(pos, -1); |
||
4669 | avox | 104 | } |
105 | |||
4749 | avox | 106 | void StoryText::insertChars(int pos, QString txt) //, const CharStyle& |
4669 | avox | 107 | { |
108 | if (pos < 0) |
||
109 | pos += length(); |
||
110 | |||
111 | assert(pos >= 0); |
||
112 | assert(pos <= length()); |
||
4749 | avox | 113 | |
5365 | avox | 114 | if (txt.length() == 0) |
115 | return; |
||
116 | |||
5184 | avox | 117 | const CharStyle style = pos == length() ? doc->docParagraphStyles[0].charStyle() : charStyle(pos); |
5291 | avox | 118 | assert(style.cfont != NULL); |
119 | |||
5184 | avox | 120 | const int paraStyle = pos == length() ? 0 : at(pos)->cab; |
4749 | avox | 121 | |
4752 | avox | 122 | for (uint i = 0; i < txt.length(); ++i) { |
4749 | avox | 123 | ScText * item = new ScText(); |
124 | item->ch= txt.mid(i, 1); |
||
125 | *static_cast<CharStyle *>(item) = style; |
||
5184 | avox | 126 | item->cab = paraStyle; |
127 | item->cselect = false; |
||
128 | item->xp = 0; |
||
129 | item->yp = 0; |
||
130 | item->PtransX = 0; |
||
131 | item->PtransY = 0; |
||
132 | item->PRot = 0; |
||
133 | item->cembedded = NULL; |
||
4749 | avox | 134 | insert(pos + i, item); |
135 | } |
||
136 | |||
4669 | avox | 137 | invalidate(pos, pos + txt.length()); |
138 | } |
||
139 | |||
140 | void StoryText::replaceChar(int pos, QChar ch) |
||
141 | { |
||
142 | if (pos < 0) |
||
143 | pos += length(); |
||
144 | |||
145 | assert(pos >= 0); |
||
146 | assert(pos < length()); |
||
147 | |||
148 | at(pos)->ch = ch; |
||
149 | |||
150 | invalidate(pos, pos + 1); |
||
151 | } |
||
152 | |||
153 | void StoryText::insertObject(int pos, PageItem* ob) |
||
154 | { |
||
155 | if (pos < 0) |
||
156 | pos += length(); |
||
157 | |||
158 | insertChars(pos, SpecialChars::OBJECT); |
||
159 | //FIXME:NLS |
||
160 | } |
||
161 | |||
162 | |||
163 | int StoryText::length() const |
||
164 | { |
||
165 | return count(); |
||
166 | } |
||
167 | |||
168 | QChar StoryText::text(int pos) const |
||
169 | { |
||
170 | if (pos < 0) |
||
171 | pos += length(); |
||
172 | |||
173 | assert(pos >= 0); |
||
174 | assert(pos < length()); |
||
175 | |||
176 | return const_cast<StoryText *>(this)->at(pos)->ch[0]; |
||
177 | } |
||
178 | |||
179 | QString StoryText::text(int pos, uint len) const |
||
180 | { |
||
181 | if (pos < 0) |
||
182 | pos += length(); |
||
183 | |||
184 | assert(len > 0); |
||
185 | assert(pos >= 0); |
||
186 | assert(pos + signed(len) <= length()); |
||
187 | |||
188 | QString result; |
||
4777 | avox | 189 | for (uint i = pos; i < pos+signed(len); ++i) |
4669 | avox | 190 | result += const_cast<StoryText *>(this)->at(i)->ch; |
191 | |||
192 | return result; |
||
193 | } |
||
194 | |||
195 | PageItem* StoryText::object(int pos) const |
||
196 | { |
||
197 | if (pos < 0) |
||
198 | pos += length(); |
||
199 | |||
200 | assert(pos >= 0); |
||
201 | assert(pos < length()); |
||
202 | |||
203 | StoryText* that = const_cast<StoryText *>(this); |
||
204 | if (that->at(pos)->cembedded != NULL) |
||
205 | return that->at(pos)->cembedded; |
||
206 | else |
||
207 | return NULL; |
||
208 | } |
||
209 | |||
210 | |||
211 | const CharStyle & StoryText::charStyle(int pos) const |
||
212 | { |
||
213 | if (pos < 0) |
||
214 | pos += length(); |
||
215 | |||
216 | assert(pos >= 0); |
||
217 | assert(pos < length()); |
||
218 | |||
219 | StoryText* that = const_cast<StoryText *>(this); |
||
220 | return dynamic_cast<const CharStyle &> (*that->at(pos)); |
||
221 | } |
||
222 | |||
223 | const ParagraphStyle & StoryText::paragraphStyle(int pos) const |
||
224 | { |
||
225 | if (pos < 0) |
||
226 | pos += length(); |
||
227 | |||
228 | assert(pos >= 0); |
||
229 | assert(pos < length()); |
||
230 | |||
5192 | avox | 231 | StoryText * that = const_cast<StoryText *> (this); |
232 | assert( that->at(pos)->cab >= 0 ); |
||
233 | assert( that->at(pos)->cab < doc->docParagraphStyles.count() ); |
||
234 | return doc->docParagraphStyles[that->at(pos)->cab]; |
||
4669 | avox | 235 | } |
236 | |||
237 | void StoryText::applyStyle(int pos, uint len, const CharStyle& style ) |
||
238 | { |
||
239 | if (pos < 0) |
||
240 | pos += length(); |
||
241 | |||
242 | assert(pos >= 0); |
||
243 | assert(pos + signed(len) <= length()); |
||
244 | |||
245 | if (len == 0) |
||
246 | return; |
||
247 | |||
4749 | avox | 248 | for (uint i=pos; i < pos+len; ++i) |
249 | at(i)->applyStyle(style); |
||
4669 | avox | 250 | |
251 | invalidate(pos, pos + len); |
||
252 | } |
||
253 | |||
254 | void StoryText::applyStyle(int pos, const ParagraphStyle& style) |
||
255 | { |
||
256 | if (pos < 0) |
||
257 | pos += length(); |
||
258 | |||
259 | assert(pos >= 0); |
||
260 | assert(pos < length()); |
||
261 | |||
5184 | avox | 262 | int paraStyle = QMAX(0, findParagraphStyle(doc, style)); //FIXME:NLS |
263 | int i = pos - 1; |
||
264 | // find start of para |
||
265 | while (i >= 0 && text(i) != SpecialChars::PARSEP) |
||
266 | --i; |
||
267 | // set 'cab' field |
||
268 | do { |
||
269 | ++i; |
||
270 | at(i)->cab = paraStyle; |
||
271 | } |
||
272 | while (i+1 < length() && text(i) != SpecialChars::PARSEP); |
||
4669 | avox | 273 | } |
274 | |||
275 | uint StoryText::nrOfParagraphs() const |
||
276 | { |
||
277 | uint result = 0; |
||
278 | StoryText* that = const_cast<StoryText *>(this); |
||
279 | for (int i=0; i < length(); ++i) |
||
5184 | avox | 280 | if (that->text(i) == SpecialChars::PARSEP) |
4669 | avox | 281 | ++result; |
282 | return result; |
||
283 | } |
||
284 | |||
285 | int StoryText::startOfParagraph(uint index) const |
||
286 | { |
||
287 | if (index == 0) |
||
288 | return 0; |
||
289 | |||
5184 | avox | 290 | StoryText* that = const_cast<StoryText *>(this); |
4669 | avox | 291 | for (int i=0; i < length(); ++i) |
5184 | avox | 292 | if (that->text(i) == SpecialChars::PARSEP && ! --index) |
4669 | avox | 293 | return i + 1; |
294 | return -1; |
||
295 | } |
||
296 | |||
297 | int StoryText::endOfParagraph(uint index) const |
||
298 | { |
||
299 | ++index; |
||
5184 | avox | 300 | StoryText* that = const_cast<StoryText *>(this); |
4669 | avox | 301 | for (int i=0; i < length(); ++i) |
5184 | avox | 302 | if (that->text(i) == SpecialChars::PARSEP && ! --index) |
4669 | avox | 303 | return i + 1; |
304 | return length(); |
||
305 | } |
||
306 | |||
307 | uint StoryText::nrOfRuns() const |
||
308 | { |
||
309 | return 1; |
||
310 | } |
||
311 | |||
312 | int StoryText::startOfRun(uint index) const |
||
313 | { |
||
314 | return 0; |
||
315 | } |
||
316 | |||
317 | int StoryText::endOfRun(uint index) const |
||
318 | { |
||
319 | return length(); |
||
320 | } |
||
321 | |||
322 | |||
323 | // selection |
||
324 | |||
325 | int StoryText::startOfSelection() const |
||
326 | { |
||
327 | return selFirst <= selLast? selFirst : 0; |
||
328 | } |
||
329 | |||
330 | int StoryText::endOfSelection() const |
||
331 | { |
||
332 | return selFirst <= selLast? selLast + 1 : -1; |
||
333 | } |
||
334 | |||
335 | int StoryText::lengthOfSelection() const |
||
336 | { |
||
337 | return selFirst <= selLast? selLast - selFirst + 1 : 0; |
||
338 | } |
||
339 | |||
340 | |||
341 | bool StoryText::selected(int pos) const |
||
342 | { |
||
4749 | avox | 343 | return (selFirst <= pos && pos <= selLast) |
4752 | avox | 344 | || (pos >= 0 && pos < length() && const_cast<StoryText*>(this)->at(pos)->cselect); |
4669 | avox | 345 | } |
346 | |||
347 | void StoryText::select(int pos, uint len, bool on) |
||
348 | { |
||
349 | if (pos < 0) |
||
350 | pos += length(); |
||
351 | |||
352 | assert( pos >= 0 ); |
||
353 | assert( pos + signed(len) <= length() ); |
||
354 | |||
355 | StoryText* that = const_cast<StoryText *>(this); |
||
356 | for (int i=pos; i < pos+signed(len); ++i) |
||
357 | that->at(i)->cselect = on; |
||
358 | |||
359 | if (on) { |
||
360 | // extend if possible |
||
361 | if (selected(pos - 1)) |
||
362 | selLast = QMAX(selLast, pos + static_cast<int>(len) - 1); |
||
363 | else if (selected(pos + len)) |
||
364 | selFirst = QMIN(selFirst, pos); |
||
365 | else { |
||
366 | selFirst = pos; |
||
367 | selLast = pos + len - 1; |
||
368 | } |
||
369 | } |
||
370 | else { |
||
371 | if (pos <= selFirst && selLast < pos + signed(len)) |
||
372 | deselectAll(); |
||
373 | // shrink |
||
374 | else if (!selected(pos - 1) && selected(pos + len - 1)) |
||
375 | selFirst = pos + len; |
||
376 | else if (selected(pos) && !selected(pos + len)) |
||
377 | selLast = pos - 1; |
||
378 | else if (selected(pos) || selected(pos + len - 1)) |
||
379 | // Grr, deselection splits selection |
||
380 | selLast = pos - 1; |
||
381 | } |
||
382 | } |
||
383 | |||
384 | void StoryText::selectAll() |
||
385 | { |
||
386 | StoryText* that = const_cast<StoryText *>(this); |
||
387 | for (int i=0; i < length(); ++i) |
||
388 | that->at(i)->cselect = true; |
||
389 | |||
390 | selFirst = 0; |
||
391 | selLast = length() - 1; |
||
392 | } |
||
393 | |||
394 | void StoryText::deselectAll() |
||
395 | { |
||
396 | StoryText* that = const_cast<StoryText *>(this); |
||
397 | for (int i=0; i < length(); ++i) |
||
398 | that->at(i)->cselect = false; |
||
399 | |||
400 | selFirst = 0; |
||
401 | selLast = -1; |
||
402 | } |
||
403 | |||
404 | void StoryText::removeSelection() |
||
405 | { |
||
406 | if (selFirst > selLast) |
||
407 | return; |
||
408 | |||
409 | assert( selFirst >= 0 ); |
||
410 | assert( selLast < length() ); |
||
411 | |||
412 | removeChars(selFirst, selLast - selFirst+1); |
||
413 | deselectAll(); |
||
414 | } |
||
415 | |||
416 | |||
417 | |||
418 | void StoryText::invalidateObject(const PageItem * embedded) |
||
419 | { |
||
420 | } |
||
421 | |||
422 | void StoryText::invalidateLayout() |
||
423 | { |
||
424 | } |
||
425 | |||
426 | void StoryText::invalidateAll() |
||
427 | { |
||
428 | } |
||
429 | |||
4749 | avox | 430 | void StoryText::invalidate(int firstitem, int lastitem) |
4669 | avox | 431 | { |
432 | } |
||
433 | |||
434 | |||
435 | // physical view |
||
436 | |||
437 | /* |
||
438 | void StoryText::validate() |
||
439 | { |
||
440 | static bool withinValidate = false; |
||
441 | |||
442 | assert( !withinValidate ); |
||
443 | withinValidate = true; |
||
444 | |||
445 | withinValidate = false; |
||
446 | } |
||
447 | */ |
||
448 | |||
449 | int StoryText::screenToPosition(FPoint coord) const |
||
450 | { |
||
451 | //FIXME:NLS |
||
452 | //FIXME: should be end of lastFrameItem |
||
453 | return length(); |
||
454 | } |
||
455 | |||
456 | |||
457 | FPoint StoryText::boundingBox(int pos, uint len) const |
||
458 | { |
||
459 | return FPoint(); //FIXME |
||
460 | } |
||
461 | |||
462 | |||
463 | int StoryText::layout(int startItem) |
||
464 | { |
||
465 | //FIXME:NLS |
||
466 | return -1; |
||
467 | } |
||
468 | |||
469 | |||
470 | uint StoryText::nrOfItems() const |
||
471 | { |
||
472 | return length(); |
||
473 | } |
||
474 | |||
475 | |||
476 | ScText* StoryText::item(uint itm) |
||
477 | { |
||
478 | assert( static_cast<int>(itm) < length() ); |
||
479 | return const_cast<StoryText *>(this)->at(itm); |
||
480 | } |
||
481 | |||
482 | const QString StoryText::itemText(uint itm) const |
||
483 | { |
||
484 | |||
485 | assert( static_cast<int>(itm) < length() ); |
||
486 | |||
487 | return text(itm, 1); |
||
488 | } |
||
489 | |||
490 | |||
491 | const CharStyle StoryText::itemStyle(uint itm) const |
||
492 | { |
||
493 | assert( static_cast<int>(itm) < length() ); |
||
494 | |||
495 | return charStyle(itm); |
||
496 | } |
||
497 | |||
498 | |||
499 | int StoryText::startOfItem(uint itm) const |
||
500 | { |
||
501 | assert( static_cast<int>(itm) < length() ); |
||
502 | |||
503 | return itm; |
||
504 | } |
||
505 | |||
506 | int StoryText::endOfItem(uint itm) const |
||
507 | { |
||
508 | assert( static_cast<int>(itm) < length() ); |
||
509 | |||
510 | return itm + 1; |
||
511 | } |
||
512 |