Subversion Repositories Scribus

Rev

Rev 13670 | Rev 15366 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8174 avox 1
/*
2
 For general Scribus (>=1.3.2) copyright and licensing information please refer
3
 to the COPYING file provided with the program. Following this notice may exist
4
 a copyright and/or license notice that predates the release of Scribus 1.3.2
5
 for which a new license (GPL+exception) is in place.
6
 */
7
/***************************************************************************
8
pageitem.cpp  -  description
9
-------------------
10
    begin                : Sat Apr 7 2001
11
    copyright            : (C) 2001 by Franz Schmid
12
    email                : Franz.Schmid@altmuehlnet.de
8931 cbradney 13
***************************************************************************/
8174 avox 14
 
15
/***************************************************************************
16
*                                                                         *
17
*   This program is free software; you can redistribute it and/or modify  *
18
*   it under the terms of the GNU General Public License as published by  *
19
*   the Free Software Foundation; either version 2 of the License, or     *
20
*   (at your option) any later version.                                   *
21
*                                                                         *
22
***************************************************************************/
23
 
13085 jghali 24
//#include <QDebug>
4777 avox 25
//FIXME: this include must go to sctextstruct.h !
9803 fschmid 26
#include <QList>
5105 mrdocs 27
#include <cassert>  //added to make Fedora-5 happy
4669 avox 28
#include "fpoint.h"
5980 avox 29
#include "scfonts.h"
7970 cbradney 30
#include "scribusdoc.h"
31
#include "sctext_shared.h"
4669 avox 32
#include "storytext.h"
8520 cbradney 33
//#include "storytext.moc"
4669 avox 34
#include "scribus.h"
5184 avox 35
#include "util.h"
8455 avox 36
#include "resourcecollection.h"
8266 avox 37
#include "desaxe/saxiohelper.h"
38
#include "desaxe/digester.h"
39
#include "desaxe/simple_actions.h"
4669 avox 40
 
41
 
7970 cbradney 42
StoryText::StoryText(ScribusDoc * doc_) : doc(doc_)
5753 jghali 43
{
6733 avox 44
        if (doc_) {
7442 avox 45
                d = new ScText_Shared(&doc_->paragraphStyles());
7958 avox 46
                doc->paragraphStyles().connect(this, SLOT(invalidateAll()));
47
                doc->charStyles().connect(this, SLOT(invalidateAll()));
6733 avox 48
        }
49
        else {
7442 avox 50
                d = new ScText_Shared(NULL);
6733 avox 51
        }
7002 avox 52
        selFirst = 0;
53
        selLast = -1;
54
 
55
        firstFrameItem = 0;
56
        lastFrameItem = -1;
7501 avox 57
        m_magicX = 0.0;
58
        m_lastMagicPos = -1;
7002 avox 59
 
60
        d->len = 0;
61
        invalidateAll();
4669 avox 62
}
63
 
7970 cbradney 64
StoryText::StoryText() : doc(NULL)
6144 avox 65
{
7442 avox 66
        d = new ScText_Shared(NULL);
7501 avox 67
 
68
        selFirst = 0;
69
        selLast = -1;
70
 
71
        firstFrameItem = 0;
72
        lastFrameItem = -1;
73
        m_magicX = 0.0;
74
        m_lastMagicPos = -1;
6144 avox 75
}
76
 
8337 avox 77
StoryText::StoryText(const StoryText & other) : QObject(), SaxIO(), doc(other.doc)
4669 avox 78
{
5721 avox 79
        d = other.d;
80
        d->refs++;
81
 
7958 avox 82
        if(doc) {
83
                doc->paragraphStyles().connect(this, SLOT(invalidateAll()));
84
                doc->charStyles().connect(this, SLOT(invalidateAll()));
85
        }
86
 
4706 avox 87
        selFirst = 0;
88
        selLast = -1;
89
 
90
        firstFrameItem = 0;
91
        lastFrameItem = -1;
7501 avox 92
        m_magicX = 0.0;
93
        m_lastMagicPos = -1;
5721 avox 94
 
4669 avox 95
        invalidateLayout();
96
}
97
 
98
StoryText::~StoryText()
99
{
9476 fschmid 100
/* Code below is not needed imho, as all connections will be disconnected automatically
101
        by the QObject destructor. At least removing that code fixes a crash when closing
102
        documents */
103
/*      if (doc)
7958 avox 104
        {
105
                doc->paragraphStyles().disconnect(this, SLOT(invalidateAll()));
106
                doc->charStyles().disconnect(this, SLOT(invalidateAll()));
9476 fschmid 107
        } */
5721 avox 108
        d->refs--;
109
        if (d->refs == 0) {
5773 avox 110
                d->clear();
111
                d->len = 0;
5721 avox 112
                delete d;
113
        }      
4669 avox 114
}
115
 
6144 avox 116
StoryText StoryText::copy() const
117
{
118
        StoryText result(doc);
119
        *(result.d) = *d;
7786 avox 120
        return result;
13085 jghali 121
//      qDebug() << QString("StoryText::copy:");
10366 jghali 122
        QListIterator<ScText*> it( *(result.d) );
6144 avox 123
        ScText* elem;
10366 jghali 124
        while ( it.hasNext() ) {
125
                elem = it.next();
13085 jghali 126
//              qDebug() << QString("\tchar '%1' size %2 (orig %3)").arg(elem->ch).arg(elem->fontSize()).arg(charStyle(i++).fontSize());
6144 avox 127
        }
128
 
129
        return result;
130
}
131
 
132
 
4669 avox 133
StoryText& StoryText::operator= (const StoryText & other)
134
{
7786 avox 135
        other.d->refs++;
136
 
5721 avox 137
        d->refs--;
138
        if (d->refs == 0) {
139
                clear();
140
                delete d;
141
        }
142
 
7958 avox 143
        if(doc) {
144
                doc->paragraphStyles().disconnect(this, SLOT(invalidateAll()));
145
                doc->charStyles().disconnect(this, SLOT(invalidateAll()));
146
        }
147
 
5721 avox 148
        doc = other.doc;
149
        d = other.d;
150
 
7958 avox 151
        if (doc) {
152
                doc->paragraphStyles().connect(this, SLOT(invalidateAll()));
153
                doc->charStyles().connect(this, SLOT(invalidateAll()));
154
        }
155
 
4706 avox 156
        selFirst = 0;
157
        selLast = -1;
158
 
159
        firstFrameItem = 0;
160
        lastFrameItem = -1;
161
 
4669 avox 162
        invalidateLayout();
163
        return *this;
164
}
165
 
166
 
167
void StoryText::clear()
168
{
169
        selFirst = 0;
170
        selLast = -1;
171
 
172
        firstFrameItem = 0;
173
        lastFrameItem = -1;
174
 
6733 avox 175
        d->defaultStyle.erase();
7232 avox 176
        d->trailingStyle.erase();
5569 avox 177
 
5721 avox 178
        d->clear();
5722 avox 179
        d->len = 0;
4669 avox 180
        invalidateAll();
181
}
182
 
183
 
6887 avox 184
void StoryText::insert(int pos, const StoryText& other, bool onlySelection)
5732 avox 185
{
8049 avox 186
        if (pos < 0)
187
                pos += length()+1;
188
 
6977 avox 189
        CharStyle cstyle(charStyle(pos));
190
        ParagraphStyle pstyle(paragraphStyle(pos));
7242 avox 191
 
192
        // this style represents all differences between this and other's defaultstyles
193
        ParagraphStyle otherDefault(other.defaultStyle());
194
        otherDefault.eraseStyle(defaultStyle());
195
 
6887 avox 196
        int otherStart  = onlySelection? other.startOfSelection() : 0;
197
        int otherEnd    = onlySelection? other.endOfSelection() : other.length();
198
        int cstyleStart = otherStart;
199
        for (int i=otherStart; i < otherEnd; ++i) {
200
                if (other.charStyle(i) == cstyle
201
                        && other.text(i) != SpecialChars::OBJECT
202
                        && other.text(i) != SpecialChars::PARSEP)
5732 avox 203
                        continue;
204
                int len = i - cstyleStart;
205
                if (len > 0) {
12093 jghali 206
                        insertCharsWithSmartHyphens(pos, other.textWithSmartHyphens(cstyleStart, len));
7242 avox 207
                        applyCharStyle(pos, len, otherDefault.charStyle());
5732 avox 208
                        applyCharStyle(pos, len, cstyle);
6887 avox 209
                        pos += len;
5732 avox 210
                }
211
                if (other.text(i) == SpecialChars::PARSEP) {
6887 avox 212
                        insertChars(pos, SpecialChars::PARSEP);
12056 jghali 213
                        //#5845 : disable for now as it has nasty side effects when linking frames
214
                        //applyStyle(pos, otherDefault);
6887 avox 215
                        applyStyle(pos, other.paragraphStyle(i));
5732 avox 216
                        cstyleStart = i+1;
6887 avox 217
                        pos += 1;
5732 avox 218
                }
6887 avox 219
                else if (other.text(i) == SpecialChars::OBJECT) {
8174 avox 220
                        insertChars(pos, SpecialChars::OBJECT);
221
                        item(pos)->embedded = other.item(i)->embedded;
6887 avox 222
                        cstyleStart = i+1;
223
                        pos += 1;
224
                }
5732 avox 225
                else {
226
                        cstyle = other.charStyle(i);
227
                        cstyleStart = i;
228
                }
229
        }
6887 avox 230
        int len = otherEnd - cstyleStart;
5732 avox 231
        if (len > 0) {
12093 jghali 232
                insertCharsWithSmartHyphens(pos, other.textWithSmartHyphens(cstyleStart, len));
7242 avox 233
                applyCharStyle(pos, len, otherDefault.charStyle());
5732 avox 234
                applyCharStyle(pos, len, cstyle);
7232 avox 235
                pos += len;
7256 avox 236
                if (other.text(otherEnd-1) != SpecialChars::PARSEP) {
12056 jghali 237
                        //#5845 : disable for now as it has nasty side effects when linking frames
238
                        //applyStyle(pos, otherDefault);
7256 avox 239
                        applyStyle(pos, other.paragraphStyle(otherEnd-1));
240
                }
5732 avox 241
        }
8049 avox 242
        invalidate(pos, length());
5732 avox 243
}
244
 
