lib

KoTextObject.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001-2006 David Faure <faure@kde.org>
3 Copyright (C) 2005 Martin Ellis <martin.ellis@kdemail.net>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "KoTextObject.h"
22#include "KoTextParag.h"
23#include "KoParagCounter.h"
24#include "KoTextZoomHandler.h"
25#include "KoTextCommand.h"
26#include "KoStyleCollection.h"
27#include "KoFontDia.h"
28#include "KoOasisContext.h"
29#include "KoVariable.h"
30#include "KoAutoFormat.h"
31#include <KoXmlNS.h>
32#include <KoDom.h>
33
34#include <tdelocale.h>
35#include <kdebug.h>
36#include <tdeapplication.h>
37
38#include <tqtimer.h>
39#include <tqregexp.h>
40#include <tqprogressdialog.h>
41
42#include <assert.h>
43
44//#define DEBUG_FORMATS
45//#define DEBUG_FORMAT_MORE
46
47const char KoTextObject::s_customItemChar = '#'; // Has to be transparent to tdespell but still be saved (not space)
48
49struct KoTextObject::KoTextObjectPrivate
50{
51public:
52 KoTextObjectPrivate() {
53 afterFormattingEmitted = false;
54 abortFormatting = false;
55 }
56 bool afterFormattingEmitted;
57 bool abortFormatting;
58};
59
60KoTextObject::KoTextObject( KoTextZoomHandler *zh, const TQFont& defaultFont,
61 const TQString &defaultLanguage, bool hyphenation,
62 KoParagStyle* defaultStyle, int tabStopWidth,
63 TQObject* parent, const char *name )
64 : TQObject( parent, name ), m_defaultStyle( defaultStyle ), undoRedoInfo( this )
65{
66 textdoc = new KoTextDocument( zh, new KoTextFormatCollection( defaultFont, TQColor(),defaultLanguage, hyphenation ) );
67 if ( tabStopWidth != -1 )
68 textdoc->setTabStops( tabStopWidth );
69 init();
70}
71
72KoTextObject::KoTextObject( KoTextDocument* _textdoc, KoParagStyle* defaultStyle,
73 TQObject* parent, const char *name )
74 : TQObject( parent, name ), m_defaultStyle( defaultStyle ), undoRedoInfo( this )
75{
76 textdoc = _textdoc;
77 init();
78}
79
80void KoTextObject::init()
81{
82 d = new KoTextObjectPrivate;
83 m_needsSpellCheck = true;
84 m_protectContent = false;
85 m_visible=true;
86 m_availableHeight = -1;
87 m_lastFormatted = textdoc->firstParag();
88 m_highlightSelectionAdded = false;
89 interval = 0;
90 changeIntervalTimer = new TQTimer( this );
91 connect( changeIntervalTimer, TQ_SIGNAL( timeout() ),
92 this, TQ_SLOT( doChangeInterval() ) );
93
94 formatTimer = new TQTimer( this );
95 connect( formatTimer, TQ_SIGNAL( timeout() ),
96 this, TQ_SLOT( formatMore() ) );
97
98 // Apply default style to initial paragraph
99 if ( m_lastFormatted && m_defaultStyle )
100 m_lastFormatted->applyStyle( m_defaultStyle );
101
102 connect( textdoc, TQ_SIGNAL( paragraphDeleted( KoTextParag* ) ),
103 this, TQ_SIGNAL( paragraphDeleted( KoTextParag* ) ) );
104 connect( textdoc, TQ_SIGNAL( paragraphDeleted( KoTextParag* ) ),
105 this, TQ_SLOT( slotParagraphDeleted( KoTextParag* ) ) );
106 connect( textdoc, TQ_SIGNAL( newCommand( KCommand* ) ),
107 this, TQ_SIGNAL( newCommand( KCommand* ) ) );
108 connect( textdoc, TQ_SIGNAL( repaintChanged() ),
109 this, TQ_SLOT( emitRepaintChanged() ) );
110
111 connect( this, TQ_SIGNAL(paragraphModified( KoTextParag*, int, int , int ) ),
112 this, TQ_SLOT(slotParagraphModified(KoTextParag *, int, int , int)));
113 connect( this, TQ_SIGNAL(paragraphCreated( KoTextParag* )),
114 this, TQ_SLOT(slotParagraphCreated(KoTextParag *)));
115}
116
117KoTextObject::~KoTextObject()
118{
119 // Avoid crash in KoTextString::clear -> accessing deleted format collection,
120 // if ~UndoRedoInfo still has a string to clear.
121 undoRedoInfo.clear();
122 delete textdoc; textdoc = 0;
123 delete d;
124}
125
126int KoTextObject::availableHeight() const
127{
128 if ( m_availableHeight == -1 )
129 emit const_cast<KoTextObject *>(this)->availableHeightNeeded();
130 Q_ASSERT( m_availableHeight != -1 );
131 return m_availableHeight;
132}
133
134void KoTextObject::slotParagraphModified(KoTextParag * /*parag*/, int /*ParagModifyType*/ _type, int , int)
135{
136 if ( _type == ChangeFormat)
137 return;
138 m_needsSpellCheck = true;
139}
140
141void KoTextObject::slotParagraphCreated(KoTextParag * /*parag*/)
142{
143 m_needsSpellCheck = true;
144}
145
146void KoTextObject::slotParagraphDeleted(KoTextParag * parag)
147{
148 if ( m_lastFormatted == parag )
149 m_lastFormatted = parag->next();
150
151 // ### TODO: remove from kwbgspellcheck
152 // not needed, since KoTextIterator takes care of that.
153}
154
156{
157 Q_ASSERT( format );
158 return format->pointSize();
159}
160
162{
163 kdDebug(32500) << "KoTextObject::zoomedFontSize: docFontSize=" << docFontSize
164 << " - in LU: " << KoTextZoomHandler::ptToLayoutUnitPt( docFontSize ) << endl;
166}
167
168// A visitor that looks for custom items in e.g. a selection
169class KoHasCustomItemVisitor : public KoParagVisitor
170{
171public:
172 KoHasCustomItemVisitor() : KoParagVisitor() { }
173 // returns false when cancelled, i.e. an item was _found_, and true if it proceeded to the end(!)
174 virtual bool visit( KoTextParag *parag, int start, int end )
175 {
176 for ( int i = start ; i < end ; ++i )
177 {
178 KoTextStringChar * ch = parag->at( i );
179 if ( ch->isCustom() )
180 return false; // found one -> stop here
181 }
182 return true;
183 }
184};
185
186bool KoTextObject::selectionHasCustomItems( KoTextDocument::SelectionId selectionId ) const
187{
188 KoHasCustomItemVisitor visitor;
189 bool noneFound = textdoc->visitSelection( selectionId, &visitor );
190 return !noneFound;
191}
192
193void KoTextObject::slotAfterUndoRedo()
194{
195 formatMore( 2 );
196 emit repaintChanged( this );
197 emit updateUI( true );
198 emit showCursor();
199 emit ensureCursorVisible();
200}
201
203{
204 undoRedoInfo.clear();
205}
206
207
208void KoTextObject::checkUndoRedoInfo( KoTextCursor * cursor, UndoRedoInfo::Type t )
209{
210 if ( undoRedoInfo.valid() && ( t != undoRedoInfo.type || cursor != undoRedoInfo.cursor ) ) {
211 undoRedoInfo.clear();
212 }
213 undoRedoInfo.type = t;
214 undoRedoInfo.cursor = cursor;
215}
216
217void KoTextObject::undo()
218{
219 undoRedoInfo.clear();
220 emit hideCursor();
221 KoTextCursor *cursor = new KoTextCursor( textdoc ); // Kindof a dummy cursor
222 KoTextCursor *c = textdoc->undo( cursor );
223 if ( !c ) {
224 delete cursor;
225 emit showCursor();
226 return;
227 }
228 // We have to set this new cursor position in all views :(
229 // It sucks a bit for useability, but otherwise one view might still have
230 // a cursor inside a deleted paragraph -> crash.
231 emit setCursor( c );
232 setLastFormattedParag( textdoc->firstParag() );
233 delete cursor;
234 TQTimer::singleShot( 0, this, TQ_SLOT( slotAfterUndoRedo() ) );
235}
236
237void KoTextObject::redo()
238{
239 undoRedoInfo.clear();
240 emit hideCursor();
241 KoTextCursor *cursor = new KoTextCursor( textdoc ); // Kindof a dummy cursor
242 KoTextCursor *c = textdoc->redo( cursor );
243 if ( !c ) {
244 delete cursor;
245 emit showCursor();
246 return;
247 }
248 emit setCursor( c ); // see undo
249 setLastFormattedParag( textdoc->firstParag() );
250 delete cursor;
251 TQTimer::singleShot( 0, this, TQ_SLOT( slotAfterUndoRedo() ) );
252}
253
254KoTextObject::UndoRedoInfo::UndoRedoInfo( KoTextObject *to )
255 : type( Invalid ), textobj(to), cursor( 0 )
256{
257 text = TQString();
258 id = -1;
259 index = -1;
260 placeHolderCmd = 0L;
261}
262
263bool KoTextObject::UndoRedoInfo::valid() const
264{
265 return text.length() > 0 && id >= 0 && index >= 0 && type != Invalid;
266}
267
268void KoTextObject::UndoRedoInfo::clear()
269{
270 if ( valid() ) {
271 KoTextDocument* textdoc = textobj->textDocument();
272 switch (type) {
273 case Insert:
274 case Return:
275 {
276 KoTextDocCommand * cmd = new KoTextInsertCommand( textdoc, id, index, text.rawData(), customItemsMap, oldParagLayouts );
277 textdoc->addCommand( cmd );
278 Q_ASSERT( placeHolderCmd );
279 if ( placeHolderCmd ) // crash prevention
280 {
281 // Inserting any custom items -> macro command, to let custom items add their command
282 if ( !customItemsMap.isEmpty() )
283 {
284 CustomItemsMap::Iterator it = customItemsMap.begin();
285 for ( ; it != customItemsMap.end(); ++it )
286 {
287 KoTextCustomItem * item = it.data();
288 KCommand * itemCmd = item->createCommand();
289 if ( itemCmd )
290 placeHolderCmd->addCommand( itemCmd );
291 }
292 placeHolderCmd->addCommand( new KoTextCommand( textobj, /*cmd, */TQString() ) );
293 }
294 else
295 {
296 placeHolderCmd->addCommand( new KoTextCommand( textobj, /*cmd, */TQString() ) );
297 }
298 }
299 } break;
300 case Delete:
301 case RemoveSelected:
302 {
303 KoTextDocCommand * cmd = textobj->deleteTextCommand( textdoc, id, index, text.rawData(), customItemsMap, oldParagLayouts );
304 textdoc->addCommand( cmd );
305 Q_ASSERT( placeHolderCmd );
306 placeHolderCmd->addCommand( new KoTextCommand( textobj, /*cmd, */TQString() ) );
307 // Deleting any custom items -> let them add their command
308 if ( !customItemsMap.isEmpty() )
309 {
310 customItemsMap.deleteAll( placeHolderCmd );
311 }
312 } break;
313 case Invalid:
314 break;
315 }
316 }
317 type = Invalid;
318 // Before Qt-3.2.0, this called KoTextString::clear(), which called resize(0) on the array, which _detached_. Tricky.
319 // Since Qt-3.2.0, resize(0) doesn't detach anymore -> KoTextDocDeleteCommand calls copy() itself.
320
321 text = TQString();
322 id = -1;
323 index = -1;
324 oldParagLayouts.clear();
325 customItemsMap.clear();
326 placeHolderCmd = 0;
327}
328
329void KoTextObject::copyCharFormatting( KoTextParag *parag, int position, int index /*in text*/, bool moveCustomItems )
330{
331 KoTextStringChar * ch = parag->at( position );
332 if ( ch->format() ) {
333 ch->format()->addRef();
334 undoRedoInfo.text.at( index ).setFormat( ch->format() );
335 }
336 if ( ch->isCustom() )
337 {
338 kdDebug(32500) << "KoTextObject::copyCharFormatting moving custom item " << ch->customItem() << " to text's " << index << " char" << endl;
339 undoRedoInfo.customItemsMap.insert( index, ch->customItem() );
340 // We copy the custom item to customItemsMap in all cases (see setFormat)
341 // We only remove from 'ch' if moveCustomItems was specified
342 if ( moveCustomItems )
343 parag->removeCustomItem(position);
344 //ch->loseCustomItem();
345 }
346}
347
348// Based on TQTextView::readFormats - with all code duplication moved to copyCharFormatting
349void KoTextObject::readFormats( KoTextCursor &c1, KoTextCursor &c2, bool copyParagLayouts, bool moveCustomItems )
350{
351 //kdDebug(32500) << "KoTextObject::readFormats moveCustomItems=" << moveCustomItems << endl;
352 int oldLen = undoRedoInfo.text.length();
353 if ( c1.parag() == c2.parag() ) {
354 undoRedoInfo.text += c1.parag()->string()->toString().mid( c1.index(), c2.index() - c1.index() );
355 for ( int i = c1.index(); i < c2.index(); ++i )
356 copyCharFormatting( c1.parag(), i, oldLen + i - c1.index(), moveCustomItems );
357 } else {
358 int lastIndex = oldLen;
359 int i;
360 //kdDebug(32500) << "KoTextObject::readFormats copying from " << c1.index() << " to " << c1.parag()->length()-1 << " into lastIndex=" << lastIndex << endl;
361 // Replace the trailing spaces with '\n'. That char carries the formatting for the trailing space.
362 undoRedoInfo.text += c1.parag()->string()->toString().mid( c1.index(), c1.parag()->length() - 1 - c1.index() ) + '\n';
363 for ( i = c1.index(); i < c1.parag()->length(); ++i, ++lastIndex )
364 copyCharFormatting( c1.parag(), i, lastIndex, moveCustomItems );
365 //++lastIndex; // skip the '\n'.
366 KoTextParag *p = c1.parag()->next();
367 while ( p && p != c2.parag() ) {
368 undoRedoInfo.text += p->string()->toString().left( p->length() - 1 ) + '\n';
369 //kdDebug(32500) << "KoTextObject::readFormats (mid) copying from 0 to " << p->length()-1 << " into i+" << lastIndex << endl;
370 for ( i = 0; i < p->length(); ++i )
371 copyCharFormatting( p, i, i + lastIndex, moveCustomItems );
372 lastIndex += p->length(); // + 1; // skip the '\n'
373 //kdDebug(32500) << "KoTextObject::readFormats lastIndex now " << lastIndex << " - text is now " << undoRedoInfo.text.toString() << endl;
374 p = p->next();
375 }
376 //kdDebug(32500) << "KoTextObject::readFormats copying [last] from 0 to " << c2.index() << " into i+" << lastIndex << endl;
377 undoRedoInfo.text += c2.parag()->string()->toString().left( c2.index() );
378 for ( i = 0; i < c2.index(); ++i )
379 copyCharFormatting( c2.parag(), i, i + lastIndex, moveCustomItems );
380 }
381
382 if ( copyParagLayouts ) {
383 KoTextParag *p = c1.parag();
384 while ( p ) {
385 undoRedoInfo.oldParagLayouts << p->paragLayout();
386 if ( p == c2.parag() )
387 break;
388 p = p->next();
389 }
390 }
391}
392
393void KoTextObject::newPlaceHolderCommand( const TQString & name )
394{
395 Q_ASSERT( !undoRedoInfo.placeHolderCmd );
396 if ( undoRedoInfo.placeHolderCmd ) kdDebug(32500) << kdBacktrace();
397 undoRedoInfo.placeHolderCmd = new KMacroCommand( name );
398 emit newCommand( undoRedoInfo.placeHolderCmd );
399}
400
401void KoTextObject::storeParagUndoRedoInfo( KoTextCursor * cursor, KoTextDocument::SelectionId selectionId )
402{
403 undoRedoInfo.clear();
404 undoRedoInfo.oldParagLayouts.clear();
405 undoRedoInfo.text = " ";
406 undoRedoInfo.index = 1;
407 if ( cursor && !textdoc->hasSelection( selectionId, true ) ) {
408 KoTextParag * p = cursor->parag();
409 undoRedoInfo.id = p->paragId();
410 undoRedoInfo.eid = p->paragId();
411 undoRedoInfo.oldParagLayouts << p->paragLayout();
412 }
413 else{
414 Q_ASSERT( textdoc->hasSelection( selectionId, true ) );
415 KoTextParag *start = textdoc->selectionStart( selectionId );
416 KoTextParag *end = textdoc->selectionEnd( selectionId );
417 undoRedoInfo.id = start->paragId();
418 undoRedoInfo.eid = end->paragId();
419 for ( ; start && start != end->next() ; start = start->next() )
420 {
421 undoRedoInfo.oldParagLayouts << start->paragLayout();
422 //kdDebug(32500) << "KoTextObject:storeParagUndoRedoInfo storing counter " << start->paragLayout().counter.counterType << endl;
423 }
424 }
425}
426
427void KoTextObject::doKeyboardAction( KoTextCursor * cursor, KoTextFormat * & /*currentFormat*/, KeyboardAction action )
428{
429 KoTextParag * parag = cursor->parag();
430 setLastFormattedParag( parag );
431 emit hideCursor();
432 bool doUpdateCurrentFormat = true;
433 switch ( action ) {
434 case ActionDelete: {
435 checkUndoRedoInfo( cursor, UndoRedoInfo::Delete );
436 if ( !undoRedoInfo.valid() ) {
437 newPlaceHolderCommand( i18n("Delete Text") );
438 undoRedoInfo.id = parag->paragId();
439 undoRedoInfo.index = cursor->index();
440 undoRedoInfo.text = TQString();
441 undoRedoInfo.oldParagLayouts << parag->paragLayout();
442 }
443 if ( !cursor->atParagEnd() )
444 {
445 KoTextStringChar * ch = parag->at( cursor->index() );
446 undoRedoInfo.text += ch->c;
447 copyCharFormatting( parag, cursor->index(), undoRedoInfo.text.length()-1, true );
448 }
449 KoParagLayout paragLayout;
450 if ( parag->next() )
451 paragLayout = parag->next()->paragLayout();
452
453 KoTextParag *old = cursor->parag();
454 if ( cursor->remove() ) {
455 if ( old != cursor->parag() && m_lastFormatted == old ) // 'old' has been deleted
456 m_lastFormatted = cursor->parag() ? cursor->parag()->prev() : 0;
457 undoRedoInfo.text += "\n";
458 undoRedoInfo.oldParagLayouts << paragLayout;
459 } else
460 emit paragraphModified( old, RemoveChar, cursor->index(), 1 );
461 } break;
462 case ActionBackspace: {
463 // Remove counter
464 if ( parag->counter() && parag->counter()->style() != KoParagCounter::STYLE_NONE && cursor->index() == 0 ) {
465 // parag->decDepth(); // We don't have support for nested lists at the moment
466 // (only in titles, but you don't want Backspace to move it up)
468 c.setDepth( parag->counter()->depth() );
469 KCommand *cmd=setCounterCommand( cursor, c );
470 if(cmd)
471 emit newCommand(cmd);
472 }
473 else if ( !cursor->atParagStart() )
474 {
475 checkUndoRedoInfo( cursor, UndoRedoInfo::Delete );
476 if ( !undoRedoInfo.valid() ) {
477 newPlaceHolderCommand( i18n("Delete Text") );
478 undoRedoInfo.id = parag->paragId();
479 undoRedoInfo.index = cursor->index();
480 undoRedoInfo.text = TQString();
481 undoRedoInfo.oldParagLayouts << parag->paragLayout();
482 }
483 undoRedoInfo.text.insert( 0, cursor->parag()->at( cursor->index()-1 ) );
484 copyCharFormatting( cursor->parag(), cursor->index()-1, 0, true );
485 undoRedoInfo.index = cursor->index()-1;
486 //KoParagLayout paragLayout = cursor->parag()->paragLayout();
487 cursor->removePreviousChar();
488 emit paragraphModified( cursor->parag(), RemoveChar, cursor->index(),1 );
489 m_lastFormatted = cursor->parag();
490 } else if ( parag->prev() ) { // joining paragraphs
491 emit paragraphDeleted( cursor->parag() );
493 textdoc->setSelectionStart( KoTextDocument::Temp, cursor );
494 cursor->gotoPreviousLetter();
495 textdoc->setSelectionEnd( KoTextDocument::Temp, cursor );
496 removeSelectedText( cursor, KoTextDocument::Temp, i18n( "Delete Text" ) );
497 emit paragraphModified( cursor->parag(), AddChar, cursor->index(), cursor->parag()->length() - cursor->index() );
498 }
499 } break;
500 case ActionReturn: {
501 checkUndoRedoInfo( cursor, UndoRedoInfo::Return );
502 if ( !undoRedoInfo.valid() ) {
503 newPlaceHolderCommand( i18n("Insert Text") );
504 undoRedoInfo.id = cursor->parag()->paragId();
505 undoRedoInfo.index = cursor->index();
506 undoRedoInfo.text = TQString();
507 }
508 undoRedoInfo.text += "\n";
509 if ( cursor->parag() )
510 {
511 TQString last_line = cursor->parag()->toString();
512 last_line.remove(0,last_line.find(' ')+1);
513
514 if( last_line.isEmpty() && cursor->parag()->counter() && cursor->parag()->counter()->numbering() == KoParagCounter::NUM_LIST ) //if the previous line the in paragraph is empty
515 {
517 KCommand *cmd=setCounterCommand( cursor, c );
518 if(cmd)
519 emit newCommand(cmd);
520 setLastFormattedParag( cursor->parag() );
521 cursor->parag()->setNoCounter();
522
523 formatMore( 2 );
524 emit repaintChanged( this );
525 emit ensureCursorVisible();
526 emit showCursor();
527 emit updateUI( doUpdateCurrentFormat );
528 return;
529 }
530 else
531 cursor->splitAndInsertEmptyParag();
532 }
533
534 Q_ASSERT( cursor->parag()->prev() );
535 setLastFormattedParag( cursor->parag() );
536
537 doUpdateCurrentFormat = false;
538 KoParagStyle * style = cursor->parag()->prev()->style();
539 if ( style )
540 {
541 KoParagStyle * newStyle = style->followingStyle();
542 if ( newStyle && style != newStyle ) // different "following style" applied
543 {
544 doUpdateCurrentFormat = true;
545 //currentFormat = textdoc->formatCollection()->format( cursor->parag()->paragFormat() );
546 //kdDebug(32500) << "KoTextFrameSet::doKeyboardAction currentFormat=" << currentFormat << " " << currentFormat->key() << endl;
547 }
548 }
549 if ( cursor->parag()->joinBorder() && cursor->parag()->bottomBorder().width() > 0 )
550 cursor->parag()->prev()->setChanged( true );
551 if ( cursor->parag()->joinBorder() && cursor->parag()->next() && cursor->parag()->next()->joinBorder() && cursor->parag()->bottomBorder() == cursor->parag()->next()->bottomBorder())
552 cursor->parag()->next()->setChanged( true );
553 emit paragraphCreated( cursor->parag() );
554
555 } break;
556 case ActionKill:
557 // Nothing to kill if at end of very last paragraph
558 if ( !cursor->atParagEnd() || cursor->parag()->next() ) {
559 checkUndoRedoInfo( cursor, UndoRedoInfo::Delete );
560 if ( !undoRedoInfo.valid() ) {
561 newPlaceHolderCommand( i18n("Delete Text") );
562 undoRedoInfo.id = cursor->parag()->paragId();
563 undoRedoInfo.index = cursor->index();
564 undoRedoInfo.text = TQString();
565 undoRedoInfo.oldParagLayouts << parag->paragLayout();
566 }
567 if ( cursor->atParagEnd() ) {
568 // Get paraglayout from next parag (next can't be 0 here)
569 KoParagLayout paragLayout = parag->next()->paragLayout();
570 if ( cursor->remove() )
571 {
572 m_lastFormatted = cursor->parag();
573 undoRedoInfo.text += "\n";
574 undoRedoInfo.oldParagLayouts << paragLayout;
575 }
576 } else {
577 int oldLen = undoRedoInfo.text.length();
578 undoRedoInfo.text += cursor->parag()->string()->toString().mid( cursor->index() );
579 for ( int i = cursor->index(); i < cursor->parag()->length(); ++i )
580 copyCharFormatting( cursor->parag(), i, oldLen + i - cursor->index(), true );
581 cursor->killLine();
582 emit paragraphModified( cursor->parag(), RemoveChar, cursor->index(), cursor->parag()->length()-cursor->index() );
583 }
584 }
585 break;
586 }
587
588 if ( !undoRedoInfo.customItemsMap.isEmpty() )
590
591 formatMore( 2 );
592 emit repaintChanged( this );
593 emit ensureCursorVisible();
594 emit showCursor();
595 emit updateUI( doUpdateCurrentFormat );
596}
597
598void KoTextObject::insert( KoTextCursor * cursor, KoTextFormat * currentFormat,
599 const TQString &txt, const TQString & commandName, KoTextDocument::SelectionId selectionId,
600 int insertFlags, CustomItemsMap customItemsMap )
601{
602 if ( protectContent() )
603 return;
604 const bool checkNewLine = insertFlags & CheckNewLine;
605 const bool removeSelected = ( insertFlags & DoNotRemoveSelected ) == 0;
606 const bool repaint = ( insertFlags & DoNotRepaint ) == 0;
607 //kdDebug(32500) << "KoTextObject::insert txt=" << txt << endl;
608 bool tinyRepaint = !checkNewLine;
609 if ( repaint )
610 emit hideCursor();
611 if ( textdoc->hasSelection( selectionId, true ) && removeSelected ) {
612 kdDebug() << k_funcinfo << "removing selection " << selectionId << endl;
613 // call replaceSelectionCommand, which will call insert() back, but this time without a selection.
614 emitNewCommand(replaceSelectionCommand( cursor, txt, commandName, selectionId, insertFlags, customItemsMap ));
615 return;
616 }
617 // Now implement overwrite mode, similarly.
618 if ( insertFlags & OverwriteMode ) {
619 textdoc->setSelectionStart( KoTextDocument::Temp, cursor );
620 KoTextCursor oc = *cursor;
621 kdDebug(32500) << "overwrite: going to insert " << txt.length() << " chars; idx=" << oc.index() << endl;
622 oc.setIndex( TQMIN( oc.index() + (int)txt.length(), oc.parag()->lastCharPos() + 1 ) );
623 kdDebug(32500) << "overwrite: removing from " << cursor->index() << " to " << oc.index() << endl;
624 if ( oc.index() > cursor->index() )
625 {
626 textdoc->setSelectionEnd( KoTextDocument::Temp, &oc );
627 int newInsertFlags = insertFlags & ~OverwriteMode;
628 newInsertFlags &= ~DoNotRemoveSelected;
629 emitNewCommand(replaceSelectionCommand( cursor, txt, commandName, KoTextDocument::Temp, newInsertFlags, customItemsMap ));
630 return;
631 }
632 }
633 KoTextCursor c2 = *cursor;
634 // Make everything ready for undo/redo (new command, or add to current one)
635 if ( !customItemsMap.isEmpty() )
637 checkUndoRedoInfo( cursor, UndoRedoInfo::Insert );
638 if ( !undoRedoInfo.valid() ) {
639 if ( !commandName.isNull() ) // see replace-selection
640 newPlaceHolderCommand( commandName );
641 undoRedoInfo.id = cursor->parag()->paragId();
642 undoRedoInfo.index = cursor->index();
643 undoRedoInfo.text = TQString();
644 }
645 int oldLen = undoRedoInfo.text.length();
646 KoTextCursor oldCursor = *cursor;
647 bool wasChanged = cursor->parag()->hasChanged();
648 int origLine; // the line the cursor was on before the insert
649 oldCursor.parag()->lineStartOfChar( oldCursor.index(), 0, &origLine );
650
651 // insert the text - finally!
652 cursor->insert( txt, checkNewLine );
653
654 setLastFormattedParag( checkNewLine ? oldCursor.parag() : cursor->parag() );
655
656 if ( !customItemsMap.isEmpty() ) {
657 customItemsMap.insertItems( oldCursor, txt.length() );
658 undoRedoInfo.customItemsMap = customItemsMap;
659 tinyRepaint = false;
660 }
661
662 textdoc->setSelectionStart( KoTextDocument::Temp, &oldCursor );
663 textdoc->setSelectionEnd( KoTextDocument::Temp, cursor );
664 //kdDebug(32500) << "KoTextObject::insert setting format " << currentFormat << endl;
665 textdoc->setFormat( KoTextDocument::Temp, currentFormat, KoTextFormat::Format );
666 textdoc->setFormat( KoTextDocument::InputMethodPreedit, currentFormat, KoTextFormat::Format );
667 textdoc->removeSelection( KoTextDocument::Temp );
668
669 if ( !customItemsMap.isEmpty() ) {
670 // Some custom items (e.g. variables) depend on the format
671 CustomItemsMap::Iterator it = customItemsMap.begin();
672 for ( ; it != customItemsMap.end(); ++it )
673 it.data()->resize();
674 }
675
676 // Speed optimization: if we only type a char, and it doesn't
677 // invalidate the next parag, only format the current one
678 // ### This idea is wrong. E.g. when the last parag grows and must create a new page.
679#if 0
680 KoTextParag *parag = cursor->parag();
681 if ( !checkNewLine && m_lastFormatted == parag && ( !parag->next() || parag->next()->isValid() ) )
682 {
683 parag->format();
684 m_lastFormatted = m_lastFormatted->next();
685 }
686#endif
687 // Call formatMore until necessary. This will create new pages if needed.
688 // Doing this here means callers don't have to do it, and cursor can be positionned correctly.
689 ensureFormatted( cursor->parag() );
690
691 // Speed optimization: if we only type a char, only repaint from current line
692 // (In fact the one before. When typing a space, a word could move up to the
693 // line before, we need to repaint it too...)
694 if ( !checkNewLine && tinyRepaint && !wasChanged )
695 {
696 // insert() called format() which called setChanged().
697 // We're reverting that, and calling setLineChanged() only.
698 Q_ASSERT( cursor->parag() == oldCursor.parag() ); // no newline!
699 KoTextParag* parag = cursor->parag();
700 // If the new char led to a new line,
701 // the wordwrap could have changed on the line above
702 // This is why we use origLine and not calling lineStartOfChar here.
703 parag->setChanged( false );
704 parag->setLineChanged( origLine - 1 ); // if origLine=0, it'll pass -1, which is 'all'
705 }
706
707 if ( repaint ) {
708 emit repaintChanged( this );
709 emit ensureCursorVisible();
710 emit showCursor();
711 // we typed the first char of a paragraph in AlignAuto mode -> show correct alignment in UI
712 if ( oldCursor.index() == 0 && oldCursor.parag()->alignment() == TQt::AlignAuto )
713 emit updateUI( true );
714
715 }
716 undoRedoInfo.text += txt;
717 for ( int i = 0; i < (int)txt.length(); ++i ) {
718 if ( txt[ oldLen + i ] != '\n' )
719 copyCharFormatting( c2.parag(), c2.index(), oldLen + i, false );
720 c2.gotoNextLetter();
721 }
722
723 if ( !removeSelected ) {
724 // ## not sure why we do this. I'd prefer leaving the selection unchanged...
725 // but then it'd need adjustements in the offsets etc.
726 if ( textdoc->removeSelection( selectionId ) && repaint )
727 selectionChangedNotify(); // does the repaint
728 }
729 if ( !customItemsMap.isEmpty()
730 && !commandName.isNull() /* see replace-selection; #139890 */ ) {
732 }
733
734 // Notifications
735 emit paragraphModified( oldCursor.parag(), AddChar, cursor->index(), txt.length() );
736 if (checkNewLine) {
737 KoTextParag* p = oldCursor.parag()->next();
738 while ( p && p != cursor->parag() ) {
739 emit paragraphCreated( p );
740 p = p->next();
741 }
742 }
743}
744
745void KoTextObject::pasteText( KoTextCursor * cursor, const TQString & text, KoTextFormat * currentFormat, bool removeSelected )
746{
747 if ( protectContent() )
748 return;
749 kdDebug(32500) << "KoTextObject::pasteText cursor parag=" << cursor->parag()->paragId() << endl;
750 TQString t = text;
751 // Need to convert CRLF to NL
752 TQRegExp crlf( TQString::fromLatin1("\r\n") );
753 t.replace( crlf, TQChar('\n') );
754 // Convert non-printable chars
755 for ( int i=0; (uint) i<t.length(); i++ ) {
756 if ( t[ i ] < ' ' && t[ i ] != '\n' && t[ i ] != '\t' )
757 t[ i ] = ' ';
758 }
759 if ( !t.isEmpty() )
760 {
761 int insertFlags = CheckNewLine;
762 if ( !removeSelected )
763 insertFlags |= DoNotRemoveSelected;
764 insert( cursor, currentFormat, t, i18n("Paste Text"),
765 KoTextDocument::Standard, insertFlags );
766 formatMore( 2 );
767 emit repaintChanged( this );
768 }
769}
770
771KCommand* KoTextObject::setParagLayoutCommand( KoTextCursor * cursor, const KoParagLayout& paragLayout,
772 KoTextDocument::SelectionId selectionId, int paragLayoutFlags,
773 int marginIndex, bool createUndoRedo )
774{
775 if ( protectContent() )
776 return 0;
777 storeParagUndoRedoInfo( cursor, selectionId );
778 undoRedoInfo.type = UndoRedoInfo::Invalid; // tricky, we don't want clear() to create a command
779 if ( paragLayoutFlags != 0 )
780 {
781 emit hideCursor();
782 if ( !textdoc->hasSelection( selectionId, true ) ) {
783 cursor->parag()->setParagLayout( paragLayout, paragLayoutFlags, marginIndex );
784 setLastFormattedParag( cursor->parag() );
785 } else {
786 KoTextParag *start = textdoc->selectionStart( selectionId );
787 KoTextParag *end = textdoc->selectionEnd( selectionId );
788 for ( ; start && start != end->next() ; start = start->next() ) {
789 if ( paragLayoutFlags == KoParagLayout::BulletNumber && start->length() <= 1 )
790 continue; // don't apply to empty paragraphs (#25742, #34062)
791 start->setParagLayout( paragLayout, paragLayoutFlags, marginIndex );
792 }
793 setLastFormattedParag( start );
794 }
795
796 formatMore( 2 );
797 emit repaintChanged( this );
798 emit showCursor();
799 emit updateUI( true );
800
801 if ( createUndoRedo )
802 {
803 //kdDebug(32500) << "KoTextObject::applyStyle KoTextParagCommand" << endl;
804 KoTextDocCommand * cmd = new KoTextParagCommand( textdoc, undoRedoInfo.id, undoRedoInfo.eid,
805 undoRedoInfo.oldParagLayouts,
806 paragLayout, paragLayoutFlags,
807 (TQStyleSheetItem::Margin)marginIndex );
808 textdoc->addCommand( cmd );
809 return new KoTextCommand( this, /*cmd, */"related to KoTextParagCommand" );
810 }
811 }
812 return 0;
813}
814
815
816void KoTextObject::applyStyle( KoTextCursor * cursor, const KoParagStyle * newStyle,
817 KoTextDocument::SelectionId selectionId,
818 int paragLayoutFlags, int formatFlags,
819 bool createUndoRedo, bool interactive )
820{
821 KCommand *cmd = applyStyleCommand( cursor, newStyle, selectionId,
822 paragLayoutFlags, formatFlags,
823 createUndoRedo, interactive );
824 if ( createUndoRedo && cmd )
825 emit newCommand( cmd );
826 else
827 Q_ASSERT( !cmd ); // mem leak, if applyStyleCommand created a command despite createUndoRedo==false!
828}
829
830KCommand *KoTextObject::applyStyleCommand( KoTextCursor * cursor, const KoParagStyle * newStyle,
831 KoTextDocument::SelectionId selectionId,
832 int paragLayoutFlags, int formatFlags,
833 bool createUndoRedo, bool interactive )
834{
835 if ( protectContent())
836 return 0L;
837 if ( interactive )
838 emit hideCursor();
839 if ( !textdoc->hasSelection( selectionId, true ) && !cursor)
840 return 0L;
846 KMacroCommand * macroCmd = createUndoRedo ? new KMacroCommand( i18n("Apply Style %1").
847 arg(newStyle->displayName() ) ) : 0;
848
849 // 1
850 //kdDebug(32500) << "KoTextObject::applyStyle setParagLayout" << endl;
851 KCommand* cmd = setParagLayoutCommand( cursor, newStyle->paragLayout(), selectionId, paragLayoutFlags, -1, createUndoRedo );
852 if ( cmd )
853 macroCmd->addCommand( cmd );
854
855 // 2
856 //kdDebug(32500) << "KoTextObject::applyStyle gathering text and formatting" << endl;
857 KoTextParag * firstParag;
858 KoTextParag * lastParag;
859 if ( !textdoc->hasSelection( selectionId, true ) ) {
860 // No selection -> apply style formatting to the whole paragraph
861 firstParag = cursor->parag();
862 lastParag = cursor->parag();
863 }
864 else
865 {
866 firstParag = textdoc->selectionStart( selectionId );
867 lastParag = textdoc->selectionEnd( selectionId );
868 }
869
870 if ( formatFlags != 0 )
871 {
872 KoTextFormat * newFormat = textdoc->formatCollection()->format( &newStyle->format() );
873
874 if ( createUndoRedo )
875 {
876 TQValueList<KoTextFormat *> lstFormats;
877 //TQString str;
878 for ( KoTextParag * parag = firstParag ; parag && parag != lastParag->next() ; parag = parag->next() )
879 {
880 //str += parag->string()->toString() + '\n';
881 lstFormats.append( parag->paragFormat() );
882 }
883 KoTextCursor c1( textdoc );
884 c1.setParag( firstParag );
885 c1.setIndex( 0 );
886 KoTextCursor c2( textdoc );
887 c2.setParag( lastParag );
888 c2.setIndex( lastParag->string()->length() );
889 undoRedoInfo.clear();
890 undoRedoInfo.type = UndoRedoInfo::Invalid; // same trick
891 readFormats( c1, c2 ); // gather char-format info but not paraglayouts nor customitems
892
893 KoTextDocCommand * cmd = new KoTextFormatCommand( textdoc, firstParag->paragId(), 0,
894 lastParag->paragId(), c2.index(),
895 undoRedoInfo.text.rawData(), newFormat,
896 formatFlags );
897 textdoc->addCommand( cmd );
898 macroCmd->addCommand( new KoTextCommand( this, /*cmd, */"related to KoTextFormatCommand" ) );
899
900 // sub-command for '3' (paragFormat)
901 cmd = new KoParagFormatCommand( textdoc, firstParag->paragId(), lastParag->paragId(),
902 lstFormats, newFormat );
903 textdoc->addCommand( cmd );
904 macroCmd->addCommand( new KoTextCommand( this, /*cmd, */"related to KoParagFormatCommand" ) );
905 }
906
907 // apply '2' and '3' (format)
908 for ( KoTextParag * parag = firstParag ; parag && parag != lastParag->next() ; parag = parag->next() )
909 {
910 //kdDebug(32500) << "KoTextObject::applyStyle parag:" << parag->paragId()
911 // << ", from 0 to " << parag->string()->length() << ", format=" << newFormat << endl;
912 parag->setFormat( 0, parag->string()->length(), newFormat, true, formatFlags );
913 parag->setFormat( newFormat );
914 }
915 //currentFormat = textdoc->formatCollection()->format( newFormat );
916 //kdDebug(32500) << "KoTextObject::applyStyle currentFormat=" << currentFormat << " " << currentFormat->key() << endl;
917 }
918
919 //resize all variables after applying the style
920 TQPtrListIterator<KoTextCustomItem> cit( textdoc->allCustomItems() );
921 for ( ; cit.current() ; ++cit )
922 cit.current()->resize();
923
924
925 if ( interactive )
926 {
927 setLastFormattedParag( firstParag );
928 formatMore( 2 );
929 emit repaintChanged( this );
930 emit updateUI( true );
931 emit showCursor();
932 }
933
934 undoRedoInfo.clear();
935
936 return macroCmd;
937}
938
939void KoTextObject::applyStyleChange( KoStyleChangeDefMap changed )
940{
941#if 0 //#ifndef NDEBUG
942 kdDebug(32500) << "KoTextObject::applyStyleChange " << changed.count() << " styles." << endl;
943 for( KoStyleChangeDefMap::const_iterator it = changed.begin(); it != changed.end(); ++it ) {
944 kdDebug(32500) << " " << it.key()->name()
945 << " paragLayoutChanged=" << (*it).paragLayoutChanged
946 << " formatChanged=" << (*it).formatChanged
947 << endl;
948 }
949#endif
950
951 KoTextParag *p = textdoc->firstParag();
952 while ( p ) {
953 KoStyleChangeDefMap::Iterator it = changed.find( p->style() );
954 if ( it != changed.end() )
955 {
956 if ( (*it).paragLayoutChanged == -1 || (*it).formatChanged == -1 ) // Style has been deleted
957 {
958 p->setStyle( m_defaultStyle ); // keeps current formatting
959 // TODO, make this undoable somehow
960 }
961 else
962 {
963 // Apply this style again, to get the changes
964 KoTextCursor cursor( textdoc );
965 cursor.setParag( p );
966 cursor.setIndex( 0 );
967 //kdDebug(32500) << "KoTextObject::applyStyleChange applying to paragraph " << p << " " << p->paragId() << endl;
968 applyStyle( &cursor, it.key(),
969 KoTextDocument::Temp, // A selection we can't have at this point
970 (*it).paragLayoutChanged, (*it).formatChanged,
971 false, false ); // don't create undo/redo, not interactive
972 }
973 } else {
974 //kdDebug(32500) << "KoTextObject::applyStyleChange leaving paragraph unchanged: " << p << " " << p->paragId() << endl;
975 }
976
977 p = p->next();
978 }
979 setLastFormattedParag( textdoc->firstParag() );
980 formatMore( 2 );
981 emit repaintChanged( this );
982 emit updateUI( true );
983}
984
986KCommand *KoTextObject::setFormatCommand( const KoTextFormat *format, int flags, bool zoomFont )
987{
988 textdoc->selectAll( KoTextDocument::Temp );
989 KCommand *cmd = setFormatCommand( 0L, 0L, format, flags, zoomFont, KoTextDocument::Temp );
990 textdoc->removeSelection( KoTextDocument::Temp );
991 return cmd;
992}
993
994KCommand * KoTextObject::setFormatCommand( KoTextCursor * cursor, KoTextFormat ** pCurrentFormat, const KoTextFormat *format, int flags, bool /*zoomFont*/, KoTextDocument::SelectionId selectionId )
995{
996 KCommand *ret = 0;
997 if ( protectContent() )
998 return ret;
999
1000 KoTextFormat* newFormat = 0;
1001 // Get new format from collection if
1002 // - caller has notion of a "current format" and new format is different
1003 // - caller has no notion of "current format", e.g. whole textobjects
1004 bool isNewFormat = ( pCurrentFormat && *pCurrentFormat && (*pCurrentFormat)->key() != format->key() );
1005 if ( isNewFormat || !pCurrentFormat )
1006 {
1007#if 0
1008 int origFontSize = 0;
1009 if ( zoomFont ) // The format has a user-specified font (e.g. setting a style, or a new font size)
1010 {
1011 origFontSize = format->pointSize();
1012 format->setPointSize( zoomedFontSize( origFontSize ) );
1013 //kdDebug(32500) << "KoTextObject::setFormatCommand format " << format->key() << " zoomed from " << origFontSize << " to " << format->font().pointSizeFloat() << endl;
1014 }
1015#endif
1016 // Remove ref to current format, if caller wanted that
1017 if ( pCurrentFormat )
1018 (*pCurrentFormat)->removeRef();
1019 // Find format in collection
1020 newFormat = textdoc->formatCollection()->format( format );
1021 if ( newFormat->isMisspelled() ) {
1022 KoTextFormat fNoMisspelled( *newFormat );
1023 newFormat->removeRef();
1024 fNoMisspelled.setMisspelled( false );
1025 newFormat = textdoc->formatCollection()->format( &fNoMisspelled );
1026 }
1027 if ( pCurrentFormat )
1028 (*pCurrentFormat) = newFormat;
1029 }
1030
1031 if ( textdoc->hasSelection( selectionId, true ) ) {
1032 emit hideCursor();
1033 KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
1034 KoTextCursor c2 = textdoc->selectionEndCursor( selectionId );
1035 undoRedoInfo.clear();
1036 int id = c1.parag()->paragId();
1037 int index = c1.index();
1038 int eid = c2.parag()->paragId();
1039 int eindex = c2.index();
1040 readFormats( c1, c2 ); // read previous formatting info
1041 //kdDebug(32500) << "KoTextObject::setFormatCommand undoredo info done" << endl;
1042 textdoc->setFormat( selectionId, format, flags );
1043 if ( !undoRedoInfo.customItemsMap.isEmpty() )
1044 {
1045 // Some custom items (e.g. variables) depend on the format
1046 CustomItemsMap::Iterator it = undoRedoInfo.customItemsMap.begin();
1047 for ( ; it != undoRedoInfo.customItemsMap.end(); ++it )
1048 it.data()->resize();
1049 }
1051 textdoc, id, index, eid, eindex, undoRedoInfo.text.rawData(),
1052 format, flags );
1053 textdoc->addCommand( cmd );
1054 ret = new KoTextCommand( this, /*cmd, */i18n("Format Text") );
1055 undoRedoInfo.clear();
1056 setLastFormattedParag( c1.parag() );
1057 formatMore( 2 );
1058 emit repaintChanged( this );
1059 emit showCursor();
1060 }
1061 if ( isNewFormat ) {
1062 emit showCurrentFormat();
1063 //kdDebug(32500) << "KoTextObject::setFormatCommand index=" << cursor->index() << " length-1=" << cursor->parag()->length() - 1 << endl;
1064 if ( cursor && cursor->index() == cursor->parag()->length() - 1 ) {
1065 newFormat->addRef();
1066 cursor->parag()->string()->setFormat( cursor->index(), newFormat, true );
1067 if ( cursor->parag()->length() == 1 ) {
1068 newFormat->addRef();
1069 cursor->parag()->setFormat( newFormat );
1070 cursor->parag()->invalidate(0);
1071 cursor->parag()->format();
1072 emit repaintChanged( this );
1073 }
1074 }
1075 }
1076 return ret;
1077}
1078
1079void KoTextObject::setFormat( KoTextCursor * cursor, KoTextFormat ** currentFormat, KoTextFormat *format, int flags, bool zoomFont )
1080{
1081 if ( protectContent() )
1082 return;
1083 KCommand *cmd = setFormatCommand( cursor, currentFormat, format, flags, zoomFont );
1084 if (cmd)
1085 emit newCommand( cmd );
1086}
1087
1088void KoTextObject::emitNewCommand(KCommand *cmd)
1089{
1090 if(cmd)
1091 emit newCommand( cmd );
1092}
1093
1094KCommand *KoTextObject::setCounterCommand( KoTextCursor * cursor, const KoParagCounter & counter, KoTextDocument::SelectionId selectionId )
1095{
1096 if ( protectContent() )
1097 return 0L;
1098 const KoParagCounter * curCounter = 0L;
1099 if(cursor)
1100 curCounter=cursor->parag()->counter();
1101 if ( !textdoc->hasSelection( selectionId, true ) &&
1102 curCounter && counter == *curCounter ) {
1103 return 0L;
1104 }
1105 emit hideCursor();
1106 storeParagUndoRedoInfo( cursor, selectionId );
1107 if ( !textdoc->hasSelection( selectionId, true ) && cursor) {
1108 cursor->parag()->setCounter( counter );
1109 setLastFormattedParag( cursor->parag() );
1110 } else {
1111 KoTextParag *start = textdoc->selectionStart( selectionId );
1112 KoTextParag *end = textdoc->selectionEnd( selectionId );
1113#if 0
1114 // Special hack for BR25742, don't apply bullet to last empty parag of the selection
1115 if ( start != end && end->length() <= 1 )
1116 {
1117 end = end->prev();
1118 undoRedoInfo.eid = end->paragId();
1119 }
1120#endif
1121 setLastFormattedParag( start );
1122 for ( ; start && start != end->next() ; start = start->next() )
1123 {
1124 if ( start->length() > 1 ) // don't apply to empty paragraphs (#25742, #34062)
1125 start->setCounter( counter );
1126 }
1127 }
1128 formatMore( 2 );
1129 emit repaintChanged( this );
1130 if ( !undoRedoInfo.newParagLayout.counter )
1131 undoRedoInfo.newParagLayout.counter = new KoParagCounter;
1132 *undoRedoInfo.newParagLayout.counter = counter;
1133 KoTextParagCommand *cmd = new KoTextParagCommand(
1134 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1135 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1136 KoParagLayout::BulletNumber );
1137 textdoc->addCommand( cmd );
1138
1139 undoRedoInfo.clear(); // type is still Invalid -> no command created
1140 emit showCursor();
1141 emit updateUI( true );
1142 return new KoTextCommand( this, /*cmd, */i18n("Change List Type") );
1143}
1144
1145KCommand * KoTextObject::setAlignCommand( KoTextCursor * cursor, int align, KoTextDocument::SelectionId selectionId )
1146{
1147 if ( protectContent() )
1148 return 0L;
1149 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1150 (int)cursor->parag()->alignment() == align )
1151 return 0L; // No change needed.
1152
1153 emit hideCursor();
1154 storeParagUndoRedoInfo( cursor ,selectionId );
1155 if ( !textdoc->hasSelection( selectionId, true ) &&cursor ) {
1156 cursor->parag()->setAlign(align);
1157 setLastFormattedParag( cursor->parag() );
1158 }
1159 else
1160 {
1161 KoTextParag *start = textdoc->selectionStart( selectionId );
1162 KoTextParag *end = textdoc->selectionEnd( selectionId );
1163 setLastFormattedParag( start );
1164 for ( ; start && start != end->next() ; start = start->next() )
1165 start->setAlign(align);
1166 }
1167 formatMore( 2 );
1168 emit repaintChanged( this );
1169 undoRedoInfo.newParagLayout.alignment = align;
1170 KoTextParagCommand *cmd = new KoTextParagCommand(
1171 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1172 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1173 KoParagLayout::Alignment );
1174 textdoc->addCommand( cmd );
1175 undoRedoInfo.clear(); // type is still Invalid -> no command created
1176 emit showCursor();
1177 emit updateUI( true );
1178 return new KoTextCommand( this, /*cmd, */i18n("Change Alignment") );
1179}
1180
1181KCommand * KoTextObject::setMarginCommand( KoTextCursor * cursor, TQStyleSheetItem::Margin m, double margin , KoTextDocument::SelectionId selectionId ) {
1182 if ( protectContent() )
1183 return 0L;
1184
1185 //kdDebug(32500) << "KoTextObject::setMargin " << m << " to value " << margin << endl;
1186 //kdDebug(32500) << "Current margin is " << cursor->parag()->margin(m) << endl;
1187 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1188 cursor->parag()->margin(m) == margin )
1189 return 0L; // No change needed.
1190
1191 emit hideCursor();
1192 storeParagUndoRedoInfo( cursor, selectionId );
1193 if ( !textdoc->hasSelection( selectionId, true )&&cursor ) {
1194 cursor->parag()->setMargin(m, margin);
1195 setLastFormattedParag( cursor->parag() );
1196 }
1197 else
1198 {
1199 KoTextParag *start = textdoc->selectionStart( selectionId );
1200 KoTextParag *end = textdoc->selectionEnd( selectionId );
1201 setLastFormattedParag( start );
1202 for ( ; start && start != end->next() ; start = start->next() )
1203 start->setMargin(m, margin);
1204 }
1205 formatMore( 2 );
1206 emit repaintChanged( this );
1207 undoRedoInfo.newParagLayout.margins[m] = margin;
1208 KoTextParagCommand *cmd = new KoTextParagCommand(
1209 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1210 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1211 KoParagLayout::Margins, m );
1212 textdoc->addCommand( cmd );
1213 TQString name;
1214 if ( m == TQStyleSheetItem::MarginFirstLine )
1215 name = i18n("Change First Line Indent");
1216 else if ( m == TQStyleSheetItem::MarginLeft || m == TQStyleSheetItem::MarginRight )
1217 name = i18n("Change Indent");
1218 else
1219 name = i18n("Change Paragraph Spacing");
1220 undoRedoInfo.clear();
1221 emit showCursor();
1222 emit updateUI( true );
1223 return new KoTextCommand( this, /*cmd, */name );
1224}
1225
1226KCommand * KoTextObject::setBackgroundColorCommand( KoTextCursor * cursor,
1227 const TQColor & color,
1228 KoTextDocument::SelectionId selectionId ) {
1229 if ( protectContent() )
1230 return 0L;
1231
1232 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1233 cursor->parag()->backgroundColor() == color )
1234 return 0L; // No change needed.
1235
1236 emit hideCursor();
1237 storeParagUndoRedoInfo( cursor, selectionId );
1238 if ( !textdoc->hasSelection( selectionId, true )&&cursor )
1239 {
1240 // Update a single paragraph
1241 cursor->parag()->setBackgroundColor(color);
1242 setLastFormattedParag( cursor->parag() );
1243 }
1244 else
1245 {
1246 // Update multiple paragraphs
1247 KoTextParag *start = textdoc->selectionStart( selectionId );
1248 KoTextParag *end = textdoc->selectionEnd( selectionId );
1249 setLastFormattedParag( start );
1250 for ( ; start && start != end->next() ; start = start->next() )
1251 start->setBackgroundColor(color);
1252 }
1253 formatMore( 2 );
1254 emit repaintChanged( this );
1255
1256 // Update undo/redo info
1257 undoRedoInfo.newParagLayout.backgroundColor = color;
1258 KoTextParagCommand *cmd = new KoTextParagCommand(
1259 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1260 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1261 KoParagLayout::BackgroundColor );
1262 textdoc->addCommand( cmd );
1263 undoRedoInfo.clear();
1264
1265 emit showCursor();
1266 emit updateUI( true );
1267 return new KoTextCommand( this, /*cmd, */ i18n("Change Paragraph Background Color" ) );
1268}
1269
1270KCommand * KoTextObject::setLineSpacingCommand( KoTextCursor * cursor, double spacing, KoParagLayout::SpacingType _type, KoTextDocument::SelectionId selectionId )
1271{
1272 if ( protectContent() )
1273 return 0L;
1274 //kdDebug(32500) << "KoTextObject::setLineSpacing to value " << spacing << endl;
1275 //kdDebug(32500) << "Current spacing is " << cursor->parag()->kwLineSpacing() << endl;
1276 //kdDebug(32500) << "Comparison says " << ( cursor->parag()->kwLineSpacing() == spacing ) << endl;
1277 //kdDebug(32500) << "hasSelection " << textdoc->hasSelection( selectionId ) << endl;
1278 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1279 cursor->parag()->kwLineSpacing() == spacing
1280 && cursor->parag()->kwLineSpacingType() == _type)
1281 return 0L; // No change needed.
1282
1283 emit hideCursor();
1284 storeParagUndoRedoInfo( cursor, selectionId );
1285 if ( !textdoc->hasSelection( selectionId, true ) && cursor ) {
1286 cursor->parag()->setLineSpacing(spacing);
1287 cursor->parag()->setLineSpacingType( _type);
1288 setLastFormattedParag( cursor->parag() );
1289 }
1290 else
1291 {
1292 KoTextParag *start = textdoc->selectionStart( selectionId );
1293 KoTextParag *end = textdoc->selectionEnd( selectionId );
1294 setLastFormattedParag( start );
1295 for ( ; start && start != end->next() ; start = start->next() )
1296 {
1297 start->setLineSpacing(spacing);
1298 start->setLineSpacingType( _type);
1299 }
1300 }
1301 formatMore( 2 );
1302 emit repaintChanged( this );
1303 undoRedoInfo.newParagLayout.setLineSpacingValue( spacing );
1304 undoRedoInfo.newParagLayout.lineSpacingType = _type;
1305 KoTextParagCommand *cmd = new KoTextParagCommand(
1306 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1307 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1308 KoParagLayout::LineSpacing );
1309 textdoc->addCommand( cmd );
1310
1311 undoRedoInfo.clear();
1312 emit showCursor();
1313 return new KoTextCommand( this, /*cmd, */i18n("Change Line Spacing") );
1314}
1315
1316
1317KCommand * KoTextObject::setBordersCommand( KoTextCursor * cursor, const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& topBorder, const KoBorder& bottomBorder , KoTextDocument::SelectionId selectionId )
1318{
1319 if ( protectContent() )
1320 return 0L;
1321 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1322 cursor->parag()->leftBorder() ==leftBorder &&
1323 cursor->parag()->rightBorder() ==rightBorder &&
1324 cursor->parag()->topBorder() ==topBorder &&
1325 cursor->parag()->bottomBorder() ==bottomBorder )
1326 return 0L; // No change needed.
1327
1328 emit hideCursor();
1329 storeParagUndoRedoInfo( cursor, selectionId );
1330 if ( !textdoc->hasSelection( selectionId, true ) ) {
1331 cursor->parag()->setLeftBorder(leftBorder);
1332 cursor->parag()->setRightBorder(rightBorder);
1333 cursor->parag()->setBottomBorder(bottomBorder);
1334 cursor->parag()->setTopBorder(topBorder);
1335 setLastFormattedParag( cursor->parag() );
1336
1337 if ( cursor->parag()->next() )
1338 cursor->parag()->next()->setChanged( true );
1339 if ( cursor->parag()->prev() )
1340 cursor->parag()->prev()->setChanged( true );
1341 }
1342 else
1343 {
1344 KoTextParag *start = textdoc->selectionStart( selectionId );
1345 KoTextParag *end = textdoc->selectionEnd( selectionId );
1346 setLastFormattedParag( start );
1347 for ( ; start && start != end->next() ; start = start->next() )
1348 {
1349 start->setLeftBorder(leftBorder);
1350 start->setRightBorder(rightBorder);
1351 start->setTopBorder(topBorder);
1352 start->setBottomBorder(bottomBorder);
1353 }
1354 textdoc->selectionStart( selectionId )->setTopBorder(topBorder);
1355
1356 if ( start && start->prev() )
1357 start->prev()->setChanged( true );
1358 if ( end && end->next() )
1359 end->next()->setChanged( true );
1360 }
1361 formatMore( 2 );
1362 emit repaintChanged( this );
1363 undoRedoInfo.newParagLayout.leftBorder=leftBorder;
1364 undoRedoInfo.newParagLayout.rightBorder=rightBorder;
1365 undoRedoInfo.newParagLayout.topBorder=topBorder;
1366 undoRedoInfo.newParagLayout.bottomBorder=bottomBorder;
1367
1368 KoTextParagCommand *cmd = new KoTextParagCommand(
1369 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1370 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1371 KoParagLayout::Borders, (TQStyleSheetItem::Margin)-1 );
1372 textdoc->addCommand( cmd );
1373
1374 undoRedoInfo.clear();
1375 emit showCursor();
1376 emit updateUI( true );
1377 return new KoTextCommand( this, /*cmd, */i18n("Change Borders") );
1378}
1379
1380KCommand * KoTextObject::setJoinBordersCommand( KoTextCursor * cursor, bool join, KoTextDocument::SelectionId selectionId )
1381{
1382 if ( protectContent() )
1383 return 0L;
1384 if ( !textdoc->hasSelection( selectionId, true ) &&
1385 cursor && cursor->parag()->joinBorder() == join )
1386 return 0L; // No change needed.
1387
1388 emit hideCursor();
1389 storeParagUndoRedoInfo( cursor, KoTextDocument::Standard );
1390 if ( !textdoc->hasSelection( selectionId, true ) )
1391 {
1392 cursor->parag()->setJoinBorder( join );
1393 setLastFormattedParag( cursor->parag() );
1394
1395 if ( cursor->parag()->next() )
1396 cursor->parag()->next()->setChanged( true );
1397 if ( cursor->parag()->prev() )
1398 cursor->parag()->prev()->setChanged( true );
1399 }
1400 else
1401 {
1402 KoTextParag *start = textdoc->selectionStart( selectionId );
1403 KoTextParag *end = textdoc->selectionEnd( selectionId );
1404 setLastFormattedParag( start );
1405 for ( ; start && start != end->next() ; start = start->next() )
1406 {
1407 start->setJoinBorder( true );
1408 }
1409 end->setJoinBorder ( true );
1410
1411 if ( start && start->prev() )
1412 start->prev()->setChanged( true );
1413 if ( end && end->next() )
1414 end->next()->setChanged( true );
1415 }
1416 formatMore( 2 );
1417
1418 emit repaintChanged( this );
1419 undoRedoInfo.newParagLayout.joinBorder=join;
1420
1421 KoTextParagCommand *cmd = new KoTextParagCommand(
1422 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1423 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1424 KoParagLayout::Borders, (TQStyleSheetItem::Margin)-1 );
1425 textdoc->addCommand( cmd );
1426
1427 undoRedoInfo.clear();
1428 emit ensureCursorVisible();
1429 emit showCursor();
1430 emit updateUI( true );
1431 return new KoTextCommand( this, /*cmd, */i18n("Change Join Borders") );
1432}
1433
1434
1435KCommand * KoTextObject::setTabListCommand( KoTextCursor * cursor, const KoTabulatorList &tabList, KoTextDocument::SelectionId selectionId )
1436{
1437 if ( protectContent() )
1438 return 0L;
1439 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1440 cursor->parag()->tabList() == tabList )
1441 return 0L; // No change needed.
1442
1443 emit hideCursor();
1444 storeParagUndoRedoInfo( cursor, selectionId );
1445
1446 if ( !textdoc->hasSelection( selectionId, true ) && cursor ) {
1447 cursor->parag()->setTabList( tabList );
1448 setLastFormattedParag( cursor->parag() );
1449 }
1450 else
1451 {
1452 KoTextParag *start = textdoc->selectionStart( selectionId );
1453 KoTextParag *end = textdoc->selectionEnd( selectionId );
1454 setLastFormattedParag( start );
1455 for ( ; start && start != end->next() ; start = start->next() )
1456 start->setTabList( tabList );
1457 }
1458
1459 formatMore( 2 );
1460 emit repaintChanged( this );
1461 undoRedoInfo.newParagLayout.setTabList( tabList );
1462 KoTextParagCommand *cmd = new KoTextParagCommand(
1463 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1464 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1465 KoParagLayout::Tabulator);
1466 textdoc->addCommand( cmd );
1467 undoRedoInfo.clear();
1468 emit showCursor();
1469 emit updateUI( true );
1470 return new KoTextCommand( this, /*cmd, */i18n("Change Tabulator") );
1471}
1472
1473KCommand * KoTextObject::setParagDirectionCommand( KoTextCursor * cursor, TQChar::Direction d, KoTextDocument::SelectionId selectionId )
1474{
1475 if ( protectContent() )
1476 return 0L;
1477 if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
1478 cursor->parag()->direction() == d )
1479 return 0L; // No change needed.
1480
1481 emit hideCursor();
1482 storeParagUndoRedoInfo( cursor, selectionId );
1483
1484 if ( !textdoc->hasSelection( selectionId, true ) && cursor ) {
1485 cursor->parag()->setDirection( d );
1486 setLastFormattedParag( cursor->parag() );
1487 }
1488 else
1489 {
1490 KoTextParag *start = textdoc->selectionStart( selectionId );
1491 KoTextParag *end = textdoc->selectionEnd( selectionId );
1492 setLastFormattedParag( start );
1493 for ( ; start && start != end->next() ; start = start->next() )
1494 start->setDirection( d );
1495 }
1496
1497 formatMore( 2 );
1498 emit repaintChanged( this );
1500#if 0
1501 undoRedoInfo.newParagLayout.direction = d;
1502 KoTextParagCommand *cmd = new KoTextParagCommand(
1503 textdoc, undoRedoInfo.id, undoRedoInfo.eid,
1504 undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
1505 KoParagLayout::Shadow);
1506 textdoc->addCommand( cmd );
1507#endif
1508 undoRedoInfo.clear();
1509 emit showCursor();
1510 emit updateUI( true );
1511#if 0
1512 return new KoTextCommand( this, /*cmd, */i18n("Change Shadow") );
1513#else
1514 return 0L;
1515#endif
1516}
1517
1518void KoTextObject::removeSelectedText( KoTextCursor * cursor, KoTextDocument::SelectionId selectionId, const TQString & cmdName, bool createUndoRedo )
1519{
1520 if ( protectContent() )
1521 return ;
1522 emit hideCursor();
1523 if( createUndoRedo)
1524 {
1525 checkUndoRedoInfo( cursor, UndoRedoInfo::RemoveSelected );
1526 if ( !undoRedoInfo.valid() ) {
1527 textdoc->selectionStart( selectionId, undoRedoInfo.id, undoRedoInfo.index );
1528 undoRedoInfo.text = TQString();
1529 newPlaceHolderCommand( cmdName.isNull() ? i18n("Remove Selected Text") : cmdName );
1530 }
1531 }
1532 KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
1533 KoTextCursor c2 = textdoc->selectionEndCursor( selectionId );
1534 readFormats( c1, c2, true, true );
1535 //kdDebug(32500) << "KoTextObject::removeSelectedText text=" << undoRedoInfo.text.toString() << endl;
1536
1537 textdoc->removeSelectedText( selectionId, cursor );
1538
1539 setLastFormattedParag( cursor->parag() );
1540 formatMore( 2 );
1541 emit repaintChanged( this );
1542 emit ensureCursorVisible();
1543 emit updateUI( true );
1544 emit showCursor();
1545 if(selectionId==KoTextDocument::Standard || selectionId==KoTextDocument::InputMethodPreedit)
1546 selectionChangedNotify();
1547 if ( createUndoRedo)
1548 undoRedoInfo.clear();
1549}
1550
1551KCommand * KoTextObject::removeSelectedTextCommand( KoTextCursor * cursor, KoTextDocument::SelectionId selectionId, bool repaint )
1552{
1553 if ( protectContent() )
1554 return 0L;
1555 if ( !textdoc->hasSelection( selectionId, true ) )
1556 return 0L;
1557
1558 undoRedoInfo.clear();
1559 textdoc->selectionStart( selectionId, undoRedoInfo.id, undoRedoInfo.index );
1560 Q_ASSERT( undoRedoInfo.id >= 0 );
1561
1562 KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
1563 KoTextCursor c2 = textdoc->selectionEndCursor( selectionId );
1564 readFormats( c1, c2, true, true );
1565
1566 textdoc->removeSelectedText( selectionId, cursor );
1567
1568 KMacroCommand *macroCmd = new KMacroCommand( i18n("Remove Selected Text") );
1569
1570 KoTextDocCommand *cmd = deleteTextCommand( textdoc, undoRedoInfo.id, undoRedoInfo.index,
1571 undoRedoInfo.text.rawData(),
1572 undoRedoInfo.customItemsMap,
1573 undoRedoInfo.oldParagLayouts );
1574 textdoc->addCommand(cmd);
1575 macroCmd->addCommand(new KoTextCommand( this, /*cmd, */TQString() ));
1576
1577 if(!undoRedoInfo.customItemsMap.isEmpty())
1578 undoRedoInfo.customItemsMap.deleteAll( macroCmd );
1579
1580 undoRedoInfo.type = UndoRedoInfo::Invalid; // we don't want clear() to create a command
1581 undoRedoInfo.clear();
1582 if ( repaint )
1583 selectionChangedNotify();
1584 return macroCmd;
1585}
1586
1587KCommand* KoTextObject::replaceSelectionCommand( KoTextCursor * cursor, const TQString & replacement,
1588 const TQString & cmdName,
1589 KoTextDocument::SelectionId selectionId,
1590 int insertFlags,
1591 CustomItemsMap customItemsMap )
1592{
1593 if ( protectContent() )
1594 return 0L;
1595 Q_ASSERT( ( insertFlags & DoNotRemoveSelected ) == 0 ); // nonsensical
1596 const bool repaint = ( insertFlags & DoNotRepaint ) == 0; // DoNotRepaint is set during search/replace
1597 if ( repaint )
1598 emit hideCursor();
1599 // This could be improved to use a macro command only when there's a selection to remove.
1600 KMacroCommand * macroCmd = new KMacroCommand( cmdName );
1601
1602 // Remember formatting
1603 KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
1604 KoTextFormat * format = c1.parag()->at( c1.index() )->format();
1605 format->addRef();
1606
1607 // Remove selected text, if any
1608 KCommand* removeSelCmd = removeSelectedTextCommand( cursor, selectionId, repaint );
1609 if ( removeSelCmd )
1610 macroCmd->addCommand( removeSelCmd );
1611
1612 // Insert replacement
1613 insert( cursor, format,
1614 replacement, TQString() /* no place holder command */,
1615 selectionId, insertFlags | DoNotRemoveSelected, customItemsMap );
1616
1617 KoTextDocCommand * cmd = new KoTextInsertCommand( textdoc, undoRedoInfo.id, undoRedoInfo.index,
1618 undoRedoInfo.text.rawData(),
1619 CustomItemsMap(), undoRedoInfo.oldParagLayouts );
1620 textdoc->addCommand( cmd );
1621 macroCmd->addCommand( new KoTextCommand( this, /*cmd, */TQString() ) );
1622
1623 undoRedoInfo.type = UndoRedoInfo::Invalid; // we don't want clear() to create a command
1624 undoRedoInfo.clear();
1625
1626 format->removeRef();
1627
1628 setLastFormattedParag( c1.parag() );
1629 if ( repaint )
1630 {
1631 formatMore( 2 );
1632 emit repaintChanged( this );
1633 emit ensureCursorVisible();
1634 emit updateUI( true );
1635 emit showCursor();
1636 if(selectionId==KoTextDocument::Standard)
1637 selectionChangedNotify();
1638 }
1639 return macroCmd;
1640}
1641
1642KCommand * KoTextObject::insertParagraphCommand( KoTextCursor *cursor )
1643{
1644 if ( protectContent() )
1645 return 0L;
1646 return replaceSelectionCommand( cursor, "\n", TQString(), KoTextDocument::Standard, CheckNewLine );
1647}
1648
1649void KoTextObject::highlightPortion( KoTextParag * parag, int index, int length, bool repaint )
1650{
1651 if ( !m_highlightSelectionAdded )
1652 {
1653 textdoc->addSelection( KoTextDocument::HighlightSelection );
1654 textdoc->setSelectionColor( KoTextDocument::HighlightSelection,
1655 TQApplication::palette().color( TQPalette::Active, TQColorGroup::Dark ) );
1656 textdoc->setInvertSelectionText( KoTextDocument::HighlightSelection, true );
1657 m_highlightSelectionAdded = true;
1658 }
1659
1660 removeHighlight(repaint); // remove previous highlighted selection
1661 KoTextCursor cursor( textdoc );
1662 cursor.setParag( parag );
1663 cursor.setIndex( index );
1664 textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
1665 cursor.setIndex( index + length );
1666 textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
1667 if ( repaint ) {
1668 parag->setChanged( true );
1669 emit repaintChanged( this );
1670 }
1671}
1672
1673void KoTextObject::removeHighlight(bool repaint)
1674{
1675 if ( textdoc->hasSelection( KoTextDocument::HighlightSelection, true ) )
1676 {
1677 KoTextParag * oldParag = textdoc->selectionStart( KoTextDocument::HighlightSelection );
1678 oldParag->setChanged( true );
1679 textdoc->removeSelection( KoTextDocument::HighlightSelection );
1680 }
1681 if ( repaint )
1682 emit repaintChanged( this );
1683}
1684
1685void KoTextObject::selectAll( bool select )
1686{
1687 if ( !select )
1688 textdoc->removeSelection( KoTextDocument::Standard );
1689 else
1690 textdoc->selectAll( KoTextDocument::Standard );
1691 selectionChangedNotify();
1692}
1693
1694void KoTextObject::selectionChangedNotify( bool enableActions /* = true */)
1695{
1696 emit repaintChanged( this );
1697 if ( enableActions )
1699}
1700
1701void KoTextObject::setViewArea( TQWidget* w, int maxY )
1702{
1703 m_mapViewAreas.replace( w, maxY );
1704}
1705
1706void KoTextObject::setLastFormattedParag( KoTextParag *parag )
1707{
1708 //kdDebug() << k_funcinfo << parag << " (" << ( parag ? TQString::number(parag->paragId()) : TQString("(null)") ) << ")" << endl;
1709 if ( !m_lastFormatted || !parag || m_lastFormatted->paragId() >= parag->paragId() ) {
1710 m_lastFormatted = parag;
1711 }
1712}
1713
1714void KoTextObject::ensureFormatted( KoTextParag * parag, bool emitAfterFormatting /* = true */ )
1715{
1716 if ( !textdoc->lastParag() )
1717 return; // safety test
1718 //kdDebug(32500) << name() << " ensureFormatted " << parag->paragId() << endl;
1719 if ( !parag->isValid() && m_lastFormatted == 0 )
1720 m_lastFormatted = parag; // bootstrap
1721
1722 while ( !parag->isValid() )
1723 {
1724 if ( !m_lastFormatted ) {
1725 kdWarning() << "ensureFormatted for parag " << parag << " " << parag->paragId() << " still not formatted, but m_lastFormatted==0" << endl;
1726 return;
1727 }
1728 // The paragid diff is "a good guess". The >=1 is a safety measure ;)
1729 bool ret = formatMore( TQMAX( 1, parag->paragId() - m_lastFormatted->paragId() ), emitAfterFormatting );
1730 if ( !ret ) { // aborted
1731 //kdDebug(32500) << "ensureFormatted aborted!" << endl;
1732 break;
1733 }
1734 }
1735 //kdDebug(32500) << name() << " ensureFormatted " << parag->paragId() << " done" << endl;
1736}
1737
1738bool KoTextObject::formatMore( int count /* = 10 */, bool emitAfterFormatting /* = true */ )
1739{
1740 if ( ( !m_lastFormatted && d->afterFormattingEmitted )
1741 || !m_visible || m_availableHeight == -1 )
1742 return false;
1743
1744 if ( !textdoc->lastParag() )
1745 return false; // safety test
1746
1747 if ( d->abortFormatting ) {
1748 d->abortFormatting = false;
1749 return false;
1750 }
1751
1752 if ( count == 0 )
1753 {
1754 formatTimer->start( interval, true );
1755 return true;
1756 }
1757
1758 int bottom = 0;
1759 if ( m_lastFormatted )
1760 {
1761 d->afterFormattingEmitted = false;
1762
1763 int viewsBottom = 0;
1764 TQMapIterator<TQWidget *, int> mapIt = m_mapViewAreas.begin();
1765 for ( ; mapIt != m_mapViewAreas.end() ; ++mapIt )
1766 viewsBottom = TQMAX( viewsBottom, mapIt.data() );
1767
1768#ifdef DEBUG_FORMAT_MORE
1769 kdDebug(32500) << "formatMore " << name()
1770 << " lastFormatted id=" << m_lastFormatted->paragId()
1771 << " lastFormatted's top=" << m_lastFormatted->rect().top()
1772 << " lastFormatted's height=" << m_lastFormatted->rect().height()
1773 << " count=" << count << " viewsBottom=" << viewsBottom
1774 << " availableHeight=" << m_availableHeight << endl;
1775#endif
1776 if ( m_lastFormatted->prev() == 0 )
1777 {
1778 emit formattingFirstParag();
1779#ifdef TIMING_FORMAT
1780 kdDebug(32500) << "formatMore " << name() << ". First parag -> starting timer" << endl;
1781 m_time.start();
1782#endif
1783 }
1784
1785 // Stop if we have formatted everything or if we need more space
1786 // Otherwise, stop formatting after "to" paragraphs,
1787 // but make sure we format everything the views need
1788 int i;
1789 for ( i = 0;
1790 m_lastFormatted && bottom + m_lastFormatted->rect().height() <= m_availableHeight &&
1791 ( i < count || bottom <= viewsBottom ) ; ++i )
1792 {
1793 KoTextParag* parag = m_lastFormatted;
1794#ifdef DEBUG_FORMAT_MORE
1795 kdDebug(32500) << "formatMore formatting " << parag << " id=" << parag->paragId() << endl;
1796#endif
1797 assert( parag->string() ); // i.e. not deleted
1798 parag->format();
1799 bottom = parag->rect().top() + parag->rect().height();
1800#if 0 //def DEBUG_FORMAT_MORE
1801 kdDebug(32500) << "formatMore(inside) top=" << parag->rect().top()
1802 << " height=" << parag->rect().height()
1803 << " bottom=" << bottom << " m_lastFormatted(next parag) = " << m_lastFormatted->next() << endl;
1804#endif
1805
1806 // Check for Head 1 (i.e. section) titles, and emit them - for the Section variable
1807 if ( parag->counter() && parag->counter()->numbering() == KoParagCounter::NUM_CHAPTER
1808 && parag->counter()->depth() == 0 )
1809 emit chapterParagraphFormatted( parag );
1810
1811 if ( d->abortFormatting ) {
1812#ifdef DEBUG_FORMAT_MORE
1813 kdDebug(32500) << "formatMore formatting aborted. " << endl;
1814#endif
1815 d->abortFormatting = false;
1816 return false;
1817 }
1818
1819 if ( parag != m_lastFormatted )
1820 kdWarning() << "Some code changed m_lastFormatted during formatting! Was " << parag->paragId() << ", is now " << m_lastFormatted->paragId() << endl;
1821#if 0 // This happens now that formatting can 'abort' (e.g. due to page not yet created)
1822 else if (!parag->isValid())
1823 kdWarning() << "PARAGRAPH " << parag->paragId() << " STILL INVALID AFTER FORMATTING" << endl;
1824#endif
1825 m_lastFormatted = parag->next();
1826 }
1827 }
1828 else // formatting was done previously, but not emit afterFormatting
1829 {
1830 TQRect rect = textdoc->lastParag()->rect();
1831 bottom = rect.top() + rect.height();
1832 }
1833#ifdef DEBUG_FORMAT_MORE
1834 TQString id;
1835 if ( m_lastFormatted ) id = TQString(" (%1)").arg(m_lastFormatted->paragId());
1836 kdDebug(32500) << "formatMore finished formatting. "
1837 << " bottom=" << bottom
1838 << " m_lastFormatted=" << m_lastFormatted << id
1839 << endl;
1840#endif
1841
1842 if ( emitAfterFormatting )
1843 {
1844 d->afterFormattingEmitted = true;
1845 bool needMoreSpace = false;
1846 // Check if we need more space
1847 if ( ( bottom > m_availableHeight ) || // this parag is already off page
1848 ( m_lastFormatted && bottom + m_lastFormatted->rect().height() > m_availableHeight ) ) // or next parag will be off page
1849 needMoreSpace = true;
1850 // default value of 'abort' depends on need more space
1851 bool abort = needMoreSpace;
1852 emit afterFormatting( bottom, m_lastFormatted, &abort );
1853 if ( abort )
1854 return false;
1855 else if ( needMoreSpace && m_lastFormatted ) // we got more space, keep formatting then
1856 return formatMore( 2 );
1857 }
1858
1859 // Now let's see when we'll need to get back here.
1860 if ( m_lastFormatted )
1861 {
1862 formatTimer->start( interval, true );
1863#ifdef DEBUG_FORMAT_MORE
1864 kdDebug(32500) << name() << " formatMore: will have to format more. formatTimer->start with interval=" << interval << endl;
1865#endif
1866 }
1867 else
1868 {
1869 interval = TQMAX( 0, interval );
1870#ifdef DEBUG_FORMAT_MORE
1871 kdDebug(32500) << name() << " formatMore: all formatted interval=" << interval << endl;
1872#endif
1873#ifdef TIMING_FORMAT
1874 //if ( frameSetInfo() == FI_BODY )
1875 kdDebug(32500) << "formatMore: " << name() << " all formatted. Took "
1876 << (double)(m_time.elapsed()) / 1000 << " seconds." << endl;
1877#endif
1878 }
1879 return true;
1880}
1881
1883{
1884 d->abortFormatting = true;
1885}
1886
1887void KoTextObject::doChangeInterval()
1888{
1889 //kdDebug(32500) << "KoTextObject::doChangeInterval back to interval=0" << endl;
1890 interval = 0;
1891}
1892
1893void KoTextObject::typingStarted()
1894{
1895 //kdDebug(32500) << "KoTextObject::typingStarted" << endl;
1896 changeIntervalTimer->stop();
1897 interval = 10;
1898}
1899
1900void KoTextObject::typingDone()
1901{
1902 changeIntervalTimer->start( 100, true );
1903}
1904
1905
1906// helper for changeCaseOfText
1907KCommand *KoTextObject::changeCaseOfTextParag( int cursorPosStart, int cursorPosEnd,
1908 KoChangeCaseDia::TypeOfCase _type,
1909 KoTextCursor *cursor, KoTextParag *parag )
1910{
1911 if ( protectContent() )
1912 return 0L;
1913
1914 KMacroCommand * macroCmd = new KMacroCommand( i18n("Change Case") );
1915 KoTextFormat *curFormat = parag->paragraphFormat();
1916 const TQString text = parag->string()->toString().mid( cursorPosStart, cursorPosEnd - cursorPosStart );
1917 int posStart = cursorPosStart;
1918 int posEnd = cursorPosStart;
1919 KoTextCursor c1( textdoc );
1920 KoTextCursor c2( textdoc );
1921 //kdDebug() << k_funcinfo << "from " << cursorPosStart << " to " << cursorPosEnd << " (excluded). Parag=" << parag << " length=" << parag->length() << endl;
1922 for ( int i = cursorPosStart; i < cursorPosEnd; ++i )
1923 {
1924 KoTextStringChar & ch = *(parag->at(i));
1925 KoTextFormat * newFormat = ch.format();
1926 if( ch.isCustom() )
1927 {
1928 posEnd = i;
1929 c1.setParag( parag );
1930 c1.setIndex( posStart );
1931 c2.setParag( parag );
1932 c2.setIndex( posEnd );
1933 //kdDebug() << k_funcinfo << "found custom at " << i << " : doing from " << posStart << " to " << posEnd << endl;
1934
1935 const TQString repl = text.mid( posStart, posEnd - posStart );
1936 textdoc->setSelectionStart( KoTextDocument::Temp, &c1 );
1937 textdoc->setSelectionEnd( KoTextDocument::Temp, &c2 );
1938 macroCmd->addCommand(replaceSelectionCommand(
1939 cursor, textChangedCase(repl,_type),
1940 TQString(), KoTextDocument::Temp));
1941 do
1942 {
1943 ++i;
1944 }
1945 while( parag->at(i)->isCustom() && i != cursorPosEnd);
1946 posStart=i;
1947 posEnd=i;
1948 }
1949 else
1950 {
1951 if ( newFormat != curFormat )
1952 {
1953 posEnd=i;
1954 c1.setParag( parag );
1955 c1.setIndex( posStart );
1956 c2.setParag( parag );
1957 c2.setIndex( posEnd );
1958 //kdDebug() << k_funcinfo << "found new format at " << i << " : doing from " << posStart << " to " << posEnd << endl;
1959
1960 const TQString repl = text.mid( posStart, posEnd - posStart );
1961 textdoc->setSelectionStart( KoTextDocument::Temp, &c1 );
1962 textdoc->setSelectionEnd( KoTextDocument::Temp, &c2 );
1963 macroCmd->addCommand(replaceSelectionCommand(
1964 cursor, textChangedCase(repl,_type),
1965 TQString(), KoTextDocument::Temp));
1966 posStart=i;
1967 posEnd=i;
1968 curFormat = newFormat;
1969 }
1970 }
1971 }
1972 if ( posStart != cursorPosEnd )
1973 {
1974 //kdDebug() << k_funcinfo << "finishing: doing from " << posStart << " to " << cursorPosEnd << endl;
1975 c1.setParag( parag );
1976 c1.setIndex( posStart );
1977 c2.setParag( parag );
1978 c2.setIndex( cursorPosEnd );
1979
1980 textdoc->setSelectionStart( KoTextDocument::Temp, &c1 );
1981 textdoc->setSelectionEnd( KoTextDocument::Temp, &c2 );
1982 const TQString repl = text.mid( posStart, cursorPosEnd - posStart );
1983 macroCmd->addCommand(replaceSelectionCommand(
1984 cursor, textChangedCase(repl,_type),
1985 TQString(), KoTextDocument::Temp));
1986 }
1987 return macroCmd;
1988
1989}
1990
1991KCommand *KoTextObject::changeCaseOfText(KoTextCursor *cursor,KoChangeCaseDia::TypeOfCase _type)
1992{
1993 if ( protectContent() )
1994 return 0L;
1995 KMacroCommand * macroCmd = new KMacroCommand( i18n("Change Case") );
1996
1997 KoTextCursor start = textdoc->selectionStartCursor( KoTextDocument::Standard );
1998 KoTextCursor end = textdoc->selectionEndCursor( KoTextDocument::Standard );
1999 emit hideCursor();
2000
2001 if ( start.parag() == end.parag() )
2002 {
2003 int endIndex = TQMIN( start.parag()->length() - 1, end.index() );
2004 macroCmd->addCommand( changeCaseOfTextParag( start.index(), endIndex, _type,
2005 cursor, start.parag() ) );
2006 }
2007 else
2008 {
2009 macroCmd->addCommand( changeCaseOfTextParag( start.index(), start.parag()->length() - 1, _type,
2010 cursor, start.parag() ) );
2011 KoTextParag *p = start.parag()->next();
2012 while ( p && p != end.parag() )
2013 {
2014 macroCmd->addCommand( changeCaseOfTextParag(0, p->length() - 1, _type, cursor, p ) );
2015 p = p->next();
2016 }
2017 if ( p )
2018 {
2019 int endIndex = TQMIN( p->length() - 1, end.index() );
2020 macroCmd->addCommand( changeCaseOfTextParag(0, endIndex, _type, cursor, end.parag() ));
2021 }
2022 }
2023 formatMore( 2 );
2024 emit repaintChanged( this );
2025 emit ensureCursorVisible();
2026 emit updateUI( true );
2027 emit showCursor();
2028 return macroCmd;
2029}
2030
2031TQString KoTextObject::textChangedCase(const TQString& _text,KoChangeCaseDia::TypeOfCase _type)
2032{
2033 TQString text(_text);
2034 switch(_type)
2035 {
2036 case KoChangeCaseDia::UpperCase:
2037 text=text.upper();
2038 break;
2039 case KoChangeCaseDia::LowerCase:
2040 text=text.lower();
2041 break;
2042 case KoChangeCaseDia::TitleCase:
2043 for(uint i=0;i<text.length();i++)
2044 {
2045 if(text.at(i)!=' ')
2046 {
2047 TQChar prev = text.at(TQMAX(i-1,0));
2048 if(i==0 || prev == ' ' || prev == '\n' || prev == '\t')
2049 text=text.replace(i, 1, text.at(i).upper() );
2050 else
2051 text=text.replace(i, 1, text.at(i).lower() );
2052 }
2053 }
2054 break;
2055 case KoChangeCaseDia::ToggleCase:
2056 for(uint i=0;i<text.length();i++)
2057 {
2058 TQString repl=TQString(text.at(i));
2059 if(text.at(i)!=text.at(i).upper())
2060 repl=repl.upper();
2061 else if(text.at(i).lower()!=text.at(i))
2062 repl=repl.lower();
2063 text=text.replace(i, 1, repl );
2064 }
2065 break;
2066 case KoChangeCaseDia::SentenceCase:
2067 for(uint i=0;i<text.length();i++)
2068 {
2069 if(text.at(i)!=' ')
2070 {
2071 TQChar prev = text.at(TQMAX(i-1,0));
2072 if(i==0 || prev == '\n' ||prev.isPunct())
2073 text=text.replace(i, 1, text.at(i).upper() );
2074 }
2075 }
2076 break;
2077 default:
2078 kdDebug(32500)<<"Error in changeCaseOfText !\n";
2079 break;
2080
2081 }
2082 return text;
2083}
2084
2085// Warning, this doesn't ref the format!
2087{
2088 // We use the formatting of the very first character
2089 // Should we use a style instead, maybe ?
2090 KoTextStringChar *ch = textdoc->firstParag()->at( 0 );
2091 return ch->format();
2092}
2093
2095{
2096 KoTextParag * parag = textdoc->firstParag();
2097 return &(parag->paragLayout());
2098}
2099
2100bool KoTextObject::rtl() const
2101{
2102 return textdoc->firstParag()->string()->isRightToLeft();
2103}
2104
2105void KoTextObject::loadOasisContent( const TQDomElement &bodyElem, KoOasisContext& context, KoStyleCollection * styleColl )
2106{
2107 textDocument()->clear(false); // Get rid of dummy paragraph (and more if any)
2108 setLastFormattedParag( 0L ); // no more parags, avoid UMR in next setLastFormattedParag call
2109
2110 KoTextParag *lastParagraph = textDocument()->loadOasisText( bodyElem, context, 0, styleColl, 0 );
2111
2112 if ( !lastParagraph ) // We created no paragraph
2113 {
2114 // Create an empty one, then. See KoTextDocument ctor.
2115 textDocument()->clear( true );
2116 textDocument()->firstParag()->setStyle( styleColl->findStyle( "Standard" ) );
2117 }
2118 else
2119 textDocument()->setLastParag( lastParagraph );
2120
2121 setLastFormattedParag( textDocument()->firstParag() );
2122}
2123
2124KoTextCursor KoTextObject::pasteOasisText( const TQDomElement &bodyElem, KoOasisContext& context,
2125 KoTextCursor& cursor, KoStyleCollection * styleColl )
2126{
2127 KoTextCursor resultCursor( cursor );
2128 KoTextParag* lastParagraph = cursor.parag();
2129 bool removeNewline = false;
2130 uint pos = cursor.index();
2131 if ( pos == 0 && lastParagraph->length() <= 1 ) {
2132 // Pasting on an empty paragraph -> respect <text:h> in selected text etc.
2133 lastParagraph = lastParagraph->prev();
2134 lastParagraph = textDocument()->loadOasisText( bodyElem, context, lastParagraph, styleColl, cursor.parag() );
2135 if ( lastParagraph ) {
2136 resultCursor.setParag( lastParagraph );
2137 resultCursor.setIndex( lastParagraph->length() - 1 );
2138 }
2139 removeNewline = true;
2140 } else {
2141 // Pasting inside a non-empty paragraph -> insert/append text to it.
2142 // This loop looks for the *FIRST* paragraph only.
2143 for ( TQDomNode text (bodyElem.firstChild()); !text.isNull(); text = text.nextSibling() )
2144 {
2145 TQDomElement tag = text.toElement();
2146 if ( tag.isNull() ) continue;
2147 // The first tag could be a text:p, text:h, text:numbered-paragraph, but also
2148 // a frame (anchored to page), a TOC, etc. For those, don't try to concat-with-existing-paragraph.
2149 // For text:numbered-paragraph, find the text:p or text:h inside it.
2150 TQDomElement tagToLoad = tag;
2151 if ( tag.localName() == "numbered-paragraph" ) {
2152 TQDomElement npchild;
2153 forEachElement( npchild, tag )
2154 {
2155 if ( npchild.localName() == "p" || npchild.localName() == "h" ) {
2156 tagToLoad = npchild;
2157 break;
2158 }
2159 }
2160 }
2161
2162 if ( tagToLoad.localName() == "p" || tagToLoad.localName() == "h" ) {
2163 context.styleStack().save();
2164 context.fillStyleStack( tagToLoad, KoXmlNS::text, "style-name", "paragraph" );
2165
2166 // OO.o compatibility: ignore leading whitespace in <p> and <h> elements
2167 lastParagraph->loadOasisSpan( tagToLoad, context, pos, true );
2168 context.styleStack().restore();
2169
2170 lastParagraph->setChanged( true );
2171 lastParagraph->invalidate( 0 );
2172
2173 // Now split this parag, to make room for the next paragraphs
2174 resultCursor.setParag( lastParagraph );
2175 resultCursor.setIndex( pos );
2176 resultCursor.splitAndInsertEmptyParag( false, true );
2177 removeNewline = true;
2178
2179 // Done with first parag, remove it and exit loop
2180 const_cast<TQDomElement &>( bodyElem ).removeChild( tag ); // somewhat hackish
2181 }
2182 break;
2183 }
2184 resultCursor.setParag( lastParagraph );
2185 resultCursor.setIndex( pos );
2186 // Load the rest the usual way.
2187 lastParagraph = textDocument()->loadOasisText( bodyElem, context, lastParagraph, styleColl, lastParagraph->next() );
2188 if ( lastParagraph != resultCursor.parag() ) // we loaded more paragraphs
2189 {
2190 removeNewline = true;
2191 resultCursor.setParag( lastParagraph );
2192 resultCursor.setIndex( lastParagraph->length() - 1 );
2193 }
2194 }
2195 KoTextParag* p = resultCursor.parag();
2196 if ( p ) p = p->next();
2197 // Remove the additional newline that loadOasisText inserted
2198 if ( removeNewline && resultCursor.remove() ) {
2199 if ( m_lastFormatted == p ) { // has been deleted
2200 m_lastFormatted = resultCursor.parag();
2201 }
2202 }
2203 return resultCursor;
2204}
2205
2206void KoTextObject::saveOasisContent( KoXmlWriter& writer, KoSavingContext& context ) const
2207{
2208 textDocument()->saveOasisContent( writer, context );
2209}
2210
2212{
2213 if ( protectContent() )
2214 return 0L;
2215 textdoc->selectAll( KoTextDocument::Temp );
2216 KoTextCursor *cursor = new KoTextCursor( textdoc );
2217 KCommand* cmd = setParagLayoutCommand( cursor, *newLayout, KoTextDocument::Temp,
2218 flags, marginIndex, true /*createUndoRedo*/ );
2219 textdoc->removeSelection( KoTextDocument::Temp );
2220 delete cursor;
2221 return cmd;
2222}
2223
2224void KoTextObject::setFormat( KoTextFormat * newFormat, int flags, bool zoomFont )
2225{
2226 if ( protectContent() )
2227 return ;
2228 // This version of setFormat works on the whole textobject - we use the Temp selection for that
2229 textdoc->selectAll( KoTextDocument::Temp );
2230 KCommand *cmd = setFormatCommand( 0L, 0L, newFormat,
2231 flags, zoomFont, KoTextDocument::Temp );
2232 textdoc->removeSelection( KoTextDocument::Temp );
2233 if (cmd)
2234 emit newCommand( cmd );
2235
2236 KoTextFormat format = *currentFormat();
2237 //format.setPointSize( docFontSize( currentFormat() ) ); // "unzoom" the font size
2238 emit showFormatObject(format);
2239}
2240
2241KCommand *KoTextObject::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type)
2242{
2243 if ( protectContent() )
2244 return 0L;
2245 textdoc->selectAll( KoTextDocument::Standard );
2246 KoTextCursor *cursor = new KoTextCursor( textdoc );
2247 KCommand* cmd = changeCaseOfText(cursor, _type);
2248 textdoc->removeSelection( KoTextDocument::Standard );
2249 delete cursor;
2250 return cmd;
2251}
2252
2253void KoTextObject::setNeedSpellCheck(bool b)
2254{
2255 m_needsSpellCheck = b;
2256 for (KoTextParag * parag = textdoc->firstParag(); parag ; parag = parag->next())
2257 parag->string()->setNeedsSpellCheck( b );
2258}
2259
2260bool KoTextObject::statistics( TQProgressDialog *progress, ulong & charsWithSpace, ulong & charsWithoutSpace, ulong & words, ulong & sentences, ulong & syllables, ulong & lines, bool selected )
2261{
2262 // parts of words for better counting of syllables:
2263 // (only use reg exp if necessary -> speed up)
2264
2265 TQStringList subs_syl;
2266 subs_syl << "cial" << "tia" << "cius" << "cious" << "giu" << "ion" << "iou";
2267 TQStringList subs_syl_regexp;
2268 subs_syl_regexp << "sia$" << "ely$";
2269
2270 TQStringList add_syl;
2271 add_syl << "ia" << "riet" << "dien" << "iu" << "io" << "ii";
2272 TQStringList add_syl_regexp;
2273 add_syl_regexp << "[aeiouym]bl$" << "[aeiou]{3}" << "^mc" << "ism$"
2274 << "[^l]lien" << "^coa[dglx]." << "[^gq]ua[^auieo]" << "dnt$";
2275
2276 TQString s;
2277 KoTextParag * parag = textdoc->firstParag();
2278 for ( ; parag ; parag = parag->next() )
2279 {
2280 if ( progress )
2281 {
2282 progress->setProgress(progress->progress()+1);
2283 // MA: resizing if KWStatisticsDialog does not work correct with this enabled, don't know why
2284 kapp->processEvents();
2285 if ( progress->wasCancelled() )
2286 return false;
2287 }
2288 // start of a table
2289/* if ( parag->at(0)->isCustom())
2290 {
2291 KoLinkVariable *var=dynamic_cast<KoLinkVariable *>(parag->at(0)->customItem());
2292 if(!var)
2293 continue;
2294 }*/
2295 bool hasTrailingSpace = true;
2296 if ( !selected ) {
2297 s = parag->string()->toString();
2298 lines += parag->lines();
2299 } else {
2300 if ( parag->hasSelection( KoTextDocument::Standard ) ) {
2301 hasTrailingSpace = false;
2302 s = parag->string()->toString();
2303 if ( !( parag->fullSelected( KoTextDocument::Standard ) ) ) {
2304 s = s.mid( parag->selectionStart( KoTextDocument::Standard ), parag->selectionEnd( KoTextDocument::Standard ) - parag->selectionStart( KoTextDocument::Standard ) );
2305 lines+=numberOfparagraphLineSelected(parag);
2306 }
2307 else
2308 lines += parag->lines();
2309 } else {
2310 continue;
2311 }
2312 }
2313
2314 // Character count
2315 for ( uint i = 0 ; i < s.length() - ( hasTrailingSpace ? 1 : 0 ) ; ++i )
2316 {
2317 TQChar ch = s[i];
2318 ++charsWithSpace;
2319 if ( !ch.isSpace() )
2320 ++charsWithoutSpace;
2321 }
2322
2323 // Syllable and Word count
2324 // Algorithm mostly taken from Greg Fast's Lingua::EN::Syllable module for Perl.
2325 // This guesses correct for 70-90% of English words, but the overall value
2326 // is quite good, as some words get a number that's too high and others get
2327 // one that's too low.
2328 // IMPORTANT: please test any changes against demos/statistics.kwd
2329 TQRegExp re("\\s+");
2330 TQStringList wordlist = TQStringList::split(re, s);
2331 words += wordlist.count();
2332 re.setCaseSensitive(false);
2333 for ( TQStringList::Iterator it = wordlist.begin(); it != wordlist.end(); ++it ) {
2334 TQString word = *it;
2335 re.setPattern("[!?.,:_\"-]"); // clean word from punctuation
2336 word.remove(re);
2337 if ( word.length() <= 3 ) { // extension to the original algorithm
2338 syllables++;
2339 continue;
2340 }
2341 re.setPattern("e$");
2342 word.remove(re);
2343 re.setPattern("[^aeiouy]+");
2344 TQStringList syls = TQStringList::split(re, word);
2345 int word_syllables = 0;
2346 for ( TQStringList::Iterator it = subs_syl.begin(); it != subs_syl.end(); ++it ) {
2347 if( word.find(*it, 0, false) != -1 )
2348 word_syllables--;
2349 }
2350 for ( TQStringList::Iterator it = subs_syl_regexp.begin(); it != subs_syl_regexp.end(); ++it ) {
2351 re.setPattern(*it);
2352 if( word.find(re) != -1 )
2353 word_syllables--;
2354 }
2355 for ( TQStringList::Iterator it = add_syl.begin(); it != add_syl.end(); ++it ) {
2356 if( word.find(*it, 0, false) != -1 )
2357 word_syllables++;
2358 }
2359 for ( TQStringList::Iterator it = add_syl_regexp.begin(); it != add_syl_regexp.end(); ++it ) {
2360 re.setPattern(*it);
2361 if( word.find(re) != -1 )
2362 word_syllables++;
2363 }
2364 word_syllables += syls.count();
2365 if ( word_syllables == 0 )
2366 word_syllables = 1;
2367 syllables += word_syllables;
2368 }
2369 re.setCaseSensitive(true);
2370
2371 // Sentence count
2372 // Clean up for better result, destroys the original text but we only want to count
2373 s = s.stripWhiteSpace();
2374 TQChar lastchar = s.at(s.length());
2375 if( ! s.isEmpty() && ! KoAutoFormat::isMark( lastchar ) ) { // e.g. for headlines
2376 s = s + ".";
2377 }
2378 re.setPattern("[.?!]+"); // count "..." as only one "."
2379 s.replace(re, ".");
2380 re.setPattern("\\d\\.\\d"); // don't count floating point numbers as sentences
2381 s.replace(re, "0,0");
2382 re.setPattern("[A-Z]\\.+"); // don't count "U.S.A." as three sentences
2383 s.replace(re, "*");
2384 for ( uint i = 0 ; i < s.length() ; ++i )
2385 {
2386 TQChar ch = s[i];
2387 if ( KoAutoFormat::isMark( ch ) )
2388 ++sentences;
2389 }
2390 }
2391 return true;
2392}
2393
2394int KoTextObject::numberOfparagraphLineSelected( KoTextParag *parag)
2395{
2396 int indexOfLineStart;
2397 int lineStart;
2398 int lineEnd;
2399 KoTextCursor c1 = textdoc->selectionStartCursor( KoTextDocument::Standard );
2400 KoTextCursor c2 = textdoc->selectionEndCursor( KoTextDocument::Standard );
2401 parag->lineStartOfChar( c1.index(), &indexOfLineStart, &lineStart );
2402
2403 parag->lineStartOfChar( c2.index(), &indexOfLineStart, &lineEnd );
2404 return (lineEnd - lineStart+1);
2405}
2406
2407KoVariable* KoTextObject::variableAtPoint( const TQPoint& iPoint ) const
2408{
2409 KoTextCursor cursor( textDocument() );
2410 int variablePosition = -1;
2411 cursor.place( iPoint, textDocument()->firstParag(), false, &variablePosition );
2412 if ( variablePosition == -1 )
2413 return 0;
2414 return variableAtPosition( cursor.parag(), variablePosition );
2415}
2416
2417KoVariable* KoTextObject::variableAtPosition( KoTextParag* parag, int index ) const
2418{
2419 KoTextStringChar * ch = parag->at( index );
2420 if ( ch->isCustom() )
2421 return dynamic_cast<KoVariable *>( ch->customItem() );
2422 return 0;
2423}
2424
2425const char * KoTextObject::acceptSelectionMimeType()
2426{
2427 return "application/vnd.oasis.opendocument.";
2428}
2429
2430TQCString KoTextObject::providesOasis( TQMimeSource* mime )
2431{
2432 const char* fmt;
2433 const char* acceptMimeType = acceptSelectionMimeType();
2434 for ( int i = 0; (fmt = mime->format(i)); ++i )
2435 {
2436 if ( TQString( fmt ).startsWith( acceptMimeType ) )
2437 {
2438 return fmt;
2439 }
2440 }
2441 return "";
2442}
2443
2444#ifndef NDEBUG
2445void KoTextObject::printRTDebug(int info)
2446{
2447 KoTextParag* lastParag = 0;
2448 for (KoTextParag * parag = textdoc->firstParag(); parag ; parag = parag->next())
2449 {
2450 assert( parag->prev() == lastParag );
2451 parag->printRTDebug( info );
2452 lastParag = parag;
2453 }
2454 if ( info == 1 )
2455 textdoc->formatCollection()->debug();
2456}
2457#endif
2458
2460
2461KCommand *KoTextFormatInterface::setBoldCommand(bool on)
2462{
2463 KoTextFormat format( *currentFormat() );
2464 format.setBold( on );
2465 return setFormatCommand( &format, KoTextFormat::Bold );
2466}
2467
2468KCommand *KoTextFormatInterface::setItalicCommand( bool on)
2469{
2470 KoTextFormat format( *currentFormat() );
2471 format.setItalic( on );
2472 return setFormatCommand( &format, KoTextFormat::Italic );
2473}
2474
2475KCommand *KoTextFormatInterface::setUnderlineCommand( bool on )
2476{
2477 KoTextFormat format( *currentFormat() );
2478 format.setUnderlineType( on ? KoTextFormat::U_SIMPLE : KoTextFormat::U_NONE);
2479 return setFormatCommand( &format, KoTextFormat::ExtendUnderLine );
2480}
2481
2482KCommand *KoTextFormatInterface::setUnderlineColorCommand( const TQColor &color )
2483{
2484 KoTextFormat format( *currentFormat() );
2485 format.setTextUnderlineColor( color);
2486 return setFormatCommand( &format, KoTextFormat::ExtendUnderLine );
2487}
2488
2489KCommand *KoTextFormatInterface::setDoubleUnderlineCommand( bool on )
2490{
2491 KoTextFormat format( *currentFormat() );
2492 format.setUnderlineType( on ? KoTextFormat::U_DOUBLE : KoTextFormat::U_NONE);
2493 return setFormatCommand( &format, KoTextFormat::ExtendUnderLine );
2494}
2495
2496KCommand *KoTextFormatInterface::setStrikeOutCommand( bool on )
2497{
2498 KoTextFormat format( *currentFormat() );
2499 format.setStrikeOutType( on ? KoTextFormat::S_SIMPLE : KoTextFormat::S_NONE);
2500 return setFormatCommand( &format, KoTextFormat::StrikeOut );
2501}
2502
2503KCommand *KoTextFormatInterface::setTextBackgroundColorCommand(const TQColor & col)
2504{
2505 KoTextFormat format( *currentFormat() );
2506 format.setTextBackgroundColor( col );
2507 return setFormatCommand( &format, KoTextFormat::TextBackgroundColor );
2508}
2509
2510KCommand *KoTextFormatInterface::setPointSizeCommand( int s )
2511{
2512 KoTextFormat format( *currentFormat() );
2513 format.setPointSize( s );
2514 return setFormatCommand( &format, KoTextFormat::Size, true /* zoom the font size */ );
2515}
2516
2517KCommand *KoTextFormatInterface::setFamilyCommand(const TQString &font)
2518{
2519 KoTextFormat format( *currentFormat() );
2520 format.setFamily( font );
2521 return setFormatCommand( &format, KoTextFormat::Family );
2522}
2523
2524TQColor KoTextFormatInterface::textBackgroundColor() const
2525{
2526 return currentFormat()->textBackgroundColor();
2527}
2528
2529TQColor KoTextFormatInterface::textUnderlineColor()const
2530{
2531 return currentFormat()->textUnderlineColor();
2532}
2533
2534TQColor KoTextFormatInterface::textColor() const
2535{
2536 return currentFormat()->color();
2537}
2538
2539bool KoTextFormatInterface::textUnderline()const
2540{
2541 return currentFormat()->underline();
2542}
2543
2544bool KoTextFormatInterface::textDoubleUnderline()const
2545{
2546 return currentFormat()->doubleUnderline();
2547}
2548
2549bool KoTextFormatInterface::textBold()const
2550{
2551 return currentFormat()->font().bold();
2552}
2553
2554bool KoTextFormatInterface::textStrikeOut()const
2555{
2556 return currentFormat()->font().strikeOut();
2557}
2558
2559bool KoTextFormatInterface::textItalic() const
2560{
2561 return currentFormat()->font().italic();
2562}
2563
2564bool KoTextFormatInterface::textSubScript() const
2565{
2566 return (currentFormat()->vAlign()==KoTextFormat::AlignSubScript);
2567}
2568
2569bool KoTextFormatInterface::textSuperScript() const
2570{
2571 return (currentFormat()->vAlign()==KoTextFormat::AlignSuperScript);
2572}
2573
2574double KoTextFormatInterface::shadowDistanceX() const
2575{
2576 return currentFormat()->shadowDistanceX();
2577}
2578
2579double KoTextFormatInterface::shadowDistanceY() const
2580{
2581 return currentFormat()->shadowDistanceY();
2582}
2583
2584TQColor KoTextFormatInterface::shadowColor() const
2585{
2586 return currentFormat()->shadowColor();
2587}
2588
2589KoTextFormat::AttributeStyle KoTextFormatInterface::fontAttribute() const
2590{
2591 return currentFormat()->attributeFont();
2592}
2593
2594double KoTextFormatInterface::relativeTextSize() const
2595{
2596 return currentFormat()->relativeTextSize();
2597}
2598
2599int KoTextFormatInterface::offsetFromBaseLine()const
2600{
2601 return currentFormat()->offsetFromBaseLine();
2602}
2603
2604bool KoTextFormatInterface::wordByWord()const
2605{
2606 return currentFormat()->wordByWord();
2607}
2608
2609bool KoTextFormatInterface::hyphenation()const
2610{
2611 return currentFormat()->hyphenation();
2612}
2613
2614KoTextFormat::UnderlineType KoTextFormatInterface::underlineType()const
2615{
2616 return currentFormat()->underlineType();
2617}
2618
2619KoTextFormat::StrikeOutType KoTextFormatInterface::strikeOutType()const
2620{
2621 return currentFormat()->strikeOutType();
2622}
2623
2624KoTextFormat::UnderlineStyle KoTextFormatInterface::underlineStyle()const
2625{
2626 return currentFormat()->underlineStyle();
2627}
2628
2629KoTextFormat::StrikeOutStyle KoTextFormatInterface::strikeOutStyle()const
2630{
2631 return currentFormat()->strikeOutStyle();
2632}
2633
2634TQFont KoTextFormatInterface::textFont() const
2635{
2636 TQFont fn( currentFormat()->font() );
2637 // "unzoom" the font size
2638 //fn.setPointSize( static_cast<int>( KoTextZoomHandler::layoutUnitPtToPt( fn.pointSize() ) ) );
2639 return fn;
2640}
2641
2642TQString KoTextFormatInterface::textFontFamily()const
2643{
2644 return currentFormat()->font().family();
2645}
2646
2647TQString KoTextFormatInterface::language() const
2648{
2649 return currentFormat()->language();
2650}
2651
2652KCommand *KoTextFormatInterface::setTextColorCommand(const TQColor &color)
2653{
2654 KoTextFormat format( *currentFormat() );
2655 format.setColor( color );
2656 return setFormatCommand( &format, KoTextFormat::Color );
2657}
2658
2659KCommand *KoTextFormatInterface::setTextSubScriptCommand(bool on)
2660{
2661 KoTextFormat format( *currentFormat() );
2662 if(!on)
2663 format.setVAlign(KoTextFormat::AlignNormal);
2664 else
2665 format.setVAlign(KoTextFormat::AlignSubScript);
2666 return setFormatCommand( &format, KoTextFormat::VAlign );
2667}
2668
2669KCommand *KoTextFormatInterface::setTextSuperScriptCommand(bool on)
2670{
2671 KoTextFormat format( *currentFormat() );
2672 if(!on)
2673 format.setVAlign(KoTextFormat::AlignNormal);
2674 else
2675 format.setVAlign(KoTextFormat::AlignSuperScript);
2676 return setFormatCommand( &format, KoTextFormat::VAlign );
2677}
2678
2679KCommand *KoTextFormatInterface::setDefaultFormatCommand()
2680{
2681 KoTextFormatCollection * coll = currentFormat()->parent();
2682 Q_ASSERT(coll);
2683 if(coll)
2684 {
2685 KoTextFormat * format = coll->defaultFormat();
2686 return setFormatCommand( format, KoTextFormat::Format );
2687 } else {
2688 kdDebug() << "useless call to setDefaultFormatCommand at: " << kdBacktrace() << endl;
2689 }
2690 return 0;
2691}
2692
2693KCommand *KoTextFormatInterface::setAlignCommand(int align)
2694{
2695 KoParagLayout format( *currentParagLayoutFormat() );
2696 format.alignment=align;
2697 return setParagLayoutFormatCommand(&format,KoParagLayout::Alignment);
2698}
2699
2700KCommand *KoTextFormatInterface::setHyphenationCommand( bool _b )
2701{
2702 KoTextFormat format( *currentFormat() );
2703 format.setHyphenation( _b );
2704 return setFormatCommand( &format, KoTextFormat::Hyphenation);
2705}
2706
2707
2708KCommand *KoTextFormatInterface::setShadowTextCommand( double shadowDistanceX, double shadowDistanceY, const TQColor& shadowColor )
2709{
2710 KoTextFormat format( *currentFormat() );
2711 format.setShadow( shadowDistanceX, shadowDistanceY, shadowColor );
2712 return setFormatCommand( &format, KoTextFormat::ShadowText );
2713}
2714
2715KCommand *KoTextFormatInterface::setFontAttributeCommand( KoTextFormat::AttributeStyle _att)
2716{
2717 KoTextFormat format( *currentFormat() );
2718 format.setAttributeFont( _att );
2719 return setFormatCommand( &format, KoTextFormat::Attribute );
2720}
2721
2722KCommand *KoTextFormatInterface::setRelativeTextSizeCommand( double _size )
2723{
2724 KoTextFormat format( *currentFormat() );
2725 format.setRelativeTextSize( _size );
2726 return setFormatCommand( &format, KoTextFormat::VAlign );
2727}
2728
2729KCommand *KoTextFormatInterface::setOffsetFromBaseLineCommand( int _offset )
2730{
2731 KoTextFormat format( *currentFormat() );
2732 format.setOffsetFromBaseLine( _offset );
2733 return setFormatCommand( &format, KoTextFormat::OffsetFromBaseLine );
2734}
2735
2736KCommand *KoTextFormatInterface::setWordByWordCommand( bool _b )
2737{
2738 KoTextFormat format( *currentFormat() );
2739 format.setWordByWord( _b );
2740 return setFormatCommand( &format, KoTextFormat::WordByWord );
2741}
2742
2743#if 0
2744void KoTextFormatInterface::setAlign(int align)
2745{
2746 KCommand *cmd = setAlignCommand( align );
2747 emitNewCommand( cmd );
2748}
2749
2750void KoTextFormatInterface::setMargin(TQStyleSheetItem::Margin m, double margin)
2751{
2752 KCommand *cmd = setMarginCommand( m, margin );
2753 emitNewCommand( cmd );
2754}
2755
2756void KoTextFormatInterface::setTabList(const KoTabulatorList & tabList )
2757{
2758 KCommand *cmd = setTabListCommand( tabList );
2759 emitNewCommand( cmd );
2760}
2761
2762void KoTextFormatInterface::setCounter(const KoParagCounter & counter )
2763{
2764 KCommand *cmd = setCounterCommand( counter );
2765 emitNewCommand( cmd );
2766}
2767
2768void KoTextFormatInterface::setParagLayoutFormat( KoParagLayout *newLayout, int flags, int marginIndex)
2769{
2770 KCommand *cmd = setParagLayoutFormatCommand(newLayout, flags, marginIndex);
2771 emitNewCommand( cmd );
2772}
2773#endif
2774
2775KCommand *KoTextFormatInterface::setMarginCommand(TQStyleSheetItem::Margin m, double margin)
2776{
2777 KoParagLayout format( *currentParagLayoutFormat() );
2778 format.margins[m]=margin;
2779 return setParagLayoutFormatCommand(&format,KoParagLayout::Margins,(int)m);
2780}
2781
2782KCommand *KoTextFormatInterface::setTabListCommand(const KoTabulatorList & tabList )
2783 {
2784 KoParagLayout format( *currentParagLayoutFormat() );
2785 format.setTabList(tabList);
2786 return setParagLayoutFormatCommand(&format,KoParagLayout::Tabulator);
2787}
2788
2789KCommand *KoTextFormatInterface::setCounterCommand(const KoParagCounter & counter )
2790{
2791 KoParagLayout format( *currentParagLayoutFormat() );
2792 if(!format.counter)
2793 format.counter = new KoParagCounter;
2794 *format.counter = counter;
2795 return setParagLayoutFormatCommand(&format,KoParagLayout::BulletNumber);
2796}
2797
2798KCommand *KoTextFormatInterface::setLanguageCommand(const TQString &_lang)
2799{
2800 KoTextFormat format( *currentFormat() );
2801 format.setLanguage(_lang);
2802 return setFormatCommand( &format, KoTextFormat::Language );
2803}
2804
2805KoTextDocCommand *KoTextFormatInterface::deleteTextCommand( KoTextDocument *textdoc, int id, int index, const TQMemArray<KoTextStringChar> & str, const CustomItemsMap & customItemsMap, const TQValueList<KoParagLayout> & oldParagLayouts )
2806{
2807 return textdoc->deleteTextCommand( textdoc, id, index, str, customItemsMap, oldParagLayouts );
2808}
2809
2810#include "KoTextObject.moc"
A CustomItemsMap associates a custom item to an index Used in the undo/redo info for insert/delete te...
void deleteAll(KMacroCommand *macroCmd)
Delete all the items from the map, adding their commands into macroCmd.
void insertItems(const KoTextCursor &startCursor, int size)
Insert all the items from the map, into the existing text.
void addCommand(KCommand *command)
const KoTextFormat & format() const
Return a format.
This is the structure associated with a paragraph (KoTextParag), to define the bullet or numbering of...
unsigned int depth() const
The level of the numbering.
Numbering numbering() const
Numbering type and style.
Command created when changing the default format of paragraphs.
This class holds the paragraph-specific formatting information It's separated from KoTextParag so tha...
SpacingType
Line spacing values Assuming h is the height of the biggest char in the line, and v is the linespacin...
A paragraph style is a combination of a character style and paragraph-layout attributes,...
Base class for "visitors".
KoParagStyle * findStyle(const TQString &name) const
Find style based on the internal name name.
Wraps a KoTextDocCommand into a KCommand, for the UI In fact the KoTextDocCommand isn't even known fr...
virtual KCommand * createCommand()
Called when the item is created or 'deleted' by the user Most custom items don't need to reimplement ...
Command created when changing formatted text.
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
The KoTextObject is the high-level object that contains a KoTextDocument (the list of paragraphs),...
void storeParagUndoRedoInfo(KoTextCursor *cursor, KoTextDocument::SelectionId selectionId=KoTextDocument::Standard)
This prepares undoRedoInfo for a paragraph formatting change If this does too much,...
void applyStyle(KoTextCursor *cursor, const KoParagStyle *style, KoTextDocument::SelectionId selectionId=KoTextDocument::Standard, int paragLayoutFlags=KoParagLayout::All, int formatFlags=KoTextFormat::Format, bool createUndoRedo=true, bool interactive=true)
Apply a KoParagStyle to a selection.
void newPlaceHolderCommand(const TQString &name)
Creates a place holder for a command that will be completed later on.
bool hasSelection() const
return true if some text is selected
virtual const KoParagLayout * currentParagLayoutFormat() const
Use this format for displaying the properties (Align/counter/...) of the object.
void clearUndoRedoInfo()
Terminate our current undo/redo info, to start with a new one.
void repaintChanged(KoTextObject *)
Tell the world that we'd like some repainting to happen.
virtual KoTextFormat * currentFormat() const
Support for treating the whole textobject as a single object Use this format for displaying the prope...
void selectionChanged(bool hasSelection)
Tell the views that the selection changed (for cut/copy...).
void showCurrentFormat()
Same thing, when the current format (of the edit object) was changed.
void applyStyleChange(KoStyleChangeDefMap changed)
Update the paragraph that use the given style, after this style was changed.
void availableHeightNeeded()
Emitted by availableHeight() when the available height hasn't been calculated yet or is invalid.
void formattingFirstParag()
Emitted by formatMore() when formatting the first paragraph.
bool selectionHasCustomItems(KoTextDocument::SelectionId selectionId=KoTextDocument::Standard) const
returns true if the given selection has any custom item in it
int zoomedFontSize(int docFontSize) const
Return the font size in LU, for this user-visible font size in pt.
void insert(KoTextCursor *cursor, KoTextFormat *currentFormat, const TQString &text, const TQString &commandName, KoTextDocument::SelectionId selectionId=KoTextDocument::Standard, int insertFlags=DefaultInsertFlags, CustomItemsMap customItemsMap=CustomItemsMap())
The main "insert" method, including undo/redo creation/update.
void setCursor(KoTextCursor *cursor)
Special hack for undo/redo - used by KoTextView.
void doKeyboardAction(KoTextCursor *cursor, KoTextFormat *&currentFormat, KeyboardAction action)
Executes keyboard action action.
@ OverwriteMode
< if true, the text to be inserted is checked for '\n' (as a paragraph delimiter)
@ DoNotRemoveSelected
whether to remove selected text before
@ DoNotRepaint
usually we repaint in insert(), this allows to turn it off
void afterFormatting(int bottom, KoTextParag *m_lastFormatted, bool *abort)
Emitted by formatMore() after formatting a bunch of paragraphs.
void abortFormatting()
Abort the current formatMore() loop, or prevent the next one from starting.
KoVariable * variableAtPoint(const TQPoint &iPoint) const
Return the variable at the given point (in document coordinates), if any.
void removeSelectedText(KoTextCursor *cursor, KoTextDocument::SelectionId selectionId=KoTextDocument::Standard, const TQString &cmdName=TQString(), bool createUndoRedo=true)
Remove the text currently selected, including undo/redo creation/update.
void copyCharFormatting(KoTextParag *parag, int position, int index, bool moveCustomItems)
Copies a formatted char, <parag, position>, into undoRedoInfo.text, at position index.
void chapterParagraphFormatted(KoTextParag *parag)
Emitted by formatMore() when formatting a "Head 1" paragraph.
KoVariable * variableAtPosition(KoTextParag *parag, int index) const
Return the variable at the given position, if any.
KCommand * applyStyleCommand(KoTextCursor *cursor, const KoParagStyle *style, KoTextDocument::SelectionId selectionId=KoTextDocument::Standard, int paragLayoutFlags=KoParagLayout::All, int formatFlags=KoTextFormat::Format, bool createUndoRedo=true, bool interactive=true)
Helper for applyStyle.
void setViewArea(TQWidget *w, int maxY)
Set the bottom of the view - in LU.
KoTextObject(KoTextZoomHandler *zh, const TQFont &defaultFont, const TQString &defaultLanguage, bool defaultHyphenation, KoParagStyle *defaultStyle, int tabStopWidth=-1, TQObject *parent=0, const char *name=0)
Constructor.
KoTextDocument * textDocument() const
Return the text document contained in this KoTextObject.
void ensureCursorVisible()
The views should make sure the cursor is visible.
void updateUI(bool updateFormat, bool force=false)
Emitted when the formatting under the cursor may have changed.
void setFormat(KoTextCursor *cursor, KoTextFormat **currentFormat, KoTextFormat *format, int flags, bool zoomFont=false)
Set format changes on selection or current cursor.
void highlightPortion(KoTextParag *parag, int index, int length, bool repaint)
Highlighting support (for search/replace, spellchecking etc.).
static TQCString providesOasis(TQMimeSource *mime)
Check if the mimesource mime provides one of the OASIS mimetypes, and if so, return it.
virtual KCommand * setParagLayoutFormatCommand(KoParagLayout *newLayout, int flags, int marginIndex=-1)
Support for changing the format in the whole textobject.
void ensureFormatted(KoTextParag *parag, bool emitAfterFormatting=true)
Make sure that parag is formatted.
int docFontSize(KoTextFormat *format) const
Return the user-visible font size for this format (i.e.
KCommand * setFormatCommand(const KoTextFormat *format, int flags, bool zoomFont=false)
Implementation of setFormatCommand from KoTextFormatInterface - apply change to the whole document.
void pasteText(KoTextCursor *cursor, const TQString &text, KoTextFormat *currentFormat, bool removeSelected)
Paste plain text at the given cursor.
void newCommand(KCommand *cmd)
Emitted when a new command has been created and should be added to the main list of commands (usually...
This class extends KoZoomHandler to add support for WYSIWYG text layouting.
static double ptToLayoutUnitPt(double pt)
Not zoom dependent.
TQString displayName() const
The user-visible name (e.g. translated, or set by the user).
A KoVariable is a custom item, i.e.
Definition KoVariable.h:364
const char * name(StdAction id)
@ Invalid
invalid property type
Definition property.h:68