summaryrefslogtreecommitdiff
path: root/noncore
authorleseb <leseb>2002-07-14 21:21:35 (UTC)
committer leseb <leseb>2002-07-14 21:21:35 (UTC)
commit4feeec8b5b41cfd3d13274411f515524f687da09 (patch) (unidiff)
tree002bbfb9997713e5d5975855d3cfbba7a71b9104 /noncore
parentbdef9cf23ced569a9bc80c1d4f25d85861273b4a (diff)
downloadopie-4feeec8b5b41cfd3d13274411f515524f687da09.zip
opie-4feeec8b5b41cfd3d13274411f515524f687da09.tar.gz
opie-4feeec8b5b41cfd3d13274411f515524f687da09.tar.bz2
opie-write first draft
Diffstat (limited to 'noncore') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-write/main.cpp37
-rw-r--r--noncore/apps/opie-write/mainwindow.cpp570
-rw-r--r--noncore/apps/opie-write/mainwindow.h113
-rw-r--r--noncore/apps/opie-write/opie-write.pro25
-rw-r--r--noncore/apps/opie-write/qcleanuphandler.h139
-rw-r--r--noncore/apps/opie-write/qcomplextext.cpp152
-rw-r--r--noncore/apps/opie-write/qcomplextext_p.h133
-rw-r--r--noncore/apps/opie-write/qrichtext.cpp8085
-rw-r--r--noncore/apps/opie-write/qrichtext_p.cpp706
-rw-r--r--noncore/apps/opie-write/qrichtext_p.h2158
-rw-r--r--noncore/apps/opie-write/qstylesheet.cpp1484
-rw-r--r--noncore/apps/opie-write/qstylesheet.h221
-rw-r--r--noncore/apps/opie-write/qt3namespace.h28
-rw-r--r--noncore/apps/opie-write/qtextedit.cpp4516
-rw-r--r--noncore/apps/opie-write/qtextedit.h448
15 files changed, 18815 insertions, 0 deletions
diff --git a/noncore/apps/opie-write/main.cpp b/noncore/apps/opie-write/main.cpp
new file mode 100644
index 0000000..027af38
--- a/dev/null
+++ b/noncore/apps/opie-write/main.cpp
@@ -0,0 +1,37 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** Licensees holding valid Qtopia Developer license may use this
7** file in accordance with the Qtopia Developer License Agreement
8** provided with the Software.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12** PURPOSE.
13**
14** email sales@trolltech.com for information about Qtopia License
15** Agreements.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#include <qpe/qpeapplication.h>
23#include <qpe/fileselector.h>
24#include "mainwindow.h"
25
26int main( int argc, char ** argv )
27{
28 QPEApplication a( argc, argv );
29
30 MainWindow e;
31 a.showMainDocumentWidget(&e);
32
33 QObject::connect( &a, SIGNAL( lastWindowClosed() ),
34 &a, SLOT( quit() ) );
35
36 a.exec();
37}
diff --git a/noncore/apps/opie-write/mainwindow.cpp b/noncore/apps/opie-write/mainwindow.cpp
new file mode 100644
index 0000000..ed95e83
--- a/dev/null
+++ b/noncore/apps/opie-write/mainwindow.cpp
@@ -0,0 +1,570 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** Licensees holding valid Qtopia Developer license may use this
7** file in accordance with the Qtopia Developer License Agreement
8** provided with the Software.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12** PURPOSE.
13**
14** email sales@trolltech.com for information about Qtopia License
15** Agreements.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#include "mainwindow.h"
23#include <qpe/fileselector.h>
24#include <qpe/applnk.h>
25#include <qpe/resource.h>
26//#include "qspellchecker.h"
27#include "qtextedit.h"
28#include <qaction.h>
29#include <qtoolbar.h>
30#include <qtoolbutton.h>
31#include <qtabwidget.h>
32#include <qapplication.h>
33#include <qfontdatabase.h>
34#include <qcombobox.h>
35#include <qlineedit.h>
36#include <qfileinfo.h>
37#include <qfile.h>
38#include <qfiledialog.h>
39#include <qprinter.h>
40#include <qpaintdevicemetrics.h>
41#include <qmenubar.h>
42#include <qpopupmenu.h>
43#include <qcolordialog.h>
44#include <qpainter.h>
45#include <qstyle.h>
46
47class ButtonMenu : public QToolButton
48{
49 Q_OBJECT
50public:
51 ButtonMenu( QWidget *parent, const char *name=0 )
52 : QToolButton( parent, name ), current(0)
53 {
54 setPopup( new QPopupMenu( this ) );
55 setPopupDelay( 1 );
56 connect( popup(), SIGNAL(activated(int)), this, SLOT(selected(int)) );
57 }
58
59 int insertItem(const QIconSet &icon, const QString &text, int id ) {
60 if ( !popup()->count() ) {
61 setIconSet( icon );
62 current = id;
63 }
64 return popup()->insertItem( icon, text, id );
65 }
66
67 void setCurrentItem( int id ) {
68 if ( id != current ) {
69 current = id;
70 setIconSet( *popup()->iconSet( id ) );
71 }
72 }
73
74 virtual QSize sizeHint() const {
75 return QToolButton::sizeHint() + QSize( 4, 0 );
76 }
77
78signals:
79 void activated( int id );
80
81protected slots:
82 void selected( int id ) {
83 current = id;
84 setIconSet( *popup()->iconSet( id ) );
85 emit activated( id );
86 }
87
88protected:
89 virtual void drawButtonLabel( QPainter *p ) {
90 p->translate( -4, 0 );
91 QToolButton::drawButtonLabel( p );
92 p->translate( 4, 0 );
93 }
94
95private:
96 int current;
97};
98
99//===========================================================================
100
101MainWindow::MainWindow( QWidget *parent, const char *name )
102 : QMainWindow( parent, name ),
103 doc( 0 )
104{
105 setRightJustification(TRUE);
106
107 editorStack = new QWidgetStack( this );
108
109 fileSelector = new FileSelector( "text/html",
110 editorStack, "fileselector" );
111
112
113 fileSelector->setCloseVisible( FALSE );
114 editorStack->addWidget( fileSelector, 0 );
115
116 editor = new Qt3::QTextEdit( editorStack );
117 editor->setTextFormat( Qt::RichText );
118 editorStack->addWidget( editor, 1 );
119
120 setupActions();
121
122 QObject::connect( fileSelector, SIGNAL(closeMe()),
123 this, SLOT(showEditTools()) );
124 QObject::connect( fileSelector, SIGNAL(fileSelected(const DocLnk &)),
125 this, SLOT(openFile(const DocLnk &)) );
126 QObject::connect( fileSelector, SIGNAL(newSelected(const DocLnk&)),
127 this, SLOT(newFile(const DocLnk&)) );
128
129 if ( fileSelector->fileCount() < 1 )
130 fileNew();
131 else {
132 fileOpen();
133 }
134 doConnections( editor );
135
136 setCentralWidget( editorStack );
137}
138
139MainWindow::~MainWindow()
140{
141 save();
142}
143
144void MainWindow::setupActions()
145{
146 setToolBarsMovable(false);
147
148 tbMenu = new QToolBar( this );
149 tbMenu->setHorizontalStretchable( TRUE );
150
151 QMenuBar *menu = new QMenuBar( tbMenu );
152
153 tbEdit = new QToolBar( this );
154
155 QPopupMenu *file = new QPopupMenu( this );
156 menu->insertItem( tr("File"), file );
157
158 QPopupMenu *edit = new QPopupMenu( this );
159 menu->insertItem( tr("Edit"), edit );
160
161 // ### perhaps these shortcut keys should have some
162 // IPaq keys defined???
163 QAction *a;
164
165 a = new QAction( tr( "New" ), Resource::loadPixmap("new"), QString::null, 0, this, 0 );
166 connect( a, SIGNAL(activated()), this, SLOT(fileNew()) );
167 a->addTo( file );
168
169 a = new QAction( tr( "Open" ), Resource::loadPixmap( "fileopen" ), QString::null, 0, this, 0 );
170 connect( a, SIGNAL(activated()), this, SLOT(fileOpen()) );
171 a->addTo( file );
172
173 a = new QAction( tr( "Undo" ), Resource::loadIconSet("opie-write/undo"),
174 QString::null, 0, this, "editUndo" );
175 connect( a, SIGNAL( activated() ), this, SLOT( editUndo() ) );
176 connect( editor, SIGNAL(undoAvailable(bool)), a, SLOT(setEnabled(bool)) );
177 a->addTo( tbEdit );
178 a->addTo( edit );
179 a = new QAction( tr( "Redo" ), Resource::loadIconSet("opie-write/redo"),
180 QString::null, 0, this, "editRedo" );
181 connect( a, SIGNAL( activated() ), this, SLOT( editRedo() ) );
182 connect( editor, SIGNAL(redoAvailable(bool)), a, SLOT(setEnabled(bool)) );
183 a->addTo( tbEdit );
184 a->addTo( edit );
185
186 edit->insertSeparator();
187
188 a = new QAction( tr( "Copy" ), Resource::loadIconSet("copy"),
189 QString::null, 0, this, "editCopy" );
190 connect( a, SIGNAL( activated() ), this, SLOT( editCopy() ) );
191 connect( editor, SIGNAL(copyAvailable(bool)), a, SLOT(setEnabled(bool)) );
192 a->addTo( tbEdit );
193 a->addTo( edit );
194 a = new QAction( tr( "Cut" ), Resource::loadIconSet("cut"),
195 QString::null, 0, this, "editCut" );
196 connect( a, SIGNAL( activated() ), this, SLOT( editCut() ) );
197 connect( editor, SIGNAL(copyAvailable(bool)), a, SLOT(setEnabled(bool)) );
198 a->addTo( tbEdit );
199 a->addTo( edit );
200 a = new QAction( tr( "Paste" ), Resource::loadPixmap("paste"),
201 QString::null, 0, this, "editPaste" );
202 connect( a, SIGNAL( activated() ), this, SLOT( editPaste() ) );
203 a->addTo( tbEdit );
204 a->addTo( edit );
205
206 tbFont = new QToolBar( this );
207 tbFont->setLabel( "Font Actions" );
208 tbFont->setHorizontalStretchable(TRUE);
209
210 comboFont = new QComboBox( FALSE, tbFont );
211 QFontDatabase db;
212 comboFont->insertStringList( db.families() );
213 connect( comboFont, SIGNAL( activated( const QString & ) ),
214 this, SLOT( textFamily( const QString & ) ) );
215 comboFont->setCurrentItem( comboFont->listBox()->index( comboFont->listBox()->findItem( QApplication::font().family() ) ) );
216
217 comboSize = new QComboBox( TRUE, tbFont );
218 QValueList<int> sizes = db.standardSizes();
219 QValueList<int>::Iterator it = sizes.begin();
220 for ( ; it != sizes.end(); ++it )
221 comboSize->insertItem( QString::number( *it ) );
222 connect( comboSize, SIGNAL( activated( const QString & ) ),
223 this, SLOT( textSize( const QString & ) ) );
224 comboSize->lineEdit()->setText( QString::number( QApplication::font().pointSize() ) );
225 comboSize->setFixedWidth( 38 );
226
227 tbStyle = new QToolBar( this );
228 tbStyle->setLabel( "Style Actions" );
229
230 actionTextBold = new QAction( tr( "Bold" ),
231 Resource::loadPixmap("bold"),
232 QString::null, CTRL + Key_B,
233 this, "textBold" );
234 connect( actionTextBold, SIGNAL( activated() ), this, SLOT( textBold() ) );
235 actionTextBold->addTo( tbStyle );
236 actionTextBold->setToggleAction( TRUE );
237 actionTextItalic = new QAction( tr( "Italic" ),
238 Resource::loadPixmap("italic"),
239 tr( "&Italic" ), CTRL + Key_I,
240 this, "textItalic" );
241 connect( actionTextItalic, SIGNAL( activated() ), this,
242 SLOT( textItalic() ) );
243 actionTextItalic->addTo( tbStyle );
244 actionTextItalic->setToggleAction( TRUE );
245 actionTextUnderline = new QAction( tr( "Underline" ),
246 Resource::loadPixmap("underline"),
247 tr( "&Underline" ), CTRL + Key_U,
248 this, "textUnderline" );
249 connect( actionTextUnderline, SIGNAL( activated() ),
250 this, SLOT( textUnderline() ) );
251 actionTextUnderline->addTo( tbStyle );
252 actionTextUnderline->setToggleAction( TRUE );
253
254 alignMenu = new ButtonMenu( tbStyle );
255 alignMenu->insertItem( Resource::loadPixmap("left"), tr("Left"), AlignLeft );
256 alignMenu->insertItem( Resource::loadPixmap("center"), tr("Center"), AlignCenter );
257 alignMenu->insertItem( Resource::loadPixmap("right"), tr("Right"), AlignRight );
258 alignMenu->insertItem( Resource::loadPixmap("opie-write/justify"), tr("Full"), Qt3::AlignJustify );
259 connect( alignMenu, SIGNAL(activated(int)), this, SLOT(textAlign(int)) );
260}
261
262Qt3::QTextEdit *MainWindow::currentEditor() const
263{
264 return editor;
265}
266
267void MainWindow::doConnections( Qt3::QTextEdit *e )
268{
269 connect( e, SIGNAL( currentFontChanged( const QFont & ) ),
270 this, SLOT( fontChanged( const QFont & ) ) );
271 connect( e, SIGNAL( currentColorChanged( const QColor & ) ),
272 this, SLOT( colorChanged( const QColor & ) ) );
273 connect( e, SIGNAL( currentAlignmentChanged( int ) ),
274 this, SLOT( alignmentChanged( int ) ) );
275}
276
277void MainWindow::updateFontSizeCombo( const QFont &f )
278{
279 comboSize->clear();
280 QFontDatabase fdb;
281 QValueList<int> sizes = fdb.pointSizes( f.family() );
282 QValueList<int>::Iterator it = sizes.begin();
283 for ( ; it != sizes.end(); ++it )
284 comboSize->insertItem( QString::number( *it ) );
285}
286
287void MainWindow::editUndo()
288{
289 if ( !currentEditor() )
290 return;
291 currentEditor()->undo();
292}
293
294void MainWindow::editRedo()
295{
296 if ( !currentEditor() )
297 return;
298 currentEditor()->redo();
299}
300
301void MainWindow::editCut()
302{
303 if ( !currentEditor() )
304 return;
305 currentEditor()->cut();
306}
307
308void MainWindow::editCopy()
309{
310 if ( !currentEditor() )
311 return;
312 currentEditor()->copy();
313}
314
315void MainWindow::editPaste()
316{
317 if ( !currentEditor() )
318 return;
319 currentEditor()->paste();
320}
321
322void MainWindow::textBold()
323{
324 if ( !currentEditor() )
325 return;
326 currentEditor()->setBold( actionTextBold->isOn() );
327}
328
329void MainWindow::textUnderline()
330{
331 if ( !currentEditor() )
332 return;
333 currentEditor()->setUnderline( actionTextUnderline->isOn() );
334}
335
336void MainWindow::textItalic()
337{
338 if ( !currentEditor() )
339 return;
340 currentEditor()->setItalic( actionTextItalic->isOn() );
341}
342
343void MainWindow::textFamily( const QString &f )
344{
345 if ( !currentEditor() )
346 return;
347 currentEditor()->setFamily( f );
348 currentEditor()->viewport()->setFocus();
349}
350
351void MainWindow::textSize( const QString &p )
352{
353 if ( !currentEditor() )
354 return;
355 currentEditor()->setPointSize( p.toInt() );
356 currentEditor()->viewport()->setFocus();
357}
358
359void MainWindow::textStyle( int i )
360{
361 if ( !currentEditor() )
362 return;
363 if ( i == 0 )
364 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayBlock,
365 Qt3::QStyleSheetItem::ListDisc );
366 else if ( i == 1 )
367 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayListItem,
368 Qt3::QStyleSheetItem::ListDisc );
369 else if ( i == 2 )
370 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayListItem,
371 Qt3::QStyleSheetItem::ListCircle );
372 else if ( i == 3 )
373 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayListItem,
374 Qt3::QStyleSheetItem::ListSquare );
375 else if ( i == 4 )
376 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayListItem,
377 Qt3::QStyleSheetItem::ListDecimal );
378 else if ( i == 5 )
379 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayListItem,
380 Qt3::QStyleSheetItem::ListLowerAlpha );
381 else if ( i == 6 )
382 currentEditor()->setParagType( Qt3::QStyleSheetItem::DisplayListItem,
383 Qt3::QStyleSheetItem::ListUpperAlpha );
384 currentEditor()->viewport()->setFocus();
385}
386
387void MainWindow::textAlign( int a )
388{
389 if ( !currentEditor() )
390 return;
391 editor->setAlignment( a );
392}
393
394void MainWindow::fontChanged( const QFont &f )
395{
396 comboFont->setCurrentItem( comboFont->listBox()->index( comboFont->listBox()->findItem( f.family() ) ) );
397 updateFontSizeCombo( f );
398 comboSize->lineEdit()->setText( QString::number( f.pointSize() ) );
399 actionTextBold->setOn( f.bold() );
400 actionTextItalic->setOn( f.italic() );
401 actionTextUnderline->setOn( f.underline() );
402}
403
404void MainWindow::colorChanged( const QColor & )
405{
406}
407
408void MainWindow::alignmentChanged( int a )
409{
410 if ( ( a == Qt3::AlignAuto ) || ( a & AlignLeft )) {
411 alignMenu->setCurrentItem(AlignLeft);
412 } else if ( ( a & AlignCenter ) ) {
413 alignMenu->setCurrentItem(AlignCenter);
414 } else if ( ( a & AlignRight ) ) {
415 alignMenu->setCurrentItem(AlignRight);
416 } else if ( ( a & Qt3::AlignJustify ) ) {
417 alignMenu->setCurrentItem(Qt3::AlignJustify);
418 }
419}
420
421void MainWindow::editorChanged( QWidget * )
422{
423 if ( !currentEditor() )
424 return;
425 fontChanged( currentEditor()->font() );
426 colorChanged( currentEditor()->color() );
427 alignmentChanged( currentEditor()->alignment() );
428}
429
430void MainWindow::fileOpen()
431{
432 save();
433 editorStack->raiseWidget( fileSelector );
434 fileSelector->reread();
435 hideEditTools();
436 fileSelector->setNewVisible( TRUE );
437 clear();
438 updateCaption();
439}
440
441void MainWindow::fileRevert()
442{
443 qDebug( "QMainWindow::fileRevert needs to be done" );
444}
445
446void MainWindow::fileNew()
447{
448 editor->setTextFormat( Qt::RichText );
449 save();
450 newFile(DocLnk());
451}
452
453void MainWindow::insertTable()
454{
455 qDebug( "MainWindow::insertTable() needs to be done" );
456}
457
458void MainWindow::newFile( const DocLnk &dl )
459{
460 DocLnk nf = dl;
461 nf.setType( "text/html" );
462 clear();
463 editorStack->raiseWidget( editor );
464 editor->viewport()->setFocus();
465 doc = new DocLnk( nf );
466 updateCaption();
467}
468
469void MainWindow::openFile( const DocLnk &dl )
470{
471 FileManager fm;
472 QString txt;
473 if ( !fm.loadFile( dl, txt ) )
474 qDebug( "couldn't open file" );
475 clear();
476 editorStack->raiseWidget( editor );
477 editor->viewport()->setFocus();
478 doc = new DocLnk( dl );
479 editor->setText( txt );
480 editor->setModified( FALSE );
481 updateCaption();
482}
483
484void MainWindow::showEditTools( void )
485{
486 tbMenu->show();
487 tbEdit->show();
488 tbFont->show();
489 tbStyle->show();
490}
491
492void MainWindow::hideEditTools( void )
493{
494 // let's reset the buttons...
495 actionTextBold->setOn( FALSE );
496 actionTextItalic->setOn( FALSE );
497 actionTextUnderline->setOn( FALSE );
498 //comboFont->setCurrentText( QApplication::font().family() );
499 comboSize->lineEdit()->setText( QString::number(QApplication::font().pointSize() ) );
500 tbMenu->hide();
501 tbEdit->hide();
502 tbFont->hide();
503 tbStyle->hide();
504}
505
506
507void MainWindow::save()
508{
509 if ( !doc )
510 return;
511 if ( !editor->isModified() )
512 return;
513
514 QString rt = editor->text();
515
516 // quick hack to get around formatting...
517 editor->setTextFormat( Qt::PlainText );
518 QString pt = editor->text();
519 editor->setTextFormat( Qt::RichText );
520
521 if ( doc->name().isEmpty() ) {
522 unsigned ispace = pt.find( ' ' );
523 unsigned ienter = pt.find( '\n' );
524 int i = (ispace < ienter) ? ispace : ienter;
525 QString docname;
526 if ( i == -1 ) {
527 if ( pt.isEmpty() )
528 docname = "Empty Text";
529 else
530 docname = pt;
531 } else {
532 docname = pt.left( i );
533 }
534 doc->setName(docname);
535 }
536 FileManager fm;
537 fm.saveFile( *doc, rt );
538}
539
540void MainWindow::clear()
541{
542 delete doc;
543 doc = 0;
544 editor->clear();
545}
546
547void MainWindow::updateCaption()
548{
549 if ( !doc )
550 setCaption( tr("Rich Text Editor") );
551 else {
552 QString s = doc->name();
553 if ( s.isEmpty() )
554 s = tr( "Unnamed" );
555 setCaption( s + " - " + tr("Rich Text Editor") );
556 }
557}
558
559void MainWindow::closeEvent( QCloseEvent *e )
560{
561 if ( editorStack->visibleWidget() == editor ) {
562 // call fileOpen instead, don't close it
563 fileOpen();
564 e->ignore();
565 } else {
566 e->accept();
567 }
568}
569
570#include "mainwindow.moc"
diff --git a/noncore/apps/opie-write/mainwindow.h b/noncore/apps/opie-write/mainwindow.h
new file mode 100644
index 0000000..565ad05
--- a/dev/null
+++ b/noncore/apps/opie-write/mainwindow.h
@@ -0,0 +1,113 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** Licensees holding valid Qtopia Developer license may use this
7** file in accordance with the Qtopia Developer License Agreement
8** provided with the Software.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12** PURPOSE.
13**
14** email sales@trolltech.com for information about Qtopia License
15** Agreements.
16**
17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you.
19**
20**********************************************************************/
21
22#ifndef MAINWINDOW_H
23#define MAINWINDOW_H
24
25#include <qmainwindow.h>
26#include <qwidgetstack.h>
27#include <qmap.h>
28#include <qpe/filemanager.h>
29
30class QAction;
31class QComboBox;
32class FileSelectorView;
33class FileSelector;
34class QToolBar;
35class ButtonMenu;
36
37namespace Qt3 {
38
39class QTextEdit;
40
41}
42
43class MainWindow : public QMainWindow
44{
45 Q_OBJECT
46
47public:
48 MainWindow( QWidget *parent = 0, const char *name = 0 );
49 ~MainWindow();
50
51protected:
52 void closeEvent( QCloseEvent *e );
53
54private slots:
55 // new file functions
56 void fileOpen();
57 void fileRevert();
58 void fileNew();
59
60 void editUndo();
61 void editRedo();
62 void editCut();
63 void editCopy();
64 void editPaste();
65
66 void textBold();
67 void textUnderline();
68 void textItalic();
69 void textFamily( const QString &f );
70 void textSize( const QString &p );
71 void textStyle( int s );
72 void textAlign( int );
73
74 void fontChanged( const QFont &f );
75 void colorChanged( const QColor &c );
76 void alignmentChanged( int a );
77 void editorChanged( QWidget * );
78
79 // these are from textedit, we may need them
80 void insertTable();
81 void newFile( const DocLnk & );
82 void openFile( const DocLnk & );
83 void showEditTools();
84 void hideEditTools();
85
86private:
87 void updateFontSizeCombo( const QFont &f );
88 void setupActions();
89 Qt3::QTextEdit *currentEditor() const;
90 void doConnections( Qt3::QTextEdit *e );
91 void updateCaption();
92 void save();
93 void clear();
94
95 // added these from the textedit
96 QWidgetStack *editorStack;
97 FileSelector *fileSelector;
98 QToolBar *tbMenu;
99 QToolBar *tbEdit;
100 QToolBar *tbFont;
101 QToolBar *tbStyle;
102 QAction *actionTextBold,
103 *actionTextUnderline,
104 *actionTextItalic;
105 QComboBox *comboFont,
106 *comboSize;
107 ButtonMenu *alignMenu;
108 DocLnk *doc;
109 Qt3::QTextEdit* editor;
110};
111
112
113#endif
diff --git a/noncore/apps/opie-write/opie-write.pro b/noncore/apps/opie-write/opie-write.pro
new file mode 100644
index 0000000..e2ce3a9
--- a/dev/null
+++ b/noncore/apps/opie-write/opie-write.pro
@@ -0,0 +1,25 @@
1 TEMPLATE= app
2 CONFIG += qt warn_on release
3
4 DESTDIR = $(OPIEDIR)/bin
5
6 HEADERS =qcleanuphandler.h \
7 qcomplextext_p.h \
8 qrichtext_p.h \
9 qstylesheet.h \
10 qtextedit.h \
11 mainwindow.h
12
13 SOURCES =qcomplextext.cpp \
14 qstylesheet.cpp \
15 qrichtext_p.cpp \
16 qrichtext.cpp \
17 qtextedit.cpp \
18 main.cpp \
19 mainwindow.cpp
20
21 INCLUDEPATH+= $(OPIEDIR)/include
22 DEPENDPATH+= $(OPIEDIR)/include
23LIBS += -lqpe
24
25 TARGET = opie-write
diff --git a/noncore/apps/opie-write/qcleanuphandler.h b/noncore/apps/opie-write/qcleanuphandler.h
new file mode 100644
index 0000000..5c5bf16
--- a/dev/null
+++ b/noncore/apps/opie-write/qcleanuphandler.h
@@ -0,0 +1,139 @@
1/****************************************************************************
2** $Id$
3**
4** ...
5**
6** Copyright (C) 2001-2002 Trolltech AS. All rights reserved.
7**
8** This file is part of the tools module of the Qt GUI Toolkit.
9**
10** This file may be distributed under the terms of the Q Public License
11** as defined by Trolltech AS of Norway and appearing in the file
12** LICENSE.QPL included in the packaging of this file.
13**
14** This file may be distributed and/or modified under the terms of the
15** GNU General Public License version 2 as published by the Free Software
16** Foundation and appearing in the file LICENSE.GPL included in the
17** packaging of this file.
18**
19** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
20** licenses may use this file in accordance with the Qt Commercial License
21** Agreement provided with the Software.
22**
23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25**
26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27** information about Qt Commercial License Agreements.
28** See http://www.trolltech.com/qpl/ for QPL licensing information.
29** See http://www.trolltech.com/gpl/ for GPL licensing information.
30**
31** Contact info@trolltech.com if any conditions of this licensing are
32** not clear to you.
33**
34**********************************************************************/
35
36#ifndef QCLEANUPHANDLER_H
37#define QCLEANUPHANDLER_H
38
39#ifndef QT_H
40#include <qlist.h>
41#endif // QT_H
42
43template<class Type>
44#ifdef Q_NO_TEMPLATE_EXPORT
45class QCleanupHandler
46#else
47class Q_EXPORT QCleanupHandler
48#endif
49{
50public:
51 QCleanupHandler() : cleanupObjects( 0 ) {}
52 ~QCleanupHandler() { clear(); }
53
54 Type* add( Type **object ) {
55 if ( !cleanupObjects )
56 cleanupObjects = new QPtrList<Type*>;
57 cleanupObjects->insert( 0, object );
58 return *object;
59 }
60
61 void remove( Type **object ) {
62 if ( !cleanupObjects )
63 return;
64 if ( cleanupObjects->findRef( object ) >= 0 )
65 (void) cleanupObjects->take();
66 }
67
68 bool isEmpty() const {
69 return cleanupObjects ? cleanupObjects->isEmpty() : TRUE;
70 }
71
72 void clear() {
73 if ( !cleanupObjects )
74 return;
75 QPtrListIterator<Type*> it( *cleanupObjects );
76 Type **object;
77 while ( ( object = it.current() ) ) {
78 delete *object;
79 *object = 0;
80 cleanupObjects->remove( object );
81 }
82 delete cleanupObjects;
83 cleanupObjects = 0;
84 }
85
86private:
87 QPtrList<Type*> *cleanupObjects;
88};
89
90template<class Type>
91#ifdef Q_NO_TEMPLATE_EXPORT
92class QSingleCleanupHandler
93#else
94class Q_EXPORT QSingleCleanupHandler
95#endif
96{
97public:
98 QSingleCleanupHandler() : object( 0 ) {}
99 ~QSingleCleanupHandler() {
100 if ( object ) {
101 delete *object;
102 *object = 0;
103 }
104 }
105 Type* set( Type **o ) {
106 object = o;
107 return *object;
108 }
109 void reset() { object = 0; }
110private:
111 Type **object;
112};
113
114template<class Type>
115#ifdef Q_NO_TEMPLATE_EXPORT
116class QSharedCleanupHandler
117#else
118class Q_EXPORT QSharedCleanupHandler
119#endif
120{
121public:
122 QSharedCleanupHandler() : object( 0 ) {}
123 ~QSharedCleanupHandler() {
124 if ( object ) {
125 if ( (*object)->deref() )
126 delete *object;
127 *object = 0;
128 }
129 }
130 Type* set( Type **o ) {
131 object = o;
132 return *object;
133 }
134 void reset() { object = 0; }
135private:
136 Type **object;
137};
138
139#endif //QCLEANUPHANDLER_H
diff --git a/noncore/apps/opie-write/qcomplextext.cpp b/noncore/apps/opie-write/qcomplextext.cpp
new file mode 100644
index 0000000..0fa6c2e
--- a/dev/null
+++ b/noncore/apps/opie-write/qcomplextext.cpp
@@ -0,0 +1,152 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of some internal classes
5**
6** Created :
7**
8** Copyright (C) 2001 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qcomplextext_p.h"
39
40#include "qrichtext_p.h"
41#include "qfontmetrics.h"
42#include "qrect.h"
43
44#include <stdlib.h>
45
46using namespace Qt3;
47
48// -----------------------------------------------------
49
50/* a small helper class used internally to resolve Bidi embedding levels.
51 Each line of text caches the embedding level at the start of the line for faster
52 relayouting
53*/
54QBidiContext::QBidiContext( uchar l, QChar::Direction e, QBidiContext *p, bool o )
55 : level(l) , override(o), dir(e)
56{
57 if ( p )
58 p->ref();
59 parent = p;
60 count = 0;
61}
62
63QBidiContext::~QBidiContext()
64{
65 if( parent && parent->deref() )
66 delete parent;
67}
68
69static QChar *shapeBuffer = 0;
70static int shapeBufSize = 0;
71
72/*
73 Arabic shaping obeys a number of rules according to the joining classes (see Unicode book, section on
74 arabic).
75
76 Each unicode char has a joining class (right, dual (left&right), center (joincausing) or transparent).
77 transparent joining is not encoded in QChar::joining(), but applies to all combining marks and format marks.
78
79 Right join-causing: dual + center
80 Left join-causing: dual + right + center
81
82 Rules are as follows (for a string already in visual order, as we have it here):
83
84 R1 Transparent characters do not affect joining behaviour.
85 R2 A right joining character, that has a right join-causing char on the right will get form XRight
86 (R3 A left joining character, that has a left join-causing char on the left will get form XLeft)
87 Note: the above rule is meaningless, as there are no pure left joining characters defined in Unicode
88 R4 A dual joining character, that has a left join-causing char on the left and a right join-causing char on
89 the right will get form XMedial
90 R5 A dual joining character, that has a right join causing char on the right, and no left join causing char on the left
91 will get form XRight
92 R6 A dual joining character, that has a left join causing char on the left, and no right join causing char on the right
93 will get form XLeft
94 R7 Otherwise the character will get form XIsolated
95
96 Additionally we have to do the minimal ligature support for lam-alef ligatures:
97
98 L1 Transparent characters do not affect ligature behaviour.
99 L2 Any sequence of Alef(XRight) + Lam(XMedial) will form the ligature Alef.Lam(XLeft)
100 L3 Any sequence of Alef(XRight) + Lam(XLeft) will form the ligature Alef.Lam(XIsolated)
101
102 The two functions defined in this class do shaping in visual and logical order. For logical order just replace right with
103 previous and left with next in the above rules ;-)
104*/
105
106/*
107 Two small helper functions for arabic shaping. They get the next shape causing character on either
108 side of the char in question. Implements rule R1.
109
110 leftChar() returns true if the char to the left is a left join-causing char
111 rightChar() returns true if the char to the right is a right join-causing char
112*/
113static inline const QChar *prevChar( const QString &str, int pos )
114{
115 //qDebug("leftChar: pos=%d", pos);
116 pos--;
117 const QChar *ch = str.unicode() + pos;
118 while( pos > -1 ) {
119 if( !ch->isMark() )
120 return ch;
121 pos--;
122 ch--;
123 }
124 return &QChar::replacement;
125}
126
127static inline const QChar *nextChar( const QString &str, int pos)
128{
129 pos++;
130 int len = str.length();
131 const QChar *ch = str.unicode() + pos;
132 while( pos < len ) {
133 //qDebug("rightChar: %d isLetter=%d, joining=%d", pos, ch.isLetter(), ch.joining());
134 if( !ch->isMark() )
135 return ch;
136 // assume it's a transparent char, this might not be 100% correct
137 pos++;
138 ch++;
139 }
140 return &QChar::replacement;
141}
142
143static inline bool prevVisualCharJoins( const QString &str, int pos)
144{
145 return ( prevChar( str, pos )->joining() != QChar::OtherJoining );
146}
147
148static inline bool nextVisualCharJoins( const QString &str, int pos)
149{
150 QChar::Joining join = nextChar( str, pos )->joining();
151 return ( join == QChar::Dual || join == QChar::Center );
152}
diff --git a/noncore/apps/opie-write/qcomplextext_p.h b/noncore/apps/opie-write/qcomplextext_p.h
new file mode 100644
index 0000000..b2d8293
--- a/dev/null
+++ b/noncore/apps/opie-write/qcomplextext_p.h
@@ -0,0 +1,133 @@
1/****************************************************************************
2** $Id$
3**
4** Internal header file.
5**
6** Created :
7**
8** Copyright (C) 2001 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#ifndef QCOMPLEXTEXT_H
39#define QCOMPLEXTEXT_H
40
41//
42// W A R N I N G
43// -------------
44//
45// This file is not part of the Qt API. It exists for the convenience
46// of Qt Remote Control. This header file may change from version to
47// version without notice, or even be removed.
48//
49// We mean it.
50//
51//
52
53#ifndef QT_H
54#include "qt3namespace.h"
55#include <qstring.h>
56#include <qpointarray.h>
57#include <qfont.h>
58#include <qpainter.h>
59#include <qlist.h>
60#include <qshared.h>
61#endif // QT_H
62
63class QFontPrivate;
64
65namespace Qt3 {
66
67// bidi helper classes. Internal to Qt
68struct Q_EXPORT QBidiStatus {
69 QBidiStatus() {
70 eor = QChar::DirON;
71 lastStrong = QChar::DirON;
72 last = QChar:: DirON;
73 }
74 QChar::Direction eor;
75 QChar::Direction lastStrong;
76 QChar::Direction last;
77};
78
79struct Q_EXPORT QBidiContext : public QShared {
80 // ### ref and deref parent?
81 QBidiContext( uchar level, QChar::Direction embedding, QBidiContext *parent = 0, bool override = FALSE );
82 ~QBidiContext();
83
84 unsigned char level;
85 bool override : 1;
86 QChar::Direction dir : 5;
87
88 QBidiContext *parent;
89};
90
91struct Q_EXPORT QBidiControl {
92 QBidiControl() { context = 0; }
93 QBidiControl( QBidiContext *c, QBidiStatus s)
94 { context = c; if( context ) context->ref(); status = s; }
95 ~QBidiControl() { if ( context && context->deref() ) delete context; }
96 void setContext( QBidiContext *c ) { if ( context == c ) return; if ( context && context->deref() ) delete context; context = c; context->ref(); }
97 QBidiContext *context;
98 QBidiStatus status;
99};
100
101struct Q_EXPORT QTextRun {
102 QTextRun(int _start, int _stop, QBidiContext *context, QChar::Direction dir);
103
104 int start;
105 int stop;
106 // explicit + implicit levels here
107 uchar level;
108};
109
110class Q_EXPORT QComplexText {
111public:
112 enum Shape {
113 XIsolated,
114 XFinal,
115 XInitial,
116 XMedial
117 };
118 static Shape glyphVariant( const QString &str, int pos);
119 static Shape glyphVariantLogical( const QString &str, int pos);
120
121 static QChar shapedCharacter(const QString &str, int pos, const QFontMetrics *fm = 0);
122
123 // positions non spacing marks relative to the base character at position pos.
124 static QPointArray positionMarks( QFontPrivate *f, const QString &str, int pos, QRect *boundingRect = 0 );
125
126 static QPtrList<QTextRun> *bidiReorderLine( QBidiControl *control, const QString &str, int start, int len,
127 QChar::Direction basicDir = QChar::DirON );
128 static QString bidiReorderString( const QString &str, QChar::Direction basicDir = QChar::DirON );
129};
130
131} // namespace Qt3
132
133#endif
diff --git a/noncore/apps/opie-write/qrichtext.cpp b/noncore/apps/opie-write/qrichtext.cpp
new file mode 100644
index 0000000..7901000
--- a/dev/null
+++ b/noncore/apps/opie-write/qrichtext.cpp
@@ -0,0 +1,8085 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of the internal Qt classes dealing with rich text
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qrichtext_p.h"
39
40#include "qstringlist.h"
41#include "qfont.h"
42#include "qtextstream.h"
43#include "qfile.h"
44#include "qregexp.h"
45#include "qapplication.h"
46#include "qclipboard.h"
47#include "qmap.h"
48#include "qfileinfo.h"
49#include "qstylesheet.h"
50#include "qmime.h"
51#include "qregexp.h"
52#include "qimage.h"
53#include "qdragobject.h"
54#include "qpaintdevicemetrics.h"
55#include "qpainter.h"
56#include "qdrawutil.h"
57#include "qcursor.h"
58#include "qstack.h"
59#include "qstyle.h"
60#include "qcomplextext_p.h"
61#include "qcleanuphandler.h"
62
63#include <stdlib.h>
64
65using namespace Qt3;
66
67//#define PARSER_DEBUG
68//#define DEBUG_COLLECTION// ---> also in qrichtext_p.h
69//#define DEBUG_TABLE_RENDERING
70
71static QTextFormatCollection *qFormatCollection = 0;
72
73const int QStyleSheetItem_WhiteSpaceNoCompression = 3; // ### belongs in QStyleSheetItem, fix 3.1
74const int QStyleSheetItem_WhiteSpaceNormalWithNewlines = 4; // ### belongs in QStyleSheetItem, fix 3.1
75
76const int border_tolerance = 2;
77
78#if defined(PARSER_DEBUG)
79static QString debug_indent;
80#endif
81
82#ifdef Q_WS_WIN
83#include "qt_windows.h"
84#endif
85
86static inline bool is_printer( QPainter *p )
87{
88 if ( !p || !p->device() )
89 return FALSE;
90 return p->device()->devType() == QInternal::Printer;
91}
92
93static inline int scale( int value, QPainter *painter )
94{
95 if ( is_printer( painter ) ) {
96 QPaintDeviceMetrics metrics( painter->device() );
97#if defined(Q_WS_X11)
98 value = value * metrics.logicalDpiY() / QPaintDevice::x11AppDpiY();
99#elif defined (Q_WS_WIN)
100 HDC hdc = GetDC( 0 );
101 int gdc = GetDeviceCaps( hdc, LOGPIXELSY );
102 if ( gdc )
103 value = value * metrics.logicalDpiY() / gdc;
104 ReleaseDC( 0, hdc );
105#elif defined (Q_WS_MAC)
106 value = value * metrics.logicalDpiY() / 75; // ##### FIXME
107#elif defined (Q_WS_QWS)
108 value = value * metrics.logicalDpiY() / 75;
109#endif
110 }
111 return value;
112}
113
114// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
115
116void QTextCommandHistory::addCommand( QTextCommand *cmd )
117{
118 if ( current < (int)history.count() - 1 ) {
119 QPtrList<QTextCommand> commands;
120 commands.setAutoDelete( FALSE );
121
122 for( int i = 0; i <= current; ++i ) {
123 commands.insert( i, history.at( 0 ) );
124 history.take( 0 );
125 }
126
127 commands.append( cmd );
128 history.clear();
129 history = commands;
130 history.setAutoDelete( TRUE );
131 } else {
132 history.append( cmd );
133 }
134
135 if ( (int)history.count() > steps )
136 history.removeFirst();
137 else
138 ++current;
139}
140
141QTextCursor *QTextCommandHistory::undo( QTextCursor *c )
142{
143 if ( current > -1 ) {
144 QTextCursor *c2 = history.at( current )->unexecute( c );
145 --current;
146 return c2;
147 }
148 return 0;
149}
150
151QTextCursor *QTextCommandHistory::redo( QTextCursor *c )
152{
153 if ( current > -1 ) {
154 if ( current < (int)history.count() - 1 ) {
155 ++current;
156 return history.at( current )->execute( c );
157 }
158 } else {
159 if ( history.count() > 0 ) {
160 ++current;
161 return history.at( current )->execute( c );
162 }
163 }
164 return 0;
165}
166
167bool QTextCommandHistory::isUndoAvailable()
168{
169 return current > -1;
170}
171
172bool QTextCommandHistory::isRedoAvailable()
173{
174 return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
175}
176
177// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
178
179QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
180 const QValueList< QPtrVector<QStyleSheetItem> > &os,
181 const QValueList<QStyleSheetItem::ListStyle> &ols,
182 const QMemArray<int> &oas)
183 : QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), oldStyles( os ), oldListStyles( ols ), oldAligns( oas )
184{
185 for ( int j = 0; j < (int)text.size(); ++j ) {
186 if ( text[ j ].format() )
187 text[ j ].format()->addRef();
188 }
189}
190
191QTextDeleteCommand::QTextDeleteCommand( QTextParag *p, int idx, const QMemArray<QTextStringChar> &str )
192 : QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str )
193{
194 for ( int i = 0; i < (int)text.size(); ++i ) {
195 if ( text[ i ].format() )
196 text[ i ].format()->addRef();
197 }
198}
199
200QTextDeleteCommand::~QTextDeleteCommand()
201{
202 for ( int i = 0; i < (int)text.size(); ++i ) {
203 if ( text[ i ].format() )
204 text[ i ].format()->removeRef();
205 }
206 text.resize( 0 );
207}
208
209QTextCursor *QTextDeleteCommand::execute( QTextCursor *c )
210{
211 QTextParag *s = doc ? doc->paragAt( id ) : parag;
212 if ( !s ) {
213 qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParag()->paragId() );
214 return 0;
215 }
216
217 cursor.setParag( s );
218 cursor.setIndex( index );
219 int len = text.size();
220 if ( c )
221 *c = cursor;
222 if ( doc ) {
223 doc->setSelectionStart( QTextDocument::Temp, &cursor );
224 for ( int i = 0; i < len; ++i )
225 cursor.gotoNextLetter();
226 doc->setSelectionEnd( QTextDocument::Temp, &cursor );
227 doc->removeSelectedText( QTextDocument::Temp, &cursor );
228 if ( c )
229 *c = cursor;
230 } else {
231 s->remove( index, len );
232 }
233
234 return c;
235}
236
237QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c )
238{
239 QTextParag *s = doc ? doc->paragAt( id ) : parag;
240 if ( !s ) {
241 qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParag()->paragId() );
242 return 0;
243 }
244
245 cursor.setParag( s );
246 cursor.setIndex( index );
247 QString str = QTextString::toString( text );
248 cursor.insert( str, TRUE, &text );
249 cursor.setParag( s );
250 cursor.setIndex( index );
251 if ( c ) {
252 c->setParag( s );
253 c->setIndex( index );
254 for ( int i = 0; i < (int)text.size(); ++i )
255 c->gotoNextLetter();
256 }
257
258 QValueList< QPtrVector<QStyleSheetItem> >::Iterator it = oldStyles.begin();
259 QValueList<QStyleSheetItem::ListStyle>::Iterator lit = oldListStyles.begin();
260 int i = 0;
261 QTextParag *p = s;
262 bool end = FALSE;
263 while ( p ) {
264 if ( it != oldStyles.end() )
265 p->setStyleSheetItems( *it );
266 else
267 end = TRUE;
268 if ( lit != oldListStyles.end() )
269 p->setListStyle( *lit );
270 else
271 end = TRUE;
272 if ( i < (int)oldAligns.size() )
273 p->setAlignment( oldAligns.at( i ) );
274 else
275 end = TRUE;
276 if ( end )
277 break;
278 p = p->next();
279 ++it;
280 ++lit;
281 ++i;
282 }
283
284 s = cursor.parag();
285 while ( s ) {
286 s->format();
287 s->setChanged( TRUE );
288 if ( s == c->parag() )
289 break;
290 s = s->next();
291 }
292
293 return &cursor;
294}
295
296QTextFormatCommand::QTextFormatCommand( QTextDocument *d, int sid, int sidx, int eid, int eidx,
297 const QMemArray<QTextStringChar> &old, QTextFormat *f, int fl )
298 : QTextCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), format( f ), oldFormats( old ), flags( fl )
299{
300 format = d->formatCollection()->format( f );
301 for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
302 if ( oldFormats[ j ].format() )
303 oldFormats[ j ].format()->addRef();
304 }
305}
306
307QTextFormatCommand::~QTextFormatCommand()
308{
309 format->removeRef();
310 for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
311 if ( oldFormats[ j ].format() )
312 oldFormats[ j ].format()->removeRef();
313 }
314}
315
316QTextCursor *QTextFormatCommand::execute( QTextCursor *c )
317{
318 QTextParag *sp = doc->paragAt( startId );
319 QTextParag *ep = doc->paragAt( endId );
320 if ( !sp || !ep )
321 return c;
322
323 QTextCursor start( doc );
324 start.setParag( sp );
325 start.setIndex( startIndex );
326 QTextCursor end( doc );
327 end.setParag( ep );
328 end.setIndex( endIndex );
329
330 doc->setSelectionStart( QTextDocument::Temp, &start );
331 doc->setSelectionEnd( QTextDocument::Temp, &end );
332 doc->setFormat( QTextDocument::Temp, format, flags );
333 doc->removeSelection( QTextDocument::Temp );
334 if ( endIndex == ep->length() )
335 end.gotoLeft();
336 *c = end;
337 return c;
338}
339
340QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c )
341{
342 QTextParag *sp = doc->paragAt( startId );
343 QTextParag *ep = doc->paragAt( endId );
344 if ( !sp || !ep )
345 return 0;
346
347 int idx = startIndex;
348 int fIndex = 0;
349 for ( ;; ) {
350 if ( oldFormats.at( fIndex ).c == '\n' ) {
351 if ( idx > 0 ) {
352 if ( idx < sp->length() && fIndex > 0 )
353 sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
354 if ( sp == ep )
355 break;
356 sp = sp->next();
357 idx = 0;
358 }
359 fIndex++;
360 }
361 if ( oldFormats.at( fIndex ).format() )
362 sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
363 idx++;
364 fIndex++;
365 if ( fIndex >= (int)oldFormats.size() )
366 break;
367 if ( idx >= sp->length() ) {
368 if ( sp == ep )
369 break;
370 sp = sp->next();
371 idx = 0;
372 }
373 }
374
375 QTextCursor end( doc );
376 end.setParag( ep );
377 end.setIndex( endIndex );
378 if ( endIndex == ep->length() )
379 end.gotoLeft();
380 *c = end;
381 return c;
382}
383
384QTextAlignmentCommand::QTextAlignmentCommand( QTextDocument *d, int fParag, int lParag, int na, const QMemArray<int> &oa )
385 : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), newAlign( na ), oldAligns( oa )
386{
387}
388
389QTextCursor *QTextAlignmentCommand::execute( QTextCursor *c )
390{
391 QTextParag *p = doc->paragAt( firstParag );
392 if ( !p )
393 return c;
394 while ( p ) {
395 p->setAlignment( newAlign );
396 if ( p->paragId() == lastParag )
397 break;
398 p = p->next();
399 }
400 return c;
401}
402
403QTextCursor *QTextAlignmentCommand::unexecute( QTextCursor *c )
404{
405 QTextParag *p = doc->paragAt( firstParag );
406 if ( !p )
407 return c;
408 int i = 0;
409 while ( p ) {
410 if ( i < (int)oldAligns.size() )
411 p->setAlignment( oldAligns.at( i ) );
412 if ( p->paragId() == lastParag )
413 break;
414 p = p->next();
415 ++i;
416 }
417 return c;
418}
419
420QTextParagTypeCommand::QTextParagTypeCommand( QTextDocument *d, int fParag, int lParag, bool l,
421 QStyleSheetItem::ListStyle s, const QValueList< QPtrVector<QStyleSheetItem> > &os,
422 const QValueList<QStyleSheetItem::ListStyle> &ols )
423 : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), list( l ), listStyle( s ), oldStyles( os ), oldListStyles( ols )
424{
425}
426
427QTextCursor *QTextParagTypeCommand::execute( QTextCursor *c )
428{
429 QTextParag *p = doc->paragAt( firstParag );
430 if ( !p )
431 return c;
432 while ( p ) {
433 p->setList( list, (int)listStyle );
434 if ( p->paragId() == lastParag )
435 break;
436 p = p->next();
437 }
438 return c;
439}
440
441QTextCursor *QTextParagTypeCommand::unexecute( QTextCursor *c )
442{
443 QTextParag *p = doc->paragAt( firstParag );
444 if ( !p )
445 return c;
446 QValueList< QPtrVector<QStyleSheetItem> >::Iterator it = oldStyles.begin();
447 QValueList<QStyleSheetItem::ListStyle>::Iterator lit = oldListStyles.begin();
448 while ( p ) {
449 if ( it != oldStyles.end() )
450 p->setStyleSheetItems( *it );
451 if ( lit != oldListStyles.end() )
452 p->setListStyle( *lit );
453 if ( p->paragId() == lastParag )
454 break;
455 p = p->next();
456 ++it;
457 ++lit;
458 }
459 return c;
460}
461
462// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
463
464QTextCursor::QTextCursor( QTextDocument *d )
465 : doc( d ), ox( 0 ), oy( 0 )
466{
467 nested = FALSE;
468 idx = 0;
469 string = doc ? doc->firstParag() : 0;
470 tmpIndex = -1;
471 valid = TRUE;
472}
473
474QTextCursor::QTextCursor()
475{
476}
477
478QTextCursor::QTextCursor( const QTextCursor &c )
479{
480 doc = c.doc;
481 ox = c.ox;
482 oy = c.oy;
483 nested = c.nested;
484 idx = c.idx;
485 string = c.string;
486 tmpIndex = c.tmpIndex;
487 indices = c.indices;
488 parags = c.parags;
489 xOffsets = c.xOffsets;
490 yOffsets = c.yOffsets;
491 valid = c.valid;
492}
493
494QTextCursor &QTextCursor::operator=( const QTextCursor &c )
495{
496 doc = c.doc;
497 ox = c.ox;
498 oy = c.oy;
499 nested = c.nested;
500 idx = c.idx;
501 string = c.string;
502 tmpIndex = c.tmpIndex;
503 indices = c.indices;
504 parags = c.parags;
505 xOffsets = c.xOffsets;
506 yOffsets = c.yOffsets;
507 valid = c.valid;
508
509 return *this;
510}
511
512bool QTextCursor::operator==( const QTextCursor &c ) const
513{
514 return doc == c.doc && string == c.string && idx == c.idx;
515}
516
517int QTextCursor::totalOffsetX() const
518{
519 if ( !nested )
520 return 0;
521 QValueStack<int>::ConstIterator xit = xOffsets.begin();
522 int xoff = ox;
523 for ( ; xit != xOffsets.end(); ++xit )
524 xoff += *xit;
525 return xoff;
526}
527
528int QTextCursor::totalOffsetY() const
529{
530 if ( !nested )
531 return 0;
532 QValueStack<int>::ConstIterator yit = yOffsets.begin();
533 int yoff = oy;
534 for ( ; yit != yOffsets.end(); ++yit )
535 yoff += *yit;
536 return yoff;
537}
538
539void QTextCursor::gotoIntoNested( const QPoint &globalPos )
540{
541 if ( !doc )
542 return;
543 push();
544 ox = 0;
545 int bl, y;
546 string->lineHeightOfChar( idx, &bl, &y );
547 oy = y + string->rect().y();
548 nested = TRUE;
549 QPoint p( globalPos.x() - offsetX(), globalPos.y() - offsetY() );
550 Q_ASSERT( string->at( idx )->isCustom() );
551 ox = string->at( idx )->x;
552 string->at( idx )->customItem()->enterAt( this, doc, string, idx, ox, oy, p );
553}
554
555void QTextCursor::invalidateNested()
556{
557 if ( nested ) {
558 QValueStack<QTextParag*>::Iterator it = parags.begin();
559 QValueStack<int>::Iterator it2 = indices.begin();
560 for ( ; it != parags.end(); ++it, ++it2 ) {
561 if ( *it == string )
562 continue;
563 (*it)->invalidate( 0 );
564 if ( (*it)->at( *it2 )->isCustom() )
565 (*it)->at( *it2 )->customItem()->invalidate();
566 }
567 }
568}
569
570void QTextCursor::insert( const QString &str, bool checkNewLine, QMemArray<QTextStringChar> *formatting )
571{
572 tmpIndex = -1;
573 bool justInsert = TRUE;
574 QString s( str );
575#if defined(Q_WS_WIN)
576 if ( checkNewLine )
577 s = s.replace( QRegExp( "\\r" ), "" );
578#endif
579 if ( checkNewLine )
580 justInsert = s.find( '\n' ) == -1;
581 if ( justInsert ) {
582 string->insert( idx, s );
583 if ( formatting ) {
584 for ( int i = 0; i < (int)s.length(); ++i ) {
585 if ( formatting->at( i ).format() ) {
586 formatting->at( i ).format()->addRef();
587 string->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE );
588 }
589 }
590 }
591 idx += s.length();
592 } else {
593 QStringList lst = QStringList::split( '\n', s, TRUE );
594 QStringList::Iterator it = lst.begin();
595 int y = string->rect().y() + string->rect().height();
596 int lastIndex = 0;
597 QTextFormat *lastFormat = 0;
598 for ( ; it != lst.end(); ) {
599 if ( it != lst.begin() ) {
600 splitAndInsertEmptyParag( FALSE, TRUE );
601 string->setEndState( -1 );
602 string->prev()->format( -1, FALSE );
603 if ( lastFormat && formatting && string->prev() ) {
604 lastFormat->addRef();
605 string->prev()->string()->setFormat( string->prev()->length() - 1, lastFormat, TRUE );
606 }
607 }
608 lastFormat = 0;
609 QString s = *it;
610 ++it;
611 if ( !s.isEmpty() )
612 string->insert( idx, s );
613 else
614 string->invalidate( 0 );
615 if ( formatting ) {
616 int len = s.length();
617 for ( int i = 0; i < len; ++i ) {
618 if ( formatting->at( i + lastIndex ).format() ) {
619 formatting->at( i + lastIndex ).format()->addRef();
620 string->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE );
621 }
622 }
623 if ( it != lst.end() )
624 lastFormat = formatting->at( len + lastIndex ).format();
625 ++len;
626 lastIndex += len;
627 }
628
629 idx += s.length();
630 }
631 string->format( -1, FALSE );
632 int dy = string->rect().y() + string->rect().height() - y;
633 QTextParag *p = string;
634 p->setParagId( p->prev()->paragId() + 1 );
635 p = p->next();
636 while ( p ) {
637 p->setParagId( p->prev()->paragId() + 1 );
638 p->move( dy );
639 p->invalidate( 0 );
640 p->setEndState( -1 );
641 p = p->next();
642 }
643 }
644
645 int h = string->rect().height();
646 string->format( -1, TRUE );
647 if ( h != string->rect().height() )
648 invalidateNested();
649 else if ( doc && doc->parent() )
650 doc->nextDoubleBuffered = TRUE;
651}
652
653void QTextCursor::gotoLeft()
654{
655 if ( string->string()->isRightToLeft() )
656 gotoNextLetter();
657 else
658 gotoPreviousLetter();
659}
660
661void QTextCursor::gotoPreviousLetter()
662{
663 tmpIndex = -1;
664
665 if ( idx > 0 ) {
666 idx--;
667 } else if ( string->prev() ) {
668 QTextParag *s = string->prev();
669 while ( s && !s->isVisible() )
670 s = s->prev();
671 if ( s ) {
672 string = s;
673 idx = string->length() - 1;
674 }
675 } else {
676 if ( nested ) {
677 pop();
678 processNesting( Prev );
679 if ( idx == -1 ) {
680 pop();
681 if ( idx > 0 ) {
682 idx--;
683 } else if ( string->prev() ) {
684 string = string->prev();
685 idx = string->length() - 1;
686 }
687 }
688 }
689 }
690
691 const QTextStringChar *tsc = string->at( idx );
692 if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
693 processNesting( EnterEnd );
694 }
695}
696
697void QTextCursor::push()
698{
699 indices.push( idx );
700 parags.push( string );
701 xOffsets.push( ox );
702 yOffsets.push( oy );
703 nestedStack.push( nested );
704}
705
706void QTextCursor::pop()
707{
708 if ( !doc )
709 return;
710 idx = indices.pop();
711 string = parags.pop();
712 ox = xOffsets.pop();
713 oy = yOffsets.pop();
714 if ( doc->parent() )
715 doc = doc->parent();
716 nested = nestedStack.pop();
717}
718
719void QTextCursor::restoreState()
720{
721 while ( !indices.isEmpty() )
722 pop();
723}
724
725bool QTextCursor::place( const QPoint &p, QTextParag *s, bool link )
726{
727 QPoint pos( p );
728 QRect r;
729 QTextParag *str = s;
730 if ( pos.y() < s->rect().y() )
731 pos.setY( s->rect().y() );
732 while ( s ) {
733 r = s->rect();
734 r.setWidth( doc ? doc->width() : QWIDGETSIZE_MAX );
735 if ( s->isVisible() )
736 str = s;
737 if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() || !s->next() )
738 break;
739 s = s->next();
740 }
741
742 if ( !s || !str )
743 return FALSE;
744
745 s = str;
746
747 setParag( s, FALSE );
748 int y = s->rect().y();
749 int lines = s->lines();
750 QTextStringChar *chr = 0;
751 int index = 0;
752 int i = 0;
753 int cy = 0;
754 int ch = 0;
755 for ( ; i < lines; ++i ) {
756 chr = s->lineStartOfLine( i, &index );
757 cy = s->lineY( i );
758 ch = s->lineHeight( i );
759 if ( !chr )
760 return FALSE;
761 if ( pos.y() >= y + cy && pos.y() <= y + cy + ch )
762 break;
763 }
764 int nextLine;
765 if ( i < lines - 1 )
766 s->lineStartOfLine( i+1, &nextLine );
767 else
768 nextLine = s->length();
769 i = index;
770 int x = s->rect().x();
771 if ( pos.x() < x )
772 pos.setX( x + 1 );
773 int cw;
774 int curpos = s->length()-1;
775 int dist = 10000000;
776 bool inCustom = FALSE;
777 while ( i < nextLine ) {
778 chr = s->at(i);
779 int cpos = x + chr->x;
780 cw = s->string()->width( i );
781 if ( chr->isCustom() && chr->customItem()->isNested() ) {
782 if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
783 pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
784 inCustom = TRUE;
785 curpos = i;
786 break;
787 }
788 } else {
789 if( chr->rightToLeft )
790 cpos += cw;
791 int d = cpos - pos.x();
792 bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
793 if ( QABS( d ) < dist || (dist == d && dm == TRUE ) ) {
794 dist = QABS( d );
795 if ( !link || pos.x() >= x + chr->x )
796 curpos = i;
797 }
798 }
799 i++;
800 }
801 setIndex( curpos, FALSE );
802
803 if ( inCustom && doc && parag()->at( curpos )->isCustom() && parag()->at( curpos )->customItem()->isNested() ) {
804 QTextDocument *oldDoc = doc;
805 gotoIntoNested( pos );
806 if ( oldDoc == doc )
807 return TRUE;
808 QPoint p( pos.x() - offsetX(), pos.y() - offsetY() );
809 if ( !place( p, document()->firstParag(), link ) )
810 pop();
811 }
812 return TRUE;
813}
814
815void QTextCursor::processNesting( Operation op )
816{
817 if ( !doc )
818 return;
819 push();
820 ox = string->at( idx )->x;
821 int bl, y;
822 string->lineHeightOfChar( idx, &bl, &y );
823 oy = y + string->rect().y();
824 nested = TRUE;
825 bool ok = FALSE;
826
827 switch ( op ) {
828 case EnterBegin:
829 ok = string->at( idx )->customItem()->enter( this, doc, string, idx, ox, oy );
830 break;
831 case EnterEnd:
832 ok = string->at( idx )->customItem()->enter( this, doc, string, idx, ox, oy, TRUE );
833 break;
834 case Next:
835 ok = string->at( idx )->customItem()->next( this, doc, string, idx, ox, oy );
836 break;
837 case Prev:
838 ok = string->at( idx )->customItem()->prev( this, doc, string, idx, ox, oy );
839 break;
840 case Down:
841 ok = string->at( idx )->customItem()->down( this, doc, string, idx, ox, oy );
842 break;
843 case Up:
844 ok = string->at( idx )->customItem()->up( this, doc, string, idx, ox, oy );
845 break;
846 }
847 if ( !ok )
848 pop();
849}
850
851void QTextCursor::gotoRight()
852{
853 if ( string->string()->isRightToLeft() )
854 gotoPreviousLetter();
855 else
856 gotoNextLetter();
857}
858
859void QTextCursor::gotoNextLetter()
860{
861 tmpIndex = -1;
862
863 const QTextStringChar *tsc = string->at( idx );
864 if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
865 processNesting( EnterBegin );
866 return;
867 }
868
869 if ( idx < string->length() - 1 ) {
870 idx++;
871 } else if ( string->next() ) {
872 QTextParag *s = string->next();
873 while ( s && !s->isVisible() )
874 s = s->next();
875 if ( s ) {
876 string = s;
877 idx = 0;
878 }
879 } else {
880 if ( nested ) {
881 pop();
882 processNesting( Next );
883 if ( idx == -1 ) {
884 pop();
885 if ( idx < string->length() - 1 ) {
886 idx++;
887 } else if ( string->next() ) {
888 string = string->next();
889 idx = 0;
890 }
891 }
892 }
893 }
894}
895
896void QTextCursor::gotoUp()
897{
898 int indexOfLineStart;
899 int line;
900 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
901 if ( !c )
902 return;
903
904 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
905 if ( indexOfLineStart == 0 ) {
906 if ( !string->prev() ) {
907 if ( !nested )
908 return;
909 pop();
910 processNesting( Up );
911 if ( idx == -1 ) {
912 pop();
913 if ( !string->prev() )
914 return;
915 idx = tmpIndex = 0;
916 } else {
917 tmpIndex = -1;
918 return;
919 }
920 }
921 QTextParag *s = string->prev();
922 while ( s && !s->isVisible() )
923 s = s->prev();
924 if ( s )
925 string = s;
926 int lastLine = string->lines() - 1;
927 if ( !string->lineStartOfLine( lastLine, &indexOfLineStart ) )
928 return;
929 if ( indexOfLineStart + tmpIndex < string->length() )
930 idx = indexOfLineStart + tmpIndex;
931 else
932 idx = string->length() - 1;
933 } else {
934 --line;
935 int oldIndexOfLineStart = indexOfLineStart;
936 if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
937 return;
938 if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart )
939 idx = indexOfLineStart + tmpIndex;
940 else
941 idx = oldIndexOfLineStart - 1;
942 }
943}
944
945void QTextCursor::gotoDown()
946{
947 int indexOfLineStart;
948 int line;
949 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
950 if ( !c )
951 return;
952
953 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
954 if ( line == string->lines() - 1 ) {
955 if ( !string->next() ) {
956 if ( !nested )
957 return;
958 pop();
959 processNesting( Down );
960 if ( idx == -1 ) {
961 pop();
962 if ( !string->next() )
963 return;
964 idx = tmpIndex = 0;
965 } else {
966 tmpIndex = -1;
967 return;
968 }
969 }
970 QTextParag *s = string->next();
971 while ( s && !s->isVisible() )
972 s = s->next();
973 if ( s )
974 string = s;
975 if ( !string->lineStartOfLine( 0, &indexOfLineStart ) )
976 return;
977 int end;
978 if ( string->lines() == 1 )
979 end = string->length();
980 else
981 string->lineStartOfLine( 1, &end );
982 if ( indexOfLineStart + tmpIndex < end )
983 idx = indexOfLineStart + tmpIndex;
984 else
985 idx = end - 1;
986 } else {
987 ++line;
988 int end;
989 if ( line == string->lines() - 1 )
990 end = string->length();
991 else
992 string->lineStartOfLine( line + 1, &end );
993 if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
994 return;
995 if ( indexOfLineStart + tmpIndex < end )
996 idx = indexOfLineStart + tmpIndex;
997 else
998 idx = end - 1;
999 }
1000}
1001
1002void QTextCursor::gotoLineEnd()
1003{
1004 tmpIndex = -1;
1005 int indexOfLineStart;
1006 int line;
1007 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
1008 if ( !c )
1009 return;
1010
1011 if ( line == string->lines() - 1 ) {
1012 idx = string->length() - 1;
1013 } else {
1014 c = string->lineStartOfLine( ++line, &indexOfLineStart );
1015 indexOfLineStart--;
1016 idx = indexOfLineStart;
1017 }
1018}
1019
1020void QTextCursor::gotoLineStart()
1021{
1022 tmpIndex = -1;
1023 int indexOfLineStart;
1024 int line;
1025 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
1026 if ( !c )
1027 return;
1028
1029 idx = indexOfLineStart;
1030}
1031
1032void QTextCursor::gotoHome()
1033{
1034 tmpIndex = -1;
1035 if ( doc )
1036 string = doc->firstParag();
1037 idx = 0;
1038}
1039
1040void QTextCursor::gotoEnd()
1041{
1042 if ( doc && !doc->lastParag()->isValid() )
1043 return;
1044
1045 tmpIndex = -1;
1046 if ( doc )
1047 string = doc->lastParag();
1048 idx = string->length() - 1;
1049}
1050
1051void QTextCursor::gotoPageUp( int visibleHeight )
1052{
1053 tmpIndex = -1;
1054 QTextParag *s = string;
1055 int h = visibleHeight;
1056 int y = s->rect().y();
1057 while ( s ) {
1058 if ( y - s->rect().y() >= h )
1059 break;
1060 s = s->prev();
1061 }
1062
1063 if ( !s && doc )
1064 s = doc->firstParag();
1065
1066 string = s;
1067 idx = 0;
1068}
1069
1070void QTextCursor::gotoPageDown( int visibleHeight )
1071{
1072 tmpIndex = -1;
1073 QTextParag *s = string;
1074 int h = visibleHeight;
1075 int y = s->rect().y();
1076 while ( s ) {
1077 if ( s->rect().y() - y >= h )
1078 break;
1079 s = s->next();
1080 }
1081
1082 if ( !s && doc ) {
1083 s = doc->lastParag();
1084 string = s;
1085 idx = string->length() - 1;
1086 return;
1087 }
1088
1089 if ( !s->isValid() )
1090 return;
1091
1092 string = s;
1093 idx = 0;
1094}
1095
1096void QTextCursor::gotoWordRight()
1097{
1098 if ( string->string()->isRightToLeft() )
1099 gotoPreviousWord();
1100 else
1101 gotoNextWord();
1102}
1103
1104void QTextCursor::gotoWordLeft()
1105{
1106 if ( string->string()->isRightToLeft() )
1107 gotoNextWord();
1108 else
1109 gotoPreviousWord();
1110}
1111
1112void QTextCursor::gotoPreviousWord()
1113{
1114 gotoPreviousLetter();
1115 tmpIndex = -1;
1116 QTextString *s = string->string();
1117 bool allowSame = FALSE;
1118 if ( idx == ((int)s->length()-1) )
1119 return;
1120 for ( int i = idx; i >= 0; --i ) {
1121 if ( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
1122 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) {
1123 if ( !allowSame )
1124 continue;
1125 idx = i + 1;
1126 return;
1127 }
1128 if ( !allowSame && !( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
1129 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) )
1130 allowSame = TRUE;
1131 }
1132 idx = 0;
1133}
1134
1135void QTextCursor::gotoNextWord()
1136{
1137 tmpIndex = -1;
1138 QTextString *s = string->string();
1139 bool allowSame = FALSE;
1140 for ( int i = idx; i < (int)s->length(); ++i ) {
1141 if ( ! (s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
1142 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';') ) {
1143 if ( !allowSame )
1144 continue;
1145 idx = i;
1146 return;
1147 }
1148 if ( !allowSame && ( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
1149 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) )
1150 allowSame = TRUE;
1151
1152 }
1153
1154 if ( idx < ((int)s->length()-1) ) {
1155 gotoLineEnd();
1156 } else if ( string->next() ) {
1157 QTextParag *s = string->next();
1158 while ( s && !s->isVisible() )
1159 s = s->next();
1160 if ( s ) {
1161 string = s;
1162 idx = 0;
1163 }
1164 } else {
1165 gotoLineEnd();
1166 }
1167}
1168
1169bool QTextCursor::atParagStart()
1170{
1171 return idx == 0;
1172}
1173
1174bool QTextCursor::atParagEnd()
1175{
1176 return idx == string->length() - 1;
1177}
1178
1179void QTextCursor::splitAndInsertEmptyParag( bool ind, bool updateIds )
1180{
1181 if ( !doc )
1182 return;
1183 tmpIndex = -1;
1184 QTextFormat *f = 0;
1185 if ( doc->useFormatCollection() ) {
1186 f = string->at( idx )->format();
1187 if ( idx == string->length() - 1 && idx > 0 )
1188 f = string->at( idx - 1 )->format();
1189 if ( f->isMisspelled() ) {
1190 f->removeRef();
1191 f = doc->formatCollection()->format( f->font(), f->color() );
1192 }
1193 }
1194
1195 if ( atParagEnd() ) {
1196 QTextParag *n = string->next();
1197 QTextParag *s = doc->createParag( doc, string, n, updateIds );
1198 if ( f )
1199 s->setFormat( 0, 1, f, TRUE );
1200 s->copyParagData( string );
1201 if ( ind ) {
1202 int oi, ni;
1203 s->indent( &oi, &ni );
1204 string = s;
1205 idx = ni;
1206 } else {
1207 string = s;
1208 idx = 0;
1209 }
1210 } else if ( atParagStart() ) {
1211 QTextParag *p = string->prev();
1212 QTextParag *s = doc->createParag( doc, p, string, updateIds );
1213 if ( f )
1214 s->setFormat( 0, 1, f, TRUE );
1215 s->copyParagData( string );
1216 if ( ind ) {
1217 s->indent();
1218 s->format();
1219 indent();
1220 string->format();
1221 }
1222 } else {
1223 QString str = string->string()->toString().mid( idx, 0xFFFFFF );
1224 QTextParag *n = string->next();
1225 QTextParag *s = doc->createParag( doc, string, n, updateIds );
1226 s->copyParagData( string );
1227 s->remove( 0, 1 );
1228 s->append( str, TRUE );
1229 for ( uint i = 0; i < str.length(); ++i ) {
1230 s->setFormat( i, 1, string->at( idx + i )->format(), TRUE );
1231 if ( string->at( idx + i )->isCustom() ) {
1232 QTextCustomItem * item = string->at( idx + i )->customItem();
1233 s->at( i )->setCustomItem( item );
1234 string->at( idx + i )->loseCustomItem();
1235 }
1236 }
1237 string->truncate( idx );
1238 if ( ind ) {
1239 int oi, ni;
1240 s->indent( &oi, &ni );
1241 string = s;
1242 idx = ni;
1243 } else {
1244 string = s;
1245 idx = 0;
1246 }
1247 }
1248
1249 invalidateNested();
1250}
1251
1252bool QTextCursor::remove()
1253{
1254 tmpIndex = -1;
1255 if ( !atParagEnd() ) {
1256 string->remove( idx, 1 );
1257 int h = string->rect().height();
1258 string->format( -1, TRUE );
1259 if ( h != string->rect().height() )
1260 invalidateNested();
1261 else if ( doc && doc->parent() )
1262 doc->nextDoubleBuffered = TRUE;
1263 return FALSE;
1264 } else if ( string->next() ) {
1265 if ( string->length() == 1 ) {
1266 string->next()->setPrev( string->prev() );
1267 if ( string->prev() )
1268 string->prev()->setNext( string->next() );
1269 QTextParag *p = string->next();
1270 delete string;
1271 string = p;
1272 string->invalidate( 0 );
1273 QTextParag *s = string;
1274 while ( s ) {
1275 s->id = s->p ? s->p->id + 1 : 0;
1276 s->state = -1;
1277 s->needPreProcess = TRUE;
1278 s->changed = TRUE;
1279 s = s->n;
1280 }
1281 string->format();
1282 } else {
1283 string->join( string->next() );
1284 }
1285 invalidateNested();
1286 return TRUE;
1287 }
1288 return FALSE;
1289}
1290
1291void QTextCursor::killLine()
1292{
1293 if ( atParagEnd() )
1294 return;
1295 string->remove( idx, string->length() - idx - 1 );
1296 int h = string->rect().height();
1297 string->format( -1, TRUE );
1298 if ( h != string->rect().height() )
1299 invalidateNested();
1300 else if ( doc && doc->parent() )
1301 doc->nextDoubleBuffered = TRUE;
1302}
1303
1304void QTextCursor::indent()
1305{
1306 int oi = 0, ni = 0;
1307 string->indent( &oi, &ni );
1308 if ( oi == ni )
1309 return;
1310
1311 if ( idx >= oi )
1312 idx += ni - oi;
1313 else
1314 idx = ni;
1315}
1316
1317void QTextCursor::setDocument( QTextDocument *d )
1318{
1319 doc = d;
1320 string = d->firstParag();
1321 idx = 0;
1322 nested = FALSE;
1323 restoreState();
1324 tmpIndex = -1;
1325}
1326
1327// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1328
1329QTextDocument::QTextDocument( QTextDocument *p )
1330 : par( p ), parParag( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 )
1331{
1332 fCollection = new QTextFormatCollection;
1333 init();
1334}
1335
1336QTextDocument::QTextDocument( QTextDocument *p, QTextFormatCollection *f )
1337 : par( p ), parParag( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 )
1338{
1339 fCollection = f;
1340 init();
1341}
1342
1343void QTextDocument::init()
1344{
1345#if defined(PARSER_DEBUG)
1346 qDebug( debug_indent + "new QTextDocument (%p)", this );
1347#endif
1348 oTextValid = TRUE;
1349 mightHaveCustomItems = FALSE;
1350 if ( par )
1351 par->insertChild( this );
1352 pProcessor = 0;
1353 useFC = TRUE;
1354 pFormatter = 0;
1355 indenter = 0;
1356 fParag = 0;
1357 txtFormat = Qt::AutoText;
1358 preferRichText = FALSE;
1359 pages = FALSE;
1360 focusIndicator.parag = 0;
1361 minw = 0;
1362 wused = 0;
1363 minwParag = curParag = 0;
1364 align = AlignAuto;
1365 nSelections = 1;
1366 addMargs = FALSE;
1367
1368 sheet_ = QStyleSheet::defaultSheet();
1369 factory_ = QMimeSourceFactory::defaultFactory();
1370 contxt = QString::null;
1371 fCollection->setStyleSheet( sheet_ );
1372
1373 underlLinks = par ? par->underlLinks : TRUE;
1374 backBrush = 0;
1375 buf_pixmap = 0;
1376 nextDoubleBuffered = FALSE;
1377
1378 if ( par )
1379 withoutDoubleBuffer = par->withoutDoubleBuffer;
1380 else
1381 withoutDoubleBuffer = FALSE;
1382
1383 lParag = fParag = createParag( this, 0, 0 );
1384 tmpCursor = 0;
1385
1386 cx = 0;
1387 cy = 2;
1388 if ( par )
1389 cx = cy = 0;
1390 cw = 600;
1391 vw = 0;
1392 flow_ = new QTextFlow;
1393 flow_->setWidth( cw );
1394
1395 leftmargin = rightmargin = 4;
1396
1397 selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
1398 selectionText[ Standard ] = TRUE;
1399 commandHistory = new QTextCommandHistory( 100 );
1400 tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
1401}
1402
1403QTextDocument::~QTextDocument()
1404{
1405 if ( par )
1406 par->removeChild( this );
1407 clear();
1408 delete commandHistory;
1409 delete flow_;
1410 if ( !par )
1411 delete pFormatter;
1412 delete fCollection;
1413 delete pProcessor;
1414 delete buf_pixmap;
1415 delete indenter;
1416 delete backBrush;
1417 if ( tArray )
1418 delete [] tArray;
1419}
1420
1421void QTextDocument::clear( bool createEmptyParag )
1422{
1423 if ( flow_ )
1424 flow_->clear();
1425 while ( fParag ) {
1426 QTextParag *p = fParag->next();
1427 delete fParag;
1428 fParag = p;
1429 }
1430 fParag = lParag = 0;
1431 if ( createEmptyParag )
1432 fParag = lParag = createParag( this );
1433 selections.clear();
1434}
1435
1436int QTextDocument::widthUsed() const
1437{
1438 return wused + border_tolerance;
1439}
1440
1441int QTextDocument::height() const
1442{
1443 int h = 0;
1444 if ( lParag )
1445 h = lParag->rect().top() + lParag->rect().height() + 1;
1446 int fh = flow_->boundingRect().bottom();
1447 return QMAX( h, fh );
1448}
1449
1450
1451
1452QTextParag *QTextDocument::createParag( QTextDocument *d, QTextParag *pr, QTextParag *nx, bool updateIds )
1453{
1454 return new QTextParag( d, pr, nx, updateIds );
1455}
1456
1457bool QTextDocument::setMinimumWidth( int needed, int used, QTextParag *p )
1458{
1459 if ( needed == -1 ) {
1460 minw = 0;
1461 wused = 0;
1462 p = 0;
1463 }
1464 if ( p == minwParag ) {
1465 minw = needed;
1466 emit minimumWidthChanged( minw );
1467 } else if ( needed > minw ) {
1468 minw = needed;
1469 minwParag = p;
1470 emit minimumWidthChanged( minw );
1471 }
1472 wused = QMAX( wused, used );
1473 wused = QMAX( wused, minw );
1474 cw = QMAX( minw, cw );
1475 return TRUE;
1476}
1477
1478void QTextDocument::setPlainText( const QString &text )
1479{
1480 clear();
1481 preferRichText = FALSE;
1482 oTextValid = TRUE;
1483 oText = text;
1484
1485 int lastNl = 0;
1486 int nl = text.find( '\n' );
1487 if ( nl == -1 ) {
1488 lParag = createParag( this, lParag, 0 );
1489 if ( !fParag )
1490 fParag = lParag;
1491 QString s = text;
1492 if ( !s.isEmpty() ) {
1493 if ( s[ (int)s.length() - 1 ] == '\r' )
1494 s.remove( s.length() - 1, 1 );
1495 lParag->append( s );
1496 }
1497 } else {
1498 for (;;) {
1499 lParag = createParag( this, lParag, 0 );
1500 if ( !fParag )
1501 fParag = lParag;
1502 QString s = text.mid( lastNl, nl - lastNl );
1503 if ( !s.isEmpty() ) {
1504 if ( s[ (int)s.length() - 1 ] == '\r' )
1505 s.remove( s.length() - 1, 1 );
1506 lParag->append( s );
1507 }
1508 if ( nl == 0xffffff )
1509 break;
1510 lastNl = nl + 1;
1511 nl = text.find( '\n', nl + 1 );
1512 if ( nl == -1 )
1513 nl = 0xffffff;
1514 }
1515 }
1516 if ( !lParag )
1517 lParag = fParag = createParag( this, 0, 0 );
1518}
1519
1520struct Q_EXPORT QTextDocumentTag {
1521 QTextDocumentTag(){}
1522 QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f )
1523 :name(n),style(s), format(f), alignment(Qt3::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) {
1524 wsm = QStyleSheetItem::WhiteSpaceNormal;
1525 }
1526 QString name;
1527 const QStyleSheetItem* style;
1528 QString anchorHref;
1529 QStyleSheetItem::WhiteSpaceMode wsm;
1530 QTextFormat format;
1531 int alignment : 16;
1532 int direction : 5;
1533 QStyleSheetItem::ListStyle liststyle;
1534
1535 QTextDocumentTag( const QTextDocumentTag& t ) {
1536 name = t.name;
1537 style = t.style;
1538 anchorHref = t.anchorHref;
1539 wsm = t.wsm;
1540 format = t.format;
1541 alignment = t.alignment;
1542 direction = t.direction;
1543 liststyle = t.liststyle;
1544 }
1545 QTextDocumentTag& operator=(const QTextDocumentTag& t) {
1546 name = t.name;
1547 style = t.style;
1548 anchorHref = t.anchorHref;
1549 wsm = t.wsm;
1550 format = t.format;
1551 alignment = t.alignment;
1552 direction = t.direction;
1553 liststyle = t.liststyle;
1554 return *this;
1555 }
1556
1557#if defined(Q_FULL_TEMPLATE_INSTANTIATION)
1558 bool operator==( const QTextDocumentTag& ) const { return FALSE; }
1559#endif
1560};
1561
1562#define NEWPAR do{ if ( !hasNewPar ) curpar = createParag( this, curpar ); \
1563 if ( curpar->isBr ) curpar->isBr = FALSE; \
1564 hasNewPar = TRUE; \
1565 curpar->setAlignment( curtag.alignment ); \
1566 curpar->setDirection( (QChar::Direction)curtag.direction ); \
1567 space = TRUE; \
1568 QPtrVector<QStyleSheetItem> vec( (uint)tags.count() + 1); \
1569 int i = 0; \
1570 for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \
1571 vec.insert( i++, (*it).style ); \
1572 vec.insert( i, curtag.style ); \
1573 curpar->setStyleSheetItems( vec ); }while(FALSE)
1574
1575
1576void QTextDocument::setRichText( const QString &text, const QString &context )
1577{
1578 setTextFormat( Qt::RichText );
1579 if ( !context.isEmpty() )
1580 setContext( context );
1581 clear();
1582 fParag = lParag = createParag( this );
1583 setRichTextInternal( text );
1584}
1585
1586static QStyleSheetItem::ListStyle chooseListStyle( const QStyleSheetItem *nstyle,
1587 const QMap<QString, QString> &attr,
1588 QStyleSheetItem::ListStyle curListStyle )
1589{
1590 if ( nstyle->name() == "ol" || nstyle->name() == "ul" ) {
1591 curListStyle = nstyle->listStyle();
1592 QMap<QString, QString>::ConstIterator it = attr.find( "type" );
1593 if ( it != attr.end() ) {
1594 QString sl = *it;
1595 if ( sl == "1" ) {
1596 curListStyle = QStyleSheetItem::ListDecimal;
1597 } else if ( sl == "a" ) {
1598 curListStyle = QStyleSheetItem::ListLowerAlpha;
1599 } else if ( sl == "A" ) {
1600 curListStyle = QStyleSheetItem::ListUpperAlpha;
1601 } else {
1602 sl = sl.lower();
1603 if ( sl == "square" )
1604 curListStyle = QStyleSheetItem::ListSquare;
1605 else if ( sl == "disc" )
1606 curListStyle = QStyleSheetItem::ListDisc;
1607 else if ( sl == "circle" )
1608 curListStyle = QStyleSheetItem::ListCircle;
1609 }
1610 }
1611 }
1612 return curListStyle;
1613}
1614
1615void QTextDocument::setRichTextInternal( const QString &text )
1616{
1617 oTextValid = TRUE;
1618 oText = text;
1619 QTextParag* curpar = lParag;
1620 int pos = 0;
1621 QValueStack<QTextDocumentTag> tags;
1622 QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() );
1623 QTextDocumentTag curtag = initag;
1624 bool space = TRUE;
1625
1626 const QChar* doc = text.unicode();
1627 int length = text.length();
1628 bool hasNewPar = curpar->length() <= 1;
1629 QString lastClose;
1630 QString anchorName;
1631 while ( pos < length ) {
1632 if ( hasPrefix(doc, length, pos, '<' ) ){
1633 if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) {
1634 // open tag
1635 QMap<QString, QString> attr;
1636 bool emptyTag = FALSE;
1637 QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag);
1638 if ( tagname.isEmpty() )
1639 continue; // nothing we could do with this, probably parse error
1640
1641 if ( tagname == "title" ) {
1642 QString title;
1643 while ( pos < length ) {
1644 if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) &&
1645 parseCloseTag( doc, length, pos ) == "title" )
1646 break;
1647 title += doc[ pos ];
1648 ++pos;
1649 }
1650 attribs.replace( "title", title );
1651 }
1652
1653 const QStyleSheetItem* nstyle = sheet_->item(tagname);
1654
1655 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1656 // if ( tagname == "br" ) {
1657 // // our standard br emty-tag handling breaks
1658 // // inside list items, we would get another
1659 // // list item in this case. As workaround, fake
1660 // // a new paragraph instead
1661 // tagname = "p";
1662 // nstyle = sheet_->item( tagname );
1663 // }
1664 if ( nstyle )
1665 hasNewPar = FALSE; // we want empty paragraphs in this case
1666 }
1667
1668 if ( nstyle ) {
1669 // we might have to close some 'forgotten' tags
1670 while ( !nstyle->allowedInContext( curtag.style ) ) {
1671 QString msg;
1672 msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)",
1673 tagname.ascii(), curtag.style->name().ascii(), pos);
1674 sheet_->error( msg );
1675 if ( tags.isEmpty() )
1676 break;
1677 curtag = tags.pop();
1678 }
1679
1680 // special handling for p. We do not want to nest there for HTML compatibility
1681 if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) {
1682 while ( curtag.style->name() == "p" ) {
1683 if ( tags.isEmpty() )
1684 break;
1685 curtag = tags.pop();
1686 }
1687 }
1688
1689 }
1690
1691 QTextCustomItem* custom = 0;
1692 // some well-known empty tags
1693 if ( tagname == "br" ) {
1694 emptyTag = TRUE;
1695 hasNewPar = FALSE;
1696 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1697 // when linebreaking a list item, we do not
1698 // actually want a new list item but just a
1699 // new line. Fake this by pushing a paragraph
1700 // onto the stack
1701 tags.push( curtag );
1702 curtag.name = tagname;
1703 curtag.style = nstyle;
1704 }
1705 NEWPAR;
1706 curpar->isBr = TRUE;
1707 curpar->setAlignment( curtag.alignment );
1708 } else if ( tagname == "hr" ) {
1709 emptyTag = TRUE;
1710 custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
1711 NEWPAR;
1712 } else if ( tagname == "table" ) {
1713 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr );
1714 curpar->setAlignment( curtag.alignment );
1715 custom = parseTable( attr, format, doc, length, pos, curpar );
1716 (void)eatSpace( doc, length, pos );
1717 emptyTag = TRUE;
1718 } else if ( tagname == "qt" ) {
1719 for ( QMap<QString, QString>::Iterator it = attr.begin(); it != attr.end(); ++it ) {
1720 if ( it.key() == "bgcolor" ) {
1721 QBrush *b = new QBrush( QColor( *it ) );
1722 setPaper( b );
1723 } else if ( it.key() == "background" ) {
1724 QImage img;
1725 const QMimeSource* m = factory_->data( *it, contxt );
1726 if ( !m ) {
1727 qWarning("QRichText: no mimesource for %s", (*it).latin1() );
1728 } else {
1729 if ( !QImageDrag::decode( m, img ) ) {
1730 qWarning("QTextImage: cannot decode %s", (*it).latin1() );
1731 }
1732 }
1733 if ( !img.isNull() ) {
1734 QPixmap pm;
1735 pm.convertFromImage( img );
1736 QBrush *b = new QBrush( QColor(), pm );
1737 setPaper( b );
1738 }
1739 } else if ( it.key() == "text" ) {
1740 QColor c( *it );
1741 if ( formatCollection()->defaultFormat()->color() != c ) {
1742 QDict<QTextFormat> formats = formatCollection()->dict();
1743 QDictIterator<QTextFormat> it( formats );
1744 while ( it.current() ) {
1745 if ( it.current() == formatCollection()->defaultFormat() ) {
1746 ++it;
1747 continue;
1748 }
1749 it.current()->setColor( c );
1750 ++it;
1751 }
1752 formatCollection()->defaultFormat()->setColor( c );
1753 curtag.format.setColor( c );
1754 }
1755 } else if ( it.key() == "link" ) {
1756 linkColor = QColor( *it );
1757 } else if ( it.key() == "title" ) {
1758 attribs.replace( it.key(), *it );
1759 }
1760 }
1761 } else {
1762 custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
1763 }
1764
1765 if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it
1766 continue;
1767
1768 if ( custom ) {
1769 int index = curpar->length() - 1;
1770 if ( index < 0 )
1771 index = 0;
1772 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr );
1773 curpar->append( QChar('*') );
1774 curpar->setFormat( index, 1, &format );
1775 curpar->at( index )->setCustomItem( custom );
1776 if ( !curtag.anchorHref.isEmpty() )
1777 curpar->at(index)->setAnchor( QString::null, curtag.anchorHref );
1778 if ( !anchorName.isEmpty() ) {
1779 curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
1780 anchorName = QString::null;
1781 }
1782 registerCustomItem( custom, curpar );
1783 hasNewPar = FALSE;
1784 } else if ( !emptyTag ) {
1785 // ignore whitespace for inline elements if there was already one
1786 if ( nstyle->whiteSpaceMode() == QStyleSheetItem::WhiteSpaceNormal
1787 && ( space || nstyle->displayMode() != QStyleSheetItem::DisplayInline ) )
1788 eatSpace( doc, length, pos );
1789
1790 // if we do nesting, push curtag on the stack,
1791 // otherwise reinint curag.
1792 if ( nstyle != curtag.style || nstyle->selfNesting() ) {
1793 tags.push( curtag );
1794 } else {
1795 if ( !tags.isEmpty() )
1796 curtag = tags.top();
1797 else
1798 curtag = initag;
1799 }
1800
1801 const QStyleSheetItem* ostyle = curtag.style;
1802
1803 curtag.name = tagname;
1804 curtag.style = nstyle;
1805 curtag.name = tagname;
1806 curtag.style = nstyle;
1807 if ( nstyle->whiteSpaceMode() != QStyleSheetItem::WhiteSpaceNormal )
1808 curtag.wsm = nstyle->whiteSpaceMode();
1809 curtag.liststyle = chooseListStyle( nstyle, attr, curtag.liststyle );
1810 curtag.format = curtag.format.makeTextFormat( nstyle, attr );
1811 if ( nstyle->isAnchor() ) {
1812 if ( !anchorName.isEmpty() )
1813 anchorName += "#" + attr["name"];
1814 else
1815 anchorName = attr["name"];
1816 curtag.anchorHref = attr["href"];
1817 }
1818
1819 if ( nstyle->alignment() != QStyleSheetItem::Undefined )
1820 curtag.alignment = nstyle->alignment();
1821
1822 if ( ostyle->displayMode() == QStyleSheetItem::DisplayListItem &&
1823 curpar->length() <= 1
1824 && nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) {
1825 // do not do anything, we reuse the paragraph we have
1826 } else if ( nstyle->displayMode() != QStyleSheetItem::DisplayInline && nstyle->displayMode() != QStyleSheetItem::DisplayNone ) {
1827 NEWPAR;
1828 }
1829
1830 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1831 curpar->setListStyle( curtag.liststyle );
1832 if ( attr.find( "value" ) != attr.end() )
1833 curpar->setListValue( (*attr.find( "value" )).toInt() );
1834 }
1835
1836 if ( nstyle->displayMode() != QStyleSheetItem::DisplayInline )
1837 curpar->setFormat( &curtag.format );
1838
1839 if ( attr.contains( "align" ) &&
1840 ( curtag.name == "p" ||
1841 curtag.name == "div" ||
1842 curtag.name == "li" ||
1843 curtag.name[ 0 ] == 'h' ) ) {
1844 QString align = attr["align"];
1845 if ( align == "center" )
1846 curtag.alignment = Qt::AlignCenter;
1847 else if ( align == "right" )
1848 curtag.alignment = Qt::AlignRight;
1849 else if ( align == "justify" )
1850 curtag.alignment = Qt3::AlignJustify;
1851 }
1852 if ( attr.contains( "dir" ) &&
1853 ( curtag.name == "p" ||
1854 curtag.name == "div" ||
1855 curtag.name == "li" ||
1856 curtag.name[ 0 ] == 'h' ) ) {
1857 QString dir = attr["dir"];
1858 if ( dir == "rtl" )
1859 curtag.direction = QChar::DirR;
1860 else if ( dir == "ltr" )
1861 curtag.direction = QChar::DirL;
1862 }
1863 if ( nstyle->displayMode() != QStyleSheetItem::DisplayInline ) {
1864 curpar->setAlignment( curtag.alignment );
1865 curpar->setDirection( (QChar::Direction)curtag.direction );
1866 }
1867 }
1868 } else {
1869 QString tagname = parseCloseTag( doc, length, pos );
1870 lastClose = tagname;
1871 if ( tagname.isEmpty() )
1872 continue; // nothing we could do with this, probably parse error
1873 if ( !sheet_->item( tagname ) ) // ignore unknown tags
1874 continue;
1875
1876
1877 // we close a block item. Since the text may continue, we need to have a new paragraph
1878 bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock;
1879
1880 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1881 needNewPar = TRUE;
1882 hasNewPar = FALSE; // we want empty paragraphs in this case
1883 }
1884
1885 // html slopiness: handle unbalanched tag closing
1886 while ( curtag.name != tagname ) {
1887 QString msg;
1888 msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)",
1889 curtag.name.ascii(), tagname.ascii(), pos);
1890 sheet_->error( msg );
1891 if ( tags.isEmpty() )
1892 break;
1893 curtag = tags.pop();
1894 }
1895
1896
1897 // close the tag
1898 if ( !tags.isEmpty() )
1899 curtag = tags.pop();
1900 else
1901 curtag = initag;
1902
1903 if ( needNewPar ) {
1904 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1905 tags.push( curtag );
1906 curtag.name = "p";
1907 curtag.style = sheet_->item( curtag.name ); // a list item continues, use p for that
1908 }
1909 NEWPAR;
1910 }
1911 }
1912 } else {
1913 // normal contents
1914 QString s;
1915 QChar c;
1916 while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){
1917 QStyleSheetItem::WhiteSpaceMode wsm = curtag.wsm;
1918 if ( s.length() > 4096 )
1919 wsm = (QStyleSheetItem::WhiteSpaceMode)QStyleSheetItem_WhiteSpaceNormalWithNewlines;
1920
1921 c = parseChar( doc, length, pos, wsm );
1922
1923 if ( c == '\n' ) // happens only in whitespacepre-mode or with WhiteSpaceNormalWithNewlines.
1924 break; // we want a new line in this case
1925
1926 bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U &&
1927 curtag.wsm != QStyleSheetItem_WhiteSpaceNoCompression;
1928
1929 if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space )
1930 continue;
1931 if ( c == '\r' )
1932 continue;
1933 space = c_isSpace;
1934 s += c;
1935 }
1936 if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) {
1937 hasNewPar = FALSE;
1938 int index = curpar->length() - 1;
1939 if ( index < 0 )
1940 index = 0;
1941 curpar->append( s );
1942 QTextFormat* f = formatCollection()->format( &curtag.format );
1943 curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already
1944 f->ref += s.length() -1; // that what friends are for...
1945 if ( !curtag.anchorHref.isEmpty() ) {
1946 for ( int i = 0; i < int(s.length()); i++ )
1947 curpar->at(index + i)->setAnchor( QString::null, curtag.anchorHref );
1948 }
1949 if ( !anchorName.isEmpty() ) {
1950 curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
1951 anchorName = QString::null;
1952 }
1953 }
1954 if ( c == '\n' ) { // happens in WhiteSpacePre mode
1955 hasNewPar = FALSE;
1956 tags.push( curtag );
1957 NEWPAR;
1958 curtag = tags.pop();
1959 }
1960 }
1961 }
1962
1963 if ( hasNewPar && curpar != fParag ) {
1964 // cleanup unused last paragraphs
1965 curpar = curpar->p;
1966 delete curpar->n;
1967 }
1968
1969 if ( !anchorName.isEmpty() ) {
1970 curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() );
1971 anchorName = QString::null;
1972 }
1973}
1974
1975void QTextDocument::setText( const QString &text, const QString &context )
1976{
1977 focusIndicator.parag = 0;
1978 selections.clear();
1979 if ( txtFormat == Qt::AutoText && QStyleSheet::mightBeRichText( text ) ||
1980 txtFormat == Qt::RichText )
1981 setRichText( text, context );
1982 else
1983 setPlainText( text );
1984}
1985
1986QString QTextDocument::plainText( QTextParag *p ) const
1987{
1988 if ( !p ) {
1989 QString buffer;
1990 QString s;
1991 QTextParag *p = fParag;
1992 while ( p ) {
1993 if ( !p->mightHaveCustomItems ) {
1994 s = p->string()->toString();
1995 } else {
1996 for ( int i = 0; i < p->length() - 1; ++i ) {
1997 if ( p->at( i )->isCustom() ) {
1998 if ( p->at( i )->customItem()->isNested() ) {
1999 s += "\n";
2000 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2001 QPtrList<QTextTableCell> cells = t->tableCells();
2002 for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
2003 s += c->richText()->plainText() + "\n";
2004 s += "\n";
2005 }
2006 } else {
2007 s += p->at( i )->c;
2008 }
2009 }
2010 }
2011 s.remove( s.length() - 1, 1 );
2012 if ( p->next() )
2013 s += "\n";
2014 buffer += s;
2015 p = p->next();
2016 }
2017 return buffer;
2018 } else {
2019 return p->string()->toString();
2020 }
2021}
2022
2023static QString align_to_string( const QString &tag, int a )
2024{
2025 if ( tag == "p" || tag == "li" || ( tag[0] == 'h' && tag[1].isDigit() ) ) {
2026 if ( a & Qt::AlignRight )
2027 return " align=\"right\"";
2028 if ( a & Qt::AlignCenter )
2029 return " align=\"center\"";
2030 if ( a & Qt3::AlignJustify )
2031 return " align=\"justify\"";
2032 }
2033 return "";
2034}
2035
2036static QString direction_to_string( const QString &tag, int d )
2037{
2038 if ( d != QChar::DirON &&
2039 ( tag == "p" || tag == "div" || tag == "li" || ( tag[0] == 'h' && tag[1].isDigit() ) ) )
2040 return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" );
2041 return "";
2042}
2043
2044QString QTextDocument::richText( QTextParag *p ) const
2045{
2046 QString s,n;
2047 if ( !p ) {
2048 p = fParag;
2049 QPtrVector<QStyleSheetItem> lastItems, items;
2050 while ( p ) {
2051 items = p->styleSheetItems();
2052 if ( items.size() ) {
2053 QStyleSheetItem *item = items[ items.size() - 1 ];
2054 items.resize( items.size() - 1 );
2055 if ( items.size() > lastItems.size() ) {
2056 for ( int i = lastItems.size(); i < (int)items.size(); ++i ) {
2057 n = items[i]->name();
2058 if ( n.isEmpty() || n == "li" )
2059 continue;
2060 s += "<" + n + align_to_string( n, p->alignment() ) + ">";
2061 }
2062 } else {
2063 QString end;
2064 for ( int i = items.size(); i < (int)lastItems.size(); ++i ) {
2065 n = lastItems[i]->name();
2066 if ( n.isEmpty() || n == "li" || n == "br" )
2067 continue;
2068 end.prepend( "</" + lastItems[ i ]->name() + ">" );
2069 }
2070 s += end;
2071 }
2072 lastItems = items;
2073 n = item->name();
2074 if ( n == "li" && p->listValue() != -1 ) {
2075 s += "<li value=\"" + QString::number( p->listValue() ) + "\">";
2076 } else {
2077 QString ps = p->richText();
2078 if ( ps.isEmpty() )
2079 s += "<br>"; // empty paragraph
2080 else if ( !n.isEmpty() ) {
2081 s += "<" + n + align_to_string( n, p->alignment() )
2082 + direction_to_string( n, p->direction() ) + ">" + ps;
2083 if ( n != "li" && n != "br")
2084 s += "</" + n + ">";
2085 } else
2086 s += ps;
2087 }
2088 } else {
2089 QString end;
2090 for ( int i = 0; i < (int)lastItems.size(); ++i ) {
2091 QString n = lastItems[i]->name();
2092 if ( n.isEmpty() || n == "li" || n == "br" )
2093 continue;
2094 end.prepend( "</" + n + ">" );
2095 }
2096 s += end;
2097 QString ps = p->richText();
2098 if ( ps.isEmpty() )
2099 s += "<br>"; // empty paragraph
2100 else
2101 s += "<p" + align_to_string( "p", p->alignment() ) + direction_to_string( "p", p->direction() )
2102 + ">" + ps + "</p>";
2103 lastItems = items;
2104 }
2105 if ( ( p = p->next() ) )
2106 s += '\n';
2107 }
2108 } else {
2109 s = p->richText();
2110 }
2111
2112 return s;
2113}
2114
2115QString QTextDocument::text() const
2116{
2117 if ( plainText().simplifyWhiteSpace().isEmpty() )
2118 return QString("");
2119 if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
2120 return richText();
2121 return plainText( 0 );
2122}
2123
2124QString QTextDocument::text( int parag ) const
2125{
2126 QTextParag *p = paragAt( parag );
2127 if ( !p )
2128 return QString::null;
2129
2130 if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
2131 return richText( p );
2132 else
2133 return plainText( p );
2134}
2135
2136void QTextDocument::invalidate()
2137{
2138 QTextParag *s = fParag;
2139 while ( s ) {
2140 s->invalidate( 0 );
2141 s = s->next();
2142 }
2143}
2144
2145void QTextDocument::selectionStart( int id, int &paragId, int &index )
2146{
2147 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2148 if ( it == selections.end() )
2149 return;
2150 QTextDocumentSelection &sel = *it;
2151 paragId = !sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
2152 index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
2153}
2154
2155QTextCursor QTextDocument::selectionStartCursor( int id)
2156{
2157 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2158 if ( it == selections.end() )
2159 return QTextCursor( this );
2160 QTextDocumentSelection &sel = *it;
2161 if ( sel.swapped )
2162 return sel.endCursor;
2163 return sel.startCursor;
2164}
2165
2166QTextCursor QTextDocument::selectionEndCursor( int id)
2167{
2168 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2169 if ( it == selections.end() )
2170 return QTextCursor( this );
2171 QTextDocumentSelection &sel = *it;
2172 if ( !sel.swapped )
2173 return sel.endCursor;
2174 return sel.startCursor;
2175}
2176
2177void QTextDocument::selectionEnd( int id, int &paragId, int &index )
2178{
2179 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2180 if ( it == selections.end() )
2181 return;
2182 QTextDocumentSelection &sel = *it;
2183 paragId = sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
2184 index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
2185}
2186
2187QTextParag *QTextDocument::selectionStart( int id )
2188{
2189 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2190 if ( it == selections.end() )
2191 return 0;
2192 QTextDocumentSelection &sel = *it;
2193 if ( sel.startCursor.parag()->paragId() < sel.endCursor.parag()->paragId() )
2194 return sel.startCursor.parag();
2195 return sel.endCursor.parag();
2196}
2197
2198QTextParag *QTextDocument::selectionEnd( int id )
2199{
2200 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2201 if ( it == selections.end() )
2202 return 0;
2203 QTextDocumentSelection &sel = *it;
2204 if ( sel.startCursor.parag()->paragId() > sel.endCursor.parag()->paragId() )
2205 return sel.startCursor.parag();
2206 return sel.endCursor.parag();
2207}
2208
2209void QTextDocument::addSelection( int id )
2210{
2211 nSelections = QMAX( nSelections, id + 1 );
2212}
2213
2214static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCursor &start, QTextCursor &end )
2215{
2216 QTextCursor c1 = start;
2217 QTextCursor c2 = end;
2218 if ( sel.swapped ) {
2219 c1 = end;
2220 c2 = start;
2221 }
2222
2223 c1.parag()->removeSelection( id );
2224 c2.parag()->removeSelection( id );
2225 if ( c1.parag() != c2.parag() ) {
2226 c1.parag()->setSelection( id, c1.index(), c1.parag()->length() - 1 );
2227 c2.parag()->setSelection( id, 0, c2.index() );
2228 } else {
2229 c1.parag()->setSelection( id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) );
2230 }
2231
2232 sel.startCursor = start;
2233 sel.endCursor = end;
2234 if ( sel.startCursor.parag() == sel.endCursor.parag() )
2235 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
2236}
2237
2238bool QTextDocument::setSelectionEnd( int id, QTextCursor *cursor )
2239{
2240 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2241 if ( it == selections.end() )
2242 return FALSE;
2243 QTextDocumentSelection &sel = *it;
2244
2245 QTextCursor start = sel.startCursor;
2246 QTextCursor end = *cursor;
2247
2248 if ( start == end ) {
2249 removeSelection( id );
2250 setSelectionStart( id, cursor );
2251 return TRUE;
2252 }
2253
2254 if ( sel.endCursor.parag() == end.parag() ) {
2255 setSelectionEndHelper( id, sel, start, end );
2256 return TRUE;
2257 }
2258
2259 bool inSelection = FALSE;
2260 QTextCursor c( this );
2261 QTextCursor tmp = sel.startCursor;
2262 if ( sel.swapped )
2263 tmp = sel.endCursor;
2264 tmp.restoreState();
2265 QTextCursor tmp2 = *cursor;
2266 tmp2.restoreState();
2267 c.setParag( tmp.parag()->paragId() < tmp2.parag()->paragId() ? tmp.parag() : tmp2.parag() );
2268 QTextCursor old;
2269 bool hadStart = FALSE;
2270 bool hadEnd = FALSE;
2271 bool hadStartParag = FALSE;
2272 bool hadEndParag = FALSE;
2273 bool hadOldStart = FALSE;
2274 bool hadOldEnd = FALSE;
2275 bool leftSelection = FALSE;
2276 sel.swapped = FALSE;
2277 for ( ;; ) {
2278 if ( c == start )
2279 hadStart = TRUE;
2280 if ( c == end )
2281 hadEnd = TRUE;
2282 if ( c.parag() == start.parag() )
2283 hadStartParag = TRUE;
2284 if ( c.parag() == end.parag() )
2285 hadEndParag = TRUE;
2286 if ( c == sel.startCursor )
2287 hadOldStart = TRUE;
2288 if ( c == sel.endCursor )
2289 hadOldEnd = TRUE;
2290
2291 if ( !sel.swapped &&
2292 ( hadEnd && !hadStart ||
2293 hadEnd && hadStart && start.parag() == end.parag() && start.index() > end.index() ) )
2294 sel.swapped = TRUE;
2295
2296 if ( c == end && hadStartParag ||
2297 c == start && hadEndParag ) {
2298 QTextCursor tmp = c;
2299 tmp.restoreState();
2300 if ( tmp.parag() != c.parag() ) {
2301 int sstart = tmp.parag()->selectionStart( id );
2302 tmp.parag()->removeSelection( id );
2303 tmp.parag()->setSelection( id, sstart, tmp.index() );
2304 }
2305 }
2306
2307 if ( inSelection &&
2308 ( c == end && hadStart || c == start && hadEnd ) )
2309 leftSelection = TRUE;
2310 else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
2311 inSelection = TRUE;
2312
2313 bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.parag()->hasSelection( id ) && c.atParagEnd();
2314 c.parag()->removeSelection( id );
2315 if ( inSelection ) {
2316 if ( c.parag() == start.parag() && start.parag() == end.parag() ) {
2317 c.parag()->setSelection( id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) );
2318 } else if ( c.parag() == start.parag() && !hadEndParag ) {
2319 c.parag()->setSelection( id, start.index(), c.parag()->length() - 1 );
2320 } else if ( c.parag() == end.parag() && !hadStartParag ) {
2321 c.parag()->setSelection( id, end.index(), c.parag()->length() - 1 );
2322 } else if ( c.parag() == end.parag() && hadEndParag ) {
2323 c.parag()->setSelection( id, 0, end.index() );
2324 } else if ( c.parag() == start.parag() && hadStartParag ) {
2325 c.parag()->setSelection( id, 0, start.index() );
2326 } else {
2327 c.parag()->setSelection( id, 0, c.parag()->length() - 1 );
2328 }
2329 }
2330
2331 if ( leftSelection )
2332 inSelection = FALSE;
2333
2334 old = c;
2335 c.gotoNextLetter();
2336 if ( old == c || noSelectionAnymore )
2337 break;
2338 }
2339
2340 if ( !sel.swapped )
2341 sel.startCursor.parag()->setSelection( id, sel.startCursor.index(), sel.startCursor.parag()->length() - 1 );
2342
2343 sel.startCursor = start;
2344 sel.endCursor = end;
2345 if ( sel.startCursor.parag() == sel.endCursor.parag() )
2346 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
2347
2348 setSelectionEndHelper( id, sel, start, end );
2349
2350 return TRUE;
2351}
2352
2353void QTextDocument::selectAll( int id )
2354{
2355 removeSelection( id );
2356
2357 QTextDocumentSelection sel;
2358 sel.swapped = FALSE;
2359 QTextCursor c( this );
2360
2361 c.setParag( fParag );
2362 c.setIndex( 0 );
2363 sel.startCursor = c;
2364
2365 c.setParag( lParag );
2366 c.setIndex( lParag->length() - 1 );
2367 sel.endCursor = c;
2368
2369 QTextParag *p = fParag;
2370 while ( p ) {
2371 p->setSelection( id, 0, p->length() - 1 );
2372 for ( int i = 0; i < (int)p->length(); ++i ) {
2373 if ( p->at( i )->isCustom() && p->at( i )->customItem()->isNested() ) {
2374 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2375 QPtrList<QTextTableCell> tableCells = t->tableCells();
2376 for ( QTextTableCell *c = tableCells.first(); c; c = tableCells.next() )
2377 c->richText()->selectAll( id );
2378 }
2379 }
2380 p = p->next();
2381 }
2382
2383 selections.insert( id, sel );
2384}
2385
2386bool QTextDocument::removeSelection( int id )
2387{
2388 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2389 if ( it == selections.end() )
2390 return FALSE;
2391
2392 QTextDocumentSelection &sel = *it;
2393
2394 if ( sel.startCursor == sel.endCursor ) {
2395 selections.remove( id );
2396 return TRUE;
2397 }
2398
2399 if ( !mightHaveCustomItems ) {
2400 QTextCursor start = sel.startCursor;
2401 QTextCursor end = sel.endCursor;
2402 if ( sel.swapped ) {
2403 start = sel.endCursor;
2404 end = sel.startCursor;
2405 }
2406
2407 for ( QTextParag *p = start.parag(); p; p = p->next() ) {
2408 p->removeSelection( id );
2409 if ( p == end.parag() )
2410 break;
2411 }
2412
2413 selections.remove( id );
2414 return TRUE;
2415 }
2416
2417 QTextCursor c( this );
2418 QTextCursor tmp = sel.startCursor;
2419 if ( sel.swapped )
2420 tmp = sel.endCursor;
2421 tmp.restoreState();
2422 c.setParag( tmp.parag() );
2423 QTextCursor old;
2424 bool hadStart = FALSE;
2425 bool hadEnd = FALSE;
2426 QTextParag *lastParag = 0;
2427 bool leftSelection = FALSE;
2428 bool inSelection = FALSE;
2429 sel.swapped = FALSE;
2430 for ( ;; ) {
2431 if ( c.parag() == sel.startCursor.parag() )
2432 hadStart = TRUE;
2433 if ( c.parag() == sel.endCursor.parag() )
2434 hadEnd = TRUE;
2435
2436 if ( inSelection &&
2437 ( c == sel.endCursor && hadStart || c == sel.startCursor && hadEnd ) )
2438 leftSelection = TRUE;
2439 else if ( !leftSelection && !inSelection && ( c.parag() == sel.startCursor.parag() || c.parag() == sel.endCursor.parag() ) )
2440 inSelection = TRUE;
2441
2442 bool noSelectionAnymore = leftSelection && !inSelection && !c.parag()->hasSelection( id ) && c.atParagEnd();
2443
2444 if ( lastParag != c.parag() )
2445 c.parag()->removeSelection( id );
2446
2447 old = c;
2448 lastParag = c.parag();
2449 c.gotoNextLetter();
2450 if ( old == c || noSelectionAnymore )
2451 break;
2452 }
2453
2454 selections.remove( id );
2455 return TRUE;
2456}
2457
2458QString QTextDocument::selectedText( int id, bool withCustom ) const
2459{
2460 // ######## TODO: look at textFormat() and return rich text or plain text (like the text() method!)
2461 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
2462 if ( it == selections.end() )
2463 return QString::null;
2464
2465 QTextDocumentSelection sel = *it;
2466
2467
2468 QTextCursor c1 = sel.startCursor;
2469 QTextCursor c2 = sel.endCursor;
2470 if ( sel.swapped ) {
2471 c2 = sel.startCursor;
2472 c1 = sel.endCursor;
2473 }
2474
2475 /* 3.0.3 improvement: Make it possible to get a reasonable
2476 selection inside a table. This approach is very conservative:
2477 make sure that both cursors have the same depth level and point
2478 to paragraphs within the same text document.
2479
2480 Meaning if you select text in two table cells, you will get the
2481 entire table. This is still far better than the 3.0.2, where
2482 you always got the entire table.
2483
2484 ### Fix this properly for 3.0.4.
2485 */
2486 while ( c2.nestedDepth() > c1.nestedDepth() )
2487 c2.oneUp();
2488 while ( c1.nestedDepth() > c2.nestedDepth() )
2489 c1.oneUp();
2490 while ( c1.nestedDepth() && c2.nestedDepth() &&
2491 c1.parag()->document() != c2.parag()->document() ) {
2492 c1.oneUp();
2493 c2.oneUp();
2494 }
2495 // do not trust sel_swapped with tables. Fix this properly for 3.0.4 as well
2496 if ( c1.parag()->paragId() > c2.parag()->paragId() ||
2497 (c1.parag() == c2.parag() && c1.index() > c2.index() ) ) {
2498 QTextCursor tmp = c1;
2499 c2 = c1;
2500 c1 = tmp;
2501 }
2502
2503 // end selection 3.0.3 improvement
2504
2505
2506 if ( c1.parag() == c2.parag() ) {
2507 QString s;
2508 QTextParag *p = c1.parag();
2509 int end = c2.index();
2510 if ( p->at( QMAX( 0, end - 1 ) )->isCustom() )
2511 ++end;
2512 if ( !withCustom || !p->mightHaveCustomItems ) {
2513 s += p->string()->toString().mid( c1.index(), end - c1.index() );
2514 } else {
2515 for ( int i = c1.index(); i < end; ++i ) {
2516 if ( p->at( i )->isCustom() ) {
2517 if ( p->at( i )->customItem()->isNested() ) {
2518 s += "\n";
2519 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2520 QPtrList<QTextTableCell> cells = t->tableCells();
2521 for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
2522 s += c->richText()->plainText() + "\n";
2523 s += "\n";
2524 }
2525 } else {
2526 s += p->at( i )->c;
2527 }
2528 }
2529 }
2530 return s;
2531 }
2532
2533 QString s;
2534 QTextParag *p = c1.parag();
2535 int start = c1.index();
2536 while ( p ) {
2537 int end = p == c2.parag() ? c2.index() : p->length() - 1;
2538 if ( p == c2.parag() && p->at( QMAX( 0, end - 1 ) )->isCustom() )
2539 ++end;
2540 if ( !withCustom || !p->mightHaveCustomItems ) {
2541 s += p->string()->toString().mid( start, end - start );
2542 if ( p != c2.parag() )
2543 s += "\n";
2544 } else {
2545 for ( int i = start; i < end; ++i ) {
2546 if ( p->at( i )->isCustom() ) {
2547 if ( p->at( i )->customItem()->isNested() ) {
2548 s += "\n";
2549 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2550 QPtrList<QTextTableCell> cells = t->tableCells();
2551 for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
2552 s += c->richText()->plainText() + "\n";
2553 s += "\n";
2554 }
2555 } else {
2556 s += p->at( i )->c;
2557 }
2558 }
2559 }
2560 start = 0;
2561 if ( p == c2.parag() )
2562 break;
2563 p = p->next();
2564 }
2565 return s;
2566}
2567
2568void QTextDocument::setFormat( int id, QTextFormat *f, int flags )
2569{
2570 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
2571 if ( it == selections.end() )
2572 return;
2573
2574 QTextDocumentSelection sel = *it;
2575
2576 QTextCursor c1 = sel.startCursor;
2577 QTextCursor c2 = sel.endCursor;
2578 if ( sel.swapped ) {
2579 c2 = sel.startCursor;
2580 c1 = sel.endCursor;
2581 }
2582
2583 c2.restoreState();
2584 c1.restoreState();
2585
2586 if ( c1.parag() == c2.parag() ) {
2587 c1.parag()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags );
2588 return;
2589 }
2590
2591 c1.parag()->setFormat( c1.index(), c1.parag()->length() - c1.index(), f, TRUE, flags );
2592 QTextParag *p = c1.parag()->next();
2593 while ( p && p != c2.parag() ) {
2594 p->setFormat( 0, p->length(), f, TRUE, flags );
2595 p = p->next();
2596 }
2597 c2.parag()->setFormat( 0, c2.index(), f, TRUE, flags );
2598}
2599
2600void QTextDocument::copySelectedText( int id )
2601{
2602#ifndef QT_NO_CLIPBOARD
2603 if ( !hasSelection( id ) )
2604 return;
2605
2606 QApplication::clipboard()->setText( selectedText( id ) );
2607#endif
2608}
2609
2610void QTextDocument::removeSelectedText( int id, QTextCursor *cursor )
2611{
2612 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2613 if ( it == selections.end() )
2614 return;
2615
2616 QTextDocumentSelection sel = *it;
2617
2618 QTextCursor c1 = sel.startCursor;
2619 QTextCursor c2 = sel.endCursor;
2620 if ( sel.swapped ) {
2621 c2 = sel.startCursor;
2622 c1 = sel.endCursor;
2623 }
2624
2625 // ### no support for editing tables yet
2626 if ( c1.nestedDepth() || c2.nestedDepth() )
2627 return;
2628
2629 c2.restoreState();
2630 c1.restoreState();
2631
2632 *cursor = c1;
2633 removeSelection( id );
2634
2635 if ( c1.parag() == c2.parag() ) {
2636 c1.parag()->remove( c1.index(), c2.index() - c1.index() );
2637 return;
2638 }
2639
2640 if ( c1.parag() == fParag && c1.index() == 0 &&
2641 c2.parag() == lParag && c2.index() == lParag->length() - 1 )
2642 cursor->setValid( FALSE );
2643
2644 bool didGoLeft = FALSE;
2645 if ( c1.index() == 0 && c1.parag() != fParag ) {
2646 cursor->gotoPreviousLetter();
2647 if ( cursor->isValid() )
2648 didGoLeft = TRUE;
2649 }
2650
2651 c1.parag()->remove( c1.index(), c1.parag()->length() - 1 - c1.index() );
2652 QTextParag *p = c1.parag()->next();
2653 int dy = 0;
2654 QTextParag *tmp;
2655 while ( p && p != c2.parag() ) {
2656 tmp = p->next();
2657 dy -= p->rect().height();
2658 delete p;
2659 p = tmp;
2660 }
2661 c2.parag()->remove( 0, c2.index() );
2662 while ( p ) {
2663 p->move( dy );
2664 p->invalidate( 0 );
2665 p->setEndState( -1 );
2666 p = p->next();
2667 }
2668
2669 c1.parag()->join( c2.parag() );
2670
2671 if ( didGoLeft )
2672 cursor->gotoNextLetter();
2673}
2674
2675void QTextDocument::indentSelection( int id )
2676{
2677 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2678 if ( it == selections.end() )
2679 return;
2680
2681 QTextDocumentSelection sel = *it;
2682 QTextParag *startParag = sel.startCursor.parag();
2683 QTextParag *endParag = sel.endCursor.parag();
2684 if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) {
2685 endParag = sel.startCursor.parag();
2686 startParag = sel.endCursor.parag();
2687 }
2688
2689 QTextParag *p = startParag;
2690 while ( p && p != endParag ) {
2691 p->indent();
2692 p = p->next();
2693 }
2694}
2695
2696void QTextDocument::addCommand( QTextCommand *cmd )
2697{
2698 commandHistory->addCommand( cmd );
2699}
2700
2701QTextCursor *QTextDocument::undo( QTextCursor *c )
2702{
2703 return commandHistory->undo( c );
2704}
2705
2706QTextCursor *QTextDocument::redo( QTextCursor *c )
2707{
2708 return commandHistory->redo( c );
2709}
2710
2711bool QTextDocument::find( const QString &expr, bool cs, bool wo, bool forward,
2712 int *parag, int *index, QTextCursor *cursor )
2713{
2714 QTextParag *p = forward ? fParag : lParag;
2715 if ( parag )
2716 p = paragAt( *parag );
2717 else if ( cursor )
2718 p = cursor->parag();
2719 bool first = TRUE;
2720
2721 while ( p ) {
2722 QString s = p->string()->toString();
2723 s.remove( s.length() - 1, 1 ); // get rid of trailing space
2724 int start = forward ? 0 : s.length() - 1;
2725 if ( first && index )
2726 start = *index;
2727 else if ( first )
2728 start = cursor->index();
2729 if ( !forward && first ) {
2730 start -= expr.length() + 1;
2731 if ( start < 0 ) {
2732 first = FALSE;
2733 p = p->prev();
2734 continue;
2735 }
2736 }
2737 first = FALSE;
2738
2739 for ( ;; ) {
2740 int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
2741 if ( res == -1 )
2742 break;
2743
2744 bool ok = TRUE;
2745 if ( wo ) {
2746 int end = res + expr.length();
2747 if ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
2748 ( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) )
2749 ok = TRUE;
2750 else
2751 ok = FALSE;
2752 }
2753 if ( ok ) {
2754 cursor->setParag( p );
2755 cursor->setIndex( res );
2756 setSelectionStart( Standard, cursor );
2757 cursor->setIndex( res + expr.length() );
2758 setSelectionEnd( Standard, cursor );
2759 if ( parag )
2760 *parag = p->paragId();
2761 if ( index )
2762 *index = res;
2763 return TRUE;
2764 }
2765 if ( forward ) {
2766 start = res + 1;
2767 } else {
2768 if ( res == 0 )
2769 break;
2770 start = res - 1;
2771 }
2772 }
2773 p = forward ? p->next() : p->prev();
2774 }
2775
2776 return FALSE;
2777}
2778
2779void QTextDocument::setTextFormat( Qt::TextFormat f )
2780{
2781 txtFormat = f;
2782 if ( txtFormat == Qt::RichText && fParag && fParag == lParag && fParag->length() <= 1 ) {
2783 QPtrVector<QStyleSheetItem> v = fParag->styleSheetItems();
2784 v.resize( v.size() + 1 );
2785 v.insert( v.size() - 1, styleSheet()->item( "p" ) );
2786 fParag->setStyleSheetItems( v );
2787 }
2788
2789}
2790
2791Qt::TextFormat QTextDocument::textFormat() const
2792{
2793 return txtFormat;
2794}
2795
2796bool QTextDocument::inSelection( int selId, const QPoint &pos ) const
2797{
2798 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( selId );
2799 if ( it == selections.end() )
2800 return FALSE;
2801
2802 QTextDocumentSelection sel = *it;
2803 QTextParag *startParag = sel.startCursor.parag();
2804 QTextParag *endParag = sel.endCursor.parag();
2805 if ( sel.startCursor.parag() == sel.endCursor.parag() &&
2806 sel.startCursor.parag()->selectionStart( selId ) == sel.endCursor.parag()->selectionEnd( selId ) )
2807 return FALSE;
2808 if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) {
2809 endParag = sel.startCursor.parag();
2810 startParag = sel.endCursor.parag();
2811 }
2812
2813 QTextParag *p = startParag;
2814 while ( p ) {
2815 if ( p->rect().contains( pos ) ) {
2816 bool inSel = FALSE;
2817 int selStart = p->selectionStart( selId );
2818 int selEnd = p->selectionEnd( selId );
2819 int y = 0;
2820 int h = 0;
2821 for ( int i = 0; i < p->length(); ++i ) {
2822 if ( i == selStart )
2823 inSel = TRUE;
2824 if ( i == selEnd )
2825 break;
2826 if ( p->at( i )->lineStart ) {
2827 y = (*p->lineStarts.find( i ))->y;
2828 h = (*p->lineStarts.find( i ))->h;
2829 }
2830 if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
2831 if ( inSel && pos.x() >= p->at( i )->x &&
2832 pos.x() <= p->at( i )->x + p->at( i )->format()->width( p->at( i )->c ) )
2833 return TRUE;
2834 }
2835 }
2836 }
2837 if ( pos.y() < p->rect().y() )
2838 break;
2839 if ( p == endParag )
2840 break;
2841 p = p->next();
2842 }
2843
2844 return FALSE;
2845}
2846
2847void QTextDocument::doLayout( QPainter *p, int w )
2848{
2849 minw = wused = 0;
2850 if ( !is_printer( p ) )
2851 p = 0;
2852 withoutDoubleBuffer = ( p != 0 );
2853 QPainter * oldPainter = QTextFormat::painter();
2854 QTextFormat::setPainter( p );
2855 flow_->setWidth( w );
2856 cw = w;
2857 vw = w;
2858 QTextParag *parag = fParag;
2859 while ( parag ) {
2860 parag->invalidate( 0 );
2861 if ( p )
2862 parag->adjustToPainter( p );
2863 parag->format();
2864 parag = parag->next();
2865 }
2866 QTextFormat::setPainter( oldPainter );
2867}
2868
2869QPixmap *QTextDocument::bufferPixmap( const QSize &s )
2870{
2871 if ( !buf_pixmap ) {
2872 int w = QABS( s.width() );
2873 int h = QABS( s.height() );
2874 buf_pixmap = new QPixmap( w, h );
2875 } else {
2876 if ( buf_pixmap->width() < s.width() ||
2877 buf_pixmap->height() < s.height() ) {
2878 buf_pixmap->resize( QMAX( s.width(), buf_pixmap->width() ),
2879 QMAX( s.height(), buf_pixmap->height() ) );
2880 }
2881 }
2882
2883 return buf_pixmap;
2884}
2885
2886void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper )
2887{
2888 if ( !firstParag() )
2889 return;
2890
2891 if ( paper ) {
2892 p->setBrushOrigin( 0, 0 );
2893
2894 p->fillRect( rect, *paper );
2895 }
2896
2897 if ( formatCollection()->defaultFormat()->color() != cg.text() ) {
2898 QDict<QTextFormat> formats = formatCollection()->dict();
2899 QDictIterator<QTextFormat> it( formats );
2900 while ( it.current() ) {
2901 if ( it.current() == formatCollection()->defaultFormat() ) {
2902 ++it;
2903 continue;
2904 }
2905 it.current()->setColor( cg.text() );
2906 ++it;
2907 }
2908 formatCollection()->defaultFormat()->setColor( cg.text() );
2909 }
2910
2911 QTextParag *parag = firstParag();
2912 while ( parag ) {
2913 if ( !parag->isValid() )
2914 parag->format();
2915 int y = parag->rect().y();
2916 QRect pr( parag->rect() );
2917 pr.setX( 0 );
2918 pr.setWidth( QWIDGETSIZE_MAX );
2919 if ( !rect.isNull() && !rect.intersects( pr ) ) {
2920 parag = parag->next();
2921 continue;
2922 }
2923 p->translate( 0, y );
2924 if ( rect.isValid() )
2925 parag->paint( *p, cg, 0, FALSE, rect.x(), rect.y(), rect.width(), rect.height() );
2926 else
2927 parag->paint( *p, cg, 0, FALSE );
2928 p->translate( 0, -y );
2929 parag = parag->next();
2930 if ( !flow()->isEmpty() )
2931 flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE );
2932 }
2933}
2934
2935void QTextDocument::drawParag( QPainter *p, QTextParag *parag, int cx, int cy, int cw, int ch,
2936 QPixmap *&doubleBuffer, const QColorGroup &cg,
2937 bool drawCursor, QTextCursor *cursor, bool resetChanged )
2938{
2939 QPainter *painter = 0;
2940 if ( resetChanged )
2941 parag->setChanged( FALSE );
2942 QRect ir( parag->rect() );
2943 bool useDoubleBuffer = !parag->document()->parent();
2944 if ( !useDoubleBuffer && parag->document()->nextDoubleBuffered )
2945 useDoubleBuffer = TRUE;
2946 if ( is_printer( p ) )
2947 useDoubleBuffer = FALSE;
2948
2949 if ( useDoubleBuffer ) {
2950 painter = new QPainter;
2951 if ( cx >= 0 && cy >= 0 )
2952 ir = ir.intersect( QRect( cx, cy, cw, ch ) );
2953 if ( !doubleBuffer ||
2954 ir.width() > doubleBuffer->width() ||
2955 ir.height() > doubleBuffer->height() ) {
2956 doubleBuffer = bufferPixmap( ir.size() );
2957 painter->begin( doubleBuffer );
2958 } else {
2959 painter->begin( doubleBuffer );
2960 }
2961 } else {
2962 painter = p;
2963 painter->translate( ir.x(), ir.y() );
2964 }
2965
2966 painter->setBrushOrigin( -ir.x(), -ir.y() );
2967
2968 if ( useDoubleBuffer || is_printer( painter ) ) {
2969 if ( !parag->backgroundColor() )
2970 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ),
2971 cg.brush( QColorGroup::Base ) );
2972 else
2973 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ),
2974 *parag->backgroundColor() );
2975 } else {
2976 if ( cursor && cursor->parag() == parag ) {
2977 if ( !parag->backgroundColor() )
2978 painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
2979 cg.brush( QColorGroup::Base ) );
2980 else
2981 painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
2982 *parag->backgroundColor() );
2983 }
2984 }
2985
2986 painter->translate( -( ir.x() - parag->rect().x() ),
2987 -( ir.y() - parag->rect().y() ) );
2988 parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch );
2989
2990 if ( useDoubleBuffer ) {
2991 delete painter;
2992 painter = 0;
2993 p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
2994 } else {
2995 painter->translate( -ir.x(), -ir.y() );
2996 }
2997
2998 if ( parag->rect().x() + parag->rect().width() < parag->document()->x() + parag->document()->width() ) {
2999 p->fillRect( parag->rect().x() + parag->rect().width(), parag->rect().y(),
3000 ( parag->document()->x() + parag->document()->width() ) -
3001 ( parag->rect().x() + parag->rect().width() ),
3002 parag->rect().height(), cg.brush( QColorGroup::Base ) );
3003 }
3004
3005 parag->document()->nextDoubleBuffered = FALSE;
3006}
3007
3008QTextParag *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
3009 bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged )
3010{
3011 if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) {
3012 withoutDoubleBuffer = TRUE;
3013 QRect r;
3014 draw( p, r, cg );
3015 return 0;
3016 }
3017 withoutDoubleBuffer = FALSE;
3018
3019 if ( !firstParag() )
3020 return 0;
3021
3022 if ( drawCursor && cursor )
3023 tmpCursor = cursor;
3024 if ( cx < 0 && cy < 0 ) {
3025 cx = 0;
3026 cy = 0;
3027 cw = width();
3028 ch = height();
3029 }
3030
3031 QTextParag *lastFormatted = 0;
3032 QTextParag *parag = firstParag();
3033
3034 QPixmap *doubleBuffer = 0;
3035 QPainter painter;
3036
3037 while ( parag ) {
3038 lastFormatted = parag;
3039 if ( !parag->isValid() )
3040 parag->format();
3041
3042 if ( !parag->rect().intersects( QRect( cx, cy, cw, ch ) ) ) {
3043 QRect pr( parag->rect() );
3044 pr.setWidth( parag->document()->width() );
3045 if ( pr.intersects( QRect( cx, cy, cw, ch ) ) )
3046 p->fillRect( pr.intersect( QRect( cx, cy, cw, ch ) ), cg.brush( QColorGroup::Base ) );
3047 if ( parag->rect().y() > cy + ch ) {
3048 tmpCursor = 0;
3049 goto floating;
3050 }
3051 parag = parag->next();
3052 continue;
3053 }
3054
3055 if ( !parag->hasChanged() && onlyChanged ) {
3056 parag = parag->next();
3057 continue;
3058 }
3059
3060 drawParag( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged );
3061 parag = parag->next();
3062 }
3063
3064 parag = lastParag();
3065
3066 floating:
3067 if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) {
3068 if ( !parag->document()->parent() ) { // !useDoubleBuffer
3069 p->fillRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
3070 parag->document()->height() - ( parag->rect().y() + parag->rect().height() ),
3071 cg.brush( QColorGroup::Base ) );
3072 }
3073 if ( !flow()->isEmpty() ) {
3074 QRect cr( cx, cy, cw, ch );
3075 // cr = cr.intersect( QRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
3076 // parag->document()->height() - ( parag->rect().y() + parag->rect().height() ) ) );
3077 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
3078 }
3079 }
3080
3081 if ( buf_pixmap && buf_pixmap->height() > 300 ) {
3082 delete buf_pixmap;
3083 buf_pixmap = 0;
3084 }
3085
3086 tmpCursor = 0;
3087 return lastFormatted;
3088}
3089
3090void QTextDocument::setDefaultFont( const QFont &f )
3091{
3092 int s = f.pointSize();
3093 bool usePixels = FALSE;
3094 if ( s == -1 ) {
3095 s = f.pixelSize();
3096 usePixels = TRUE;
3097 }
3098 updateFontSizes( s, usePixels );
3099}
3100
3101void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParag *p )
3102{
3103 if ( i && i->placement() != QTextCustomItem::PlaceInline ) {
3104 flow_->registerFloatingItem( i );
3105 p->registerFloatingItem( i );
3106 i->setParagraph( p );
3107 }
3108 p->mightHaveCustomItems = mightHaveCustomItems = TRUE;
3109}
3110
3111void QTextDocument::unregisterCustomItem( QTextCustomItem *i, QTextParag *p )
3112{
3113 flow_->unregisterFloatingItem( i );
3114 p->unregisterFloatingItem( i );
3115 i->setParagraph( 0 );
3116}
3117
3118bool QTextDocument::hasFocusParagraph() const
3119{
3120 return !!focusIndicator.parag;
3121}
3122
3123QString QTextDocument::focusHref() const
3124{
3125 return focusIndicator.href;
3126}
3127
3128bool QTextDocument::focusNextPrevChild( bool next )
3129{
3130 if ( !focusIndicator.parag ) {
3131 if ( next ) {
3132 focusIndicator.parag = fParag;
3133 focusIndicator.start = 0;
3134 focusIndicator.len = 0;
3135 } else {
3136 focusIndicator.parag = lParag;
3137 focusIndicator.start = lParag->length();
3138 focusIndicator.len = 0;
3139 }
3140 } else {
3141 focusIndicator.parag->setChanged( TRUE );
3142 }
3143 focusIndicator.href = QString::null;
3144
3145 if ( next ) {
3146 QTextParag *p = focusIndicator.parag;
3147 int index = focusIndicator.start + focusIndicator.len;
3148 while ( p ) {
3149 for ( int i = index; i < p->length(); ++i ) {
3150 if ( p->at( i )->isAnchor() ) {
3151 p->setChanged( TRUE );
3152 focusIndicator.parag = p;
3153 focusIndicator.start = i;
3154 focusIndicator.len = 0;
3155 focusIndicator.href = p->at( i )->anchorHref();
3156 while ( i < p->length() ) {
3157 if ( !p->at( i )->isAnchor() )
3158 return TRUE;
3159 focusIndicator.len++;
3160 i++;
3161 }
3162 } else if ( p->at( i )->isCustom() ) {
3163 if ( p->at( i )->customItem()->isNested() ) {
3164 QTextTable *t = (QTextTable*)p->at( i )->customItem();
3165 QPtrList<QTextTableCell> cells = t->tableCells();
3166 // first try to continue
3167 QTextTableCell *c;
3168 bool resetCells = TRUE;
3169 for ( c = cells.first(); c; c = cells.next() ) {
3170 if ( c->richText()->hasFocusParagraph() ) {
3171 if ( c->richText()->focusNextPrevChild( next ) ) {
3172 p->setChanged( TRUE );
3173 focusIndicator.parag = p;
3174 focusIndicator.start = i;
3175 focusIndicator.len = 0;
3176 focusIndicator.href = c->richText()->focusHref();
3177 return TRUE;
3178 } else {
3179 resetCells = FALSE;
3180 c = cells.next();
3181 break;
3182 }
3183 }
3184 }
3185 // now really try
3186 if ( resetCells )
3187 c = cells.first();
3188 for ( ; c; c = cells.next() ) {
3189 if ( c->richText()->focusNextPrevChild( next ) ) {
3190 p->setChanged( TRUE );
3191 focusIndicator.parag = p;
3192 focusIndicator.start = i;
3193 focusIndicator.len = 0;
3194 focusIndicator.href = c->richText()->focusHref();
3195 return TRUE;
3196 }
3197 }
3198 }
3199 }
3200 }
3201 index = 0;
3202 p = p->next();
3203 }
3204 } else {
3205 QTextParag *p = focusIndicator.parag;
3206 int index = focusIndicator.start - 1;
3207 if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 )
3208 index++;
3209 while ( p ) {
3210 for ( int i = index; i >= 0; --i ) {
3211 if ( p->at( i )->isAnchor() ) {
3212 p->setChanged( TRUE );
3213 focusIndicator.parag = p;
3214 focusIndicator.start = i;
3215 focusIndicator.len = 0;
3216 focusIndicator.href = p->at( i )->anchorHref();
3217 while ( i >= -1 ) {
3218 if ( i < 0 || !p->at( i )->isAnchor() ) {
3219 focusIndicator.start++;
3220 return TRUE;
3221 }
3222 if ( i < 0 )
3223 break;
3224 focusIndicator.len++;
3225 focusIndicator.start--;
3226 i--;
3227 }
3228 } else if ( p->at( i )->isCustom() ) {
3229 if ( p->at( i )->customItem()->isNested() ) {
3230 QTextTable *t = (QTextTable*)p->at( i )->customItem();
3231 QPtrList<QTextTableCell> cells = t->tableCells();
3232 // first try to continue
3233 QTextTableCell *c;
3234 bool resetCells = TRUE;
3235 for ( c = cells.last(); c; c = cells.prev() ) {
3236 if ( c->richText()->hasFocusParagraph() ) {
3237 if ( c->richText()->focusNextPrevChild( next ) ) {
3238 p->setChanged( TRUE );
3239 focusIndicator.parag = p;
3240 focusIndicator.start = i;
3241 focusIndicator.len = 0;
3242 focusIndicator.href = c->richText()->focusHref();
3243 return TRUE;
3244 } else {
3245 resetCells = FALSE;
3246 c = cells.prev();
3247 break;
3248 }
3249 }
3250 if ( cells.at() == 0 )
3251 break;
3252 }
3253 // now really try
3254 if ( resetCells )
3255 c = cells.last();
3256 for ( ; c; c = cells.prev() ) {
3257 if ( c->richText()->focusNextPrevChild( next ) ) {
3258 p->setChanged( TRUE );
3259 focusIndicator.parag = p;
3260 focusIndicator.start = i;
3261 focusIndicator.len = 0;
3262 focusIndicator.href = c->richText()->focusHref();
3263 return TRUE;
3264 }
3265 if ( cells.at() == 0 )
3266 break;
3267 }
3268 }
3269 }
3270 }
3271 p = p->prev();
3272 if ( p )
3273 index = p->length() - 1;
3274 }
3275 }
3276
3277 focusIndicator.parag = 0;
3278
3279 return FALSE;
3280}
3281
3282int QTextDocument::length() const
3283{
3284 int l = 0;
3285 QTextParag *p = fParag;
3286 while ( p ) {
3287 l += p->length() - 1; // don't count trailing space
3288 p = p->next();
3289 }
3290 return l;
3291}
3292
3293// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3294
3295int QTextFormat::width( const QChar &c ) const
3296{
3297 if ( c.unicode() == 0xad ) // soft hyphen
3298 return 0;
3299 if ( !pntr || !pntr->isActive() ) {
3300 if ( c == '\t' )
3301 return fm.width( 'x' ) * 8;
3302 if ( ha == AlignNormal ) {
3303 int w;
3304 if ( c.row() )
3305 w = fm.width( c );
3306 else
3307 w = widths[ c.unicode() ];
3308 if ( w == 0 && !c.row() ) {
3309 w = fm.width( c );
3310 ( (QTextFormat*)this )->widths[ c.unicode() ] = w;
3311 }
3312 return w;
3313 } else {
3314 QFont f( fn );
3315 if ( usePixelSizes )
3316 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
3317 else
3318 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
3319 QFontMetrics fm_( f );
3320 return fm_.width( c );
3321 }
3322 }
3323
3324 QFont f( fn );
3325 if ( ha != AlignNormal ) {
3326 if ( usePixelSizes )
3327 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
3328 else
3329 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
3330 }
3331 pntr->setFont( f );
3332
3333 return pntr->fontMetrics().width( c );
3334}
3335
3336int QTextFormat::width( const QString &str, int pos ) const
3337{
3338 int w = 0;
3339 if ( str[ pos ].unicode() == 0xad )
3340 return w;
3341 if ( !pntr || !pntr->isActive() ) {
3342 if ( ha == AlignNormal ) {
3343 w = fm.width( str[ pos ] );
3344 } else {
3345 QFont f( fn );
3346 if ( usePixelSizes )
3347 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
3348 else
3349 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
3350 QFontMetrics fm_( f );
3351 w = fm_.width( str[ pos ] );
3352 }
3353 } else {
3354 QFont f( fn );
3355 if ( ha != AlignNormal ) {
3356 if ( usePixelSizes )
3357 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
3358 else
3359 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
3360 }
3361 pntr->setFont( f );
3362 w = pntr->fontMetrics().width( str[ pos ] );
3363 }
3364 return w;
3365}
3366
3367// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3368
3369QTextString::QTextString()
3370{
3371 bidiDirty = FALSE;
3372 bidi = FALSE;
3373 rightToLeft = FALSE;
3374 dir = QChar::DirON;
3375}
3376
3377QTextString::QTextString( const QTextString &s )
3378{
3379 bidiDirty = s.bidiDirty;
3380 bidi = s.bidi;
3381 rightToLeft = s.rightToLeft;
3382 dir = s.dir;
3383 data = s.subString();
3384}
3385
3386void QTextString::insert( int index, const QString &s, QTextFormat *f )
3387{
3388 int os = data.size();
3389 data.resize( data.size() + s.length() );
3390 if ( index < os ) {
3391 memmove( data.data() + index + s.length(), data.data() + index,
3392 sizeof( QTextStringChar ) * ( os - index ) );
3393 }
3394 for ( int i = 0; i < (int)s.length(); ++i ) {
3395 data[ (int)index + i ].x = 0;
3396 data[ (int)index + i ].lineStart = 0;
3397 data[ (int)index + i ].d.format = 0;
3398 data[ (int)index + i ].type = QTextStringChar::Regular;
3399 data[ (int)index + i ].rightToLeft = 0;
3400 data[ (int)index + i ].startOfRun = 0;
3401 data[ (int)index + i ].c = s[ i ];
3402 data[ (int)index + i ].setFormat( f );
3403 }
3404 bidiDirty = TRUE;
3405}
3406
3407QTextString::~QTextString()
3408{
3409 clear();
3410}
3411
3412void QTextString::insert( int index, QTextStringChar *c )
3413{
3414 int os = data.size();
3415 data.resize( data.size() + 1 );
3416 if ( index < os ) {
3417 memmove( data.data() + index + 1, data.data() + index,
3418 sizeof( QTextStringChar ) * ( os - index ) );
3419 }
3420 data[ (int)index ].c = c->c;
3421 data[ (int)index ].x = 0;
3422 data[ (int)index ].lineStart = 0;
3423 data[ (int)index ].rightToLeft = 0;
3424 data[ (int)index ].d.format = 0;
3425 data[ (int)index ].type = QTextStringChar::Regular;
3426 data[ (int)index ].setFormat( c->format() );
3427 bidiDirty = TRUE;
3428}
3429
3430void QTextString::truncate( int index )
3431{
3432 index = QMAX( index, 0 );
3433 index = QMIN( index, (int)data.size() - 1 );
3434 if ( index < (int)data.size() ) {
3435 for ( int i = index + 1; i < (int)data.size(); ++i ) {
3436 if ( !(data[ i ].type == QTextStringChar::Regular) ) {
3437 delete data[ i ].customItem();
3438 if ( data[ i ].d.custom->format )
3439 data[ i ].d.custom->format->removeRef();
3440 delete data[ i ].d.custom;
3441 data[ i ].d.custom = 0;
3442 } else if ( data[ i ].format() ) {
3443 data[ i ].format()->removeRef();
3444 }
3445 }
3446 }
3447 data.truncate( index );
3448 bidiDirty = TRUE;
3449}
3450
3451void QTextString::remove( int index, int len )
3452{
3453 for ( int i = index; i < (int)data.size() && i - index < len; ++i ) {
3454 if ( !(data[ i ].type == QTextStringChar::Regular) ) {
3455 delete data[ i ].customItem();
3456 if ( data[ i ].d.custom->format )
3457 data[ i ].d.custom->format->removeRef();
3458 delete data[ i ].d.custom;
3459 data[ i ].d.custom = 0;
3460 } else if ( data[ i ].format() ) {
3461 data[ i ].format()->removeRef();
3462 }
3463 }
3464 memmove( data.data() + index, data.data() + index + len,
3465 sizeof( QTextStringChar ) * ( data.size() - index - len ) );
3466 data.resize( data.size() - len );
3467 bidiDirty = TRUE;
3468}
3469
3470void QTextString::clear()
3471{
3472 for ( int i = 0; i < (int)data.count(); ++i ) {
3473 if ( !(data[ i ].type == QTextStringChar::Regular) ) {
3474 delete data[ i ].customItem();
3475 if ( data[ i ].d.custom->format )
3476 data[ i ].d.custom->format->removeRef();
3477 delete data[ i ].d.custom;
3478 data[ i ].d.custom = 0;
3479 } else if ( data[ i ].format() ) {
3480 data[ i ].format()->removeRef();
3481 }
3482 }
3483 data.resize( 0 );
3484}
3485
3486void QTextString::setFormat( int index, QTextFormat *f, bool useCollection )
3487{
3488 if ( useCollection && data[ index ].format() )
3489 data[ index ].format()->removeRef();
3490 data[ index ].setFormat( f );
3491}
3492
3493void QTextString::checkBidi() const
3494{
3495 bool rtlKnown = FALSE;
3496 if ( dir == QChar::DirR ) {
3497 ((QTextString *)this)->bidi = TRUE;
3498 ((QTextString *)this)->rightToLeft = TRUE;
3499 rtlKnown = TRUE;
3500 return;
3501 } else if ( dir == QChar::DirL ) {
3502 ((QTextString *)this)->rightToLeft = FALSE;
3503 rtlKnown = TRUE;
3504 } else {
3505 ((QTextString *)this)->rightToLeft = FALSE;
3506 }
3507
3508 int len = data.size();
3509 const QTextStringChar *c = data.data();
3510 ((QTextString *)this)->bidi = FALSE;
3511 while( len ) {
3512 if ( !rtlKnown ) {
3513 switch( c->c.direction() )
3514 {
3515 case QChar::DirL:
3516 case QChar::DirLRO:
3517 case QChar::DirLRE:
3518 ((QTextString *)this)->rightToLeft = FALSE;
3519 rtlKnown = TRUE;
3520 break;
3521 case QChar::DirR:
3522 case QChar::DirAL:
3523 case QChar::DirRLO:
3524 case QChar::DirRLE:
3525 ((QTextString *)this)->rightToLeft = TRUE;
3526 rtlKnown = TRUE;
3527 break;
3528 default:
3529 break;
3530 }
3531 }
3532 uchar row = c->c.row();
3533 if( (row > 0x04 && row < 0x09) || (row > 0xfa && row < 0xff) ) {
3534 ((QTextString *)this)->bidi = TRUE;
3535 if ( rtlKnown )
3536 return;
3537 }
3538 len--;
3539 ++c;
3540 }
3541}
3542
3543void QTextDocument::setStyleSheet( QStyleSheet *s )
3544{
3545 if ( !s )
3546 return;
3547 sheet_ = s;
3548 fCollection->setStyleSheet( s );
3549 updateStyles();
3550}
3551
3552void QTextDocument::updateStyles()
3553{
3554 invalidate();
3555 if ( par )
3556 underlLinks = par->underlLinks;
3557 fCollection->updateStyles();
3558 for ( QTextDocument *d = childList.first(); d; d = childList.next() )
3559 d->updateStyles();
3560}
3561
3562void QTextDocument::updateFontSizes( int base, bool usePixels )
3563{
3564 for ( QTextDocument *d = childList.first(); d; d = childList.next() )
3565 d->updateFontSizes( base, usePixels );
3566 invalidate();
3567 fCollection->updateFontSizes( base, usePixels );
3568}
3569
3570void QTextDocument::updateFontAttributes( const QFont &f, const QFont &old )
3571{
3572 for ( QTextDocument *d = childList.first(); d; d = childList.next() )
3573 d->updateFontAttributes( f, old );
3574 invalidate();
3575 fCollection->updateFontAttributes( f, old );
3576}
3577
3578void QTextStringChar::setFormat( QTextFormat *f )
3579{
3580 if ( type == Regular ) {
3581 d.format = f;
3582 } else {
3583 if ( !d.custom ) {
3584 d.custom = new CustomData;
3585 d.custom->custom = 0;
3586 }
3587 d.custom->format = f;
3588 }
3589}
3590
3591void QTextStringChar::setCustomItem( QTextCustomItem *i )
3592{
3593 if ( type == Regular ) {
3594 QTextFormat *f = format();
3595 d.custom = new CustomData;
3596 d.custom->format = f;
3597 } else {
3598 delete d.custom->custom;
3599 }
3600 d.custom->custom = i;
3601 type = (type == Anchor ? CustomAnchor : Custom);
3602}
3603
3604void QTextStringChar::loseCustomItem()
3605{
3606 if ( type == Custom ) {
3607 QTextFormat *f = d.custom->format;
3608 d.custom->custom = 0;
3609 delete d.custom;
3610 type = Regular;
3611 d.format = f;
3612 } else if ( type == CustomAnchor ) {
3613 d.custom->custom = 0;
3614 type = Anchor;
3615 }
3616}
3617
3618QString QTextStringChar::anchorName() const
3619{
3620 if ( type == Regular )
3621 return QString::null;
3622 else
3623 return d.custom->anchorName;
3624}
3625
3626QString QTextStringChar::anchorHref() const
3627{
3628 if ( type == Regular )
3629 return QString::null;
3630 else
3631 return d.custom->anchorHref;
3632}
3633
3634void QTextStringChar::setAnchor( const QString& name, const QString& href )
3635{
3636 if ( type == Regular ) {
3637 QTextFormat *f = format();
3638 d.custom = new CustomData;
3639 d.custom->custom = 0;
3640 d.custom->format = f;
3641 type = Anchor;
3642 } else if ( type == Custom ) {
3643 type = CustomAnchor;
3644 }
3645 d.custom->anchorName = name;
3646 d.custom->anchorHref = href;
3647}
3648
3649
3650int QTextString::width( int idx ) const
3651{
3652 int w = 0;
3653 QTextStringChar *c = &at( idx );
3654 if ( c->c.unicode() == 0xad )
3655 return 0;
3656 if( c->isCustom() ) {
3657 if( c->customItem()->placement() == QTextCustomItem::PlaceInline )
3658 w = c->customItem()->width;
3659 } else {
3660 int r = c->c.row();
3661 if( r < 0x06 || r > 0x1f )
3662 w = c->format()->width( c->c );
3663 else {
3664 // complex text. We need some hacks to get the right metric here
3665 QString str;
3666 int pos = 0;
3667 if( idx > 4 )
3668 pos = idx - 4;
3669 int off = idx - pos;
3670 int end = QMIN( length(), idx + 4 );
3671 while ( pos < end ) {
3672 str += at(pos).c;
3673 pos++;
3674 }
3675 w = c->format()->width( str, off );
3676 }
3677 }
3678 return w;
3679}
3680
3681QMemArray<QTextStringChar> QTextString::subString( int start, int len ) const
3682{
3683 if ( len == 0xFFFFFF )
3684 len = data.size();
3685 QMemArray<QTextStringChar> a;
3686 a.resize( len );
3687 for ( int i = 0; i < len; ++i ) {
3688 QTextStringChar *c = &data[ i + start ];
3689 a[ i ].c = c->c;
3690 a[ i ].x = 0;
3691 a[ i ].lineStart = 0;
3692 a[ i ].rightToLeft = 0;
3693 a[ i ].d.format = 0;
3694 a[ i ].type = QTextStringChar::Regular;
3695 a[ i ].setFormat( c->format() );
3696 if ( c->format() )
3697 c->format()->addRef();
3698 }
3699 return a;
3700}
3701
3702QTextStringChar *QTextStringChar::clone() const
3703{
3704 QTextStringChar *chr = new QTextStringChar;
3705 chr->c = c;
3706 chr->x = 0;
3707 chr->lineStart = 0;
3708 chr->rightToLeft = 0;
3709 chr->d.format = 0;
3710 chr->type = QTextStringChar::Regular;
3711 chr->setFormat( format() );
3712 if ( chr->format() )
3713 chr->format()->addRef();
3714 return chr;
3715}
3716
3717// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3718
3719QTextParag::QTextParag( QTextDocument *d, QTextParag *pr, QTextParag *nx, bool updateIds )
3720 : invalid( 0 ), p( pr ), n( nx ), docOrPseudo( d ), align( 0 ),mSelections( 0 ),
3721 mStyleSheetItemsVec( 0 ), mFloatingItems( 0 ), listS( QStyleSheetItem::ListDisc ),
3722 numSubParag( -1 ), tm( -1 ), bm( -1 ), lm( -1 ), rm( -1 ), flm( -1 ),
3723 tArray(0), tabStopWidth(0), eData( 0 )
3724{
3725 listS = QStyleSheetItem::ListDisc;
3726 if ( ! (hasdoc = docOrPseudo != 0 ) )
3727 docOrPseudo = new QTextParagPseudoDocument;
3728 bgcol = 0;
3729 breakable = TRUE;
3730 isBr = FALSE;
3731 movedDown = FALSE;
3732 mightHaveCustomItems = FALSE;
3733 visible = TRUE;
3734 list_val = -1;
3735 newLinesAllowed = FALSE;
3736 lastInFrame = FALSE;
3737 defFormat = formatCollection()->defaultFormat();
3738 if ( !hasdoc ) {
3739 tabStopWidth = defFormat->width( 'x' ) * 8;
3740 pseudoDocument()->commandHistory = new QTextCommandHistory( 100 );
3741 }
3742#if defined(PARSER_DEBUG)
3743 qDebug( debug_indent + "new QTextParag" );
3744#endif
3745 fullWidth = TRUE;
3746
3747 if ( p )
3748 p->n = this;
3749 if ( n )
3750 n->p = this;
3751
3752
3753 if ( !p && hasdoc )
3754 document()->setFirstParag( this );
3755 if ( !n && hasdoc )
3756 document()->setLastParag( this );
3757
3758 changed = FALSE;
3759 firstFormat = TRUE;
3760 state = -1;
3761 needPreProcess = FALSE;
3762
3763 if ( p )
3764 id = p->id + 1;
3765 else
3766 id = 0;
3767 if ( n && updateIds ) {
3768 QTextParag *s = n;
3769 while ( s ) {
3770 s->id = s->p->id + 1;
3771 s->numSubParag = -1;
3772 s->lm = s->rm = s->tm = s->bm = -1, s->flm = -1;
3773 s = s->n;
3774 }
3775 }
3776 firstPProcess = TRUE;
3777
3778 str = new QTextString();
3779 str->insert( 0, " ", formatCollection()->defaultFormat() );
3780}
3781
3782QTextParag::~QTextParag()
3783{
3784 delete str;
3785 if ( hasdoc ) {
3786 register QTextDocument *doc = document();
3787 if ( this == doc->minwParag ) {
3788 doc->minwParag = 0;
3789 doc->minw = 0;
3790 }
3791 if ( this == doc->curParag )
3792 doc->curParag = 0;
3793 } else {
3794 delete pseudoDocument();
3795 }
3796 if ( tArray )
3797 delete [] tArray;
3798 delete eData;
3799 QMap<int, QTextParagLineStart*>::Iterator it = lineStarts.begin();
3800 for ( ; it != lineStarts.end(); ++it )
3801 delete *it;
3802 if ( mSelections )
3803 delete mSelections;
3804 if ( mFloatingItems )
3805 delete mFloatingItems;
3806 if ( mStyleSheetItemsVec )
3807 delete mStyleSheetItemsVec;
3808 if ( p )
3809 p->setNext( n );
3810 if ( n )
3811 n->setPrev( p );
3812}
3813
3814void QTextParag::setNext( QTextParag *s )
3815{
3816 n = s;
3817 if ( !n && hasdoc )
3818 document()->setLastParag( this );
3819}
3820
3821void QTextParag::setPrev( QTextParag *s )
3822{
3823 p = s;
3824 if ( !p && hasdoc )
3825 document()->setFirstParag( this );
3826}
3827
3828void QTextParag::invalidate( int chr )
3829{
3830 if ( invalid < 0 )
3831 invalid = chr;
3832 else
3833 invalid = QMIN( invalid, chr );
3834 if ( mFloatingItems ) {
3835 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
3836 i->ypos = -1;
3837 }
3838 lm = rm = bm = tm = flm = -1;
3839}
3840
3841void QTextParag::insert( int index, const QString &s )
3842{
3843 if ( hasdoc && !document()->useFormatCollection() && document()->preProcessor() )
3844 str->insert( index, s,
3845 document()->preProcessor()->format( QTextPreProcessor::Standard ) );
3846 else
3847 str->insert( index, s, formatCollection()->defaultFormat() );
3848 invalidate( index );
3849 needPreProcess = TRUE;
3850}
3851
3852void QTextParag::truncate( int index )
3853{
3854 str->truncate( index );
3855 insert( length(), " " );
3856 needPreProcess = TRUE;
3857}
3858
3859void QTextParag::remove( int index, int len )
3860{
3861 if ( index + len - str->length() > 0 )
3862 return;
3863 for ( int i = index; i < index + len; ++i ) {
3864 QTextStringChar *c = at( i );
3865 if ( hasdoc && c->isCustom() ) {
3866 document()->unregisterCustomItem( c->customItem(), this );
3867 }
3868 }
3869 str->remove( index, len );
3870 invalidate( 0 );
3871 needPreProcess = TRUE;
3872}
3873
3874void QTextParag::join( QTextParag *s )
3875{
3876 int oh = r.height() + s->r.height();
3877 n = s->n;
3878 if ( n )
3879 n->p = this;
3880 else if ( hasdoc )
3881 document()->setLastParag( this );
3882
3883 int start = str->length();
3884 if ( length() > 0 && at( length() - 1 )->c == ' ' ) {
3885 remove( length() - 1, 1 );
3886 --start;
3887 }
3888 append( s->str->toString(), TRUE );
3889
3890 for ( int i = 0; i < s->length(); ++i ) {
3891 if ( !hasdoc || document()->useFormatCollection() ) {
3892 s->str->at( i ).format()->addRef();
3893 str->setFormat( i + start, s->str->at( i ).format(), TRUE );
3894 }
3895 if ( s->str->at( i ).isCustom() ) {
3896 QTextCustomItem * item = s->str->at( i ).customItem();
3897 str->at( i + start ).setCustomItem( item );
3898 s->str->at( i ).loseCustomItem();
3899 }
3900 if ( s->str->at( i ).isAnchor() ) {
3901 str->at( i + start ).setAnchor( s->str->at( i ).anchorName(),
3902 s->str->at( i ).anchorHref() );
3903 }
3904 }
3905
3906 if ( !extraData() && s->extraData() ) {
3907 setExtraData( s->extraData() );
3908 s->setExtraData( 0 );
3909 } else if ( extraData() && s->extraData() ) {
3910 extraData()->join( s->extraData() );
3911 }
3912 delete s;
3913 invalidate( 0 );
3914 r.setHeight( oh );
3915 needPreProcess = TRUE;
3916 if ( n ) {
3917 QTextParag *s = n;
3918 while ( s ) {
3919 s->id = s->p->id + 1;
3920 s->state = -1;
3921 s->needPreProcess = TRUE;
3922 s->changed = TRUE;
3923 s = s->n;
3924 }
3925 }
3926 format();
3927 state = -1;
3928}
3929
3930void QTextParag::move( int &dy )
3931{
3932 if ( dy == 0 )
3933 return;
3934 changed = TRUE;
3935 r.moveBy( 0, dy );
3936 if ( mFloatingItems ) {
3937 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
3938 i->ypos += dy;
3939 }
3940 if ( p )
3941 p->lastInFrame = TRUE;
3942
3943 // do page breaks if required
3944 if ( hasdoc && document()->isPageBreakEnabled() ) {
3945 int shift;
3946 if ( ( shift = document()->formatter()->formatVertically( document(), this ) ) ) {
3947 if ( p )
3948 p->setChanged( TRUE );
3949 dy += shift;
3950 }
3951 }
3952}
3953
3954void QTextParag::format( int start, bool doMove )
3955{
3956 if ( !str || str->length() == 0 || !formatter() )
3957 return;
3958
3959 if ( hasdoc &&
3960 document()->preProcessor() &&
3961 ( needPreProcess || state == -1 ) )
3962 document()->preProcessor()->process( document(), this, invalid <= 0 ? 0 : invalid );
3963 needPreProcess = FALSE;
3964
3965 if ( invalid == -1 )
3966 return;
3967
3968 r.moveTopLeft( QPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) );
3969 r.setWidth( documentWidth() );
3970 if ( p )
3971 p->lastInFrame = FALSE;
3972
3973 movedDown = FALSE;
3974 bool formattedAgain = FALSE;
3975
3976 formatAgain:
3977
3978 if ( hasdoc && mFloatingItems ) {
3979 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
3980 i->ypos = r.y();
3981 if ( i->placement() == QTextCustomItem::PlaceRight ) {
3982 i->xpos = r.x() + r.width() - i->width;
3983 }
3984 }
3985 }
3986 QMap<int, QTextParagLineStart*> oldLineStarts = lineStarts;
3987 lineStarts.clear();
3988 int y = formatter()->format( document(), this, start, oldLineStarts );
3989
3990
3991 r.setWidth( QMAX( r.width(), formatter()->minimumWidth() ) );
3992
3993
3994 QMap<int, QTextParagLineStart*>::Iterator it = oldLineStarts.begin();
3995
3996 for ( ; it != oldLineStarts.end(); ++it )
3997 delete *it;
3998
3999 QTextStringChar *c = 0;
4000 // do not do this on mac, as the paragraph
4001 // with has to be the full document width on mac as the selections
4002 // always extend completely to the right. This is a bit unefficient,
4003 // as this results in a bigger double buffer than needed but ok for
4004 // now.
4005 if ( lineStarts.count() == 1 ) { //&& ( !doc || document()->flow()->isEmpty() ) ) {
4006 if ( !string()->isBidi() ) {
4007 c = &str->at( str->length() - 1 );
4008 r.setWidth( c->x + str->width( str->length() - 1 ) );
4009 } else {
4010 r.setWidth( lineStarts[0]->w );
4011 }
4012 }
4013
4014 if ( newLinesAllowed ) {
4015 it = lineStarts.begin();
4016 int usedw = 0;
4017 for ( ; it != lineStarts.end(); ++it )
4018 usedw = QMAX( usedw, (*it)->w );
4019 if ( r.width() <= 0 ) {
4020 // if the user specifies an invalid rect, this means that the
4021 // bounding box should grow to the width that the text actually
4022 // needs
4023 r.setWidth( usedw );
4024 } else {
4025 r.setWidth( QMIN( usedw, r.width() ) );
4026 }
4027 }
4028
4029 if ( y != r.height() )
4030 r.setHeight( y );
4031
4032 if ( !visible ) {
4033 r.setHeight( 0 );
4034 } else {
4035 int minw = formatter()->minimumWidth();
4036 int wused = formatter()->widthUsed();
4037 wused = QMAX( minw, wused );
4038 if ( hasdoc ) {
4039 document()->setMinimumWidth( minw, wused, this );
4040 } else {
4041 pseudoDocument()->minw = QMAX( pseudoDocument()->minw, minw );
4042 pseudoDocument()->wused = QMAX( pseudoDocument()->wused, wused );
4043 }
4044 }
4045
4046 // do page breaks if required
4047 if ( hasdoc && document()->isPageBreakEnabled() ) {
4048 int shift = document()->formatter()->formatVertically( document(), this );
4049 if ( shift && !formattedAgain ) {
4050 formattedAgain = TRUE;
4051 goto formatAgain;
4052 }
4053 }
4054
4055 if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) {
4056 int dy = ( r.y() + r.height() ) - n->r.y();
4057 QTextParag *s = n;
4058 bool makeInvalid = p && p->lastInFrame;
4059 while ( s && dy ) {
4060 if ( !s->isFullWidth() )
4061 makeInvalid = TRUE;
4062 if ( makeInvalid )
4063 s->invalidate( 0 );
4064 s->move( dy );
4065 if ( s->lastInFrame )
4066 makeInvalid = TRUE;
4067 s = s->n;
4068 }
4069 }
4070
4071 firstFormat = FALSE;
4072 changed = TRUE;
4073 invalid = -1;
4074 //##### string()->setTextChanged( FALSE );
4075}
4076
4077int QTextParag::lineHeightOfChar( int i, int *bl, int *y ) const
4078{
4079 if ( !isValid() )
4080 ( (QTextParag*)this )->format();
4081
4082 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.end();
4083 --it;
4084 for ( ;; ) {
4085 if ( i >= it.key() ) {
4086 if ( bl )
4087 *bl = ( *it )->baseLine;
4088 if ( y )
4089 *y = ( *it )->y;
4090 return ( *it )->h;
4091 }
4092 if ( it == lineStarts.begin() )
4093 break;
4094 --it;
4095 }
4096
4097 qWarning( "QTextParag::lineHeightOfChar: couldn't find lh for %d", i );
4098 return 15;
4099}
4100
4101QTextStringChar *QTextParag::lineStartOfChar( int i, int *index, int *line ) const
4102{
4103 if ( !isValid() )
4104 ( (QTextParag*)this )->format();
4105
4106 int l = (int)lineStarts.count() - 1;
4107 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.end();
4108 --it;
4109 for ( ;; ) {
4110 if ( i >= it.key() ) {
4111 if ( index )
4112 *index = it.key();
4113 if ( line )
4114 *line = l;
4115 return &str->at( it.key() );
4116 }
4117 if ( it == lineStarts.begin() )
4118 break;
4119 --it;
4120 --l;
4121 }
4122
4123 qWarning( "QTextParag::lineStartOfChar: couldn't find %d", i );
4124 return 0;
4125}
4126
4127int QTextParag::lines() const
4128{
4129 if ( !isValid() )
4130 ( (QTextParag*)this )->format();
4131
4132 return (int)lineStarts.count();
4133}
4134
4135QTextStringChar *QTextParag::lineStartOfLine( int line, int *index ) const
4136{
4137 if ( !isValid() )
4138 ( (QTextParag*)this )->format();
4139
4140 if ( line >= 0 && line < (int)lineStarts.count() ) {
4141 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin();
4142 while ( line-- > 0 )
4143 ++it;
4144 int i = it.key();
4145 if ( index )
4146 *index = i;
4147 return &str->at( i );
4148 }
4149
4150 qWarning( "QTextParag::lineStartOfLine: couldn't find %d", line );
4151 return 0;
4152}
4153
4154int QTextParag::leftGap() const
4155{
4156 if ( !isValid() )
4157 ( (QTextParag*)this )->format();
4158
4159 int line = 0;
4160 int x = str->at(0).x; /* set x to x of first char */
4161 if ( str->isBidi() ) {
4162 for ( int i = 1; i < str->length(); ++i )
4163 x = QMIN(x, str->at(i).x);
4164 return x;
4165 }
4166
4167 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin();
4168 while (line < (int)lineStarts.count()) {
4169 int i = it.key(); /* char index */
4170 x = QMIN(x, str->at(i).x);
4171 ++it;
4172 ++line;
4173 }
4174 return x;
4175}
4176
4177void QTextParag::setFormat( int index, int len, QTextFormat *f, bool useCollection, int flags )
4178{
4179 if ( !f )
4180 return;
4181 if ( index < 0 )
4182 index = 0;
4183 if ( index > str->length() - 1 )
4184 index = str->length() - 1;
4185 if ( index + len >= str->length() )
4186 len = str->length() - index;
4187
4188 QTextFormatCollection *fc = 0;
4189 if ( useCollection )
4190 fc = formatCollection();
4191 QTextFormat *of;
4192 for ( int i = 0; i < len; ++i ) {
4193 of = str->at( i + index ).format();
4194 if ( !changed && f->key() != of->key() )
4195 changed = TRUE;
4196 if ( invalid == -1 &&
4197 ( f->font().family() != of->font().family() ||
4198 f->font().pointSize() != of->font().pointSize() ||
4199 f->font().weight() != of->font().weight() ||
4200 f->font().italic() != of->font().italic() ||
4201 f->vAlign() != of->vAlign() ) ) {
4202 invalidate( 0 );
4203 }
4204 if ( flags == -1 || flags == QTextFormat::Format || !fc ) {
4205 if ( fc )
4206 f = fc->format( f );
4207 str->setFormat( i + index, f, useCollection );
4208 } else {
4209 QTextFormat *fm = fc->format( of, f, flags );
4210 str->setFormat( i + index, fm, useCollection );
4211 }
4212 }
4213}
4214
4215void QTextParag::indent( int *oldIndent, int *newIndent )
4216{
4217 if ( !hasdoc || !document()->indent() || style() && style()->displayMode() != QStyleSheetItem::DisplayBlock ) {
4218 if ( oldIndent )
4219 *oldIndent = 0;
4220 if ( newIndent )
4221 *newIndent = 0;
4222 if ( oldIndent && newIndent )
4223 *newIndent = *oldIndent;
4224 return;
4225 }
4226 document()->indent()->indent( document(), this, oldIndent, newIndent );
4227}
4228
4229void QTextParag::paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor, bool drawSelections,
4230 int clipx, int clipy, int clipw, int cliph )
4231{
4232 if ( !visible )
4233 return;
4234 QTextStringChar *chr = at( 0 );
4235 int i = 0;
4236 int h = 0;
4237 int baseLine = 0, lastBaseLine = 0;
4238 QTextStringChar *formatChar = 0;
4239 int lastY = -1;
4240 int startX = 0;
4241 int bw = 0;
4242 int cy = 0;
4243 int curx = -1, cury = 0, curh = 0;
4244 bool lastDirection = chr->rightToLeft;
4245 const int full_sel_width = (hasdoc ? document()->width() : r.width());
4246#if 0 // seems we don't need that anymore
4247 int tw = 0;
4248#endif
4249
4250 QString qstr = str->toString();
4251 // ### workaround so that \n are not drawn, actually this should be
4252 // fixed in QFont somewhere (under Windows you get ugly boxes
4253 // otherwise)
4254 QChar* uc = (QChar*) qstr.unicode();
4255 for ( uint ii = 0; ii < qstr.length(); ii++ ) {
4256 if ( uc[(int)ii]== '\n' )
4257 uc[(int)ii] = 0x20;
4258 }
4259
4260
4261 const int nSels = hasdoc ? document()->numSelections() : 1;
4262 QMemArray<int> selectionStarts( nSels );
4263 QMemArray<int> selectionEnds( nSels );
4264 if ( drawSelections ) {
4265 bool hasASelection = FALSE;
4266 for ( i = 0; i < nSels; ++i ) {
4267 if ( !hasSelection( i ) ) {
4268 selectionStarts[ i ] = -1;
4269 selectionEnds[ i ] = -1;
4270 } else {
4271 hasASelection = TRUE;
4272 selectionStarts[ i ] = selectionStart( i );
4273 int end = selectionEnd( i );
4274 if ( end == length() - 1 && n && n->hasSelection( i ) )
4275 end++;
4276 selectionEnds[ i ] = end;
4277 }
4278 }
4279 if ( !hasASelection )
4280 drawSelections = FALSE;
4281 }
4282
4283 int line = -1;
4284 int cw;
4285 bool didListLabel = FALSE;
4286 int paintStart = 0;
4287 int paintEnd = -1;
4288 int lasth = 0;
4289 for ( i = 0; i < length(); i++ ) {
4290 chr = at( i );
4291#if 0 // seems we don't need that anymore
4292 if ( !str->isBidi() && is_printer( &painter ) ) { // ### fix our broken ps-printer
4293 if ( !chr->lineStart )
4294 chr->x = QMAX( chr->x, tw );
4295 else
4296 tw = 0;
4297 }
4298#endif
4299 cw = string()->width( i );
4300 if ( chr->c == '\t' && i < length() - 1 )
4301 cw = at( i + 1 )->x - chr->x + 1;
4302 if ( chr->c.unicode() == 0xad && i < length() - 1 )
4303 cw = 0;
4304
4305 // init a new line
4306 if ( chr->lineStart ) {
4307#if 0 // seems we don't need that anymore
4308 tw = 0;
4309#endif
4310 ++line;
4311 lineInfo( line, cy, h, baseLine );
4312 lasth = h;
4313 if ( clipy != -1 && cy > clipy - r.y() + cliph ) // outside clip area, leave
4314 break;
4315 if ( lastBaseLine == 0 )
4316 lastBaseLine = baseLine;
4317 }
4318
4319 // draw bullet list items
4320 if ( !didListLabel && line == 0 && style() && style()->displayMode() == QStyleSheetItem::DisplayListItem ) {
4321 didListLabel = TRUE;
4322 drawLabel( &painter, chr->x, cy, 0, 0, baseLine, cg );
4323 }
4324
4325 // check for cursor mark
4326 if ( cursor && this == cursor->parag() && i == cursor->index() ) {
4327 curx = cursor->x();
4328 QTextStringChar *c = chr;
4329 if ( i > 0 )
4330 --c;
4331 curh = c->format()->height();
4332 cury = cy + baseLine - c->format()->ascent();
4333 }
4334
4335 // first time - start again...
4336 if ( !formatChar || lastY == -1 ) {
4337 formatChar = chr;
4338 lastY = cy;
4339 startX = chr->x;
4340 if ( !chr->isCustom() && chr->c != '\n' )
4341 paintEnd = i;
4342 bw = cw;
4343 if ( !chr->isCustom() )
4344 continue;
4345 }
4346
4347 // check if selection state changed
4348 bool selectionChange = FALSE;
4349 if ( drawSelections ) {
4350 for ( int j = 0; j < nSels; ++j ) {
4351 selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i;
4352 if ( selectionChange )
4353 break;
4354 }
4355 }
4356
4357 //if something (format, etc.) changed, draw what we have so far
4358 if ( ( ( ( alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify && at(paintEnd)->c.isSpace() ) ||
4359 lastDirection != (bool)chr->rightToLeft ||
4360 chr->startOfRun ||
4361 lastY != cy || chr->format() != formatChar->format() || chr->isAnchor() != formatChar->isAnchor() ||
4362 ( paintEnd != -1 && at( paintEnd )->c =='\t' ) || chr->c == '\t' ||
4363 ( paintEnd != -1 && at( paintEnd )->c.unicode() == 0xad ) || chr->c.unicode() == 0xad ||
4364 selectionChange || chr->isCustom() ) ) {
4365 if ( paintStart <= paintEnd ) {
4366 // ### temporary hack until I get the new placement/shaping stuff working
4367 int x = startX;
4368 if ( ( alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify && paintEnd != -1 &&
4369 paintEnd > 1 && at( paintEnd )->c.isSpace() ) {
4370 int add = str->at(paintEnd).x - str->at(paintEnd-1).x - str->width(paintEnd-1);
4371 bw += ( lastDirection ? 0 : add );
4372 }
4373 drawParagString( painter, qstr, paintStart, paintEnd - paintStart + 1, x, lastY,
4374 lastBaseLine, bw, lasth, drawSelections,
4375 formatChar, i, selectionStarts, selectionEnds, cg, lastDirection );
4376 }
4377#if 0 // seems we don't need that anymore
4378 if ( !str->isBidi() && is_printer( &painter ) ) { // ### fix our broken ps-printer
4379 if ( !chr->lineStart ) {
4380 // ### the next line doesn't look 100% correct for arabic
4381 tw = startX + painter.fontMetrics().width( qstr.mid(paintStart, paintEnd - paintStart +1) );
4382 chr->x = QMAX( chr->x, tw );
4383 } else {
4384 tw = 0;
4385 }
4386 }
4387#endif
4388 if ( !chr->isCustom() ) {
4389 if ( chr->c != '\n' ) {
4390 paintStart = i;
4391 paintEnd = i;
4392 } else {
4393 paintStart = i+1;
4394 paintEnd = -1;
4395 }
4396 formatChar = chr;
4397 lastY = cy;
4398 startX = chr->x;
4399 bw = cw;
4400 } else {
4401 if ( chr->customItem()->placement() == QTextCustomItem::PlaceInline ) {
4402 chr->customItem()->draw( &painter, chr->x, cy, clipx - r.x(), clipy - r.y(), clipw, cliph, cg,
4403 nSels && selectionStarts[ 0 ] <= i && selectionEnds[ 0 ] >= i );
4404 paintStart = i+1;
4405 paintEnd = -1;
4406 formatChar = chr;
4407 lastY = cy;
4408 startX = chr->x + string()->width( i );
4409 bw = 0;
4410 } else {
4411 chr->customItem()->resize( chr->customItem()->width );
4412 paintStart = i+1;
4413 paintEnd = -1;
4414 formatChar = chr;
4415 lastY = cy;
4416 startX = chr->x + string()->width( i );
4417 bw = 0;
4418 }
4419 }
4420 } else {
4421 if ( chr->c != '\n' ) {
4422 if( chr->rightToLeft ) {
4423 startX = chr->x;
4424 }
4425 paintEnd = i;
4426 }
4427 bw += cw;
4428 }
4429 lastBaseLine = baseLine;
4430 lasth = h;
4431 lastDirection = chr->rightToLeft;
4432 }
4433
4434 // if we are through the parag, but still have some stuff left to draw, draw it now
4435 if ( paintStart <= paintEnd ) {
4436 bool selectionChange = FALSE;
4437 if ( drawSelections ) {
4438 for ( int j = 0; j < nSels; ++j ) {
4439 selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i;
4440 if ( selectionChange )
4441 break;
4442 }
4443 }
4444 int x = startX;
4445 drawParagString( painter, qstr, paintStart, paintEnd-paintStart+1, x, lastY,
4446 lastBaseLine, bw, h, drawSelections,
4447 formatChar, i, selectionStarts, selectionEnds, cg, lastDirection );
4448 }
4449
4450 // if we should draw a cursor, draw it now
4451 if ( curx != -1 && cursor ) {
4452 painter.fillRect( QRect( curx, cury, 1, curh - lineSpacing() ), cg.color( QColorGroup::Text ) );
4453 painter.save();
4454 if ( string()->isBidi() ) {
4455 const int d = 4;
4456 if ( at( cursor->index() )->rightToLeft ) {
4457 painter.setPen( Qt::black );
4458 painter.drawLine( curx, cury, curx - d / 2, cury + d / 2 );
4459 painter.drawLine( curx, cury + d, curx - d / 2, cury + d / 2 );
4460 } else {
4461 painter.setPen( Qt::black );
4462 painter.drawLine( curx, cury, curx + d / 2, cury + d / 2 );
4463 painter.drawLine( curx, cury + d, curx + d / 2, cury + d / 2 );
4464 }
4465 }
4466 painter.restore();
4467 }
4468}
4469
4470//#define BIDI_DEBUG
4471
4472void QTextParag::drawParagString( QPainter &painter, const QString &s, int start, int len, int startX,
4473 int lastY, int baseLine, int bw, int h, bool drawSelections,
4474 QTextStringChar *formatChar, int i, const QMemArray<int> &selectionStarts,
4475 const QMemArray<int> &selectionEnds, const QColorGroup &cg, bool rightToLeft )
4476{
4477 bool plainText = hasdoc ? document()->textFormat() == Qt::PlainText : FALSE;
4478 QTextFormat* format = formatChar->format();
4479 QString str( s );
4480 if ( str[ (int)str.length() - 1 ].unicode() == 0xad )
4481 str.remove( str.length() - 1, 1 );
4482 if ( !plainText || hasdoc && format->color() != document()->formatCollection()->defaultFormat()->color() )
4483 painter.setPen( QPen( format->color() ) );
4484 else
4485 painter.setPen( cg.text() );
4486 painter.setFont( format->font() );
4487
4488 if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() ) {
4489 if ( format->useLinkColor() ) {
4490 if ( document()->linkColor.isValid() )
4491 painter.setPen( document()->linkColor );
4492 else
4493 painter.setPen( QPen( Qt::blue ) );
4494 }
4495 if ( document()->underlineLinks() ) {
4496 QFont fn = format->font();
4497 fn.setUnderline( TRUE );
4498 painter.setFont( fn );
4499 }
4500 }
4501
4502 if ( drawSelections ) {
4503 const int nSels = hasdoc ? document()->numSelections() : 1;
4504 const int startSel = is_printer( 0 ) ? 1 : 0;
4505 for ( int j = startSel; j < nSels; ++j ) {
4506 if ( i > selectionStarts[ j ] && i <= selectionEnds[ j ] ) {
4507 if ( !hasdoc || document()->invertSelectionText( j ) )
4508 painter.setPen( QPen( cg.color( QColorGroup::HighlightedText ) ) );
4509 if ( j == QTextDocument::Standard )
4510 painter.fillRect( startX, lastY, bw, h, cg.color( QColorGroup::Highlight ) );
4511 else
4512 painter.fillRect( startX, lastY, bw, h, hasdoc ? document()->selectionColor( j ) : cg.color( QColorGroup::Highlight ) );
4513 }
4514 }
4515 }
4516
4517 if ( str[ start ] != '\t' && str[ start ].unicode() != 0xad ) {
4518 if ( format->vAlign() == QTextFormat::AlignNormal ) {
4519 painter.drawText( startX, lastY + baseLine, str.mid( start ), len );
4520#ifdef BIDI_DEBUG
4521 painter.save();
4522 painter.setPen ( Qt::red );
4523 painter.drawLine( startX, lastY, startX, lastY + baseLine );
4524 painter.drawLine( startX, lastY + baseLine/2, startX + 10, lastY + baseLine/2 );
4525 int w = 0;
4526 int i = 0;
4527 while( i < len )
4528 w += painter.fontMetrics().charWidth( str, start + i++ );
4529 painter.setPen ( Qt::blue );
4530 painter.drawLine( startX + w - 1, lastY, startX + w - 1, lastY + baseLine );
4531 painter.drawLine( startX + w - 1, lastY + baseLine/2, startX + w - 1 - 10, lastY + baseLine/2 );
4532 painter.restore();
4533#endif
4534 } else if ( format->vAlign() == QTextFormat::AlignSuperScript ) {
4535 QFont f( painter.font() );
4536 if ( format->fontSizesInPixels() )
4537 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
4538 else
4539 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
4540 painter.setFont( f );
4541 painter.drawText( startX, lastY + baseLine - ( painter.fontMetrics().height() / 2 ),
4542 str.mid( start ), len );
4543 } else if ( format->vAlign() == QTextFormat::AlignSubScript ) {
4544 QFont f( painter.font() );
4545 if ( format->fontSizesInPixels() )
4546 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
4547 else
4548 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
4549 painter.setFont( f );
4550 painter.drawText( startX, lastY + baseLine + painter.fontMetrics().height() / 6, str.mid( start ), len );
4551 }
4552 }
4553 if ( i + 1 < length() && at( i + 1 )->lineStart && at( i )->c.unicode() == 0xad ) {
4554 painter.drawText( startX + bw, lastY + baseLine, "\xad" );
4555 }
4556 if ( format->isMisspelled() ) {
4557 painter.save();
4558 painter.setPen( QPen( Qt::red, 1, Qt::DotLine ) );
4559 painter.drawLine( startX, lastY + baseLine + 1, startX + bw, lastY + baseLine + 1 );
4560 painter.restore();
4561 }
4562
4563 i -= len;
4564
4565 if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() &&
4566 document()->focusIndicator.parag == this &&
4567 ( document()->focusIndicator.start >= i &&
4568 document()->focusIndicator.start + document()->focusIndicator.len <= i + len ||
4569 document()->focusIndicator.start <= i &&
4570 document()->focusIndicator.start + document()->focusIndicator.len >= i + len ) ) {
4571 painter.drawWinFocusRect( QRect( startX, lastY, bw, h ) );
4572 }
4573
4574}
4575
4576void QTextParag::drawLabel( QPainter* p, int x, int y, int w, int h, int base, const QColorGroup& cg )
4577{
4578 if ( !style() )
4579 return;
4580 QRect r ( x, y, w, h );
4581 QStyleSheetItem::ListStyle s = listStyle();
4582
4583 p->save();
4584 p->setPen( defFormat->color() );
4585
4586 QFont font2( defFormat->font() );
4587 if ( length() > 0 ) {
4588 QTextFormat *format = at( 0 )->format();
4589 if ( format ) {
4590 if ( format->fontSizesInPixels() )
4591 font2.setPixelSize( at( 0 )->format()->font().pixelSize() );
4592 else
4593 font2.setPointSize( at( 0 )->format()->font().pointSize() );
4594 }
4595 }
4596 p->setFont( font2 );
4597 QFontMetrics fm( p->fontMetrics() );
4598 int size = fm.lineSpacing() / 3;
4599
4600 switch ( s ) {
4601 case QStyleSheetItem::ListDecimal:
4602 case QStyleSheetItem::ListLowerAlpha:
4603 case QStyleSheetItem::ListUpperAlpha:
4604 {
4605 int n = numberOfSubParagraph();
4606 QString l;
4607 switch ( s ) {
4608 case QStyleSheetItem::ListLowerAlpha:
4609 if ( n < 27 ) {
4610 l = QChar( ('a' + (char) (n-1)));
4611 break;
4612 }
4613 case QStyleSheetItem::ListUpperAlpha:
4614 if ( n < 27 ) {
4615 l = QChar( ('A' + (char) (n-1)));
4616 break;
4617 }
4618 break;
4619 default: //QStyleSheetItem::ListDecimal:
4620 l.setNum( n );
4621 break;
4622 }
4623 l += QString::fromLatin1(". ");
4624 p->drawText( r.right() - fm.width( l ), r.top() + base, l );
4625 }
4626 break;
4627 case QStyleSheetItem::ListSquare:
4628 {
4629 QRect er( r.right() - size * 2, r.top() + fm.height() / 2 - size / 2, size, size );
4630 p->fillRect( er , cg.brush( QColorGroup::Foreground ) );
4631 }
4632 break;
4633 case QStyleSheetItem::ListCircle:
4634 {
4635 QRect er( r.right()-size*2, r.top() + fm.height() / 2 - size / 2, size, size);
4636 p->drawEllipse( er );
4637 }
4638 break;
4639 case QStyleSheetItem::ListDisc:
4640 default:
4641 {
4642 p->setBrush( cg.brush( QColorGroup::Foreground ));
4643 QRect er( r.right()-size*2, r.top() + fm.height() / 2 - size / 2, size, size);
4644 p->drawEllipse( er );
4645 p->setBrush( Qt::NoBrush );
4646 }
4647 break;
4648 }
4649
4650 p->restore();
4651}
4652
4653void QTextParag::setStyleSheetItems( const QPtrVector<QStyleSheetItem> &vec )
4654{
4655 styleSheetItemsVec() = vec;
4656 invalidate( 0 );
4657 lm = rm = tm = bm = flm = -1;
4658 numSubParag = -1;
4659}
4660
4661void QTextParag::setList( bool b, int listStyle )
4662{
4663 if ( !hasdoc )
4664 return;
4665
4666 if ( !style() ) {
4667 styleSheetItemsVec().resize( 2 );
4668 mStyleSheetItemsVec->insert( 0, document()->styleSheet()->item( "html" ) );
4669 mStyleSheetItemsVec->insert( 1, document()->styleSheet()->item( "p" ) );
4670 }
4671
4672 if ( b ) {
4673 if ( style()->displayMode() != QStyleSheetItem::DisplayListItem || this->listStyle() != listStyle ) {
4674 styleSheetItemsVec().remove( styleSheetItemsVec().size() - 1 );
4675 QStyleSheetItem *item = (*mStyleSheetItemsVec)[ mStyleSheetItemsVec->size() - 1 ];
4676 if ( item )
4677 mStyleSheetItemsVec->remove( mStyleSheetItemsVec->size() - 1 );
4678 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 1,
4679 listStyle == QStyleSheetItem::ListDisc || listStyle == QStyleSheetItem::ListCircle
4680 || listStyle == QStyleSheetItem::ListSquare ?
4681 document()->styleSheet()->item( "ul" ) : document()->styleSheet()->item( "ol" ) );
4682 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 1, document()->styleSheet()->item( "li" ) );
4683 setListStyle( (QStyleSheetItem::ListStyle)listStyle );
4684 } else {
4685 return;
4686 }
4687 } else {
4688 if ( style()->displayMode() != QStyleSheetItem::DisplayBlock ) {
4689 styleSheetItemsVec().remove( styleSheetItemsVec().size() - 1 );
4690 if ( mStyleSheetItemsVec->size() >= 2 ) {
4691 mStyleSheetItemsVec->remove( mStyleSheetItemsVec->size() - 2 );
4692 mStyleSheetItemsVec->resize( mStyleSheetItemsVec->size() - 2 );
4693 } else {
4694 mStyleSheetItemsVec->resize( mStyleSheetItemsVec->size() - 1 );
4695 }
4696 } else {
4697 return;
4698 }
4699 }
4700 invalidate( 0 );
4701 lm = rm = tm = bm = flm = -1;
4702 numSubParag = -1;
4703 if ( next() ) {
4704 QTextParag *s = next();
4705 while ( s ) {
4706 s->numSubParag = -1;
4707 s->lm = s->rm = s->tm = s->bm = flm = -1;
4708 s->numSubParag = -1;
4709 s->invalidate( 0 );
4710 s = s->next();
4711 }
4712 }
4713}
4714
4715void QTextParag::incDepth()
4716{
4717 if ( !style() || !hasdoc )
4718 return;
4719 if ( style()->displayMode() != QStyleSheetItem::DisplayListItem )
4720 return;
4721 styleSheetItemsVec().resize( styleSheetItemsVec().size() + 1 );
4722 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 1, (*mStyleSheetItemsVec)[ mStyleSheetItemsVec->size() - 2 ] );
4723 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 2,
4724 listStyle() == QStyleSheetItem::ListDisc || listStyle() == QStyleSheetItem::ListCircle ||
4725 listStyle() == QStyleSheetItem::ListSquare ?
4726 document()->styleSheet()->item( "ul" ) : document()->styleSheet()->item( "ol" ) );
4727 invalidate( 0 );
4728 lm = -1;
4729 flm = -1;
4730}
4731
4732void QTextParag::decDepth()
4733{
4734 if ( !style() || !hasdoc )
4735 return;
4736 if ( style()->displayMode() != QStyleSheetItem::DisplayListItem )
4737 return;
4738 int numLists = 0;
4739 QStyleSheetItem *lastList = 0;
4740 int lastIndex = 0;
4741 int i;
4742 if ( mStyleSheetItemsVec ) {
4743 for ( i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
4744 QStyleSheetItem *item = (*mStyleSheetItemsVec)[ i ];
4745 if ( item->name() == "ol" || item->name() == "ul" ) {
4746 lastList = item;
4747 lastIndex = i;
4748 numLists++;
4749 }
4750 }
4751 }
4752
4753 if ( !lastList )
4754 return;
4755 styleSheetItemsVec().remove( lastIndex );
4756 for ( i = lastIndex; i < (int)mStyleSheetItemsVec->size() - 1; ++i )
4757 mStyleSheetItemsVec->insert( i, (*mStyleSheetItemsVec)[ i + 1 ] );
4758 mStyleSheetItemsVec->resize( mStyleSheetItemsVec->size() - 1 );
4759 if ( numLists == 1 )
4760 setList( FALSE, -1 );
4761 invalidate( 0 );
4762 lm = -1;
4763 flm = -1;
4764}
4765
4766int QTextParag::listDepth() const
4767{
4768 int numLists = 0;
4769 int i;
4770 if ( mStyleSheetItemsVec ) {
4771 for ( i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
4772 QStyleSheetItem *item = (*mStyleSheetItemsVec)[ i ];
4773 if ( item->name() == "ol" || item->name() == "ul" )
4774 numLists++;
4775 }
4776 }
4777 return numLists - 1;
4778}
4779
4780int *QTextParag::tabArray() const
4781{
4782 int *ta = tArray;
4783 if ( !ta && hasdoc )
4784 ta = document()->tabArray();
4785 return ta;
4786}
4787
4788int QTextParag::nextTab( int, int x )
4789{
4790 int *ta = tArray;
4791 if ( hasdoc ) {
4792 if ( !ta )
4793 ta = document()->tabArray();
4794 tabStopWidth = document()->tabStopWidth();
4795 }
4796 if ( ta ) {
4797 int i = 0;
4798 while ( ta[ i ] ) {
4799 if ( ta[ i ] >= x )
4800 return tArray[ i ];
4801 ++i;
4802 }
4803 return tArray[ 0 ];
4804 } else {
4805 int d;
4806 if ( tabStopWidth != 0 )
4807 d = x / tabStopWidth;
4808 else
4809 return x;
4810 return tabStopWidth * ( d + 1 );
4811 }
4812}
4813
4814void QTextParag::adjustToPainter( QPainter *p )
4815{
4816 for ( int i = 0; i < length(); ++i ) {
4817 if ( at( i )->isCustom() )
4818 at( i )->customItem()->adjustToPainter( p );
4819 }
4820}
4821
4822QTextFormatCollection *QTextParag::formatCollection() const
4823{
4824 if ( hasdoc )
4825 return document()->formatCollection();
4826 if ( !qFormatCollection ) {
4827 qFormatCollection = new QTextFormatCollection;
4828 static QSingleCleanupHandler<QTextFormatCollection> qtfCleanup;
4829 qtfCleanup.set( &qFormatCollection );
4830 }
4831 return qFormatCollection;
4832}
4833
4834QString QTextParag::richText() const
4835{
4836 QString s;
4837 QTextStringChar *formatChar = 0;
4838 QString spaces;
4839 bool lastCharWasSpace = FALSE;
4840 int firstcol = 0;
4841 for ( int i = 0; i < length()-1; ++i ) {
4842 QTextStringChar *c = &str->at( i );
4843 if ( c->isAnchor() && !c->anchorName().isEmpty() ) {
4844 if ( c->anchorName().contains( '#' ) ) {
4845 QStringList l = QStringList::split( '#', c->anchorName() );
4846 for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it )
4847 s += "<a name=\"" + *it + "\"></a>";
4848 } else {
4849 s += "<a name=\"" + c->anchorName() + "\"></a>";
4850 }
4851 }
4852 if ( !formatChar ) {
4853 s += c->format()->makeFormatChangeTags( 0, QString::null, c->anchorHref() );
4854 formatChar = c;
4855 } else if ( ( formatChar->format()->key() != c->format()->key() ) ||
4856 (formatChar->isAnchor() != c->isAnchor() &&
4857 (!c->anchorHref().isEmpty() || !formatChar->anchorHref().isEmpty() ) ) ) {// lisp was here
4858
4859 if ( !spaces.isEmpty() ) {
4860 if ( spaces[0] == '\t' || lastCharWasSpace )
4861 s += "<wsp>" + spaces + "</wsp>";
4862 else if ( spaces.length() > 1 )
4863 s += "<wsp>" + spaces.mid(1) + "</wsp> ";
4864 else
4865 s += spaces;
4866 lastCharWasSpace = TRUE;
4867 spaces = QString::null;
4868 }
4869 s += c->format()->makeFormatChangeTags( formatChar->format() , formatChar->anchorHref(), c->anchorHref() );
4870 formatChar = c;
4871 }
4872
4873 if ( c->c == ' ' || c->c == '\t' ) {
4874 spaces += c->c;
4875 continue;
4876 } else if ( !spaces.isEmpty() ) {
4877 if ( spaces[0] == '\t' || lastCharWasSpace )
4878 s += "<wsp>" + spaces + "</wsp>";
4879 else if ( spaces.length() > 1 )
4880 s += "<wsp>" + spaces.mid(1) + "</wsp> ";
4881 else
4882 s += spaces;
4883 spaces = QString::null;
4884 if ( s.length() - firstcol > 60 ) {
4885 s += '\n';
4886 firstcol = s.length();
4887 }
4888 }
4889
4890 lastCharWasSpace = FALSE;
4891 if ( c->c == '<' ) {
4892 s += "&lt;";
4893 } else if ( c->c == '>' ) {
4894 s += "&gt;";
4895 } else if ( c->isCustom() ) {
4896 s += c->customItem()->richText();
4897 } else {
4898 s += c->c;
4899 }
4900 }
4901 if ( !spaces.isEmpty() ) {
4902 if ( spaces.length() > 1 || spaces[0] == '\t' || lastCharWasSpace )
4903 s += "<wsp>" + spaces + "</wsp>";
4904 else
4905 s += spaces;
4906 }
4907
4908 if ( formatChar )
4909 s += formatChar->format()->makeFormatEndTags( formatChar->anchorHref() );
4910 return s;
4911}
4912
4913void QTextParag::addCommand( QTextCommand *cmd )
4914{
4915 if ( !hasdoc )
4916 pseudoDocument()->commandHistory->addCommand( cmd );
4917 else
4918 document()->commands()->addCommand( cmd );
4919}
4920
4921QTextCursor *QTextParag::undo( QTextCursor *c )
4922{
4923 if ( !hasdoc )
4924 return pseudoDocument()->commandHistory->undo( c );
4925 return document()->commands()->undo( c );
4926}
4927
4928QTextCursor *QTextParag::redo( QTextCursor *c )
4929{
4930 if ( !hasdoc )
4931 return pseudoDocument()->commandHistory->redo( c );
4932 return document()->commands()->redo( c );
4933}
4934
4935int QTextParag::topMargin() const
4936{
4937 if ( !p && ( !hasdoc || !document()->addMargins() ) )
4938 return 0;
4939 if ( tm != -1 )
4940 return tm;
4941 QStyleSheetItem *item = style();
4942 if ( !item ) {
4943 ( (QTextParag*)this )->tm = 0;
4944 return 0;
4945 }
4946
4947 int m = 0;
4948 if ( item->margin( QStyleSheetItem::MarginTop ) != QStyleSheetItem::Undefined )
4949 m = item->margin( QStyleSheetItem::MarginTop );
4950 if ( mStyleSheetItemsVec ) {
4951 QStyleSheetItem *it = 0;
4952 QStyleSheetItem *p = prev() ? prev()->style() : 0;
4953 for ( int i = (int)mStyleSheetItemsVec->size() - 2 ; i >= 0; --i ) {
4954 it = (*mStyleSheetItemsVec)[ i ];
4955 if ( it != p )
4956 break;
4957 int mar = it->margin( QStyleSheetItem::MarginTop );
4958 m += (mar != QStyleSheetItem::Undefined) ? mar : 0;
4959 if ( it->displayMode() != QStyleSheetItem::DisplayInline )
4960 break;
4961 }
4962 }
4963 m = scale( m, QTextFormat::painter() );
4964
4965 ( (QTextParag*)this )->tm = m;
4966 return tm;
4967}
4968
4969int QTextParag::bottomMargin() const
4970{
4971 if ( bm != -1 )
4972 return bm;
4973 QStyleSheetItem *item = style();
4974 if ( !item || !next() ) {
4975 ( (QTextParag*)this )->bm = 0;
4976 return 0;
4977 }
4978
4979 int m = 0;
4980 if ( item->margin( QStyleSheetItem::MarginBottom ) != QStyleSheetItem::Undefined )
4981 m = item->margin( QStyleSheetItem::MarginBottom );
4982 if ( mStyleSheetItemsVec ) {
4983 QStyleSheetItem *it = 0;
4984 QStyleSheetItem *n = next() ? next()->style() : 0;
4985 for ( int i =(int)mStyleSheetItemsVec->size() - 2 ; i >= 0; --i ) {
4986 it = (*mStyleSheetItemsVec)[ i ];
4987 if ( it != n )
4988 break;
4989 int mar = it->margin( QStyleSheetItem::MarginBottom );
4990 m += mar != QStyleSheetItem::Undefined ? mar : 0;
4991 if ( it->displayMode() != QStyleSheetItem::DisplayInline )
4992 break;
4993 }
4994 }
4995 m = scale ( m, QTextFormat::painter() );
4996
4997 ( (QTextParag*)this )->bm = m;
4998 return bm;
4999}
5000
5001int QTextParag::leftMargin() const
5002{
5003 if ( lm != -1 )
5004 return lm;
5005 QStyleSheetItem *item = style();
5006 if ( !item ) {
5007 ( (QTextParag*)this )->lm = 0;
5008 return 0;
5009 }
5010 int m = 0;
5011 if ( mStyleSheetItemsVec ) {
5012 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
5013 item = (*mStyleSheetItemsVec)[ i ];
5014 int mar = item->margin( QStyleSheetItem::MarginLeft );
5015 m += mar != QStyleSheetItem::Undefined ? mar : 0;
5016 if ( item->name() == "ol" || item->name() == "ul" ) {
5017 QPainter* oldPainter = QTextFormat::painter();
5018 QTextFormat::setPainter( 0 );
5019 m += defFormat->width( '1' ) +
5020 defFormat->width( '2' ) +
5021 defFormat->width( '3' ) +
5022 defFormat->width( '.' );
5023 QTextFormat::setPainter( oldPainter );
5024 }
5025 }
5026 }
5027
5028 m = scale ( m, QTextFormat::painter() );
5029
5030 ( (QTextParag*)this )->lm = m;
5031 return lm;
5032}
5033
5034int QTextParag::firstLineMargin() const
5035{
5036 if ( flm != -1 )
5037 return lm;
5038 QStyleSheetItem *item = style();
5039 if ( !item ) {
5040 ( (QTextParag*)this )->flm = 0;
5041 return 0;
5042 }
5043 int m = 0;
5044 if ( mStyleSheetItemsVec ) {
5045 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
5046 item = (*mStyleSheetItemsVec)[ i ];
5047 int mar = item->margin( QStyleSheetItem::MarginFirstLine );
5048 m += mar != QStyleSheetItem::Undefined ? mar : 0;
5049 }
5050 }
5051
5052 m = scale( m, QTextFormat::painter() );
5053
5054 ( (QTextParag*)this )->flm = m;
5055 return flm;
5056}
5057
5058int QTextParag::rightMargin() const
5059{
5060 if ( rm != -1 )
5061 return rm;
5062 QStyleSheetItem *item = style();
5063 if ( !item ) {
5064 ( (QTextParag*)this )->rm = 0;
5065 return 0;
5066 }
5067 int m = 0;
5068 if ( mStyleSheetItemsVec ) {
5069 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
5070 item = (*mStyleSheetItemsVec)[ i ];
5071 int mar = item->margin( QStyleSheetItem::MarginRight );
5072 m += mar != QStyleSheetItem::Undefined ? mar : 0;
5073 }
5074 }
5075 m = scale( m, QTextFormat::painter() );
5076
5077 ( (QTextParag*)this )->rm = m;
5078 return rm;
5079}
5080
5081int QTextParag::lineSpacing() const
5082{
5083 QStyleSheetItem *item = style();
5084 if ( !item )
5085 return 0;
5086
5087 int ls = item->lineSpacing();
5088 if ( ls == QStyleSheetItem::Undefined )
5089 return 0;
5090 ls = scale( ls, QTextFormat::painter() );
5091
5092 return ls;
5093}
5094
5095void QTextParag::copyParagData( QTextParag *parag )
5096{
5097 setStyleSheetItems( parag->styleSheetItems() );
5098 setListStyle( parag->listStyle() );
5099 setAlignment( parag->alignment() );
5100 QColor *c = parag->backgroundColor();
5101 if ( c )
5102 setBackgroundColor( *c );
5103}
5104
5105void QTextParag::show()
5106{
5107 if ( visible || !hasdoc )
5108 return;
5109 visible = TRUE;
5110}
5111
5112void QTextParag::hide()
5113{
5114 if ( !visible || !hasdoc )
5115 return;
5116 visible = FALSE;
5117}
5118
5119void QTextParag::setDirection( QChar::Direction d )
5120{
5121 if ( str && str->direction() != d ) {
5122 str->setDirection( d );
5123 invalidate( 0 );
5124 }
5125}
5126
5127QChar::Direction QTextParag::direction() const
5128{
5129 return (str ? str->direction() : QChar::DirON );
5130}
5131
5132void QTextParag::setChanged( bool b, bool recursive )
5133{
5134 changed = b;
5135 if ( recursive ) {
5136 if ( document() && document()->parentParag() )
5137 document()->parentParag()->setChanged( b, recursive );
5138 }
5139}
5140
5141// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5142
5143
5144QTextPreProcessor::QTextPreProcessor()
5145{
5146}
5147
5148// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5149
5150QTextFormatter::QTextFormatter()
5151 : thisminw(0), thiswused(0), wrapEnabled( TRUE ), wrapColumn( -1 ), biw( FALSE )
5152{
5153}
5154
5155/* only used for bidi or complex text reordering
5156 */
5157QTextParagLineStart *QTextFormatter::formatLine( QTextParag *parag, QTextString *string, QTextParagLineStart *line,
5158 QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
5159{
5160#ifndef QT_NO_COMPLEXTEXT
5161 if( string->isBidi() )
5162 return bidiReorderLine( parag, string, line, startChar, lastChar, align, space );
5163#endif
5164 space = QMAX( space, 0 ); // #### with nested tables this gets negative because of a bug I didn't find yet, so workaround for now. This also means non-left aligned nested tables do not work at the moment
5165 int start = (startChar - &string->at(0));
5166 int last = (lastChar - &string->at(0) );
5167 // do alignment Auto == Left in this case
5168 if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) {
5169 if ( align & Qt::AlignHCenter )
5170 space /= 2;
5171 for ( int j = start; j <= last; ++j )
5172 string->at( j ).x += space;
5173 } else if ( align & Qt3::AlignJustify ) {
5174 int numSpaces = 0;
5175 for ( int j = start; j < last; ++j ) {
5176 if( isBreakable( string, j ) ) {
5177 numSpaces++;
5178 }
5179 }
5180 int toAdd = 0;
5181 for ( int k = start + 1; k <= last; ++k ) {
5182 if( isBreakable( string, k ) && numSpaces ) {
5183 int s = space / numSpaces;
5184 toAdd += s;
5185 space -= s;
5186 numSpaces--;
5187 }
5188 string->at( k ).x += toAdd;
5189 }
5190 }
5191
5192 if ( last >= 0 && last < string->length() )
5193 line->w = string->at( last ).x + string->width( last );
5194 else
5195 line->w = 0;
5196
5197 return new QTextParagLineStart();
5198}
5199
5200#ifndef QT_NO_COMPLEXTEXT
5201
5202#ifdef BIDI_DEBUG
5203#include <iostream>
5204#endif
5205
5206// collects one line of the paragraph and transforms it to visual order
5207QTextParagLineStart *QTextFormatter::bidiReorderLine( QTextParag * /*parag*/, QTextString *text, QTextParagLineStart *line,
5208 QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
5209{
5210 int start = (startChar - &text->at(0));
5211 int last = (lastChar - &text->at(0) );
5212 //qDebug("doing BiDi reordering from %d to %d!", start, last);
5213
5214 QBidiControl *control = new QBidiControl( line->context(), line->status );
5215 QString str;
5216 str.setUnicode( 0, last - start + 1 );
5217 // fill string with logically ordered chars.
5218 QTextStringChar *ch = startChar;
5219 QChar *qch = (QChar *)str.unicode();
5220 while ( ch <= lastChar ) {
5221 *qch = ch->c;
5222 qch++;
5223 ch++;
5224 }
5225 int x = startChar->x;
5226
5227 QPtrList<QTextRun> *runs;
5228 runs = QComplexText::bidiReorderLine(control, str, 0, last - start + 1,
5229 (text->isRightToLeft() ? QChar::DirR : QChar::DirL) );
5230
5231 // now construct the reordered string out of the runs...
5232
5233 int numSpaces = 0;
5234 // set the correct alignment. This is a bit messy....
5235 if( align == Qt3::AlignAuto ) {
5236 // align according to directionality of the paragraph...
5237 if ( text->isRightToLeft() )
5238 align = Qt::AlignRight;
5239 }
5240
5241 if ( align & Qt::AlignHCenter )
5242 x += space/2;
5243 else if ( align & Qt::AlignRight )
5244 x += space;
5245 else if ( align & Qt3::AlignJustify ) {
5246 for ( int j = start; j < last; ++j ) {
5247 if( isBreakable( text, j ) ) {
5248 numSpaces++;
5249 }
5250 }
5251 }
5252 int toAdd = 0;
5253 bool first = TRUE;
5254 QTextRun *r = runs->first();
5255 int xmax = -0xffffff;
5256 while ( r ) {
5257 if(r->level %2) {
5258 // odd level, need to reverse the string
5259 int pos = r->stop + start;
5260 while(pos >= r->start + start) {
5261 QTextStringChar *c = &text->at(pos);
5262 if( numSpaces && !first && isBreakable( text, pos ) ) {
5263 int s = space / numSpaces;
5264 toAdd += s;
5265 space -= s;
5266 numSpaces--;
5267 } else if ( first ) {
5268 first = FALSE;
5269 if ( c->c == ' ' )
5270 x -= c->format()->width( ' ' );
5271 }
5272 c->x = x + toAdd;
5273 c->rightToLeft = TRUE;
5274 c->startOfRun = FALSE;
5275 int ww = 0;
5276 if ( c->c.unicode() >= 32 || c->c == '\t' || c->c == '\n' || c->isCustom() ) {
5277 ww = text->width( pos );
5278 } else {
5279 ww = c->format()->width( ' ' );
5280 }
5281 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
5282 x += ww;
5283 pos--;
5284 }
5285 } else {
5286 int pos = r->start + start;
5287 while(pos <= r->stop + start) {
5288 QTextStringChar* c = &text->at(pos);
5289 if( numSpaces && !first && isBreakable( text, pos ) ) {
5290 int s = space / numSpaces;
5291 toAdd += s;
5292 space -= s;
5293 numSpaces--;
5294 } else if ( first ) {
5295 first = FALSE;
5296 if ( c->c == ' ' )
5297 x -= c->format()->width( ' ' );
5298 }
5299 c->x = x + toAdd;
5300 c->rightToLeft = FALSE;
5301 c->startOfRun = FALSE;
5302 int ww = 0;
5303 if ( c->c.unicode() >= 32 || c->c == '\t' || c->isCustom() ) {
5304 ww = text->width( pos );
5305 } else {
5306 ww = c->format()->width( ' ' );
5307 }
5308 //qDebug("setting char %d at pos %d", pos, x);
5309 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
5310 x += ww;
5311 pos++;
5312 }
5313 }
5314 text->at( r->start + start ).startOfRun = TRUE;
5315 r = runs->next();
5316 }
5317
5318 line->w = xmax + 10;
5319 QTextParagLineStart *ls = new QTextParagLineStart( control->context, control->status );
5320 delete control;
5321 delete runs;
5322 return ls;
5323}
5324#endif
5325
5326bool QTextFormatter::isBreakable( QTextString *string, int pos ) const
5327{
5328 const QChar &c = string->at( pos ).c;
5329 char ch = c.latin1();
5330 if ( c.isSpace() && ch != '\n' && c.unicode() != 0x00a0U )
5331 return TRUE;
5332 if ( c.unicode() == 0xad ) // soft hyphen
5333 return TRUE;
5334 if ( !ch ) {
5335 // not latin1, need to do more sophisticated checks for other scripts
5336 uchar row = c.row();
5337 if ( row == 0x0e ) {
5338 // 0e00 - 0e7f == Thai
5339 if ( c.cell() < 0x80 ) {
5340#ifdef HAVE_THAI_BREAKS
5341 // check for thai
5342 if( string != cachedString ) {
5343 // build up string of thai chars
5344 QTextCodec *thaiCodec = QTextCodec::codecForMib(2259);
5345 if ( !thaiCache )
5346 thaiCache = new QCString;
5347 if ( !thaiIt )
5348 thaiIt = ThBreakIterator::createWordInstance();
5349 *thaiCache = thaiCodec->fromUnicode( s->string() );
5350 }
5351 thaiIt->setText(thaiCache->data());
5352 for(int i = thaiIt->first(); i != thaiIt->DONE; i = thaiIt->next() ) {
5353 if( i == pos )
5354 return TRUE;
5355 if( i > pos )
5356 return FALSE;
5357 }
5358 return FALSE;
5359#else
5360 // if we don't have a thai line breaking lib, allow
5361 // breaks everywhere except directly before punctuation.
5362 return TRUE;
5363#endif
5364 } else
5365 return FALSE;
5366 }
5367 if ( row < 0x11 ) // no asian font
5368 return FALSE;
5369 if ( row > 0x2d && row < 0xfb || row == 0x11 )
5370 // asian line breaking. Everywhere allowed except directly
5371 // in front of a punctuation character.
5372 return TRUE;
5373 }
5374 return FALSE;
5375}
5376
5377void QTextFormatter::insertLineStart( QTextParag *parag, int index, QTextParagLineStart *ls )
5378{
5379 if ( index > 0 ) { // we can assume that only first line starts are insrted multiple times
5380 parag->lineStartList().insert( index, ls );
5381 return;
5382 }
5383 QMap<int, QTextParagLineStart*>::Iterator it;
5384 if ( ( it = parag->lineStartList().find( index ) ) == parag->lineStartList().end() ) {
5385 parag->lineStartList().insert( index, ls );
5386 } else {
5387 delete *it;
5388 parag->lineStartList().remove( it );
5389 parag->lineStartList().insert( index, ls );
5390 }
5391}
5392
5393
5394/* Standard pagebreak algorithm using QTextFlow::adjustFlow. Returns
5395 the shift of the paragraphs bottom line.
5396 */
5397int QTextFormatter::formatVertically( QTextDocument* doc, QTextParag* parag )
5398{
5399 int oldHeight = parag->rect().height();
5400 QMap<int, QTextParagLineStart*>& lineStarts = parag->lineStartList();
5401 QMap<int, QTextParagLineStart*>::Iterator it = lineStarts.begin();
5402 int h = doc->addMargins() ? parag->topMargin() : 0;
5403 for ( ; it != lineStarts.end() ; ++it ) {
5404 QTextParagLineStart * ls = it.data();
5405 ls->y = h;
5406 QTextStringChar *c = &parag->string()->at(it.key());
5407 if ( c && c->customItem() && c->customItem()->ownLine() ) {
5408 int h = c->customItem()->height;
5409 c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
5410 int delta = c->customItem()->height - h;
5411 ls->h += delta;
5412 if ( delta )
5413 parag->setMovedDown( TRUE );
5414 } else {
5415 int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h );
5416 ls->y += shift;
5417 if ( shift )
5418 parag->setMovedDown( TRUE );
5419 }
5420 h = ls->y + ls->h;
5421 }
5422 int m = parag->bottomMargin();
5423 if ( parag->next() && doc && !doc->addMargins() )
5424 m = QMAX( m, parag->next()->topMargin() );
5425 if ( parag->next() && parag->next()->isLineBreak() )
5426 m = 0;
5427 h += m;
5428 parag->setHeight( h );
5429 return h - oldHeight;
5430}
5431
5432// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5433
5434QTextFormatterBreakInWords::QTextFormatterBreakInWords()
5435{
5436}
5437
5438int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParag *parag,
5439 int start, const QMap<int, QTextParagLineStart*> & )
5440{
5441 QTextStringChar *c = 0;
5442 QTextStringChar *firstChar = 0;
5443 int left = doc ? parag->leftMargin() + doc->leftMargin() : 4;
5444 int x = left + ( doc ? parag->firstLineMargin() : 0 );
5445 int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 0 );
5446 int y = doc && doc->addMargins() ? parag->topMargin() : 0;
5447 int h = y;
5448 int len = parag->length();
5449 if ( doc )
5450 x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 4 );
5451 int rm = parag->rightMargin();
5452 int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5453 bool fullWidth = TRUE;
5454 int minw = 0;
5455 int wused = 0;
5456 bool wrapEnabled = isWrapEnabled( parag );
5457
5458 start = 0; //######### what is the point with start?! (Matthias)
5459 if ( start == 0 )
5460 c = &parag->string()->at( 0 );
5461
5462 int i = start;
5463 QTextParagLineStart *lineStart = new QTextParagLineStart( y, y, 0 );
5464 insertLineStart( parag, 0, lineStart );
5465
5466 QPainter *painter = QTextFormat::painter();
5467
5468 int col = 0;
5469 int ww = 0;
5470 QChar lastChr;
5471 for ( ; i < len; ++i, ++col ) {
5472 if ( c )
5473 lastChr = c->c;
5474 c = &parag->string()->at( i );
5475 c->rightToLeft = FALSE;
5476 // ### the lines below should not be needed
5477 if ( painter )
5478 c->format()->setPainter( painter );
5479 if ( i > 0 ) {
5480 c->lineStart = 0;
5481 } else {
5482 c->lineStart = 1;
5483 firstChar = c;
5484 }
5485 if ( c->c.unicode() >= 32 || c->isCustom() ) {
5486 ww = parag->string()->width( i );
5487 } else if ( c->c == '\t' ) {
5488 int nx = parag->nextTab( i, x - left ) + left;
5489 if ( nx < x )
5490 ww = w - x;
5491 else
5492 ww = nx - x;
5493 } else {
5494 ww = c->format()->width( ' ' );
5495 }
5496
5497 if ( c->isCustom() && c->customItem()->ownLine() ) {
5498 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5499 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5500 c->customItem()->resize( w - x );
5501 w = dw;
5502 y += h;
5503 h = c->height();
5504 lineStart = new QTextParagLineStart( y, h, h );
5505 insertLineStart( parag, i, lineStart );
5506 c->lineStart = 1;
5507 firstChar = c;
5508 x = 0xffffff;
5509 continue;
5510 }
5511
5512 if ( wrapEnabled &&
5513 ( wrapAtColumn() == -1 && x + ww > w ||
5514 wrapAtColumn() != -1 && col >= wrapAtColumn() ) ||
5515 parag->isNewLinesAllowed() && lastChr == '\n' ) {
5516 x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5517 w = dw;
5518 y += h;
5519 h = c->height();
5520 lineStart = formatLine( parag, parag->string(), lineStart, firstChar, c-1 );
5521 lineStart->y = y;
5522 insertLineStart( parag, i, lineStart );
5523 lineStart->baseLine = c->ascent();
5524 lineStart->h = c->height();
5525 c->lineStart = 1;
5526 firstChar = c;
5527 col = 0;
5528 if ( wrapAtColumn() != -1 )
5529 minw = QMAX( minw, w );
5530 } else if ( lineStart ) {
5531 lineStart->baseLine = QMAX( lineStart->baseLine, c->ascent() );
5532 h = QMAX( h, c->height() );
5533 lineStart->h = h;
5534 }
5535
5536 c->x = x;
5537 x += ww;
5538 wused = QMAX( wused, x );
5539 }
5540
5541 int m = parag->bottomMargin();
5542 if ( parag->next() && doc && !doc->addMargins() )
5543 m = QMAX( m, parag->next()->topMargin() );
5544 parag->setFullWidth( fullWidth );
5545 if ( parag->next() && parag->next()->isLineBreak() )
5546 m = 0;
5547 y += h + m;
5548 if ( !wrapEnabled )
5549 minw = QMAX(minw, wused);
5550
5551 thisminw = minw;
5552 thiswused = wused;
5553 return y;
5554}
5555
5556// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5557
5558QTextFormatterBreakWords::QTextFormatterBreakWords()
5559{
5560}
5561
5562#define DO_FLOW( lineStart ) do{ if ( doc && doc->isPageBreakEnabled() ) { \
5563 int yflow = lineStart->y + parag->rect().y();\
5564 int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \
5565 lineStart->y += shift;\
5566 y += shift;\
5567 }}while(FALSE)
5568
5569int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParag *parag,
5570 int start, const QMap<int, QTextParagLineStart*> & )
5571{
5572 QTextStringChar *c = 0;
5573 QTextStringChar *firstChar = 0;
5574 QTextString *string = parag->string();
5575 int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
5576 int x = left + ( doc ? parag->firstLineMargin() : 0 );
5577 int y = doc && doc->addMargins() ? parag->topMargin() : 0;
5578 int h = y;
5579 int len = parag->length();
5580 if ( doc )
5581 x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 );
5582 int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 );
5583
5584 int curLeft = x;
5585 int rm = parag->rightMargin();
5586 int rdiff = doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 0 ) : 0;
5587 int w = dw - rdiff;
5588 bool fullWidth = TRUE;
5589 int marg = left + rdiff;
5590 int minw = 0;
5591 int wused = 0;
5592 int tminw = marg;
5593 int linespace = doc ? parag->lineSpacing() : 0;
5594 bool wrapEnabled = isWrapEnabled( parag );
5595
5596 start = 0;
5597 if ( start == 0 )
5598 c = &parag->string()->at( 0 );
5599
5600 int i = start;
5601 QTextParagLineStart *lineStart = new QTextParagLineStart( y, y, 0 );
5602 insertLineStart( parag, 0, lineStart );
5603 int lastBreak = -1;
5604 int tmpBaseLine = 0, tmph = 0;
5605 bool lastWasNonInlineCustom = FALSE;
5606
5607 int align = parag->alignment();
5608 if ( align == Qt3::AlignAuto && doc && doc->alignment() != Qt3::AlignAuto )
5609 align = doc->alignment();
5610
5611 align &= Qt3::AlignHorizontal_Mask;
5612
5613 QPainter *painter = QTextFormat::painter();
5614 int col = 0;
5615 int ww = 0;
5616 QChar lastChr;
5617 for ( ; i < len; ++i, ++col ) {
5618 if ( c )
5619 lastChr = c->c;
5620 // ### next line should not be needed
5621 if ( painter )
5622 c->format()->setPainter( painter );
5623 c = &string->at( i );
5624 c->rightToLeft = FALSE;
5625 if ( i > 0 && (x > curLeft || ww == 0) || lastWasNonInlineCustom ) {
5626 c->lineStart = 0;
5627 } else {
5628 c->lineStart = 1;
5629 firstChar = c;
5630 }
5631
5632 if ( c->isCustom() && c->customItem()->placement() != QTextCustomItem::PlaceInline )
5633 lastWasNonInlineCustom = TRUE;
5634 else
5635 lastWasNonInlineCustom = FALSE;
5636
5637 if ( c->c.unicode() >= 32 || c->isCustom() ) {
5638 ww = string->width( i );
5639 } else if ( c->c == '\t' ) {
5640 int nx = parag->nextTab( i, x - left ) + left;
5641 if ( nx < x )
5642 ww = w - x;
5643 else
5644 ww = nx - x;
5645 } else {
5646 ww = c->format()->width( ' ' );
5647 }
5648
5649 // last character ("invisible" space) has no width
5650 if ( i == len - 1 )
5651 ww = 0;
5652
5653 QTextCustomItem* ci = c->customItem();
5654 if ( c->isCustom() && ci->ownLine() ) {
5655 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5656 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5657 QTextParagLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, w - x );
5658 ci->resize( w - x);
5659 if ( ci->width < w - x ) {
5660 if ( align & Qt::AlignHCenter )
5661 x = ( w - ci->width ) / 2;
5662 else if ( align & Qt::AlignRight ) {
5663 x = w - ci->width;
5664 }
5665 }
5666 c->x = x;
5667 curLeft = x;
5668 if ( i == 0 || !isBreakable( string, i - 1 ) || string->at( i - 1 ).lineStart == 0 ) {
5669 y += QMAX( h, tmph );
5670 tmph = c->height() + linespace;
5671 h = tmph;
5672 lineStart = lineStart2;
5673 lineStart->y = y;
5674 insertLineStart( parag, i, lineStart );
5675 c->lineStart = 1;
5676 firstChar = c;
5677 } else {
5678 tmph = c->height() + linespace;
5679 h = tmph;
5680 delete lineStart2;
5681 }
5682 lineStart->h = h;
5683 lineStart->baseLine = h;
5684 tmpBaseLine = lineStart->baseLine;
5685 lastBreak = -2;
5686 x = 0xffffff;
5687 minw = QMAX( minw, tminw );
5688
5689 int tw = ci->minimumWidth();
5690 if ( tw < QWIDGETSIZE_MAX )
5691 tminw = tw;
5692 else
5693 tminw = marg;
5694 wused = QMAX( wused, ci->width );
5695 continue;
5696 } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) {
5697 int tw = ci->minimumWidth();
5698 if ( tw < QWIDGETSIZE_MAX )
5699 minw = QMAX( minw, tw );
5700 }
5701
5702 if ( wrapEnabled && ( !c->c.isSpace() || lastBreak == -2 )
5703 && ( lastBreak != -1 || allowBreakInWords() ) &&
5704 ( wrapAtColumn() == -1 && x + ww > w && lastBreak != -1 ||
5705 wrapAtColumn() == -1 && x + ww > w - 4 && lastBreak == -1 && allowBreakInWords() ||
5706 wrapAtColumn() != -1 && col >= wrapAtColumn() ) ||
5707 parag->isNewLinesAllowed() && lastChr == '\n' && firstChar < c ) {
5708 if ( wrapAtColumn() != -1 )
5709 minw = QMAX( minw, x + ww );
5710 if ( lastBreak < 0 ) {
5711 if ( lineStart ) {
5712 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
5713 h = QMAX( h, tmph );
5714 lineStart->h = h;
5715 DO_FLOW( lineStart );
5716 }
5717 lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, w - x );
5718 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5719 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5720 if ( parag->isNewLinesAllowed() && c->c == '\t' ) {
5721 int nx = parag->nextTab( i, x - left ) + left;
5722 if ( nx < x )
5723 ww = w - x;
5724 else
5725 ww = nx - x;
5726 }
5727 curLeft = x;
5728 y += h;
5729 tmph = c->height() + linespace;
5730 h = 0;
5731 lineStart->y = y;
5732 insertLineStart( parag, i, lineStart );
5733 lineStart->baseLine = c->ascent();
5734 lineStart->h = c->height();
5735 c->lineStart = 1;
5736 firstChar = c;
5737 tmpBaseLine = lineStart->baseLine;
5738 lastBreak = -1;
5739 col = 0;
5740 } else {
5741 DO_FLOW( lineStart );
5742 i = lastBreak;
5743 lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ), align, w - string->at( i ).x );
5744 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5745 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5746 if ( parag->isNewLinesAllowed() && c->c == '\t' ) {
5747 int nx = parag->nextTab( i, x - left ) + left;
5748 if ( nx < x )
5749 ww = w - x;
5750 else
5751 ww = nx - x;
5752 }
5753 curLeft = x;
5754 y += h;
5755 tmph = c->height() + linespace;
5756 h = tmph;
5757 lineStart->y = y;
5758 insertLineStart( parag, i + 1, lineStart );
5759 lineStart->baseLine = c->ascent();
5760 lineStart->h = c->height();
5761 c->lineStart = 1;
5762 firstChar = c;
5763 tmpBaseLine = lineStart->baseLine;
5764 lastBreak = -1;
5765 col = 0;
5766 tminw = marg;
5767 continue;
5768 }
5769 } else if ( lineStart && ( isBreakable( string, i ) || parag->isNewLinesAllowed() && c->c == '\n' ) ) {
5770 if ( len <= 2 || i < len - 1 ) {
5771 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
5772 tmph = QMAX( tmph, c->height() + linespace );
5773 }
5774 minw = QMAX( minw, tminw );
5775 tminw = marg + ww;
5776 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
5777 h = QMAX( h, tmph );
5778 lineStart->h = h;
5779 if ( i < len - 2 || c->c != ' ' )
5780 lastBreak = i;
5781 } else {
5782 tminw += ww;
5783 int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height() + linespace - c->ascent() );
5784 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
5785 tmph = tmpBaseLine + belowBaseLine;
5786 }
5787
5788 c->x = x;
5789 x += ww;
5790 wused = QMAX( wused, x );
5791 }
5792
5793 // ### hack. The last char in the paragraph is always invisible, and somehow sometimes has a wrong format. It changes between
5794 // layouting and printing. This corrects some layouting errors in BiDi mode due to this.
5795 if ( len > 1 && !c->isAnchor() ) {
5796 c->format()->removeRef();
5797 c->setFormat( string->at( len - 2 ).format() );
5798 c->format()->addRef();
5799 }
5800
5801 if ( lineStart ) {
5802 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
5803 h = QMAX( h, tmph );
5804 lineStart->h = h;
5805 // last line in a paragraph is not justified
5806 if ( align == Qt3::AlignJustify )
5807 align = Qt3::AlignAuto;
5808 DO_FLOW( lineStart );
5809 lineStart = formatLine( parag, string, lineStart, firstChar, c, align, w - x );
5810 delete lineStart;
5811 }
5812
5813 minw = QMAX( minw, tminw );
5814
5815 int m = parag->bottomMargin();
5816 if ( parag->next() && doc && !doc->addMargins() )
5817 m = QMAX( m, parag->next()->topMargin() );
5818 parag->setFullWidth( fullWidth );
5819 if ( parag->next() && parag->next()->isLineBreak() )
5820 m = 0;
5821 y += h + m;
5822
5823 wused += rm;
5824 if ( !wrapEnabled || wrapAtColumn() != -1 )
5825 minw = QMAX(minw, wused);
5826 thisminw = minw;
5827 thiswused = wused;
5828 return y;
5829}
5830
5831// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5832
5833QTextIndent::QTextIndent()
5834{
5835}
5836
5837// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5838
5839QTextFormatCollection::QTextFormatCollection()
5840 : cKey( 307 ), sheet( 0 )
5841{
5842 defFormat = new QTextFormat( QApplication::font(),
5843 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
5844 lastFormat = cres = 0;
5845 cflags = -1;
5846 cKey.setAutoDelete( TRUE );
5847 cachedFormat = 0;
5848}
5849
5850QTextFormatCollection::~QTextFormatCollection()
5851{
5852 delete defFormat;
5853}
5854
5855QTextFormat *QTextFormatCollection::format( QTextFormat *f )
5856{
5857 if ( f->parent() == this || f == defFormat ) {
5858#ifdef DEBUG_COLLECTION
5859 qDebug( "need '%s', best case!", f->key().latin1() );
5860#endif
5861 lastFormat = f;
5862 lastFormat->addRef();
5863 return lastFormat;
5864 }
5865
5866 if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
5867#ifdef DEBUG_COLLECTION
5868 qDebug( "need '%s', good case!", f->key().latin1() );
5869#endif
5870 lastFormat->addRef();
5871 return lastFormat;
5872 }
5873
5874 QTextFormat *fm = cKey.find( f->key() );
5875 if ( fm ) {
5876#ifdef DEBUG_COLLECTION
5877 qDebug( "need '%s', normal case!", f->key().latin1() );
5878#endif
5879 lastFormat = fm;
5880 lastFormat->addRef();
5881 return lastFormat;
5882 }
5883
5884 if ( f->key() == defFormat->key() )
5885 return defFormat;
5886
5887#ifdef DEBUG_COLLECTION
5888 qDebug( "need '%s', worst case!", f->key().latin1() );
5889#endif
5890 lastFormat = createFormat( *f );
5891 lastFormat->collection = this;
5892 cKey.insert( lastFormat->key(), lastFormat );
5893 return lastFormat;
5894}
5895
5896QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags )
5897{
5898 if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
5899#ifdef DEBUG_COLLECTION
5900 qDebug( "mix of '%s' and '%s, best case!", of->key().latin1(), nf->key().latin1() );
5901#endif
5902 cres->addRef();
5903 return cres;
5904 }
5905
5906 cres = createFormat( *of );
5907 kof = of->key();
5908 knf = nf->key();
5909 cflags = flags;
5910 if ( flags & QTextFormat::Bold )
5911 cres->fn.setBold( nf->fn.bold() );
5912 if ( flags & QTextFormat::Italic )
5913 cres->fn.setItalic( nf->fn.italic() );
5914 if ( flags & QTextFormat::Underline )
5915 cres->fn.setUnderline( nf->fn.underline() );
5916 if ( flags & QTextFormat::Family )
5917 cres->fn.setFamily( nf->fn.family() );
5918 if ( flags & QTextFormat::Size ) {
5919 if ( of->usePixelSizes )
5920 cres->fn.setPixelSize( nf->fn.pixelSize() );
5921 else
5922 cres->fn.setPointSize( nf->fn.pointSize() );
5923 }
5924 if ( flags & QTextFormat::Color )
5925 cres->col = nf->col;
5926 if ( flags & QTextFormat::Misspelled )
5927 cres->missp = nf->missp;
5928 if ( flags & QTextFormat::VAlign )
5929 cres->ha = nf->ha;
5930 cres->update();
5931
5932 QTextFormat *fm = cKey.find( cres->key() );
5933 if ( !fm ) {
5934#ifdef DEBUG_COLLECTION
5935 qDebug( "mix of '%s' and '%s, worst case!", of->key().latin1(), nf->key().latin1() );
5936#endif
5937 cres->collection = this;
5938 cKey.insert( cres->key(), cres );
5939 } else {
5940#ifdef DEBUG_COLLECTION
5941 qDebug( "mix of '%s' and '%s, good case!", of->key().latin1(), nf->key().latin1() );
5942#endif
5943 delete cres;
5944 cres = fm;
5945 cres->addRef();
5946 }
5947
5948 return cres;
5949}
5950
5951QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c )
5952{
5953 if ( cachedFormat && cfont == f && ccol == c ) {
5954#ifdef DEBUG_COLLECTION
5955 qDebug( "format of font and col '%s' - best case", cachedFormat->key().latin1() );
5956#endif
5957 cachedFormat->addRef();
5958 return cachedFormat;
5959 }
5960
5961 QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal );
5962 cachedFormat = cKey.find( key );
5963 cfont = f;
5964 ccol = c;
5965
5966 if ( cachedFormat ) {
5967#ifdef DEBUG_COLLECTION
5968 qDebug( "format of font and col '%s' - good case", cachedFormat->key().latin1() );
5969#endif
5970 cachedFormat->addRef();
5971 return cachedFormat;
5972 }
5973
5974 if ( key == defFormat->key() )
5975 return defFormat;
5976
5977 cachedFormat = createFormat( f, c );
5978 cachedFormat->collection = this;
5979 cKey.insert( cachedFormat->key(), cachedFormat );
5980 if ( cachedFormat->key() != key )
5981 qWarning("ASSERT: keys for format not identical: '%s '%s'", cachedFormat->key().latin1(), key.latin1() );
5982#ifdef DEBUG_COLLECTION
5983 qDebug( "format of font and col '%s' - worst case", cachedFormat->key().latin1() );
5984#endif
5985 return cachedFormat;
5986}
5987
5988void QTextFormatCollection::remove( QTextFormat *f )
5989{
5990 if ( lastFormat == f )
5991 lastFormat = 0;
5992 if ( cres == f )
5993 cres = 0;
5994 if ( cachedFormat == f )
5995 cachedFormat = 0;
5996 cKey.remove( f->key() );
5997}
5998
5999void QTextFormatCollection::debug()
6000{
6001#ifdef DEBUG_COLLECTION
6002 qDebug( "------------ QTextFormatCollection: debug --------------- BEGIN" );
6003 QDictIterator<QTextFormat> it( cKey );
6004 for ( ; it.current(); ++it ) {
6005 qDebug( "format '%s' (%p): refcount: %d", it.current()->key().latin1(),
6006 it.current(), it.current()->ref );
6007 }
6008 qDebug( "------------ QTextFormatCollection: debug --------------- END" );
6009#endif
6010}
6011
6012void QTextFormatCollection::updateStyles()
6013{
6014 QDictIterator<QTextFormat> it( cKey );
6015 QTextFormat *f;
6016 while ( ( f = it.current() ) ) {
6017 ++it;
6018 f->updateStyle();
6019 }
6020 updateKeys();
6021}
6022
6023void QTextFormatCollection::updateFontSizes( int base, bool usePixels )
6024{
6025 QDictIterator<QTextFormat> it( cKey );
6026 QTextFormat *f;
6027 while ( ( f = it.current() ) ) {
6028 ++it;
6029 f->stdSize = base;
6030 f->usePixelSizes = usePixels;
6031 if ( usePixels )
6032 f->fn.setPixelSize( f->stdSize );
6033 else
6034 f->fn.setPointSize( f->stdSize );
6035 styleSheet()->scaleFont( f->fn, f->logicalFontSize );
6036 f->update();
6037 }
6038 f = defFormat;
6039 f->stdSize = base;
6040 f->usePixelSizes = usePixels;
6041 if ( usePixels )
6042 f->fn.setPixelSize( f->stdSize );
6043 else
6044 f->fn.setPointSize( f->stdSize );
6045 styleSheet()->scaleFont( f->fn, f->logicalFontSize );
6046 f->update();
6047 updateKeys();
6048}
6049
6050void QTextFormatCollection::updateFontAttributes( const QFont &f, const QFont &old )
6051{
6052 QDictIterator<QTextFormat> it( cKey );
6053 QTextFormat *fm;
6054 while ( ( fm = it.current() ) ) {
6055 ++it;
6056 if ( fm->fn.family() == old.family() &&
6057 fm->fn.weight() == old.weight() &&
6058 fm->fn.italic() == old.italic() &&
6059 fm->fn.underline() == old.underline() ) {
6060 fm->fn.setFamily( f.family() );
6061 fm->fn.setWeight( f.weight() );
6062 fm->fn.setItalic( f.italic() );
6063 fm->fn.setUnderline( f.underline() );
6064 fm->update();
6065 }
6066 }
6067 fm = defFormat;
6068 if ( fm->fn.family() == old.family() &&
6069 fm->fn.weight() == old.weight() &&
6070 fm->fn.italic() == old.italic() &&
6071 fm->fn.underline() == old.underline() ) {
6072 fm->fn.setFamily( f.family() );
6073 fm->fn.setWeight( f.weight() );
6074 fm->fn.setItalic( f.italic() );
6075 fm->fn.setUnderline( f.underline() );
6076 fm->update();
6077 }
6078 updateKeys();
6079}
6080
6081
6082// the keys in cKey have changed, rebuild the hashtable
6083void QTextFormatCollection::updateKeys()
6084{
6085 if ( cKey.isEmpty() )
6086 return;
6087 cKey.setAutoDelete( FALSE );
6088 QTextFormat** formats = new QTextFormat*[ cKey.count() + 1];
6089 QTextFormat **f = formats;
6090 QDictIterator<QTextFormat> it( cKey );
6091 while ( ( *f = it.current() ) ) {
6092 ++it;
6093 ++f;
6094 }
6095 cKey.clear();
6096 for ( f = formats; *f; f++ )
6097 cKey.insert( (*f)->key(), *f );
6098 cKey.setAutoDelete( TRUE );
6099}
6100
6101
6102
6103// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6104
6105void QTextFormat::setBold( bool b )
6106{
6107 if ( b == fn.bold() )
6108 return;
6109 fn.setBold( b );
6110 update();
6111}
6112
6113void QTextFormat::setMisspelled( bool b )
6114{
6115 if ( b == (bool)missp )
6116 return;
6117 missp = b;
6118 update();
6119}
6120
6121void QTextFormat::setVAlign( VerticalAlignment a )
6122{
6123 if ( a == ha )
6124 return;
6125 ha = a;
6126 update();
6127}
6128
6129void QTextFormat::setItalic( bool b )
6130{
6131 if ( b == fn.italic() )
6132 return;
6133 fn.setItalic( b );
6134 update();
6135}
6136
6137void QTextFormat::setUnderline( bool b )
6138{
6139 if ( b == fn.underline() )
6140 return;
6141 fn.setUnderline( b );
6142 update();
6143}
6144
6145void QTextFormat::setFamily( const QString &f )
6146{
6147 if ( f == fn.family() )
6148 return;
6149 fn.setFamily( f );
6150 update();
6151}
6152
6153void QTextFormat::setPointSize( int s )
6154{
6155 if ( s == fn.pointSize() )
6156 return;
6157 fn.setPointSize( s );
6158 usePixelSizes = FALSE;
6159 update();
6160}
6161
6162void QTextFormat::setFont( const QFont &f )
6163{
6164 if ( f == fn && !k.isEmpty() )
6165 return;
6166 fn = f;
6167 update();
6168}
6169
6170void QTextFormat::setColor( const QColor &c )
6171{
6172 if ( c == col )
6173 return;
6174 col = c;
6175 update();
6176}
6177
6178static int makeLogicFontSize( int s )
6179{
6180 int defSize = QApplication::font().pointSize();
6181 if ( s < defSize - 4 )
6182 return 1;
6183 if ( s < defSize )
6184 return 2;
6185 if ( s < defSize + 4 )
6186 return 3;
6187 if ( s < defSize + 8 )
6188 return 4;
6189 if ( s < defSize + 12 )
6190 return 5;
6191 if (s < defSize + 16 )
6192 return 6;
6193 return 7;
6194}
6195
6196static QTextFormat *defaultFormat = 0;
6197
6198QString QTextFormat::makeFormatChangeTags( QTextFormat *f, const QString& oldAnchorHref, const QString& anchorHref ) const
6199{
6200 if ( !defaultFormat ) // #### wrong, use the document's default format instead
6201 defaultFormat = new QTextFormat( QApplication::font(),
6202 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
6203
6204 QString tag;
6205 if ( f ) {
6206 if ( f->font() != defaultFormat->font() ) {
6207 if ( f->font().family() != defaultFormat->font().family()
6208 || f->font().pointSize() != defaultFormat->font().pointSize()
6209 || f->color().rgb() != defaultFormat->color().rgb() )
6210 tag += "</font>";
6211 if ( f->font().underline() && f->font().underline() != defaultFormat->font().underline() )
6212 tag += "</u>";
6213 if ( f->font().italic() && f->font().italic() != defaultFormat->font().italic() )
6214 tag += "</i>";
6215 if ( f->font().bold() && f->font().bold() != defaultFormat->font().bold() )
6216 tag += "</b>";
6217 }
6218 if ( !oldAnchorHref.isEmpty() )
6219 tag += "</a>";
6220 }
6221
6222 if ( !anchorHref.isEmpty() )
6223 tag += "<a href=\"" + anchorHref + "\">";
6224
6225 if ( font() != defaultFormat->font() ) {
6226 if ( font().bold() && font().bold() != defaultFormat->font().bold() )
6227 tag += "<b>";
6228 if ( font().italic() && font().italic() != defaultFormat->font().italic() )
6229 tag += "<i>";
6230 if ( font().underline() && font().underline() != defaultFormat->font().underline() )
6231 tag += "<u>";
6232 }
6233 if ( font() != defaultFormat->font()
6234 || color().rgb() != defaultFormat->color().rgb() ) {
6235 QString f;
6236 if ( font().family() != defaultFormat->font().family() )
6237 f +=" face=\"" + fn.family() + "\"";
6238 if ( font().pointSize() != defaultFormat->font().pointSize() ) {
6239 f +=" size=\"" + QString::number( makeLogicFontSize( fn.pointSize() ) ) + "\"";
6240 f +=" style=\"font-size:" + QString::number( fn.pointSize() ) + "pt\"";
6241 }
6242 if ( color().rgb() != defaultFormat->color().rgb() )
6243 f +=" color=\"" + col.name() + "\"";
6244 if ( !f.isEmpty() )
6245 tag += "<font" + f + ">";
6246 }
6247
6248 return tag;
6249}
6250
6251QString QTextFormat::makeFormatEndTags( const QString& anchorHref ) const
6252{
6253 if ( !defaultFormat )
6254 defaultFormat = new QTextFormat( QApplication::font(),
6255 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
6256
6257 QString tag;
6258 if ( font() != defaultFormat->font() ) {
6259 if ( font().family() != defaultFormat->font().family()
6260 || font().pointSize() != defaultFormat->font().pointSize()
6261 || color().rgb() != defaultFormat->color().rgb() )
6262 tag += "</font>";
6263 if ( font().underline() && font().underline() != defaultFormat->font().underline() )
6264 tag += "</u>";
6265 if ( font().italic() && font().italic() != defaultFormat->font().italic() )
6266 tag += "</i>";
6267 if ( font().bold() && font().bold() != defaultFormat->font().bold() )
6268 tag += "</b>";
6269 }
6270 if ( !anchorHref.isEmpty() )
6271 tag += "</a>";
6272 return tag;
6273}
6274
6275QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr ) const
6276{
6277 QTextFormat format(*this);
6278 if ( style ) {
6279 format.style = style->name();
6280 if ( style->name() == "font") {
6281 if ( attr.contains("color") ) {
6282 QString s = attr["color"];
6283 if ( !s.isEmpty() ) {
6284 format.col.setNamedColor( s );
6285 format.linkColor = FALSE;
6286 }
6287 }
6288 if ( attr.contains("size") ) {
6289 QString a = attr["size"];
6290 int n = a.toInt();
6291 if ( a[0] == '+' || a[0] == '-' )
6292 n += format.logicalFontSize;
6293 format.logicalFontSize = n;
6294 if ( format.usePixelSizes )
6295 format.fn.setPixelSize( format.stdSize );
6296 else
6297 format.fn.setPointSize( format.stdSize );
6298 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
6299 }
6300 if ( attr.contains("style" ) ) {
6301 QString a = attr["style"];
6302 if ( a.startsWith( "font-size:" ) ) {
6303 QString s = a.mid( a.find( ':' ) + 1 );
6304 int n = s.left( s.length() - 2 ).toInt();
6305 format.logicalFontSize = 0;
6306 if ( format.usePixelSizes )
6307 format.fn.setPixelSize( n );
6308 else
6309 format.fn.setPointSize( n );
6310 }
6311 }
6312 if ( attr.contains("face") ) {
6313 QString a = attr["face"];
6314 if ( a.contains(',') )
6315 a = a.left( a.find(',') );
6316 format.fn.setFamily( a );
6317 }
6318 } else {
6319 if ( !style->isAnchor() && style->color().isValid() ) {
6320 // the style is not an anchor and defines a color.
6321 // It might be used inside an anchor and it should
6322 // override the link color.
6323 format.linkColor = FALSE;
6324 }
6325 switch ( style->verticalAlignment() ) {
6326 case QStyleSheetItem::VAlignBaseline:
6327 format.setVAlign( QTextFormat::AlignNormal );
6328 break;
6329 case QStyleSheetItem::VAlignSuper:
6330 format.setVAlign( QTextFormat::AlignSuperScript );
6331 break;
6332 case QStyleSheetItem::VAlignSub:
6333 format.setVAlign( QTextFormat::AlignSubScript );
6334 break;
6335 }
6336
6337 if ( style->fontWeight() != QStyleSheetItem::Undefined )
6338 format.fn.setWeight( style->fontWeight() );
6339 if ( style->fontSize() != QStyleSheetItem::Undefined ) {
6340 format.fn.setPointSize( style->fontSize() );
6341 } else if ( style->logicalFontSize() != QStyleSheetItem::Undefined ) {
6342 format.logicalFontSize = style->logicalFontSize();
6343 if ( format.usePixelSizes )
6344 format.fn.setPixelSize( format.stdSize );
6345 else
6346 format.fn.setPointSize( format.stdSize );
6347 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
6348 } else if ( style->logicalFontSizeStep() ) {
6349 format.logicalFontSize += style->logicalFontSizeStep();
6350 if ( format.usePixelSizes )
6351 format.fn.setPixelSize( format.stdSize );
6352 else
6353 format.fn.setPointSize( format.stdSize );
6354 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
6355 }
6356 if ( !style->fontFamily().isEmpty() )
6357 format.fn.setFamily( style->fontFamily() );
6358 if ( style->color().isValid() )
6359 format.col = style->color();
6360 if ( style->definesFontItalic() )
6361 format.fn.setItalic( style->fontItalic() );
6362 if ( style->definesFontUnderline() )
6363 format.fn.setUnderline( style->fontUnderline() );
6364 }
6365 }
6366
6367 format.update();
6368 return format;
6369}
6370
6371struct QPixmapInt
6372{
6373 QPixmapInt() : ref( 0 ) {}
6374 QPixmap pm;
6375 int ref;
6376};
6377
6378static QMap<QString, QPixmapInt> *pixmap_map = 0;
6379
6380QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context,
6381 QMimeSourceFactory &factory )
6382 : QTextCustomItem( p )
6383{
6384#if defined(PARSER_DEBUG)
6385 qDebug( debug_indent + "new QTextImage (pappi: %p)", p );
6386#endif
6387
6388 width = height = 0;
6389 if ( attr.contains("width") )
6390 width = attr["width"].toInt();
6391 if ( attr.contains("height") )
6392 height = attr["height"].toInt();
6393
6394 reg = 0;
6395 QString imageName = attr["src"];
6396
6397 if (!imageName)
6398 imageName = attr["source"];
6399
6400#if defined(PARSER_DEBUG)
6401 qDebug( debug_indent + " .." + imageName );
6402#endif
6403
6404 if ( !imageName.isEmpty() ) {
6405 imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory );
6406 if ( !pixmap_map )
6407 pixmap_map = new QMap<QString, QPixmapInt>;
6408 if ( pixmap_map->contains( imgId ) ) {
6409 QPixmapInt& pmi = pixmap_map->operator[](imgId);
6410 pm = pmi.pm;
6411 pmi.ref++;
6412 width = pm.width();
6413 height = pm.height();
6414 } else {
6415 QImage img;
6416 const QMimeSource* m =
6417 factory.data( imageName, context );
6418 if ( !m ) {
6419 qWarning("QTextImage: no mimesource for %s", imageName.latin1() );
6420 }
6421 else {
6422 if ( !QImageDrag::decode( m, img ) ) {
6423 qWarning("QTextImage: cannot decode %s", imageName.latin1() );
6424 }
6425 }
6426
6427 if ( !img.isNull() ) {
6428 if ( width == 0 ) {
6429 width = img.width();
6430 if ( height != 0 ) {
6431 width = img.width() * height / img.height();
6432 }
6433 }
6434 if ( height == 0 ) {
6435 height = img.height();
6436 if ( width != img.width() ) {
6437 height = img.height() * width / img.width();
6438 }
6439 }
6440 if ( img.width() != width || img.height() != height ){
6441#ifndef QT_NO_IMAGE_SMOOTHSCALE
6442 img = img.smoothScale(width, height);
6443#endif
6444 width = img.width();
6445 height = img.height();
6446 }
6447 pm.convertFromImage( img );
6448 }
6449 if ( !pm.isNull() ) {
6450 QPixmapInt& pmi = pixmap_map->operator[](imgId);
6451 pmi.pm = pm;
6452 pmi.ref++;
6453 }
6454 }
6455 if ( pm.mask() ) {
6456 QRegion mask( *pm.mask() );
6457 QRegion all( 0, 0, pm.width(), pm.height() );
6458 reg = new QRegion( all.subtract( mask ) );
6459 }
6460 }
6461
6462 if ( pm.isNull() && (width*height)==0 )
6463 width = height = 50;
6464
6465 place = PlaceInline;
6466 if ( attr["align"] == "left" )
6467 place = PlaceLeft;
6468 else if ( attr["align"] == "right" )
6469 place = PlaceRight;
6470
6471 tmpwidth = width;
6472 tmpheight = height;
6473
6474 attributes = attr;
6475}
6476
6477QTextImage::~QTextImage()
6478{
6479 if ( pixmap_map && pixmap_map->contains( imgId ) ) {
6480 QPixmapInt& pmi = pixmap_map->operator[](imgId);
6481 pmi.ref--;
6482 if ( !pmi.ref ) {
6483 pixmap_map->remove( imgId );
6484 if ( pixmap_map->isEmpty() ) {
6485 delete pixmap_map;
6486 pixmap_map = 0;
6487 }
6488 }
6489 }
6490}
6491
6492QString QTextImage::richText() const
6493{
6494 QString s;
6495 s += "<img ";
6496 QMap<QString, QString>::ConstIterator it = attributes.begin();
6497 for ( ; it != attributes.end(); ++it )
6498 s += it.key() + "=" + *it + " ";
6499 s += ">";
6500 return s;
6501}
6502
6503void QTextImage::adjustToPainter( QPainter* p )
6504{
6505 width = scale( tmpwidth, p );
6506 height = scale( tmpheight, p );
6507}
6508
6509#if !defined(Q_WS_X11)
6510#include <qbitmap.h>
6511#include "qcleanuphandler.h"
6512static QPixmap *qrt_selection = 0;
6513static QSingleCleanupHandler<QPixmap> qrt_cleanup_pixmap;
6514static void qrt_createSelectionPixmap( const QColorGroup &cg )
6515{
6516 qrt_selection = new QPixmap( 2, 2 );
6517 qrt_cleanup_pixmap.set( &qrt_selection );
6518 qrt_selection->fill( Qt::color0 );
6519 QBitmap m( 2, 2 );
6520 m.fill( Qt::color1 );
6521 QPainter p( &m );
6522 p.setPen( Qt::color0 );
6523 for ( int j = 0; j < 2; ++j ) {
6524 p.drawPoint( j % 2, j );
6525 }
6526 p.end();
6527 qrt_selection->setMask( m );
6528 qrt_selection->fill( cg.highlight() );
6529}
6530#endif
6531
6532void QTextImage::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
6533{
6534 if ( placement() != PlaceInline ) {
6535 x = xpos;
6536 y = ypos;
6537 }
6538
6539 if ( pm.isNull() ) {
6540 p->fillRect( x , y, width, height, cg.dark() );
6541 return;
6542 }
6543
6544 if ( is_printer( p ) ) {
6545 p->drawPixmap( x, y, pm );
6546 return;
6547 }
6548
6549 if ( placement() != PlaceInline && !QRect( xpos, ypos, width, height ).intersects( QRect( cx, cy, cw, ch ) ) )
6550 return;
6551
6552 if ( placement() == PlaceInline )
6553 p->drawPixmap( x , y, pm );
6554 else
6555 p->drawPixmap( cx , cy, pm, cx - x, cy - y, cw, ch );
6556
6557 if ( selected && placement() == PlaceInline && is_printer( p ) ) {
6558#if defined(Q_WS_X11)
6559 p->fillRect( QRect( QPoint( x, y ), pm.size() ), QBrush( cg.highlight(), QBrush::Dense4Pattern) );
6560#else // in WIN32 Dense4Pattern doesn't work correctly (transparency problem), so work around it
6561 if ( !qrt_selection )
6562 qrt_createSelectionPixmap( cg );
6563 p->drawTiledPixmap( x, y, pm.width(), pm.height(), *qrt_selection );
6564#endif
6565 }
6566}
6567
6568void QTextHorizontalLine::adjustToPainter( QPainter* p )
6569{
6570 height = scale( tmpheight, p );
6571}
6572
6573
6574QTextHorizontalLine::QTextHorizontalLine( QTextDocument *p, const QMap<QString, QString> &attr,
6575 const QString &,
6576 QMimeSourceFactory & )
6577 : QTextCustomItem( p )
6578{
6579 height = tmpheight = 8;
6580 if ( attr.find( "color" ) != attr.end() )
6581 color = QColor( *attr.find( "color" ) );
6582}
6583
6584QTextHorizontalLine::~QTextHorizontalLine()
6585{
6586}
6587
6588QString QTextHorizontalLine::richText() const
6589{
6590 return "<hr>";
6591}
6592
6593void QTextHorizontalLine::draw( QPainter* p, int x, int y, int , int , int , int , const QColorGroup& cg, bool selected )
6594{
6595 QRect r( x, y, width, height);
6596 if ( is_printer( p ) ) {
6597 QPen oldPen = p->pen();
6598 if ( !color.isValid() )
6599 p->setPen( QPen( cg.text(), height/8 ) );
6600 else
6601 p->setPen( QPen( color, height/8 ) );
6602 p->drawLine( r.left()-1, y + height / 2, r.right() + 1, y + height / 2 );
6603 p->setPen( oldPen );
6604 } else {
6605 QColorGroup g( cg );
6606 if ( color.isValid() )
6607 g.setColor( QColorGroup::Dark, color );
6608 if ( selected )
6609 p->fillRect( r.left(), y, r.right(), y + height, g.highlight() );
6610 qDrawShadeLine( p, r.left() - 1, y + height / 2, r.right() + 1, y + height / 2, g, TRUE, height / 8 );
6611 }
6612}
6613
6614
6615/*****************************************************************/
6616// Small set of utility functions to make the parser a bit simpler
6617//
6618
6619bool QTextDocument::hasPrefix(const QChar* doc, int length, int pos, QChar c)
6620{
6621 if ( pos >= length )
6622 return FALSE;
6623 return doc[ pos ].lower() == c.lower();
6624}
6625
6626bool QTextDocument::hasPrefix( const QChar* doc, int length, int pos, const QString& s )
6627{
6628 if ( pos + (int) s.length() >= length )
6629 return FALSE;
6630 for ( int i = 0; i < (int)s.length(); i++ ) {
6631 if ( doc[ pos + i ].lower() != s[ i ].lower() )
6632 return FALSE;
6633 }
6634 return TRUE;
6635}
6636
6637static bool qt_is_cell_in_use( QPtrList<QTextTableCell>& cells, int row, int col )
6638{
6639 for ( QTextTableCell* c = cells.first(); c; c = cells.next() ) {
6640 if ( row >= c->row() && row < c->row() + c->rowspan()
6641 && col >= c->column() && col < c->column() + c->colspan() )
6642 return TRUE;
6643 }
6644 return FALSE;
6645}
6646
6647QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt,
6648 const QChar* doc, int length, int& pos, QTextParag *curpar )
6649{
6650
6651 QTextTable* table = new QTextTable( this, attr );
6652 int row = -1;
6653 int col = -1;
6654
6655 QString rowbgcolor;
6656 QString rowalign;
6657 QString tablebgcolor = attr["bgcolor"];
6658
6659 QPtrList<QTextTableCell> multicells;
6660
6661 QString tagname;
6662 (void) eatSpace(doc, length, pos);
6663 while ( pos < length) {
6664 if (hasPrefix(doc, length, pos, QChar('<')) ){
6665 if (hasPrefix(doc, length, pos+1, QChar('/'))) {
6666 tagname = parseCloseTag( doc, length, pos );
6667 if ( tagname == "table" ) {
6668#if defined(PARSER_DEBUG)
6669 debug_indent.remove( debug_indent.length() - 3, 2 );
6670#endif
6671 return table;
6672 }
6673 } else {
6674 QMap<QString, QString> attr2;
6675 bool emptyTag = FALSE;
6676 tagname = parseOpenTag( doc, length, pos, attr2, emptyTag );
6677 if ( tagname == "tr" ) {
6678 rowbgcolor = attr2["bgcolor"];
6679 rowalign = attr2["align"];
6680 row++;
6681 col = -1;
6682 }
6683 else if ( tagname == "td" || tagname == "th" ) {
6684 col++;
6685 while ( qt_is_cell_in_use( multicells, row, col ) ) {
6686 col++;
6687 }
6688
6689 if ( row >= 0 && col >= 0 ) {
6690 const QStyleSheetItem* s = sheet_->item(tagname);
6691 if ( !attr2.contains("bgcolor") ) {
6692 if (!rowbgcolor.isEmpty() )
6693 attr2["bgcolor"] = rowbgcolor;
6694 else if (!tablebgcolor.isEmpty() )
6695 attr2["bgcolor"] = tablebgcolor;
6696 }
6697 if ( !attr2.contains("align") ) {
6698 if (!rowalign.isEmpty() )
6699 attr2["align"] = rowalign;
6700 }
6701
6702 // extract the cell contents
6703 int end = pos;
6704 while ( end < length
6705 && !hasPrefix( doc, length, end, "</td")
6706 && !hasPrefix( doc, length, end, "<td")
6707 && !hasPrefix( doc, length, end, "</th")
6708 && !hasPrefix( doc, length, end, "<th")
6709 && !hasPrefix( doc, length, end, "<td")
6710 && !hasPrefix( doc, length, end, "</tr")
6711 && !hasPrefix( doc, length, end, "<tr")
6712 && !hasPrefix( doc, length, end, "</table") ) {
6713 if ( hasPrefix( doc, length, end, "<table" ) ) { // nested table
6714 int nested = 1;
6715 ++end;
6716 while ( end < length && nested != 0 ) {
6717 if ( hasPrefix( doc, length, end, "</table" ) )
6718 nested--;
6719 if ( hasPrefix( doc, length, end, "<table" ) )
6720 nested++;
6721 end++;
6722 }
6723 }
6724 end++;
6725 }
6726 QTextTableCell* cell = new QTextTableCell( table, row, col,
6727 attr2, s, fmt.makeTextFormat( s, attr2 ),
6728 contxt, *factory_, sheet_,
6729 QString( doc, length).mid( pos, end - pos ) );
6730 cell->richText()->parParag = curpar;
6731 if ( cell->colspan() > 1 || cell->rowspan() > 1 )
6732 multicells.append( cell );
6733 col += cell->colspan()-1;
6734 pos = end;
6735 }
6736 }
6737 }
6738
6739 } else {
6740 ++pos;
6741 }
6742 }
6743#if defined(PARSER_DEBUG)
6744 debug_indent.remove( debug_indent.length() - 3, 2 );
6745#endif
6746 return table;
6747}
6748
6749bool QTextDocument::eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp )
6750{
6751 int old_pos = pos;
6752 while (pos < length && doc[pos].isSpace() && ( includeNbsp || (doc[pos] != QChar::nbsp ) ) )
6753 pos++;
6754 return old_pos < pos;
6755}
6756
6757bool QTextDocument::eat(const QChar* doc, int length, int& pos, QChar c)
6758{
6759 bool ok = pos < length && doc[pos] == c;
6760 if ( ok )
6761 pos++;
6762 return ok;
6763}
6764/*****************************************************************/
6765
6766struct Entity {
6767 const char * name;
6768 Q_UINT16 code;
6769};
6770
6771static const Entity entitylist [] = {
6772 { "AElig", 0x00c6 },
6773 { "Aacute", 0x00c1 },
6774 { "Acirc", 0x00c2 },
6775 { "Agrave", 0x00c0 },
6776 { "Alpha", 0x0391 },
6777 { "AMP", 38 },
6778 { "Aring", 0x00c5 },
6779 { "Atilde", 0x00c3 },
6780 { "Auml", 0x00c4 },
6781 { "Beta", 0x0392 },
6782 { "Ccedil", 0x00c7 },
6783 { "Chi", 0x03a7 },
6784 { "Dagger", 0x2021 },
6785 { "Delta", 0x0394 },
6786 { "ETH", 0x00d0 },
6787 { "Eacute", 0x00c9 },
6788 { "Ecirc", 0x00ca },
6789 { "Egrave", 0x00c8 },
6790 { "Epsilon", 0x0395 },
6791 { "Eta", 0x0397 },
6792 { "Euml", 0x00cb },
6793 { "Gamma", 0x0393 },
6794 { "GT", 62 },
6795 { "Iacute", 0x00cd },
6796 { "Icirc", 0x00ce },
6797 { "Igrave", 0x00cc },
6798 { "Iota", 0x0399 },
6799 { "Iuml", 0x00cf },
6800 { "Kappa", 0x039a },
6801 { "Lambda", 0x039b },
6802 { "LT", 60 },
6803 { "Mu", 0x039c },
6804 { "Ntilde", 0x00d1 },
6805 { "Nu", 0x039d },
6806 { "OElig", 0x0152 },
6807 { "Oacute", 0x00d3 },
6808 { "Ocirc", 0x00d4 },
6809 { "Ograve", 0x00d2 },
6810 { "Omega", 0x03a9 },
6811 { "Omicron", 0x039f },
6812 { "Oslash", 0x00d8 },
6813 { "Otilde", 0x00d5 },
6814 { "Ouml", 0x00d6 },
6815 { "Phi", 0x03a6 },
6816 { "Pi", 0x03a0 },
6817 { "Prime", 0x2033 },
6818 { "Psi", 0x03a8 },
6819 { "QUOT", 34 },
6820 { "Rho", 0x03a1 },
6821 { "Scaron", 0x0160 },
6822 { "Sigma", 0x03a3 },
6823 { "THORN", 0x00de },
6824 { "Tau", 0x03a4 },
6825 { "Theta", 0x0398 },
6826 { "Uacute", 0x00da },
6827 { "Ucirc", 0x00db },
6828 { "Ugrave", 0x00d9 },
6829 { "Upsilon", 0x03a5 },
6830 { "Uuml", 0x00dc },
6831 { "Xi", 0x039e },
6832 { "Yacute", 0x00dd },
6833 { "Yuml", 0x0178 },
6834 { "Zeta", 0x0396 },
6835 { "aacute", 0x00e1 },
6836 { "acirc", 0x00e2 },
6837 { "acute", 0x00b4 },
6838 { "aelig", 0x00e6 },
6839 { "agrave", 0x00e0 },
6840 { "alefsym", 0x2135 },
6841 { "alpha", 0x03b1 },
6842 { "amp", 38 },
6843 { "and", 0x22a5 },
6844 { "ang", 0x2220 },
6845 { "apos", 0x0027 },
6846 { "aring", 0x00e5 },
6847 { "asymp", 0x2248 },
6848 { "atilde", 0x00e3 },
6849 { "auml", 0x00e4 },
6850 { "bdquo", 0x201e },
6851 { "beta", 0x03b2 },
6852 { "brvbar", 0x00a6 },
6853 { "bull", 0x2022 },
6854 { "cap", 0x2229 },
6855 { "ccedil", 0x00e7 },
6856 { "cedil", 0x00b8 },
6857 { "cent", 0x00a2 },
6858 { "chi", 0x03c7 },
6859 { "circ", 0x02c6 },
6860 { "clubs", 0x2663 },
6861 { "cong", 0x2245 },
6862 { "copy", 0x00a9 },
6863 { "crarr", 0x21b5 },
6864 { "cup", 0x222a },
6865 { "curren", 0x00a4 },
6866 { "dArr", 0x21d3 },
6867 { "dagger", 0x2020 },
6868 { "darr", 0x2193 },
6869 { "deg", 0x00b0 },
6870 { "delta", 0x03b4 },
6871 { "diams", 0x2666 },
6872 { "divide", 0x00f7 },
6873 { "eacute", 0x00e9 },
6874 { "ecirc", 0x00ea },
6875 { "egrave", 0x00e8 },
6876 { "empty", 0x2205 },
6877 { "emsp", 0x2003 },
6878 { "ensp", 0x2002 },
6879 { "epsilon", 0x03b5 },
6880 { "equiv", 0x2261 },
6881 { "eta", 0x03b7 },
6882 { "eth", 0x00f0 },
6883 { "euml", 0x00eb },
6884 { "euro", 0x20ac },
6885 { "exist", 0x2203 },
6886 { "fnof", 0x0192 },
6887 { "forall", 0x2200 },
6888 { "frac12", 0x00bd },
6889 { "frac14", 0x00bc },
6890 { "frac34", 0x00be },
6891 { "frasl", 0x2044 },
6892 { "gamma", 0x03b3 },
6893 { "ge", 0x2265 },
6894 { "gt", 62 },
6895 { "hArr", 0x21d4 },
6896 { "harr", 0x2194 },
6897 { "hearts", 0x2665 },
6898 { "hellip", 0x2026 },
6899 { "iacute", 0x00ed },
6900 { "icirc", 0x00ee },
6901 { "iexcl", 0x00a1 },
6902 { "igrave", 0x00ec },
6903 { "image", 0x2111 },
6904 { "infin", 0x221e },
6905 { "int", 0x222b },
6906 { "iota", 0x03b9 },
6907 { "iquest", 0x00bf },
6908 { "isin", 0x2208 },
6909 { "iuml", 0x00ef },
6910 { "kappa", 0x03ba },
6911 { "lArr", 0x21d0 },
6912 { "lambda", 0x03bb },
6913 { "lang", 0x2329 },
6914 { "laquo", 0x00ab },
6915 { "larr", 0x2190 },
6916 { "lceil", 0x2308 },
6917 { "ldquo", 0x201c },
6918 { "le", 0x2264 },
6919 { "lfloor", 0x230a },
6920 { "lowast", 0x2217 },
6921 { "loz", 0x25ca },
6922 { "lrm", 0x200e },
6923 { "lsaquo", 0x2039 },
6924 { "lsquo", 0x2018 },
6925 { "lt", 60 },
6926 { "macr", 0x00af },
6927 { "mdash", 0x2014 },
6928 { "micro", 0x00b5 },
6929 { "middot", 0x00b7 },
6930 { "minus", 0x2212 },
6931 { "mu", 0x03bc },
6932 { "nabla", 0x2207 },
6933 { "nbsp", 0x00a0 },
6934 { "ndash", 0x2013 },
6935 { "ne", 0x2260 },
6936 { "ni", 0x220b },
6937 { "not", 0x00ac },
6938 { "notin", 0x2209 },
6939 { "nsub", 0x2284 },
6940 { "ntilde", 0x00f1 },
6941 { "nu", 0x03bd },
6942 { "oacute", 0x00f3 },
6943 { "ocirc", 0x00f4 },
6944 { "oelig", 0x0153 },
6945 { "ograve", 0x00f2 },
6946 { "oline", 0x203e },
6947 { "omega", 0x03c9 },
6948 { "omicron", 0x03bf },
6949 { "oplus", 0x2295 },
6950 { "or", 0x22a6 },
6951 { "ordf", 0x00aa },
6952 { "ordm", 0x00ba },
6953 { "oslash", 0x00f8 },
6954 { "otilde", 0x00f5 },
6955 { "otimes", 0x2297 },
6956 { "ouml", 0x00f6 },
6957 { "para", 0x00b6 },
6958 { "part", 0x2202 },
6959 { "percnt", 0x0025 },
6960 { "permil", 0x2030 },
6961 { "perp", 0x22a5 },
6962 { "phi", 0x03c6 },
6963 { "pi", 0x03c0 },
6964 { "piv", 0x03d6 },
6965 { "plusmn", 0x00b1 },
6966 { "pound", 0x00a3 },
6967 { "prime", 0x2032 },
6968 { "prod", 0x220f },
6969 { "prop", 0x221d },
6970 { "psi", 0x03c8 },
6971 { "quot", 34 },
6972 { "rArr", 0x21d2 },
6973 { "radic", 0x221a },
6974 { "rang", 0x232a },
6975 { "raquo", 0x00bb },
6976 { "rarr", 0x2192 },
6977 { "rceil", 0x2309 },
6978 { "rdquo", 0x201d },
6979 { "real", 0x211c },
6980 { "reg", 0x00ae },
6981 { "rfloor", 0x230b },
6982 { "rho", 0x03c1 },
6983 { "rlm", 0x200f },
6984 { "rsaquo", 0x203a },
6985 { "rsquo", 0x2019 },
6986 { "sbquo", 0x201a },
6987 { "scaron", 0x0161 },
6988 { "sdot", 0x22c5 },
6989 { "sect", 0x00a7 },
6990 { "shy", 0x00ad },
6991 { "sigma", 0x03c3 },
6992 { "sigmaf", 0x03c2 },
6993 { "sim", 0x223c },
6994 { "spades", 0x2660 },
6995 { "sub", 0x2282 },
6996 { "sube", 0x2286 },
6997 { "sum", 0x2211 },
6998 { "sup1", 0x00b9 },
6999 { "sup2", 0x00b2 },
7000 { "sup3", 0x00b3 },
7001 { "sup", 0x2283 },
7002 { "supe", 0x2287 },
7003 { "szlig", 0x00df },
7004 { "tau", 0x03c4 },
7005 { "there4", 0x2234 },
7006 { "theta", 0x03b8 },
7007 { "thetasym", 0x03d1 },
7008 { "thinsp", 0x2009 },
7009 { "thorn", 0x00fe },
7010 { "tilde", 0x02dc },
7011 { "times", 0x00d7 },
7012 { "trade", 0x2122 },
7013 { "uArr", 0x21d1 },
7014 { "uacute", 0x00fa },
7015 { "uarr", 0x2191 },
7016 { "ucirc", 0x00fb },
7017 { "ugrave", 0x00f9 },
7018 { "uml", 0x00a8 },
7019 { "upsih", 0x03d2 },
7020 { "upsilon", 0x03c5 },
7021 { "uuml", 0x00fc },
7022 { "weierp", 0x2118 },
7023 { "xi", 0x03be },
7024 { "yacute", 0x00fd },
7025 { "yen", 0x00a5 },
7026 { "yuml", 0x00ff },
7027 { "zeta", 0x03b6 },
7028 { "zwj", 0x200d },
7029 { "zwnj", 0x200c },
7030 { "", 0x0000 }
7031};
7032
7033
7034
7035
7036
7037static QMap<QCString, QChar> *html_map = 0;
7038static void qt_cleanup_html_map()
7039{
7040 delete html_map;
7041 html_map = 0;
7042}
7043
7044static QMap<QCString, QChar> *htmlMap()
7045{
7046 if ( !html_map ) {
7047 html_map = new QMap<QCString, QChar>;
7048 qAddPostRoutine( qt_cleanup_html_map );
7049
7050 const Entity *ent = entitylist;
7051 while( ent->code ) {
7052 html_map->insert( ent->name, QChar(ent->code) );
7053 ent++;
7054 }
7055 }
7056 return html_map;
7057}
7058
7059QChar QTextDocument::parseHTMLSpecialChar(const QChar* doc, int length, int& pos)
7060{
7061 QCString s;
7062 pos++;
7063 int recoverpos = pos;
7064 while ( pos < length && doc[pos] != ';' && !doc[pos].isSpace() && pos < recoverpos + 6) {
7065 s += doc[pos];
7066 pos++;
7067 }
7068 if (doc[pos] != ';' && !doc[pos].isSpace() ) {
7069 pos = recoverpos;
7070 return '&';
7071 }
7072 pos++;
7073
7074 if ( s.length() > 1 && s[0] == '#') {
7075 int num = s.mid(1).toInt();
7076 if ( num == 151 ) // ### hack for designer manual
7077 return '-';
7078 return num;
7079 }
7080
7081 QMap<QCString, QChar>::Iterator it = htmlMap()->find(s);
7082 if ( it != htmlMap()->end() ) {
7083 return *it;
7084 }
7085
7086 pos = recoverpos;
7087 return '&';
7088}
7089
7090QString QTextDocument::parseWord(const QChar* doc, int length, int& pos, bool lower)
7091{
7092 QString s;
7093
7094 if (doc[pos] == '"') {
7095 pos++;
7096 while ( pos < length && doc[pos] != '"' ) {
7097 s += doc[pos];
7098 pos++;
7099 }
7100 eat(doc, length, pos, '"');
7101 } else {
7102 static QString term = QString::fromLatin1("/>");
7103 while( pos < length &&
7104 (doc[pos] != '>' && !hasPrefix( doc, length, pos, term))
7105 && doc[pos] != '<'
7106 && doc[pos] != '='
7107 && !doc[pos].isSpace())
7108 {
7109 if ( doc[pos] == '&')
7110 s += parseHTMLSpecialChar( doc, length, pos );
7111 else {
7112 s += doc[pos];
7113 pos++;
7114 }
7115 }
7116 if (lower)
7117 s = s.lower();
7118 }
7119 return s;
7120}
7121
7122QChar QTextDocument::parseChar(const QChar* doc, int length, int& pos, QStyleSheetItem::WhiteSpaceMode wsm )
7123{
7124 if ( pos >= length )
7125 return QChar::null;
7126
7127 QChar c = doc[pos++];
7128
7129 if (c == '<' )
7130 return QChar::null;
7131
7132 if ( c.isSpace() && c != QChar::nbsp ) {
7133 if ( wsm == QStyleSheetItem::WhiteSpacePre ) {
7134 if ( c == ' ' )
7135 return QChar::nbsp;
7136 else
7137 return c;
7138 } else if ( wsm == QStyleSheetItem_WhiteSpaceNoCompression ) {
7139 return c;
7140 } else if ( wsm == QStyleSheetItem_WhiteSpaceNormalWithNewlines ) {
7141 if ( c == '\n' )
7142 return c;
7143 while ( pos< length &&
7144 doc[pos].isSpace() && doc[pos] != QChar::nbsp && doc[pos] != '\n' )
7145 pos++;
7146 return ' ';
7147 } else { // non-pre mode: collapse whitespace except nbsp
7148 while ( pos< length &&
7149 doc[pos].isSpace() && doc[pos] != QChar::nbsp )
7150 pos++;
7151 if ( wsm == QStyleSheetItem::WhiteSpaceNoWrap )
7152 return QChar::nbsp;
7153 else
7154 return ' ';
7155 }
7156 }
7157 else if ( c == '&' )
7158 return parseHTMLSpecialChar( doc, length, --pos );
7159 else
7160 return c;
7161}
7162
7163QString QTextDocument::parseOpenTag(const QChar* doc, int length, int& pos,
7164 QMap<QString, QString> &attr, bool& emptyTag)
7165{
7166 emptyTag = FALSE;
7167 pos++;
7168 if ( hasPrefix(doc, length, pos, '!') ) {
7169 if ( hasPrefix( doc, length, pos+1, "--")) {
7170 pos += 3;
7171 // eat comments
7172 QString pref = QString::fromLatin1("-->");
7173 while ( !hasPrefix(doc, length, pos, pref ) && pos < length )
7174 pos++;
7175 if ( hasPrefix(doc, length, pos, pref ) ) {
7176 pos += 3;
7177 eatSpace(doc, length, pos, TRUE);
7178 }
7179 emptyTag = TRUE;
7180 return QString::null;
7181 }
7182 else {
7183 // eat strange internal tags
7184 while ( !hasPrefix(doc, length, pos, '>') && pos < length )
7185 pos++;
7186 if ( hasPrefix(doc, length, pos, '>') ) {
7187 pos++;
7188 eatSpace(doc, length, pos, TRUE);
7189 }
7190 return QString::null;
7191 }
7192 }
7193
7194 QString tag = parseWord(doc, length, pos );
7195 eatSpace(doc, length, pos, TRUE);
7196 static QString term = QString::fromLatin1("/>");
7197 static QString s_TRUE = QString::fromLatin1("TRUE");
7198
7199 while (doc[pos] != '>' && ! (emptyTag = hasPrefix(doc, length, pos, term) )) {
7200 QString key = parseWord(doc, length, pos );
7201 eatSpace(doc, length, pos, TRUE);
7202 if ( key.isEmpty()) {
7203 // error recovery
7204 while ( pos < length && doc[pos] != '>' )
7205 pos++;
7206 break;
7207 }
7208 QString value;
7209 if (hasPrefix(doc, length, pos, '=') ){
7210 pos++;
7211 eatSpace(doc, length, pos);
7212 value = parseWord(doc, length, pos, FALSE);
7213 }
7214 else
7215 value = s_TRUE;
7216 attr.insert(key.lower(), value );
7217 eatSpace(doc, length, pos, TRUE);
7218 }
7219
7220 if (emptyTag) {
7221 eat(doc, length, pos, '/');
7222 eat(doc, length, pos, '>');
7223 }
7224 else
7225 eat(doc, length, pos, '>');
7226
7227 return tag;
7228}
7229
7230QString QTextDocument::parseCloseTag( const QChar* doc, int length, int& pos )
7231{
7232 pos++;
7233 pos++;
7234 QString tag = parseWord(doc, length, pos );
7235 eatSpace(doc, length, pos, TRUE);
7236 eat(doc, length, pos, '>');
7237 return tag;
7238}
7239
7240QTextFlow::QTextFlow()
7241{
7242 w = pagesize = 0;
7243 leftItems.setAutoDelete( FALSE );
7244 rightItems.setAutoDelete( FALSE );
7245}
7246
7247QTextFlow::~QTextFlow()
7248{
7249}
7250
7251void QTextFlow::clear()
7252{
7253 leftItems.clear();
7254 rightItems.clear();
7255}
7256
7257void QTextFlow::setWidth( int width )
7258{
7259 w = width;
7260}
7261
7262int QTextFlow::adjustLMargin( int yp, int, int margin, int space )
7263{
7264 for ( QTextCustomItem* item = leftItems.first(); item; item = leftItems.next() ) {
7265 if ( item->ypos == -1 )
7266 continue;
7267 if ( yp >= item->ypos && yp < item->ypos + item->height )
7268 margin = QMAX( margin, item->xpos + item->width + space );
7269 }
7270 return margin;
7271}
7272
7273int QTextFlow::adjustRMargin( int yp, int, int margin, int space )
7274{
7275 for ( QTextCustomItem* item = rightItems.first(); item; item = rightItems.next() ) {
7276 if ( item->ypos == -1 )
7277 continue;
7278 if ( yp >= item->ypos && yp < item->ypos + item->height )
7279 margin = QMAX( margin, w - item->xpos - space );
7280 }
7281 return margin;
7282}
7283
7284
7285int QTextFlow::adjustFlow( int y, int /*w*/, int h )
7286{
7287 if ( pagesize > 0 ) { // check pages
7288 int yinpage = y % pagesize;
7289 if ( yinpage <= border_tolerance )
7290 return border_tolerance - yinpage;
7291 else
7292 if ( yinpage + h > pagesize - border_tolerance )
7293 return ( pagesize - yinpage ) + border_tolerance;
7294 }
7295 return 0;
7296}
7297
7298void QTextFlow::unregisterFloatingItem( QTextCustomItem* item )
7299{
7300 leftItems.removeRef( item );
7301 rightItems.removeRef( item );
7302}
7303
7304void QTextFlow::registerFloatingItem( QTextCustomItem* item )
7305{
7306 if ( item->placement() == QTextCustomItem::PlaceRight ) {
7307 if ( !rightItems.contains( item ) )
7308 rightItems.append( item );
7309 } else if ( item->placement() == QTextCustomItem::PlaceLeft &&
7310 !leftItems.contains( item ) ) {
7311 leftItems.append( item );
7312 }
7313}
7314
7315QRect QTextFlow::boundingRect() const
7316{
7317 QRect br;
7318 QPtrListIterator<QTextCustomItem> l( leftItems );
7319 while( l.current() ) {
7320 br = br.unite( l.current()->geometry() );
7321 ++l;
7322 }
7323 QPtrListIterator<QTextCustomItem> r( rightItems );
7324 while( r.current() ) {
7325 br = br.unite( r.current()->geometry() );
7326 ++r;
7327 }
7328 return br;
7329}
7330
7331
7332void QTextFlow::drawFloatingItems( QPainter* p, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
7333{
7334 QTextCustomItem *item;
7335 for ( item = leftItems.first(); item; item = leftItems.next() ) {
7336 if ( item->xpos == -1 || item->ypos == -1 )
7337 continue;
7338 item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected );
7339 }
7340
7341 for ( item = rightItems.first(); item; item = rightItems.next() ) {
7342 if ( item->xpos == -1 || item->ypos == -1 )
7343 continue;
7344 item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected );
7345 }
7346}
7347
7348// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7349
7350void QTextCustomItem::pageBreak( int /*y*/ , QTextFlow* /*flow*/ )
7351{
7352}
7353
7354QTextTable::QTextTable( QTextDocument *p, const QMap<QString, QString> & attr )
7355 : QTextCustomItem( p )
7356{
7357 cells.setAutoDelete( FALSE );
7358#if defined(PARSER_DEBUG)
7359 debug_indent += "\t";
7360 qDebug( debug_indent + "new QTextTable (%p)", this );
7361 debug_indent += "\t";
7362#endif
7363 cellspacing = 2;
7364 if ( attr.contains("cellspacing") )
7365 cellspacing = attr["cellspacing"].toInt();
7366 cellpadding = 1;
7367 if ( attr.contains("cellpadding") )
7368 cellpadding = attr["cellpadding"].toInt();
7369 border = innerborder = 0;
7370 if ( attr.contains("border" ) ) {
7371 QString s( attr["border"] );
7372 if ( s == "TRUE" )
7373 border = 1;
7374 else
7375 border = attr["border"].toInt();
7376 }
7377 us_b = border;
7378
7379 innerborder = us_ib = border ? 1 : 0;
7380
7381 if ( border )
7382 cellspacing += 2;
7383
7384 us_ib = innerborder;
7385 us_cs = cellspacing;
7386 us_cp = cellpadding;
7387 outerborder = cellspacing + border;
7388 us_ob = outerborder;
7389 layout = new QGridLayout( 1, 1, cellspacing );
7390
7391 fixwidth = 0;
7392 stretch = 0;
7393 if ( attr.contains("width") ) {
7394 bool b;
7395 QString s( attr["width"] );
7396 int w = s.toInt( &b );
7397 if ( b ) {
7398 fixwidth = w;
7399 } else {
7400 s = s.stripWhiteSpace();
7401 if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' )
7402 stretch = s.left( s.length()-1).toInt();
7403 }
7404 }
7405
7406 place = PlaceInline;
7407 if ( attr["align"] == "left" )
7408 place = PlaceLeft;
7409 else if ( attr["align"] == "right" )
7410 place = PlaceRight;
7411 cachewidth = 0;
7412 attributes = attr;
7413 pageBreakFor = -1;
7414}
7415
7416QTextTable::~QTextTable()
7417{
7418 delete layout;
7419}
7420
7421QString QTextTable::richText() const
7422{
7423 QString s;
7424 s = "<table ";
7425 QMap<QString, QString>::ConstIterator it = attributes.begin();
7426 for ( ; it != attributes.end(); ++it )
7427 s += it.key() + "=" + *it + " ";
7428 s += ">\n";
7429
7430 int lastRow = -1;
7431 bool needEnd = FALSE;
7432 QPtrListIterator<QTextTableCell> it2( cells );
7433 while ( it2.current() ) {
7434 QTextTableCell *cell = it2.current();
7435 ++it2;
7436 if ( lastRow != cell->row() ) {
7437 if ( lastRow != -1 )
7438 s += "</tr>\n";
7439 s += "<tr>";
7440 lastRow = cell->row();
7441 needEnd = TRUE;
7442 }
7443 s += "<td ";
7444 it = cell->attributes.begin();
7445 for ( ; it != cell->attributes.end(); ++it )
7446 s += it.key() + "=" + *it + " ";
7447 s += ">";
7448 s += cell->richText()->richText();
7449 s += "</td>";
7450 }
7451 if ( needEnd )
7452 s += "</tr>\n";
7453 s += "</table>\n";
7454 return s;
7455}
7456
7457void QTextTable::adjustToPainter( QPainter* p )
7458{
7459 cellspacing = scale( us_cs, p );
7460 cellpadding = scale( us_cp, p );
7461 border = scale( us_b , p );
7462 innerborder = scale( us_ib, p );
7463 outerborder = scale( us_ob ,p );
7464 width = 0;
7465 cachewidth = 0;
7466 for ( QTextTableCell* cell = cells.first(); cell; cell = cells.next() )
7467 cell->adjustToPainter( p );
7468}
7469
7470void QTextTable::adjustCells( int y , int shift )
7471{
7472 QPtrListIterator<QTextTableCell> it( cells );
7473 QTextTableCell* cell;
7474 bool enlarge = FALSE;
7475 while ( ( cell = it.current() ) ) {
7476 ++it;
7477 QRect r = cell->geometry();
7478 if ( y <= r.top() ) {
7479 r.moveBy(0, shift );
7480 cell->setGeometry( r );
7481 enlarge = TRUE;
7482 } else if ( y <= r.bottom() ) {
7483 r.rBottom() += shift;
7484 cell->setGeometry( r );
7485 enlarge = TRUE;
7486 }
7487 }
7488 if ( enlarge )
7489 height += shift;
7490}
7491
7492void QTextTable::pageBreak( int yt, QTextFlow* flow )
7493{
7494 if ( flow->pageSize() <= 0 )
7495 return;
7496 if ( layout && pageBreakFor > 0 && pageBreakFor != yt ) {
7497 layout->invalidate();
7498 int h = layout->heightForWidth( width-2*outerborder );
7499 layout->setGeometry( QRect(0, 0, width-2*outerborder, h) );
7500 height = layout->geometry().height()+2*outerborder;
7501 }
7502 pageBreakFor = yt;
7503 QPtrListIterator<QTextTableCell> it( cells );
7504 QTextTableCell* cell;
7505 while ( ( cell = it.current() ) ) {
7506 ++it;
7507 int y = yt + outerborder + cell->geometry().y();
7508 int shift = flow->adjustFlow( y - cellspacing, width, cell->richText()->height() + 2*cellspacing );
7509 adjustCells( y - outerborder - yt, shift );
7510 }
7511}
7512
7513
7514void QTextTable::draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
7515{
7516 if ( placement() != PlaceInline ) {
7517 x = xpos;
7518 y = ypos;
7519 }
7520
7521 for (QTextTableCell* cell = cells.first(); cell; cell = cells.next() ) {
7522 if ( cx < 0 && cy < 0 ||
7523 QRect( cx, cy, cw, ch ).intersects( QRect( x + outerborder + cell->geometry().x(),
7524 y + outerborder + cell->geometry().y(),
7525 cell->geometry().width(), cell->geometry().height() ) ) ) {
7526 cell->draw( p, x+outerborder, y+outerborder, cx, cy, cw, ch, cg, selected );
7527 if ( border ) {
7528 QRect r( x+outerborder+cell->geometry().x() - innerborder,
7529 y+outerborder+cell->geometry().y() - innerborder,
7530 cell->geometry().width() + 2 * innerborder,
7531 cell->geometry().height() + 2 * innerborder );
7532 if ( is_printer( p ) ) {
7533 QPen oldPen = p->pen();
7534 QRect r2 = r;
7535 r2.setLeft( r2.left() + innerborder/2 );
7536 r2.setTop( r2.top() + innerborder/2 );
7537 r2.setRight( r2.right() - innerborder/2 );
7538 r2.setBottom( r2.bottom() - innerborder/2 );
7539 p->setPen( QPen( cg.text(), innerborder ) );
7540 p->drawRect( r2 );
7541 p->setPen( oldPen );
7542 } else {
7543 int s = QMAX( cellspacing-2*innerborder, 0);
7544 if ( s ) {
7545 p->fillRect( r.left()-s, r.top(), s+1, r.height(), cg.button() );
7546 p->fillRect( r.right(), r.top(), s+1, r.height(), cg.button() );
7547 p->fillRect( r.left()-s, r.top()-s, r.width()+2*s, s, cg.button() );
7548 p->fillRect( r.left()-s, r.bottom(), r.width()+2*s, s, cg.button() );
7549 }
7550 qDrawShadePanel( p, r, cg, TRUE, innerborder );
7551 }
7552 }
7553 }
7554 }
7555 if ( border ) {
7556 QRect r ( x, y, width, height );
7557 if ( is_printer( p ) ) {
7558 QRect r2 = r;
7559 r2.setLeft( r2.left() + border/2 );
7560 r2.setTop( r2.top() + border/2 );
7561 r2.setRight( r2.right() - border/2 );
7562 r2.setBottom( r2.bottom() - border/2 );
7563 QPen oldPen = p->pen();
7564 p->setPen( QPen( cg.text(), border ) );
7565 p->drawRect( r2 );
7566 p->setPen( oldPen );
7567 } else {
7568 int s = border+QMAX( cellspacing-2*innerborder, 0);
7569 if ( s ) {
7570 p->fillRect( r.left(), r.top(), s, r.height(), cg.button() );
7571 p->fillRect( r.right()-s, r.top(), s, r.height(), cg.button() );
7572 p->fillRect( r.left(), r.top(), r.width(), s, cg.button() );
7573 p->fillRect( r.left(), r.bottom()-s, r.width(), s, cg.button() );
7574 }
7575 qDrawShadePanel( p, r, cg, FALSE, border );
7576 }
7577 }
7578
7579#if defined(DEBUG_TABLE_RENDERING)
7580 p->save();
7581 p->setPen( Qt::red );
7582 p->drawRect( x, y, width, height );
7583 p->restore();
7584#endif
7585}
7586
7587int QTextTable::minimumWidth() const
7588{
7589 return (layout ? layout->minimumSize().width() : 0) + 2 * outerborder;
7590}
7591
7592void QTextTable::resize( int nwidth )
7593{
7594 if ( fixwidth && cachewidth != 0 )
7595 return;
7596 if ( nwidth == cachewidth )
7597 return;
7598
7599
7600 cachewidth = nwidth;
7601 int w = nwidth;
7602
7603 format( w );
7604
7605 if ( stretch )
7606 nwidth = nwidth * stretch / 100;
7607
7608 width = nwidth;
7609 layout->invalidate();
7610 int shw = layout->sizeHint().width() + 2*outerborder;
7611 int mw = layout->minimumSize().width() + 2*outerborder;
7612 if ( stretch )
7613 width = QMAX( mw, nwidth );
7614 else
7615 width = QMAX( mw, QMIN( nwidth, shw ) );
7616
7617 if ( fixwidth )
7618 width = fixwidth;
7619
7620 layout->invalidate();
7621 mw = layout->minimumSize().width() + 2*outerborder;
7622 width = QMAX( width, mw );
7623
7624 int h = layout->heightForWidth( width-2*outerborder );
7625 layout->setGeometry( QRect(0, 0, width-2*outerborder, h) );
7626 height = layout->geometry().height()+2*outerborder;
7627}
7628
7629void QTextTable::format( int w )
7630{
7631 for ( int i = 0; i < (int)cells.count(); ++i ) {
7632 QTextTableCell *cell = cells.at( i );
7633 QRect r = cell->geometry();
7634 r.setWidth( w - 2*outerborder );
7635 cell->setGeometry( r );
7636 }
7637}
7638
7639void QTextTable::addCell( QTextTableCell* cell )
7640{
7641 cells.append( cell );
7642 layout->addMultiCell( cell, cell->row(), cell->row() + cell->rowspan()-1,
7643 cell->column(), cell->column() + cell->colspan()-1 );
7644}
7645
7646bool QTextTable::enter( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, bool atEnd )
7647{
7648 currCell.remove( c );
7649 if ( !atEnd )
7650 return next( c, doc, parag, idx, ox, oy );
7651 currCell.insert( c, cells.count() );
7652 return prev( c, doc, parag, idx, ox, oy );
7653}
7654
7655bool QTextTable::enterAt( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, const QPoint &pos )
7656{
7657 currCell.remove( c );
7658 int lastCell = -1;
7659 int lastY = -1;
7660 int i;
7661 for ( i = 0; i < (int)cells.count(); ++i ) {
7662 QTextTableCell *cell = cells.at( i );
7663 if ( !cell )
7664 continue;
7665 QRect r( cell->geometry().x(),
7666 cell->geometry().y(),
7667 cell->geometry().width() + 2 * innerborder + 2 * outerborder,
7668 cell->geometry().height() + 2 * innerborder + 2 * outerborder );
7669
7670 if ( r.left() <= pos.x() && r.right() >= pos.x() ) {
7671 if ( cell->geometry().y() > lastY ) {
7672 lastCell = i;
7673 lastY = cell->geometry().y();
7674 }
7675 if ( r.top() <= pos.y() && r.bottom() >= pos.y() ) {
7676 currCell.insert( c, i );
7677 break;
7678 }
7679 }
7680 }
7681 if ( i == (int) cells.count() )
7682 return FALSE; // no cell found
7683
7684 if ( currCell.find( c ) == currCell.end() ) {
7685 if ( lastY != -1 )
7686 currCell.insert( c, lastCell );
7687 else
7688 return FALSE;
7689 }
7690
7691 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7692 if ( !cell )
7693 return FALSE;
7694 doc = cell->richText();
7695 parag = doc->firstParag();
7696 idx = 0;
7697 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7698 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7699 return TRUE;
7700}
7701
7702bool QTextTable::next( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
7703{
7704 int cc = -1;
7705 if ( currCell.find( c ) != currCell.end() )
7706 cc = *currCell.find( c );
7707 if ( cc > (int)cells.count() - 1 || cc < 0 )
7708 cc = -1;
7709 currCell.remove( c );
7710 currCell.insert( c, ++cc );
7711 if ( cc >= (int)cells.count() ) {
7712 currCell.insert( c, 0 );
7713 QTextCustomItem::next( c, doc, parag, idx, ox, oy );
7714 QTextTableCell *cell = cells.first();
7715 if ( !cell )
7716 return FALSE;
7717 doc = cell->richText();
7718 idx = -1;
7719 return TRUE;
7720 }
7721
7722 if ( currCell.find( c ) == currCell.end() )
7723 return FALSE;
7724 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7725 if ( !cell )
7726 return FALSE;
7727 doc = cell->richText();
7728 parag = doc->firstParag();
7729 idx = 0;
7730 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7731 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7732 return TRUE;
7733}
7734
7735bool QTextTable::prev( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
7736{
7737 int cc = -1;
7738 if ( currCell.find( c ) != currCell.end() )
7739 cc = *currCell.find( c );
7740 if ( cc > (int)cells.count() - 1 || cc < 0 )
7741 cc = cells.count();
7742 currCell.remove( c );
7743 currCell.insert( c, --cc );
7744 if ( cc < 0 ) {
7745 currCell.insert( c, 0 );
7746 QTextCustomItem::prev( c, doc, parag, idx, ox, oy );
7747 QTextTableCell *cell = cells.first();
7748 if ( !cell )
7749 return FALSE;
7750 doc = cell->richText();
7751 idx = -1;
7752 return TRUE;
7753 }
7754
7755 if ( currCell.find( c ) == currCell.end() )
7756 return FALSE;
7757 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7758 if ( !cell )
7759 return FALSE;
7760 doc = cell->richText();
7761 parag = doc->firstParag();
7762 idx = parag->length() - 1;
7763 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7764 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7765 return TRUE;
7766}
7767
7768bool QTextTable::down( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
7769{
7770 if ( currCell.find( c ) == currCell.end() )
7771 return FALSE;
7772 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7773 if ( cell->row_ == layout->numRows() - 1 ) {
7774 currCell.insert( c, 0 );
7775 QTextCustomItem::down( c, doc, parag, idx, ox, oy );
7776 QTextTableCell *cell = cells.first();
7777 if ( !cell )
7778 return FALSE;
7779 doc = cell->richText();
7780 idx = -1;
7781 return TRUE;
7782 }
7783
7784 int oldRow = cell->row_;
7785 int oldCol = cell->col_;
7786 if ( currCell.find( c ) == currCell.end() )
7787 return FALSE;
7788 int cc = *currCell.find( c );
7789 for ( int i = cc; i < (int)cells.count(); ++i ) {
7790 cell = cells.at( i );
7791 if ( cell->row_ > oldRow && cell->col_ == oldCol ) {
7792 currCell.insert( c, i );
7793 break;
7794 }
7795 }
7796 doc = cell->richText();
7797 if ( !cell )
7798 return FALSE;
7799 parag = doc->firstParag();
7800 idx = 0;
7801 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7802 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7803 return TRUE;
7804}
7805
7806bool QTextTable::up( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
7807{
7808 if ( currCell.find( c ) == currCell.end() )
7809 return FALSE;
7810 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7811 if ( cell->row_ == 0 ) {
7812 currCell.insert( c, 0 );
7813 QTextCustomItem::up( c, doc, parag, idx, ox, oy );
7814 QTextTableCell *cell = cells.first();
7815 if ( !cell )
7816 return FALSE;
7817 doc = cell->richText();
7818 idx = -1;
7819 return TRUE;
7820 }
7821
7822 int oldRow = cell->row_;
7823 int oldCol = cell->col_;
7824 if ( currCell.find( c ) == currCell.end() )
7825 return FALSE;
7826 int cc = *currCell.find( c );
7827 for ( int i = cc; i >= 0; --i ) {
7828 cell = cells.at( i );
7829 if ( cell->row_ < oldRow && cell->col_ == oldCol ) {
7830 currCell.insert( c, i );
7831 break;
7832 }
7833 }
7834 doc = cell->richText();
7835 if ( !cell )
7836 return FALSE;
7837 parag = doc->lastParag();
7838 idx = parag->length() - 1;
7839 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7840 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7841 return TRUE;
7842}
7843
7844QTextTableCell::QTextTableCell( QTextTable* table,
7845 int row, int column,
7846 const QMap<QString, QString> &attr,
7847 const QStyleSheetItem* /*style*/, // ### use them
7848 const QTextFormat& /*fmt*/, const QString& context,
7849 QMimeSourceFactory &factory, QStyleSheet *sheet,
7850 const QString& doc)
7851{
7852#if defined(PARSER_DEBUG)
7853 qDebug( debug_indent + "new QTextTableCell1 (pappi: %p)", table );
7854 qDebug( debug_indent + doc );
7855#endif
7856 cached_width = -1;
7857 cached_sizehint = -1;
7858
7859 maxw = QWIDGETSIZE_MAX;
7860 minw = 0;
7861
7862 parent = table;
7863 row_ = row;
7864 col_ = column;
7865 stretch_ = 0;
7866 richtext = new QTextDocument( table->parent );
7867 richtext->setTableCell( this );
7868 QString a = *attr.find( "align" );
7869 if ( !a.isEmpty() ) {
7870 a = a.lower();
7871 if ( a == "left" )
7872 richtext->setAlignment( Qt::AlignLeft );
7873 else if ( a == "center" )
7874 richtext->setAlignment( Qt::AlignHCenter );
7875 else if ( a == "right" )
7876 richtext->setAlignment( Qt::AlignRight );
7877 }
7878 align = 0;
7879 QString va = *attr.find( "valign" );
7880 if ( !va.isEmpty() ) {
7881 va = va.lower();
7882 if ( va == "center" )
7883 align |= Qt::AlignVCenter;
7884 else if ( va == "bottom" )
7885 align |= Qt::AlignBottom;
7886 }
7887 richtext->setFormatter( table->parent->formatter() );
7888 richtext->setUseFormatCollection( table->parent->useFormatCollection() );
7889 richtext->setMimeSourceFactory( &factory );
7890 richtext->setStyleSheet( sheet );
7891 richtext->setDefaultFont( table->parent->formatCollection()->defaultFormat()->font() );
7892 richtext->setRichText( doc, context );
7893 rowspan_ = 1;
7894 colspan_ = 1;
7895 if ( attr.contains("colspan") )
7896 colspan_ = attr["colspan"].toInt();
7897 if ( attr.contains("rowspan") )
7898 rowspan_ = attr["rowspan"].toInt();
7899
7900 background = 0;
7901 if ( attr.contains("bgcolor") ) {
7902 background = new QBrush(QColor( attr["bgcolor"] ));
7903 }
7904
7905
7906 hasFixedWidth = FALSE;
7907 if ( attr.contains("width") ) {
7908 bool b;
7909 QString s( attr["width"] );
7910 int w = s.toInt( &b );
7911 if ( b ) {
7912 maxw = w;
7913 minw = maxw;
7914 hasFixedWidth = TRUE;
7915 } else {
7916 s = s.stripWhiteSpace();
7917 if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' )
7918 stretch_ = s.left( s.length()-1).toInt();
7919 }
7920 }
7921
7922 attributes = attr;
7923
7924 parent->addCell( this );
7925}
7926
7927QTextTableCell::QTextTableCell( QTextTable* table, int row, int column )
7928{
7929#if defined(PARSER_DEBUG)
7930 qDebug( debug_indent + "new QTextTableCell2( pappi: %p", table );
7931#endif
7932 maxw = QWIDGETSIZE_MAX;
7933 minw = 0;
7934 cached_width = -1;
7935 cached_sizehint = -1;
7936
7937 parent = table;
7938 row_ = row;
7939 col_ = column;
7940 stretch_ = 0;
7941 richtext = new QTextDocument( table->parent );
7942 richtext->setTableCell( this );
7943 richtext->setFormatter( table->parent->formatter() );
7944 richtext->setUseFormatCollection( table->parent->useFormatCollection() );
7945 richtext->setDefaultFont( table->parent->formatCollection()->defaultFormat()->font() );
7946 richtext->setRichText( "<html></html>", QString::null );
7947 rowspan_ = 1;
7948 colspan_ = 1;
7949 background = 0;
7950 hasFixedWidth = FALSE;
7951 parent->addCell( this );
7952}
7953
7954
7955QTextTableCell::~QTextTableCell()
7956{
7957 delete background;
7958 background = 0;
7959 delete richtext;
7960 richtext = 0;
7961}
7962
7963QSize QTextTableCell::sizeHint() const
7964{
7965 int extra = 2 * ( parent->innerborder + parent->cellpadding + border_tolerance);
7966 int used = richtext->widthUsed() + extra;
7967
7968 if (stretch_ ) {
7969 int w = parent->width * stretch_ / 100 - 2*parent->cellspacing - 2*parent->cellpadding;
7970 return QSize( QMIN( w, maxw ), 0 ).expandedTo( minimumSize() );
7971 }
7972
7973 return QSize( used, 0 ).expandedTo( minimumSize() );
7974}
7975
7976QSize QTextTableCell::minimumSize() const
7977{
7978 int extra = 2 * ( parent->innerborder + parent->cellpadding + border_tolerance);
7979 return QSize( QMAX( richtext->minimumWidth() + extra, minw), 0 );
7980}
7981
7982QSize QTextTableCell::maximumSize() const
7983{
7984 return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
7985}
7986
7987QSizePolicy::ExpandData QTextTableCell::expanding() const
7988{
7989 return QSizePolicy::BothDirections;
7990}
7991
7992bool QTextTableCell::isEmpty() const
7993{
7994 return FALSE;
7995}
7996void QTextTableCell::setGeometry( const QRect& r )
7997{
7998 int extra = 2 * ( parent->innerborder + parent->cellpadding );
7999 if ( r.width() != cached_width )
8000 richtext->doLayout( QTextFormat::painter(), r.width() - extra );
8001 cached_width = r.width();
8002 geom = r;
8003}
8004
8005QRect QTextTableCell::geometry() const
8006{
8007 return geom;
8008}
8009
8010bool QTextTableCell::hasHeightForWidth() const
8011{
8012 return TRUE;
8013}
8014
8015int QTextTableCell::heightForWidth( int w ) const
8016{
8017 int extra = 2 * ( parent->innerborder + parent->cellpadding );
8018 w = QMAX( minw, w );
8019
8020 if ( cached_width != w ) {
8021 QTextTableCell* that = (QTextTableCell*) this;
8022 that->richtext->doLayout( QTextFormat::painter(), w - extra );
8023 that->cached_width = w;
8024 }
8025 return richtext->height() + extra;
8026}
8027
8028void QTextTableCell::adjustToPainter( QPainter* p )
8029{
8030 QTextParag *parag = richtext->firstParag();
8031 while ( parag ) {
8032 parag->adjustToPainter( p );
8033 parag = parag->next();
8034 }
8035}
8036
8037int QTextTableCell::horizontalAlignmentOffset() const
8038{
8039 return parent->cellpadding;
8040}
8041
8042int QTextTableCell::verticalAlignmentOffset() const
8043{
8044 if ( (align & Qt::AlignVCenter ) == Qt::AlignVCenter )
8045 return ( geom.height() - richtext->height() ) / 2;
8046 else if ( ( align & Qt::AlignBottom ) == Qt::AlignBottom )
8047 return geom.height() - parent->cellpadding - richtext->height() ;
8048 return parent->cellpadding;
8049}
8050
8051void QTextTableCell::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool )
8052{
8053 if ( cached_width != geom.width() ) {
8054 int extra = 2 * ( parent->innerborder + parent->cellpadding );
8055 richtext->doLayout( p, geom.width() - extra );
8056 cached_width = geom.width();
8057 }
8058 QColorGroup g( cg );
8059 if ( background )
8060 g.setBrush( QColorGroup::Base, *background );
8061 else if ( richtext->paper() )
8062 g.setBrush( QColorGroup::Base, *richtext->paper() );
8063
8064 p->save();
8065 p->translate( x + geom.x(), y + geom.y() );
8066 if ( background )
8067 p->fillRect( 0, 0, geom.width(), geom.height(), *background );
8068 else if ( richtext->paper() )
8069 p->fillRect( 0, 0, geom.width(), geom.height(), *richtext->paper() );
8070
8071 p->translate( horizontalAlignmentOffset(), verticalAlignmentOffset() );
8072
8073 QRegion r;
8074 QTextCursor *c = 0;
8075 if ( richtext->parent()->tmpCursor )
8076 c = richtext->parent()->tmpCursor;
8077 if ( cx >= 0 && cy >= 0 )
8078 richtext->draw( p, cx - ( x + horizontalAlignmentOffset() + geom.x() ),
8079 cy - ( y + geom.y() + verticalAlignmentOffset() ),
8080 cw, ch, g, FALSE, (c != 0), c );
8081 else
8082 richtext->draw( p, -1, -1, -1, -1, g, FALSE, (c != 0), c );
8083
8084 p->restore();
8085}
diff --git a/noncore/apps/opie-write/qrichtext_p.cpp b/noncore/apps/opie-write/qrichtext_p.cpp
new file mode 100644
index 0000000..fb20730
--- a/dev/null
+++ b/noncore/apps/opie-write/qrichtext_p.cpp
@@ -0,0 +1,706 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of the internal Qt classes dealing with rich text
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qrichtext_p.h"
39
40using namespace Qt3;
41
42QTextCommand::~QTextCommand() {}
43QTextCommand::Commands QTextCommand::type() const { return Invalid; }
44
45
46QTextCustomItem::~QTextCustomItem() {}
47void QTextCustomItem::adjustToPainter( QPainter* p){ if ( p ) width = 0; }
48QTextCustomItem::Placement QTextCustomItem::placement() const { return PlaceInline; }
49
50bool QTextCustomItem::ownLine() const { return FALSE; }
51void QTextCustomItem::resize( int nwidth ){ width = nwidth; }
52void QTextCustomItem::invalidate() {}
53
54bool QTextCustomItem::isNested() const { return FALSE; }
55int QTextCustomItem::minimumWidth() const { return 0; }
56
57QString QTextCustomItem::richText() const { return QString::null; }
58
59bool QTextCustomItem::enter( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, bool atEnd )
60{
61 doc = doc; parag = parag; idx = idx; ox = ox; oy = oy; Q_UNUSED( atEnd ) return TRUE;
62
63}
64bool QTextCustomItem::enterAt( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, const QPoint & )
65{
66 doc = doc; parag = parag; idx = idx; ox = ox; oy = oy; return TRUE;
67}
68bool QTextCustomItem::next( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
69{
70 doc = doc; parag = parag; idx = idx; ox = ox; oy = oy; return TRUE;
71}
72bool QTextCustomItem::prev( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
73{
74 doc = doc; parag = parag; idx = idx; ox = ox; oy = oy; return TRUE;
75}
76bool QTextCustomItem::down( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
77{
78 doc = doc; parag = parag; idx = idx; ox = ox; oy = oy; return TRUE;
79}
80bool QTextCustomItem::up( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy )
81{
82 doc = doc; parag = parag; idx = idx; ox = ox; oy = oy; return TRUE;
83}
84
85void QTextFlow::setPageSize( int ps ) { pagesize = ps; }
86bool QTextFlow::isEmpty() { return leftItems.isEmpty() && rightItems.isEmpty(); }
87
88void QTextTableCell::invalidate() { cached_width = -1; cached_sizehint = -1; }
89
90void QTextTable::invalidate() { cachewidth = -1; }
91
92QTextParagData::~QTextParagData() {}
93void QTextParagData::join( QTextParagData * ) {}
94
95QTextFormatter::~QTextFormatter() {}
96void QTextFormatter::setWrapEnabled( bool b ) { wrapEnabled = b; }
97void QTextFormatter::setWrapAtColumn( int c ) { wrapColumn = c; }
98
99
100
101int QTextCursor::x() const
102{
103 QTextStringChar *c = string->at( idx );
104 int curx = c->x;
105 if ( !c->rightToLeft &&
106 c->c.isSpace() &&
107 idx > 0 &&
108 ( string->alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify )
109 curx = string->at( idx - 1 )->x + string->string()->width( idx - 1 );
110 if ( c->rightToLeft )
111 curx += string->string()->width( idx );
112 return curx;
113}
114
115int QTextCursor::y() const
116{
117 int dummy, line;
118 string->lineStartOfChar( idx, &dummy, &line );
119 return string->lineY( line );
120}
121
122bool QTextDocument::hasSelection( int id, bool visible ) const
123{
124 return ( selections.find( id ) != selections.end() &&
125 ( !visible ||
126 ( (QTextDocument*)this )->selectionStartCursor( id ) !=
127 ( (QTextDocument*)this )->selectionEndCursor( id ) ) );
128}
129
130void QTextDocument::setSelectionStart( int id, QTextCursor *cursor )
131{
132 QTextDocumentSelection sel;
133 sel.startCursor = *cursor;
134 sel.endCursor = *cursor;
135 sel.swapped = FALSE;
136 selections[ id ] = sel;
137}
138
139QTextParag *QTextDocument::paragAt( int i ) const
140{
141 QTextParag* p = curParag;
142 if ( !p || p->paragId() > i )
143 p = fParag;
144 while ( p && p->paragId() != i )
145 p = p->next();
146 ((QTextDocument*)this)->curParag = p;
147 return p;
148}
149
150
151QTextFormat::~QTextFormat()
152{
153}
154
155QTextFormat::QTextFormat()
156 : fm( QFontMetrics( fn ) ), linkColor( TRUE ), logicalFontSize( 3 ), stdSize( qApp->font().pointSize() ),
157 different( NoFlags )
158{
159 ref = 0;
160
161 usePixelSizes = FALSE;
162 if ( stdSize == -1 ) {
163 stdSize = qApp->font().pixelSize();
164 usePixelSizes = TRUE;
165 }
166
167 missp = FALSE;
168 ha = AlignNormal;
169 collection = 0;
170}
171
172QTextFormat::QTextFormat( const QStyleSheetItem *style )
173 : fm( QFontMetrics( fn ) ), linkColor( TRUE ), logicalFontSize( 3 ), stdSize( qApp->font().pointSize() ),
174 different( NoFlags )
175{
176 ref = 0;
177
178 usePixelSizes = FALSE;
179 if ( stdSize == -1 ) {
180 stdSize = qApp->font().pixelSize();
181 usePixelSizes = TRUE;
182 }
183
184 this->style = style->name();
185 missp = FALSE;
186 ha = AlignNormal;
187 collection = 0;
188 fn = QFont( style->fontFamily(),
189 style->fontSize(),
190 style->fontWeight(),
191 style->fontItalic() );
192 fn.setUnderline( style->fontUnderline() );
193 col = style->color();
194 fm = QFontMetrics( fn );
195 leftBearing = fm.minLeftBearing();
196 rightBearing = fm.minRightBearing();
197 hei = fm.lineSpacing();
198 asc = fm.ascent() + (fm.leading()+1)/2;
199 dsc = fm.descent();
200 missp = FALSE;
201 ha = AlignNormal;
202 memset( widths, 0, 256 );
203 generateKey();
204 addRef();
205 updateStyleFlags();
206}
207
208QTextFormat::QTextFormat( const QFont &f, const QColor &c, QTextFormatCollection *parent )
209 : fn( f ), col( c ), fm( QFontMetrics( f ) ), linkColor( TRUE ),
210 logicalFontSize( 3 ), stdSize( f.pointSize() ), different( NoFlags )
211{
212 ref = 0;
213 usePixelSizes = FALSE;
214 if ( stdSize == -1 ) {
215 stdSize = f.pixelSize();
216 usePixelSizes = TRUE;
217 }
218 collection = parent;
219 leftBearing = fm.minLeftBearing();
220 rightBearing = fm.minRightBearing();
221 hei = fm.lineSpacing();
222 asc = fm.ascent() + (fm.leading()+1)/2;
223 dsc = fm.descent();
224 missp = FALSE;
225 ha = AlignNormal;
226 memset( widths, 0, 256 );
227 generateKey();
228 addRef();
229 updateStyleFlags();
230}
231
232QTextFormat::QTextFormat( const QTextFormat &f )
233 : fm( f.fm )
234{
235 ref = 0;
236 collection = 0;
237 fn = f.fn;
238 col = f.col;
239 leftBearing = f.leftBearing;
240 rightBearing = f.rightBearing;
241 memset( widths, 0, 256 );
242 hei = f.hei;
243 asc = f.asc;
244 dsc = f.dsc;
245 stdSize = f.stdSize;
246 usePixelSizes = f.usePixelSizes;
247 logicalFontSize = f.logicalFontSize;
248 missp = f.missp;
249 ha = f.ha;
250 k = f.k;
251 linkColor = f.linkColor;
252 style = f.style;
253 different = f.different;
254 addRef();
255}
256
257QTextFormat& QTextFormat::operator=( const QTextFormat &f )
258{
259 ref = 0;
260 collection = f.collection;
261 fn = f.fn;
262 col = f.col;
263 fm = f.fm;
264 leftBearing = f.leftBearing;
265 rightBearing = f.rightBearing;
266 memset( widths, 0, 256 );
267 hei = f.hei;
268 asc = f.asc;
269 dsc = f.dsc;
270 stdSize = f.stdSize;
271 usePixelSizes = f.usePixelSizes;
272 logicalFontSize = f.logicalFontSize;
273 missp = f.missp;
274 ha = f.ha;
275 k = f.k;
276 linkColor = f.linkColor;
277 style = f.style;
278 different = f.different;
279 addRef();
280 return *this;
281}
282
283void QTextFormat::update()
284{
285 fm = QFontMetrics( fn );
286 leftBearing = fm.minLeftBearing();
287 rightBearing = fm.minRightBearing();
288 hei = fm.lineSpacing();
289 asc = fm.ascent() + (fm.leading()+1)/2;
290 dsc = fm.descent();
291 memset( widths, 0, 256 );
292 generateKey();
293 updateStyleFlags();
294}
295
296
297QPainter* QTextFormat::pntr = 0;
298
299void QTextFormat::setPainter( QPainter *p )
300{
301 pntr = p;
302}
303
304QPainter* QTextFormat::painter()
305{
306 return pntr;
307}
308
309
310int QTextFormat::minLeftBearing() const
311{
312 if ( !pntr || !pntr->isActive() )
313 return leftBearing;
314 pntr->setFont( fn );
315 return pntr->fontMetrics().minLeftBearing();
316}
317
318int QTextFormat::minRightBearing() const
319{
320 if ( !pntr || !pntr->isActive() )
321 return rightBearing;
322 pntr->setFont( fn );
323 return pntr->fontMetrics().minRightBearing();
324}
325
326int QTextFormat::height() const
327{
328 if ( !pntr || !pntr->isActive() )
329 return hei;
330 pntr->setFont( fn );
331 return pntr->fontMetrics().lineSpacing();
332}
333
334int QTextFormat::ascent() const
335{
336 if ( !pntr || !pntr->isActive() )
337 return asc;
338 pntr->setFont( fn );
339 return pntr->fontMetrics().ascent() + (pntr->fontMetrics().leading()+1)/2;
340}
341
342int QTextFormat::descent() const
343{
344 if ( !pntr || !pntr->isActive() )
345 return dsc;
346 pntr->setFont( fn );
347 return pntr->fontMetrics().descent();
348}
349
350int QTextFormat::leading() const
351{
352 if ( !pntr || !pntr->isActive() )
353 return fm.leading();
354 pntr->setFont( fn );
355 return pntr->fontMetrics().leading();
356}
357
358void QTextFormat::generateKey()
359{
360 k = getKey( fn, col, isMisspelled(), vAlign() );
361}
362
363QString QTextFormat::getKey( const QFont &fn, const QColor &col, bool misspelled, VerticalAlignment a )
364{
365 QString k = fn.key();
366 k += '/';
367 k += QString::number( (uint)col.rgb() );
368 k += '/';
369 k += QString::number( (int)misspelled );
370 k += '/';
371 k += QString::number( (int)a );
372 return k;
373}
374
375void QTextFormat::updateStyle()
376{
377 if ( !collection || !collection->styleSheet() )
378 return;
379 QStyleSheetItem *item = collection->styleSheet()->item( style );
380 if ( !item )
381 return;
382 if ( !( different & Color ) && item->color().isValid() )
383 col = item->color();
384 if ( !( different & Size ) && item->fontSize() != -1 )
385 fn.setPointSize( item->fontSize() );
386 if ( !( different & Family ) && !item->fontFamily().isEmpty() )
387 fn.setFamily( item->fontFamily() );
388 if ( !( different & Bold ) && item->fontWeight() != -1 )
389 fn.setWeight( item->fontWeight() );
390 if ( !( different & Italic ) && item->definesFontItalic() )
391 fn.setItalic( item->fontItalic() );
392 if ( !( different & Underline ) && item->definesFontUnderline() )
393 fn.setUnderline( item->fontUnderline() );
394 generateKey();
395 update();
396
397}
398
399void QTextFormat::updateStyleFlags()
400{
401 different = NoFlags;
402 if ( !collection || !collection->styleSheet() )
403 return;
404 QStyleSheetItem *item = collection->styleSheet()->item( style );
405 if ( !item )
406 return;
407 if ( item->color() != col )
408 different |= Color;
409 if ( item->fontSize() != fn.pointSize() )
410 different |= Size;
411 if ( item->fontFamily() != fn.family() )
412 different |= Family;
413 if ( item->fontItalic() != fn.italic() )
414 different |= Italic;
415 if ( item->fontUnderline() != fn.underline() )
416 different |= Underline;
417 if ( item->fontWeight() != fn.weight() )
418 different |= Bold;
419}
420
421QString QTextString::toString( const QMemArray<QTextStringChar> &data )
422{
423 QString s;
424 int l = data.size();
425 s.setUnicode( 0, l );
426 QTextStringChar *c = data.data();
427 QChar *uc = (QChar *)s.unicode();
428 while ( l-- ) {
429 *uc = c->c;
430 // ### workaround so that non-breaking whitespaces are drawn
431 // properly, actually this should be fixed in QFont somewhere
432 if ( *uc == (char)0xa0 )
433 *uc = 0x20;
434 uc++;
435 c++;
436 }
437
438 return s;
439}
440
441QString QTextString::toString() const
442{
443 return toString( data );
444}
445
446void QTextParag::setSelection( int id, int start, int end )
447{
448 QMap<int, QTextParagSelection>::ConstIterator it = selections().find( id );
449 if ( it != mSelections->end() ) {
450 if ( start == ( *it ).start && end == ( *it ).end )
451 return;
452 }
453
454 QTextParagSelection sel;
455 sel.start = start;
456 sel.end = end;
457 (*mSelections)[ id ] = sel;
458 setChanged( TRUE, TRUE );
459}
460
461void QTextParag::removeSelection( int id )
462{
463 if ( !hasSelection( id ) )
464 return;
465 if ( mSelections )
466 mSelections->remove( id );
467 setChanged( TRUE, TRUE );
468}
469
470int QTextParag::selectionStart( int id ) const
471{
472 if ( !mSelections )
473 return -1;
474 QMap<int, QTextParagSelection>::ConstIterator it = mSelections->find( id );
475 if ( it == mSelections->end() )
476 return -1;
477 return ( *it ).start;
478}
479
480int QTextParag::selectionEnd( int id ) const
481{
482 if ( !mSelections )
483 return -1;
484 QMap<int, QTextParagSelection>::ConstIterator it = mSelections->find( id );
485 if ( it == mSelections->end() )
486 return -1;
487 return ( *it ).end;
488}
489
490bool QTextParag::hasSelection( int id ) const
491{
492 if ( !mSelections )
493 return FALSE;
494 QMap<int, QTextParagSelection>::ConstIterator it = mSelections->find( id );
495 if ( it == mSelections->end() )
496 return FALSE;
497 return ( *it ).start != ( *it ).end || length() == 1;
498}
499
500bool QTextParag::fullSelected( int id ) const
501{
502 if ( !mSelections )
503 return FALSE;
504 QMap<int, QTextParagSelection>::ConstIterator it = mSelections->find( id );
505 if ( it == mSelections->end() )
506 return FALSE;
507 return ( *it ).start == 0 && ( *it ).end == str->length() - 1;
508}
509
510int QTextParag::lineY( int l ) const
511{
512 if ( l > (int)lineStarts.count() - 1 ) {
513 qWarning( "QTextParag::lineY: line %d out of range!", l );
514 return 0;
515 }
516
517 if ( !isValid() )
518 ( (QTextParag*)this )->format();
519
520 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin();
521 while ( l-- > 0 )
522 ++it;
523 return ( *it )->y;
524}
525
526int QTextParag::lineBaseLine( int l ) const
527{
528 if ( l > (int)lineStarts.count() - 1 ) {
529 qWarning( "QTextParag::lineBaseLine: line %d out of range!", l );
530 return 10;
531 }
532
533 if ( !isValid() )
534 ( (QTextParag*)this )->format();
535
536 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin();
537 while ( l-- > 0 )
538 ++it;
539 return ( *it )->baseLine;
540}
541
542int QTextParag::lineHeight( int l ) const
543{
544 if ( l > (int)lineStarts.count() - 1 ) {
545 qWarning( "QTextParag::lineHeight: line %d out of range!", l );
546 return 15;
547 }
548
549 if ( !isValid() )
550 ( (QTextParag*)this )->format();
551
552 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin();
553 while ( l-- > 0 )
554 ++it;
555 return ( *it )->h;
556}
557
558void QTextParag::lineInfo( int l, int &y, int &h, int &bl ) const
559{
560 if ( l > (int)lineStarts.count() - 1 ) {
561 qWarning( "QTextParag::lineInfo: line %d out of range!", l );
562 qDebug( "%d %d", (int)lineStarts.count() - 1, l );
563 y = 0;
564 h = 15;
565 bl = 10;
566 return;
567 }
568
569 if ( !isValid() )
570 ( (QTextParag*)this )->format();
571
572 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin();
573 while ( l-- > 0 )
574 ++it;
575 y = ( *it )->y;
576 h = ( *it )->h;
577 bl = ( *it )->baseLine;
578}
579
580int QTextParag::alignment() const
581{
582 if ( align != -1 )
583 return align;
584 QStyleSheetItem *item = style();
585 if ( !item )
586 return Qt3::AlignAuto;
587 if ( mStyleSheetItemsVec ) {
588 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
589 item = (*mStyleSheetItemsVec)[ i ];
590 if ( item->alignment() != QStyleSheetItem::Undefined )
591 return item->alignment();
592 }
593 }
594 return Qt3::AlignAuto;
595}
596
597QPtrVector<QStyleSheetItem> QTextParag::styleSheetItems() const
598{
599 QPtrVector<QStyleSheetItem> vec;
600 if ( mStyleSheetItemsVec ) {
601 vec.resize( mStyleSheetItemsVec->size() );
602 for ( int i = 0; i < (int)vec.size(); ++i )
603 vec.insert( i, (*mStyleSheetItemsVec)[ i ] );
604 }
605 return vec;
606}
607
608QStyleSheetItem *QTextParag::style() const
609{
610 if ( !mStyleSheetItemsVec || mStyleSheetItemsVec->size() == 0 )
611 return 0;
612 return (*mStyleSheetItemsVec)[ mStyleSheetItemsVec->size() - 1 ];
613}
614
615int QTextParag::numberOfSubParagraph() const
616{
617 if ( list_val != -1 )
618 return list_val;
619 if ( numSubParag != -1 )
620 return numSubParag;
621 int n = 0;
622 QTextParag *p = (QTextParag*)this;
623 while ( p && ( styleSheetItemsVec().size() >= p->styleSheetItemsVec().size() &&
624 styleSheetItemsVec()[ (int)p->styleSheetItemsVec().size() - 1 ] == p->style() ||
625 p->styleSheetItemsVec().size() >= styleSheetItemsVec().size() &&
626 p->styleSheetItemsVec()[ (int)styleSheetItemsVec().size() - 1 ] == style() ) ) {
627 if ( p->style() == style() && listStyle() != p->listStyle()
628 && p->styleSheetItemsVec().size() == styleSheetItemsVec().size() )
629 break;
630 if ( p->style()->displayMode() == QStyleSheetItem::DisplayListItem
631 && p->style() != style() || styleSheetItemsVec().size() == p->styleSheetItemsVec().size() )
632 ++n;
633 p = p->prev();
634 }
635 ( (QTextParag*)this )->numSubParag = n;
636 return n;
637}
638
639void QTextParag::setFormat( QTextFormat *fm )
640{
641 bool doUpdate = FALSE;
642 if (defFormat && (defFormat != formatCollection()->defaultFormat()))
643 doUpdate = TRUE;
644 defFormat = formatCollection()->format( fm );
645 if ( !doUpdate )
646 return;
647 for ( int i = 0; i < length(); ++i ) {
648 if ( at( i )->format()->styleName() == defFormat->styleName() )
649 at( i )->format()->updateStyle();
650 }
651}
652
653QTextFormatter *QTextParag::formatter() const
654{
655 if ( hasdoc )
656 return document()->formatter();
657 if ( pseudoDocument()->pFormatter )
658 return pseudoDocument()->pFormatter;
659 return ( ( (QTextParag*)this )->pseudoDocument()->pFormatter = new QTextFormatterBreakWords );
660}
661
662void QTextParag::setTabArray( int *a )
663{
664 delete [] tArray;
665 tArray = a;
666}
667
668void QTextParag::setTabStops( int tw )
669{
670 if ( hasdoc )
671 document()->setTabStops( tw );
672 else
673 tabStopWidth = tw;
674}
675
676QMap<int, QTextParagSelection> &QTextParag::selections() const
677{
678 if ( !mSelections )
679 ((QTextParag *)this)->mSelections = new QMap<int, QTextParagSelection>;
680 return *mSelections;
681}
682
683QPtrVector<QStyleSheetItem> &QTextParag::styleSheetItemsVec() const
684{
685 if ( !mStyleSheetItemsVec )
686 ((QTextParag *)this)->mStyleSheetItemsVec = new QPtrVector<QStyleSheetItem>;
687 return *mStyleSheetItemsVec;
688}
689
690QPtrList<QTextCustomItem> &QTextParag::floatingItems() const
691{
692 if ( !mFloatingItems )
693 ((QTextParag *)this)->mFloatingItems = new QPtrList<QTextCustomItem>;
694 return *mFloatingItems;
695}
696
697QTextStringChar::~QTextStringChar()
698{
699 if ( format() )
700 format()->removeRef();
701 if ( type ) // not Regular
702 delete d.custom;
703}
704
705QTextParagPseudoDocument::QTextParagPseudoDocument():pFormatter(0),commandHistory(0), minw(0),wused(0){}
706QTextParagPseudoDocument::~QTextParagPseudoDocument(){ delete pFormatter; delete commandHistory; }
diff --git a/noncore/apps/opie-write/qrichtext_p.h b/noncore/apps/opie-write/qrichtext_p.h
new file mode 100644
index 0000000..94ce913
--- a/dev/null
+++ b/noncore/apps/opie-write/qrichtext_p.h
@@ -0,0 +1,2158 @@
1/****************************************************************************
2** $Id$
3**
4** Definition of internal rich text classes
5**
6** Created : 990124
7**
8** Copyright (C) 1999-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#ifndef QRICHTEXT_P_H
39#define QRICHTEXT_P_H
40
41//
42// W A R N I N G
43// -------------
44//
45// This file is not part of the Qt API. It exists for the convenience
46// of a number of Qt sources files. This header file may change from
47// version to version without notice, or even be removed.
48//
49// We mean it.
50//
51//
52
53#ifndef QT_H
54#include "qt3namespace.h"
55#include "qstring.h"
56#include "qlist.h"
57#include "qrect.h"
58#include "qfontmetrics.h"
59#include "qintdict.h"
60#include "qmap.h"
61#include "qstringlist.h"
62#include "qfont.h"
63#include "qcolor.h"
64#include "qsize.h"
65#include "qvaluelist.h"
66#include "qvaluestack.h"
67#include "qobject.h"
68#include "qdict.h"
69#include "qtextstream.h"
70#include "qpixmap.h"
71#include "qstylesheet.h"
72#include "qvector.h"
73#include "qpainter.h"
74#include "qlayout.h"
75#include "qobject.h"
76#include "qcomplextext_p.h"
77#include "qapplication.h"
78#include <limits.h>
79#endif // QT_H
80
81//#define DEBUG_COLLECTION
82
83namespace Qt3 {
84
85class QTextDocument;
86class QTextString;
87class QTextPreProcessor;
88class QTextFormat;
89class QTextCursor;
90class QTextParag;
91class QTextFormatter;
92class QTextIndent;
93class QTextFormatCollection;
94class QStyleSheetItem;
95class QTextCustomItem;
96class QTextFlow;
97struct QBidiContext;
98
99// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
100
101class Q_EXPORT QTextStringChar
102{
103 friend class QTextString;
104
105public:
106 // this is never called, initialize variables in QTextString::insert()!!!
107 QTextStringChar() : lineStart( 0 ), type( Regular ), startOfRun( 0 ) {d.format=0;}
108 ~QTextStringChar();
109
110 QChar c;
111 enum Type { Regular=0, Custom=1, Anchor=2, CustomAnchor=3 };
112 uint lineStart : 1;
113 uint rightToLeft : 1;
114 uint hasCursor : 1;
115 uint canBreak : 1;
116 Type type : 2;
117 uint startOfRun : 1;
118
119 int x;
120 int height() const;
121 int ascent() const;
122 int descent() const;
123 bool isCustom() const { return (type & Custom) != 0; }
124 QTextFormat *format() const;
125 QTextCustomItem *customItem() const;
126 void setFormat( QTextFormat *f );
127 void setCustomItem( QTextCustomItem *i );
128 QTextStringChar *clone() const;
129 struct CustomData
130 {
131 QTextFormat *format;
132 QTextCustomItem *custom;
133 QString anchorName;
134 QString anchorHref;
135 };
136
137 void loseCustomItem();
138
139 union {
140 QTextFormat* format;
141 CustomData* custom;
142 } d;
143
144 bool isAnchor() const { return ( type & Anchor) != 0; }
145 QString anchorName() const;
146 QString anchorHref() const;
147 void setAnchor( const QString& name, const QString& href );
148
149private:
150 QTextStringChar &operator=( const QTextStringChar & ) {
151 //abort();
152 return *this;
153 }
154 friend class QComplexText;
155 friend class QTextParag;
156};
157
158#if defined(Q_TEMPLATEDLL)
159// MOC_SKIP_BEGIN
160template class Q_EXPORT QMemArray<QTextStringChar>;
161// MOC_SKIP_END
162#endif
163
164class Q_EXPORT QTextString
165{
166public:
167
168 QTextString();
169 QTextString( const QTextString &s );
170 virtual ~QTextString();
171
172 static QString toString( const QMemArray<QTextStringChar> &data );
173 QString toString() const;
174
175 QTextStringChar &at( int i ) const;
176 int length() const;
177
178 int width( int idx ) const;
179
180 void insert( int index, const QString &s, QTextFormat *f );
181 void insert( int index, QTextStringChar *c );
182 void truncate( int index );
183 void remove( int index, int len );
184 void clear();
185
186 void setFormat( int index, QTextFormat *f, bool useCollection );
187
188 void setBidi( bool b ) { bidi = b; }
189 bool isBidi() const;
190 bool isRightToLeft() const;
191 QChar::Direction direction() const;
192 void setDirection( QChar::Direction d ) { dir = d; bidiDirty = TRUE; }
193
194 QMemArray<QTextStringChar> subString( int start = 0, int len = 0xFFFFFF ) const;
195 QMemArray<QTextStringChar> rawData() const { return data; }
196
197 void operator=( const QString &s ) { clear(); insert( 0, s, 0 ); }
198 void operator+=( const QString &s );
199 void prepend( const QString &s ) { insert( 0, s, 0 ); }
200
201private:
202 void checkBidi() const;
203
204 QMemArray<QTextStringChar> data;
205 uint bidiDirty : 1;
206 uint bidi : 1; // true when the paragraph has right to left characters
207 uint rightToLeft : 1;
208 uint dir : 5;
209};
210
211inline bool QTextString::isBidi() const
212{
213 if ( bidiDirty )
214 checkBidi();
215 return bidi;
216}
217
218inline bool QTextString::isRightToLeft() const
219{
220 if ( bidiDirty )
221 checkBidi();
222 return rightToLeft;
223}
224
225inline QChar::Direction QTextString::direction() const
226{
227 return (QChar::Direction) dir;
228}
229
230// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
231
232#if defined(Q_TEMPLATEDLL)
233// MOC_SKIP_BEGIN
234template class Q_EXPORT QValueStack<int>;
235template class Q_EXPORT QValueStack<QTextParag*>;
236template class Q_EXPORT QValueStack<bool>;
237// MOC_SKIP_END
238#endif
239
240class Q_EXPORT QTextCursor
241{
242public:
243 QTextCursor( QTextDocument *d );
244 QTextCursor();
245 QTextCursor( const QTextCursor &c );
246 QTextCursor &operator=( const QTextCursor &c );
247 virtual ~QTextCursor() {}
248
249 bool operator==( const QTextCursor &c ) const;
250 bool operator!=( const QTextCursor &c ) const { return !(*this == c); }
251
252 QTextDocument *document() const { return doc; }
253 void setDocument( QTextDocument *d );
254
255 QTextParag *parag() const;
256 int index() const;
257 void setParag( QTextParag *s, bool restore = TRUE );
258
259 void gotoLeft();
260 void gotoRight();
261 void gotoNextLetter();
262 void gotoPreviousLetter();
263 void gotoUp();
264 void gotoDown();
265 void gotoLineEnd();
266 void gotoLineStart();
267 void gotoHome();
268 void gotoEnd();
269 void gotoPageUp( int visibleHeight );
270 void gotoPageDown( int visibleHeight );
271 void gotoNextWord();
272 void gotoPreviousWord();
273 void gotoWordLeft();
274 void gotoWordRight();
275
276 void insert( const QString &s, bool checkNewLine, QMemArray<QTextStringChar> *formatting = 0 );
277 void splitAndInsertEmptyParag( bool ind = TRUE, bool updateIds = TRUE );
278 bool remove();
279 void killLine();
280 void indent();
281
282 bool atParagStart();
283 bool atParagEnd();
284
285 void setIndex( int i, bool restore = TRUE );
286
287 void checkIndex();
288
289 int offsetX() const { return ox; }
290 int offsetY() const { return oy; }
291
292 QTextParag *topParag() const { return parags.isEmpty() ? string : parags.first(); }
293 int totalOffsetX() const;
294 int totalOffsetY() const;
295
296 bool place( const QPoint &pos, QTextParag *s ) { return place( pos, s, FALSE ); }
297 bool place( const QPoint &pos, QTextParag *s, bool link );
298 void restoreState();
299
300 int x() const;
301 int y() const;
302
303 int nestedDepth() const { return (int)indices.count(); } //### size_t/int cast
304 void oneUp() { if ( !indices.isEmpty() ) pop(); }
305 void setValid( bool b ) { valid = b; }
306 bool isValid() const { return valid; }
307
308private:
309 enum Operation { EnterBegin, EnterEnd, Next, Prev, Up, Down };
310
311 void push();
312 void pop();
313 void processNesting( Operation op );
314 void invalidateNested();
315 void gotoIntoNested( const QPoint &globalPos );
316
317 QTextParag *string;
318 QTextDocument *doc;
319 int idx, tmpIndex;
320 int ox, oy;
321 QValueStack<int> indices;
322 QValueStack<QTextParag*> parags;
323 QValueStack<int> xOffsets;
324 QValueStack<int> yOffsets;
325 QValueStack<bool> nestedStack;
326 uint nested : 1;
327 uint valid : 1;
328
329};
330
331// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
332
333class Q_EXPORT QTextCommand
334{
335public:
336 enum Commands { Invalid, Insert, Delete, Format, Alignment, ParagType };
337
338 QTextCommand( QTextDocument *d ) : doc( d ), cursor( d ) {}
339 virtual ~QTextCommand();
340
341 virtual Commands type() const;
342
343 virtual QTextCursor *execute( QTextCursor *c ) = 0;
344 virtual QTextCursor *unexecute( QTextCursor *c ) = 0;
345
346protected:
347 QTextDocument *doc;
348 QTextCursor cursor;
349
350};
351
352#if defined(Q_TEMPLATEDLL)
353// MOC_SKIP_BEGIN
354template class Q_EXPORT QPtrList<QTextCommand>;
355// MOC_SKIP_END
356#endif
357
358class Q_EXPORT QTextCommandHistory
359{
360public:
361 QTextCommandHistory( int s ) : current( -1 ), steps( s ) { history.setAutoDelete( TRUE ); }
362 virtual ~QTextCommandHistory();
363
364 void clear() { history.clear(); current = -1; }
365
366 void addCommand( QTextCommand *cmd );
367 QTextCursor *undo( QTextCursor *c );
368 QTextCursor *redo( QTextCursor *c );
369
370 bool isUndoAvailable();
371 bool isRedoAvailable();
372
373 void setUndoDepth( int d ) { steps = d; }
374 int undoDepth() const { return steps; }
375
376 int historySize() const { return history.count(); }
377 int currentPosition() const { return current; }
378
379private:
380 QPtrList<QTextCommand> history;
381 int current, steps;
382
383};
384
385inline QTextCommandHistory::~QTextCommandHistory()
386{
387 clear();
388}
389
390// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
391
392class Q_EXPORT QTextCustomItem
393{
394public:
395 QTextCustomItem( QTextDocument *p )
396 : xpos(0), ypos(-1), width(-1), height(0), parent( p )
397 {}
398 virtual ~QTextCustomItem();
399 virtual void draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected ) = 0;
400
401 virtual void adjustToPainter( QPainter* );
402
403 enum Placement { PlaceInline = 0, PlaceLeft, PlaceRight };
404 virtual Placement placement() const;
405 bool placeInline() { return placement() == PlaceInline; }
406
407 virtual bool ownLine() const;
408 virtual void resize( int nwidth );
409 virtual void invalidate();
410 virtual int ascent() const { return height; }
411
412 virtual bool isNested() const;
413 virtual int minimumWidth() const;
414
415 virtual QString richText() const;
416
417 int xpos; // used for floating items
418 int ypos; // used for floating items
419 int width;
420 int height;
421
422 QRect geometry() const { return QRect( xpos, ypos, width, height ); }
423
424 virtual bool enter( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, bool atEnd = FALSE );
425 virtual bool enterAt( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, const QPoint & );
426 virtual bool next( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
427 virtual bool prev( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
428 virtual bool down( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
429 virtual bool up( QTextCursor *, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
430
431 void setParagraph( QTextParag *p ) { parag = p; }
432 QTextParag *paragrapth() const { return parag; }
433
434 QTextDocument *parent;
435 QTextParag *parag;
436
437 virtual void pageBreak( int y, QTextFlow* flow );
438};
439
440#if defined(Q_TEMPLATEDLL)
441// MOC_SKIP_BEGIN
442template class Q_EXPORT QMap<QString, QString>;
443// MOC_SKIP_END
444#endif
445
446class Q_EXPORT QTextImage : public QTextCustomItem
447{
448public:
449 QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context,
450 QMimeSourceFactory &factory );
451 virtual ~QTextImage();
452
453 Placement placement() const { return place; }
454 void adjustToPainter( QPainter* );
455 int minimumWidth() const { return width; }
456
457 QString richText() const;
458
459 void draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected );
460
461private:
462 QRegion* reg;
463 QPixmap pm;
464 Placement place;
465 int tmpwidth, tmpheight;
466 QMap<QString, QString> attributes;
467 QString imgId;
468
469};
470
471class Q_EXPORT QTextHorizontalLine : public QTextCustomItem
472{
473public:
474 QTextHorizontalLine( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context,
475 QMimeSourceFactory &factory );
476 virtual ~QTextHorizontalLine();
477
478 void adjustToPainter( QPainter* );
479 void draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected );
480 QString richText() const;
481
482 bool ownLine() const { return TRUE; }
483
484private:
485 int tmpheight;
486 QColor color;
487
488};
489
490#if defined(Q_TEMPLATEDLL)
491// MOC_SKIP_BEGIN
492template class Q_EXPORT QPtrList<QTextCustomItem>;
493// MOC_SKIP_END
494#endif
495
496class Q_EXPORT QTextFlow
497{
498 friend class QTextDocument;
499 friend class QTextTableCell;
500
501public:
502 QTextFlow();
503 virtual ~QTextFlow();
504
505 virtual void setWidth( int width );
506 int width() const;
507
508 virtual void setPageSize( int ps );
509 int pageSize() const { return pagesize; }
510
511 virtual int adjustLMargin( int yp, int h, int margin, int space );
512 virtual int adjustRMargin( int yp, int h, int margin, int space );
513
514 virtual void registerFloatingItem( QTextCustomItem* item );
515 virtual void unregisterFloatingItem( QTextCustomItem* item );
516 virtual QRect boundingRect() const;
517 virtual void drawFloatingItems(QPainter* p, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected );
518
519 virtual int adjustFlow( int y, int w, int h ); // adjusts y according to the defined pagesize. Returns the shift.
520
521 virtual bool isEmpty();
522
523 void clear();
524
525private:
526 int w;
527 int pagesize;
528
529 QPtrList<QTextCustomItem> leftItems;
530 QPtrList<QTextCustomItem> rightItems;
531
532};
533
534inline int QTextFlow::width() const { return w; }
535
536class QTextTable;
537
538class Q_EXPORT QTextTableCell : public QLayoutItem
539{
540 friend class QTextTable;
541
542public:
543 QTextTableCell( QTextTable* table,
544 int row, int column,
545 const QMap<QString, QString> &attr,
546 const QStyleSheetItem* style,
547 const QTextFormat& fmt, const QString& context,
548 QMimeSourceFactory &factory, QStyleSheet *sheet, const QString& doc );
549 QTextTableCell( QTextTable* table, int row, int column );
550 virtual ~QTextTableCell();
551
552 QSize sizeHint() const ;
553 QSize minimumSize() const ;
554 QSize maximumSize() const ;
555 QSizePolicy::ExpandData expanding() const;
556 bool isEmpty() const;
557 void setGeometry( const QRect& ) ;
558 QRect geometry() const;
559
560 bool hasHeightForWidth() const;
561 int heightForWidth( int ) const;
562
563 void adjustToPainter( QPainter* );
564
565 int row() const { return row_; }
566 int column() const { return col_; }
567 int rowspan() const { return rowspan_; }
568 int colspan() const { return colspan_; }
569 int stretch() const { return stretch_; }
570
571 QTextDocument* richText() const { return richtext; }
572 QTextTable* table() const { return parent; }
573
574 void draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected );
575
576 QBrush *backGround() const { return background; }
577 virtual void invalidate();
578
579 int verticalAlignmentOffset() const;
580 int horizontalAlignmentOffset() const;
581
582private:
583 QRect geom;
584 QTextTable* parent;
585 QTextDocument* richtext;
586 int row_;
587 int col_;
588 int rowspan_;
589 int colspan_;
590 int stretch_;
591 int maxw;
592 int minw;
593 bool hasFixedWidth;
594 QBrush *background;
595 int cached_width;
596 int cached_sizehint;
597 QMap<QString, QString> attributes;
598 int align;
599};
600
601#if defined(Q_TEMPLATEDLL)
602// MOC_SKIP_BEGIN
603template class Q_EXPORT QPtrList<QTextTableCell>;
604template class Q_EXPORT QMap<QTextCursor*, int>;
605// MOC_SKIP_END
606#endif
607
608class Q_EXPORT QTextTable: public QTextCustomItem
609{
610 friend class QTextTableCell;
611
612public:
613 QTextTable( QTextDocument *p, const QMap<QString, QString> &attr );
614 virtual ~QTextTable();
615
616 void adjustToPainter( QPainter *p );
617 void pageBreak( int y, QTextFlow* flow );
618 void draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch,
619 const QColorGroup& cg, bool selected );
620
621 bool noErase() const { return TRUE; }
622 bool ownLine() const { return TRUE; }
623 Placement placement() const { return place; }
624 bool isNested() const { return TRUE; }
625 void resize( int nwidth );
626 virtual void invalidate();
627
628 virtual bool enter( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, bool atEnd = FALSE );
629 virtual bool enterAt( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, const QPoint &pos );
630 virtual bool next( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
631 virtual bool prev( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
632 virtual bool down( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
633 virtual bool up( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy );
634
635 QString richText() const;
636
637 int minimumWidth() const;
638
639 QPtrList<QTextTableCell> tableCells() const { return cells; }
640
641 bool isStretching() const { return stretch; }
642
643private:
644 void format( int w );
645 void addCell( QTextTableCell* cell );
646
647private:
648 QGridLayout* layout;
649 QPtrList<QTextTableCell> cells;
650 int cachewidth;
651 int fixwidth;
652 int cellpadding;
653 int cellspacing;
654 int border;
655 int outerborder;
656 int stretch;
657 int innerborder;
658 int us_cp, us_ib, us_b, us_ob, us_cs;
659 QMap<QString, QString> attributes;
660 QMap<QTextCursor*, int> currCell;
661 Placement place;
662 void adjustCells( int y , int shift );
663 int pageBreakFor;
664};
665
666// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
667
668class QTextTableCell;
669class QTextParag;
670
671struct Q_EXPORT QTextDocumentSelection
672{
673 QTextCursor startCursor, endCursor;
674 bool swapped;
675};
676
677#if defined(Q_TEMPLATEDLL)
678// MOC_SKIP_BEGIN
679template class Q_EXPORT QMap<int, QColor>;
680template class Q_EXPORT QMap<int, bool>;
681template class Q_EXPORT QMap<int, QTextDocumentSelection>;
682template class Q_EXPORT QPtrList<QTextDocument>;
683// MOC_SKIP_END
684#endif
685
686class Q_EXPORT QTextDocument : public QObject
687{
688 Q_OBJECT
689
690 friend class QTextTableCell;
691 friend class QTextCursor;
692 friend class QTextEdit;
693 friend class QTextParag;
694
695public:
696 enum SelectionIds {
697 Standard = 0,
698 Temp = 32000 // This selection must not be drawn, it's used e.g. by undo/redo to
699 // remove multiple lines with removeSelectedText()
700 };
701
702 QTextDocument( QTextDocument *p );
703 QTextDocument( QTextDocument *d, QTextFormatCollection *f );
704 virtual ~QTextDocument();
705
706 QTextDocument *parent() const { return par; }
707 QTextParag *parentParag() const { return parParag; }
708
709 void setText( const QString &text, const QString &context );
710 QMap<QString, QString> attributes() const { return attribs; }
711 void setAttributes( const QMap<QString, QString> &attr ) { attribs = attr; }
712
713 QString text() const;
714 QString text( int parag ) const;
715 QString originalText() const;
716
717 int x() const;
718 int y() const;
719 int width() const;
720 int widthUsed() const;
721 int visibleWidth() const;
722 int height() const;
723 void setWidth( int w );
724 int minimumWidth() const;
725 bool setMinimumWidth( int needed, int used = -1, QTextParag *parag = 0 );
726
727 void setY( int y );
728 int leftMargin() const;
729 void setLeftMargin( int lm );
730 int rightMargin() const;
731 void setRightMargin( int rm );
732
733 QTextParag *firstParag() const;
734 QTextParag *lastParag() const;
735 void setFirstParag( QTextParag *p );
736 void setLastParag( QTextParag *p );
737
738 void invalidate();
739
740 void setPreProcessor( QTextPreProcessor *sh );
741 QTextPreProcessor *preProcessor() const;
742
743 void setFormatter( QTextFormatter *f );
744 QTextFormatter *formatter() const;
745
746 void setIndent( QTextIndent *i );
747 QTextIndent *indent() const;
748
749 QColor selectionColor( int id ) const;
750 bool invertSelectionText( int id ) const;
751 void setSelectionColor( int id, const QColor &c );
752 void setInvertSelectionText( int id, bool b );
753 bool hasSelection( int id, bool visible = FALSE ) const;
754 void setSelectionStart( int id, QTextCursor *cursor );
755 bool setSelectionEnd( int id, QTextCursor *cursor );
756 void selectAll( int id );
757 bool removeSelection( int id );
758 void selectionStart( int id, int &paragId, int &index );
759 QTextCursor selectionStartCursor( int id );
760 QTextCursor selectionEndCursor( int id );
761 void selectionEnd( int id, int &paragId, int &index );
762 void setFormat( int id, QTextFormat *f, int flags );
763 QTextParag *selectionStart( int id );
764 QTextParag *selectionEnd( int id );
765 int numSelections() const { return nSelections; }
766 void addSelection( int id );
767
768 QString selectedText( int id, bool withCustom = TRUE ) const;
769 void copySelectedText( int id );
770 void removeSelectedText( int id, QTextCursor *cursor );
771 void indentSelection( int id );
772
773 QTextParag *paragAt( int i ) const;
774
775 void addCommand( QTextCommand *cmd );
776 QTextCursor *undo( QTextCursor *c = 0 );
777 QTextCursor *redo( QTextCursor *c = 0 );
778 QTextCommandHistory *commands() const { return commandHistory; }
779
780 QTextFormatCollection *formatCollection() const;
781
782 bool find( const QString &expr, bool cs, bool wo, bool forward, int *parag, int *index, QTextCursor *cursor );
783
784 void setTextFormat( Qt::TextFormat f );
785 Qt::TextFormat textFormat() const;
786
787 bool inSelection( int selId, const QPoint &pos ) const;
788
789 QStyleSheet *styleSheet() const { return sheet_; }
790 QMimeSourceFactory *mimeSourceFactory() const { return factory_; }
791 QString context() const { return contxt; }
792
793 void setStyleSheet( QStyleSheet *s );
794 void updateStyles();
795 void updateFontSizes( int base, bool usePixels );
796 void updateFontAttributes( const QFont &f, const QFont &old );
797 void setMimeSourceFactory( QMimeSourceFactory *f ) { if ( f ) factory_ = f; }
798 void setContext( const QString &c ) { if ( !c.isEmpty() ) contxt = c; }
799
800 void setUnderlineLinks( bool b ) { underlLinks = b; }
801 bool underlineLinks() const { return underlLinks; }
802
803 void setPaper( QBrush *brush ) { if ( backBrush ) delete backBrush; backBrush = brush; }
804 QBrush *paper() const { return backBrush; }
805
806 void doLayout( QPainter *p, int w );
807 void draw( QPainter *p, const QRect& rect, const QColorGroup &cg, const QBrush *paper = 0 );
808 void drawParag( QPainter *p, QTextParag *parag, int cx, int cy, int cw, int ch,
809 QPixmap *&doubleBuffer, const QColorGroup &cg,
810 bool drawCursor, QTextCursor *cursor, bool resetChanged = TRUE );
811 QTextParag *draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
812 bool onlyChanged = FALSE, bool drawCursor = FALSE, QTextCursor *cursor = 0,
813 bool resetChanged = TRUE );
814
815 void setDefaultFont( const QFont &f );
816
817 void registerCustomItem( QTextCustomItem *i, QTextParag *p );
818 void unregisterCustomItem( QTextCustomItem *i, QTextParag *p );
819
820 void setFlow( QTextFlow *f );
821 void takeFlow();
822 QTextFlow *flow() const { return flow_; }
823 bool isPageBreakEnabled() const { return pages; }
824 void setPageBreakEnabled( bool b ) { pages = b; }
825
826 void setUseFormatCollection( bool b ) { useFC = b; }
827 bool useFormatCollection() const { return useFC; }
828
829 QTextTableCell *tableCell() const { return tc; }
830 void setTableCell( QTextTableCell *c ) { tc = c; }
831
832 void setPlainText( const QString &text );
833 void setRichText( const QString &text, const QString &context );
834 QString richText( QTextParag *p = 0 ) const;
835 QString plainText( QTextParag *p = 0 ) const;
836
837 bool focusNextPrevChild( bool next );
838
839 int alignment() const;
840 void setAlignment( int a );
841
842 int *tabArray() const;
843 int tabStopWidth() const;
844 void setTabArray( int *a );
845 void setTabStops( int tw );
846
847 void setUndoDepth( int d ) { commandHistory->setUndoDepth( d ); }
848 int undoDepth() const { return commandHistory->undoDepth(); }
849
850 int length() const;
851 void clear( bool createEmptyParag = FALSE );
852
853 virtual QTextParag *createParag( QTextDocument *d, QTextParag *pr = 0, QTextParag *nx = 0, bool updateIds = TRUE );
854 void insertChild( QObject *o ) { QObject::insertChild( o ); }
855 void removeChild( QObject *o ) { QObject::removeChild( o ); }
856 void insertChild( QTextDocument *d ) { childList.append( d ); }
857 void removeChild( QTextDocument *d ) { childList.removeRef( d ); }
858 QPtrList<QTextDocument> children() const { return childList; }
859
860 void setAddMargins( bool b ) { addMargs = b; }
861 int addMargins() const { return addMargs; }
862
863 bool hasFocusParagraph() const;
864 QString focusHref() const;
865
866 void invalidateOriginalText() { oTextValid = FALSE; oText = ""; }
867
868signals:
869 void minimumWidthChanged( int );
870
871private:
872 void init();
873 QPixmap *bufferPixmap( const QSize &s );
874 // HTML parser
875 bool hasPrefix(const QChar* doc, int length, int pos, QChar c);
876 bool hasPrefix(const QChar* doc, int length, int pos, const QString& s);
877 QTextCustomItem* parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt,
878 const QChar* doc, int length, int& pos, QTextParag *curpar );
879 bool eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp = FALSE );
880 bool eat(const QChar* doc, int length, int& pos, QChar c);
881 QString parseOpenTag(const QChar* doc, int length, int& pos, QMap<QString, QString> &attr, bool& emptyTag);
882 QString parseCloseTag( const QChar* doc, int length, int& pos );
883 QChar parseHTMLSpecialChar(const QChar* doc, int length, int& pos);
884 QString parseWord(const QChar* doc, int length, int& pos, bool lower = TRUE);
885 QChar parseChar(const QChar* doc, int length, int& pos, QStyleSheetItem::WhiteSpaceMode wsm );
886 void setRichTextInternal( const QString &text );
887
888private:
889 struct Q_EXPORT Focus {
890 QTextParag *parag;
891 int start, len;
892 QString href;
893 };
894
895 int cx, cy, cw, vw;
896 QTextParag *fParag, *lParag;
897 QTextPreProcessor *pProcessor;
898 QMap<int, QColor> selectionColors;
899 QMap<int, QTextDocumentSelection> selections;
900 QMap<int, bool> selectionText;
901 QTextCommandHistory *commandHistory;
902 QTextFormatter *pFormatter;
903 QTextIndent *indenter;
904 QTextFormatCollection *fCollection;
905 Qt::TextFormat txtFormat;
906 uint preferRichText : 1;
907 uint pages : 1;
908 uint useFC : 1;
909 uint withoutDoubleBuffer : 1;
910 uint underlLinks : 1;
911 uint nextDoubleBuffered : 1;
912 uint addMargs : 1;
913 uint oTextValid : 1;
914 uint mightHaveCustomItems : 1;
915 int align;
916 int nSelections;
917 QTextFlow *flow_;
918 QTextDocument *par;
919 QTextParag *parParag;
920 QTextTableCell *tc;
921 QTextCursor *tmpCursor;
922 QBrush *backBrush;
923 QPixmap *buf_pixmap;
924 Focus focusIndicator;
925 int minw;
926 int wused;
927 int leftmargin;
928 int rightmargin;
929 QTextParag *minwParag, *curParag;
930 QStyleSheet* sheet_;
931 QMimeSourceFactory* factory_;
932 QString contxt;
933 QMap<QString, QString> attribs;
934 int *tArray;
935 int tStopWidth;
936 int uDepth;
937 QString oText;
938 QPtrList<QTextDocument> childList;
939 QColor linkColor;
940
941};
942
943// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
944
945
946class Q_EXPORT QTextDeleteCommand : public QTextCommand
947{
948public:
949 QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
950 const QValueList< QPtrVector<QStyleSheetItem> > &os,
951 const QValueList<QStyleSheetItem::ListStyle> &ols,
952 const QMemArray<int> &oas );
953 QTextDeleteCommand( QTextParag *p, int idx, const QMemArray<QTextStringChar> &str );
954 virtual ~QTextDeleteCommand();
955
956 Commands type() const { return Delete; }
957 QTextCursor *execute( QTextCursor *c );
958 QTextCursor *unexecute( QTextCursor *c );
959
960protected:
961 int id, index;
962 QTextParag *parag;
963 QMemArray<QTextStringChar> text;
964 QValueList< QPtrVector<QStyleSheetItem> > oldStyles;
965 QValueList<QStyleSheetItem::ListStyle> oldListStyles;
966 QMemArray<int> oldAligns;
967
968};
969
970class Q_EXPORT QTextInsertCommand : public QTextDeleteCommand
971{
972public:
973 QTextInsertCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
974 const QValueList< QPtrVector<QStyleSheetItem> > &os,
975 const QValueList<QStyleSheetItem::ListStyle> &ols,
976 const QMemArray<int> &oas )
977 : QTextDeleteCommand( d, i, idx, str, os, ols, oas ) {}
978 QTextInsertCommand( QTextParag *p, int idx, const QMemArray<QTextStringChar> &str )
979 : QTextDeleteCommand( p, idx, str ) {}
980 virtual ~QTextInsertCommand() {}
981
982 Commands type() const { return Insert; }
983 QTextCursor *execute( QTextCursor *c ) { return QTextDeleteCommand::unexecute( c ); }
984 QTextCursor *unexecute( QTextCursor *c ) { return QTextDeleteCommand::execute( c ); }
985
986};
987
988class Q_EXPORT QTextFormatCommand : public QTextCommand
989{
990public:
991 QTextFormatCommand( QTextDocument *d, int sid, int sidx, int eid, int eidx, const QMemArray<QTextStringChar> &old, QTextFormat *f, int fl );
992 virtual ~QTextFormatCommand();
993
994 Commands type() const { return Format; }
995 QTextCursor *execute( QTextCursor *c );
996 QTextCursor *unexecute( QTextCursor *c );
997
998protected:
999 int startId, startIndex, endId, endIndex;
1000 QTextFormat *format;
1001 QMemArray<QTextStringChar> oldFormats;
1002 int flags;
1003
1004};
1005
1006class Q_EXPORT QTextAlignmentCommand : public QTextCommand
1007{
1008public:
1009 QTextAlignmentCommand( QTextDocument *d, int fParag, int lParag, int na, const QMemArray<int> &oa );
1010 virtual ~QTextAlignmentCommand() {}
1011
1012 Commands type() const { return Alignment; }
1013 QTextCursor *execute( QTextCursor *c );
1014 QTextCursor *unexecute( QTextCursor *c );
1015
1016private:
1017 int firstParag, lastParag;
1018 int newAlign;
1019 QMemArray<int> oldAligns;
1020
1021};
1022
1023class Q_EXPORT QTextParagTypeCommand : public QTextCommand
1024{
1025public:
1026 QTextParagTypeCommand( QTextDocument *d, int fParag, int lParag, bool l,
1027 QStyleSheetItem::ListStyle s, const QValueList< QPtrVector<QStyleSheetItem> > &os,
1028 const QValueList<QStyleSheetItem::ListStyle> &ols );
1029 virtual ~QTextParagTypeCommand() {}
1030
1031 Commands type() const { return ParagType; }
1032 QTextCursor *execute( QTextCursor *c );
1033 QTextCursor *unexecute( QTextCursor *c );
1034
1035private:
1036 int firstParag, lastParag;
1037 bool list;
1038 QStyleSheetItem::ListStyle listStyle;
1039 QValueList< QPtrVector<QStyleSheetItem> > oldStyles;
1040 QValueList<QStyleSheetItem::ListStyle> oldListStyles;
1041
1042};
1043
1044// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1045
1046struct Q_EXPORT QTextParagSelection
1047{
1048 int start, end;
1049};
1050
1051struct Q_EXPORT QTextParagLineStart
1052{
1053 QTextParagLineStart() : y( 0 ), baseLine( 0 ), h( 0 )
1054#ifndef QT_NO_COMPLEXTEXT
1055 , bidicontext( 0 )
1056#endif
1057 { }
1058 QTextParagLineStart( ushort y_, ushort bl, ushort h_ ) : y( y_ ), baseLine( bl ), h( h_ ),
1059 w( 0 )
1060#ifndef QT_NO_COMPLEXTEXT
1061 , bidicontext( 0 )
1062#endif
1063 { }
1064#ifndef QT_NO_COMPLEXTEXT
1065 QTextParagLineStart( QBidiContext *c, QBidiStatus s ) : y(0), baseLine(0), h(0),
1066 status( s ), bidicontext( c ) { if ( bidicontext ) bidicontext->ref(); }
1067#endif
1068
1069 virtual ~QTextParagLineStart()
1070 {
1071#ifndef QT_NO_COMPLEXTEXT
1072 if ( bidicontext && bidicontext->deref() )
1073 delete bidicontext;
1074#endif
1075 }
1076
1077#ifndef QT_NO_COMPLEXTEXT
1078 void setContext( QBidiContext *c ) {
1079 if ( c == bidicontext )
1080 return;
1081 if ( bidicontext && bidicontext->deref() )
1082 delete bidicontext;
1083 bidicontext = c;
1084 if ( bidicontext )
1085 bidicontext->ref();
1086 }
1087 QBidiContext *context() const { return bidicontext; }
1088#endif
1089
1090public:
1091 ushort y, baseLine, h;
1092#ifndef QT_NO_COMPLEXTEXT
1093 QBidiStatus status;
1094#endif
1095 int w;
1096
1097private:
1098#ifndef QT_NO_COMPLEXTEXT
1099 QBidiContext *bidicontext;
1100#endif
1101};
1102
1103#if defined(Q_TEMPLATEDLL)
1104// MOC_SKIP_BEGIN
1105template class Q_EXPORT QMap<int, QTextParagSelection>;
1106template class Q_EXPORT QMap<int, QTextParagLineStart*>;
1107// MOC_SKIP_END
1108#endif
1109
1110class Q_EXPORT QTextParagData
1111{
1112public:
1113 QTextParagData() {}
1114 virtual ~QTextParagData();
1115 virtual void join( QTextParagData * );
1116};
1117
1118class Q_EXPORT QTextParagPseudoDocument
1119{
1120public:
1121 QTextParagPseudoDocument();
1122 ~QTextParagPseudoDocument();
1123 QRect docRect;
1124 QTextFormatter *pFormatter;
1125 QTextCommandHistory *commandHistory;
1126 int minw;
1127 int wused;
1128};
1129
1130//nase
1131class Q_EXPORT QTextParag
1132{
1133 friend class QTextDocument;
1134 friend class QTextCursor;
1135
1136public:
1137 QTextParag( QTextDocument *d, QTextParag *pr = 0, QTextParag *nx = 0, bool updateIds = TRUE );
1138 virtual ~QTextParag();
1139
1140 QTextString *string() const;
1141 QTextStringChar *at( int i ) const; // maybe remove later
1142 int leftGap() const;
1143 int length() const; // maybe remove later
1144
1145 void setListStyle( QStyleSheetItem::ListStyle ls );
1146 QStyleSheetItem::ListStyle listStyle() const;
1147 void setListValue( int v ) { list_val = v; }
1148 int listValue() const { return list_val; }
1149
1150 void setList( bool b, int listStyle );
1151 void incDepth();
1152 void decDepth();
1153 int listDepth() const;
1154
1155 void setFormat( QTextFormat *fm );
1156 QTextFormat *paragFormat() const;
1157
1158 QTextDocument *document() const;
1159 QTextParagPseudoDocument *pseudoDocument() const;
1160
1161 QRect rect() const;
1162 void setHeight( int h ) { r.setHeight( h ); }
1163 void show();
1164 void hide();
1165 bool isVisible() const { return visible; }
1166
1167 QTextParag *prev() const;
1168 QTextParag *next() const;
1169 void setPrev( QTextParag *s );
1170 void setNext( QTextParag *s );
1171
1172 void insert( int index, const QString &s );
1173 void append( const QString &s, bool reallyAtEnd = FALSE );
1174 void truncate( int index );
1175 void remove( int index, int len );
1176 void join( QTextParag *s );
1177
1178 void invalidate( int chr );
1179
1180 void move( int &dy );
1181 void format( int start = -1, bool doMove = TRUE );
1182
1183 bool isValid() const;
1184 bool hasChanged() const;
1185 void setChanged( bool b, bool recursive = FALSE );
1186
1187 int lineHeightOfChar( int i, int *bl = 0, int *y = 0 ) const;
1188 QTextStringChar *lineStartOfChar( int i, int *index = 0, int *line = 0 ) const;
1189 int lines() const;
1190 QTextStringChar *lineStartOfLine( int line, int *index = 0 ) const;
1191 int lineY( int l ) const;
1192 int lineBaseLine( int l ) const;
1193 int lineHeight( int l ) const;
1194 void lineInfo( int l, int &y, int &h, int &bl ) const;
1195
1196 void setSelection( int id, int start, int end );
1197 void removeSelection( int id );
1198 int selectionStart( int id ) const;
1199 int selectionEnd( int id ) const;
1200 bool hasSelection( int id ) const;
1201 bool hasAnySelection() const;
1202 bool fullSelected( int id ) const;
1203
1204 void setEndState( int s );
1205 int endState() const;
1206
1207 void setParagId( int i );
1208 int paragId() const;
1209
1210 bool firstPreProcess() const;
1211 void setFirstPreProcess( bool b );
1212
1213 void indent( int *oldIndent = 0, int *newIndent = 0 );
1214
1215 void setExtraData( QTextParagData *data );
1216 QTextParagData *extraData() const;
1217
1218 QMap<int, QTextParagLineStart*> &lineStartList();
1219
1220 void setFormat( int index, int len, QTextFormat *f, bool useCollection = TRUE, int flags = -1 );
1221
1222 void setAlignment( int a );
1223 int alignment() const;
1224
1225 virtual void paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor = 0, bool drawSelections = FALSE,
1226 int clipx = -1, int clipy = -1, int clipw = -1, int cliph = -1 );
1227
1228 void setStyleSheetItems( const QPtrVector<QStyleSheetItem> &vec );
1229 QPtrVector<QStyleSheetItem> styleSheetItems() const;
1230 QStyleSheetItem *style() const;
1231
1232 virtual int topMargin() const;
1233 virtual int bottomMargin() const;
1234 virtual int leftMargin() const;
1235 virtual int firstLineMargin() const;
1236 virtual int rightMargin() const;
1237 virtual int lineSpacing() const;
1238
1239 int numberOfSubParagraph() const;
1240 void registerFloatingItem( QTextCustomItem *i );
1241 void unregisterFloatingItem( QTextCustomItem *i );
1242
1243 void setFullWidth( bool b ) { fullWidth = b; }
1244 bool isFullWidth() const { return fullWidth; }
1245
1246 QTextTableCell *tableCell() const;
1247
1248 QBrush *background() const;
1249
1250 int documentWidth() const;
1251 int documentVisibleWidth() const;
1252 int documentX() const;
1253 int documentY() const;
1254 QTextFormatCollection *formatCollection() const;
1255 QTextFormatter *formatter() const;
1256
1257 virtual int nextTab( int i, int x );
1258 int *tabArray() const;
1259 void setTabArray( int *a );
1260 void setTabStops( int tw );
1261
1262 void adjustToPainter( QPainter *p );
1263
1264 void setNewLinesAllowed( bool b );
1265 bool isNewLinesAllowed() const;
1266
1267 QString richText() const;
1268
1269 void addCommand( QTextCommand *cmd );
1270 QTextCursor *undo( QTextCursor *c = 0 );
1271 QTextCursor *redo( QTextCursor *c = 0 );
1272 QTextCommandHistory *commands() const;
1273 virtual void copyParagData( QTextParag *parag );
1274
1275 void setBreakable( bool b ) { breakable = b; }
1276 bool isBreakable() const { return breakable; }
1277
1278 void setBackgroundColor( const QColor &c );
1279 QColor *backgroundColor() const { return bgcol; }
1280 void clearBackgroundColor();
1281
1282 bool isLineBreak() const { return isBr; }
1283
1284 void setMovedDown( bool b ) { movedDown = b; }
1285 bool wasMovedDown() const { return movedDown; }
1286
1287 void setDirection( QChar::Direction d );
1288 QChar::Direction direction() const;
1289
1290protected:
1291 virtual void drawLabel( QPainter* p, int x, int y, int w, int h, int base, const QColorGroup& cg );
1292 virtual void drawParagString( QPainter &painter, const QString &str, int start, int len, int startX,
1293 int lastY, int baseLine, int bw, int h, bool drawSelections,
1294 QTextStringChar *formatChar, int i, const QMemArray<int> &selectionStarts,
1295 const QMemArray<int> &selectionEnds, const QColorGroup &cg, bool rightToLeft );
1296
1297private:
1298 QMap<int, QTextParagSelection> &selections() const;
1299 QPtrVector<QStyleSheetItem> &styleSheetItemsVec() const;
1300 QPtrList<QTextCustomItem> &floatingItems() const;
1301
1302 QMap<int, QTextParagLineStart*> lineStarts;
1303 int invalid;
1304 QRect r;
1305 QTextParag *p, *n;
1306 void *docOrPseudo;
1307 uint changed : 1;
1308 uint firstFormat : 1;
1309 uint firstPProcess : 1;
1310 uint needPreProcess : 1;
1311 uint fullWidth : 1;
1312 uint newLinesAllowed : 1;
1313 uint lastInFrame : 1;
1314 uint visible : 1;
1315 uint breakable : 1;
1316 uint isBr : 1;
1317 uint movedDown : 1;
1318 uint mightHaveCustomItems : 1;
1319 uint hasdoc : 1;
1320 int align : 4;
1321 int state, id;
1322 QTextString *str;
1323 QMap<int, QTextParagSelection> *mSelections;
1324 QPtrVector<QStyleSheetItem> *mStyleSheetItemsVec;
1325 QPtrList<QTextCustomItem> *mFloatingItems;
1326 QStyleSheetItem::ListStyle listS;
1327 int numSubParag;
1328 int tm, bm, lm, rm, flm;
1329 QTextFormat *defFormat;
1330 int *tArray;
1331 int tabStopWidth;
1332 QTextParagData *eData;
1333 int list_val;
1334 QColor *bgcol;
1335
1336};
1337
1338// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1339
1340class Q_EXPORT QTextFormatter
1341{
1342public:
1343 QTextFormatter();
1344 virtual ~QTextFormatter();
1345
1346 virtual int format( QTextDocument *doc, QTextParag *parag, int start, const QMap<int, QTextParagLineStart*> &oldLineStarts ) = 0;
1347 virtual int formatVertically( QTextDocument* doc, QTextParag* parag );
1348
1349 bool isWrapEnabled( QTextParag *p ) const { if ( !wrapEnabled ) return FALSE; if ( p && !p->isBreakable() ) return FALSE; return TRUE;}
1350 int wrapAtColumn() const { return wrapColumn;}
1351 virtual void setWrapEnabled( bool b );
1352 virtual void setWrapAtColumn( int c );
1353 virtual void setAllowBreakInWords( bool b ) { biw = b; }
1354 bool allowBreakInWords() const { return biw; }
1355
1356 int minimumWidth() const { return thisminw; }
1357 int widthUsed() const { return thiswused; }
1358
1359protected:
1360 virtual QTextParagLineStart *formatLine( QTextParag *parag, QTextString *string, QTextParagLineStart *line, QTextStringChar *start,
1361 QTextStringChar *last, int align = Qt3::AlignAuto, int space = 0 );
1362#ifndef QT_NO_COMPLEXTEXT
1363 virtual QTextParagLineStart *bidiReorderLine( QTextParag *parag, QTextString *string, QTextParagLineStart *line, QTextStringChar *start,
1364 QTextStringChar *last, int align, int space );
1365#endif
1366 virtual bool isBreakable( QTextString *string, int pos ) const;
1367 void insertLineStart( QTextParag *parag, int index, QTextParagLineStart *ls );
1368
1369 int thisminw;
1370 int thiswused;
1371
1372private:
1373 bool wrapEnabled;
1374 int wrapColumn;
1375 bool biw;
1376
1377#ifdef HAVE_THAI_BREAKS
1378 static QCString *thaiCache;
1379 static QTextString *cachedString;
1380 static ThBreakIterator *thaiIt;
1381#endif
1382};
1383
1384// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1385
1386class Q_EXPORT QTextFormatterBreakInWords : public QTextFormatter
1387{
1388public:
1389 QTextFormatterBreakInWords();
1390 virtual ~QTextFormatterBreakInWords() {}
1391
1392 int format( QTextDocument *doc, QTextParag *parag, int start, const QMap<int, QTextParagLineStart*> &oldLineStarts );
1393
1394};
1395
1396// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1397
1398class Q_EXPORT QTextFormatterBreakWords : public QTextFormatter
1399{
1400public:
1401 QTextFormatterBreakWords();
1402 virtual ~QTextFormatterBreakWords() {}
1403
1404 int format( QTextDocument *doc, QTextParag *parag, int start, const QMap<int, QTextParagLineStart*> &oldLineStarts );
1405
1406};
1407
1408// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1409
1410class Q_EXPORT QTextIndent
1411{
1412public:
1413 QTextIndent();
1414 virtual ~QTextIndent() {}
1415
1416 virtual void indent( QTextDocument *doc, QTextParag *parag, int *oldIndent = 0, int *newIndent = 0 ) = 0;
1417
1418};
1419
1420// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1421
1422class Q_EXPORT QTextPreProcessor
1423{
1424public:
1425 enum Ids {
1426 Standard = 0
1427 };
1428
1429 QTextPreProcessor();
1430 virtual ~QTextPreProcessor() {}
1431
1432 virtual void process( QTextDocument *doc, QTextParag *, int, bool = TRUE ) = 0;
1433 virtual QTextFormat *format( int id ) = 0;
1434
1435};
1436
1437// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1438
1439class Q_EXPORT QTextFormat
1440{
1441 friend class QTextFormatCollection;
1442 friend class QTextDocument;
1443
1444public:
1445 enum Flags {
1446 NoFlags,
1447 Bold = 1,
1448 Italic = 2,
1449 Underline = 4,
1450 Family = 8,
1451 Size = 16,
1452 Color = 32,
1453 Misspelled = 64,
1454 VAlign = 128,
1455 Font = Bold | Italic | Underline | Family | Size,
1456 Format = Font | Color | Misspelled | VAlign
1457 };
1458
1459 enum VerticalAlignment { AlignNormal, AlignSuperScript, AlignSubScript };
1460
1461 QTextFormat();
1462 virtual ~QTextFormat();
1463
1464 QTextFormat( const QStyleSheetItem *s );
1465 QTextFormat( const QFont &f, const QColor &c, QTextFormatCollection *parent = 0 );
1466 QTextFormat( const QTextFormat &fm );
1467 QTextFormat makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr ) const;
1468 QTextFormat& operator=( const QTextFormat &fm );
1469 QColor color() const;
1470 QFont font() const;
1471 bool isMisspelled() const;
1472 VerticalAlignment vAlign() const;
1473 int minLeftBearing() const;
1474 int minRightBearing() const;
1475 int width( const QChar &c ) const;
1476 int width( const QString &str, int pos ) const;
1477 int height() const;
1478 int ascent() const;
1479 int descent() const;
1480 int leading() const;
1481 bool useLinkColor() const;
1482
1483 void setBold( bool b );
1484 void setItalic( bool b );
1485 void setUnderline( bool b );
1486 void setFamily( const QString &f );
1487 void setPointSize( int s );
1488 void setFont( const QFont &f );
1489 void setColor( const QColor &c );
1490 void setMisspelled( bool b );
1491 void setVAlign( VerticalAlignment a );
1492
1493 bool operator==( const QTextFormat &f ) const;
1494 QTextFormatCollection *parent() const;
1495 QString key() const;
1496
1497 static QString getKey( const QFont &f, const QColor &c, bool misspelled, VerticalAlignment vAlign );
1498
1499 void addRef();
1500 void removeRef();
1501
1502 QString makeFormatChangeTags( QTextFormat *f, const QString& oldAnchorHref, const QString& anchorHref ) const;
1503 QString makeFormatEndTags( const QString& anchorHref ) const;
1504
1505 static void setPainter( QPainter *p );
1506 static QPainter* painter();
1507 void updateStyle();
1508 void updateStyleFlags();
1509 void setStyle( const QString &s );
1510 QString styleName() const { return style; }
1511
1512 int changed() const { return different; }
1513 bool fontSizesInPixels() { return usePixelSizes; }
1514
1515protected:
1516 virtual void generateKey();
1517
1518private:
1519 void update();
1520
1521private:
1522 QFont fn;
1523 QColor col;
1524 QFontMetrics fm;
1525 uint missp : 1;
1526 uint linkColor : 1;
1527 uint usePixelSizes : 1;
1528 int leftBearing, rightBearing;
1529 VerticalAlignment ha;
1530 uchar widths[ 256 ];
1531 int hei, asc, dsc;
1532 QTextFormatCollection *collection;
1533 int ref;
1534 QString k;
1535 int logicalFontSize;
1536 int stdSize;
1537 static QPainter *pntr;
1538 QString style;
1539 int different;
1540
1541};
1542
1543// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1544
1545#if defined(Q_TEMPLATEDLL)
1546// MOC_SKIP_BEGIN
1547template class Q_EXPORT QDict<QTextFormat>;
1548// MOC_SKIP_END
1549#endif
1550
1551class Q_EXPORT QTextFormatCollection
1552{
1553 friend class QTextDocument;
1554 friend class QTextFormat;
1555
1556public:
1557 QTextFormatCollection();
1558 virtual ~QTextFormatCollection();
1559
1560 void setDefaultFormat( QTextFormat *f );
1561 QTextFormat *defaultFormat() const;
1562 virtual QTextFormat *format( QTextFormat *f );
1563 virtual QTextFormat *format( QTextFormat *of, QTextFormat *nf, int flags );
1564 virtual QTextFormat *format( const QFont &f, const QColor &c );
1565 virtual void remove( QTextFormat *f );
1566 virtual QTextFormat *createFormat( const QTextFormat &f ) { return new QTextFormat( f ); }
1567 virtual QTextFormat *createFormat( const QFont &f, const QColor &c ) { return new QTextFormat( f, c, this ); }
1568 void debug();
1569
1570 QStyleSheet *styleSheet() const { return sheet; }
1571 void setStyleSheet( QStyleSheet *s ) { sheet = s; }
1572 void updateStyles();
1573 void updateFontSizes( int base, bool usePixels );
1574 void updateFontAttributes( const QFont &f, const QFont &old );
1575 QDict<QTextFormat> dict() const { return cKey; }
1576
1577private:
1578 void updateKeys();
1579
1580private:
1581 QTextFormat *defFormat, *lastFormat, *cachedFormat;
1582 QDict<QTextFormat> cKey;
1583 QTextFormat *cres;
1584 QFont cfont;
1585 QColor ccol;
1586 QString kof, knf;
1587 int cflags;
1588 QStyleSheet *sheet;
1589
1590};
1591
1592// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1593
1594inline int QTextString::length() const
1595{
1596 return data.size();
1597}
1598
1599inline void QTextString::operator+=( const QString &s )
1600{
1601 insert( length(), s, 0 );
1602}
1603
1604inline int QTextParag::length() const
1605{
1606 return str->length();
1607}
1608
1609inline QRect QTextParag::rect() const
1610{
1611 return r;
1612}
1613
1614inline QTextParag *QTextCursor::parag() const
1615{
1616 return string;
1617}
1618
1619inline int QTextCursor::index() const
1620{
1621 return idx;
1622}
1623
1624inline void QTextCursor::setIndex( int i, bool restore )
1625{
1626 if ( restore )
1627 restoreState();
1628 if ( i < 0 || i >= string->length() ) {
1629#if defined(QT_CHECK_RANGE)
1630 qWarning( "QTextCursor::setIndex: %d out of range", i );
1631#endif
1632 i = i < 0 ? 0 : string->length() - 1;
1633 }
1634
1635 tmpIndex = -1;
1636 idx = i;
1637}
1638
1639inline void QTextCursor::setParag( QTextParag *s, bool restore )
1640{
1641 if ( restore )
1642 restoreState();
1643 idx = 0;
1644 string = s;
1645 tmpIndex = -1;
1646}
1647
1648inline void QTextCursor::checkIndex()
1649{
1650 if ( idx >= string->length() )
1651 idx = string->length() - 1;
1652}
1653
1654// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1655
1656inline int QTextDocument::x() const
1657{
1658 return cx;
1659}
1660
1661inline int QTextDocument::y() const
1662{
1663 return cy;
1664}
1665
1666inline int QTextDocument::width() const
1667{
1668 return QMAX( cw, flow_->width() );
1669}
1670
1671inline int QTextDocument::visibleWidth() const
1672{
1673 return vw;
1674}
1675
1676inline QTextParag *QTextDocument::firstParag() const
1677{
1678 return fParag;
1679}
1680
1681inline QTextParag *QTextDocument::lastParag() const
1682{
1683 return lParag;
1684}
1685
1686inline void QTextDocument::setFirstParag( QTextParag *p )
1687{
1688 fParag = p;
1689}
1690
1691inline void QTextDocument::setLastParag( QTextParag *p )
1692{
1693 lParag = p;
1694}
1695
1696inline void QTextDocument::setWidth( int w )
1697{
1698 cw = QMAX( w, minw );
1699 flow_->setWidth( cw );
1700 vw = w;
1701}
1702
1703inline int QTextDocument::minimumWidth() const
1704{
1705 return minw;
1706}
1707
1708inline void QTextDocument::setY( int y )
1709{
1710 cy = y;
1711}
1712
1713inline int QTextDocument::leftMargin() const
1714{
1715 return leftmargin;
1716}
1717
1718inline void QTextDocument::setLeftMargin( int lm )
1719{
1720 leftmargin = lm;
1721}
1722
1723inline int QTextDocument::rightMargin() const
1724{
1725 return rightmargin;
1726}
1727
1728inline void QTextDocument::setRightMargin( int rm )
1729{
1730 rightmargin = rm;
1731}
1732
1733inline QTextPreProcessor *QTextDocument::preProcessor() const
1734{
1735 return pProcessor;
1736}
1737
1738inline void QTextDocument::setPreProcessor( QTextPreProcessor * sh )
1739{
1740 pProcessor = sh;
1741}
1742
1743inline void QTextDocument::setFormatter( QTextFormatter *f )
1744{
1745 delete pFormatter;
1746 pFormatter = f;
1747}
1748
1749inline QTextFormatter *QTextDocument::formatter() const
1750{
1751 return pFormatter;
1752}
1753
1754inline void QTextDocument::setIndent( QTextIndent *i )
1755{
1756 indenter = i;
1757}
1758
1759inline QTextIndent *QTextDocument::indent() const
1760{
1761 return indenter;
1762}
1763
1764inline QColor QTextDocument::selectionColor( int id ) const
1765{
1766 return selectionColors[ id ];
1767}
1768
1769inline bool QTextDocument::invertSelectionText( int id ) const
1770{
1771 return selectionText[ id ];
1772}
1773
1774inline void QTextDocument::setSelectionColor( int id, const QColor &c )
1775{
1776 selectionColors[ id ] = c;
1777}
1778
1779inline void QTextDocument::setInvertSelectionText( int id, bool b )
1780{
1781 selectionText[ id ] = b;
1782}
1783
1784inline QTextFormatCollection *QTextDocument::formatCollection() const
1785{
1786 return fCollection;
1787}
1788
1789inline int QTextDocument::alignment() const
1790{
1791 return align;
1792}
1793
1794inline void QTextDocument::setAlignment( int a )
1795{
1796 align = a;
1797}
1798
1799inline int *QTextDocument::tabArray() const
1800{
1801 return tArray;
1802}
1803
1804inline int QTextDocument::tabStopWidth() const
1805{
1806 return tStopWidth;
1807}
1808
1809inline void QTextDocument::setTabArray( int *a )
1810{
1811 tArray = a;
1812}
1813
1814inline void QTextDocument::setTabStops( int tw )
1815{
1816 tStopWidth = tw;
1817}
1818
1819inline QString QTextDocument::originalText() const
1820{
1821 if ( oTextValid )
1822 return oText;
1823 return text();
1824}
1825
1826inline void QTextDocument::setFlow( QTextFlow *f )
1827{
1828 if ( flow_ )
1829 delete flow_;
1830 flow_ = f;
1831}
1832
1833inline void QTextDocument::takeFlow()
1834{
1835 flow_ = 0;
1836}
1837
1838// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1839
1840inline QColor QTextFormat::color() const
1841{
1842 return col;
1843}
1844
1845inline QFont QTextFormat::font() const
1846{
1847 return fn;
1848}
1849
1850inline bool QTextFormat::isMisspelled() const
1851{
1852 return missp;
1853}
1854
1855inline QTextFormat::VerticalAlignment QTextFormat::vAlign() const
1856{
1857 return ha;
1858}
1859
1860inline bool QTextFormat::operator==( const QTextFormat &f ) const
1861{
1862 return k == f.k;
1863}
1864
1865inline QTextFormatCollection *QTextFormat::parent() const
1866{
1867 return collection;
1868}
1869
1870inline void QTextFormat::addRef()
1871{
1872 ref++;
1873#ifdef DEBUG_COLLECTION
1874 qDebug( "add ref of '%s' to %d (%p)", k.latin1(), ref, this );
1875#endif
1876}
1877
1878inline void QTextFormat::removeRef()
1879{
1880 ref--;
1881 if ( !collection )
1882 return;
1883 if ( this == collection->defFormat )
1884 return;
1885#ifdef DEBUG_COLLECTION
1886 qDebug( "remove ref of '%s' to %d (%p)", k.latin1(), ref, this );
1887#endif
1888 if ( ref == 0 )
1889 collection->remove( this );
1890}
1891
1892inline QString QTextFormat::key() const
1893{
1894 return k;
1895}
1896
1897inline bool QTextFormat::useLinkColor() const
1898{
1899 return linkColor;
1900}
1901
1902inline void QTextFormat::setStyle( const QString &s )
1903{
1904 style = s;
1905 updateStyleFlags();
1906}
1907
1908// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1909
1910inline QTextStringChar &QTextString::at( int i ) const
1911{
1912 return data[ i ];
1913}
1914
1915// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1916
1917inline QTextStringChar *QTextParag::at( int i ) const
1918{
1919 return &str->at( i );
1920}
1921
1922inline bool QTextParag::isValid() const
1923{
1924 return invalid == -1;
1925}
1926
1927inline bool QTextParag::hasChanged() const
1928{
1929 return changed;
1930}
1931
1932inline void QTextParag::setBackgroundColor( const QColor & c )
1933{
1934 delete bgcol;
1935 bgcol = new QColor( c );
1936 setChanged( TRUE );
1937}
1938
1939inline void QTextParag::clearBackgroundColor()
1940{
1941 delete bgcol; bgcol = 0; setChanged( TRUE );
1942}
1943
1944inline void QTextParag::append( const QString &s, bool reallyAtEnd )
1945{
1946 if ( reallyAtEnd )
1947 insert( str->length(), s );
1948 else
1949 insert( QMAX( str->length() - 1, 0 ), s );
1950}
1951
1952inline QTextParag *QTextParag::prev() const
1953{
1954 return p;
1955}
1956
1957inline QTextParag *QTextParag::next() const
1958{
1959 return n;
1960}
1961
1962inline bool QTextParag::hasAnySelection() const
1963{
1964 return mSelections ? !selections().isEmpty() : FALSE;
1965}
1966
1967inline void QTextParag::setEndState( int s )
1968{
1969 if ( s == state )
1970 return;
1971 state = s;
1972}
1973
1974inline int QTextParag::endState() const
1975{
1976 return state;
1977}
1978
1979inline void QTextParag::setParagId( int i )
1980{
1981 id = i;
1982}
1983
1984inline int QTextParag::paragId() const
1985{
1986 if ( id == -1 )
1987 qWarning( "invalid parag id!!!!!!!! (%p)", (void*)this );
1988 return id;
1989}
1990
1991inline bool QTextParag::firstPreProcess() const
1992{
1993 return firstPProcess;
1994}
1995
1996inline void QTextParag::setFirstPreProcess( bool b )
1997{
1998 firstPProcess = b;
1999}
2000
2001inline QMap<int, QTextParagLineStart*> &QTextParag::lineStartList()
2002{
2003 return lineStarts;
2004}
2005
2006inline QTextString *QTextParag::string() const
2007{
2008 return str;
2009}
2010
2011inline QTextDocument *QTextParag::document() const
2012{
2013 if ( hasdoc )
2014 return (QTextDocument*) docOrPseudo;
2015 return 0;
2016}
2017
2018inline QTextParagPseudoDocument *QTextParag::pseudoDocument() const
2019{
2020 if ( hasdoc )
2021 return 0;
2022 return (QTextParagPseudoDocument*) docOrPseudo;
2023}
2024
2025
2026inline QTextTableCell *QTextParag::tableCell() const
2027{
2028 return hasdoc ? document()->tableCell () : 0;
2029}
2030
2031inline QTextCommandHistory *QTextParag::commands() const
2032{
2033 return hasdoc ? document()->commands() : pseudoDocument()->commandHistory;
2034}
2035
2036
2037inline void QTextParag::setAlignment( int a )
2038{
2039 if ( a == (int)align )
2040 return;
2041 align = a;
2042 invalidate( 0 );
2043}
2044
2045inline void QTextParag::setListStyle( QStyleSheetItem::ListStyle ls )
2046{
2047 listS = ls;
2048 invalidate( 0 );
2049}
2050
2051inline QStyleSheetItem::ListStyle QTextParag::listStyle() const
2052{
2053 return listS;
2054}
2055
2056inline QTextFormat *QTextParag::paragFormat() const
2057{
2058 return defFormat;
2059}
2060
2061inline void QTextParag::registerFloatingItem( QTextCustomItem *i )
2062{
2063 floatingItems().append( i );
2064}
2065
2066inline void QTextParag::unregisterFloatingItem( QTextCustomItem *i )
2067{
2068 floatingItems().removeRef( i );
2069}
2070
2071inline QBrush *QTextParag::background() const
2072{
2073 return tableCell() ? tableCell()->backGround() : 0;
2074}
2075
2076inline int QTextParag::documentWidth() const
2077{
2078 return hasdoc ? document()->width() : pseudoDocument()->docRect.width();
2079}
2080
2081inline int QTextParag::documentVisibleWidth() const
2082{
2083 return hasdoc ? document()->visibleWidth() : pseudoDocument()->docRect.width();
2084}
2085
2086inline int QTextParag::documentX() const
2087{
2088 return hasdoc ? document()->x() : pseudoDocument()->docRect.x();
2089}
2090
2091inline int QTextParag::documentY() const
2092{
2093 return hasdoc ? document()->y() : pseudoDocument()->docRect.y();
2094}
2095
2096inline void QTextParag::setExtraData( QTextParagData *data )
2097{
2098 eData = data;
2099}
2100
2101inline QTextParagData *QTextParag::extraData() const
2102{
2103 return eData;
2104}
2105
2106inline void QTextParag::setNewLinesAllowed( bool b )
2107{
2108 newLinesAllowed = b;
2109}
2110
2111inline bool QTextParag::isNewLinesAllowed() const
2112{
2113 return newLinesAllowed;
2114}
2115
2116// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2117
2118inline void QTextFormatCollection::setDefaultFormat( QTextFormat *f )
2119{
2120 defFormat = f;
2121}
2122
2123inline QTextFormat *QTextFormatCollection::defaultFormat() const
2124{
2125 return defFormat;
2126}
2127
2128// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2129
2130inline QTextFormat *QTextStringChar::format() const
2131{
2132 return (type == Regular) ? d.format : d.custom->format;
2133}
2134
2135
2136inline QTextCustomItem *QTextStringChar::customItem() const
2137{
2138 return isCustom() ? d.custom->custom : 0;
2139}
2140
2141inline int QTextStringChar::height() const
2142{
2143 return !isCustom() ? format()->height() : ( customItem()->placement() == QTextCustomItem::PlaceInline ? customItem()->height : 0 );
2144}
2145
2146inline int QTextStringChar::ascent() const
2147{
2148 return !isCustom() ? format()->ascent() : ( customItem()->placement() == QTextCustomItem::PlaceInline ? customItem()->ascent() : 0 );
2149}
2150
2151inline int QTextStringChar::descent() const
2152{
2153 return !isCustom() ? format()->descent() : 0;
2154}
2155
2156} // namespace Qt3
2157
2158#endif
diff --git a/noncore/apps/opie-write/qstylesheet.cpp b/noncore/apps/opie-write/qstylesheet.cpp
new file mode 100644
index 0000000..7ab9ec6
--- a/dev/null
+++ b/noncore/apps/opie-write/qstylesheet.cpp
@@ -0,0 +1,1484 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of the QStyleSheet class
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qstylesheet.h"
39
40#include "qrichtext_p.h"
41#include "qlayout.h"
42#include "qpainter.h"
43#include "qcleanuphandler.h"
44
45#include <stdio.h>
46
47using namespace Qt3;
48
49namespace Qt3 {
50
51class QStyleSheetItemData
52{
53public:
54 QStyleSheetItem::DisplayMode disp;
55 int fontitalic;
56 int fontunderline;
57 int fontweight;
58 int fontsize;
59 int fontsizelog;
60 int fontsizestep;
61 int lineSpacing;
62 QString fontfamily;
63 QStyleSheetItem *parentstyle;
64 QString stylename;
65 int ncolumns;
66 QColor col;
67 bool anchor;
68 int align;
69 QStyleSheetItem::VerticalAlignment valign;
70 int margin[5];
71 QStyleSheetItem::ListStyle list;
72 QStyleSheetItem::WhiteSpaceMode whitespacemode;
73 QString contxt;
74 bool selfnest;
75 QStyleSheet* sheet;
76};
77
78}
79
80/*!
81 \class QStyleSheetItem qstylesheet.h
82 \ingroup text
83 \brief The QStyleSheetItem class provides an encapsulation of a set of text styles.
84
85 A style sheet item consists of a name and a set of attributes that
86 specifiy its font, color, etc. When used in a \link QStyleSheet
87 style sheet\endlink (see styleSheet()), items define the name() of a
88 rich text tag and the display property changes associated with it.
89
90 The \link QStyleSheetItem::DisplayMode display mode\endlink
91 attribute indicates whether the item is a block, an inline element
92 or a list element; see setDisplayMode(). The treatment of whitespace
93 is controlled by the \link QStyleSheetItem::WhiteSpaceMode white
94 space mode\endlink; see setWhiteSpaceMode(). An item's margins are
95 set with setMargin(), and line spacing is set with setLineSpacing().
96 In the case of list items, the list style is set with
97 setListStyle(). An item may be a hypertext link anchor; see
98 setAnchor(). Other attributes are set with setAlignment(),
99 setVerticalAlignment(), setFontFamily(), setFontSize(),
100 setFontWeight(), setFontItalic(), setFontUnderline() and setColor().
101*/
102
103/*! \enum QStyleSheetItem::AdditionalStyleValues
104 \internal
105*/
106
107/*! \enum QStyleSheetItem::WhiteSpaceMode
108
109 This enum defines the ways in which QStyleSheet can treat whitespace. There are three values at present:
110
111 \value WhiteSpaceNormal any sequence of whitespace (including
112 line-breaks) is equivalent to a single space.
113
114 \value WhiteSpacePre whitespace must be output exactly as given
115 in the input.
116
117 \value WhiteSpaceNoWrap multiple spaces are collapsed as with
118 WhiteSpaceNormal, but no automatic line-breaks occur. To break lines manually,
119 use the \c{<br>} tag.
120
121*/
122
123/*! \enum QStyleSheetItem::Margin
124
125 \value MarginLeft left margin
126 \value MarginRight right margin
127 \value MarginTop top margin
128 \value MarginBottom bottom margin
129 \value MarginAll all margins (left, right, top and bottom)
130 \value MarginVertical top and bottom margins
131 \value MarginHorizontal left and right margins
132 \value MarginFirstLine margin (indentation) of the first line of a paragarph (in addition to the MarginLeft of the paragraph)
133*/
134
135/*!
136 Constructs a new style named \a name for the stylesheet \a parent.
137
138 All properties in QStyleSheetItem are initially in the "do not change" state,
139 except \link QStyleSheetItem::DisplayMode display mode\endlink, which defaults
140 to \c DisplayInline.
141*/
142QStyleSheetItem::QStyleSheetItem( QStyleSheet* parent, const QString& name )
143{
144 d = new QStyleSheetItemData;
145 d->stylename = name.lower();
146 d->sheet = parent;
147 init();
148 if (parent)
149 parent->insert( this );
150}
151
152/*!
153 Copy constructor. Constructs a copy of \a other that is
154 not bound to any style sheet.
155 */
156QStyleSheetItem::QStyleSheetItem( const QStyleSheetItem & other )
157{
158 d = new QStyleSheetItemData;
159 *d = *other.d;
160}
161
162
163/*!
164 Destroys the style. Note that QStyleSheetItem objects become owned
165 by QStyleSheet when they are created.
166 */
167QStyleSheetItem::~QStyleSheetItem()
168{
169 delete d;
170}
171
172
173
174/*!
175 Returns the style sheet this item is in.
176 */
177QStyleSheet* QStyleSheetItem::styleSheet()
178{
179 return d->sheet;
180}
181
182/*!
183 \overload
184 Returns the style sheet this item is in.
185 */
186const QStyleSheet* QStyleSheetItem::styleSheet() const
187{
188 return d->sheet;
189}
190
191/*!
192 \internal
193 Internal initialization
194 */
195void QStyleSheetItem::init()
196{
197 d->disp = DisplayInline;
198
199 d->fontitalic = Undefined;
200 d->fontunderline = Undefined;
201 d->fontweight = Undefined;
202 d->fontsize = Undefined;
203 d->fontsizelog = Undefined;
204 d->fontsizestep = 0;
205 d->ncolumns = Undefined;
206 d->col = QColor(); // !isValid()
207 d->anchor = FALSE;
208 d->align = Undefined;
209 d->valign = VAlignBaseline;
210 d->margin[0] = Undefined;
211 d->margin[1] = Undefined;
212 d->margin[2] = Undefined;
213 d->margin[3] = Undefined;
214 d->margin[4] = Undefined;
215 d->list = QStyleSheetItem::ListDisc;
216 d->whitespacemode = QStyleSheetItem::WhiteSpaceNormal;
217 d->selfnest = TRUE;
218 d->lineSpacing = Undefined;
219}
220
221/*!
222 Returns the name of the style item.
223*/
224QString QStyleSheetItem::name() const
225{
226 return d->stylename;
227}
228
229/*!
230 Returns the \link QStyleSheetItem::DisplayMode display mode\endlink
231 of the style.
232
233 \sa setDisplayMode()
234 */
235QStyleSheetItem::DisplayMode QStyleSheetItem::displayMode() const
236{
237 return d->disp;
238}
239
240/*! \enum QStyleSheetItem::DisplayMode
241
242 This enum type defines the way adjacent elements are displayed. The possible values are:
243
244 \value DisplayBlock elements are displayed as a rectangular block
245 (e.g. \c{<p>...</p>}).
246
247 \value DisplayInline elements are displayed in a horizontally flowing
248 sequence (e.g. \c{<em>...</em>}).
249
250 \value DisplayListItem elements are displayed in a vertical sequence
251 (e.g. \c{<li>...</li>}).
252
253 \value DisplayNone elements are not displayed at all.
254*/
255
256/*!
257 Sets the display mode of the style to \a m.
258
259 \sa displayMode()
260 */
261void QStyleSheetItem::setDisplayMode(DisplayMode m)
262{
263 d->disp=m;
264}
265
266
267/*!
268 Returns the alignment of this style. Possible values are AlignAuto, AlignLeft,
269 AlignRight, AlignCenter and AlignJustify.
270
271 \sa setAlignment(), Qt::AlignmentFlags
272 */
273int QStyleSheetItem::alignment() const
274{
275 return d->align;
276}
277
278/*!
279 Sets the alignment to \a f. This only makes sense for styles with a
280 \link QStyleSheetItem::DisplayMode display mode\endlink of
281 DisplayBlock. Possible values are AlignAuto, AlignLeft, AlignRight,
282 AlignCenter and AlignJustify.
283
284 \sa alignment(), displayMode(), Qt::AlignmentFlags
285 */
286void QStyleSheetItem::setAlignment( int f )
287{
288 d->align = f;
289}
290
291
292/*!
293 Returns the vertical alignment of the style. Possible values are
294 VAlignBaseline, VAlignSub and VAlignSuper.
295
296 psa setVerticalAlignment()
297 */
298QStyleSheetItem::VerticalAlignment QStyleSheetItem::verticalAlignment() const
299{
300 return d->valign;
301}
302
303/*! \enum QStyleSheetItem::VerticalAlignment
304
305 This enum type defines the way elements are aligned vertically. This
306 is supported for text elements only. The possible values are:
307
308 \value VAlignBaseline align the baseline of the element (or the
309 bottom, if the element doesn't have a baseline) with the baseline of
310 the parent
311
312 \value VAlignSub subscript the element
313
314 \value VAlignSuper superscript the element
315
316*/
317
318
319/*!
320 Sets the vertical alignment to \a valign. Possible values are
321 VAlignBaseline, VAlignSub and VAlignSuper.
322
323 The vertical alignment property is not inherited.
324
325 \sa verticalAlignment()
326 */
327void QStyleSheetItem::setVerticalAlignment( VerticalAlignment valign )
328{
329 d->valign = valign;
330}
331
332
333/*!
334 Returns TRUE if the style sets an italic font; otherwise returns FALSE.
335
336 \sa setFontItalic(), definesFontItalic()
337 */
338bool QStyleSheetItem::fontItalic() const
339{
340 return d->fontitalic > 0;
341}
342
343/*!
344 If \a italic is TRUE sets italic for the style; otherwise sets
345 upright.
346
347 \sa fontItalic(), definesFontItalic()
348 */
349void QStyleSheetItem::setFontItalic(bool italic)
350{
351 d->fontitalic = italic?1:0;
352}
353
354/*!
355 Returns whether the style defines a font shape. A style
356 does not define any shape until setFontItalic() is called.
357
358 \sa setFontItalic(), fontItalic()
359 */
360bool QStyleSheetItem::definesFontItalic() const
361{
362 return d->fontitalic != Undefined;
363}
364
365/*!
366 Returns TRUE if the style sets an underlined font; otherwise returns FALSE.
367
368 \sa setFontUnderline(), definesFontUnderline()
369 */
370bool QStyleSheetItem::fontUnderline() const
371{
372 return d->fontunderline > 0;
373}
374
375/*!
376 If \a underline is TRUE sets underline for the style; otherwise sets
377 no underline.
378
379 \sa fontUnderline(), definesFontUnderline()
380 */
381void QStyleSheetItem::setFontUnderline(bool underline)
382{
383 d->fontunderline = underline?1:0;
384}
385
386/*!
387 Returns whether the style defines a setting for the underline
388 property of the font. A style does not define this until
389 setFontUnderline() is called.
390
391 \sa setFontUnderline(), fontUnderline() */
392bool QStyleSheetItem::definesFontUnderline() const
393{
394 return d->fontunderline != Undefined;
395}
396
397
398/*!
399 Returns the font weight setting of the style. This is either a
400 valid QFont::Weight or the value QStyleSheetItem::Undefined.
401
402 \sa setFontWeight(), QFont
403 */
404int QStyleSheetItem::fontWeight() const
405{
406 return d->fontweight;
407}
408
409/*!
410 Sets the font weight setting of the style to \a w. Valid values are
411 those defined by QFont::Weight.
412
413 \sa QFont, fontWeight()
414 */
415void QStyleSheetItem::setFontWeight(int w)
416{
417 d->fontweight = w;
418}
419
420/*!
421 Returns the logical font size setting of the style. This is either a valid
422 size between 1 and 7 or QStyleSheetItem::Undefined.
423
424 \sa setLogicalFontSize(), setLogicalFontSizeStep(), QFont::pointSize(), QFont::setPointSize()
425 */
426int QStyleSheetItem::logicalFontSize() const
427{
428 return d->fontsizelog;
429}
430
431
432/*!
433 Sets the logical font size setting of the style to \a s.
434 Valid logical sizes are 1 to 7.
435
436 \sa logicalFontSize(), QFont::pointSize(), QFont::setPointSize()
437 */
438void QStyleSheetItem::setLogicalFontSize(int s)
439{
440 d->fontsizelog = s;
441}
442
443/*!
444 Returns the logical font size step of this style.
445
446 The default is 0. Tags such as \c big define \c +1; \c small defines
447 \c -1.
448
449 \sa setLogicalFontSizeStep()
450 */
451int QStyleSheetItem::logicalFontSizeStep() const
452{
453 return d->fontsizestep;
454}
455
456/*!
457 Sets the logical font size step of this style to \a s.
458
459 \sa logicalFontSizeStep()
460 */
461void QStyleSheetItem::setLogicalFontSizeStep( int s )
462{
463 d->fontsizestep = s;
464}
465
466
467
468/*!
469 Sets the font size setting of the style to \a s points.
470
471 \sa fontSize(), QFont::pointSize(), QFont::setPointSize()
472 */
473void QStyleSheetItem::setFontSize(int s)
474{
475 d->fontsize = s;
476}
477
478/*!
479 Returns the font size setting of the style. This is either a valid
480 point size or QStyleSheetItem::Undefined.
481
482 \sa setFontSize(), QFont::pointSize(), QFont::setPointSize()
483 */
484int QStyleSheetItem::fontSize() const
485{
486 return d->fontsize;
487}
488
489
490/*!
491 Returns the font family setting of the style. This is either a valid
492 font family or QString::null if no family has been set.
493
494 \sa setFontFamily(), QFont::family(), QFont::setFamily()
495 */
496QString QStyleSheetItem::fontFamily() const
497{
498 return d->fontfamily;
499}
500
501/*!
502 Sets the font family setting of the style to \a fam.
503
504 \sa fontFamily(), QFont::family(), QFont::setFamily()
505 */
506void QStyleSheetItem::setFontFamily( const QString& fam)
507{
508 d->fontfamily = fam;
509}
510
511
512/*!\obsolete
513 Returns the number of columns for this style.
514
515 \sa setNumberOfColumns(), displayMode(), setDisplayMode()
516
517 */
518int QStyleSheetItem::numberOfColumns() const
519{
520 return d->ncolumns;
521}
522
523
524/*!\obsolete
525 Sets the number of columns for this style. Elements in the style
526 are divided into columns.
527
528 This makes sense only if the style uses a block display mode
529 (see QStyleSheetItem::DisplayMode).
530
531 \sa numberOfColumns()
532 */
533void QStyleSheetItem::setNumberOfColumns(int ncols)
534{
535 if (ncols > 0)
536 d->ncolumns = ncols;
537}
538
539
540/*!
541 Returns the text color of this style or an invalid color
542 if no color has been set.
543
544 \sa setColor() QColor::isValid()
545 */
546QColor QStyleSheetItem::color() const
547{
548 return d->col;
549}
550
551/*!
552 Sets the text color of this style to \a c.
553
554 \sa color()
555 */
556void QStyleSheetItem::setColor( const QColor &c)
557{
558 d->col = c;
559}
560
561/*!
562 Returns whether this style is an anchor.
563
564 \sa setAnchor()
565 */
566bool QStyleSheetItem::isAnchor() const
567{
568 return d->anchor;
569}
570
571/*!
572 If \a anc is TRUE sets this style to be an anchor (hypertext link);
573 otherwise sets it to not be an anchor. Elements in this style have
574 connections to other documents or anchors.
575
576 \sa isAnchor()
577 */
578void QStyleSheetItem::setAnchor(bool anc)
579{
580 d->anchor = anc;
581}
582
583
584/*!
585 Returns the whitespace mode.
586
587 \sa setWhiteSpaceMode() WhiteSpaceMode
588 */
589QStyleSheetItem::WhiteSpaceMode QStyleSheetItem::whiteSpaceMode() const
590{
591 return d->whitespacemode;
592}
593
594/*!
595 Sets the whitespace mode to \a m.
596 \sa WhiteSpaceMode
597 */
598void QStyleSheetItem::setWhiteSpaceMode(WhiteSpaceMode m)
599{
600 d->whitespacemode = m;
601}
602
603
604/*!
605 Returns the width of margin \a m in pixels.
606
607 The margin, \a m, can be \c MarginLeft, \c MarginRight,
608 \c MarginTop, \c MarginBottom, \c MarginAll, \c MarginVertical or \c
609 MarginHorizontal.
610
611 \sa setMargin() Margin
612 */
613int QStyleSheetItem::margin(Margin m) const
614{
615 return d->margin[m];
616}
617
618
619/*!
620 Sets the width of margin \a m to \a v pixels.
621
622 The margin, \a m, can be \c MarginLeft, \c MarginRight,
623 \c MarginTop, \c MarginBottom, \c MarginAll, \c MarginVertical or \c
624 MarginHorizontal. The value \a v must be >= 0.
625
626 \sa margin()
627 */
628void QStyleSheetItem::setMargin(Margin m, int v)
629{
630 if (m == MarginAll ) {
631 d->margin[0] = v;
632 d->margin[1] = v;
633 d->margin[2] = v;
634 d->margin[3] = v;
635 d->margin[4] = v;
636 } else if (m == MarginVertical ) {
637 d->margin[MarginTop] = v;
638 d->margin[MarginBottom] = v;
639 } else if (m == MarginHorizontal ) {
640 d->margin[MarginLeft] = v;
641 d->margin[MarginRight] = v;
642 } else {
643 d->margin[m] = v;
644 }
645}
646
647
648/*!
649 Returns the list style of the style.
650
651 \sa setListStyle() ListStyle
652 */
653QStyleSheetItem::ListStyle QStyleSheetItem::listStyle() const
654{
655 return d->list;
656}
657
658/*! \enum QStyleSheetItem::ListStyle
659
660 This enum type defines how the items in a list are prefixed when
661 displayed. The currently defined values are:
662
663 \value ListDisc a filled circle (i.e. a bullet)
664 \value ListCircle an unfilled circle
665 \value ListSquare a filled square
666 \value ListDecimal an integer in base 10: \e 1, \e 2, \e 3, ...
667 \value ListLowerAlpha a lowercase letter: \e a, \e b, \e c, ...
668 \value ListUpperAlpha an uppercase letter: \e A, \e B, \e C, ...
669*/
670/*!
671 Sets the list style of the style to \a s.
672
673 This is used by nested elements that have a display mode of
674 \c DisplayListItem.
675
676 \sa listStyle() DisplayMode ListStyle
677 */
678void QStyleSheetItem::setListStyle(ListStyle s)
679{
680 d->list=s;
681}
682
683
684/*! Returns a space-separated list of names of styles that may
685 contain elements of this style. If nothing has been set, contexts()
686 returns an empty string, which indicates that this style can be
687 nested everywhere.
688
689 \sa setContexts()
690 */
691QString QStyleSheetItem::contexts() const
692{
693 return d->contxt;
694}
695
696/*!
697 Sets a space-separated list of names of styles that may contain
698 elements of this style. If \a c is empty, the style can be nested
699 everywhere.
700
701 \sa contexts()
702 */
703void QStyleSheetItem::setContexts( const QString& c)
704{
705 d->contxt = QChar(' ') + c + QChar(' ');
706}
707
708/*!
709 Returns TRUE if this style can be nested into an element
710 of style \a s; otherwise returns FALSE.
711
712 \sa contexts(), setContexts()
713 */
714bool QStyleSheetItem::allowedInContext( const QStyleSheetItem* s) const
715{
716 if ( d->contxt.isEmpty() )
717 return TRUE;
718 return d->contxt.find( QChar(' ')+s->name()+QChar(' ')) != -1;
719}
720
721
722/*!
723 Returns TRUE if this style has self-nesting enabled; otherwise
724 returns FALSE.
725
726 \sa setSelfNesting()
727 */
728bool QStyleSheetItem::selfNesting() const
729{
730 return d->selfnest;
731}
732
733/*!
734 Sets the self-nesting property for this style to \a nesting.
735
736 In order to support "dirty" HTML, paragraphs \c{<p>} and list items
737 \c{<li>} are not self-nesting. This means that starting a new
738 paragraph or list item automatically closes the previous one.
739
740 \sa selfNesting()
741 */
742void QStyleSheetItem::setSelfNesting( bool nesting )
743{
744 d->selfnest = nesting;
745}
746
747/*! Sets the linespacing to be \a ls pixels */
748
749void QStyleSheetItem::setLineSpacing( int ls )
750{
751 d->lineSpacing = ls;
752}
753
754/*! Returns the linespacing */
755
756int QStyleSheetItem::lineSpacing() const
757{
758 return d->lineSpacing;
759}
760
761//************************************************************************
762
763
764
765
766//************************************************************************
767
768
769/*!
770 \class QStyleSheet qstylesheet.h
771 \ingroup text
772 \brief The QStyleSheet class is a collection of styles for rich text
773 rendering and a generator of tags.
774
775 \ingroup graphics
776 \ingroup helpsystem
777
778 By creating QStyleSheetItem objects for a style sheet you build a
779 definition of a set of tags. This definition will be used by the
780 internal rich text rendering system to parse and display text
781 documents to which the style sheet applies. Rich text is normally
782 visualized in a QTextView or a QTextBrowser. However, QLabel,
783 QWhatsThis and QMessageBox also support it, and other classes are
784 likely to follow. With QSimpleRichText it is possible to use the
785 rich text renderer for custom widgets as well.
786
787 The default QStyleSheet object has the following style bindings,
788 sorted by structuring bindings, anchors, character style bindings
789 (i.e. inline styles), special elements such as horizontal lines or
790 images, and other tags. In addition, rich text supports simple HTML
791 tables.
792
793 The structuring tags are
794 \list
795 \i \c{<qt>}...\c{</qt>}
796 - A Qt rich text document. It understands the following attributes:
797 \list
798 \i title
799 - The caption of the document. This attribute is easily accessible with
800 QTextView::documentTitle().
801 \i type
802 - The type of the document. The default type is \c page . It
803 indicates that the document is displayed in a page of its
804 own. Another style is \c detail, which can be used to
805 explain certain expressions in more detail in a few
806 sentences. The QTextBrowser will then keep the current page
807 and display the new document in a small popup similar to
808 QWhatsThis. Note that links will not work in documents with
809 \c{<qt type="detail">...</qt>}.
810 \i bgcolor
811 - The background color, for example \c bgcolor="yellow" or \c
812 bgcolor="#0000FF".
813 \i background
814 - The background pixmap, for example \c
815 background="granit.xpm". The pixmap name will be resolved by
816 a QMimeSourceFactory().
817 \i text
818 - The default text color, for example \c text="red".
819 \i link
820 - The link color, for example \c link="green".
821 \endlist
822 \i \c{<h1>...</h1>}
823 - A top-level heading.
824 \i \c{<h2>...</h2>}
825 - A sublevel heading.
826 \i \c{<h3>...</h3>}
827 - A sub-sublevel heading.
828 \i \c{<p>...</p>}
829 - A left-aligned paragraph. Adjust the alignment with
830 the \c align attribute. Possible values are
831 \c left, \c right and \c center.
832 \i \c{<center>...</center>}
833 - A centered paragraph.
834 \i \c{<blockquote>...</blockquote>}
835 - An indented paragraph that is useful for quotes.
836 \i \c{<ul>...</ul>}
837 - An unordered list. You can also pass a type argument to
838 define the bullet style. The default is \c type=disc; other
839 types are \c circle and \c square.
840 \i \c{<ol>...</ol>}
841 - An ordered list. You can also pass a type argument to define
842 the enumeration label style. The default is \c type="1"; other
843 types are \c "a" and \c "A".
844 \i <tt>&lt;li&gt;</tt>...<tt>&lt;/li&gt;</tt>
845 - A list item. This tag can be used only within the context of
846 \c ol or \c ul.
847 \i \c{<pre>...</pre>}
848 - For larger chunks of code. Whitespaces in the contents are preserved.
849 For small bits of code use the inline-style \c code.
850 \endlist
851
852 Anchors and links are done with a single tag:
853 \list
854 \i \c{<a>...</a>}
855 - An anchor or link. The reference target is defined in the \c
856 href attribute of the tag as in \c{<a
857 href="target.qml">...</a>}. You can also specify an
858 additional anchor within the specified target document, for
859 example \c{<a href="target.qml#123">...</a>}. If \c a is
860 meant to be an anchor, the reference source is given in the
861 \c name attribute.
862 \endlist
863
864 The default character style bindings are
865 \list
866 \i \c{<em>...</em>}
867 - Emphasized. By default this is the same as
868 \c{<i>...</i>} (italic).
869 \i \c{<strong>...</strong>}
870 - Strong. By default this is the same as
871 \c{<b>...</b>} (bold).
872 \i \c{<i>...</i>}
873 - Italic font style.
874 \i \c{<b>...</b>}
875 - Bold font style.
876 \i \c{<u>...</u>}
877 - Underlined font style.
878 \i \c{<big>...</big>}
879 - A larger font size.
880 \i \c{<small>...</small>}
881 - A smaller font size.
882 \i \c{<code>...</code>}
883 - Indicates code. By default this is the same as
884 \c{<tt>...</tt>} (typewriter). For
885 larger junks of code use the block-tag \c pre.
886 \i \c{<tt>...</tt>}
887 - Typewriter font style.
888 \i \c{<font>...</font>}
889 - Customizes the font size, family and text color. The tag understands
890 the following attributes:
891 \list
892 \i color
893 - The text color, for example \c color="red" or \c color="#FF0000".
894 \i size
895 - The logical size of the font. Logical sizes 1 to 7 are supported.
896 The value may either be absolute (for example,
897 \c size=3) or relative (\c size=-2). In the latter case the sizes
898 are simply added.
899 \i face
900 - The family of the font, for example \c face=times.
901 \endlist
902 \endlist
903
904 Special elements are:
905 \list
906 \i \c{<img>}
907 - An image. The image name for the mime source
908 factory is given in the source attribute, for example
909 \c{<img src="qt.xpm">}
910 The image tag also understands the attributes \c width and \c
911 height that determine the size of the image. If the pixmap
912 does not fit the specified size it will be scaled
913 automatically (by using QImage::smoothScale()).
914
915 The \c align attribute determines where the image is
916 placed. By default, an image is placed inline just like a
917 normal character. Specify \c left or \c right to place the
918 image at the respective side.
919 \i \c{<hr>}
920 - A horizonal line.
921 \i \c{<br>}
922 - A line break.
923 \endlist
924
925 Another tag not in any of the above cathegories is
926 \list
927 \i \c{<nobr>...</nobr>}
928 - No break. Prevents word wrap.
929 \endlist
930
931 In addition, rich text supports simple HTML tables. A table consists
932 of one or more rows each of which contains one or more cells. Cells
933 are either data cells or header cells, depending on their
934 content. Cells which span rows and columns are supported.
935
936 \list
937 \i \c{<table>...</table>}
938 - A table. Tables support the following attributes:
939 \list
940 \i bgcolor
941 - The background color.
942 \i width
943 - The table width. This is either an absolute pixel width or a relative
944 percentage of the table's width, for example \c width=80%.
945 \i border
946 - The width of the table border. The default is 0 (= no border).
947 \i cellspacing
948 - Additional space around the table cells. The default is 2.
949 \i cellpadding
950 - Additional space around the contents of table cells. The default is 1.
951 \endlist
952 \i \c{<tr>...</tr>}
953 - A table row. This is only valid within a \c table. Rows support
954 the following attribute:
955 \list
956 \i bgcolor
957 - The background color.
958 \endlist
959 \i \c{<th>...</th>}
960 - A table header cell. Similar to \c td, but defaults to center alignment
961 and a bold font.
962 \i \c{<td>...</td>}
963 - A table data cell. This is only valid within a \c tr. Cells
964 support the following attributes:
965 \list
966 \i bgcolor
967 - The background color.
968 \i width
969 - The cell width. This is either an absolute pixel width or a relative
970 percentage of table's width, for example \c width=50%.
971 \i colspan
972 - Specifies how many columns this cell spans. The default is 1.
973 \i rowspan
974 - Specifies how many rows this cell spans. The default is 1.
975 \i align
976 - Alignment; possible values are \c left, \c right, and \c center. The
977 default is left.
978 \endlist
979 \endlist
980*/
981
982/*!
983 Creates a style sheet with parent \a parent and name \a name. Like
984 any QObject it will be deleted when its parent is
985 destroyed (if the child still exists).
986
987 By default the style sheet has the tag definitions defined above.
988*/
989QStyleSheet::QStyleSheet( QObject *parent, const char *name )
990 : QObject( parent, name )
991{
992 init();
993}
994
995/*!
996 Destroys the style sheet. All styles inserted into the style sheet
997 will be deleted.
998*/
999QStyleSheet::~QStyleSheet()
1000{
1001}
1002
1003/*!
1004 \internal
1005 Initialized the style sheet to the basic Qt style.
1006*/
1007void QStyleSheet::init()
1008{
1009 styles.setAutoDelete( TRUE );
1010
1011 nullstyle = new QStyleSheetItem( this,
1012 QString::fromLatin1("") );
1013
1014 QStyleSheetItem* style;
1015
1016 style = new QStyleSheetItem( this, "qml" ); // compatibility
1017 style->setDisplayMode( QStyleSheetItem::DisplayBlock );
1018
1019 style = new QStyleSheetItem( this, QString::fromLatin1("qt") );
1020 style->setDisplayMode( QStyleSheetItem::DisplayBlock );
1021 //style->setMargin( QStyleSheetItem::MarginAll, 4 );
1022
1023 style = new QStyleSheetItem( this, QString::fromLatin1("a") );
1024 style->setAnchor( TRUE );
1025
1026 style = new QStyleSheetItem( this, QString::fromLatin1("em") );
1027 style->setFontItalic( TRUE );
1028
1029 style = new QStyleSheetItem( this, QString::fromLatin1("i") );
1030 style->setFontItalic( TRUE );
1031
1032 style = new QStyleSheetItem( this, QString::fromLatin1("big") );
1033 style->setLogicalFontSizeStep( 1 );
1034 style = new QStyleSheetItem( this, QString::fromLatin1("large") ); // compatibility
1035 style->setLogicalFontSizeStep( 1 );
1036
1037 style = new QStyleSheetItem( this, QString::fromLatin1("small") );
1038 style->setLogicalFontSizeStep( -1 );
1039
1040 style = new QStyleSheetItem( this, QString::fromLatin1("strong") );
1041 style->setFontWeight( QFont::Bold);
1042
1043 style = new QStyleSheetItem( this, QString::fromLatin1("b") );
1044 style->setFontWeight( QFont::Bold);
1045
1046 style = new QStyleSheetItem( this, QString::fromLatin1("h1") );
1047 style->setFontWeight( QFont::Bold);
1048 style->setLogicalFontSize(6);
1049 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1050 style-> setMargin(QStyleSheetItem::MarginTop, 12);
1051 style-> setMargin(QStyleSheetItem::MarginBottom, 6);
1052
1053 style = new QStyleSheetItem( this, QString::fromLatin1("h2") );
1054 style->setFontWeight( QFont::Bold);
1055 style->setLogicalFontSize(5);
1056 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1057 style-> setMargin(QStyleSheetItem::MarginTop, 10);
1058 style-> setMargin(QStyleSheetItem::MarginBottom, 5);
1059
1060 style = new QStyleSheetItem( this, QString::fromLatin1("h3") );
1061 style->setFontWeight( QFont::Bold);
1062 style->setLogicalFontSize(4);
1063 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1064 style-> setMargin(QStyleSheetItem::MarginTop, 8);
1065 style-> setMargin(QStyleSheetItem::MarginBottom, 4);
1066
1067 style = new QStyleSheetItem( this, QString::fromLatin1("h4") );
1068 style->setFontWeight( QFont::Bold);
1069 style->setLogicalFontSize(3);
1070 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1071 style-> setMargin(QStyleSheetItem::MarginTop, 8);
1072 style-> setMargin(QStyleSheetItem::MarginBottom, 4);
1073
1074 style = new QStyleSheetItem( this, QString::fromLatin1("h5") );
1075 style->setFontWeight( QFont::Bold);
1076 style->setLogicalFontSize(2);
1077 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1078 style-> setMargin(QStyleSheetItem::MarginTop, 8);
1079 style-> setMargin(QStyleSheetItem::MarginBottom, 4);
1080
1081 style = new QStyleSheetItem( this, QString::fromLatin1("p") );
1082 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1083 style-> setMargin(QStyleSheetItem::MarginVertical, 8);
1084 style->setSelfNesting( FALSE );
1085
1086 style = new QStyleSheetItem( this, QString::fromLatin1("center") );
1087 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1088 style->setAlignment( AlignCenter );
1089
1090 style = new QStyleSheetItem( this, QString::fromLatin1("twocolumn") );
1091 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1092 style->setNumberOfColumns( 2 );
1093
1094 style = new QStyleSheetItem( this, QString::fromLatin1("multicol") );
1095 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1096 (void) new QStyleSheetItem( this, QString::fromLatin1("font") );
1097
1098 style = new QStyleSheetItem( this, QString::fromLatin1("ul") );
1099 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1100 style-> setMargin(QStyleSheetItem::MarginVertical, 4);
1101
1102 style = new QStyleSheetItem( this, QString::fromLatin1("ol") );
1103 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1104 style->setListStyle( QStyleSheetItem::ListDecimal );
1105 style-> setMargin(QStyleSheetItem::MarginVertical, 4);
1106
1107 style = new QStyleSheetItem( this, QString::fromLatin1("li") );
1108 style->setDisplayMode(QStyleSheetItem::DisplayListItem);
1109 style->setSelfNesting( FALSE );
1110 style->setContexts(QString::fromLatin1("ol ul"));
1111 style-> setMargin(QStyleSheetItem::MarginVertical, 4);
1112
1113 style = new QStyleSheetItem( this, QString::fromLatin1("code") );
1114 style->setFontFamily( QString::fromLatin1("courier") );
1115
1116 style = new QStyleSheetItem( this, QString::fromLatin1("tt") );
1117 style->setFontFamily( QString::fromLatin1("courier") );
1118
1119 new QStyleSheetItem(this, QString::fromLatin1("img"));
1120 new QStyleSheetItem(this, QString::fromLatin1("br"));
1121 new QStyleSheetItem(this, QString::fromLatin1("hr"));
1122 style = new QStyleSheetItem(this, QString::fromLatin1("sub"));
1123 style->setVerticalAlignment( QStyleSheetItem::VAlignSub );
1124 style = new QStyleSheetItem(this, QString::fromLatin1("sup"));
1125 style->setVerticalAlignment( QStyleSheetItem::VAlignSuper );
1126
1127 style = new QStyleSheetItem( this, QString::fromLatin1("pre") );
1128 style->setFontFamily( QString::fromLatin1("courier") );
1129 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1130 style->setWhiteSpaceMode(QStyleSheetItem::WhiteSpacePre);
1131
1132 style = new QStyleSheetItem( this, QString::fromLatin1("blockquote") );
1133 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1134 style->setMargin(QStyleSheetItem::MarginHorizontal, 40 );
1135
1136 style = new QStyleSheetItem( this, QString::fromLatin1("head") );
1137 style->setDisplayMode(QStyleSheetItem::DisplayNone);
1138 style = new QStyleSheetItem( this, QString::fromLatin1("div") );
1139 style->setDisplayMode(QStyleSheetItem::DisplayBlock) ;
1140 style = new QStyleSheetItem( this, QString::fromLatin1("dl") );
1141 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1142 style = new QStyleSheetItem( this, QString::fromLatin1("dt") );
1143 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1144 style->setContexts(QString::fromLatin1("dl") );
1145 style = new QStyleSheetItem( this, QString::fromLatin1("dd") );
1146 style->setDisplayMode(QStyleSheetItem::DisplayBlock);
1147 style->setMargin(QStyleSheetItem::MarginLeft, 30);
1148 style->setContexts(QString::fromLatin1("dt dl") );
1149 style = new QStyleSheetItem( this, QString::fromLatin1("u") );
1150 style->setFontUnderline( TRUE);
1151 style = new QStyleSheetItem( this, QString::fromLatin1("nobr") );
1152 style->setWhiteSpaceMode( QStyleSheetItem::WhiteSpaceNoWrap );
1153 style = new QStyleSheetItem( this, QString::fromLatin1("wsp") ); // qt extension for QTextEdit
1154 style->setWhiteSpaceMode( (QStyleSheetItem::WhiteSpaceMode) 3 ); // WhiteSpaceModeNoCompression
1155
1156 // tables
1157 style = new QStyleSheetItem( this, QString::fromLatin1("table") );
1158 style = new QStyleSheetItem( this, QString::fromLatin1("tr") );
1159 style->setContexts(QString::fromLatin1("table"));
1160 style = new QStyleSheetItem( this, QString::fromLatin1("td") );
1161 style->setContexts(QString::fromLatin1("tr"));
1162 style = new QStyleSheetItem( this, QString::fromLatin1("th") );
1163 style->setFontWeight( QFont::Bold );
1164 style->setAlignment( Qt::AlignCenter );
1165 style->setContexts(QString::fromLatin1("tr"));
1166
1167 style = new QStyleSheetItem( this, QString::fromLatin1("html") );
1168}
1169
1170
1171
1172static QStyleSheet* defaultsheet = 0;
1173static QSingleCleanupHandler<QStyleSheet> qt_cleanup_stylesheet;
1174
1175/*!
1176 Returns the application-wide default style sheet. This style sheet is
1177 used by rich text rendering classes such as QSimpleRichText,
1178 QWhatsThis and QMessageBox to define the rendering style and
1179 available tags within rich text documents. It serves also as initial
1180 style sheet for the more complex render widgets QTextEdit and
1181 QTextBrowser.
1182
1183 \sa setDefaultSheet()
1184*/
1185QStyleSheet* QStyleSheet::defaultSheet()
1186{
1187 if (!defaultsheet) {
1188 defaultsheet = new QStyleSheet();
1189 qt_cleanup_stylesheet.set( &defaultsheet );
1190 }
1191 return defaultsheet;
1192}
1193
1194/*!
1195 Sets the application-wide default style sheet to \a sheet, deleting
1196 any style sheet previously set. The ownership is transferred to
1197 QStyleSheet.
1198
1199 \sa defaultSheet()
1200*/
1201void QStyleSheet::setDefaultSheet( QStyleSheet* sheet)
1202{
1203 if ( defaultsheet != sheet ) {
1204 if ( defaultsheet )
1205 qt_cleanup_stylesheet.reset();
1206 delete defaultsheet;
1207 }
1208 defaultsheet = sheet;
1209 if ( defaultsheet )
1210 qt_cleanup_stylesheet.set( &defaultsheet );
1211}
1212
1213/*!\internal
1214 Inserts \a style. Any tags generated after this time will be
1215 bound to this style. Note that \a style becomes owned by the
1216 style sheet and will be deleted when the style sheet is destroyed.
1217*/
1218void QStyleSheet::insert( QStyleSheetItem* style )
1219{
1220 styles.insert(style->name(), style);
1221}
1222
1223
1224/*!
1225 Returns the style with name \a name or 0 if there is no such style.
1226 */
1227QStyleSheetItem* QStyleSheet::item( const QString& name)
1228{
1229 if ( name.isNull() )
1230 return 0;
1231 return styles[name];
1232}
1233
1234/*!
1235 \overload
1236 Returns the style with name \a name or 0 if there is no such style (const version)
1237 */
1238const QStyleSheetItem* QStyleSheet::item( const QString& name) const
1239{
1240 if ( name.isNull() )
1241 return 0;
1242 return styles[name];
1243}
1244
1245
1246/*!
1247 \preliminary
1248 Generates an internal object for the tag called \a name, given the
1249 attributes \a attr, and using additional information provided
1250 by the mime source factory \a factory.
1251
1252 \a context is the optional context of the document, i.e. the path to
1253 look for relative links. This becomes important if the text contains
1254 relative references, for example within image tags. QSimpleRichText
1255 always uses the default mime source factory (see
1256 \l{QMimeSourceFactory::defaultFactory()}) to resolve these references.
1257 The context will then be used to calculate the absolute path. See
1258 QMimeSourceFactory::makeAbsolute() for details.
1259
1260 \a emptyTag and \a doc are for internal use only.
1261
1262 This function should not (yet) be used in application code.
1263*/
1264QTextCustomItem* QStyleSheet::tag( const QString& name,
1265 const QMap<QString, QString> &attr,
1266 const QString& context,
1267 const QMimeSourceFactory& factory,
1268 bool /*emptyTag */, QTextDocument *doc ) const
1269{
1270 static QString s_img = QString::fromLatin1("img");
1271 static QString s_hr = QString::fromLatin1("hr");
1272
1273 const QStyleSheetItem* style = item( name );
1274 // first some known tags
1275 if ( !style )
1276 return 0;
1277 if ( style->name() == s_img )
1278 return new QTextImage( doc, attr, context, (QMimeSourceFactory&)factory );
1279 if ( style->name() == s_hr )
1280 return new QTextHorizontalLine( doc, attr, context, (QMimeSourceFactory&)factory );
1281 return 0;
1282}
1283
1284
1285/*!
1286 Auxiliary function. Converts the plain text string \a plain to a
1287 rich text formatted paragraph while preserving its look.
1288
1289 \a mode defines the whitespace mode. Possible values are \c
1290 QStyleSheetItem::WhiteSpacePre (no wrapping, all whitespaces
1291 preserved) and \c QStyleSheetItem::WhiteSpaceNormal (wrapping,
1292 simplified whitespaces).
1293
1294 \sa escape()
1295 */
1296QString QStyleSheet::convertFromPlainText( const QString& plain, QStyleSheetItem::WhiteSpaceMode mode )
1297{
1298 int col = 0;
1299 QString rich;
1300 rich += "<p>";
1301 for ( int i = 0; i < int(plain.length()); ++i ) {
1302 if ( plain[i] == '\n' ){
1303 if ( col == 1 )
1304 rich += "<p></p>";
1305 else
1306 rich += "<br>";
1307 col = 0;
1308 }
1309 else if ( mode == QStyleSheetItem::WhiteSpacePre && plain[i] == '\t' ){
1310 rich += 0x00a0U;
1311 while ( col % 4 ) {
1312 rich += 0x00a0U;
1313 ++col;
1314 }
1315 }
1316 else if ( mode == QStyleSheetItem::WhiteSpacePre && plain[i].isSpace() )
1317 rich += 0x00a0U;
1318 else if ( plain[i] == '<' )
1319 rich +="&lt;";
1320 else if ( plain[i] == '>' )
1321 rich +="&gt;";
1322 else if ( plain[i] == '&' )
1323 rich +="&amp;";
1324 else
1325 rich += plain[i];
1326 ++col;
1327 }
1328 rich += "</p>";
1329 return rich;
1330}
1331
1332/*!
1333 Auxiliary function. Converts the plain text string \a plain to a
1334 rich text formatted string with any HTML meta-characters escaped.
1335
1336 \sa convertFromPlainText()
1337 */
1338QString QStyleSheet::escape( const QString& plain)
1339{
1340 QString rich;
1341 for ( int i = 0; i < int(plain.length()); ++i ) {
1342 if ( plain[i] == '<' )
1343 rich +="&lt;";
1344 else if ( plain[i] == '>' )
1345 rich +="&gt;";
1346 else if ( plain[i] == '&' )
1347 rich +="&amp;";
1348 else
1349 rich += plain[i];
1350 }
1351 return rich;
1352}
1353
1354// Must doc this enum somewhere, and it is logically related to QStyleSheet
1355
1356/*!
1357 \enum Qt::TextFormat
1358
1359 This enum is used in widgets that can display both plain text and
1360 rich text, e.g. QLabel. It is used for deciding whether a text
1361 string should be interpreted as one or the other. This is
1362 normally done by passing one of the enum values to a setTextFormat()
1363 function.
1364
1365 \value PlainText The text string is interpreted as a plain text string.
1366
1367 \value RichText The text string is interpreted as a rich text string
1368 using the current QStyleSheet::defaultSheet().
1369
1370 \value AutoText The text string is interpreted as for \c RichText if
1371 QStyleSheet::mightBeRichText() returns TRUE, otherwise as for \c
1372 PlainText.
1373*/
1374
1375/*!
1376 Returns TRUE if the string \a text is likely to be rich text;
1377 otherwise returns FALSE.
1378
1379 Note: The function uses a fast and therefore simple heuristic. It
1380 mainly checks whether there is something that looks like a tag
1381 before the first line break. Although the result may be correct for
1382 most common cases, there is no guarantee.
1383*/
1384bool QStyleSheet::mightBeRichText( const QString& text)
1385{
1386 if ( text.isEmpty() )
1387 return FALSE;
1388 if ( text.left(5).lower() == "<!doc" )
1389 return TRUE;
1390 int open = 0;
1391 while ( open < int(text.length()) && text[open] != '<'
1392 && text[open] != '\n' && text[open] != '&')
1393 ++open;
1394 if ( text[open] == '&' ) {
1395 if ( text.mid(open+1,3) == "lt;" )
1396 return TRUE; // support desperate attempt of user to see <...>
1397 } else if ( text[open] == '<' ) {
1398 int close = text.find('>', open);
1399 if ( close > -1 ) {
1400 QString tag;
1401 for (int i = open+1; i < close; ++i) {
1402 if ( text[i].isDigit() || text[i].isLetter() )
1403 tag += text[i];
1404 else if ( !tag.isEmpty() && text[i].isSpace() )
1405 break;
1406 else if ( !text[i].isSpace() && (!tag.isEmpty() || text[i] != '!' ) )
1407 return FALSE; // that's not a tag
1408 }
1409 return defaultSheet()->item( tag.lower() ) != 0;
1410 }
1411 }
1412 return FALSE;
1413}
1414
1415
1416/*! \fn void QStyleSheet::error( const QString& msg) const
1417
1418 This virtual function is called when an error occurs when
1419 processing rich text. Reimplement it if you need to catch
1420 error messages.
1421
1422 Errors might occur if some rich text strings contain tags that are
1423 not understood by the stylesheet, if some tags are nested incorrectly, or
1424 if tags are not closed properly.
1425
1426 \a msg is the error message.
1427*/
1428void QStyleSheet::error( const QString& ) const
1429{
1430}
1431
1432
1433/*!
1434 Scales the font \a font to the appropriate physical point size
1435 corresponding to the logical font size \a logicalSize.
1436
1437 When calling this function, \a font has a point size corresponding to
1438 the logical font size 3.
1439
1440 Logical font sizes range from 1 to 7, with 1 being the smallest.
1441
1442 \sa QStyleSheetItem::logicalFontSize(),
1443 QStyleSheetItem::logicalFontSizeStep(), QFont::setPointSize()
1444 */
1445void QStyleSheet::scaleFont( QFont& font, int logicalSize ) const
1446{
1447 if ( logicalSize < 1 )
1448 logicalSize = 1;
1449 if ( logicalSize > 7 )
1450 logicalSize = 7;
1451 int baseSize = font.pointSize();
1452 bool pixel = FALSE;
1453 if ( baseSize == -1 ) {
1454 baseSize = font.pixelSize();
1455 pixel = TRUE;
1456 }
1457 int s;
1458 switch ( logicalSize ) {
1459 case 1:
1460 s = baseSize/2;
1461 break;
1462 case 2:
1463 s = (8 * baseSize) / 10;
1464 break;
1465 case 4:
1466 s = (12 * baseSize) / 10;
1467 break;
1468 case 5:
1469 s = (15 * baseSize) / 10;
1470 break;
1471 case 6:
1472 s = 2 * baseSize;
1473 break;
1474 case 7:
1475 s = (24 * baseSize) / 10;
1476 break;
1477 default:
1478 s = baseSize;
1479 }
1480 if ( pixel )
1481 font.setPixelSize( s );
1482 else
1483 font.setPointSize( s );
1484}
diff --git a/noncore/apps/opie-write/qstylesheet.h b/noncore/apps/opie-write/qstylesheet.h
new file mode 100644
index 0000000..bb209fa
--- a/dev/null
+++ b/noncore/apps/opie-write/qstylesheet.h
@@ -0,0 +1,221 @@
1/****************************************************************************
2** $Id$
3**
4** Definition of the QStyleSheet class
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#ifndef QSTYLESHEET_H
39#define QSTYLESHEET_H
40
41#ifndef QT_H
42#include "qt3namespace.h"
43#include "qstring.h"
44#include "qvaluelist.h"
45#include "qvector.h"
46#include "qdict.h"
47#include "qobject.h"
48#endif // QT_H
49
50template<class Key, class T> class QMap;
51
52namespace Qt3 {
53
54class QStyleSheet;
55class QTextDocument;
56class QStyleSheetItemData;
57
58class Q_EXPORT QStyleSheetItem : public Qt
59{
60public:
61 QStyleSheetItem( QStyleSheet* parent, const QString& name );
62 QStyleSheetItem( const QStyleSheetItem & );
63 ~QStyleSheetItem();
64
65 QString name() const;
66
67 QStyleSheet* styleSheet();
68 const QStyleSheet* styleSheet() const;
69
70 enum AdditionalStyleValues { Undefined = - 1};
71
72 enum DisplayMode {
73 DisplayBlock,
74 DisplayInline,
75 DisplayListItem,
76 DisplayNone
77 };
78
79 DisplayMode displayMode() const;
80 void setDisplayMode(DisplayMode m);
81
82 int alignment() const;
83 void setAlignment( int f);
84
85 enum VerticalAlignment {
86 VAlignBaseline,
87 VAlignSub,
88 VAlignSuper
89 };
90
91 VerticalAlignment verticalAlignment() const;
92 void setVerticalAlignment( VerticalAlignment valign );
93
94 int fontWeight() const;
95 void setFontWeight(int w);
96
97 int logicalFontSize() const;
98 void setLogicalFontSize(int s);
99
100 int logicalFontSizeStep() const;
101 void setLogicalFontSizeStep( int s );
102
103 int fontSize() const;
104 void setFontSize(int s);
105
106 QString fontFamily() const;
107 void setFontFamily( const QString& );
108
109 int numberOfColumns() const;
110 void setNumberOfColumns(int ncols);
111
112 QColor color() const;
113 void setColor( const QColor &);
114
115 bool fontItalic() const;
116 void setFontItalic( bool );
117 bool definesFontItalic() const;
118
119 bool fontUnderline() const;
120 void setFontUnderline( bool );
121 bool definesFontUnderline() const;
122
123 bool isAnchor() const;
124 void setAnchor(bool anc);
125
126 enum WhiteSpaceMode { WhiteSpaceNormal, WhiteSpacePre, WhiteSpaceNoWrap };
127 WhiteSpaceMode whiteSpaceMode() const;
128 void setWhiteSpaceMode(WhiteSpaceMode m);
129
130 enum Margin {
131 MarginLeft,
132 MarginRight,
133 MarginTop,
134 MarginBottom,
135 MarginFirstLine,
136 MarginAll,
137 MarginVertical,
138 MarginHorizontal
139 };
140
141 int margin( Margin m) const;
142 void setMargin( Margin, int);
143
144 enum ListStyle {
145 ListDisc,
146 ListCircle,
147 ListSquare,
148 ListDecimal,
149 ListLowerAlpha,
150 ListUpperAlpha
151 };
152
153 ListStyle listStyle() const;
154 void setListStyle( ListStyle );
155
156 QString contexts() const;
157 void setContexts( const QString& );
158 bool allowedInContext( const QStyleSheetItem* ) const;
159
160 bool selfNesting() const;
161 void setSelfNesting( bool );
162
163 void setLineSpacing( int ls );
164 int lineSpacing() const;
165
166private:
167 void init();
168 QStyleSheetItemData* d;
169};
170
171
172#if defined(Q_TEMPLATEDLL)
173// MOC_SKIP_BEGIN
174template class Q_EXPORT QDict<QStyleSheetItem>;
175template class Q_EXPORT QValueList< QPtrVector<QStyleSheetItem> >;
176template class Q_EXPORT QPtrVector<QStyleSheetItem>;
177template class Q_EXPORT QValueList<QStyleSheetItem::ListStyle>;
178// MOC_SKIP_END
179#endif
180
181class QTextCustomItem;
182
183class Q_EXPORT QStyleSheet : public QObject
184{
185 Q_OBJECT
186public:
187 QStyleSheet( QObject *parent=0, const char *name=0 );
188 virtual ~QStyleSheet();
189
190 static QStyleSheet* defaultSheet();
191 static void setDefaultSheet( QStyleSheet* );
192
193
194 QStyleSheetItem* item( const QString& name);
195 const QStyleSheetItem* item( const QString& name) const;
196
197 void insert( QStyleSheetItem* item);
198
199 virtual QTextCustomItem* tag( const QString& name,
200 const QMap<QString, QString> &attr,
201 const QString& context,
202 const QMimeSourceFactory& factory,
203 bool emptyTag, QTextDocument *doc ) const;
204
205 static QString escape( const QString& );
206 static QString convertFromPlainText( const QString&, QStyleSheetItem::WhiteSpaceMode mode = QStyleSheetItem::WhiteSpacePre );
207 static bool mightBeRichText( const QString& );
208
209 virtual void scaleFont( QFont& font, int logicalSize ) const;
210
211 virtual void error( const QString& ) const;
212
213private:
214 void init();
215 QDict<QStyleSheetItem> styles;
216 QStyleSheetItem* nullstyle;
217};
218
219} // namespace Qt3
220
221#endif // QSTYLESHEET_H
diff --git a/noncore/apps/opie-write/qt3namespace.h b/noncore/apps/opie-write/qt3namespace.h
new file mode 100644
index 0000000..81c5020
--- a/dev/null
+++ b/noncore/apps/opie-write/qt3namespace.h
@@ -0,0 +1,28 @@
1#ifndef QT3NAMESPACE_H
2#define QT3NAMESPACE_H
3
4#include <qnamespace.h>
5
6#define Q_ASSERT ASSERT
7#define Q_WS_QWS
8
9#define QMemArray QArray
10#define QPtrList QList
11#define QPtrListIterator QListIterator
12#define QPtrVector QVector
13
14namespace Qt3 {
15
16enum NewAlignmentFlags {
17 AlignAuto = 0x0000,
18 AlignJustify = 0x0080,
19 AlignHorizontal_Mask = Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter | AlignJustify
20};
21
22enum NewWidgetFlags {
23 WStaticContents = Qt::WNorthWestGravity
24};
25
26}
27
28#endif // QT3NAMESPACE_H
diff --git a/noncore/apps/opie-write/qtextedit.cpp b/noncore/apps/opie-write/qtextedit.cpp
new file mode 100644
index 0000000..9c5ea79
--- a/dev/null
+++ b/noncore/apps/opie-write/qtextedit.cpp
@@ -0,0 +1,4516 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of the QTextEdit class
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qtextedit.h"
39
40#include "qrichtext_p.h"
41#include "qpainter.h"
42#include "qpen.h"
43#include "qbrush.h"
44#include "qpixmap.h"
45#include "qfont.h"
46#include "qcolor.h"
47#include "qstyle.h"
48#include "qsize.h"
49#include "qevent.h"
50#include "qtimer.h"
51#include "qapplication.h"
52#include "qlistbox.h"
53#include "qvbox.h"
54#include "qapplication.h"
55#include "qclipboard.h"
56#include "qcolordialog.h"
57#include "qfontdialog.h"
58#include "qstylesheet.h"
59#include "qdragobject.h"
60#include "qurl.h"
61#include "qcursor.h"
62#include "qregexp.h"
63#include "qpopupmenu.h"
64
65#define ACCEL_KEY(k) "\t" + QString("Ctrl+" #k)
66
67using namespace Qt3;
68
69struct QUndoRedoInfoPrivate
70{
71 QTextString text;
72};
73
74namespace Qt3 {
75
76class QTextEditPrivate
77{
78public:
79 QTextEditPrivate()
80 :preeditStart(-1),preeditLength(-1),ensureCursorVisibleInShowEvent(FALSE) {}
81 int id[ 7 ];
82 int preeditStart;
83 int preeditLength;
84 bool ensureCursorVisibleInShowEvent;
85};
86
87}
88
89static bool block_set_alignment = FALSE;
90
91/*!
92 \class QTextEdit qtextedit.h
93 \brief The QTextEdit widget provides a sophisticated single-page rich text editor.
94
95 \ingroup basic
96 \ingroup text
97 \mainclass
98
99 QTextEdit is an advanced WYSIWYG editor supporting rich text
100 formatting. It is optimized to handle large documents and to
101 respond quickly to user input.
102
103 QTextEdit works on paragraphs and characters. A paragraph is a
104 formatted string which is word-wrapped to fit into the width of
105 the widget. A document consists of zero or more paragraphs,
106 indexed from 0. Characters are indexed on a per-paragraph basis,
107 also indexed from 0. The words in the paragraph are aligned in
108 accordance with the paragraph's alignment(). Paragraphs are
109 separated by hard line breaks. Each character within a paragraph
110 has its own attributes, for example, font and color.
111
112 QTextEdit can display images (using QMimeSourceFactory), lists and
113 tables. If the text is too large to view within the text edit's
114 viewport, scrollbars will appear. The text edit can load both
115 plain text and HTML files (a subset of HTML 3.2 and 4). The
116 rendering style and the set of valid tags are defined by a
117 styleSheet(). Change the style sheet with \l{setStyleSheet()}; see
118 QStyleSheet for details. The images identified by image tags are
119 displayed if they can be interpreted using the text edit's
120 \l{QMimeSourceFactory}; see setMimeSourceFactory().
121
122 If you want a text browser with more navigation use QTextBrowser.
123 If you just need to display a small piece of rich text use QLabel
124 or QSimpleRichText.
125
126 If you create a new QTextEdit, and want to allow the user to edit
127 rich text, call setTextFormat(Qt::RichText) to ensure that the
128 text is treated as rich text. (Rich text uses HTML tags to set
129 text formatting attributes. See QStyleSheet for information on the
130 HTML tags that are supported.). If you don't call setTextFormat()
131 explicitly the text edit will guess from the text itself whether
132 it is rich text or plain text. This means that if the text looks
133 like HTML or XML it will probably be interpreted as rich text, so
134 you should call setTextFormat(Qt::PlainText) to preserve such
135 text.
136
137 The text edit documentation uses the following concepts:
138 \list
139 \i <i>current format</i> --
140 this is the format at the current cursor position, \e and it
141 is the format of the selected text if any.
142 \i <i>current paragraph</i> -- the paragraph which contains the
143 cursor.
144 \endlist
145
146 The text is set or replaced using setText() which deletes any
147 existing text and replaces it with the text passed in the
148 setText() call. Text can be inserted with insert(), paste() and
149 pasteSubType(). Text can also be cut(). The entire text is deleted
150 with clear() and the selected text is deleted with
151 removeSelectedText(). Selected (marked) text can also be deleted
152 with del() (which will delete the character to the right of the
153 cursor if no text is selected).
154
155 The current format's attributes are set with setItalic(),
156 setBold(), setUnderline(), setFamily() (font family),
157 setPointSize(), setColor() and setCurrentFont(). The current
158 paragraph's style is set with setParagType() and its alignment is
159 set with setAlignment().
160
161 Use setSelection() to select text. The setSelectionAttributes()
162 function is used to indicate how selected text should be
163 displayed. Use hasSelectedText() to find out if any text is
164 selected. The currently selected text's position is available
165 using getSelection() and the selected text itself is returned by
166 selectedText(). The selection can be copied to the clipboard with
167 copy(), or cut to the clipboard with cut(). It can be deleted with
168 removeSelectedText(). The entire text can be selected (or
169 unselected) using selectAll(). QTextEdit supports multiple
170 selections. Most of the selection functions operate on the default
171 selection, selection 0. If the user presses a non-selecting key,
172 e.g. a cursor key without also holding down Shift, all selections
173 are cleared.
174
175 Set and get the position of the cursor with setCursorPosition()
176 and getCursorPosition() respectively. When the cursor is moved,
177 the signals currentFontChanged(), currentColorChanged() and
178 currentAlignmentChanged() are emitted to reflect the font, color
179 and alignment at the new cursor position.
180
181 If the text changes, the textChanged() signal is emitted, and if
182 the user inserts a new line by pressing Return or Enter,
183 returnPressed() is emitted. The isModified() function will return
184 TRUE if the text has been modified.
185
186 QTextEdit provides command-based undo and redo. To set the depth
187 of the command history use setUndoDepth() which defaults to 100
188 steps. To undo or redo the last operation call undo() or redo().
189 The signals undoAvailable() and redoAvailable() indicate whether
190 the undo and redo operations can be executed.
191
192 The indent() function is used to reindent a paragraph. It is
193 useful for code editors, for example in <em>Qt Designer</em>'s
194 code editor \e{Ctrl+I} invokes the indent() function.
195
196 Loading and saving text is achieved using setText() and text(),
197 for example:
198 \code
199 QFile file( fileName ); // Read the text from a file
200 if ( file.open( IO_ReadOnly ) ) {
201 QTextStream ts( &file );
202 textEdit->setText( ts.read() );
203 }
204 \endcode
205 \code
206 QFile file( fileName ); // Write the text to a file
207 if ( file.open( IO_WriteOnly ) ) {
208 QTextStream ts( &file );
209 ts << textEdit->text();
210 textEdit->setModified( FALSE );
211 }
212 \endcode
213
214 By default the text edit wraps words at whitespace to fit within
215 the text edit widget. The setWordWrap() function is used to
216 specify the kind of word wrap you want, or \c NoWrap if you don't
217 want any wrapping. Call setWordWrap() to set a fixed pixel width
218 \c FixedPixelWidth, or character column (e.g. 80 column) \c
219 FixedColumnWidth with the pixels or columns specified with
220 setWrapColumnOrWidth(). If you use word wrap to the widget's width
221 \c WidgetWidth, you can specify whether to break on whitespace or
222 anywhere with setWrapPolicy().
223
224 The background color is set differently than other widgets, using
225 setPaper(). You specify a brush style which could be a plain color
226 or a complex pixmap.
227
228 Hypertext links are automatically underlined; this can be changed
229 with setLinkUnderline(). The tab stop width is set with
230 setTabStopWidth().
231
232 The zoomIn() and zoomOut() functions can be used to resize the
233 text by increasing (decreasing for zoomOut()) the point size used.
234 Images are not affected by the zoom functions.
235
236 The lines() function returns the number of lines in the text and
237 paragraphs() returns the number of paragraphs. The number of lines
238 within a particular paragraph is returned by linesOfParagraph().
239 The length of the entire text in characters is returned by
240 length().
241
242 You can scroll to an anchor in the text, e.g. \c{<a
243 name="anchor">} with scrollToAnchor(). The find() function can be
244 used to find and select a given string within the text.
245
246 The list of key-bindings which are implemented for editing:
247 \table
248 \header \i Keypresses \i Action
249 \row \i \e{Backspace} \i Delete the character to the left of the cursor
250 \row \i \e{Delete} \i Delete the character to the right of the cursor
251 \row \i \e{Ctrl+A} \i Move the cursor to the beginning of the line
252 \row \i \e{Ctrl+B} \i Move the cursor one character left
253 \row \i \e{Ctrl+C} \i Copy the marked text to the clipboard (also
254 \e{Ctrl+Insert} under Windows)
255 \row \i \e{Ctrl+D} \i Delete the character to the right of the cursor
256 \row \i \e{Ctrl+E} \i Move the cursor to the end of the line
257 \row \i \e{Ctrl+F} \i Move the cursor one character right
258 \row \i \e{Ctrl+H} \i Delete the character to the left of the cursor
259 \row \i \e{Ctrl+K} \i Delete to end of line
260 \row \i \e{Ctrl+N} \i Move the cursor one line down
261 \row \i \e{Ctrl+P} \i Move the cursor one line up
262 \row \i \e{Ctrl+V} \i Paste the clipboard text into line edit
263 (also \e{Shift+Insert} under Windows)
264 \row \i \e{Ctrl+X} \i Cut the marked text, copy to clipboard
265 (also \e{Shift+Delete} under Windows)
266 \row \i \e{Ctrl+Z} \i Undo the last operation
267 \row \i \e{Ctrl+Y} \i Redo the last operation
268 \row \i \e{LeftArrow} \i Move the cursor one character left
269 \row \i \e{Ctrl+LeftArrow} \i Move the cursor one word left
270 \row \i \e{RightArrow} \i Move the cursor one character right
271 \row \i \e{Ctrl+RightArrow} \i Move the cursor one word right
272 \row \i \e{UpArrow} \i Move the cursor one line up
273 \row \i \e{Ctrl+UpArrow} \i Move the cursor one word up
274 \row \i \e{DownArrow} \i Move the cursor one line down
275 \row \i \e{Ctrl+Down Arrow} \i Move the cursor one word down
276 \row \i \e{PageUp} \i Move the cursor one page up
277 \row \i \e{PageDown} \i Move the cursor one page down
278 \row \i \e{Home} \i Move the cursor to the beginning of the line
279 \row \i \e{Ctrl+Home} \i Move the cursor to the beginning of the text
280 \row \i \e{End} \i Move the cursor to the end of the line
281 \row \i \e{Ctrl+End} \i Move the cursor to the end of the text
282 \row \i \e{Shift+Wheel} \i Scroll the page horizontally
283 (the Wheel is the mouse wheel)
284 \row \i \e{Ctrl+Wheel} \i Zoom the text
285 \endtable
286
287 To select (mark) text hold down the Shift key whilst pressing one
288 of the movement keystrokes, for example, <i>Shift+Right Arrow</i>
289 will select the character to the right, and <i>Shift+Ctrl+Right
290 Arrow</i> will select the word to the right, etc.
291
292 By default the text edit widget operates in insert mode so all
293 text that the user enters is inserted into the text edit and any
294 text to the right of the cursor is moved out of the way. The mode
295 can be changed to overwrite, where new text overwrites any text to
296 the right of the cursor, using setOverwriteMode().
297
298 QTextEdit can also be used as read-only text viewer. Call
299 setReadOnly( TRUE ) to disable editing. A read-only QTextEdit
300 provides the same functionality as the (obsolete) QTextView.
301 (QTextView is still supplied for compatibility with old code.)
302
303 When QTextEdit is used read-only the key-bindings are limited to
304 navigation, and text may only be selected with the mouse:
305 \table
306 \header \i Keypresses \i Action
307 \row \i \e{UpArrow} \i Move one line up
308 \row \i \e{DownArrow} \i Move one line down
309 \row \i \e{LeftArrow} \i Move one character left
310 \row \i \e{RightArrow} \i Move one character right
311 \row \i \e{PageUp} \i Move one (viewport) page up
312 \row \i \e{PageDown} \i Move one (viewport) page down
313 \row \i \e{Home} \i Move to the beginning of the text
314 \row \i \e{End} \i Move to the end of the text
315 \row \i \e{Shift+Wheel} \i Scroll the page horizontally (the Wheel is the mouse wheel)
316 \row \i \e{Ctrl+Wheel} \i Zoom the text
317 \endtable
318
319 The text edit may be able to provide some meta-information. For
320 example, the documentTitle() function will return the text from
321 within HTML \c{<title>} tags.
322
323 The text displayed in a text edit has a \e context. The context is
324 a path which the text edit's QMimeSourceFactory uses to resolve
325 the locations of files and images. It is passed to the
326 mimeSourceFactory() when quering data. (See QTextEdit() and
327 \l{context()}.)
328
329 Note that we do not intend to add a full-featured web browser
330 widget to Qt (because that would easily double Qt's size and only
331 a few applications would benefit from it). The rich
332 text support in Qt is designed to provide a fast, portable and
333 efficient way to add reasonable online help facilities to
334 applications, and to provide a basis for rich text editors.
335*/
336
337/*! \enum QTextEdit::KeyboardAction
338
339 This enum is used by doKeyboardAction() to specify which action
340 should be executed:
341
342 \value ActionBackspace Delete the character to the left of the
343 cursor.
344
345 \value ActionDelete Delete the character to the right of the cursor.
346
347 \value ActionReturn Split the paragraph at the cursor position.
348
349 \value ActionKill If the cursor is not at the end of the paragraph,
350 delete the text from the cursor position until the end of the
351 paragraph. If the cursor is at the end of the paragraph, delete the
352 hard line break at the end of the paragraph - this will cause this
353 paragraph to be joined with the following paragraph.
354*/
355
356/*! \enum QTextEdit::VerticalAlignment
357
358 This enum is used to set the vertical alignment of the text.
359
360 \value AlignNormal Normal alignment
361 \value AlignSuperScript Superscript
362 \value AlignSubScript Subscript
363*/
364
365/*! \fn void QTextEdit::copyAvailable (bool yes)
366
367 This signal is emitted when text is selected or de-selected in the text
368 edit.
369
370 When text is selected this signal will be emitted with \a yes set to
371 TRUE. If no text has been selected or if the selected text is
372 de-selected this signal is emitted with \a yes set to FALSE.
373
374 If \a yes is TRUE then copy() can be used to copy the selection to the
375 clipboard. If \a yes is FALSE then copy() does nothing.
376
377 \sa selectionChanged()
378*/
379
380
381/*! \fn void QTextEdit::textChanged()
382
383 This signal is emitted whenever the text in the text edit changes.
384
385 \sa setText() append()
386 */
387
388/*! \fn void QTextEdit::selectionChanged()
389
390 This signal is emitted whenever the selection changes.
391
392 \sa setSelection() copyAvailable()
393*/
394
395/*! \fn QTextDocument *QTextEdit::document() const
396
397 \internal
398
399 This function returns the QTextDocument which is used by the text
400 edit.
401*/
402
403/*! \fn void QTextEdit::setDocument( QTextDocument *doc )
404
405 \internal
406
407 This function sets the QTextDocument which should be used by the text
408 edit to \a doc. This can be used, for example, if you want to
409 display a document using multiple views. You would create a
410 QTextDocument and set it to the text edits which should display it.
411 You would need to connect to the textChanged() and
412 selectionChanged() signals of all the text edits and update them all
413 accordingly (preferably with a slight delay for efficiency reasons).
414*/
415
416/*! \enum QTextEdit::CursorAction
417
418 This enum is used by moveCursor() to specify in which direction
419 the cursor should be moved:
420
421 \value MoveBackward Moves the cursor one character backward
422
423 \value MoveWordBackward Moves the cursor one word backward
424
425 \value MoveForward Moves the cursor one character forward
426
427 \value MoveWordForward Moves the cursor one word forward
428
429 \value MoveUp Moves the cursor up one line
430
431 \value MoveDown Moves the cursor down one line
432
433 \value MoveLineStart Moves the cursor to the beginning of the line
434
435 \value MoveLineEnd Moves the cursor to the end of the line
436
437 \value MoveHome Moves the cursor to the beginning of the document
438
439 \value MoveEnd Moves the cursor to the end of the document
440
441 \value MovePgUp Moves the cursor one page up
442
443 \value MovePgDown Moves the cursor one page down
444*/
445
446
447/*!
448 \property QTextEdit::overwriteMode
449 \brief the text edit's overwrite mode
450
451 If FALSE (the default) characters entered by the user are inserted
452 with any characters to the right being moved out of the way.
453 If TRUE, the editor is in overwrite mode, i.e. characters entered by
454 the user overwrite any characters to the right of the cursor position.
455*/
456
457/*! \fn void QTextEdit::setCurrentFont( const QFont &f )
458
459 Sets the font of the current format to \a f.
460
461 \sa font() setPointSize() setFamily()
462*/
463
464/*!
465 \property QTextEdit::undoDepth
466 \brief the depth of the undo history
467
468 The maximum number of steps in the undo/redo history.
469 The default is 100.
470
471 \sa undo() redo()
472*/
473
474/*! \fn void QTextEdit::undoAvailable( bool yes )
475
476 This signal is emitted when the availability of undo changes. If \a
477 yes is TRUE, then undo() will work until undoAvailable( FALSE ) is
478 next emitted.
479
480 \sa undo() undoDepth()
481*/
482
483/*! \fn void QTextEdit::modificationChanged( bool m )
484
485 This signal is emitted when the modification of the document
486 changed. If \a m is TRUE, the document was modified, otherwise the
487 modification state has been reset to unmodified.
488
489 \sa modified
490*/
491
492/*! \fn void QTextEdit::redoAvailable( bool yes )
493
494 This signal is emitted when the availability of redo changes. If \a
495 yes is TRUE, then redo() will work until redoAvailable( FALSE ) is
496 next emitted.
497
498 \sa redo() undoDepth()
499*/
500
501/*! \fn void QTextEdit::currentFontChanged( const QFont &f )
502
503 This signal is emitted if the font of the current format has changed.
504
505 The new font is \a f.
506
507 \sa setCurrentFont()
508*/
509
510/*! \fn void QTextEdit::currentColorChanged( const QColor &c )
511
512 This signal is emitted if the color of the current format has changed.
513
514 The new color is \a c.
515
516 \sa setColor()
517*/
518
519/*! \fn void QTextEdit::currentVerticalAlignmentChanged( VerticalAlignment a )
520
521 This signal is emitted if the vertical alignment of the current
522 format has changed.
523
524 The new vertical alignment is \a a.
525
526 \sa setVerticalAlignment()
527*/
528
529/*! \fn void QTextEdit::currentAlignmentChanged( int a )
530
531 This signal is emitted if the alignment of the current paragraph
532 has changed.
533
534 The new alignment is \a a.
535
536 \sa setAlignment()
537*/
538
539/*! \fn void QTextEdit::cursorPositionChanged( QTextCursor *c )
540
541 This signal is emitted if the position of the cursor changed. \a c
542 points to the text cursor object.
543
544 \sa setCursorPosition()
545*/
546
547/*! \overload void QTextEdit::cursorPositionChanged( int para, int pos )
548
549 This signal is emitted if the position of the cursor changed. \a
550 para contains the paragraph index and \a pos contains the character
551 position within the paragraph.
552
553 \sa setCursorPosition()
554*/
555
556/*! \fn void QTextEdit::returnPressed()
557
558 This signal is emitted if the user pressed the Return or the Enter key.
559*/
560
561/*!
562 \fn QTextCursor *QTextEdit::textCursor() const
563
564 Returns the text edit's text cursor.
565
566 \warning QTextCursor is not in the public API, but in special
567 circumstances you might wish to use it.
568*/
569
570/*! Constructs an empty QTextEdit with parent \a parent and name \a
571 name.
572*/
573
574QTextEdit::QTextEdit( QWidget *parent, const char *name )
575 : QScrollView( parent, name, WStaticContents | WRepaintNoErase | WResizeNoErase ),
576 doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
577{
578 init();
579}
580
581/*!
582 Constructs a QTextEdit with parent \a parent and name \a name. The
583 text edit will display the text \a text using context \a context.
584
585 The \a context is a path which the text edit's QMimeSourceFactory
586 uses to resolve the locations of files and images. It is passed to
587 the mimeSourceFactory() when quering data.
588
589 For example if the text contains an image tag,
590 \c{<img src="image.png">}, and the context is "path/to/look/in", the
591 QMimeSourceFactory will try to load the image from
592 "path/to/look/in/image.png". If the tag was
593 \c{<img src="/image.png">}, the context will not be used (because
594 QMimeSourceFactory recognizes that we have used an absolute path)
595 and will try to load "/image.png". The context is applied in exactly
596 the same way to \e hrefs, for example,
597 \c{<a href="target.html">Target</a>}, would resolve to
598 "path/to/look/in/target.html".
599
600*/
601
602QTextEdit::QTextEdit( const QString& text, const QString& context,
603 QWidget *parent, const char *name)
604 : QScrollView( parent, name, WStaticContents | WRepaintNoErase | WResizeNoErase ),
605 doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
606{
607 init();
608 setText( text, context );
609}
610
611/*! \reimp */
612
613QTextEdit::~QTextEdit()
614{
615 delete undoRedoInfo.d;
616 undoRedoInfo.d = 0;
617 delete cursor;
618 delete doc;
619 delete d;
620}
621
622void QTextEdit::init()
623{
624 setFrameStyle( Sunken );
625 undoEnabled = TRUE;
626 readonly = TRUE;
627 setReadOnly( FALSE );
628 d = new QTextEditPrivate;
629 connect( doc, SIGNAL( minimumWidthChanged( int ) ),
630 this, SLOT( documentWidthChanged( int ) ) );
631
632 mousePressed = FALSE;
633 inDoubleClick = FALSE;
634 modified = FALSE;
635 onLink = QString::null;
636 overWrite = FALSE;
637 wrapMode = WidgetWidth;
638 wrapWidth = -1;
639 wPolicy = AtWhiteSpace;
640 inDnD = FALSE;
641
642 doc->setFormatter( new QTextFormatterBreakWords );
643 currentFormat = doc->formatCollection()->defaultFormat();
644 currentAlignment = Qt3::AlignAuto;
645
646 viewport()->setBackgroundMode( PaletteBase );
647 viewport()->setAcceptDrops( TRUE );
648 resizeContents( 0, doc->lastParag() ?
649 ( doc->lastParag()->paragId() + 1 ) * doc->formatCollection()->defaultFormat()->height() : 0 );
650
651 setKeyCompression( TRUE );
652 viewport()->setMouseTracking( TRUE );
653#ifndef QT_NO_CURSOR
654 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
655#endif
656 cursor = new QTextCursor( doc );
657
658 formatTimer = new QTimer( this );
659 connect( formatTimer, SIGNAL( timeout() ),
660 this, SLOT( formatMore() ) );
661 lastFormatted = doc->firstParag();
662
663 scrollTimer = new QTimer( this );
664 connect( scrollTimer, SIGNAL( timeout() ),
665 this, SLOT( autoScrollTimerDone() ) );
666
667 interval = 0;
668 changeIntervalTimer = new QTimer( this );
669 connect( changeIntervalTimer, SIGNAL( timeout() ),
670 this, SLOT( doChangeInterval() ) );
671
672 cursorVisible = TRUE;
673 blinkTimer = new QTimer( this );
674 connect( blinkTimer, SIGNAL( timeout() ),
675 this, SLOT( blinkCursor() ) );
676
677#ifndef QT_NO_DRAGANDDROP
678 dragStartTimer = new QTimer( this );
679 connect( dragStartTimer, SIGNAL( timeout() ),
680 this, SLOT( startDrag() ) );
681#endif
682
683
684 formatMore();
685
686 blinkCursorVisible = FALSE;
687
688 viewport()->setFocusProxy( this );
689 viewport()->setFocusPolicy( WheelFocus );
690 viewport()->installEventFilter( this );
691 installEventFilter( this );
692}
693
694void QTextEdit::paintDocument( bool drawAll, QPainter *p, int cx, int cy, int cw, int ch )
695{
696 bool drawCur = hasFocus() || viewport()->hasFocus();
697 if ( hasSelectedText() || isReadOnly() || !cursorVisible )
698 drawCur = FALSE;
699 QColorGroup g = colorGroup();
700 if ( doc->paper() )
701 g.setBrush( QColorGroup::Base, *doc->paper() );
702
703 if ( contentsY() < doc->y() ) {
704 p->fillRect( contentsX(), contentsY(), visibleWidth(), doc->y(),
705 g.brush( QColorGroup::Base ) );
706 }
707 if ( drawAll && doc->width() - contentsX() < cx + cw ) {
708 p->fillRect( doc->width() - contentsX(), cy, cx + cw - doc->width() + contentsX(), ch,
709 g.brush( QColorGroup::Base ) );
710 }
711
712 p->setBrushOrigin( -contentsX(), -contentsY() );
713
714 lastFormatted = doc->draw( p, cx, cy, cw, ch, g, !drawAll, drawCur, cursor );
715
716 if ( lastFormatted == doc->lastParag() )
717 resizeContents( contentsWidth(), doc->height() );
718
719 if ( contentsHeight() < visibleHeight() && ( !doc->lastParag() || doc->lastParag()->isValid() ) && drawAll )
720 p->fillRect( 0, contentsHeight(), visibleWidth(),
721 visibleHeight() - contentsHeight(), g.brush( QColorGroup::Base ) );
722}
723
724/*! \reimp */
725
726void QTextEdit::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
727{
728 paintDocument( TRUE, p, cx, cy, cw, ch );
729 int v;
730 p->setPen( foregroundColor() );
731 if ( document()->isPageBreakEnabled() && ( v = document()->flow()->pageSize() ) > 0 ) {
732 int l = int(cy / v) * v;
733 while ( l < cy + ch ) {
734 p->drawLine( cx, l, cx + cw - 1, l );
735 l += v;
736 }
737 }
738
739}
740
741/*! \reimp */
742
743void QTextEdit::drawContents( QPainter * )
744{
745}
746
747/*! \reimp */
748
749bool QTextEdit::event( QEvent *e )
750{
751 if ( e->type() == QEvent::AccelOverride && !isReadOnly() ) {
752 QKeyEvent* ke = (QKeyEvent*) e;
753 if ( ke->state() == NoButton || ke->state() == Keypad ) {
754 if ( ke->key() < Key_Escape ) {
755 ke->accept();
756 } else {
757 switch ( ke->key() ) {
758 case Key_Return:
759 case Key_Enter:
760 case Key_Delete:
761 case Key_Home:
762 case Key_End:
763 case Key_Backspace:
764 ke->accept();
765 default:
766 break;
767 }
768 }
769 } else if ( ke->state() & ControlButton ) {
770 switch ( ke->key() ) {
771// Those are too frequently used for application functionality
772 /* case Key_A:
773 case Key_B:
774 case Key_D:
775 case Key_E:
776 case Key_F:
777 case Key_H:
778 case Key_I:
779 case Key_K:
780 case Key_N:
781 case Key_P:
782 case Key_T:
783*/
784 case Key_C:
785 case Key_V:
786 case Key_X:
787 case Key_Y:
788 case Key_Z:
789 case Key_Left:
790 case Key_Right:
791 case Key_Up:
792 case Key_Down:
793 case Key_Home:
794 case Key_End:
795 case Key_Tab:
796#if defined (Q_WS_WIN)
797 case Key_Insert:
798 case Key_Delete:
799#endif
800 ke->accept();
801 default:
802 break;
803 }
804 } else {
805 switch ( ke->key() ) {
806#if defined (Q_WS_WIN)
807 case Key_Insert:
808 ke->accept();
809#endif
810 default:
811 break;
812 }
813 }
814 }
815
816 if ( e->type() == QEvent::Show && d->ensureCursorVisibleInShowEvent ) {
817 sync();
818 ensureCursorVisible();
819 d->ensureCursorVisibleInShowEvent = FALSE;
820 }
821 return QWidget::event( e );
822}
823
824/*!
825 Processes the key event, \a e.
826 By default key events are used to provide keyboard navigation and
827 text editing.
828*/
829
830void QTextEdit::keyPressEvent( QKeyEvent *e )
831{
832 changeIntervalTimer->stop();
833 interval = 10;
834 bool unknown = FALSE;
835 if ( isReadOnly() ) {
836 if ( !handleReadOnlyKeyEvent( e ) )
837 QScrollView::keyPressEvent( e );
838 changeIntervalTimer->start( 100, TRUE );
839 return;
840 }
841
842
843 bool selChanged = FALSE;
844 for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
845 selChanged = doc->removeSelection( i ) || selChanged;
846
847 if ( selChanged ) {
848 cursor->parag()->document()->nextDoubleBuffered = TRUE;
849 repaintChanged();
850 }
851
852 bool clearUndoRedoInfo = TRUE;
853
854
855 switch ( e->key() ) {
856 case Key_Left:
857 case Key_Right: {
858 // a bit hacky, but can't change this without introducing new enum values for move and keeping the
859 // correct semantics and movement for BiDi and non BiDi text.
860 CursorAction a;
861 if ( cursor->parag()->string()->isRightToLeft() == (e->key() == Key_Right) )
862 a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
863 else
864 a = e->state() & ControlButton ? MoveWordForward : MoveForward;
865 moveCursor( a, e->state() & ShiftButton );
866 break;
867 }
868 case Key_Up:
869 moveCursor( e->state() & ControlButton ? MovePgUp : MoveUp, e->state() & ShiftButton );
870 break;
871 case Key_Down:
872 moveCursor( e->state() & ControlButton ? MovePgDown : MoveDown, e->state() & ShiftButton );
873 break;
874 case Key_Home:
875 moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
876 break;
877 case Key_End:
878 moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
879 break;
880 case Key_Prior:
881 moveCursor( MovePgUp, e->state() & ShiftButton );
882 break;
883 case Key_Next:
884 moveCursor( MovePgDown, e->state() & ShiftButton );
885 break;
886 case Key_Return: case Key_Enter:
887 if ( doc->hasSelection( QTextDocument::Standard, FALSE ) )
888 removeSelectedText();
889#ifndef QT_NO_CURSOR
890 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
891#endif
892 clearUndoRedoInfo = FALSE;
893 doKeyboardAction( ActionReturn );
894 emit returnPressed();
895 break;
896 case Key_Delete:
897#if defined (Q_WS_WIN)
898 if ( e->state() & ShiftButton ) {
899 cut();
900 break;
901 } else
902#endif
903 if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
904 removeSelectedText();
905 break;
906 }
907 doKeyboardAction( ActionDelete );
908 clearUndoRedoInfo = FALSE;
909
910 break;
911 case Key_Insert:
912 if ( e->state() & ShiftButton )
913 paste();
914 break;
915 case Key_Backspace:
916 if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
917 removeSelectedText();
918 break;
919 }
920
921 if ( !cursor->parag()->prev() &&
922 cursor->atParagStart() )
923 break;
924
925 doKeyboardAction( ActionBackspace );
926 clearUndoRedoInfo = FALSE;
927
928 break;
929 case Key_F16: // Copy key on Sun keyboards
930 copy();
931 break;
932 case Key_F18: // Paste key on Sun keyboards
933 paste();
934 break;
935 case Key_F20: // Cut key on Sun keyboards
936 cut();
937 break;
938 default: {
939 if ( e->text().length() &&
940 ( !( e->state() & ControlButton ) &&
941 !( e->state() & AltButton ) ||
942 ( ( e->state() & ControlButton | AltButton ) == (ControlButton|AltButton) ) ) &&
943 ( !e->ascii() || e->ascii() >= 32 || e->text() == "\t" ) ) {
944 clearUndoRedoInfo = FALSE;
945 if ( e->key() == Key_Tab ) {
946 if ( textFormat() == Qt::RichText &&
947 cursor->index() == 0 && cursor->parag()->style() &&
948 cursor->parag()->style()->displayMode() ==
949 QStyleSheetItem::DisplayListItem ) {
950 cursor->parag()->incDepth();
951 drawCursor( FALSE );
952 repaintChanged();
953 drawCursor( TRUE );
954 break;
955 }
956 }
957 if ( textFormat() == Qt::RichText && ( !cursor->parag()->style() ||
958 cursor->parag()->style()->displayMode() == QStyleSheetItem::DisplayBlock ) &&
959 cursor->index() == 0 && ( e->text()[0] == '-' || e->text()[0] == '*' ) ) {
960 setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
961 cursor->parag()->incDepth();
962 drawCursor( FALSE );
963 repaintChanged();
964 drawCursor( TRUE );
965 } else {
966 if ( overWrite && !cursor->atParagEnd() )
967 cursor->remove();
968 QString t = e->text();
969 QTextParag *p = cursor->parag();
970 if ( p && p->string() && p->string()->isRightToLeft() ) {
971 QChar *c = (QChar *)t.unicode();
972 int l = t.length();
973 while( l-- ) {
974 if ( c->mirrored() )
975 *c = c->mirroredChar();
976 c++;
977 }
978 }
979 insert( t, TRUE, FALSE, TRUE );
980 }
981 break;
982 } else if ( e->state() & ControlButton ) {
983 switch ( e->key() ) {
984 case Key_C: case Key_F16: // Copy key on Sun keyboards
985 copy();
986 break;
987 case Key_V:
988 paste();
989 break;
990 case Key_X:
991 cut();
992 break;
993 case Key_I: case Key_T: case Key_Tab:
994 indent();
995 break;
996 case Key_A:
997#if defined(Q_WS_X11)
998 moveCursor( MoveLineStart, e->state() & ShiftButton );
999#else
1000 selectAll( TRUE );
1001#endif
1002 break;
1003 case Key_B:
1004 moveCursor( MoveBackward, e->state() & ShiftButton );
1005 break;
1006 case Key_F:
1007 moveCursor( MoveForward, e->state() & ShiftButton );
1008 break;
1009 case Key_D:
1010 if ( doc->hasSelection( QTextDocument::Standard ) ) {
1011 removeSelectedText();
1012 break;
1013 }
1014 doKeyboardAction( ActionDelete );
1015 clearUndoRedoInfo = FALSE;
1016 break;
1017 case Key_H:
1018 if ( doc->hasSelection( QTextDocument::Standard ) ) {
1019 removeSelectedText();
1020 break;
1021 }
1022 if ( !cursor->parag()->prev() &&
1023 cursor->atParagStart() )
1024 break;
1025
1026 doKeyboardAction( ActionBackspace );
1027 clearUndoRedoInfo = FALSE;
1028 break;
1029 case Key_E:
1030 moveCursor( MoveLineEnd, e->state() & ShiftButton );
1031 break;
1032 case Key_N:
1033 moveCursor( MoveDown, e->state() & ShiftButton );
1034 break;
1035 case Key_P:
1036 moveCursor( MoveUp, e->state() & ShiftButton );
1037 break;
1038 case Key_Z:
1039 undo();
1040 break;
1041 case Key_Y:
1042 redo();
1043 break;
1044 case Key_K:
1045 doKeyboardAction( ActionKill );
1046 break;
1047#if defined(Q_WS_WIN)
1048 case Key_Insert:
1049 copy();
1050 break;
1051 case Key_Delete:
1052 del();
1053 break;
1054#endif
1055 default:
1056 unknown = FALSE;
1057 break;
1058 }
1059 } else {
1060 unknown = TRUE;
1061 }
1062 }
1063 }
1064
1065 emit cursorPositionChanged( cursor );
1066 emit cursorPositionChanged( cursor->parag()->paragId(), cursor->index() );
1067 if ( clearUndoRedoInfo )
1068 clearUndoRedo();
1069 changeIntervalTimer->start( 100, TRUE );
1070 if ( unknown )
1071 e->ignore();
1072}
1073
1074/*!
1075 Executes keyboard action \a action. This is normally called by
1076 a key event handler.
1077*/
1078
1079void QTextEdit::doKeyboardAction( KeyboardAction action )
1080{
1081 if ( isReadOnly() )
1082 return;
1083
1084 if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
1085 return;
1086
1087 lastFormatted = cursor->parag();
1088 drawCursor( FALSE );
1089 bool doUpdateCurrentFormat = TRUE;
1090
1091 switch ( action ) {
1092 case ActionDelete: {
1093 checkUndoRedoInfo( UndoRedoInfo::Delete );
1094 if ( !undoRedoInfo.valid() ) {
1095 undoRedoInfo.id = cursor->parag()->paragId();
1096 undoRedoInfo.index = cursor->index();
1097 undoRedoInfo.d->text = QString::null;
1098 }
1099 undoRedoInfo.d->text += cursor->parag()->at( cursor->index() )->c;
1100 if ( cursor->parag()->at( cursor->index() )->format() ) {
1101 cursor->parag()->at( cursor->index() )->format()->addRef();
1102 undoRedoInfo.d->text.at( undoRedoInfo.d->text.length() - 1 ).setFormat( cursor->parag()->at( cursor->index() )->format() );
1103 }
1104 QTextParag *old = cursor->parag();
1105 if ( cursor->remove() ) {
1106 if ( old != cursor->parag() && lastFormatted == old )
1107 lastFormatted = cursor->parag() ? cursor->parag()->prev() : 0;
1108 undoRedoInfo.d->text += "\n";
1109 }
1110 } break;
1111 case ActionBackspace:
1112 if ( textFormat() == Qt::RichText &&
1113 cursor->parag()->style() &&
1114 cursor->parag()->style()->displayMode() == QStyleSheetItem::DisplayListItem &&
1115 cursor->index() == 0 ) {
1116 cursor->parag()->decDepth();
1117 lastFormatted = cursor->parag();
1118 repaintChanged();
1119 drawCursor( TRUE );
1120 return;
1121 }
1122 checkUndoRedoInfo( UndoRedoInfo::Delete );
1123 if ( !undoRedoInfo.valid() ) {
1124 undoRedoInfo.id = cursor->parag()->paragId();
1125 undoRedoInfo.index = cursor->index();
1126 undoRedoInfo.d->text = QString::null;
1127 }
1128 cursor->gotoPreviousLetter();
1129 undoRedoInfo.d->text.prepend( QString( cursor->parag()->at( cursor->index() )->c ) );
1130 if ( cursor->parag()->at( cursor->index() )->format() ) {
1131 cursor->parag()->at( cursor->index() )->format()->addRef();
1132 undoRedoInfo.d->text.at( 0 ).setFormat( cursor->parag()->at( cursor->index() )->format() );
1133 }
1134 undoRedoInfo.index = cursor->index();
1135 if ( cursor->remove() ) {
1136 undoRedoInfo.d->text.remove( 0, 1 );
1137 undoRedoInfo.d->text.prepend( "\n" );
1138 undoRedoInfo.index = cursor->index();
1139 undoRedoInfo.id = cursor->parag()->paragId();
1140 }
1141 lastFormatted = cursor->parag();
1142 break;
1143 case ActionReturn: {
1144 checkUndoRedoInfo( UndoRedoInfo::Return );
1145 if ( !undoRedoInfo.valid() ) {
1146 undoRedoInfo.id = cursor->parag()->paragId();
1147 undoRedoInfo.index = cursor->index();
1148 undoRedoInfo.d->text = QString::null;
1149 }
1150 undoRedoInfo.d->text += "\n";
1151 cursor->splitAndInsertEmptyParag();
1152 if ( cursor->parag()->prev() ) {
1153 lastFormatted = cursor->parag()->prev();
1154 lastFormatted->invalidate( 0 );
1155 }
1156 doUpdateCurrentFormat = FALSE;
1157 } break;
1158 case ActionKill:
1159 checkUndoRedoInfo( UndoRedoInfo::Delete );
1160 if ( !undoRedoInfo.valid() ) {
1161 undoRedoInfo.id = cursor->parag()->paragId();
1162 undoRedoInfo.index = cursor->index();
1163 undoRedoInfo.d->text = QString::null;
1164 }
1165 if ( cursor->atParagEnd() ) {
1166 undoRedoInfo.d->text += cursor->parag()->at( cursor->index() )->c;
1167 if ( cursor->parag()->at( cursor->index() )->format() ) {
1168 cursor->parag()->at( cursor->index() )->format()->addRef();
1169 undoRedoInfo.d->text.at( undoRedoInfo.d->text.length() - 1 ).setFormat( cursor->parag()->at( cursor->index() )->format() );
1170 }
1171 QTextParag *old = cursor->parag();
1172 if ( cursor->remove() ) {
1173 if ( old != cursor->parag() && lastFormatted == old )
1174 lastFormatted = cursor->parag() ? cursor->parag()->prev() : 0;
1175 undoRedoInfo.d->text += "\n";
1176 }
1177 } else {
1178 int oldLen = undoRedoInfo.d->text.length();
1179 undoRedoInfo.d->text += cursor->parag()->string()->toString().mid( cursor->index() );
1180 for ( int i = cursor->index(); i < cursor->parag()->length(); ++i ) {
1181 if ( cursor->parag()->at( i )->format() ) {
1182 cursor->parag()->at( i )->format()->addRef();
1183 undoRedoInfo.d->text.at( oldLen + i - cursor->index() ).setFormat( cursor->parag()->at( i )->format() );
1184 }
1185 }
1186 undoRedoInfo.d->text.remove( undoRedoInfo.d->text.length() - 1, 1 );
1187 cursor->killLine();
1188 }
1189 break;
1190 }
1191
1192 formatMore();
1193 repaintChanged();
1194 ensureCursorVisible();
1195 drawCursor( TRUE );
1196
1197 if ( hasFocus() || viewport()->hasFocus() ) {
1198 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1199 if ( !readonly ) {
1200 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
1201 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
1202 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
1203 }
1204 }
1205
1206 if ( doUpdateCurrentFormat )
1207 updateCurrentFormat();
1208 setModified();
1209 emit textChanged();
1210}
1211
1212void QTextEdit::readFormats( QTextCursor &c1, QTextCursor &c2, int oldLen, QTextString &text, bool fillStyles )
1213{
1214 c2.restoreState();
1215 c1.restoreState();
1216 if ( c1.parag() == c2.parag() ) {
1217 for ( int i = c1.index(); i < c2.index(); ++i ) {
1218 if ( c1.parag()->at( i )->format() ) {
1219 c1.parag()->at( i )->format()->addRef();
1220 text.at( oldLen + i - c1.index() ).setFormat( c1.parag()->at( i )->format() );
1221 }
1222 }
1223 if ( fillStyles ) {
1224 undoRedoInfo.oldAligns[ 0 ] = c1.parag()->alignment();
1225 undoRedoInfo.oldStyles << c1.parag()->styleSheetItems();
1226 undoRedoInfo.oldListStyles << c1.parag()->listStyle();
1227 }
1228 } else {
1229 int lastIndex = oldLen;
1230 int i;
1231 for ( i = c1.index(); i < c1.parag()->length(); ++i ) {
1232 if ( c1.parag()->at( i )->format() ) {
1233 c1.parag()->at( i )->format()->addRef();
1234 text.at( lastIndex ).setFormat( c1.parag()->at( i )->format() );
1235 lastIndex++;
1236 }
1237 }
1238 QTextParag *p = c1.parag()->next();
1239 while ( p && p != c2.parag() ) {
1240 for ( int i = 0; i < p->length(); ++i ) {
1241 if ( p->at( i )->format() ) {
1242 p->at( i )->format()->addRef();
1243 text.at( i + lastIndex ).setFormat( p->at( i )->format() );
1244 }
1245 }
1246 lastIndex += p->length();
1247 p = p->next();
1248 }
1249 for ( i = 0; i < c2.index(); ++i ) {
1250 if ( c2.parag()->at( i )->format() ) {
1251 c2.parag()->at( i )->format()->addRef();
1252 text.at( i + lastIndex ).setFormat( c2.parag()->at( i )->format() );
1253 }
1254 }
1255 if ( fillStyles ) {
1256 QTextParag *p = c1.parag();
1257 i = 0;
1258 while ( p ) {
1259 if ( i < (int)undoRedoInfo.oldAligns.size() )
1260 undoRedoInfo.oldAligns[ i ] = p->alignment();
1261 undoRedoInfo.oldStyles << p->styleSheetItems();
1262 undoRedoInfo.oldListStyles << p->listStyle();
1263 if ( p == c2.parag() )
1264 break;
1265 p = p->next();
1266 ++i;
1267 }
1268 }
1269 }
1270}
1271
1272/*! Removes the selection \a selNum (by default 0). This does not
1273 remove the selected text.
1274
1275 \sa removeSelectedText()
1276*/
1277
1278void QTextEdit::removeSelection( int selNum )
1279{
1280 doc->removeSelection( selNum );
1281 repaintChanged();
1282}
1283
1284/*! Deletes the selected text (i.e. the default selection's text) of
1285 the selection \a selNum (by default, 0). If there is no selected text
1286 nothing happens.
1287
1288 \sa selectedText removeSelection()
1289*/
1290
1291void QTextEdit::removeSelectedText( int selNum )
1292{
1293 if ( isReadOnly() )
1294 return;
1295
1296 QTextCursor c1 = doc->selectionStartCursor( selNum );
1297 QTextCursor c2 = doc->selectionEndCursor( selNum );
1298
1299 // ### no support for editing tables yet
1300 if ( c1.nestedDepth() || c2.nestedDepth() )
1301 return;
1302
1303 for ( int i = 0; i < (int)doc->numSelections(); ++i ) {
1304 if ( i == selNum )
1305 continue;
1306 doc->removeSelection( i );
1307 }
1308
1309 drawCursor( FALSE );
1310 checkUndoRedoInfo( UndoRedoInfo::RemoveSelected );
1311 if ( !undoRedoInfo.valid() ) {
1312 doc->selectionStart( selNum, undoRedoInfo.id, undoRedoInfo.index );
1313 undoRedoInfo.d->text = QString::null;
1314 }
1315 int oldLen = undoRedoInfo.d->text.length();
1316 undoRedoInfo.d->text = doc->selectedText( selNum, FALSE );
1317 undoRedoInfo.oldAligns.resize( undoRedoInfo.oldAligns.size() + QMAX( 0, c2.parag()->paragId() - c1.parag()->paragId() + 1 ) );
1318 readFormats( c1, c2, oldLen, undoRedoInfo.d->text, TRUE );
1319 doc->removeSelectedText( selNum, cursor );
1320 if ( cursor->isValid() ) {
1321 ensureCursorVisible();
1322 lastFormatted = cursor->parag();
1323 formatMore();
1324 repaintChanged();
1325 ensureCursorVisible();
1326 drawCursor( TRUE );
1327 clearUndoRedo();
1328#if defined(Q_WS_WIN)
1329 // there seems to be a problem with repainting or erasing the area
1330 // of the scrollview which is not the contents on windows
1331 if ( contentsHeight() < visibleHeight() )
1332 viewport()->repaint( 0, contentsHeight(), visibleWidth(), visibleHeight() - contentsHeight(), TRUE );
1333#endif
1334#ifndef QT_NO_CURSOR
1335 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
1336#endif
1337 if ( hasFocus() || viewport()->hasFocus() ) {
1338 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1339 if ( !readonly ) {
1340 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
1341 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
1342 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
1343 }
1344 }
1345 } else {
1346 cursor->setDocument( doc );
1347 cursor->setParag( doc->firstParag() );
1348 cursor->setIndex( 0 );
1349 drawCursor( TRUE );
1350 viewport()->repaint( TRUE );
1351 }
1352 setModified();
1353 emit textChanged();
1354 emit selectionChanged();
1355}
1356
1357/*! Moves the text cursor according to \a action. This is normally
1358 used by some key event handler. \a select specifies whether the text
1359 between the current cursor position and the new position should be
1360 selected.
1361*/
1362
1363void QTextEdit::moveCursor( CursorAction action, bool select )
1364{
1365 drawCursor( FALSE );
1366 if ( select ) {
1367 if ( !doc->hasSelection( QTextDocument::Standard ) )
1368 doc->setSelectionStart( QTextDocument::Standard, cursor );
1369 moveCursor( action );
1370 if ( doc->setSelectionEnd( QTextDocument::Standard, cursor ) ) {
1371 cursor->parag()->document()->nextDoubleBuffered = TRUE;
1372 repaintChanged();
1373 } else {
1374 drawCursor( TRUE );
1375 }
1376 ensureCursorVisible();
1377 emit selectionChanged();
1378 emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
1379 } else {
1380 bool redraw = doc->removeSelection( QTextDocument::Standard );
1381 moveCursor( action );
1382 if ( !redraw ) {
1383 ensureCursorVisible();
1384 drawCursor( TRUE );
1385 } else {
1386 cursor->parag()->document()->nextDoubleBuffered = TRUE;
1387 repaintChanged();
1388 ensureCursorVisible();
1389 drawCursor( TRUE );
1390#ifndef QT_NO_CURSOR
1391 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
1392#endif
1393 }
1394 if ( redraw ) {
1395 emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
1396 emit selectionChanged();
1397 }
1398 }
1399
1400 drawCursor( TRUE );
1401 updateCurrentFormat();
1402 if ( hasFocus() || viewport()->hasFocus() ) {
1403 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1404 if ( !readonly ) {
1405 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
1406 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
1407 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
1408 }
1409 }
1410}
1411
1412/*! \overload
1413*/
1414
1415void QTextEdit::moveCursor( CursorAction action )
1416{
1417 switch ( action ) {
1418 case MoveBackward:
1419 cursor->gotoPreviousLetter();
1420 break;
1421 case MoveWordBackward:
1422 cursor->gotoPreviousWord();
1423 break;
1424 case MoveForward:
1425 cursor->gotoNextLetter();
1426 break;
1427 case MoveWordForward:
1428 cursor->gotoNextWord();
1429 break;
1430 case MoveUp:
1431 cursor->gotoUp();
1432 break;
1433 case MovePgUp:
1434 cursor->gotoPageUp( visibleHeight() );
1435 break;
1436 case MoveDown:
1437 cursor->gotoDown();
1438 break;
1439 case MovePgDown:
1440 cursor->gotoPageDown( visibleHeight() );
1441 break;
1442 case MoveLineStart:
1443 cursor->gotoLineStart();
1444 break;
1445 case MoveHome:
1446 cursor->gotoHome();
1447 break;
1448 case MoveLineEnd:
1449 cursor->gotoLineEnd();
1450 break;
1451 case MoveEnd:
1452 ensureFormatted( doc->lastParag() );
1453 cursor->gotoEnd();
1454 break;
1455 }
1456
1457 if ( hasFocus() || viewport()->hasFocus() ) {
1458 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1459 if ( !readonly ) {
1460 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
1461 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
1462 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
1463 }
1464 }
1465 updateCurrentFormat();
1466}
1467
1468/*! \reimp */
1469
1470void QTextEdit::resizeEvent( QResizeEvent *e )
1471{
1472 QScrollView::resizeEvent( e );
1473}
1474
1475/*! \reimp */
1476
1477void QTextEdit::viewportResizeEvent( QResizeEvent *e )
1478{
1479 QScrollView::viewportResizeEvent( e );
1480 if ( e->oldSize().width() != e->size().width() )
1481 doResize();
1482}
1483
1484static bool blockEnsureCursorVisible = FALSE;
1485
1486/*!
1487 Ensures that the cursor is visible by scrolling the text edit if
1488 necessary.
1489
1490 \sa setCursorPosition()
1491*/
1492
1493void QTextEdit::ensureCursorVisible()
1494{
1495 if ( blockEnsureCursorVisible )
1496 return;
1497 if ( !isVisible() ) {
1498 d->ensureCursorVisibleInShowEvent = TRUE;
1499 return;
1500 }
1501 lastFormatted = cursor->parag();
1502 formatMore();
1503 QTextStringChar *chr = cursor->parag()->at( cursor->index() );
1504 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1505 int x = cursor->parag()->rect().x() + chr->x + cursor->offsetX();
1506 int y = 0; int dummy;
1507 cursor->parag()->lineHeightOfChar( cursor->index(), &dummy, &y );
1508 y += cursor->parag()->rect().y() + cursor->offsetY();
1509 int w = 1;
1510 ensureVisible( x, y + h / 2, w, h / 2 + 2 );
1511}
1512
1513/*!
1514 \internal
1515*/
1516void QTextEdit::drawCursor( bool visible )
1517{
1518 if ( !isUpdatesEnabled() ||
1519 !viewport()->isUpdatesEnabled() ||
1520 !cursor->parag() ||
1521 !cursor->parag()->isValid() ||
1522 !selectedText().isEmpty() ||
1523 ( visible && !hasFocus() && !viewport()->hasFocus() && !inDnD ) ||
1524 isReadOnly() )
1525 return;
1526
1527 QPainter p( viewport() );
1528 QRect r( cursor->topParag()->rect() );
1529 cursor->parag()->setChanged( TRUE );
1530 p.translate( -contentsX() + cursor->totalOffsetX(), -contentsY() + cursor->totalOffsetY() );
1531 QPixmap *pix = 0;
1532 QColorGroup cg( colorGroup() );
1533 if ( cursor->parag()->background() )
1534 cg.setBrush( QColorGroup::Base, *cursor->parag()->background() );
1535 else if ( doc->paper() )
1536 cg.setBrush( QColorGroup::Base, *doc->paper() );
1537 p.setBrushOrigin( -contentsX(), -contentsY() );
1538 cursor->parag()->document()->nextDoubleBuffered = TRUE;
1539 if ( !cursor->nestedDepth() ) {
1540 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1541 int dist = 5;
1542 if ( ( cursor->parag()->alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify )
1543 dist = 50;
1544 int x = r.x() - cursor->totalOffsetX() + cursor->x() - dist;
1545 x = QMAX( x, 0 );
1546 p.setClipRect( QRect( x - contentsX(),
1547 r.y() - cursor->totalOffsetY() + cursor->y() - contentsY(), 2 * dist, h ) );
1548 doc->drawParag( &p, cursor->parag(), x,
1549 r.y() - cursor->totalOffsetY() + cursor->y(), 2 * dist, h, pix, cg, visible, cursor );
1550 } else {
1551 doc->drawParag( &p, cursor->parag(), r.x() - cursor->totalOffsetX(),
1552 r.y() - cursor->totalOffsetY(), r.width(), r.height(),
1553 pix, cg, visible, cursor );
1554 }
1555 cursorVisible = visible;
1556}
1557
1558enum {
1559 IdUndo = 0,
1560 IdRedo = 1,
1561 IdCut = 2,
1562 IdCopy = 3,
1563 IdPaste = 4,
1564 IdClear = 5,
1565 IdSelectAll = 6
1566};
1567
1568/*! \reimp */
1569#ifndef QT_NO_WHEELEVENT
1570void QTextEdit::contentsWheelEvent( QWheelEvent *e )
1571{
1572 if ( isReadOnly() ) {
1573 if ( e->state() & ControlButton ) {
1574 if ( e->delta() > 0 )
1575 zoomOut();
1576 else if ( e->delta() < 0 )
1577 zoomIn();
1578 return;
1579 }
1580 }
1581 QScrollView::contentsWheelEvent( e );
1582}
1583#endif
1584
1585/*! \reimp */
1586
1587void QTextEdit::contentsMousePressEvent( QMouseEvent *e )
1588{
1589 clearUndoRedo();
1590 QTextCursor oldCursor = *cursor;
1591 QTextCursor c = *cursor;
1592 mousePos = e->pos();
1593 mightStartDrag = FALSE;
1594 pressedLink = QString::null;
1595
1596 if ( e->button() == LeftButton ) {
1597 mousePressed = TRUE;
1598 drawCursor( FALSE );
1599 placeCursor( e->pos() );
1600 ensureCursorVisible();
1601
1602 if ( isReadOnly() && linksEnabled() ) {
1603 QTextCursor c = *cursor;
1604 placeCursor( e->pos(), &c, TRUE );
1605 if ( c.parag() && c.parag()->at( c.index() ) &&
1606 c.parag()->at( c.index() )->isAnchor() ) {
1607 pressedLink = c.parag()->at( c.index() )->anchorHref();
1608 }
1609 }
1610
1611#ifndef QT_NO_DRAGANDDROP
1612 if ( doc->inSelection( QTextDocument::Standard, e->pos() ) ) {
1613 mightStartDrag = TRUE;
1614 drawCursor( TRUE );
1615 dragStartTimer->start( QApplication::startDragTime(), TRUE );
1616 dragStartPos = e->pos();
1617 return;
1618 }
1619#endif
1620
1621 bool redraw = FALSE;
1622 if ( doc->hasSelection( QTextDocument::Standard ) ) {
1623 if ( !( e->state() & ShiftButton ) ) {
1624 redraw = doc->removeSelection( QTextDocument::Standard );
1625 doc->setSelectionStart( QTextDocument::Standard, cursor );
1626 } else {
1627 redraw = doc->setSelectionEnd( QTextDocument::Standard, cursor ) || redraw;
1628 }
1629 } else {
1630 if ( isReadOnly() || !( e->state() & ShiftButton ) ) {
1631 doc->setSelectionStart( QTextDocument::Standard, cursor );
1632 } else {
1633 doc->setSelectionStart( QTextDocument::Standard, &c );
1634 redraw = doc->setSelectionEnd( QTextDocument::Standard, cursor ) || redraw;
1635 }
1636 }
1637
1638 for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
1639 redraw = doc->removeSelection( i ) || redraw;
1640
1641 if ( !redraw ) {
1642 drawCursor( TRUE );
1643 } else {
1644 repaintChanged();
1645#ifndef QT_NO_CURSOR
1646 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
1647#endif
1648 }
1649 } else if ( e->button() == MidButton ) {
1650 bool redraw = doc->removeSelection( QTextDocument::Standard );
1651 if ( !redraw ) {
1652 drawCursor( TRUE );
1653 } else {
1654 repaintChanged();
1655#ifndef QT_NO_CURSOR
1656 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
1657#endif
1658 }
1659 }
1660
1661 if ( *cursor != oldCursor )
1662 updateCurrentFormat();
1663}
1664
1665/*! \reimp */
1666
1667void QTextEdit::contentsMouseMoveEvent( QMouseEvent *e )
1668{
1669 if ( mousePressed ) {
1670#ifndef QT_NO_DRAGANDDROP
1671 if ( mightStartDrag ) {
1672 dragStartTimer->stop();
1673 if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() )
1674 startDrag();
1675#ifndef QT_NO_CURSOR
1676 if ( !isReadOnly() )
1677 viewport()->setCursor( ibeamCursor );
1678#endif
1679 return;
1680 }
1681#endif
1682 mousePos = e->pos();
1683 handleMouseMove( mousePos );
1684 oldMousePos = mousePos;
1685 }
1686
1687#ifndef QT_NO_CURSOR
1688 if ( !isReadOnly() && !mousePressed ) {
1689 if ( doc->hasSelection( QTextDocument::Standard ) && doc->inSelection( QTextDocument::Standard, e->pos() ) )
1690 viewport()->setCursor( arrowCursor );
1691 else
1692 viewport()->setCursor( ibeamCursor );
1693 }
1694#endif
1695 updateCursor( e->pos() );
1696}
1697
1698/*! \reimp */
1699
1700void QTextEdit::contentsMouseReleaseEvent( QMouseEvent * e )
1701{
1702 QTextCursor oldCursor = *cursor;
1703 if ( scrollTimer->isActive() )
1704 scrollTimer->stop();
1705#ifndef QT_NO_DRAGANDDROP
1706 if ( dragStartTimer->isActive() )
1707 dragStartTimer->stop();
1708 if ( mightStartDrag ) {
1709 selectAll( FALSE );
1710 mousePressed = FALSE;
1711 }
1712#endif
1713 if ( mousePressed ) {
1714 mousePressed = FALSE;
1715 }
1716 emit cursorPositionChanged( cursor );
1717 emit cursorPositionChanged( cursor->parag()->paragId(), cursor->index() );
1718 if ( oldCursor != *cursor )
1719 updateCurrentFormat();
1720 inDoubleClick = FALSE;
1721
1722#ifndef QT_NO_NETWORKPROTOCOL
1723 if ( !onLink.isEmpty() && onLink == pressedLink && linksEnabled() ) {
1724 QUrl u( doc->context(), onLink, TRUE );
1725 emitLinkClicked( u.toString( FALSE, FALSE ) );
1726
1727 // emitting linkClicked() may result in that the cursor winds
1728 // up hovering over a different valid link - check this and
1729 // set the appropriate cursor shape
1730 updateCursor( e->pos() );
1731 }
1732#endif
1733 drawCursor( TRUE );
1734 if ( !doc->hasSelection( QTextDocument::Standard, TRUE ) )
1735 doc->removeSelection( QTextDocument::Standard );
1736
1737 emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
1738 emit selectionChanged();
1739}
1740
1741/*! \reimp */
1742
1743void QTextEdit::contentsMouseDoubleClickEvent( QMouseEvent * )
1744{
1745 QTextCursor c1 = *cursor;
1746 QTextCursor c2 = *cursor;
1747 if ( cursor->index() > 0 && !cursor->parag()->at( cursor->index()-1 )->c.isSpace() )
1748 c1.gotoPreviousWord();
1749 if ( !cursor->parag()->at( cursor->index() )->c.isSpace() && !cursor->atParagEnd() )
1750 c2.gotoNextWord();
1751
1752 doc->setSelectionStart( QTextDocument::Standard, &c1 );
1753 doc->setSelectionEnd( QTextDocument::Standard, &c2 );
1754
1755 *cursor = c2;
1756
1757 repaintChanged();
1758
1759 inDoubleClick = TRUE;
1760 mousePressed = TRUE;
1761}
1762
1763#ifndef QT_NO_DRAGANDDROP
1764
1765/*! \reimp */
1766
1767void QTextEdit::contentsDragEnterEvent( QDragEnterEvent *e )
1768{
1769 if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
1770 e->ignore();
1771 return;
1772 }
1773 e->acceptAction();
1774 inDnD = TRUE;
1775}
1776
1777/*! \reimp */
1778
1779void QTextEdit::contentsDragMoveEvent( QDragMoveEvent *e )
1780{
1781 if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
1782 e->ignore();
1783 return;
1784 }
1785 drawCursor( FALSE );
1786 placeCursor( e->pos(), cursor );
1787 drawCursor( TRUE );
1788 e->acceptAction();
1789}
1790
1791/*! \reimp */
1792
1793void QTextEdit::contentsDragLeaveEvent( QDragLeaveEvent * )
1794{
1795 inDnD = FALSE;
1796}
1797
1798/*! \reimp */
1799
1800void QTextEdit::contentsDropEvent( QDropEvent *e )
1801{
1802 if ( isReadOnly() )
1803 return;
1804 inDnD = FALSE;
1805 e->acceptAction();
1806 QString text;
1807 bool intern = FALSE;
1808 if ( QTextDrag::decode( e, text ) ) {
1809 if ( ( e->source() == this ||
1810 e->source() == viewport() ) &&
1811 e->action() == QDropEvent::Move ) {
1812 removeSelectedText();
1813 intern = TRUE;
1814 } else {
1815 doc->removeSelection( QTextDocument::Standard );
1816#ifndef QT_NO_CURSOR
1817 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
1818#endif
1819 }
1820 drawCursor( FALSE );
1821 placeCursor( e->pos(), cursor );
1822 drawCursor( TRUE );
1823 if ( !cursor->nestedDepth() ) {
1824 insert( text, FALSE, TRUE, FALSE );
1825 } else {
1826 if ( intern )
1827 undo();
1828 e->ignore();
1829 }
1830 }
1831}
1832
1833#endif
1834
1835void QTextEdit::autoScrollTimerDone()
1836{
1837 if ( mousePressed )
1838 handleMouseMove( viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) ) );
1839}
1840
1841void QTextEdit::handleMouseMove( const QPoint& pos )
1842{
1843 if ( !mousePressed )
1844 return;
1845
1846 if ( !scrollTimer->isActive() && pos.y() < contentsY() || pos.y() > contentsY() + visibleHeight() )
1847 scrollTimer->start( 100, FALSE );
1848 else if ( scrollTimer->isActive() && pos.y() >= contentsY() && pos.y() <= contentsY() + visibleHeight() )
1849 scrollTimer->stop();
1850
1851 drawCursor( FALSE );
1852 QTextCursor oldCursor = *cursor;
1853
1854 placeCursor( pos );
1855
1856 if ( inDoubleClick ) {
1857 QTextCursor cl = *cursor;
1858 cl.gotoPreviousWord();
1859 QTextCursor cr = *cursor;
1860 cr.gotoNextWord();
1861
1862 int diff = QABS( oldCursor.parag()->at( oldCursor.index() )->x - mousePos.x() );
1863 int ldiff = QABS( cl.parag()->at( cl.index() )->x - mousePos.x() );
1864 int rdiff = QABS( cr.parag()->at( cr.index() )->x - mousePos.x() );
1865
1866
1867 if ( cursor->parag()->lineStartOfChar( cursor->index() ) !=
1868 oldCursor.parag()->lineStartOfChar( oldCursor.index() ) )
1869 diff = 0xFFFFFF;
1870
1871 if ( rdiff < diff && rdiff < ldiff )
1872 *cursor = cr;
1873 else if ( ldiff < diff && ldiff < rdiff )
1874 *cursor = cl;
1875 else
1876 *cursor = oldCursor;
1877
1878 }
1879 ensureCursorVisible();
1880
1881 bool redraw = FALSE;
1882 if ( doc->hasSelection( QTextDocument::Standard ) ) {
1883 redraw = doc->setSelectionEnd( QTextDocument::Standard, cursor ) || redraw;
1884 }
1885
1886 if ( !redraw ) {
1887 drawCursor( TRUE );
1888 } else {
1889 repaintChanged();
1890 drawCursor( TRUE );
1891 }
1892
1893 if ( currentFormat && currentFormat->key() != cursor->parag()->at( cursor->index() )->format()->key() ) {
1894 currentFormat->removeRef();
1895 currentFormat = doc->formatCollection()->format( cursor->parag()->at( cursor->index() )->format() );
1896 if ( currentFormat->isMisspelled() ) {
1897 currentFormat->removeRef();
1898 currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
1899 }
1900 emit currentFontChanged( currentFormat->font() );
1901 emit currentColorChanged( currentFormat->color() );
1902 emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
1903 }
1904
1905 if ( currentAlignment != cursor->parag()->alignment() ) {
1906 currentAlignment = cursor->parag()->alignment();
1907 block_set_alignment = TRUE;
1908 emit currentAlignmentChanged( currentAlignment );
1909 block_set_alignment = FALSE;
1910 }
1911}
1912
1913/*!
1914 \fn void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c )
1915 Places the cursor \a c at the character which is closest to position
1916 \a pos (in contents coordinates). If \a c is 0, the default text
1917 cursor is used.
1918
1919 \sa setCursorPosition()
1920*/
1921
1922void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c, bool link )
1923{
1924 if ( !c )
1925 c = cursor;
1926
1927 c->restoreState();
1928 QTextParag *s = doc->firstParag();
1929 c->place( pos, s, link );
1930 if ( hasFocus() || viewport()->hasFocus() ) {
1931 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
1932 if ( !readonly ) {
1933 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
1934 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
1935 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
1936 }
1937 }
1938}
1939
1940void QTextEdit::formatMore()
1941{
1942 if ( !lastFormatted )
1943 return;
1944
1945 int bottom = contentsHeight();
1946 int lastBottom = -1;
1947 int to = !sender() ? 2 : 20;
1948 bool firstVisible = FALSE;
1949 QRect cr( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
1950 for ( int i = 0; ( i < to || firstVisible ) && lastFormatted; ++i ) {
1951 lastFormatted->format();
1952 if ( i == 0 )
1953 firstVisible = lastFormatted->rect().intersects( cr );
1954 else if ( firstVisible )
1955 firstVisible = lastFormatted->rect().intersects( cr );
1956 bottom = QMAX( bottom, lastFormatted->rect().top() +
1957 lastFormatted->rect().height() );
1958 lastBottom = lastFormatted->rect().top() + lastFormatted->rect().height();
1959 lastFormatted = lastFormatted->next();
1960 if ( lastFormatted )
1961 lastBottom = -1;
1962 }
1963
1964 if ( bottom > contentsHeight() )
1965 resizeContents( contentsWidth(), QMAX( doc->height(), bottom ) );
1966 else if ( lastBottom != -1 && lastBottom < contentsHeight() )
1967 resizeContents( contentsWidth(), QMAX( doc->height(), lastBottom ) );
1968
1969 if ( lastFormatted )
1970 formatTimer->start( interval, TRUE );
1971 else
1972 interval = QMAX( 0, interval );
1973}
1974
1975void QTextEdit::doResize()
1976{
1977 if ( wrapMode == FixedPixelWidth )
1978 return;
1979 doc->setMinimumWidth( -1 );
1980 resizeContents( 0, 0 );
1981 doc->setWidth( visibleWidth() );
1982 doc->invalidate();
1983 lastFormatted = doc->firstParag();
1984 interval = 0;
1985 formatMore();
1986 repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE );
1987}
1988
1989/*! \internal */
1990
1991void QTextEdit::doChangeInterval()
1992{
1993 interval = 0;
1994}
1995
1996/*! \reimp */
1997
1998bool QTextEdit::eventFilter( QObject *o, QEvent *e )
1999{
2000 if ( o == this || o == viewport() ) {
2001 if ( e->type() == QEvent::FocusIn ) {
2002 blinkTimer->start( QApplication::cursorFlashTime() / 2 );
2003 drawCursor( TRUE );
2004
2005 if ( !readonly ) {
2006 // make sure the micro focus hint is updated...
2007 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
2008 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
2009 cursor->y() + cursor->parag()->rect().y() -
2010 contentsY() + frameWidth(), 0,
2011 cursor->parag()->lineHeightOfChar( cursor->index() ),
2012 TRUE );
2013 }
2014 } else if ( e->type() == QEvent::FocusOut ) {
2015 blinkTimer->stop();
2016 drawCursor( FALSE );
2017 }
2018 }
2019
2020 return QScrollView::eventFilter( o, e );
2021}
2022
2023/*!
2024 Inserts \a text at the current cursor position. If \a indent is TRUE,
2025 the paragraph is re-indented. If \a checkNewLine is TRUE, newline
2026 characters in \a text result in hard line breaks (i.e. new
2027 paragraphs). If \a checkNewLine is FALSE the behaviour of the editor
2028 is undefined if the \a text contains newlines. If \a removeSelected is
2029 TRUE, any selected text (in selection 0) is removed before the text is
2030 inserted.
2031
2032 \sa paste() pasteSubType()
2033*/
2034
2035void QTextEdit::insert( const QString &text, bool indent, bool checkNewLine, bool removeSelected )
2036{
2037 if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
2038 return;
2039 QString txt( text );
2040 drawCursor( FALSE );
2041 if ( !isReadOnly() && doc->hasSelection( QTextDocument::Standard ) && removeSelected )
2042 removeSelectedText();
2043 QTextCursor c2 = *cursor;
2044 int oldLen = 0;
2045
2046 if ( undoEnabled && !isReadOnly() ) {
2047 checkUndoRedoInfo( UndoRedoInfo::Insert );
2048 if ( !undoRedoInfo.valid() ) {
2049 undoRedoInfo.id = cursor->parag()->paragId();
2050 undoRedoInfo.index = cursor->index();
2051 undoRedoInfo.d->text = QString::null;
2052 }
2053 oldLen = undoRedoInfo.d->text.length();
2054 }
2055
2056 lastFormatted = checkNewLine && cursor->parag()->prev() ?
2057 cursor->parag()->prev() : cursor->parag();
2058 QTextCursor oldCursor = *cursor;
2059 cursor->insert( txt, checkNewLine );
2060 if ( doc->useFormatCollection() ) {
2061 doc->setSelectionStart( QTextDocument::Temp, &oldCursor );
2062 doc->setSelectionEnd( QTextDocument::Temp, cursor );
2063 doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
2064 doc->removeSelection( QTextDocument::Temp );
2065 }
2066
2067 if ( indent && ( txt == "{" || txt == "}" || txt == ":" || txt == "#" ) )
2068 cursor->indent();
2069 formatMore();
2070 repaintChanged();
2071 ensureCursorVisible();
2072 drawCursor( TRUE );
2073
2074 if ( undoEnabled && !isReadOnly() ) {
2075 undoRedoInfo.d->text += txt;
2076 if ( !doc->preProcessor() ) {
2077 for ( int i = 0; i < (int)txt.length(); ++i ) {
2078 if ( txt[ i ] != '\n' && c2.parag()->at( c2.index() )->format() ) {
2079 c2.parag()->at( c2.index() )->format()->addRef();
2080 undoRedoInfo.d->text.setFormat( oldLen + i, c2.parag()->at( c2.index() )->format(), TRUE );
2081 }
2082 c2.gotoNextLetter();
2083 }
2084 }
2085 }
2086
2087 setModified();
2088 emit textChanged();
2089 if ( !removeSelected ) {
2090 doc->setSelectionStart( QTextDocument::Standard, &oldCursor );
2091 doc->setSelectionEnd( QTextDocument::Standard, cursor );
2092 repaintChanged();
2093 }
2094 if ( hasFocus() || viewport()->hasFocus() ) {
2095 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
2096 if ( !readonly ) {
2097 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
2098 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
2099 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
2100 }
2101 }
2102}
2103
2104/*! Inserts \a text in the paragraph \a para and position \a index */
2105
2106void QTextEdit::insertAt( const QString &text, int para, int index )
2107{
2108 QTextParag *p = doc->paragAt( para );
2109 if ( !p )
2110 return;
2111 QTextCursor tmp = *cursor;
2112 cursor->setParag( p );
2113 cursor->setIndex( index );
2114 insert( text, FALSE, TRUE, FALSE );
2115 *cursor = tmp;
2116 removeSelection( QTextDocument::Standard );
2117}
2118
2119/*! Inserts \a text as the paragraph at position \a para. If \a para
2120 is -1, the text is appended.
2121*/
2122
2123void QTextEdit::insertParagraph( const QString &text, int para )
2124{
2125 QTextParag *p = doc->paragAt( para );
2126 if ( p ) {
2127 QTextCursor tmp( doc );
2128 tmp.setParag( p );
2129 tmp.setIndex( 0 );
2130 tmp.insert( text, TRUE );
2131 tmp.splitAndInsertEmptyParag();
2132 repaintChanged();
2133 } else {
2134 append( text );
2135 }
2136}
2137
2138/*! Removes the paragraph \a para */
2139
2140void QTextEdit::removeParagraph( int para )
2141{
2142 QTextParag *p = doc->paragAt( para );
2143 if ( !p )
2144 return;
2145 for ( int i = 0; i < doc->numSelections(); ++i )
2146 doc->removeSelection( i );
2147
2148 if ( p == doc->firstParag() && p == doc->lastParag() ) {
2149 p->remove( 0, p->length() - 1 );
2150 repaintChanged();
2151 return;
2152 }
2153 drawCursor( FALSE );
2154 bool resetCursor = cursor->parag() == p;
2155 if ( p->prev() )
2156 p->prev()->setNext( p->next() );
2157 else
2158 doc->setFirstParag( p->next() );
2159 if ( p->next() )
2160 p->next()->setPrev( p->prev() );
2161 else
2162 doc->setLastParag( p->prev() );
2163 QTextParag *start = p->next();
2164 int h = p->rect().height();
2165 delete p;
2166 p = start;
2167 int dy = -h;
2168 while ( p ) {
2169 p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
2170 p->move( dy );
2171 p->invalidate( 0 );
2172 p->setEndState( -1 );
2173 p = p->next();
2174 }
2175
2176 if ( resetCursor ) {
2177 cursor->setParag( doc->firstParag() );
2178 cursor->setIndex( 0 );
2179 }
2180 repaintChanged();
2181 drawCursor( TRUE );
2182}
2183
2184/*!
2185 Undoes the last operation.
2186
2187 If there is no operation to undo, e.g. there is no undo step in the
2188 undo/redo history, nothing happens.
2189
2190 \sa undoAvailable() redo() undoDepth()
2191*/
2192
2193void QTextEdit::undo()
2194{
2195 // XXX FIXME The next line is here because there may be a command
2196 // that needs to be 'flushed'. The FIXME is because I am not
2197 // 100% certain this is the right call to do this.
2198 clearUndoRedo();
2199 if ( isReadOnly() || !doc->commands()->isUndoAvailable() || !undoEnabled )
2200 return;
2201
2202 for ( int i = 0; i < (int)doc->numSelections(); ++i )
2203 doc->removeSelection( i );
2204
2205#ifndef QT_NO_CURSOR
2206 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
2207#endif
2208
2209 clearUndoRedo();
2210 drawCursor( FALSE );
2211 QTextCursor *c = doc->undo( cursor );
2212 if ( !c ) {
2213 drawCursor( TRUE );
2214 return;
2215 }
2216 lastFormatted = 0;
2217 ensureCursorVisible();
2218 repaintChanged();
2219 drawCursor( TRUE );
2220 setModified();
2221 emit textChanged();
2222 if ( hasFocus() || viewport()->hasFocus() ) {
2223 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
2224 if ( !readonly ) {
2225 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
2226 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
2227 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
2228 }
2229 }
2230}
2231
2232/*!
2233 Redoes the last operation.
2234
2235 If there is no operation to redo, e.g. there is no redo step in the
2236 undo/redo history, nothing happens.
2237
2238 \sa redoAvailable() undo() undoDepth()
2239*/
2240
2241void QTextEdit::redo()
2242{
2243 if ( isReadOnly() || !doc->commands()->isRedoAvailable() || !undoEnabled )
2244 return;
2245
2246 for ( int i = 0; i < (int)doc->numSelections(); ++i )
2247 doc->removeSelection( i );
2248
2249#ifndef QT_NO_CURSOR
2250 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
2251#endif
2252
2253 clearUndoRedo();
2254 drawCursor( FALSE );
2255 QTextCursor *c = doc->redo( cursor );
2256 if ( !c ) {
2257 drawCursor( TRUE );
2258 return;
2259 }
2260 lastFormatted = 0;
2261 ensureCursorVisible();
2262 repaintChanged();
2263 ensureCursorVisible();
2264 drawCursor( TRUE );
2265 setModified();
2266 emit textChanged();
2267 if ( hasFocus() || viewport()->hasFocus() ) {
2268 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
2269 if ( !readonly ) {
2270 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
2271 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
2272 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
2273 }
2274 }
2275}
2276
2277/*!
2278 Pastes the text from the clipboard into the text edit at the current
2279 cursor position. Only plain text is pasted.
2280
2281 If there is no text in the clipboard nothing happens.
2282
2283 \sa pasteSubType() cut() QTextEdit::copy()
2284*/
2285
2286void QTextEdit::paste()
2287{
2288#ifndef QT_NO_CLIPBOARD
2289 if ( isReadOnly() )
2290 return;
2291 pasteSubType( "plain" );
2292 if ( hasFocus() || viewport()->hasFocus() ) {
2293 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
2294 if ( !readonly ) {
2295 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
2296 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
2297 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
2298 }
2299 }
2300#endif
2301}
2302
2303void QTextEdit::checkUndoRedoInfo( UndoRedoInfo::Type t )
2304{
2305 if ( undoRedoInfo.valid() && t != undoRedoInfo.type ) {
2306 clearUndoRedo();
2307 }
2308 undoRedoInfo.type = t;
2309}
2310
2311/*! Repaints any paragraphs that have changed.
2312
2313 Although used extensively internally you shouldn't need to call this
2314 yourself.
2315*/
2316
2317void QTextEdit::repaintChanged()
2318{
2319 if ( !isUpdatesEnabled() || !viewport()->isUpdatesEnabled() )
2320 return;
2321 QPainter p( viewport() );
2322 p.translate( -contentsX(), -contentsY() );
2323 paintDocument( FALSE, &p, contentsX(), contentsY(), visibleWidth(), visibleHeight() );
2324}
2325
2326/*!
2327 Copies the selected text (from selection 0) to the clipboard and
2328 deletes it from the text edit.
2329
2330 If there is no selected text (in selection 0) nothing happens.
2331
2332 \sa QTextEdit::copy() paste() pasteSubType()
2333*/
2334
2335void QTextEdit::cut()
2336{
2337 if ( isReadOnly() )
2338 return;
2339
2340 if ( doc->hasSelection( QTextDocument::Standard ) ) {
2341 doc->copySelectedText( QTextDocument::Standard );
2342 removeSelectedText();
2343 }
2344 if ( hasFocus() || viewport()->hasFocus() ) {
2345 int h = cursor->parag()->lineHeightOfChar( cursor->index() );
2346 if ( !readonly ) {
2347 QFont f = cursor->parag()->at( cursor->index() )->format()->font();
2348 setMicroFocusHint( cursor->x() - contentsX() + frameWidth(),
2349 cursor->y() + cursor->parag()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
2350 }
2351 }
2352}
2353
2354/*! Copies any selected text (from selection 0) to the clipboard.
2355
2356 \sa hasSelectedText() copyAvailable()
2357 */
2358
2359void QTextEdit::copy()
2360{
2361 if ( !doc->selectedText( QTextDocument::Standard ).isEmpty() )
2362 doc->copySelectedText( QTextDocument::Standard );
2363}
2364
2365/*!
2366 Re-indents the current paragraph.
2367*/
2368
2369void QTextEdit::indent()
2370{
2371 if ( isReadOnly() )
2372 return;
2373
2374 drawCursor( FALSE );
2375 if ( !doc->hasSelection( QTextDocument::Standard ) )
2376 cursor->indent();
2377 else
2378 doc->indentSelection( QTextDocument::Standard );
2379 repaintChanged();
2380 drawCursor( TRUE );
2381 setModified();
2382 emit textChanged();
2383}
2384
2385/*! Reimplemented to allow tabbing through links.
2386 If \a n is TRUE the tab moves the focus to the next child; if \a n
2387 is FALSE the tab moves the focus to the previous child.
2388 Returns TRUE if the focus was moved; otherwise returns FALSE.
2389 */
2390
2391bool QTextEdit::focusNextPrevChild( bool n )
2392{
2393 if ( !isReadOnly() || !linksEnabled() )
2394 return FALSE;
2395 bool b = doc->focusNextPrevChild( n );
2396 repaintChanged();
2397 if ( b )
2398 //##### this does not work with tables. The focusIndicator
2399 //should really be a QTextCursor. Fix 3.1
2400 makeParagVisible( doc->focusIndicator.parag );
2401 return b;
2402}
2403
2404/*!
2405 \internal
2406
2407 This functions sets the current format to \a f. Only the fields of \a
2408 f which are specified by the \a flags are used.
2409*/
2410
2411void QTextEdit::setFormat( QTextFormat *f, int flags )
2412{
2413 if ( doc->hasSelection( QTextDocument::Standard ) ) {
2414 drawCursor( FALSE );
2415 QString str = doc->selectedText( QTextDocument::Standard );
2416 QTextCursor c1 = doc->selectionStartCursor( QTextDocument::Standard );
2417 QTextCursor c2 = doc->selectionEndCursor( QTextDocument::Standard );
2418 clearUndoRedo();
2419 undoRedoInfo.type = UndoRedoInfo::Format;
2420 undoRedoInfo.id = c1.parag()->paragId();
2421 undoRedoInfo.index = c1.index();
2422 undoRedoInfo.eid = c2.parag()->paragId();
2423 undoRedoInfo.eindex = c2.index();
2424 undoRedoInfo.d->text = str;
2425 readFormats( c1, c2, 0, undoRedoInfo.d->text );
2426 undoRedoInfo.format = f;
2427 undoRedoInfo.flags = flags;
2428 clearUndoRedo();
2429 doc->setFormat( QTextDocument::Standard, f, flags );
2430 repaintChanged();
2431 formatMore();
2432 drawCursor( TRUE );
2433 setModified();
2434 emit textChanged();
2435 }
2436 if ( currentFormat && currentFormat->key() != f->key() ) {
2437 currentFormat->removeRef();
2438 currentFormat = doc->formatCollection()->format( f );
2439 if ( currentFormat->isMisspelled() ) {
2440 currentFormat->removeRef();
2441 currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
2442 }
2443 emit currentFontChanged( currentFormat->font() );
2444 emit currentColorChanged( currentFormat->color() );
2445 emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
2446 if ( cursor->index() == cursor->parag()->length() - 1 ) {
2447 currentFormat->addRef();
2448 cursor->parag()->string()->setFormat( cursor->index(), currentFormat, TRUE );
2449 if ( cursor->parag()->length() == 1 ) {
2450 cursor->parag()->invalidate( 0 );
2451 cursor->parag()->format();
2452 repaintChanged();
2453 }
2454 }
2455 }
2456}
2457
2458/*! \reimp */
2459
2460void QTextEdit::setPalette( const QPalette &p )
2461{
2462 QScrollView::setPalette( p );
2463 if ( textFormat() == PlainText ) {
2464 QTextFormat *f = doc->formatCollection()->defaultFormat();
2465 f->setColor( colorGroup().text() );
2466 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
2467 }
2468}
2469
2470/*!
2471 Sets the paragraph style of the current paragraph
2472 to \a dm. If \a dm is QStyleSheetItem::DisplayListItem, the
2473 type of the list item is set to \a listStyle.
2474
2475 \sa setAlignment()
2476*/
2477
2478void QTextEdit::setParagType( QStyleSheetItem::DisplayMode dm, QStyleSheetItem::ListStyle listStyle )
2479{
2480 if ( isReadOnly() )
2481 return;
2482
2483 drawCursor( FALSE );
2484 if ( !doc->hasSelection( QTextDocument::Standard ) ) {
2485 clearUndoRedo();
2486 undoRedoInfo.type = UndoRedoInfo::ParagType;
2487 QValueList< QPtrVector<QStyleSheetItem> > oldStyles;
2488 undoRedoInfo.oldStyles.clear();
2489 undoRedoInfo.oldStyles << cursor->parag()->styleSheetItems();
2490 undoRedoInfo.oldListStyles.clear();
2491 undoRedoInfo.oldListStyles << cursor->parag()->listStyle();
2492 undoRedoInfo.list = dm == QStyleSheetItem::DisplayListItem;
2493 undoRedoInfo.listStyle = listStyle;
2494 undoRedoInfo.id = cursor->parag()->paragId();
2495 undoRedoInfo.eid = cursor->parag()->paragId();
2496 undoRedoInfo.d->text = " ";
2497 undoRedoInfo.index = 1;
2498 clearUndoRedo();
2499 cursor->parag()->setList( dm == QStyleSheetItem::DisplayListItem, listStyle );
2500 repaintChanged();
2501 } else {
2502 QTextParag *start = doc->selectionStart( QTextDocument::Standard );
2503 QTextParag *end = doc->selectionEnd( QTextDocument::Standard );
2504 lastFormatted = start;
2505 clearUndoRedo();
2506 undoRedoInfo.type = UndoRedoInfo::ParagType;
2507 undoRedoInfo.id = start->paragId();
2508 undoRedoInfo.eid = end->paragId();
2509 undoRedoInfo.list = dm == QStyleSheetItem::DisplayListItem;
2510 undoRedoInfo.listStyle = listStyle;
2511 undoRedoInfo.oldStyles.clear();
2512 undoRedoInfo.oldListStyles.clear();
2513 while ( start ) {
2514 undoRedoInfo.oldStyles << start->styleSheetItems();
2515 undoRedoInfo.oldListStyles << start->listStyle();
2516 start->setList( dm == QStyleSheetItem::DisplayListItem, listStyle );
2517 if ( start == end )
2518 break;
2519 start = start->next();
2520 }
2521 undoRedoInfo.d->text = " ";
2522 undoRedoInfo.index = 1;
2523 clearUndoRedo();
2524 repaintChanged();
2525 formatMore();
2526 }
2527 drawCursor( TRUE );
2528 setModified();
2529 emit textChanged();
2530}
2531
2532/*!
2533 Sets the alignment of the current paragraph to \a a. Valid alignments
2534 are \c Qt::AlignLeft, \c Qt::AlignRight, Qt::AlignJustify and
2535 Qt::AlignCenter (which centers horizontally).
2536
2537 \sa setParagType()
2538*/
2539
2540void QTextEdit::setAlignment( int a )
2541{
2542 if ( isReadOnly() || block_set_alignment )
2543 return;
2544
2545 drawCursor( FALSE );
2546 if ( !doc->hasSelection( QTextDocument::Standard ) ) {
2547 if ( cursor->parag()->alignment() != a ) {
2548 clearUndoRedo();
2549 undoRedoInfo.type = UndoRedoInfo::Alignment;
2550 QMemArray<int> oa( 1 );
2551 oa[ 0 ] = cursor->parag()->alignment();
2552 undoRedoInfo.oldAligns = oa;
2553 undoRedoInfo.newAlign = a;
2554 undoRedoInfo.id = cursor->parag()->paragId();
2555 undoRedoInfo.eid = cursor->parag()->paragId();
2556 undoRedoInfo.d->text = " ";
2557 undoRedoInfo.index = 1;
2558 clearUndoRedo();
2559 cursor->parag()->setAlignment( a );
2560 repaintChanged();
2561 }
2562 } else {
2563 QTextParag *start = doc->selectionStart( QTextDocument::Standard );
2564 QTextParag *end = doc->selectionEnd( QTextDocument::Standard );
2565 lastFormatted = start;
2566 int len = end->paragId() - start->paragId() + 1;
2567 clearUndoRedo();
2568 undoRedoInfo.type = UndoRedoInfo::Alignment;
2569 undoRedoInfo.id = start->paragId();
2570 undoRedoInfo.eid = end->paragId();
2571 QMemArray<int> oa( QMAX( 0, len ) );
2572 int i = 0;
2573 while ( start ) {
2574 if ( i < (int)oa.size() )
2575 oa[ i ] = start->alignment();
2576 start->setAlignment( a );
2577 if ( start == end )
2578 break;
2579 start = start->next();
2580 ++i;
2581 }
2582 undoRedoInfo.oldAligns = oa;
2583 undoRedoInfo.newAlign = a;
2584 undoRedoInfo.d->text = " ";
2585 undoRedoInfo.index = 1;
2586 clearUndoRedo();
2587 repaintChanged();
2588 formatMore();
2589 }
2590 drawCursor( TRUE );
2591 if ( currentAlignment != a ) {
2592 currentAlignment = a;
2593 emit currentAlignmentChanged( currentAlignment );
2594 }
2595 setModified();
2596 emit textChanged();
2597}
2598
2599void QTextEdit::updateCurrentFormat()
2600{
2601 int i = cursor->index();
2602 if ( i > 0 )
2603 --i;
2604 if ( doc->useFormatCollection() &&
2605 ( !currentFormat || currentFormat->key() != cursor->parag()->at( i )->format()->key() ) ) {
2606 if ( currentFormat )
2607 currentFormat->removeRef();
2608 currentFormat = doc->formatCollection()->format( cursor->parag()->at( i )->format() );
2609 if ( currentFormat->isMisspelled() ) {
2610 currentFormat->removeRef();
2611 currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
2612 }
2613 emit currentFontChanged( currentFormat->font() );
2614 emit currentColorChanged( currentFormat->color() );
2615 emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
2616 }
2617
2618 if ( currentAlignment != cursor->parag()->alignment() ) {
2619 currentAlignment = cursor->parag()->alignment();
2620 block_set_alignment = TRUE;
2621 emit currentAlignmentChanged( currentAlignment );
2622 block_set_alignment = FALSE;
2623 }
2624}
2625
2626/*!
2627 If \a b is TRUE sets the current format to italic; otherwise sets
2628 the current format to non-italic.
2629
2630 \sa italic()
2631*/
2632
2633void QTextEdit::setItalic( bool b )
2634{
2635 QTextFormat f( *currentFormat );
2636 f.setItalic( b );
2637 QTextFormat *f2 = doc->formatCollection()->format( &f );
2638 setFormat( f2, QTextFormat::Italic );
2639}
2640
2641/*!
2642 If \a b is TRUE sets the current format to bold; otherwise sets the
2643 current format to non-bold.
2644
2645 \sa bold()
2646*/
2647
2648void QTextEdit::setBold( bool b )
2649{
2650 QTextFormat f( *currentFormat );
2651 f.setBold( b );
2652 QTextFormat *f2 = doc->formatCollection()->format( &f );
2653 setFormat( f2, QTextFormat::Bold );
2654}
2655
2656/*!
2657 If \a b is TRUE sets the current format to underline; otherwise sets
2658 the current format to non-underline.
2659
2660 \sa underline()
2661*/
2662
2663void QTextEdit::setUnderline( bool b )
2664{
2665 QTextFormat f( *currentFormat );
2666 f.setUnderline( b );
2667 QTextFormat *f2 = doc->formatCollection()->format( &f );
2668 setFormat( f2, QTextFormat::Underline );
2669}
2670
2671/*!
2672 Sets the font family of the current format to \a fontFamily.
2673
2674 \sa family() setCurrentFont()
2675*/
2676
2677void QTextEdit::setFamily( const QString &fontFamily )
2678{
2679 QTextFormat f( *currentFormat );
2680 f.setFamily( fontFamily );
2681 QTextFormat *f2 = doc->formatCollection()->format( &f );
2682 setFormat( f2, QTextFormat::Family );
2683}
2684
2685/*!
2686 Sets the point size of the current format to \a s.
2687
2688 Note that if \a s is zero or negative, the behaviour of this
2689 function is not defined.
2690
2691 \sa pointSize() setCurrentFont() setFamily()
2692*/
2693
2694void QTextEdit::setPointSize( int s )
2695{
2696 QTextFormat f( *currentFormat );
2697 f.setPointSize( s );
2698 QTextFormat *f2 = doc->formatCollection()->format( &f );
2699 setFormat( f2, QTextFormat::Size );
2700}
2701
2702/*!
2703 Sets the color of the current format, i.e. of the text, to \a c.
2704
2705 \sa color() setPaper()
2706*/
2707
2708void QTextEdit::setColor( const QColor &c )
2709{
2710 QTextFormat f( *currentFormat );
2711 f.setColor( c );
2712 QTextFormat *f2 = doc->formatCollection()->format( &f );
2713 setFormat( f2, QTextFormat::Color );
2714}
2715
2716/*!
2717 Sets the vertical alignment of the current format, i.e. of the text, to \a a.
2718
2719 \sa color() setPaper()
2720*/
2721
2722void QTextEdit::setVerticalAlignment( VerticalAlignment a )
2723{
2724 QTextFormat f( *currentFormat );
2725 f.setVAlign( (QTextFormat::VerticalAlignment)a );
2726 QTextFormat *f2 = doc->formatCollection()->format( &f );
2727 setFormat( f2, QTextFormat::VAlign );
2728}
2729
2730void QTextEdit::setFontInternal( const QFont &f_ )
2731{
2732 QTextFormat f( *currentFormat );
2733 f.setFont( f_ );
2734 QTextFormat *f2 = doc->formatCollection()->format( &f );
2735 setFormat( f2, QTextFormat::Font );
2736}
2737
2738
2739QString QTextEdit::text() const
2740{
2741 if ( isReadOnly() )
2742 return doc->originalText();
2743 return doc->text();
2744}
2745
2746/*!
2747 \overload
2748 Returns the text of paragraph \a para.
2749
2750 If textFormat() is \c RichText the text will contain HTML
2751 formatting tags.
2752*/
2753
2754QString QTextEdit::text( int para ) const
2755{
2756 return doc->text( para );
2757}
2758
2759/*!
2760 \overload
2761
2762 Changes the text of the text edit to the string \a text and the
2763 context to \a context. Any previous text is removed.
2764
2765 \a text may be interpreted either as plain text or as rich text,
2766 depending on the textFormat(). The default setting is \c AutoText,
2767 i.e. the text edit autodetects the format from \a text.
2768
2769 The optional \a context is a path which the text edit's
2770 QMimeSourceFactory uses to resolve the locations of files and images.
2771 (See \l{QTextEdit::QTextEdit()}.) It is passed to the text edit's
2772 QMimeSourceFactory when quering data.
2773
2774 Note that the undo/redo history is cleared by this function.
2775
2776 \sa text(), setTextFormat()
2777*/
2778
2779void QTextEdit::setText( const QString &text, const QString &context )
2780{
2781 if ( !isModified() && this->context() == context && this->text() == text )
2782 return;
2783
2784 emit undoAvailable( FALSE );
2785 emit redoAvailable( FALSE );
2786 undoRedoInfo.clear();
2787 doc->commands()->clear();
2788
2789 lastFormatted = 0;
2790 cursor->restoreState();
2791 doc->setText( text, context );
2792
2793 if ( wrapMode == FixedPixelWidth ) {
2794 resizeContents( wrapWidth, 0 );
2795 doc->setWidth( wrapWidth );
2796 doc->setMinimumWidth( wrapWidth );
2797 } else {
2798 doc->setMinimumWidth( -1 );
2799 resizeContents( 0, 0 );
2800 }
2801
2802 cursor->setDocument( doc );
2803 lastFormatted = doc->firstParag();
2804 cursor->setParag( doc->firstParag() );
2805 cursor->setIndex( 0 );
2806 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
2807
2808 if ( isModified() )
2809 setModified( FALSE );
2810 emit textChanged();
2811 formatMore();
2812 updateCurrentFormat();
2813}
2814
2815/*!
2816 \property QTextEdit::text
2817 \brief the text edit's text
2818
2819 There is no default text.
2820
2821 On setting, any previous text is deleted.
2822
2823 The text may be interpreted either as plain text or as rich text,
2824 depending on the textFormat(). The default setting is \c AutoText,
2825 i.e. the text edit autodetects the format of the text.
2826
2827 For richtext, calling text() on an editable QTextEdit will cause the text
2828 to be regenerated from the textedit. This may mean that the QString returned
2829 may not be exactly the same as the one that was set.
2830
2831 \sa textFormat
2832*/
2833
2834
2835/*!
2836 \property QTextEdit::readOnly
2837 \brief whether the text edit is read-only
2838
2839 In a read-only text edit the user can only navigate through the text
2840 and select text; modifying the text is not possible.
2841
2842 This property's default is FALSE.
2843*/
2844
2845/*!
2846 Finds the next occurrence of the string, \a expr. Returns TRUE if
2847 \a expr is found; otherwise returns FALSE.
2848
2849 If \a para and \a index are both null the search begins from the
2850 start of the text. If \a para and \a index are both not null, the
2851 search begins from the \e *\a index character position in the \e
2852 *\a para paragraph.
2853
2854 If \a cs is TRUE the search is case sensitive, otherwise it is
2855 case insensitive. If \a wo is TRUE the search looks for whole word
2856 matches only; otherwise it searches for any matching text. If \a
2857 forward is TRUE (the default) the search works forward from the
2858 starting position to the end of the text, otherwise it works
2859 backwards to the beginning of the text.
2860
2861 If \a expr is found the function returns TRUE. If \a index and \a
2862 para are not null, the number of the paragraph in which the first
2863 character of the match was found is put into \e *\a para, and the
2864 index position of that character within the paragraph is put into
2865 \e *\a index.
2866
2867 If \a expr is not found the function returns FALSE. If \a index
2868 and \a para are not null and \a expr is not found, \e *\a index
2869 and \e *\a para are undefined.
2870*/
2871
2872bool QTextEdit::find( const QString &expr, bool cs, bool wo, bool forward,
2873 int *para, int *index )
2874{
2875 drawCursor( FALSE );
2876 doc->removeSelection( QTextDocument::Standard );
2877#ifndef QT_NO_CURSOR
2878 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
2879#endif
2880 bool found = doc->find( expr, cs, wo, forward, para, index, cursor );
2881 ensureCursorVisible();
2882 drawCursor( TRUE );
2883 repaintChanged();
2884 return found;
2885}
2886
2887void QTextEdit::blinkCursor()
2888{
2889 if ( !cursorVisible )
2890 return;
2891 bool cv = cursorVisible;
2892 blinkCursorVisible = !blinkCursorVisible;
2893 drawCursor( blinkCursorVisible );
2894 cursorVisible = cv;
2895}
2896
2897/*!
2898 Sets the cursor to position \a index in paragraph \a para.
2899
2900 \sa getCursorPosition()
2901*/
2902
2903void QTextEdit::setCursorPosition( int para, int index )
2904{
2905 QTextParag *p = doc->paragAt( para );
2906 if ( !p )
2907 return;
2908
2909 if ( index > p->length() - 1 )
2910 index = p->length() - 1;
2911
2912 drawCursor( FALSE );
2913 cursor->setParag( p );
2914 cursor->setIndex( index );
2915 ensureCursorVisible();
2916 drawCursor( TRUE );
2917 emit cursorPositionChanged( cursor );
2918 emit cursorPositionChanged( cursor->parag()->paragId(), cursor->index() );
2919}
2920
2921/*!
2922 This function sets the \e *\a para and \e *\a index parameters to the
2923 current cursor position. \a para and \a index must be non-null int
2924 pointers.
2925
2926 \sa setCursorPosition()
2927 */
2928
2929void QTextEdit::getCursorPosition( int *para, int *index ) const
2930{
2931 if ( !para || !index )
2932 return;
2933 *para = cursor->parag()->paragId();
2934 *index = cursor->index();
2935}
2936
2937/*! Sets a selection which starts at position \a indexFrom in
2938 paragraph \a paraFrom and ends at position \a indexTo in paragraph
2939 \a paraTo. Existing selections which have a different id (selNum)
2940 are not removed, existing selections which have the same id as \a
2941 selNum are removed.
2942
2943 Uses the selection settings of selection \a selNum. If \a selNum is 0,
2944 this is the default selection.
2945
2946 The cursor is moved to the end of the selection if \a selNum is 0,
2947 otherwise the cursor position remains unchanged.
2948
2949 \sa getSelection() selectedText
2950*/
2951
2952void QTextEdit::setSelection( int paraFrom, int indexFrom,
2953 int paraTo, int indexTo, int selNum )
2954{
2955 if ( doc->hasSelection( selNum ) ) {
2956 doc->removeSelection( selNum );
2957 repaintChanged();
2958 }
2959 if ( selNum > doc->numSelections() - 1 )
2960 doc->addSelection( selNum );
2961 QTextParag *p1 = doc->paragAt( paraFrom );
2962 if ( !p1 )
2963 return;
2964 QTextParag *p2 = doc->paragAt( paraTo );
2965 if ( !p2 )
2966 return;
2967
2968 if ( indexFrom > p1->length() - 1 )
2969 indexFrom = p1->length() - 1;
2970 if ( indexTo > p2->length() - 1 )
2971 indexTo = p2->length() - 1;
2972
2973 drawCursor( FALSE );
2974 QTextCursor c = *cursor;
2975 QTextCursor oldCursor = *cursor;
2976 c.setParag( p1 );
2977 c.setIndex( indexFrom );
2978 cursor->setParag( p2 );
2979 cursor->setIndex( indexTo );
2980 doc->setSelectionStart( selNum, &c );
2981 doc->setSelectionEnd( selNum, cursor );
2982 repaintChanged();
2983 ensureCursorVisible();
2984 if ( selNum != QTextDocument::Standard )
2985 *cursor = oldCursor;
2986 drawCursor( TRUE );
2987}
2988
2989/*!
2990 If there is a selection, \e *\a paraFrom is set to the number of the
2991 paragraph in which the selection begins and \e *\a paraTo is set to
2992 the number of the paragraph in which the selection ends. (They could
2993 be the same.) \e *\a indexFrom is set to the index at which the
2994 selection begins within \e *\a paraFrom, and \e *\a indexTo is set to
2995 the index at which the selection ends within \e *\a paraTo.
2996
2997 If there is no selection, \e *\a paraFrom, \e *\a indexFrom, \e *\a
2998 paraTo and \e *\a indexTo are all set to -1.
2999
3000 \a paraFrom, \a indexFrom, \a paraTo and \a indexTo must be non-null
3001 int pointers.
3002
3003 The \a selNum is the number of the selection (multiple selections
3004 are supported). It defaults to 0 (the default selection).
3005
3006 \sa setSelection() selectedText
3007*/
3008
3009void QTextEdit::getSelection( int *paraFrom, int *indexFrom,
3010 int *paraTo, int *indexTo, int selNum ) const
3011{
3012 if ( !paraFrom || !paraTo || !indexFrom || !indexTo )
3013 return;
3014 if ( !doc->hasSelection( selNum ) ) {
3015 *paraFrom = -1;
3016 *indexFrom = -1;
3017 *paraTo = -1;
3018 *indexTo = -1;
3019 return;
3020 }
3021
3022 doc->selectionStart( selNum, *paraFrom, *indexFrom );
3023 doc->selectionEnd( selNum, *paraTo, *indexTo );
3024}
3025
3026/*!
3027 \property QTextEdit::textFormat
3028 \brief the text format: rich text, plain text or auto text
3029
3030 The text format is one of the following:
3031 \list
3032 \i PlainText - all characters, except newlines, are displayed
3033 verbatim, including spaces. Whenever a newline appears in the text the
3034 text edit inserts a hard line break and begins a new paragraph.
3035 \i RichText - rich text rendering. The available styles are
3036 defined in the default stylesheet QStyleSheet::defaultSheet().
3037 \i AutoText - this is the default. The text edit autodetects
3038 which rendering style is best, \c PlainText or \c RichText. This is
3039 done by using the QStyleSheet::mightBeRichText() function.
3040 \endlist
3041*/
3042
3043void QTextEdit::setTextFormat( TextFormat format )
3044{
3045 doc->setTextFormat( format );
3046}
3047
3048Qt::TextFormat QTextEdit::textFormat() const
3049{
3050 return doc->textFormat();
3051}
3052
3053/*!
3054 Returns the number of paragraphs in the text; this could be 0.
3055*/
3056
3057int QTextEdit::paragraphs() const
3058{
3059 return doc->lastParag()->paragId() + 1;
3060}
3061
3062/*!
3063 Returns the number of lines in paragraph \a para, or -1 if there
3064 is no paragraph with index \a para.
3065*/
3066
3067int QTextEdit::linesOfParagraph( int para ) const
3068{
3069 QTextParag *p = doc->paragAt( para );
3070 if ( !p )
3071 return -1;
3072 return p->lines();
3073}
3074
3075/*!
3076 Returns the length of the paragraph \a para (number of
3077 characters), or -1 if there is no paragraph with index \a para
3078*/
3079
3080int QTextEdit::paragraphLength( int para ) const
3081{
3082 QTextParag *p = doc->paragAt( para );
3083 if ( !p )
3084 return -1;
3085 return p->length() - 1;
3086}
3087
3088/*!
3089 Returns the number of lines in the text edit; this could be 0.
3090
3091 \warning This function may be slow. Lines change all the time
3092 during word wrapping, so this function has to iterate over all the
3093 paragraphs and get the number of lines from each one individually.
3094*/
3095
3096int QTextEdit::lines() const
3097{
3098 QTextParag *p = doc->firstParag();
3099 int l = 0;
3100 while ( p ) {
3101 l += p->lines();
3102 p = p->next();
3103 }
3104
3105 return l;
3106}
3107
3108/*!
3109 Returns the line number of the line in paragraph \a para in which
3110 the character at position \a index appears. The \a index position is
3111 relative to the beginning of the paragraph. If there is no such
3112 paragraph or no such character at the \a index position (e.g. the
3113 index is out of range) -1 is returned.
3114*/
3115
3116int QTextEdit::lineOfChar( int para, int index )
3117{
3118 QTextParag *p = doc->paragAt( para );
3119 if ( !p )
3120 return -1;
3121
3122 int idx, line;
3123 QTextStringChar *c = p->lineStartOfChar( index, &idx, &line );
3124 if ( !c )
3125 return -1;
3126
3127 return line;
3128}
3129
3130void QTextEdit::setModified( bool m )
3131{
3132 bool oldModified = modified;
3133 modified = m;
3134 if ( modified && doc->oTextValid )
3135 doc->invalidateOriginalText();
3136 if ( oldModified != modified )
3137 emit modificationChanged( modified );
3138}
3139
3140/*! \property QTextEdit::modified
3141 \brief whether the document has been modified by the user
3142*/
3143
3144bool QTextEdit::isModified() const
3145{
3146 return modified;
3147}
3148
3149void QTextEdit::setModified()
3150{
3151 if ( !isModified() )
3152 setModified( TRUE );
3153}
3154
3155/*!
3156 Returns TRUE if the current format is italic; otherwise returns FALSE.
3157
3158 \sa setItalic()
3159*/
3160
3161bool QTextEdit::italic() const
3162{
3163 return currentFormat->font().italic();
3164}
3165
3166/*!
3167 Returns TRUE if the current format is bold; otherwise returns FALSE.
3168
3169 \sa setBold()
3170*/
3171
3172bool QTextEdit::bold() const
3173{
3174 return currentFormat->font().bold();
3175}
3176
3177/*!
3178 Returns TRUE if the current format is underlined; otherwise returns
3179 FALSE.
3180
3181 \sa setUnderline()
3182*/
3183
3184bool QTextEdit::underline() const
3185{
3186 return currentFormat->font().underline();
3187}
3188
3189/*!
3190 Returns the font family of the current format.
3191
3192 \sa setFamily() setCurrentFont() setPointSize()
3193*/
3194
3195QString QTextEdit::family() const
3196{
3197 return currentFormat->font().family();
3198}
3199
3200/*!
3201 Returns the point size of the font of the current format.
3202
3203 \sa setFamily() setCurrentFont() setPointSize()
3204
3205*/
3206
3207int QTextEdit::pointSize() const
3208{
3209 return currentFormat->font().pointSize();
3210}
3211
3212/*!
3213 Returns the color of the current format.
3214
3215 \sa setColor() setPaper()
3216*/
3217
3218QColor QTextEdit::color() const
3219{
3220 return currentFormat->color();
3221}
3222
3223/*!
3224 Returns the font of the current format.
3225
3226 \sa setCurrentFont() setFamily() setPointSize()
3227
3228*/
3229
3230QFont QTextEdit::font() const
3231{
3232 return currentFormat->font();
3233}
3234
3235/*!
3236 Returns the alignment of the current paragraph.
3237
3238 \sa setAlignment()
3239*/
3240
3241int QTextEdit::alignment() const
3242{
3243 return currentAlignment;
3244}
3245
3246void QTextEdit::startDrag()
3247{
3248#ifndef QT_NO_DRAGANDDROP
3249 mousePressed = FALSE;
3250 inDoubleClick = FALSE;
3251 QDragObject *drag = new QTextDrag( doc->selectedText( QTextDocument::Standard ), viewport() );
3252 if ( isReadOnly() ) {
3253 drag->dragCopy();
3254 } else {
3255 if ( drag->drag() && QDragObject::target() != this && QDragObject::target() != viewport() )
3256 removeSelectedText();
3257 }
3258#endif
3259}
3260
3261/*!
3262 If \a select is TRUE (the default), all the text is selected as
3263 selection 0.
3264 If \a select is FALSE any selected text is unselected, i.e., the
3265 default selection (selection 0) is cleared.
3266
3267 \sa selectedText
3268*/
3269
3270void QTextEdit::selectAll( bool select )
3271{
3272 if ( !select )
3273 doc->removeSelection( QTextDocument::Standard );
3274 else
3275 doc->selectAll( QTextDocument::Standard );
3276 repaintChanged();
3277 emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
3278 emit selectionChanged();
3279#ifndef QT_NO_CURSOR
3280 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
3281#endif
3282}
3283
3284void QTextEdit::UndoRedoInfo::clear()
3285{
3286 if ( valid() ) {
3287 if ( type == Insert || type == Return )
3288 doc->addCommand( new QTextInsertCommand( doc, id, index, d->text.rawData(), oldStyles, oldListStyles, oldAligns ) );
3289 else if ( type == Format )
3290 doc->addCommand( new QTextFormatCommand( doc, id, index, eid, eindex, d->text.rawData(), format, flags ) );
3291 else if ( type == Alignment )
3292 doc->addCommand( new QTextAlignmentCommand( doc, id, eid, newAlign, oldAligns ) );
3293 else if ( type == ParagType )
3294 doc->addCommand( new QTextParagTypeCommand( doc, id, eid, list, listStyle, oldStyles, oldListStyles ) );
3295 else if ( type != Invalid )
3296 doc->addCommand( new QTextDeleteCommand( doc, id, index, d->text.rawData(), oldStyles, oldListStyles, oldAligns ) );
3297 }
3298 d->text = QString::null;
3299 id = -1;
3300 index = -1;
3301 oldStyles.clear();
3302 oldListStyles.clear();
3303 oldAligns.resize( 0 );
3304}
3305
3306
3307/*!
3308 If there is some selected text (in selection 0) it is deleted. If
3309 there is no selected text (in selection 0) the character to the
3310 right of the text cursor is deleted.
3311
3312 \sa removeSelectedText() cut()
3313
3314*/
3315
3316void QTextEdit::del()
3317{
3318 if ( doc->hasSelection( QTextDocument::Standard ) ) {
3319 removeSelectedText();
3320 return;
3321 }
3322
3323 doKeyboardAction( ActionDelete );
3324}
3325
3326
3327QTextEdit::UndoRedoInfo::UndoRedoInfo( QTextDocument *dc )
3328 : type( Invalid ), doc( dc )
3329{
3330 d = new QUndoRedoInfoPrivate;
3331 d->text = QString::null;
3332 id = -1;
3333 index = -1;
3334}
3335
3336QTextEdit::UndoRedoInfo::~UndoRedoInfo()
3337{
3338 delete d;
3339}
3340
3341bool QTextEdit::UndoRedoInfo::valid() const
3342{
3343 return d->text.length() > 0 && id >= 0 && index >= 0;
3344}
3345
3346/*!
3347 \internal
3348
3349 Resets the current format to the default format.
3350*/
3351
3352void QTextEdit::resetFormat()
3353{
3354 setAlignment( Qt3::AlignAuto );
3355 setParagType( QStyleSheetItem::DisplayBlock, QStyleSheetItem::ListDisc );
3356 setFormat( doc->formatCollection()->defaultFormat(), QTextFormat::Format );
3357}
3358
3359/*! Returns the QStyleSheet which is currently used in this text edit.
3360
3361 \sa setStyleSheet()
3362 */
3363
3364QStyleSheet* QTextEdit::styleSheet() const
3365{
3366 return doc->styleSheet();
3367}
3368
3369/*! Sets the stylesheet to use with this text edit to \a styleSheet. Changes
3370 will only take effect for new text added with setText() or append().
3371
3372 \sa styleSheet()
3373 */
3374
3375void QTextEdit::setStyleSheet( QStyleSheet* styleSheet )
3376{
3377 doc->setStyleSheet( styleSheet );
3378}
3379
3380/*!
3381 \property QTextEdit::paper
3382 \brief the background (paper) brush.
3383
3384 The brush that is currently used to draw the background of the
3385 text edit. The initial setting is an empty brush.
3386 */
3387
3388void QTextEdit::setPaper( const QBrush& pap )
3389{
3390 doc->setPaper( new QBrush( pap ) );
3391 viewport()->setBackgroundColor( pap.color() );
3392 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
3393}
3394
3395QBrush QTextEdit::paper() const
3396{
3397 if ( doc->paper() )
3398 return *doc->paper();
3399 return QBrush();
3400}
3401
3402/*!
3403 \property QTextEdit::linkUnderline
3404 \brief whether hypertext links will be underlined
3405
3406 If TRUE (the default) hypertext links will be displayed underlined.
3407 If FALSE links will not be displayed underlined.
3408*/
3409
3410void QTextEdit::setLinkUnderline( bool b )
3411{
3412 if ( b == doc->underlineLinks() )
3413 return;
3414 doc->setUnderlineLinks( b );
3415 updateStyles();
3416}
3417
3418bool QTextEdit::linkUnderline() const
3419{
3420 return doc->underlineLinks();
3421}
3422
3423/*! Sets the text edit's mimesource factory to \a factory. See
3424 QMimeSourceFactory for further details.
3425
3426 \sa mimeSourceFactory()
3427 */
3428
3429void QTextEdit::setMimeSourceFactory( QMimeSourceFactory* factory )
3430{
3431 doc->setMimeSourceFactory( factory );
3432}
3433
3434/*! Returns the QMimeSourceFactory which is currently used by this
3435 text edit.
3436
3437 \sa setMimeSourceFactory()
3438*/
3439
3440QMimeSourceFactory* QTextEdit::mimeSourceFactory() const
3441{
3442 return doc->mimeSourceFactory();
3443}
3444
3445/*!
3446 Returns how many pixels high the text edit needs to be to display
3447 all the text if the text edit is \a w pixels wide.
3448*/
3449
3450int QTextEdit::heightForWidth( int w ) const
3451{
3452 int oldw = doc->width();
3453 doc->doLayout( 0, w );
3454 int h = doc->height();
3455 doc->setWidth( oldw );
3456 doc->invalidate();
3457 ( (QTextEdit*)this )->formatMore();
3458 return h;
3459}
3460
3461/*! Appends the text \a text to the end of the text edit.
3462 Note that the undo/redo history is cleared by this function.
3463 */
3464
3465void QTextEdit::append( const QString &text )
3466{
3467 // flush and clear the undo/redo stack if necessary
3468 if ( isReadOnly() && undoRedoInfo.valid() ) {
3469 undoRedoInfo.clear();
3470 doc->commands()->clear();
3471 }
3472 doc->removeSelection( QTextDocument::Standard );
3473 TextFormat f = doc->textFormat();
3474 if ( f == AutoText ) {
3475 if ( QStyleSheet::mightBeRichText( text ) )
3476 f = RichText;
3477 else
3478 f = PlainText;
3479 }
3480 if ( f == PlainText ) {
3481 QTextCursor oldc( *cursor );
3482 ensureFormatted( doc->lastParag() );
3483 bool scrollToEnd = contentsY() >= contentsHeight() - visibleHeight() -
3484 ( horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0 );
3485 if ( !scrollToEnd )
3486 blockEnsureCursorVisible = TRUE;
3487 cursor->gotoEnd();
3488 if ( cursor->index() > 0 )
3489 cursor->splitAndInsertEmptyParag();
3490 QTextCursor oldCursor2 = *cursor;
3491 cursor->insert( text, TRUE );
3492 if ( doc->useFormatCollection() && currentFormat != cursor->parag()->at( cursor->index() )->format() ) {
3493 doc->setSelectionStart( QTextDocument::Temp, &oldCursor2 );
3494 doc->setSelectionEnd( QTextDocument::Temp, cursor );
3495 doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
3496 doc->removeSelection( QTextDocument::Temp );
3497 }
3498 formatMore();
3499 repaintChanged();
3500 ensureCursorVisible();
3501 drawCursor( TRUE );
3502 *cursor = oldc;
3503 if ( !scrollToEnd )
3504 blockEnsureCursorVisible = FALSE;
3505 } else if ( f == RichText ) {
3506 doc->setRichTextInternal( text );
3507 repaintChanged();
3508 }
3509 setModified();
3510 emit textChanged();
3511}
3512
3513/*! \property QTextEdit::hasSelectedText
3514 \brief whether some text is selected in selection 0
3515 */
3516
3517bool QTextEdit::hasSelectedText() const
3518{
3519 return doc->hasSelection( QTextDocument::Standard );
3520}
3521
3522/*!\property QTextEdit::selectedText
3523 \brief The selected text (from selection 0) or an empty string if
3524 there is no currently selected text (in selection 0).
3525
3526 The text is always returned as \c PlainText regardless of the text
3527 format. In a future version of Qt an HTML subset \e may be returned
3528 depending on the text format.
3529
3530 \sa hasSelectedText
3531 */
3532
3533QString QTextEdit::selectedText() const
3534{
3535 return doc->selectedText( QTextDocument::Standard );
3536}
3537
3538bool QTextEdit::handleReadOnlyKeyEvent( QKeyEvent *e )
3539{
3540 switch( e->key() ) {
3541 case Key_Down:
3542 setContentsPos( contentsX(), contentsY() + 10 );
3543 break;
3544 case Key_Up:
3545 setContentsPos( contentsX(), contentsY() - 10 );
3546 break;
3547 case Key_Left:
3548 setContentsPos( contentsX() - 10, contentsY() );
3549 break;
3550 case Key_Right:
3551 setContentsPos( contentsX() + 10, contentsY() );
3552 break;
3553 case Key_PageUp:
3554 setContentsPos( contentsX(), contentsY() - visibleHeight() );
3555 break;
3556 case Key_PageDown:
3557 setContentsPos( contentsX(), contentsY() + visibleHeight() );
3558 break;
3559 case Key_Home:
3560 setContentsPos( contentsX(), 0 );
3561 break;
3562 case Key_End:
3563 setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
3564 break;
3565 case Key_F16: // Copy key on Sun keyboards
3566 copy();
3567 break;
3568#ifndef QT_NO_NETWORKPROTOCOL
3569 case Key_Return:
3570 case Key_Enter:
3571 case Key_Space: {
3572 if ( !doc->focusIndicator.href.isEmpty() ) {
3573 QUrl u( doc->context(), doc->focusIndicator.href, TRUE );
3574 emitLinkClicked( u.toString( FALSE, FALSE ) );
3575#ifndef QT_NO_CURSOR
3576 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
3577#endif
3578 }
3579 } break;
3580#endif
3581 default:
3582 if ( e->state() & ControlButton ) {
3583 switch ( e->key() ) {
3584 case Key_C: case Key_F16: // Copy key on Sun keyboards
3585 copy();
3586 break;
3587 }
3588 }
3589 return FALSE;
3590 }
3591 return TRUE;
3592}
3593
3594/*! Returns the context of the edit.
3595 The context is a path which the text edit's QMimeSourceFactory
3596 uses to resolve the locations of files and images.
3597
3598 \sa text
3599*/
3600
3601QString QTextEdit::context() const
3602{
3603 return doc->context();
3604}
3605
3606/*!
3607 \property QTextEdit::documentTitle
3608 \brief the title of the document parsed from the text.
3609
3610 For \c PlainText the title will be an empty string. For \c RichText
3611 the title will be the text between the \c{<title>} tags, if present,
3612 otherwise an empty string.
3613*/
3614
3615QString QTextEdit::documentTitle() const
3616{
3617 return doc->attributes()[ "title" ];
3618}
3619
3620void QTextEdit::makeParagVisible( QTextParag *p )
3621{
3622 setContentsPos( contentsX(), QMIN( p->rect().y(), contentsHeight() - visibleHeight() ) );
3623}
3624
3625/*! Scrolls the text edit to make the text at the anchor called \a name
3626 visible, if it can be found in the document. If the anchor isn't found
3627 no scrolling will occur. An anchor is defined using the HTML anchor
3628 tag, e.g. \c{<a name="target">}.
3629*/
3630
3631void QTextEdit::scrollToAnchor( const QString& name )
3632{
3633 if ( name.isEmpty() )
3634 return;
3635 sync();
3636 QTextCursor cursor( doc );
3637 QTextParag* last = doc->lastParag();
3638 do {
3639 QTextStringChar* c = cursor.parag()->at( cursor.index() );
3640 if( c->isAnchor() ) {
3641 QString a = c->anchorName();
3642 if ( a == name ||
3643 (a.contains( '#' ) && QStringList::split( '#', a ).contains( name ) ) ) {
3644 setContentsPos( contentsX(), QMIN( cursor.parag()->rect().top() + cursor.totalOffsetY(), contentsHeight() - visibleHeight() ) );
3645 return;
3646 }
3647 }
3648 cursor.gotoNextLetter();
3649 } while( cursor.parag() != last || !cursor.atParagEnd() );
3650}
3651
3652/*! If there is an anchor at position \a pos (in contents
3653 coordinates), its name is returned, otherwise an empty string is
3654 returned.
3655*/
3656
3657QString QTextEdit::anchorAt( const QPoint& pos )
3658{
3659 QTextCursor c( doc );
3660 placeCursor( pos, &c );
3661 return c.parag()->at( c.index() )->anchorHref();
3662}
3663
3664void QTextEdit::documentWidthChanged( int w )
3665{
3666 resizeContents( QMAX( visibleWidth(), w), contentsHeight() );
3667}
3668
3669/*!
3670 Updates all the rendering styles used to display the text. You will
3671 probably want to call this function after calling setStyleSheet().
3672*/
3673
3674void QTextEdit::updateStyles()
3675{
3676 doc->updateStyles();
3677 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
3678}
3679
3680void QTextEdit::setDocument( QTextDocument *dc )
3681{
3682 if ( dc == doc )
3683 return;
3684 doc = dc;
3685 cursor->setDocument( doc );
3686 clearUndoRedo();
3687 lastFormatted = 0;
3688}
3689
3690#ifndef QT_NO_CLIPBOARD
3691
3692/*!
3693 Pastes the text with format \a subtype from the clipboard into the
3694 text edit at the current cursor position. The \a subtype can be
3695 "plain" or "html".
3696
3697 If there is no text with format \a subtype in the clipboard nothing
3698 happens.
3699
3700 \sa paste() cut() QTextEdit::copy()
3701*/
3702void QTextEdit::pasteSubType( const QCString& subtype )
3703{
3704 QCString st = subtype;
3705 QString t = QApplication::clipboard()->text(st);
3706 if ( !t.isEmpty() ) {
3707#if defined(Q_OS_WIN32)
3708 // Need to convert CRLF to LF
3709 int index = t.find( QString::fromLatin1("\r\n"), 0 );
3710 while ( index != -1 ) {
3711 t.replace( index, 2, QChar('\n') );
3712 index = t.find( "\r\n", index );
3713 }
3714#elif defined(Q_OS_MAC)
3715 //need to convert CR to LF
3716 for( unsigned int index = 0; index < t.length(); index++ )
3717 if(t[index] == '\r')
3718 t[index] = '\n';
3719#endif
3720 for ( int i=0; (uint) i<t.length(); i++ ) {
3721 if ( t[ i ] < ' ' && t[ i ] != '\n' && t[ i ] != '\t' )
3722 t[ i ] = ' ';
3723 }
3724 if ( !t.isEmpty() )
3725 insert( t, FALSE, TRUE, TRUE );
3726 }
3727}
3728
3729#ifndef QT_NO_MIMECLIPBOARD
3730/*!
3731 Prompts the user to choose a type from a list of text types available,
3732 then copies text from the clipboard (if there is any) into the text
3733 edit at the current text cursor position. Any selected text (in
3734 selection 0) is first deleted.
3735*/
3736void QTextEdit::pasteSpecial( const QPoint& pt )
3737{
3738 QCString st = pickSpecial( QApplication::clipboard()->data(), TRUE, pt );
3739 if ( !st.isEmpty() )
3740 pasteSubType( st );
3741}
3742#endif
3743#ifndef QT_NO_MIME
3744QCString QTextEdit::pickSpecial( QMimeSource* ms, bool always_ask, const QPoint& pt )
3745{
3746 if ( ms ) {
3747#ifndef QT_NO_POPUPMENU
3748 QPopupMenu popup( this, "qt_pickspecial_menu" );
3749 QString fmt;
3750 int n = 0;
3751 QDict<void> done;
3752 for (int i = 0; !( fmt = ms->format( i ) ).isNull(); i++) {
3753 int semi = fmt.find( ";" );
3754 if ( semi >= 0 )
3755 fmt = fmt.left( semi );
3756 if ( fmt.left( 5 ) == "text/" ) {
3757 fmt = fmt.mid( 5 );
3758 if ( !done.find( fmt ) ) {
3759 done.insert( fmt,(void*)1 );
3760 popup.insertItem( fmt, i );
3761 n++;
3762 }
3763 }
3764 }
3765 if ( n ) {
3766 int i = n ==1 && !always_ask ? popup.idAt( 0 ) : popup.exec( pt );
3767 if ( i >= 0 )
3768 return popup.text(i).latin1();
3769 }
3770#else
3771 QString fmt;
3772 for (int i = 0; !( fmt = ms->format( i ) ).isNull(); i++) {
3773 int semi = fmt.find( ";" );
3774 if ( semi >= 0 )
3775 fmt = fmt.left( semi );
3776 if ( fmt.left( 5 ) == "text/" ) {
3777 fmt = fmt.mid( 5 );
3778 return fmt.latin1();
3779 }
3780 }
3781#endif
3782 }
3783 return QCString();
3784}
3785#endif // QT_NO_MIME
3786#endif // QT_NO_CLIPBOARD
3787
3788/*! \enum QTextEdit::WordWrap
3789
3790 This enum defines the QTextEdit's word wrap modes. The following
3791 values are valid:
3792
3793 \value NoWrap Do not wrap the text.
3794
3795 \value WidgetWidth Wrap the text at the current width of the
3796 widget (this is the default). Wrapping is at whitespace by default;
3797 this can be changed with setWrapPolicy().
3798
3799 \value FixedPixelWidth Wrap the text at a fixed number of pixels from
3800 the widget's left side. The number of pixels is set with
3801 wrapColumnOrWidth().
3802
3803 \value FixedColumnWidth Wrap the text at a fixed number of character
3804 columns from the widget's left side. The number of characters is set
3805 with wrapColumnOrWidth().
3806 This is useful if you need formatted text that can also be
3807 displayed gracefully on devices with monospaced fonts, for example a
3808 standard VT100 terminal, where you might set wrapColumnOrWidth() to
3809 80.
3810
3811 \sa setWordWrap() wordWrap()
3812*/
3813
3814/*!
3815 \property QTextEdit::wordWrap
3816 \brief the word wrap mode
3817
3818 The default mode is \c WidgetWidth which causes words to be wrapped
3819 at the right edge of the text edit. Wrapping occurs at whitespace,
3820 keeping whole words intact. If you want wrapping to occur within
3821 words use setWrapPolicy(). If you set a wrap mode of \c
3822 FixedPixelWidth or \c FixedColumnWidth you should also call
3823 setWrapColumnOrWidth() with the width you want.
3824
3825 \sa WordWrap, wrapColumnOrWidth, wrapPolicy,
3826*/
3827
3828void QTextEdit::setWordWrap( WordWrap mode )
3829{
3830 if ( wrapMode == mode )
3831 return;
3832 wrapMode = mode;
3833 switch ( mode ) {
3834 case NoWrap:
3835 document()->formatter()->setWrapEnabled( FALSE );
3836 document()->formatter()->setWrapAtColumn( -1 );
3837 doc->setWidth( visibleWidth() );
3838 doc->setMinimumWidth( -1 );
3839 doc->invalidate();
3840 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
3841 lastFormatted = doc->firstParag();
3842 interval = 0;
3843 formatMore();
3844 break;
3845 case WidgetWidth:
3846 document()->formatter()->setWrapEnabled( TRUE );
3847 document()->formatter()->setWrapAtColumn( -1 );
3848 doResize();
3849 break;
3850 case FixedPixelWidth:
3851 document()->formatter()->setWrapEnabled( TRUE );
3852 document()->formatter()->setWrapAtColumn( -1 );
3853 if ( wrapWidth < 0 )
3854 wrapWidth = 200;
3855 setWrapColumnOrWidth( wrapWidth );
3856 break;
3857 case FixedColumnWidth:
3858 if ( wrapWidth < 0 )
3859 wrapWidth = 80;
3860 document()->formatter()->setWrapEnabled( TRUE );
3861 document()->formatter()->setWrapAtColumn( wrapWidth );
3862 setWrapColumnOrWidth( wrapWidth );
3863 break;
3864 }
3865}
3866
3867QTextEdit::WordWrap QTextEdit::wordWrap() const
3868{
3869 return wrapMode;
3870}
3871
3872/*!
3873 \property QTextEdit::wrapColumnOrWidth
3874 \brief the position (in pixels or columns depending on the wrap mode) where text will be wrapped
3875
3876 If the wrap mode is \c FixedPixelWidth, the value is the number
3877 of pixels from the left edge of the text edit at which text should
3878 be wrapped. If the wrap mode is \c FixedColumnWidth, the value is
3879 the column number (in character columns) from the left edge of the
3880 text edit at which text should be wrapped.
3881
3882 \sa wordWrap
3883 */
3884void QTextEdit::setWrapColumnOrWidth( int value )
3885{
3886 wrapWidth = value;
3887 if ( wrapMode == FixedColumnWidth ) {
3888 document()->formatter()->setWrapAtColumn( wrapWidth );
3889 resizeContents( 0, 0 );
3890 doc->setWidth( visibleWidth() );
3891 doc->setMinimumWidth( -1 );
3892 } else if (wrapMode == FixedPixelWidth ) {
3893 document()->formatter()->setWrapAtColumn( -1 );
3894 resizeContents( wrapWidth, 0 );
3895 doc->setWidth( wrapWidth );
3896 doc->setMinimumWidth( wrapWidth );
3897 } else {
3898 return;
3899 }
3900 doc->invalidate();
3901 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
3902 lastFormatted = doc->firstParag();
3903 interval = 0;
3904 formatMore();
3905}
3906
3907int QTextEdit::wrapColumnOrWidth() const
3908{
3909 if ( wrapMode == WidgetWidth )
3910 return visibleWidth();
3911 return wrapWidth;
3912}
3913
3914
3915/*! \enum QTextEdit::WrapPolicy
3916
3917 This enum defines where text can be wrapped in word wrap mode.
3918
3919 The following values are valid:
3920 \value AtWhiteSpace Break lines at whitespace, e.g. spaces or
3921 newlines.
3922 \value Anywhere Break anywhere, including within words.
3923 \value AtWordBoundary Don't use this deprecated value (it is a
3924 synonym for AtWhiteSpace which you should use instead).
3925
3926 \sa setWrapPolicy()
3927*/
3928
3929/*!
3930 \property QTextEdit::wrapPolicy
3931 \brief the word wrap policy, at whitespace or anywhere
3932
3933 Defines where text can be wrapped when word wrap mode is not
3934 \c NoWrap. The choices are \c AtWhiteSpace (the default) and \c
3935 Anywhere.
3936
3937 \sa wordWrap
3938 */
3939
3940void QTextEdit::setWrapPolicy( WrapPolicy policy )
3941{
3942 if ( wPolicy == policy )
3943 return;
3944 wPolicy = policy;
3945 QTextFormatter *formatter;
3946 if ( policy == AtWhiteSpace )
3947 formatter = new QTextFormatterBreakWords;
3948 else
3949 formatter = new QTextFormatterBreakInWords;
3950 formatter->setWrapAtColumn( document()->formatter()->wrapAtColumn() );
3951 formatter->setWrapEnabled( document()->formatter()->isWrapEnabled( 0 ) );
3952 document()->setFormatter( formatter );
3953 doc->invalidate();
3954 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
3955 lastFormatted = doc->firstParag();
3956 interval = 0;
3957 formatMore();
3958}
3959
3960QTextEdit::WrapPolicy QTextEdit::wrapPolicy() const
3961{
3962 return wPolicy;
3963}
3964
3965/*!
3966 Deletes all the text in the text edit.
3967
3968 \sa cut() removeSelectedText() setText()
3969
3970*/
3971
3972void QTextEdit::clear()
3973{
3974 // make clear undoable
3975 doc->selectAll( QTextDocument::Temp );
3976 removeSelectedText( QTextDocument::Temp );
3977
3978 setContentsPos( 0, 0 );
3979 if ( cursor->isValid() )
3980 cursor->restoreState();
3981 doc->clear( TRUE );
3982 cursor->setDocument( doc );
3983 cursor->setParag( doc->firstParag() );
3984 cursor->setIndex( 0 );
3985 lastFormatted = 0;
3986 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
3987
3988 emit cursorPositionChanged( cursor );
3989 emit cursorPositionChanged( cursor->parag()->paragId(), cursor->index() );
3990}
3991
3992int QTextEdit::undoDepth() const
3993{
3994 return document()->undoDepth();
3995}
3996
3997/*!
3998 \property QTextEdit::length
3999 \brief the number of characters in the text
4000
4001*/
4002
4003int QTextEdit::length() const
4004{
4005 return document()->length();
4006}
4007
4008/*!
4009 \property QTextEdit::tabStopWidth
4010 \brief the tab stop width in pixels
4011
4012*/
4013
4014int QTextEdit::tabStopWidth() const
4015{
4016 return document()->tabStopWidth();
4017}
4018
4019void QTextEdit::setUndoDepth( int d )
4020{
4021 document()->setUndoDepth( d );
4022}
4023
4024void QTextEdit::setTabStopWidth( int ts )
4025{
4026 document()->setTabStops( ts );
4027 doc->invalidate();
4028 lastFormatted = doc->firstParag();
4029 interval = 0;
4030 formatMore();
4031 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
4032}
4033
4034/*! \reimp */
4035
4036QSize QTextEdit::sizeHint() const
4037{
4038 // ### calculate a reasonable one
4039 return QSize( 100, 100 );
4040}
4041
4042void QTextEdit::clearUndoRedo()
4043{
4044 undoRedoInfo.clear();
4045 emit undoAvailable( doc->commands()->isUndoAvailable() );
4046 emit redoAvailable( doc->commands()->isRedoAvailable() );
4047}
4048
4049/*! This function gets the format of the character at position \a
4050 index in paragraph \a para. Sets \a font to the character's font, \a
4051 color to the character's color and \a verticalAlignment to the
4052 character's vertical alignment.
4053
4054 Returns FALSE if \a para or \a index is out of range otherwise
4055 returns TRUE.
4056*/
4057
4058bool QTextEdit::getFormat( int para, int index, QFont *font, QColor *color, VerticalAlignment *verticalAlignment )
4059{
4060 if ( !font || !color )
4061 return FALSE;
4062 QTextParag *p = doc->paragAt( para );
4063 if ( !p )
4064 return FALSE;
4065 if ( index < 0 || index >= p->length() )
4066 return FALSE;
4067 *font = p->at( index )->format()->font();
4068 *color = p->at( index )->format()->color();
4069 *verticalAlignment = (VerticalAlignment)p->at( index )->format()->vAlign();
4070 return TRUE;
4071}
4072
4073/*! This function gets the format of the paragraph \a para. Sets \a
4074 font to the paragraphs's font, \a color to the paragraph's color, \a
4075 verticalAlignment to the paragraph's vertical alignment, \a
4076 alignment to the paragraph's alignment, \a displayMode to the
4077 paragraph's display mode, \a listStyle to the paragraph's list style
4078 (if the display mode is QStyleSheetItem::DisplayListItem) and \a
4079 listDepth to the depth of the list (if the display mode is
4080 QStyleSheetItem::DisplayListItem).
4081
4082 Returns FALSE if \a para is out of range otherwise returns TRUE.
4083*/
4084
4085bool QTextEdit::getParagraphFormat( int para, QFont *font, QColor *color,
4086 VerticalAlignment *verticalAlignment, int *alignment,
4087 QStyleSheetItem::DisplayMode *displayMode,
4088 QStyleSheetItem::ListStyle *listStyle,
4089 int *listDepth )
4090{
4091 if ( !font || !color || !alignment || !displayMode || !listStyle )
4092 return FALSE;
4093 QTextParag *p = doc->paragAt( para );
4094 if ( !p )
4095 return FALSE;
4096 *font = p->paragFormat()->font();
4097 *color = p->paragFormat()->color();
4098 *verticalAlignment = (VerticalAlignment)p->paragFormat()->vAlign();
4099 *alignment = p->alignment();
4100 *displayMode = p->style() ? p->style()->displayMode() : QStyleSheetItem::DisplayBlock;
4101 *listStyle = p->listStyle();
4102 *listDepth = p->listDepth();
4103 return TRUE;
4104}
4105
4106
4107
4108/*!
4109
4110 This function is called to create a right mouse button popup menu
4111 at the document position \a pos. If you want to create a custom
4112 popup menu, reimplement this function and return the created
4113 popup menu. Ownership of the popup menu is transferred to the
4114 caller.
4115*/
4116
4117QPopupMenu *QTextEdit::createPopupMenu( const QPoint& pos )
4118{
4119#ifndef QT_NO_POPUPMENU
4120 QPopupMenu *popup = new QPopupMenu( this, "qt_edit_menu" );
4121 if ( !isReadOnly() ) {
4122 d->id[ IdUndo ] = popup->insertItem( tr( "&Undo" ) + ACCEL_KEY( Z ) );
4123 d->id[ IdRedo ] = popup->insertItem( tr( "&Redo" ) + ACCEL_KEY( Y ) );
4124 popup->insertSeparator();
4125 }
4126#ifndef QT_NO_CLIPBOARD
4127 if ( !isReadOnly() )
4128 d->id[ IdCut ] = popup->insertItem( tr( "Cu&t" ) + ACCEL_KEY( X ) );
4129 d->id[ IdCopy ] = popup->insertItem( tr( "&Copy" ) + ACCEL_KEY( C ) );
4130 if ( !isReadOnly() )
4131 d->id[ IdPaste ] = popup->insertItem( tr( "&Paste" ) + ACCEL_KEY( V ) );
4132#endif
4133 if ( !isReadOnly() ) {
4134 d->id[ IdClear ] = popup->insertItem( tr( "Clear" ) );
4135 popup->insertSeparator();
4136 }
4137#if defined(Q_WS_X11)
4138 d->id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) );
4139#else
4140 d->id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) + ACCEL_KEY( A ) );
4141#endif
4142 popup->setItemEnabled( d->id[ IdUndo ], !isReadOnly() && doc->commands()->isUndoAvailable() );
4143 popup->setItemEnabled( d->id[ IdRedo ], !isReadOnly() && doc->commands()->isRedoAvailable() );
4144#ifndef QT_NO_CLIPBOARD
4145 popup->setItemEnabled( d->id[ IdCut ], !isReadOnly() && doc->hasSelection( QTextDocument::Standard, TRUE ) );
4146 popup->setItemEnabled( d->id[ IdCopy ], doc->hasSelection( QTextDocument::Standard, TRUE ) );
4147 popup->setItemEnabled( d->id[ IdPaste ], !isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
4148#endif
4149 popup->setItemEnabled( d->id[ IdClear ], !isReadOnly() && !text().isEmpty() );
4150 popup->setItemEnabled( d->id[ IdSelectAll ], (bool)text().length() );
4151 return popup;
4152#else
4153 return 0;
4154#endif
4155}
4156
4157/*! \overload
4158 This function is called to create a right mouse button popup menu.
4159 If you want to create a custom popup menu, reimplement this function
4160 and return the created popup menu. Ownership of the popup menu is
4161 transferred to the caller.
4162*/
4163
4164QPopupMenu *QTextEdit::createPopupMenu()
4165{
4166 return 0;
4167}
4168
4169/*! \reimp */
4170
4171void QTextEdit::setFont( const QFont &f )
4172{
4173 QFont old( QScrollView::font() );
4174 QScrollView::setFont( f );
4175 doc->setMinimumWidth( -1 );
4176
4177 // ### that is a bit hacky
4178 static short diff = 1;
4179 diff *= -1;
4180 doc->setWidth( visibleWidth() + diff );
4181
4182 int s = f.pointSize();
4183 bool usePixels = FALSE;
4184 if ( s == -1 ) {
4185 s = f.pixelSize();
4186 usePixels = TRUE;
4187 }
4188 doc->updateFontSizes( s, usePixels );
4189 doc->updateFontAttributes( f, old );
4190 lastFormatted = doc->firstParag();
4191 formatMore();
4192 repaintChanged();
4193}
4194
4195/*! \fn QTextEdit::zoomIn()
4196
4197 \overload
4198
4199 Zooms in on the text by by making the base font size one
4200 point larger and recalculating all font sizes. This does not change
4201 the size of any images.
4202
4203 \sa zoomOut()
4204
4205*/
4206
4207/*! \fn QTextEdit::zoomOut()
4208
4209 \overload
4210
4211 Zooms out on the text by by making the base font size one
4212 point smaller and recalculating all font sizes. This does not change
4213 the size of any images.
4214
4215 \sa zoomIn()
4216*/
4217
4218
4219/*!
4220 Zooms in on the text by by making the base font size \a range
4221 points larger and recalculating all font sizes. This does not change
4222 the size of any images.
4223
4224 \sa zoomOut()
4225*/
4226
4227void QTextEdit::zoomIn( int range )
4228{
4229 QFont f( QScrollView::font() );
4230 f.setPointSize( f.pointSize() + range );
4231 setFont( f );
4232}
4233
4234/*! Zooms out on the text by making the base font size \a range
4235 points smaller and recalculating all font sizes. This does not
4236 change the size of any images.
4237
4238 \sa zoomIn()
4239*/
4240
4241void QTextEdit::zoomOut( int range )
4242{
4243 QFont f( QScrollView::font() );
4244 f.setPointSize( QMAX( 1, f.pointSize() - range ) );
4245 setFont( f );
4246}
4247
4248/*! Zooms the text by making the base font size \a size points and
4249 recalculating all font sizes. This does not change the size of any
4250 images.
4251*/
4252
4253void QTextEdit::zoomTo( int size )
4254{
4255 QFont f( QScrollView::font() );
4256 f.setPointSize( size );
4257 setFont( f );
4258}
4259
4260/*!
4261 \internal
4262
4263 QTextEdit is optimized for large amounts text. One of its
4264 optimizations is to format only the visible text, formatting the rest
4265 on demand, e.g. as the user scrolls, so you don't usually need to
4266 call this function.
4267
4268 In some situations you may want to force the whole text
4269 to be formatted. For example, if after calling setText(), you wanted
4270 to know the height of the document (using contentsHeight()), you
4271 would call this function first.
4272*/
4273
4274void QTextEdit::sync()
4275{
4276 QTextParag *p = lastFormatted;
4277 while ( p ) {
4278 p->format();
4279 p = p->next();
4280 }
4281 resizeContents( contentsWidth(), doc->height() );
4282}
4283
4284/*! \reimp */
4285
4286void QTextEdit::setEnabled( bool b )
4287{
4288 QScrollView::setEnabled( b );
4289 if ( !b ) {
4290 blinkTimer->stop();
4291 drawCursor( FALSE );
4292 }
4293 if ( textFormat() == PlainText ) {
4294 QTextFormat *f = doc->formatCollection()->defaultFormat();
4295 f->setColor( colorGroup().text() );
4296 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
4297 }
4298 if ( b ) {
4299 blinkTimer->start( QApplication::cursorFlashTime() / 2 );
4300 drawCursor( TRUE );
4301 }
4302}
4303
4304/*!
4305 Sets the background color of selection number \a selNum to \a back and
4306 specifies whether the text of this selection should be inverted with \a
4307 invertText.
4308
4309 This only works for \a selNum > 0. The default selection (\a selNum ==
4310 0) gets its attributes from the colorGroup() of this widget.
4311*/
4312
4313void QTextEdit::setSelectionAttributes( int selNum, const QColor &back, bool invertText )
4314{
4315 if ( selNum < 1 )
4316 return;
4317 if ( selNum > doc->numSelections() )
4318 doc->addSelection( selNum );
4319 doc->setSelectionColor( selNum, back );
4320 doc->setInvertSelectionText( selNum, invertText );
4321}
4322
4323/*! \reimp */
4324void QTextEdit::windowActivationChange( bool )
4325{
4326 if ( !isVisible() )
4327 return;
4328
4329 if ( palette().active() != palette().inactive() )
4330 updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
4331}
4332
4333void QTextEdit::setReadOnly( bool b )
4334{
4335 if ( readonly == b )
4336 return;
4337 readonly = b;
4338#ifndef QT_NO_CURSOR
4339 if ( readonly )
4340 viewport()->setCursor( arrowCursor );
4341 else
4342 viewport()->setCursor( ibeamCursor );
4343#endif
4344}
4345
4346/*! Scrolls to the bottom of the document and does formatting if
4347 required */
4348
4349void QTextEdit::scrollToBottom()
4350{
4351 sync();
4352 setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
4353}
4354
4355/*! Returns the rectangle of the paragraph \a para in contents
4356 coordinates, or an invalid rectangle if \a para is out of range.
4357*/
4358
4359QRect QTextEdit::paragraphRect( int para ) const
4360{
4361 QTextEdit *that = (QTextEdit *)this;
4362 that->sync();
4363 QTextParag *p = doc->paragAt( para );
4364 if ( !p )
4365 return QRect( -1, -1, -1, -1 );
4366 return p->rect();
4367}
4368
4369/*!
4370 Returns the paragraph which is at position \a pos (in contents
4371 coordinates), or -1 if there is no paragraph with index \a pos.
4372*/
4373
4374int QTextEdit::paragraphAt( const QPoint &pos ) const
4375{
4376 QTextCursor c( doc );
4377 c.place( pos, doc->firstParag() );
4378 if ( c.parag() )
4379 return c.parag()->paragId();
4380 return -1;
4381}
4382
4383/*!
4384 Returns the index of the character (relative to its paragraph) at
4385 position \a pos (in contents coordinates). If \a para is not null,
4386 \e *\a para is set to this paragraph. If there is no character at
4387 \a pos, -1 is returned.
4388*/
4389
4390int QTextEdit::charAt( const QPoint &pos, int *para ) const
4391{
4392 QTextCursor c( doc );
4393 c.place( pos, doc->firstParag() );
4394 if ( c.parag() ) {
4395 if ( para )
4396 *para = c.parag()->paragId();
4397 return c.index();
4398 }
4399 return -1;
4400}
4401
4402/*! Sets the background color of the paragraph \a para to \a bg */
4403
4404void QTextEdit::setParagraphBackgroundColor( int para, const QColor &bg )
4405{
4406 QTextParag *p = doc->paragAt( para );
4407 if ( !p )
4408 return;
4409 p->setBackgroundColor( bg );
4410 repaintChanged();
4411}
4412
4413/*! Clears the background color of the paragraph \a para, so that the
4414 default color is used again.
4415*/
4416
4417void QTextEdit::clearParagraphBackground( int para )
4418{
4419 QTextParag *p = doc->paragAt( para );
4420 if ( !p )
4421 return;
4422 p->clearBackgroundColor();
4423 repaintChanged();
4424}
4425
4426/*! Returns the background color of the paragraph \a para or an
4427 invalid color if \a para is out of range or the paragraph has no
4428 background set
4429*/
4430
4431QColor QTextEdit::paragraphBackgroundColor( int para ) const
4432{
4433 QTextParag *p = doc->paragAt( para );
4434 if ( !p )
4435 return QColor();
4436 QColor *c = p->backgroundColor();
4437 if ( c )
4438 return *c;
4439 return QColor();
4440}
4441
4442/*! \property QTextEdit::undoRedoEnabled
4443 \brief whether undo/redo is enabled
4444
4445 The default is TRUE.
4446*/
4447
4448void QTextEdit::setUndoRedoEnabled( bool b )
4449{
4450 undoEnabled = b;
4451}
4452
4453bool QTextEdit::isUndoRedoEnabled() const
4454{
4455 return undoEnabled;
4456}
4457
4458/*! Returns whether undo is available */
4459
4460bool QTextEdit::isUndoAvailable() const
4461{
4462 return doc->commands()->isUndoAvailable() || undoRedoInfo.valid();
4463}
4464
4465/*! Returns whether redo is available */
4466
4467bool QTextEdit::isRedoAvailable() const
4468{
4469 return doc->commands()->isRedoAvailable();
4470}
4471
4472void QTextEdit::ensureFormatted( QTextParag *p )
4473{
4474 while ( !p->isValid() ) {
4475 if ( !lastFormatted )
4476 return;
4477 formatMore();
4478 }
4479}
4480
4481/*! \internal */
4482void QTextEdit::updateCursor( const QPoint & pos )
4483{
4484 if ( isReadOnly() && linksEnabled() ) {
4485 QTextCursor c = *cursor;
4486 placeCursor( pos, &c, TRUE );
4487
4488#ifndef QT_NO_NETWORKPROTOCOL
4489 if ( c.parag() && c.parag()->at( c.index() ) &&
4490 c.parag()->at( c.index() )->isAnchor() &&
4491 !c.parag()->at( c.index() )->anchorHref().isEmpty() ) {
4492 if ( c.index() < c.parag()->length() - 1 )
4493 onLink = c.parag()->at( c.index() )->anchorHref();
4494 else
4495 onLink = QString::null;
4496
4497#ifndef QT_NO_CURSOR
4498 viewport()->setCursor( onLink.isEmpty() ? arrowCursor : pointingHandCursor );
4499#endif
4500 QUrl u( doc->context(), onLink, TRUE );
4501 emitHighlighted( u.toString( FALSE, FALSE ) );
4502 } else {
4503#ifndef QT_NO_CURSOR
4504 viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
4505#endif
4506 onLink = QString::null;
4507 emitHighlighted( QString::null );
4508 }
4509#endif
4510 }
4511}
4512
4513void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c )
4514{
4515 placeCursor( pos, c, FALSE );
4516}
diff --git a/noncore/apps/opie-write/qtextedit.h b/noncore/apps/opie-write/qtextedit.h
new file mode 100644
index 0000000..b4e5701
--- a/dev/null
+++ b/noncore/apps/opie-write/qtextedit.h
@@ -0,0 +1,448 @@
1/****************************************************************************
2** $Id$
3**
4** Definition of the QTextEdit class
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#ifndef QTEXTEDIT_H
39#define QTEXTEDIT_H
40
41#ifndef QT_H
42#include "qscrollview.h"
43#include "qstylesheet.h"
44#include "qvector.h"
45#include "qvaluelist.h"
46#endif // QT_H
47
48class QPainter;
49class QKeyEvent;
50class QResizeEvent;
51class QMouseEvent;
52class QTimer;
53class QFont;
54class QColor;
55struct QUndoRedoInfoPrivate;
56class QPopupMenu;
57
58namespace Qt3 {
59
60class QTextString;
61class QTextDocument;
62class QTextCursor;
63class QTextCommand;
64class QTextParag;
65class QTextFormat;
66class QTextBrowser;
67class QTextEditPrivate;
68
69class Q_EXPORT QTextEdit : public QScrollView
70{
71 friend class QTextBrowser;
72
73 Q_OBJECT
74 Q_ENUMS( WordWrap WrapPolicy )
75 Q_PROPERTY( TextFormat textFormat READ textFormat WRITE setTextFormat )
76 Q_PROPERTY( QString text READ text WRITE setText )
77 Q_PROPERTY( QBrush paper READ paper WRITE setPaper )
78 Q_PROPERTY( bool linkUnderline READ linkUnderline WRITE setLinkUnderline )
79 Q_PROPERTY( QString documentTitle READ documentTitle )
80 Q_PROPERTY( int length READ length )
81 Q_PROPERTY( WordWrap wordWrap READ wordWrap WRITE setWordWrap )
82 Q_PROPERTY( int wrapColumnOrWidth READ wrapColumnOrWidth WRITE setWrapColumnOrWidth )
83 Q_PROPERTY( WrapPolicy wrapPolicy READ wrapPolicy WRITE setWrapPolicy )
84 Q_PROPERTY( bool hasSelectedText READ hasSelectedText )
85 Q_PROPERTY( QString selectedText READ selectedText )
86 Q_PROPERTY( int undoDepth READ undoDepth WRITE setUndoDepth )
87 Q_PROPERTY( bool overwriteMode READ isOverwriteMode WRITE setOverwriteMode )
88 Q_PROPERTY( bool modified READ isModified WRITE setModified DESIGNABLE false )
89 Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
90 Q_PROPERTY( bool undoRedoEnabled READ isUndoRedoEnabled WRITE setUndoRedoEnabled )
91 Q_PROPERTY( int tabStopWidth READ tabStopWidth WRITE setTabStopWidth )
92
93public:
94 enum WordWrap {
95 NoWrap,
96 WidgetWidth,
97 FixedPixelWidth,
98 FixedColumnWidth
99 };
100
101 enum WrapPolicy {
102 AtWordBoundary,
103 Anywhere,
104 AtWhiteSpace = AtWordBoundary // deprecated, don't use
105 };
106
107 enum KeyboardAction {
108 ActionBackspace,
109 ActionDelete,
110 ActionReturn,
111 ActionKill
112 };
113
114 enum CursorAction {
115 MoveBackward,
116 MoveForward,
117 MoveWordBackward,
118 MoveWordForward,
119 MoveUp,
120 MoveDown,
121 MoveLineStart,
122 MoveLineEnd,
123 MoveHome,
124 MoveEnd,
125 MovePgUp,
126 MovePgDown
127 };
128
129 enum VerticalAlignment {
130 AlignNormal,
131 AlignSuperScript,
132 AlignSubScript
133 };
134
135 QTextEdit( const QString& text, const QString& context = QString::null,
136 QWidget* parent=0, const char* name=0);
137 QTextEdit( QWidget* parent=0, const char* name=0 );
138 virtual ~QTextEdit();
139 void setPalette( const QPalette & );
140
141 QString text() const;
142 QString text( int para ) const;
143 TextFormat textFormat() const;
144 QString context() const;
145 QString documentTitle() const;
146
147 void getSelection( int *paraFrom, int *indexFrom,
148 int *paraTo, int *indexTo, int selNum = 0 ) const;
149 virtual bool find( const QString &expr, bool cs, bool wo, bool forward = TRUE,
150 int *para = 0, int *index = 0 );
151
152 int paragraphs() const;
153 int lines() const;
154 int linesOfParagraph( int para ) const;
155 int lineOfChar( int para, int chr );
156 int length() const;
157 QRect paragraphRect( int para ) const;
158 int paragraphAt( const QPoint &pos ) const;
159 int charAt( const QPoint &pos, int *para ) const;
160 int paragraphLength( int para ) const;
161
162 QStyleSheet* styleSheet() const;
163 QMimeSourceFactory* mimeSourceFactory() const;
164
165 QBrush paper() const;
166 bool linkUnderline() const;
167
168 int heightForWidth( int w ) const;
169
170 bool hasSelectedText() const;
171 QString selectedText() const;
172 bool isUndoAvailable() const;
173 bool isRedoAvailable() const;
174
175 WordWrap wordWrap() const;
176 int wrapColumnOrWidth() const;
177 WrapPolicy wrapPolicy() const;
178
179 int tabStopWidth() const;
180
181 QString anchorAt( const QPoint& pos );
182
183 QSize sizeHint() const;
184
185 bool isReadOnly() const { return readonly; }
186
187 void getCursorPosition( int *parag, int *index ) const;
188
189 bool isModified() const;
190 bool italic() const;
191 bool bold() const;
192 bool underline() const;
193 QString family() const;
194 int pointSize() const;
195 QColor color() const;
196 QFont font() const;
197 int alignment() const;
198 int undoDepth() const;
199 virtual bool getFormat( int para, int index, QFont *font, QColor *color, VerticalAlignment *verticalAlignment );
200 virtual bool getParagraphFormat( int para, QFont *font, QColor *color,
201 VerticalAlignment *verticalAlignment, int *alignment,
202 QStyleSheetItem::DisplayMode *displayMode,
203 QStyleSheetItem::ListStyle *listStyle,
204 int *listDepth );
205 bool isOverwriteMode() const { return overWrite; }
206 QColor paragraphBackgroundColor( int para ) const;
207
208 bool isUndoRedoEnabled() const;
209 bool eventFilter( QObject *o, QEvent *e );
210
211public slots:
212 void setEnabled( bool );
213 virtual void setMimeSourceFactory( QMimeSourceFactory* factory );
214 virtual void setStyleSheet( QStyleSheet* styleSheet );
215 virtual void scrollToAnchor( const QString& name );
216 virtual void setPaper( const QBrush& pap );
217 virtual void setLinkUnderline( bool );
218
219 virtual void setWordWrap( WordWrap mode );
220 virtual void setWrapColumnOrWidth( int );
221 virtual void setWrapPolicy( WrapPolicy policy );
222
223 virtual void copy();
224 virtual void append( const QString& text );
225
226 void setText( const QString &txt ) { setText( txt, QString::null ); }
227 virtual void setText( const QString &txt, const QString &context );
228 virtual void setTextFormat( TextFormat f );
229
230 virtual void selectAll( bool select = TRUE );
231 virtual void setTabStopWidth( int ts );
232 virtual void zoomIn( int range );
233 virtual void zoomIn() { zoomIn( 1 ); }
234 virtual void zoomOut( int range );
235 virtual void zoomOut() { zoomOut( 1 ); }
236 virtual void zoomTo( int size );
237
238 virtual void sync();
239 virtual void setReadOnly( bool b );
240
241 virtual void undo();
242 virtual void redo();
243 virtual void cut();
244 virtual void paste();
245#ifndef QT_NO_CLIPBOARD
246 virtual void pasteSubType( const QCString &subtype );
247#endif
248 virtual void clear();
249 virtual void del();
250 virtual void indent();
251 virtual void setItalic( bool b );
252 virtual void setBold( bool b );
253 virtual void setUnderline( bool b );
254 virtual void setFamily( const QString &f );
255 virtual void setPointSize( int s );
256 virtual void setColor( const QColor &c );
257 virtual void setFont( const QFont &f );
258 virtual void setVerticalAlignment( VerticalAlignment a );
259 virtual void setAlignment( int a );
260 virtual void setParagType( QStyleSheetItem::DisplayMode dm, QStyleSheetItem::ListStyle listStyle );
261 virtual void setCursorPosition( int parag, int index );
262 virtual void setSelection( int parag_from, int index_from, int parag_to, int index_to, int selNum = 0 );
263 virtual void setSelectionAttributes( int selNum, const QColor &back, bool invertText );
264 virtual void setModified( bool m );
265 virtual void resetFormat();
266 virtual void setUndoDepth( int d );
267 virtual void setFormat( QTextFormat *f, int flags );
268 virtual void ensureCursorVisible();
269 virtual void placeCursor( const QPoint &pos, QTextCursor *c = 0 );
270 virtual void moveCursor( CursorAction action, bool select );
271 virtual void doKeyboardAction( KeyboardAction action );
272 virtual void removeSelectedText( int selNum = 0 );
273 virtual void removeSelection( int selNum = 0 );
274 virtual void setCurrentFont( const QFont &f );
275 virtual void setOverwriteMode( bool b ) { overWrite = b; }
276
277 virtual void scrollToBottom();
278
279 virtual void insert( const QString &text, bool indent, bool checkNewLine, bool removeSelected );
280 virtual void insertAt( const QString &text, int para, int index );
281 virtual void removeParagraph( int para );
282 virtual void insertParagraph( const QString &text, int para );
283
284 virtual void setParagraphBackgroundColor( int para, const QColor &bg );
285 virtual void clearParagraphBackground( int para );
286
287 virtual void setUndoRedoEnabled( bool b );
288
289signals:
290 void textChanged();
291 void selectionChanged();
292 void copyAvailable( bool );
293 void undoAvailable( bool yes );
294 void redoAvailable( bool yes );
295 void currentFontChanged( const QFont &f );
296 void currentColorChanged( const QColor &c );
297 void currentAlignmentChanged( int a );
298 void currentVerticalAlignmentChanged( VerticalAlignment a );
299 void cursorPositionChanged( QTextCursor *c );
300 void cursorPositionChanged( int para, int pos );
301 void returnPressed();
302 void modificationChanged( bool m );
303
304protected:
305 void repaintChanged();
306 void updateStyles();
307 void drawContents( QPainter *p, int cx, int cy, int cw, int ch );
308 bool event( QEvent *e );
309 void keyPressEvent( QKeyEvent *e );
310 void resizeEvent( QResizeEvent *e );
311 void viewportResizeEvent( QResizeEvent* );
312 void contentsMousePressEvent( QMouseEvent *e );
313 void contentsMouseMoveEvent( QMouseEvent *e );
314 void contentsMouseReleaseEvent( QMouseEvent *e );
315 void contentsMouseDoubleClickEvent( QMouseEvent *e );
316#ifndef QT_NO_WHEELEVENT
317 void contentsWheelEvent( QWheelEvent *e );
318#endif
319#ifndef QT_NO_DRAGANDDROP
320 void contentsDragEnterEvent( QDragEnterEvent *e );
321 void contentsDragMoveEvent( QDragMoveEvent *e );
322 void contentsDragLeaveEvent( QDragLeaveEvent *e );
323 void contentsDropEvent( QDropEvent *e );
324#endif
325 bool focusNextPrevChild( bool next );
326 QTextDocument *document() const;
327 QTextCursor *textCursor() const;
328 void setDocument( QTextDocument *doc );
329 virtual QPopupMenu *createPopupMenu( const QPoint& pos );
330 virtual QPopupMenu *createPopupMenu();
331 void drawCursor( bool visible );
332
333 void windowActivationChange( bool );
334
335protected slots:
336 virtual void doChangeInterval();
337
338private slots:
339 void formatMore();
340 void doResize();
341 void autoScrollTimerDone();
342 void blinkCursor();
343 void setModified();
344 void startDrag();
345 void documentWidthChanged( int w );
346
347private:
348 struct Q_EXPORT UndoRedoInfo {
349 enum Type { Invalid, Insert, Delete, Backspace, Return, RemoveSelected, Format, Alignment, ParagType };
350
351 UndoRedoInfo( QTextDocument *dc );
352 ~UndoRedoInfo();
353 void clear();
354 bool valid() const;
355
356 QUndoRedoInfoPrivate *d;
357 int id;
358 int index;
359 int eid;
360 int eindex;
361 QTextFormat *format;
362 int flags;
363 Type type;
364 QTextDocument *doc;
365 QMemArray<int> oldAligns;
366 int newAlign;
367 bool list;
368 QStyleSheetItem::ListStyle listStyle;
369 QValueList< QPtrVector<QStyleSheetItem> > oldStyles;
370 QValueList<QStyleSheetItem::ListStyle> oldListStyles;
371 };
372
373private:
374 void updateCursor( const QPoint & pos );
375 void handleMouseMove( const QPoint& pos );
376 void drawContents( QPainter * );
377 virtual bool linksEnabled() const { return FALSE; }
378 void init();
379 void checkUndoRedoInfo( UndoRedoInfo::Type t );
380 void updateCurrentFormat();
381 bool handleReadOnlyKeyEvent( QKeyEvent *e );
382 void makeParagVisible( QTextParag *p );
383#ifndef QT_NO_MIME
384 QCString pickSpecial(QMimeSource* ms, bool always_ask, const QPoint&);
385#endif
386#ifndef QT_NO_MIMECLIPBOARD
387 void pasteSpecial(const QPoint&);
388#endif
389 void setFontInternal( const QFont &f );
390
391 virtual void emitHighlighted( const QString & ) {}
392 virtual void emitLinkClicked( const QString & ) {}
393
394 void readFormats( QTextCursor &c1, QTextCursor &c2, int oldLen, QTextString &text, bool fillStyles = FALSE );
395 void clearUndoRedo();
396 void paintDocument( bool drawAll, QPainter *p, int cx = -1, int cy = -1, int cw = -1, int ch = -1 );
397 void moveCursor( CursorAction action );
398 void ensureFormatted( QTextParag *p );
399 void placeCursor( const QPoint &pos, QTextCursor *c, bool link );
400
401private:
402 QTextDocument *doc;
403 QTextCursor *cursor;
404 QTimer *formatTimer, *scrollTimer, *changeIntervalTimer, *blinkTimer, *dragStartTimer;
405 QTextParag *lastFormatted;
406 int interval;
407 UndoRedoInfo undoRedoInfo;
408 QTextFormat *currentFormat;
409 int currentAlignment;
410 QPoint oldMousePos, mousePos;
411 QPoint dragStartPos;
412 QString onLink;
413 WordWrap wrapMode;
414 WrapPolicy wPolicy;
415 int wrapWidth;
416 QString pressedLink;
417 QTextEditPrivate *d;
418 bool inDoubleClick : 1;
419 bool mousePressed : 1;
420 bool cursorVisible : 1;
421 bool blinkCursorVisible : 1;
422 bool readOnly : 1;
423 bool modified : 1;
424 bool mightStartDrag : 1;
425 bool inDnD : 1;
426 bool readonly : 1;
427 bool undoEnabled : 1;
428 bool overWrite : 1;
429};
430
431inline QTextDocument *QTextEdit::document() const
432{
433 return doc;
434}
435
436inline QTextCursor *QTextEdit::textCursor() const
437{
438 return cursor;
439}
440
441inline void QTextEdit::setCurrentFont( const QFont &f )
442{
443 QTextEdit::setFontInternal( f );
444}
445
446}
447
448#endif //QTEXTVIEW_H