245
 
5721 avox 246
/**
247
    Make sure that the paragraph CharStyle's point to the new ParagraphStyle
248
 */
8174 avox 249
void StoryText::insertParSep(int pos)
5721 avox 250
{
8174 avox 251
        ScText* it = item_p(pos);
6733 avox 252
        if(!it->parstyle) {
8174 avox 253
                it->parstyle = new ParagraphStyle(paragraphStyle(pos+1));
8134 avox 254
                it->parstyle->setContext( & d->pstyleContext);
12689 jghali 255
                // #7432 : when inserting a paragraph separator, apply/erase the trailing Style
12796 pierre 256
                if (pos >= signed(d->len - 1))
12689 jghali 257
                {
258
                        applyStyle(pos, d->trailingStyle);
259
                        d->trailingStyle.erase();
260
                }
8194 avox 261
//              it->parstyle->setName("para"); // DONT TRANSLATE
262
//              it->parstyle->charStyle().setName("cpara"); // DONT TRANSLATE
8134 avox 263
//              it->parstyle->charStyle().setContext( d->defaultStyle.charStyleContext() );
6733 avox 264
        }
8134 avox 265
        d->replaceCharStyleContextInParagraph(pos, it->parstyle->charStyleContext());
5721 avox 266
}
267
/**
268
     need to remove the ParagraphStyle structure and replace all pointers
269
     to it...
270
 */
8174 avox 271
void StoryText::removeParSep(int pos)
5721 avox 272
{
8174 avox 273
        ScText* it = item_p(pos);
5721 avox 274
        if (it->parstyle) {
6733 avox 275
//              const CharStyle* oldP = & it->parstyle->charStyle();
276
//              const CharStyle* newP = & that->paragraphStyle(pos+1).charStyle();
277
//              d->replaceParentStyle(pos, oldP, newP);
5778 avox 278
                delete it->parstyle;
5980 avox 279
                it->parstyle = 0;
5721 avox 280
        }
8134 avox 281
        // demote this parsep so the assert code in replaceCharStyleContextInParagraph()
6904 avox 282
        // doesnt choke:
9737 jghali 283
        it->ch = 0;
8174 avox 284
        d->replaceCharStyleContextInParagraph(pos, paragraphStyle(pos+1).charStyleContext());  
5721 avox 285
}
286
 
4669 avox 287
void StoryText::removeChars(int pos, uint len)
288
{
289
        if (pos < 0)
290
                pos += length();
8049 avox 291
 
4669 avox 292
        assert( len > 0 );
293
        assert( pos >= 0 );
11991 jghali 294
        // This case can be handled more gracefully
295
        // assert( pos + static_cast<int>(len) <= length() );
296
        if (pos >= length())
297
                return;
298
        if (pos + static_cast<int>(len) > length())
299
                len = length() - pos;
4749 avox 300
 
5751 avox 301
        for ( int i=pos + static_cast<int>(len) - 1; i >= pos; --i )
4749 avox 302
        {
5721 avox 303
                ScText *it = d->at(i);
9737 jghali 304
                if ((it->ch == SpecialChars::PARSEP)) {
8174 avox 305
                        removeParSep(i);
4749 avox 306
                }
9737 jghali 307
//              qDebug("remove char %d at %d", (int) it->ch.unicode(), i);
10366 jghali 308
                d->takeAt(i);
5722 avox 309
                d->len--;
4749 avox 310
                delete it;
311
        }
5722 avox 312
 
313
        d->len = d->count();
8049 avox 314
        invalidate(pos, length());
4669 avox 315
}
316
 
9645 avox 317
void StoryText::insertChars(int pos, QString txt, bool applyNeighbourStyle) //, const CharStyle & charstyle)
4669 avox 318
{
319
        if (pos < 0)
8049 avox 320
                pos += length()+1;
4669 avox 321
 
322
        assert(pos >= 0);
323
        assert(pos <= length());
4749 avox 324
 
5365 avox 325
        if (txt.length() == 0)
326
                return;
327
 
8134 avox 328
        const StyleContext* cStyleContext = paragraphStyle(pos).charStyleContext();
9426 avox 329
 
9645 avox 330
        ScText clone;
331
        if (applyNeighbourStyle)
332
        {
10394 cbradney 333
                int referenceChar = qMax(0, qMin(pos, length()-1));
9645 avox 334
                clone.applyCharStyle(charStyle(referenceChar));
335
                clone.setEffects(ScStyle_Default);
336
        }
9607 avox 337
 
8546 cbradney 338
        for (int i = 0; i < txt.length(); ++i) {
9426 avox 339
                ScText * item = new ScText(clone);
9737 jghali 340
                item->ch= txt.at(i);
8134 avox 341
                item->setContext(cStyleContext);
5721 avox 342
                d->insert(pos + i, item);
5722 avox 343
                d->len++;
9737 jghali 344
                if (item->ch == SpecialChars::PARSEP) {
13085 jghali 345
//                      qDebug() << QString("new PARSEP %2 at %1").arg(pos).arg(paragraphStyle(pos).name());
8174 avox 346
                        insertParSep(pos + i);
5721 avox 347
                }
4749 avox 348
        }
349
 
5722 avox 350
        d->len = d->count();
4669 avox 351
        invalidate(pos, pos + txt.length());
352
}
353
 
12093 jghali 354
void StoryText::insertCharsWithSmartHyphens(int pos, QString txt, bool applyNeighbourStyle)
355
{
356
        if (pos < 0)
357
                pos += length()+1;
358
 
359
        assert(pos >= 0);
360
        assert(pos <= length());
361
 
362
        if (txt.length() == 0)
363
                return;
364
 
365
        const StyleContext* cStyleContext = paragraphStyle(pos).charStyleContext();
366
 
367
        ScText clone;
368
        if (applyNeighbourStyle)
369
        {
370
                int referenceChar = qMax(0, qMin(pos, length()-1));
371
                clone.applyCharStyle(charStyle(referenceChar));
372
                clone.setEffects(ScStyle_Default);
373
        }
374
 
375
        int inserted = 0;
376
        for (int i = 0; i < txt.length(); ++i)
377
        {
378
                QChar ch = txt.at(i);
12112 jghali 379
                int  index  = pos + inserted;
12093 jghali 380
                bool insert = true;
12097 jghali 381
                if (ch == SpecialChars::SHYPHEN && index > 0) {
382
                        ScText* lastItem = this->item(index - 1);
13161 malex 383
                        // qreal SHY means user provided SHY, single SHY is automatic one
12093 jghali 384
                        if (lastItem->effects() & ScStyle_HyphenationPossible)
385
                                lastItem->setEffects(lastItem->effects() & ~ScStyle_HyphenationPossible);
386
                        else
387
                        {
388
                                lastItem->setEffects(lastItem->effects() | ScStyle_HyphenationPossible);
389
                                insert = false;
390
                        }
391
                }
392
                if (insert)
393
                {
394
                        ScText * item = new ScText(clone);
395
                        item->ch = ch;
396
                        item->setContext(cStyleContext);
12097 jghali 397
                        d->insert(index, item);
12093 jghali 398
                        d->len++;
399
                        if (item->ch == SpecialChars::PARSEP) {
12097 jghali 400
                                insertParSep(index);
12093 jghali 401
                        }
402
                        ++inserted;
403
                }
404
        }
405
 
406
        d->len = d->count();
407
        invalidate(pos, pos + inserted);
408
}
409
 
4669 avox 410
void StoryText::replaceChar(int pos, QChar ch)
411
{
412
        if (pos < 0)
413
                pos += length();
414
 
415
        assert(pos >= 0);
416
        assert(pos < length());
417
 
5721 avox 418
        ScText* item = d->at(pos);
9737 jghali 419
        if (item->ch == ch)
5721 avox 420
                return;
421
 
9737 jghali 422
        if (d->at(pos)->ch == SpecialChars::PARSEP) {
8174 avox 423
                removeParSep(pos);
5721 avox 424
        }
425
        item->ch = ch;
9737 jghali 426
        if (d->at(pos)->ch == SpecialChars::PARSEP) {
8174 avox 427
                insertParSep(pos);
5721 avox 428
        }
429
 
4669 avox 430
        invalidate(pos, pos + 1);
431
}
432
 
5559 avox 433
void StoryText::hyphenateWord(int pos, uint len, char* hyphens)
434
{
435
        assert(pos >= 0);
5691 avox 436
        assert(pos + signed(len) <= length());
5559 avox 437
 
6940 avox 438
//      QString dump("");
5691 avox 439
        for (int i=pos; i < pos+signed(len); ++i)
6937 avox 440
        {
6940 avox 441
//              dump += d->at(i)->ch;
6937 avox 442
                if(hyphens && hyphens[i-pos] & 1) {
5721 avox 443
                        d->at(i)->setEffects(d->at(i)->effects() | ScStyle_HyphenationPossible);
6940 avox 444
//                      dump += "-";
6937 avox 445
                }
446
                else {
5721 avox 447
                        d->at(i)->setEffects(d->at(i)->effects() & ~ScStyle_HyphenationPossible);
6937 avox 448
                }
449
        }
13085 jghali 450
//      qDebug() << QString("st: %1").arg(dump);
5559 avox 451
        invalidate(pos, pos + len);
452
}
453
 
4669 avox 454
void StoryText::insertObject(int pos, PageItem* ob)
455
{
456
        if (pos < 0)
8049 avox 457
                pos += length()+1;
4669 avox 458
 
459
        insertChars(pos, SpecialChars::OBJECT);
8174 avox 460
        const_cast<StoryText *>(this)->d->at(pos)->embedded = InlineFrame(ob);
8289 avox 461
        ob->isEmbedded = true;   // this might not be enough...
4669 avox 462
}
463
 
464
 
465
int StoryText::length() const
466
{
5722 avox 467
        return d->len;
4669 avox 468
}
469
 
470
QChar StoryText::text(int pos) const
471
{
472
        if (pos < 0)
473
                pos += length();
474
 
475
        assert(pos >= 0);
476
        assert(pos < length());
477
 
9737 jghali 478
        return const_cast<StoryText *>(this)->d->at(pos)->ch;
4669 avox 479
}
480
 
481
QString StoryText::text(int pos, uint len) const
482
{
483
        if (pos < 0)
484
                pos += length();
485
 
486
        assert(pos >= 0);
487
        assert(pos + signed(len) <= length());
488
 
489
        QString result;
5721 avox 490
        StoryText* that(const_cast<StoryText*>(this));
491
        for (int i = pos; i < pos+signed(len); ++i) {
10366 jghali 492
                result += that->d->at(i)->ch;
5721 avox 493
        }
4669 avox 494
 
495
        return result;
496
}
497
 
12093 jghali 498
QString StoryText::textWithSmartHyphens(int pos, uint len) const
499
{
500
        QString result("");
501
        int lastPos = pos;
502
 
503
        len = qMin((uint) (length() - pos), len);
504
        for (int i = pos; i < pos+signed(len); ++i)
505
        {
506
                if (this->charStyle(i).effects() & ScStyle_HyphenationPossible
507
                        // duplicate SHYPHEN if already present to indicate a user provided SHYPHEN:
508
                        || this->text(i) == SpecialChars::SHYPHEN)
509
                {
510
                        result += text(lastPos, i + 1 - lastPos);
511
                        result += SpecialChars::SHYPHEN;
512
                        lastPos = i+1;
513
                }
514
        }
515
        if (lastPos < pos+signed(len))
516
                result += text(lastPos, pos+signed(len) - lastPos);
517
        return result;
518
}
519
 
4669 avox 520
PageItem* StoryText::object(int pos) const
521
{
522
        if (pos < 0)
523
                pos += length();
524
 
525
        assert(pos >= 0);
526
        assert(pos < length());
527
 
8174 avox 528
        StoryText* that = const_cast<StoryText *>(this);
529
        return that->d->at(pos)->embedded.getItem();
4669 avox 530
}
531
 
532
 
533
const CharStyle & StoryText::charStyle(int pos) const
534
{
535
        if (pos < 0)
536
                pos += length();
537
 
538
        assert(pos >= 0);
5732 avox 539
        assert(pos <= length());
4669 avox 540
 
6144 avox 541
        if (length() == 0) {
13085 jghali 542
//              qDebug() << "storytext::charstyle: default";
5732 avox 543
                return defaultStyle().charStyle();
6144 avox 544
        }
545
        else if (pos == length()) {
13144 fschmid 546
                qDebug() << "storytext::charstyle: access at end of text %i" << pos;
5732 avox 547
                --pos;
6144 avox 548
        }
8956 avox 549
        if (text(pos) == SpecialChars::PARSEP)
550
                return paragraphStyle(pos).charStyle();
5732 avox 551
 
4669 avox 552
        StoryText* that = const_cast<StoryText *>(this);
5721 avox 553
        return dynamic_cast<const CharStyle &> (*that->d->at(pos));
4669 avox 554
}
555
 
556
const ParagraphStyle & StoryText::paragraphStyle(int pos) const
557
{
558
        if (pos < 0)
559
                pos += length();
560
 
561
        assert(pos >= 0);
5721 avox 562
        assert(pos <= length());
4669 avox 563
 
6733 avox 564
        assert(d);
565
 
5192 avox 566
        StoryText * that = const_cast<StoryText *> (this);
5721 avox 567
//      assert( that->at(pos)->cab >= 0 );
568
//      assert( that->at(pos)->cab < doc->docParagraphStyles.count() );
569
//      return doc->docParagraphStyles[that->at(pos)->cab];
570
 
10366 jghali 571
        while (pos < length() && that->d->at(pos)->ch != SpecialChars::PARSEP) {
5721 avox 572
                ++pos;
573
        }
6909 avox 574
        if (pos >= length()) {
7232 avox 575
                return that->d->trailingStyle;
5778 avox 576
        }
10366 jghali 577
        else if ( !that->d->at(pos)->parstyle ) {
578
                ScText* current = that->d->at(pos);
10394 cbradney 579
                qDebug("inserting default parstyle at %i", pos);
10366 jghali 580
                current->parstyle = new ParagraphStyle();
581
                current->parstyle->setContext( & d->pstyleContext);
582
//              current->parstyle->setName( "para(paragraphStyle)" ); // DONT TRANSLATE
583
//              current->parstyle->charStyle().setName( "cpara(paragraphStyle)" ); // DONT TRANSLATE
584
//              current->parstyle->charStyle().setContext( d->defaultStyle.charStyleContext());
5721 avox 585
        }
5778 avox 586
        else {
13085 jghali 587
//              qDebug() << QString("using parstyle at %1").arg(pos);
5778 avox 588
        }
10366 jghali 589
        assert (that->d->at(pos)->parstyle);
590
        return *that->d->at(pos)->parstyle;
4669 avox 591
}
592
 
5559 avox 593
const ParagraphStyle& StoryText::defaultStyle() const
594
{
6733 avox 595
        assert(d);
5721 avox 596
        return d->defaultStyle;
5559 avox 597
}
598
 
5569 avox 599
 
600
void StoryText::setDefaultStyle(const ParagraphStyle& style)
601
{
8134 avox 602
        const StyleContext * oldPContext = d->defaultStyle.context();
8289 avox 603
//      const StyleContext * oldCContext = d->defaultStyle.charStyle().context();
5721 avox 604
        d->defaultStyle = style;
8134 avox 605
        d->defaultStyle.setContext( oldPContext );
8194 avox 606
//      d->defaultStyle.setName( "storydefault" ); // DONT TRANSLATE
607
//      d->defaultStyle.charStyle().setName( "cstorydefault" ); // DONT TRANSLATE
13085 jghali 608
//      qDebug() << QString("defstyle %1 context %2 defcstyle %3 ccontext %4 newcontext %5")
8134 avox 609
//                 .arg((uint)&d->defaultStyle,16).arg((uint)oldPContext,16)
610
//                 .arg((uint)&d->defaultStyle.charStyle(),16).arg((uint)oldCContext,16)
13085 jghali 611
//                 .arg((uint)d->defaultStyle.charStyle().context(),16);
8134 avox 612
//      d->defaultStyle.charStyle().setContext( oldCContext );
7958 avox 613
        invalidateAll();
5569 avox 614
}
615
 
616
 
5721 avox 617
void StoryText::applyCharStyle(int pos, uint len, const CharStyle& style )
4669 avox 618
{
619
        if (pos < 0)
620
                pos += length();
621
 
11968 fschmid 622
/* Why do we use an assert here instead of a gracefully return doing nothing ????? */
623
//      assert(pos >= 0);
624
//      assert(pos + signed(len) <= length());
625
        if (pos < 0)
626
                return;
627
        if (pos + signed(len) > length())
628
                return;
4669 avox 629
 
630
        if (len == 0)
631
                return;
632
 
10366 jghali 633
        ScText* itText;
5721 avox 634
        for (uint i=pos; i < pos+len; ++i) {
10366 jghali 635
                itText = d->at(i);
11936 jghali 636
                // #6165 : applying style on last character applies style on whole text on next open 
637
                /*if (itText->ch == SpecialChars::PARSEP && itText->parstyle != NULL)
638
                        itText->parstyle->charStyle().applyCharStyle(style);*/
10366 jghali 639
                itText->applyCharStyle(style);
5721 avox 640
        }
4669 avox 641
 
642
        invalidate(pos, pos + len);
643
}
644
 
5773 avox 645
 
646
 
647
void StoryText::eraseCharStyle(int pos, uint len, const CharStyle& style )
648
{
649
        if (pos < 0)
650
                pos += length();
651
 
652
        assert(pos >= 0);
653
        assert(pos + signed(len) <= length());
654
 
655
        if (len == 0)
656
                return;
657
 
10366 jghali 658
        ScText* itText;
5773 avox 659
        for (uint i=pos; i < pos+len; ++i) {
10366 jghali 660
                itText = d->at(i);
13290 jghali 661
                // FIXME?? see #6165 : should we really erase charstyle of paragraph style??
10366 jghali 662
                if (itText->ch == SpecialChars::PARSEP && itText->parstyle != NULL)
663
                        itText->parstyle->charStyle().eraseCharStyle(style);
664
                itText->eraseCharStyle(style);
5773 avox 665
        }
666
 
667
        invalidate(pos, pos + len);
668
}
669
 
13290 jghali 670
void StoryText::applyStyle(int pos, const ParagraphStyle& style, bool rmDirectFormatting)
4669 avox 671
{
672
        if (pos < 0)
673
                pos += length();
674
 
675
        assert(pos >= 0);
5721 avox 676
        assert(pos <= length());
4669 avox 677
 
5721 avox 678
        int i = pos;
9737 jghali 679
        while (i < length() && d->at(i)->ch != SpecialChars::PARSEP) {
5184 avox 680
                ++i;
681
        }
5721 avox 682
        if (i < length()) {
683
                if (!d->at(i)->parstyle) {
10394 cbradney 684
                        qDebug("PARSEP without style at pos %i", i);
5980 avox 685
                        d->at(i)->parstyle = new ParagraphStyle();
8134 avox 686
                        d->at(i)->parstyle->setContext( & d->pstyleContext);
8194 avox 687
//                      d->at(i)->parstyle->setName( "para(applyStyle)" ); // DONT TRANSLATE
688
//                      d->at(i)->parstyle->charStyle().setName( "cpara(applyStyle)" ); // DONT TRANSLATE
8134 avox 689
//                      d->at(i)->parstyle->charStyle().setContext( d->defaultStyle.charStyleContext() );
5721 avox 690
                }
13085 jghali 691
//              qDebug() << QString("applying parstyle %2 at %1 for %3").arg(i).arg(paragraphStyle(pos).name()).arg(pos);
5721 avox 692
                d->at(i)->parstyle->applyStyle(style);
693
        }
694
        else {
695
                // not happy about this but inserting a new PARSEP makes more trouble
13085 jghali 696
//              qDebug() << QString("applying parstyle %1 as defaultstyle for %2").arg(paragraphStyle(pos).name()).arg(pos);
7232 avox 697
                d->trailingStyle.applyStyle(style);
5721 avox 698
        }
13290 jghali 699
        if (rmDirectFormatting)
700
        {
701
                --i;
702
                while (i >= 0 && d->at(i)->ch != SpecialChars::PARSEP)
703
                {
704
                        d->at(i)->eraseDirectFormatting();
705
                        --i;
706
                }
707
        }
8562 jghali 708
        invalidate(pos, qMin(i, length()));
4669 avox 709
}
710
 
5773 avox 711
void StoryText::eraseStyle(int pos, const ParagraphStyle& style)
712
{
713
        if (pos < 0)
714
                pos += length();
715
 
716
        assert(pos >= 0);
717
        assert(pos <= length());
718
 
719
        int i = pos;
9737 jghali 720
        while (i < length() && d->at(i)->ch != SpecialChars::PARSEP) {
5773 avox 721
                ++i;
722
        }
723
        if (i < length()) {
724
                if (!d->at(i)->parstyle) {
10394 cbradney 725
                        qDebug("PARSEP without style at pos %i", i);
5980 avox 726
                        d->at(i)->parstyle = new ParagraphStyle();
8134 avox 727
                        d->at(i)->parstyle->setContext( & d->pstyleContext);
8194 avox 728
//                      d->at(i)->parstyle->setName( "para(eraseStyle)" ); // DONT TRANSLATE
729
//                      d->at(i)->parstyle->charStyle().setName( "cpara(eraseStyle)" ); // DONT TRANSLATE
8134 avox 730
//                      d->at(i)->parstyle->charStyle().setContext( d->defaultStyle.charStyleContext());
5773 avox 731
                }
13085 jghali 732
                //              qDebug() << QString("applying parstyle %2 at %1 for %3").arg(i).arg(paragraphStyle(pos).name()).arg(pos);
5773 avox 733
                d->at(i)->parstyle->eraseStyle(style);
734
        }
735
        else {
736
                // not happy about this but inserting a new PARSEP makes more trouble
13085 jghali 737
                //              qDebug() << QString("applying parstyle %1 as defaultstyle for %2").arg(paragraphStyle(pos).name()).arg(pos);
7232 avox 738
                d->trailingStyle.eraseStyle(style);
5773 avox 739
        }
8562 jghali 740
        invalidate(pos, qMin(i, length()));
5773 avox 741
}
742
 
743
 
6733 avox 744
void StoryText::setStyle(int pos, const ParagraphStyle& style)
745
{
746
        eraseStyle(pos, paragraphStyle(pos));
747
        applyStyle(pos, style);
748
}
749
 
750
 
751
void StoryText::setCharStyle(int pos, uint len, const CharStyle& style)
752
{
9067 avox 753
        if (pos < 0)
754
                pos += length();
755
 
756
        assert(pos >= 0);
9645 avox 757
        assert(len <= unsigned(length()));
9067 avox 758
        assert(pos + signed(len) <= length());
759
 
760
        if (len == 0)
761
                return;
762
 
10366 jghali 763
        ScText* itText;
9067 avox 764
        for (uint i=pos; i < pos+len; ++i) {
10366 jghali 765
                itText = d->at(i);
11936 jghali 766
                // #6165 : applying style on last character applies style on whole text on next open 
767
                /*if (itText->ch == SpecialChars::PARSEP && itText->parstyle != NULL)
768
                        itText->parstyle->charStyle() = style;*/
10366 jghali 769
                itText->setStyle(style);
9067 avox 770
        }
771
 
772
        invalidate(pos, pos + len);
6733 avox 773
}
774
 
775
 
8455 avox 776
 
777
void StoryText::getNamedResources(ResourceCollection& lists) const
778
{
8938 avox 779
        d->defaultStyle.getNamedResources(lists);
780
        d->trailingStyle.getNamedResources(lists);
781
 
8455 avox 782
        for (int i=0; i < length(); ++i)
783
        {
784
                if (text(i) == SpecialChars::PARSEP)
785
                        paragraphStyle(i).getNamedResources(lists);
786
                else if (text(i) == SpecialChars::OBJECT)
787
                        object(i)->getNamedResources(lists);
788
                else
789
                        charStyle(i).getNamedResources(lists);
790
        }
791
}
792
 
793
 
7442 avox 794
void StoryText::replaceStyles(QMap<QString,QString> newNameForOld)
795
{
8455 avox 796
        ResourceCollection newnames;
8775 cbradney 797
        newnames.mapStyles(newNameForOld);
8455 avox 798
        replaceNamedResources(newnames);
799
}
800
 
801
void StoryText::replaceNamedResources(ResourceCollection& newNames)
802
{
7442 avox 803
        int len = length();
8455 avox 804
 
805
        d->defaultStyle.replaceNamedResources(newNames);
806
        d->trailingStyle.replaceNamedResources(newNames);
807
 
7442 avox 808
        if (len == 0)
809
                return;
810
 
10366 jghali 811
        ScText* itText;
7501 avox 812
        for (int i=0; i < len; ++i) {
10366 jghali 813
                itText = d->at(i);
814
                if (itText->parstyle)
815
                        itText->parstyle->replaceNamedResources(newNames);
8455 avox 816
                else
10366 jghali 817
                        itText->replaceNamedResources(newNames);
7442 avox 818
        }
819
 
820
        invalidate(0, len);    
821
}
822
 
8455 avox 823
 
7442 avox 824
void StoryText::replaceCharStyles(QMap<QString,QString> newNameForOld)
825
{
8455 avox 826
        ResourceCollection newnames;
8775 cbradney 827
        newnames.mapCharStyles(newNameForOld);
8455 avox 828
        replaceNamedResources(newnames);
7442 avox 829
}
830
 
8455 avox 831
 
10623 avox 832
int StoryText::nrOfParagraph(uint index) const
833
{
10643 fschmid 834
        int result = 0;
10623 avox 835
        StoryText* that = const_cast<StoryText *>(this);
836
        bool lastWasPARSEP = true;
11359 jghali 837
        index = qMin(index, (uint) that->length());
11229 fschmid 838
        for (uint i=0; i < index; ++i) {
10623 avox 839
                lastWasPARSEP = that->d->at(i)->ch == SpecialChars::PARSEP;
840
                if (lastWasPARSEP)
841
                        ++result;
842
        }
11380 jghali 843
        return result;
10623 avox 844
}
845
 
4669 avox 846
uint StoryText::nrOfParagraphs() const
847
{
848
        uint result = 0;
5721 avox 849
        StoryText* that = const_cast<StoryText *>(this);
7059 avox 850
        bool lastWasPARSEP = true;
5721 avox 851
        for (int i=0; i < length(); ++i) {
10366 jghali 852
                lastWasPARSEP = that->d->at(i)->ch == SpecialChars::PARSEP;
6887 avox 853
                if (lastWasPARSEP)
4669 avox 854
                        ++result;
5721 avox 855
        }
11359 jghali 856
        return lastWasPARSEP ? result : result + 1;
4669 avox 857
}
858
 
859
int StoryText::startOfParagraph(uint index) const
860
{
861
        if (index == 0)
862
                return 0;
863
 
5184 avox 864
        StoryText* that = const_cast<StoryText *>(this);
5721 avox 865
        for (int i=0; i < length(); ++i) {
10366 jghali 866
                if (that->d->at(i)->ch == SpecialChars::PARSEP && ! --index)
4669 avox 867
                        return i + 1;
5721 avox 868
        }
6887 avox 869
        return length();
4669 avox 870
}
871
 
872
int StoryText::endOfParagraph(uint index) const
873
{
874
        ++index;
5184 avox 875
        StoryText* that = const_cast<StoryText *>(this);
5721 avox 876
        for (int i=0; i < length(); ++i) {
10366 jghali 877
                if (that->d->at(i)->ch == SpecialChars::PARSEP && ! --index)
5721 avox 878
                        return i;
879
        }
4669 avox 880
        return length();
881
}
882
 
883
uint StoryText::nrOfRuns() const
884
{
5464 avox 885
        return length();
4669 avox 886
}
887
 
888
int StoryText::startOfRun(uint index) const
889
{
5464 avox 890
        return index;
4669 avox 891
}
892
 
893
int StoryText::endOfRun(uint index) const
894
{
5464 avox 895
        return index + 1;
4669 avox 896
}
897
 
7501 avox 898
// positioning. all positioning methods return char positions
899
// FIXME: make that methods use correct semantic boundaries
4669 avox 900
 
7501 avox 901
static QString wordBoundaries(" .,:;\"'!?\n");
902
static QString sentenceBoundaries(".:!?\n");
903
 
904
int StoryText::nextChar(int pos)
905
{
906
        if (pos < length())
907
                return pos+1;
908
        else
909
                return length();
910
}
911
int StoryText::prevChar(int pos)
912
{
913
        if (pos > 0)
914
                return pos - 1;
915
        else
916
                return 0;
917
}
918
int StoryText::nextWord(int pos)
919
{
920
        int len = length();
8562 jghali 921
        pos = qMin(len, pos+1);
10394 cbradney 922
        while (pos < len  && wordBoundaries.indexOf(text(pos)) < 0)
7501 avox 923
                ++pos;
924
        return pos < len ? pos + 1 : pos;
925
}
926
int StoryText::prevWord(int pos)
927
{
8562 jghali 928
        pos = qMax(0, pos-1);
10394 cbradney 929
        while (pos > 0 && wordBoundaries.indexOf(text(pos)) < 0)
7501 avox 930
                --pos;
10394 cbradney 931
        return wordBoundaries.indexOf(text(pos)) < 0 ? pos + 1 : pos;
7501 avox 932
}
933
int StoryText::nextSentence(int pos)
934
{
935
        int len = length();
8562 jghali 936
        pos = qMin(len, pos+1);
10394 cbradney 937
        while (pos < len && sentenceBoundaries.indexOf(text(pos)) < 0)
7501 avox 938
                ++pos;
939
        return pos < len ? pos + 1 : pos;
940
}
941
int StoryText::prevSentence(int pos)
942
{
8562 jghali 943
        pos = qMax(0, pos-1);
10394 cbradney 944
        while (pos > 0 && sentenceBoundaries.indexOf(text(pos)) < 0)
7501 avox 945
                --pos;
10394 cbradney 946
        return sentenceBoundaries.indexOf(text(pos)) < 0 ? pos + 1 : pos;
7501 avox 947
}
948
int StoryText::nextParagraph(int pos)
949
{
950
        int len = length();
8562 jghali 951
        pos = qMin(len, pos+1);
7501 avox 952
        while (pos < len && text(pos) != SpecialChars::PARSEP)
953
                ++pos;
7637 avox 954
        return pos;
7501 avox 955
}
956
int StoryText::prevParagraph(int pos)
957
{
8562 jghali 958
        pos = qMax(0, pos-1);
7501 avox 959
        while (pos > 0 && text(pos) != SpecialChars::PARSEP)
960
                --pos;
7637 avox 961
        return pos;
7501 avox 962
}
963
 
964
// these need valid layout:
965
 
966
int StoryText::startOfLine(int pos)
967
{
8546 cbradney 968
        for (int i=0; i < m_lines.count(); ++i) {
7501 avox 969
                const LineSpec & ls(m_lines.at(i));
970
                if (ls.firstItem <= pos && pos <= ls.lastItem)
971
                        return ls.firstItem;
972
        }
973
        return 0;
974
}
975
int StoryText::endOfLine(int pos)
976
{
8546 cbradney 977
        for (int i=0; i < m_lines.count(); ++i) {
7501 avox 978
                const LineSpec & ls(m_lines.at(i));
979
                if (ls.firstItem <= pos && pos <= ls.lastItem)
7657 avox 980
                        return text(ls.lastItem) == SpecialChars::PARSEP ? ls.lastItem :
981
                                text(ls.lastItem) == ' ' ? ls.lastItem : ls.lastItem + 1;
7501 avox 982
        }
983
        return length();
984
}
985
int StoryText::prevLine(int pos)
986
{
8546 cbradney 987
        for (int i=0; i < m_lines.count(); ++i)
7501 avox 988
        {
989
                // find line for pos
990
                const LineSpec & ls(m_lines.at(i));
991
                if (ls.firstItem <= pos && pos <= ls.lastItem)
992
                {
7522 avox 993
                        if (i == 0)
994
                                return startOfLine(pos);
7501 avox 995
                        // find current xpos
13161 malex 996
                        qreal xpos = 0.0;
7501 avox 997
                        for (int j = ls.firstItem; j < pos; ++j)
998
                                xpos += item(j)->glyph.wide();
999
                        if (pos != m_lastMagicPos || xpos > m_magicX)
1000
                                m_magicX = xpos;
1001
                        const LineSpec & ls2(m_lines.at(i-1));
1002
                        // find new cpos
1003
                        xpos = 0.0;
1004
                        for (int j = ls2.firstItem; j <= ls2.lastItem; ++j)
1005
                        {
1006
                                xpos += item(j)->glyph.wide();
1007
                                if (xpos > m_magicX) {
1008
                                        m_lastMagicPos = j;
1009
                                        return j;
1010
                                }
1011
                        }
1012
                        m_lastMagicPos = ls2.lastItem;
1013
                        return ls2.lastItem;
1014
                }
1015
        }
1016
        return firstFrameItem;
1017
}
1018
 
1019
int StoryText::nextLine(int pos)
1020
{
8546 cbradney 1021
        for (int i=0; i < m_lines.count(); ++i)
7501 avox 1022
        {
1023
                // find line for pos
1024
                const LineSpec & ls(m_lines.at(i));
1025
                if (ls.firstItem <= pos && pos <= ls.lastItem)
1026
                {
7522 avox 1027
                        if (i+1 == m_lines.count())
1028
                                return endOfLine(pos);
7501 avox 1029
                        // find current xpos
13161 malex 1030
                        qreal xpos = 0.0;
7501 avox 1031
                        for (int j = ls.firstItem; j < pos; ++j)
1032
                                xpos += item(j)->glyph.wide();
1033
                        if (pos != m_lastMagicPos || xpos > m_magicX)
1034
                                m_magicX = xpos;
1035
                        const LineSpec & ls2(m_lines.at(i+1));
1036
                        // find new cpos
1037
                        xpos = 0.0;
1038
                        for (int j = ls2.firstItem; j <= ls2.lastItem; ++j)
1039
                        {
1040
                                xpos += item(j)->glyph.wide();
1041
                                if (xpos > m_magicX) {
1042
                                        m_lastMagicPos = j;
1043
                                        return j;
1044
                                }
1045
                        }
1046
                        m_lastMagicPos = ls2.lastItem + 1;
1047
                        return ls2.lastItem + 1;
1048
                }
1049
        }
1050
        return lastFrameItem;
1051
}
1052
 
1053
int StoryText::startOfFrame(int pos)
1054
{
1055
        return firstFrameItem;
1056
}
1057
int StoryText::endOfFrame(int pos)
1058
{
7637 avox 1059
        return lastFrameItem + 1;
7501 avox 1060
}
1061
 
4669 avox 1062
// selection
1063
 
1064
int StoryText::startOfSelection() const
1065
{
1066
        return selFirst <= selLast? selFirst : 0;
1067
}
1068
 
1069
int StoryText::endOfSelection() const
1070
{
1071
        return selFirst <= selLast? selLast + 1 : -1;
1072
}
1073
 
1074
int StoryText::lengthOfSelection() const
1075
{
1076
        return selFirst <= selLast? selLast - selFirst + 1 : 0;
1077
}
1078
 
1079
 
1080
bool StoryText::selected(int pos) const
1081
{
4749 avox 1082
        return (selFirst <= pos && pos <= selLast)
5721 avox 1083
//             || (pos >= 0 && pos < length() && const_cast<StoryText*>(this)->d->at(pos)->cselect)
1084
        ;
4669 avox 1085
}
1086
 
13054 pierre 1087
 
1088
int StoryText::selectWord(int pos)
1089
{
1090
        //Double click in a frame to select a word
1091
 
1092
        int a = pos;
1093
        while(a > 0)
1094
        {
1095
                if (text(a-1).isLetterOrNumber())
1096
                        --a;
1097
                else
1098
                        break;
1099
        }
1100
        int b = pos;
1101
        while(b < length())
1102
        {
1103
                if (text(b).isLetterOrNumber())
1104
                        ++b;
1105
                else
1106
                        break;
1107
        }
1108
        select(a, b - a);
1109
        return a;
1110
}
1111
 
1112
 
4669 avox 1113
void StoryText::select(int pos, uint len, bool on)
1114
{
1115
        if (pos < 0)
1116
                pos += length();
1117
 
1118
        assert( pos >= 0 );
1119
        assert( pos + signed(len) <= length() );
1120
 
5751 avox 1121
//      qDebug("old selection: %d - %d", selFirst, selLast);
1122
 
5721 avox 1123
//      StoryText* that = const_cast<StoryText *>(this);
1124
//      for (int i=pos; i < pos+signed(len); ++i)
1125
//              that->at(i)->cselect = on;
4669 avox 1126
 
1127
        if (on) {
1128
                // extend if possible
1129
                if (selected(pos - 1))
8562 jghali 1130
                        selLast = qMax(selLast, pos + static_cast<int>(len) - 1);
4669 avox 1131
                else if (selected(pos + len))
8562 jghali 1132
                        selFirst = qMin(selFirst, pos);
4669 avox 1133
                else {
1134
                        selFirst = pos;
1135
                        selLast = pos + len - 1;
1136
                }
1137
        }
1138
        else {
1139
                if (pos <= selFirst && selLast < pos + signed(len))
1140
                        deselectAll();
1141
                // shrink
1142
                else if (!selected(pos - 1) && selected(pos + len - 1))
1143
                        selFirst = pos + len;
1144
                else if (selected(pos) && !selected(pos + len))
1145
                        selLast = pos - 1;
1146
                else if (selected(pos) || selected(pos + len - 1))
1147
                        // Grr, deselection splits selection
1148
                        selLast = pos - 1;
1149
        }
5751 avox 1150
 
1151
//      qDebug("new selection: %d - %d", selFirst, selLast);
4669 avox 1152
}
1153
 
13054 pierre 1154
void StoryText::extendSelection(int oldPos, int newPos)
1155
{
1156
        if (selFirst <= selLast)
1157
        {
1158
                // have selection
1159
                if (selLast == oldPos - 1)
1160
                {
1161
                        selLast = newPos - 1;
1162
                        return;
1163
                }
1164
                else if (selFirst == oldPos)
1165
                {
1166
                        selFirst = newPos;
1167
                        return;
1168
                }
1169
                // can't extend, fall through
1170
        }
1171
        // no previous selection
1172
        if (newPos > oldPos)
1173
        {
1174
                selFirst = oldPos;
1175
                selLast = newPos - 1;
1176
        }
1177
        else
1178
        {
1179
                selFirst = newPos;
1180
                selLast = oldPos - 1;
1181
        }
1182
}
1183
 
4669 avox 1184
void StoryText::selectAll()
1185
{
5721 avox 1186
/*      StoryText* that = const_cast<StoryText *>(this);
1187
        that->at(0);
1188
        for (int i=0; i < length(); ++i) {
1189
                that->current()->cselect = true;
1190
                that->next();
1191
        }
1192
*/
4669 avox 1193
        selFirst = 0;
1194
        selLast = length() - 1;
1195
}
1196
 
1197
void StoryText::deselectAll()
1198
{
5721 avox 1199
/*      StoryText* that = const_cast<StoryText *>(this);
1200
        that->at(0);
1201
        for (int i=0; i < length(); ++i) {
1202
                that->current()->cselect = false;
1203
                that->next();
1204
        }
1205
*/     
4669 avox 1206
        selFirst = 0;
1207
        selLast = -1;
1208
}
1209
 
1210
void StoryText::removeSelection()
1211
{
5751 avox 1212
//      qDebug("removeSelection: %d - %d", selFirst, selLast);
4669 avox 1213
        if (selFirst > selLast)
1214
                return;
1215
 
1216
        assert( selFirst >= 0 );
1217
        assert( selLast < length() );
1218
 
1219
        removeChars(selFirst, selLast - selFirst+1);
1220
        deselectAll();
1221
}
1222
 
1223
 
1224
 
1225
void StoryText::invalidateObject(const PageItem * embedded)
1226
{
1227
}
1228
 
1229
void StoryText::invalidateLayout()
1230
{
1231
}
1232
 
1233
void StoryText::invalidateAll()
1234
{
8134 avox 1235
        d->pstyleContext.invalidate();
7958 avox 1236
        invalidate(0, nrOfItems());
4669 avox 1237
}
1238
 
7958 avox 1239
void StoryText::invalidate(int firstItem, int endItem)
4669 avox 1240
{
7958 avox 1241
        for (int i=firstItem; i < endItem; ++i) {
1242
                ParagraphStyle* par = item(i)->parstyle;
1243
                if (par)
8134 avox 1244
                        par->charStyleContext()->invalidate();
7958 avox 1245
        }
13148 pierre 1246
        emit changed();
4669 avox 1247
}
1248
 
1249
 
1250
// physical view
1251
 
1252
/*
1253
void StoryText::validate()
1254
{
1255
        static bool withinValidate = false;
1256
 
1257
        assert( !withinValidate );
1258
        withinValidate = true;
1259
 
1260
        withinValidate = false;
1261
}
1262
*/
1263
 
1264
int StoryText::screenToPosition(FPoint coord) const
1265
{
13161 malex 1266
        qreal maxx = coord.x() - 1.0;
6144 avox 1267
        for (unsigned int i=0; i < lines(); ++i)
1268
        {
1269
                LineSpec ls = line(i);
13085 jghali 1270
//              qDebug() << QString("screenToPosition: (%1,%2) -> y %3 - %4 + %5").arg(coord.x()).arg(coord.y()).arg(ls.y).arg(ls.ascent).arg(ls.descent);
6144 avox 1271
                if (ls.y + ls.descent < coord.y())
1272
                        continue;
13161 malex 1273
                qreal xpos = ls.x;
7501 avox 1274
                for (int j = ls.firstItem; j <= ls.lastItem; ++j) {
13085 jghali 1275
//                              qDebug() << QString("screenToPosition: (%1,%2) -> x %3 + %4").arg(coord.x()).arg(coord.y()).arg(xpos).arg(item(j)->glyph.wide());
13161 malex 1276
                        qreal width = item(j)->glyph.wide();
7501 avox 1277
                        xpos += width;
1278
                        if (xpos >= coord.x())
1279
                                return xpos - width/2 > coord.x() ? j : j+1;
6144 avox 1280
                }
7501 avox 1281
                if (xpos > maxx)
1282
                        maxx = xpos;
1283
                if (xpos + 1.0 > coord.x()) // allow 1pt after end of line
1284
                        return ls.lastItem + 1;
13054 pierre 1285
                else if (coord.x() <= ls.x + ls.width) // last line of paragraph?
1286
                        return ls.lastItem;
7501 avox 1287
                else if (xpos < ls.x + 0.01 && maxx >= coord.x()) // check for empty line
1288
                        return ls.firstItem;
6144 avox 1289
        }
8562 jghali 1290
        return qMax(lastFrameItem+1, firstFrameItem);
4669 avox 1291
}
1292
 
1293
 
6144 avox 1294
FRect StoryText::boundingBox(int pos, uint len) const
4669 avox 1295
{
6144 avox 1296
        FRect result;
8922 avox 1297
        LineSpec ls;
6144 avox 1298
        for (uint i=0; i < lines(); ++i)
1299
        {
8922 avox 1300
                ls = line(i);
6144 avox 1301
                if (ls.lastItem < pos)
1302
                        continue;
1303
                if (ls.firstItem <= pos) {
9165 avox 1304
                        /*
1305
                        if (ls.lastItem == pos && (item(pos)->effects() & ScStyle_SuppressSpace)  )
8922 avox 1306
                        {
1307
                                if (i+1 < lines())
1308
                                {
1309
                                        ls = line(i+1);
1310
                                        result.setRect(ls.x, ls.y - ls.ascent, 1, ls.ascent + ls.descent);
1311
                                }
1312
                                else
1313
                                {
1314
                                        ls = line(lines()-1);
8931 cbradney 1315
                                        const ParagraphStyle& pstyle(paragraphStyle(pos));
1316
                                        result.setRect(ls.x, ls.y + pstyle.lineSpacing() - ls.ascent, 1, ls.ascent + ls.descent);
8922 avox 1317
                                }
1318
                        }
9165 avox 1319
                        else */
8922 avox 1320
                        {
13161 malex 1321
                                qreal xpos = ls.x;
8922 avox 1322
                                for (int j = ls.firstItem; j < pos; ++j)
12309 fschmid 1323
                                {
1324
                                        if (item(j)->ch == SpecialChars::OBJECT)
12317 fschmid 1325
                                                xpos += (object(j)->gWidth + object(j)->lineWidth()) * item(j)->glyph.scaleH;
12309 fschmid 1326
                                        else
1327
                                                xpos += item(j)->glyph.wide();
1328
                                }
13161 malex 1329
                                qreal finalw = 1;
12309 fschmid 1330
                                if (item(pos)->ch == SpecialChars::OBJECT)
12317 fschmid 1331
                                        finalw = (object(pos)->gWidth + object(pos)->lineWidth()) * item(pos)->glyph.scaleH;
12309 fschmid 1332
                                else
1333
                                        finalw = item(pos)->glyph.wide();
13061 pierre 1334
                                const CharStyle& cs(charStyle(pos));
13161 malex 1335
                                qreal desc = -cs.font().descent(cs.fontSize() / 10.0);
1336
                                qreal asce = cs.font().ascent(cs.fontSize() / 10.0);
13061 pierre 1337
                                result.setRect(xpos, ls.y - asce, pos < length()? finalw : 1, desc+asce);
8922 avox 1338
                        }
9165 avox 1339
                        return result;
6144 avox 1340
                }
1341
        }
12796 pierre 1342
        const ParagraphStyle& pstyle(paragraphStyle(qMin(pos, length()))); // rather the trailing style than a segfault.
9165 avox 1343
        if (lines() > 0)
1344
        {
1345
                ls = line(lines()-1);          
1346
                result.setRect(ls.x, ls.y + pstyle.lineSpacing() - ls.ascent, 1, ls.ascent + ls.descent);
1347
        }
1348
        else
1349
        {
1350
                result.setRect(1, 1, 1, pstyle.lineSpacing());
1351
        }      
6144 avox 1352
        return result;
4669 avox 1353
}
1354
 
1355
int StoryText::layout(int startItem)
1356
{
1357
        //FIXME:NLS
1358
        return -1;
1359
}
1360
 
1361
 
1362
uint StoryText::nrOfItems() const
1363
{
1364
        return length();
1365
}
1366
 
1367
 
1368
ScText*  StoryText::item(uint itm)
1369
{
1370
        assert( static_cast<int>(itm) < length() );
5721 avox 1371
        return const_cast<StoryText *>(this)->d->at(itm);
4669 avox 1372
}
1373
 
6144 avox 1374
 
1375
const ScText*  StoryText::item(uint itm) const
1376
{
1377
        assert( static_cast<int>(itm) < length() );
1378
        return const_cast<StoryText *>(this)->d->at(itm);
1379
}
1380
 
7442 avox 1381
 
4669 avox 1382
const QString StoryText::itemText(uint itm) const
1383
{
1384
 
1385
        assert( static_cast<int>(itm) < length() );
1386
 
1387
        return text(itm, 1);
1388
}
1389
 
1390
 
1391
const CharStyle StoryText::itemStyle(uint itm) const
1392
{
1393
        assert( static_cast<int>(itm) < length() );
1394
 
1395
        return charStyle(itm);
1396
}
1397
 
1398
 
1399
int StoryText::startOfItem(uint itm) const
1400
{
1401
        assert( static_cast<int>(itm) < length() );
1402
 
1403
        return itm;
1404
}
1405
 
1406
int StoryText::endOfItem(uint itm) const
1407
{
1408
        assert( static_cast<int>(itm) < length() );
1409
 
1410
        return itm + 1;
1411
}
1412
 
8194 avox 1413
 
8266 avox 1414
using namespace desaxe;
8194 avox 1415
 
8800 jghali 1416
void StoryText::saxx(SaxHandler& handler, const Xml_string& elemtag) const
8194 avox 1417
{
1418
        Xml_attr empty;
1419
        Xml_attr pageno;
1420
        pageno.insert("name", "pgno");
11713 fschmid 1421
        Xml_attr pageco;
1422
        pageco.insert("name", "pgco");
8194 avox 1423
 
8266 avox 1424
        handler.begin(elemtag, empty);
1425
        defaultStyle().saxx(handler, "defaultstyle");
8194 avox 1426
 
8398 avox 1427
        CharStyle lastStyle(charStyle(0));
8194 avox 1428
        bool lastWasPar = true;
1429
        int lastPos = 0;
8398 avox 1430
        handler.begin("p", empty);
1431
        paragraphStyle(0).saxx(handler);
1432
        handler.begin("span", empty);
1433
        lastStyle.saxx(handler);
8194 avox 1434
        for (int i=0; i < length(); ++i)
1435
        {
1436
                const QChar curr(text(i));
1437
                const CharStyle& style(charStyle(i));
1438
 
1439
                if (curr == SpecialChars::OBJECT ||
1440
                        curr == SpecialChars::TAB ||
1441
                        curr == SpecialChars::PARSEP ||
1442
                        curr == SpecialChars::LINEBREAK ||
1443
                        curr == SpecialChars::COLBREAK ||
1444
                        curr == SpecialChars::FRAMEBREAK ||
1445
                        curr == SpecialChars::PAGENUMBER ||
11713 fschmid 1446
                        curr == SpecialChars::PAGECOUNT ||
8194 avox 1447
                        curr.unicode() < 32 ||
1448
                        (0xd800 <= curr.unicode() && curr.unicode() < 0xe000) ||
1449
                        curr.unicode() == 0xfffe || curr.unicode() == 0xffff ||
1450
                        style != lastStyle)
1451
                {
1452
                        // something new, write pending chars
1453
                        if  (i - lastPos > 0)
1454
                        {
12093 jghali 1455
                                handler.chars(textWithSmartHyphens(lastPos, i-lastPos));
8194 avox 1456
                        }
1457
                        lastPos = i;
1458
                }
1459
 
1460
                lastWasPar = (curr == SpecialChars::PARSEP);
1461
                if (lastWasPar)
1462
                {
8398 avox 1463
                        handler.end("span");
1464
                        handler.end("p");
1465
                        handler.begin("p", empty);
8913 avox 1466
                        paragraphStyle(i+1).saxx(handler);
8398 avox 1467
                        handler.begin("span", empty);
12962 jghali 1468
                        lastStyle.erase();
8194 avox 1469
                }
1470
                else if (curr == SpecialChars::OBJECT && object(i) != NULL)
1471
                {
1472
                        object(i)->saxx(handler);
1473
                }
1474
                else if (curr == SpecialChars::TAB)
1475
                {
8266 avox 1476
                        handler.beginEnd("tab", empty);
8194 avox 1477
                }
1478
                else if (curr == SpecialChars::LINEBREAK)
1479
                {
8266 avox 1480
                        handler.beginEnd("breakline", empty);
8194 avox 1481
                }
1482
                else if (curr == SpecialChars::COLBREAK)
1483
                {
8266 avox 1484
                        handler.beginEnd("breakcol", empty);
8194 avox 1485
                }
1486
                else if (curr == SpecialChars::FRAMEBREAK)
1487
                {
8266 avox 1488
                        handler.beginEnd("breakframe", empty);
8194 avox 1489
                }
1490
                else if (curr == SpecialChars::PAGENUMBER)
1491
                {
8266 avox 1492
                        handler.beginEnd("var", pageno);
8194 avox 1493
                }
11713 fschmid 1494
                else if (curr == SpecialChars::PAGECOUNT)
1495
                {
1496
                        handler.beginEnd("var", pageco);
1497
                }
8194 avox 1498
                else if (curr.unicode() < 32 ||
1499
                                 (0xd800 <= curr.unicode() && curr.unicode() < 0xe000) ||
1500
                                 curr.unicode() == 0xfffe || curr.unicode() == 0xffff)
1501
                {
1502
                        Xml_attr unic;
8266 avox 1503
                        unic.insert("code", toXMLString(curr.unicode()));
1504
                        handler.beginEnd("unicode", unic);
8194 avox 1505
                }
1506
                else if (lastStyle != style)
1507
                {
8398 avox 1508
                        handler.end("span");
1509
                        handler.begin("span", empty);
8194 avox 1510
                        style.saxx(handler);
1511
                        lastStyle = style;
1512
                        continue;
1513
                }
1514
                else
1515
                        continue;
1516
                lastPos = i+1;
1517
        }
1518
 
1519
        if  (length() - lastPos > 0)
12093 jghali 1520
                handler.chars(textWithSmartHyphens(lastPos, length()-lastPos));
8398 avox 1521
        handler.end("span");
1522
        handler.end("p");
8194 avox 1523
 
8398 avox 1524
//      if (!lastWasPar)
1525
//              paragraphStyle(length()-1).saxx(handler);
8194 avox 1526
 
8266 avox 1527
        handler.end(elemtag);
8194 avox 1528
 
1529
}
1530
 
8266 avox 1531
 
1532
class AppendText_body : public Action_body
1533
{
1534
public:
8834 cbradney 1535
        void chars(const Xml_string& txt)
8266 avox 1536
        {
12093 jghali 1537
                QChar chr;
1538
                int   lastPos = 0, len;
8266 avox 1539
                StoryText* obj = this->dig->top<StoryText>();
12093 jghali 1540
                for (int i = 0; i < txt.length(); ++i)
1541
                {
1542
                        chr = txt.at(i);
1543
                        if (chr == SpecialChars::SHYPHEN && i > 0)
1544
                        {
1545
                                int toInsert = i - lastPos;
1546
                                if (toInsert > 0)
1547
                                        obj->insertChars(obj->length(), txt.mid(lastPos, toInsert));
1548
                                len = obj->length();
1549
                                ScText* lastItem = obj->item(len-1);
13161 malex 1550
                                // qreal SHY means user provided SHY, single SHY is automatic one
12093 jghali 1551
                                if (lastItem->effects() & ScStyle_HyphenationPossible)
1552
                                {
1553
                                        lastItem->setEffects(lastItem->effects() & ~ScStyle_HyphenationPossible);
1554
                                        obj->insertChars(len, QString(chr));
1555
                                }
1556
                                else
1557
                                {
1558
                                        lastItem->setEffects(lastItem->effects() | ScStyle_HyphenationPossible);
1559
                                }
1560
                                lastPos = i + 1;
1561
                        }
1562
                }
1563
                if (lastPos < txt.length())
1564
                {
1565
                        QString ins = (lastPos == 0) ? txt : txt.right(txt.length() - lastPos);
1566
                        len = obj->length();
1567
                        obj->insertChars(len, ins);
1568
                }
8266 avox 1569
        }
1570
};
1571
 
1572
struct  AppendText : public MakeAction<AppendText_body>
1573
{};
1574
 
1575
 
1576
class AppendSpecial_body : public Action_body
1577
{
1578
public:
1579
        AppendSpecial_body(QChar sp) : chr(sp) {}
1580
 
8834 cbradney 1581
        void begin(const Xml_string& tag, Xml_attr attr)
8266 avox 1582
        {
1583
                StoryText* obj = this->dig->top<StoryText>();
1584
                Xml_attr::iterator code = attr.find("code");
11713 fschmid 1585
                Xml_attr::iterator name = attr.find("name");
8266 avox 1586
                if (tag == "unicode" && code != attr.end())
1587
                        obj->insertChars(-1, QChar(parseUInt(Xml_data(code))));
11713 fschmid 1588
                else if (tag == "var" && name != attr.end())
1589
                {
1590
                        if (Xml_data(name) == "pgno")
1591
                                obj->insertChars(-1, SpecialChars::PAGENUMBER);
1592
                        else
1593
                                obj->insertChars(-1, SpecialChars::PAGECOUNT);
1594
                }
8266 avox 1595
                else
1596
                        obj->insertChars(-1, chr);
1597
        }
1598
private:
1599
        QChar chr;
1600
};
1601
 
1602
struct AppendSpecial : public MakeAction<AppendSpecial_body, QChar>
1603
{
1604
        AppendSpecial(QChar sp) : MakeAction<AppendSpecial_body, QChar>(sp) {}
1605
        AppendSpecial() : MakeAction<AppendSpecial_body, QChar>(SpecialChars::BLANK) {}
1606
};
1607
 
1608
 
1609
class AppendInlineFrame_body : public Action_body
1610
{
1611
public:
8834 cbradney 1612
        void end(const Xml_string& tag) // this could be a setter if we had StoryText::appendObject() ...
8266 avox 1613
        {
1614
                StoryText* story = this->dig->top<StoryText>(1);
1615
                PageItem* obj = this->dig->top<PageItem>(0);
14085 jghali 1616
                // FIXME : currently inline objects are added to doc items when parsing
1617
                // We have to remove them from object list and add them to the FrameItems list
1618
                // before inserting them in story object
1619
                QList<PageItem*> *items = obj->doc()->Items;
1620
                if (items->count() > 0)
1621
                {
1622
                        if (items->last() == obj) // try a fast path first
1623
                                items->removeLast();
1624
                        else
1625
                                items->removeAll(obj);
1626
                }
1627
                obj->doc()->FrameItems.append(obj);
1628
                obj->ItemNr = obj->doc()->FrameItems.count() - 1;
8266 avox 1629
                story->insertObject(-1, obj);
1630
        }
1631
};
1632
 
1633
struct AppendInlineFrame : public MakeAction<AppendInlineFrame_body>
1634
{};
1635
 
8398 avox 1636
/*
8266 avox 1637
class ApplyStyle_body : public Action_body
1638
{
1639
public:
8834 cbradney 1640
        void end(const Xml_string& tag)
8266 avox 1641
        {
13085 jghali 1642
                qDebug() << "storytext desaxe: apply style";
8266 avox 1643
                StoryText* story = this->dig->top<StoryText>(1);
1644
                ParagraphStyle* obj = this->dig->top<ParagraphStyle>(0);
1645
                story->applyStyle(-1, *obj);
1646
        }
1647
};
1648
 
1649
struct ApplyStyle : public MakeAction<ApplyStyle_body>
1650
{};
1651
 
1652
 
8289 avox 1653
class ApplyCharStyle_body : public Action_body
1654
{
1655
public:
1656
        ApplyCharStyle_body() : storyTag(StoryText::saxxDefaultElem), lastPos(0), lastStyle()
1657
        {}
1658
        ApplyCharStyle_body(const Xml_string& tag) : storyTag(tag), lastPos(0), lastStyle()
1659
        {}
1660
 
8834 cbradney 1661
        void end(const Xml_string& tag)
8289 avox 1662
        {
13085 jghali 1663
                qDebug() << "storytext desaxe: apply charstyle";
8289 avox 1664
                if (tag == CharStyle::saxxDefaultElem)
1665
                {
1666
                        StoryText* story = this->dig->top<StoryText>(1);
1667
                        CharStyle* obj = this->dig->top<CharStyle>(0);
1668
                        int len = story->length();
1669
                        if (len > lastPos && lastStyle != *obj)
1670
                        {
1671
                                story->applyCharStyle(lastPos, len - lastPos, lastStyle);
1672
                                lastPos = len;
1673
                                lastStyle = *obj;
1674
                        }
1675
                }
1676
                else if (tag == StoryText::saxxDefaultElem)
1677
                {
1678
                        StoryText* story = this->dig->top<StoryText>();
1679
                        int len = story->length();
1680
                        if (len > lastPos)
1681
                        {
1682
                                story->applyCharStyle(lastPos, len - lastPos, lastStyle);
1683
                        }
1684
                }
1685
        }
1686
private:
1687
        Xml_string storyTag;
1688
        int lastPos;
1689
        CharStyle lastStyle;
1690
};
1691
 
1692
struct ApplyCharStyle : public MakeAction<ApplyCharStyle_body, const Xml_string&>
1693
{
1694
        ApplyCharStyle() : MakeAction<ApplyCharStyle_body, const Xml_string&>() {}
1695
        ApplyCharStyle(const Xml_string& tag) : MakeAction<ApplyCharStyle_body, const Xml_string&>(tag) {}
1696
};
1697
 
8398 avox 1698
*/
8289 avox 1699
 
8398 avox 1700
class Paragraph_body : public Action_body
1701
{
1702
public:
13442 jghali 1703
        Paragraph_body() : lastPos(0), numPara(0), lastStyle(NULL)
8398 avox 1704
        {}
1705
 
1706
        ~Paragraph_body()
1707
        {
1708
                if (lastStyle)
1709
                        delete lastStyle;
1710
        }
1711
 
8834 cbradney 1712
        void begin(const Xml_string& tag, Xml_attr attr)
8398 avox 1713
        {
13670 jghali 1714
                if (tag == "text-content")
8398 avox 1715
                {
13670 jghali 1716
                        numPara = 0;
1717
                }
1718
                else if (tag == "p")
1719
                {
8398 avox 1720
                        StoryText* story = this->dig->top<StoryText>();
13085 jghali 1721
//                      qDebug() << QString("startpar: %1->%2 %3->NULL").arg(lastPos).arg(story->length()).arg((ulong)lastStyle);
13445 jghali 1722
                        lastPos = story->length();
13442 jghali 1723
                        if (numPara > 0) {
8398 avox 1724
                                story->insertChars(-1, SpecialChars::PARSEP);
8455 avox 1725
                                ++lastPos;
1726
                        }
8398 avox 1727
                        if (lastStyle)
1728
                                delete lastStyle;
1729
                        lastStyle = NULL;
1730
                }
1731
        }
1732
 
8834 cbradney 1733
        void end(const Xml_string& tag)
8398 avox 1734
        {
1735
                if (tag == ParagraphStyle::saxxDefaultElem)
1736
                {
1737
                        if (lastStyle)
1738
                                delete lastStyle;
1739
                        lastStyle = this->dig->top<ParagraphStyle>(0);
13085 jghali 1740
//                      qDebug() << QString("endstyle: %1 %2 %3").arg("?").arg(lastPos).arg((ulong)lastStyle);
8398 avox 1741
                }
1742
                else if (tag == "p")
1743
                {
1744
                        StoryText* story = this->dig->top<StoryText>();
1745
                        int len = story->length();
13085 jghali 1746
//                      qDebug() << QString("endpar: %1 %2 %3 %4").arg(len).arg(lastPos).arg((ulong)lastStyle).arg(lastStyle? lastStyle->parent() : QString());
13445 jghali 1747
                        if (len >= lastPos && lastStyle)
8398 avox 1748
                        {
1749
                                story->applyStyle(lastPos, *lastStyle);
1750
                        }
13442 jghali 1751
                        ++numPara;
8398 avox 1752
                }
1753
        }
1754
private:
1755
        int lastPos;
13442 jghali 1756
        int numPara;
8398 avox 1757
        ParagraphStyle* lastStyle;
1758
};
1759
 
1760
struct Paragraph : public MakeAction<Paragraph_body>
1761
{
1762
        Paragraph() : MakeAction<Paragraph_body>() {}
1763
};
1764
 
1765
 
1766
class SpanAction_body : public Action_body
1767
{
1768
public:
1769
        SpanAction_body() : lastPos(0), lastStyle(NULL)
1770
        {}
1771
 
1772
        ~SpanAction_body()
1773
        {
1774
                if (lastStyle)
1775
                        delete lastStyle;
1776
        }
1777
 
8834 cbradney 1778
        void begin(const Xml_string& tag, Xml_attr attr)
8398 avox 1779
        {
13085 jghali 1780
//              qDebug() << QString("spanaction: begin %1").arg(tag);
8398 avox 1781
                if (tag == "span")
1782
                {
1783
                        StoryText* story = this->dig->top<StoryText>();
1784
                        lastPos = story->length();
1785
                        if (lastStyle)
1786
                                delete lastStyle;
1787
                        lastStyle = NULL;
1788
                }
1789
        }
1790
 
8834 cbradney 1791
        void end(const Xml_string& tag)
8398 avox 1792
        {
1793
                if (tag == CharStyle::saxxDefaultElem)
13085 jghali 1794
//                      qDebug() << QString("spanaction: end %1").arg(tag);
8398 avox 1795
                {
1796
                        if (lastStyle)
1797
                                delete lastStyle;
1798
                        lastStyle = this->dig->top<CharStyle>(0);
1799
                }
8413 avox 1800
                else if (tag == "span")
8398 avox 1801
                {
1802
                        StoryText* story = this->dig->top<StoryText>();
1803
                        int len = story->length();
1804
                        if (len > lastPos && lastStyle)
1805
                        {
1806
                                story->applyCharStyle(lastPos, len - lastPos, *lastStyle);
1807
                        }
1808
                }
1809
        }
1810
private:
1811
        int lastPos;
1812
        CharStyle* lastStyle;
1813
};
1814
 
1815
struct SpanAction : public MakeAction<SpanAction_body>
1816
{
1817
        SpanAction() : MakeAction<SpanAction_body>() {}
1818
};
1819
 
1820
 
8266 avox 1821
const Xml_string StoryText::saxxDefaultElem("story");
1822
 
8834 cbradney 1823
void StoryText::desaxeRules(const Xml_string& prefixPattern, Digester& ruleset, Xml_string elemtag)
8266 avox 1824
{
1825
        Xml_string storyPrefix(Digester::concat(prefixPattern, elemtag));
1826
        ruleset.addRule(storyPrefix, Factory<StoryText>());
1827
 
1828
        ParagraphStyle::desaxeRules(storyPrefix, ruleset, "defaultstyle");
1829
        ruleset.addRule(Digester::concat(storyPrefix, "defaultstyle"), SetterWithConversion<StoryText, const ParagraphStyle&, ParagraphStyle>( & StoryText::setDefaultStyle ));
1830
 
8398 avox 1831
        Paragraph paraAction;
1832
        Xml_string paraPrefix(Digester::concat(storyPrefix, "p"));
13670 jghali 1833
        ruleset.addRule(storyPrefix, paraAction ); // needed to initialize some variables
11713 fschmid 1834
        ruleset.addRule(paraPrefix, paraAction );
8398 avox 1835
        ParagraphStyle::desaxeRules(paraPrefix, ruleset, ParagraphStyle::saxxDefaultElem);
11713 fschmid 1836
        ruleset.addRule(Digester::concat(paraPrefix, ParagraphStyle::saxxDefaultElem), paraAction );
8266 avox 1837
 
8398 avox 1838
        SpanAction spanAction;
1839
        Xml_string spanPrefix(Digester::concat(paraPrefix, "span"));
1840
        ruleset.addRule(spanPrefix, spanAction );
1841
        CharStyle::desaxeRules(spanPrefix, ruleset, CharStyle::saxxDefaultElem);
1842
        ruleset.addRule(Digester::concat(spanPrefix, CharStyle::saxxDefaultElem), spanAction );
1843
 
1844
        ruleset.addRule(spanPrefix, AppendText());
8266 avox 1845
 
8398 avox 1846
        ruleset.addRule(Digester::concat(spanPrefix, "breakline"), AppendSpecial(SpecialChars::LINEBREAK) );
1847
        ruleset.addRule(Digester::concat(spanPrefix, "breakcol"), AppendSpecial(SpecialChars::COLBREAK) );
1848
        ruleset.addRule(Digester::concat(spanPrefix, "breakframe"), AppendSpecial(SpecialChars::FRAMEBREAK) );
11713 fschmid 1849
        ruleset.addRule(Digester::concat(spanPrefix, "tab"), AppendSpecial(SpecialChars::TAB) );
1850
        ruleset.addRule(Digester::concat(spanPrefix, "unicode"), AppendSpecial() );
1851
        ruleset.addRule(Digester::concat(spanPrefix, "var"), AppendSpecial());
8266 avox 1852
 
1853
        //PageItem::desaxeRules(storyPrefix, ruleset); argh, that would be recursive!
11713 fschmid 1854
        ruleset.addRule(Digester::concat(spanPrefix, "item"), AppendInlineFrame() );
8266 avox 1855
 
1856
}