Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qtextedit.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** $Id: qtextedit.cpp,v 1.5 2004/06/10 22:34:29 ar Exp $
00003 **
00004 ** Implementation of the QTextEdit class
00005 **
00006 ** Created : 990101
00007 **
00008 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
00009 **
00010 ** This file is part of the widgets module of the Qt GUI Toolkit.
00011 **
00012 ** This file may be distributed under the terms of the Q Public License
00013 ** as defined by Trolltech AS of Norway and appearing in the file
00014 ** LICENSE.QPL included in the packaging of this file.
00015 **
00016 ** This file may be distributed and/or modified under the terms of the
00017 ** GNU General Public License version 2 as published by the Free Software
00018 ** Foundation and appearing in the file LICENSE.GPL included in the
00019 ** packaging of this file.
00020 **
00021 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
00022 ** licenses may use this file in accordance with the Qt Commercial License
00023 ** Agreement provided with the Software.
00024 **
00025 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00026 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00027 **
00028 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00029 **   information about Qt Commercial License Agreements.
00030 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00031 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00032 **
00033 ** Contact info@trolltech.com if any conditions of this licensing are
00034 ** not clear to you.
00035 **
00036 **********************************************************************/
00037 
00038 #include "qtextedit.h"
00039 
00040 #include "qrichtext_p.h"
00041 #include "qlistbox.h"
00042 #include "qclipboard.h"
00043 #include "qpopupmenu.h"
00044 
00045 #define ACCEL_KEY(k) "\t" + QString("Ctrl+" #k)
00046 
00047 using namespace Qt3;
00048 
00049 static bool qt_enable_richtext_copy = FALSE;
00050 
00051 struct QUndoRedoInfoPrivate
00052 {
00053     QTextString text;
00054 };
00055 
00056 namespace Qt3 {
00057 
00058 class QTextEditPrivate
00059 {
00060 public:
00061     QTextEditPrivate()
00062     :preeditStart(-1),preeditLength(-1),ensureCursorVisibleInShowEvent(FALSE)
00063     {
00064     for ( int i=0; i<7; i++ )
00065         id[i] = 0;
00066     }
00067     int id[ 7 ];
00068     int preeditStart;
00069     int preeditLength;
00070     bool ensureCursorVisibleInShowEvent;
00071     QString scrollToAnchor; // used to deferr scrollToAnchor() until the show event when we are resized
00072 };
00073 
00074 }
00075 
00076 static bool block_set_alignment = FALSE;
00077 
00625 QTextEdit::QTextEdit( QWidget *parent, const char *name )
00626     : QScrollView( parent, name, WStaticContents | WRepaintNoErase | WResizeNoErase ),
00627       doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
00628 {
00629     init();
00630 }
00631 
00653 QTextEdit::QTextEdit( const QString& text, const QString& context,
00654               QWidget *parent, const char *name)
00655     : QScrollView( parent, name, WStaticContents | WRepaintNoErase | WResizeNoErase ),
00656       doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
00657 {
00658     init();
00659     setText( text, context );
00660 }
00661 
00664 QTextEdit::~QTextEdit()
00665 {
00666     delete undoRedoInfo.d;
00667     undoRedoInfo.d = 0;
00668     delete cursor;
00669     delete doc;
00670     delete d;
00671 }
00672 
00673 void QTextEdit::init()
00674 {
00675     setFrameStyle( Sunken );
00676     setVScrollBarMode( AlwaysOn );
00677     undoEnabled = TRUE;
00678     readonly = TRUE;
00679     setReadOnly( FALSE );
00680     d = new QTextEditPrivate;
00681     connect( doc, SIGNAL( minimumWidthChanged(int) ),
00682          this, SLOT( documentWidthChanged(int) ) );
00683 
00684     mousePressed = FALSE;
00685     inDoubleClick = FALSE;
00686     modified = FALSE;
00687     onLink = QString::null;
00688     overWrite = FALSE;
00689     wrapMode = WidgetWidth;
00690     wrapWidth = -1;
00691     wPolicy = AtWhiteSpace;
00692     inDnD = FALSE;
00693 
00694     doc->setFormatter( new QTextFormatterBreakWords );
00695     doc->formatCollection()->defaultFormat()->setFont( QScrollView::font() );
00696     doc->formatCollection()->defaultFormat()->setColor( colorGroup().color( QColorGroup::Text ) );
00697     currentFormat = doc->formatCollection()->defaultFormat();
00698     currentAlignment = Qt3::AlignAuto;
00699 
00700     viewport()->setBackgroundMode( PaletteBase );
00701     viewport()->setAcceptDrops( TRUE );
00702     resizeContents( 0, doc->lastParagraph() ?
00703             ( doc->lastParagraph()->paragId() + 1 ) * doc->formatCollection()->defaultFormat()->height() : 0 );
00704 
00705     setKeyCompression( TRUE );
00706     viewport()->setMouseTracking( TRUE );
00707 #ifndef QT_NO_CURSOR
00708     viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
00709 #endif
00710     cursor = new QTextCursor( doc );
00711 
00712     formatTimer = new QTimer( this );
00713     connect( formatTimer, SIGNAL( timeout() ),
00714          this, SLOT( formatMore() ) );
00715     lastFormatted = doc->firstParagraph();
00716 
00717     scrollTimer = new QTimer( this );
00718     connect( scrollTimer, SIGNAL( timeout() ),
00719          this, SLOT( autoScrollTimerDone() ) );
00720 
00721     interval = 0;
00722     changeIntervalTimer = new QTimer( this );
00723     connect( changeIntervalTimer, SIGNAL( timeout() ),
00724          this, SLOT( doChangeInterval() ) );
00725 
00726     cursorVisible = TRUE;
00727     blinkTimer = new QTimer( this );
00728     connect( blinkTimer, SIGNAL( timeout() ),
00729          this, SLOT( blinkCursor() ) );
00730 
00731 #ifndef QT_NO_DRAGANDDROP
00732     dragStartTimer = new QTimer( this );
00733     connect( dragStartTimer, SIGNAL( timeout() ),
00734          this, SLOT( startDrag() ) );
00735 #endif
00736 
00737 
00738     formatMore();
00739 
00740     blinkCursorVisible = FALSE;
00741 
00742     viewport()->setFocusProxy( this );
00743     viewport()->setFocusPolicy( WheelFocus );
00744     viewport()->installEventFilter( this );
00745     installEventFilter( this );
00746 }
00747 
00748 void QTextEdit::paintDocument( bool drawAll, QPainter *p, int cx, int cy, int cw, int ch )
00749 {
00750     bool drawCur = hasFocus() || viewport()->hasFocus();
00751     if ( hasSelectedText() || isReadOnly() || !cursorVisible )
00752     drawCur = FALSE;
00753     QColorGroup g = colorGroup();
00754     if ( doc->paper() )
00755     g.setBrush( QColorGroup::Base, *doc->paper() );
00756 
00757     if ( contentsY() < doc->y() ) {
00758     p->fillRect( contentsX(), contentsY(), visibleWidth(), doc->y(),
00759              g.brush( QColorGroup::Base ) );
00760     }
00761     if ( drawAll && doc->width() - contentsX() < cx + cw ) {
00762     p->fillRect( doc->width() - contentsX(), cy, cx + cw - doc->width() + contentsX(), ch,
00763              g.brush( QColorGroup::Base ) );
00764     }
00765 
00766     p->setBrushOrigin( -contentsX(), -contentsY() );
00767 
00768     lastFormatted = doc->draw( p, cx, cy, cw, ch, g, !drawAll, drawCur, cursor );
00769 
00770     if ( lastFormatted == doc->lastParagraph() )
00771     resizeContents( contentsWidth(), doc->height() );
00772 
00773     if ( contentsHeight() < visibleHeight() && ( !doc->lastParagraph() || doc->lastParagraph()->isValid() ) && drawAll )
00774     p->fillRect( 0, contentsHeight(), visibleWidth(),
00775              visibleHeight() - contentsHeight(), g.brush( QColorGroup::Base ) );
00776 }
00777 
00780 void QTextEdit::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
00781 {
00782     paintDocument( TRUE, p, cx, cy, cw, ch );
00783     int v;
00784     p->setPen( foregroundColor() );
00785     if ( document()->isPageBreakEnabled() &&  ( v = document()->flow()->pageSize() ) > 0 ) {
00786     int l = int(cy / v) * v;
00787     while ( l < cy + ch ) {
00788         p->drawLine( cx, l, cx + cw - 1, l );
00789         l += v;
00790     }
00791     }
00792 
00793 }
00794 
00797 void QTextEdit::drawContents( QPainter * )
00798 {
00799 }
00800 
00803 bool QTextEdit::event( QEvent *e )
00804 {
00805     if ( e->type() == QEvent::AccelOverride && !isReadOnly() ) {
00806     QKeyEvent* ke = (QKeyEvent*) e;
00807     if ( ke->state() == NoButton || ke->state() == Keypad ) {
00808         if ( ke->key() < Key_Escape ) {
00809         ke->accept();
00810         } else {
00811         switch ( ke->key() ) {
00812         case Key_Return:
00813         case Key_Enter:
00814         case Key_Delete:
00815         case Key_Home:
00816         case Key_End:
00817         case Key_Backspace:
00818             ke->accept();
00819         default:
00820             break;
00821         }
00822         }
00823     } else if ( ke->state() & ControlButton ) {
00824         switch ( ke->key() ) {
00825 // Those are too frequently used for application functionality
00826 /*      case Key_A:
00827         case Key_B:
00828         case Key_D:
00829         case Key_E:
00830         case Key_F:
00831         case Key_H:
00832         case Key_I:
00833         case Key_K:
00834         case Key_N:
00835         case Key_P:
00836         case Key_T:
00837 */
00838         case Key_C:
00839         case Key_V:
00840         case Key_X:
00841         case Key_Y:
00842         case Key_Z:
00843         case Key_Left:
00844         case Key_Right:
00845         case Key_Up:
00846         case Key_Down:
00847         case Key_Home:
00848         case Key_End:
00849         case Key_Tab:
00850 #if defined (Q_WS_WIN)
00851         case Key_Insert:
00852         case Key_Delete:
00853 #endif
00854         ke->accept();
00855         default:
00856         break;
00857         }
00858     } else {
00859         switch ( ke->key() ) {
00860 #if defined (Q_WS_WIN)
00861         case Key_Insert:
00862         ke->accept();
00863 #endif
00864         default:
00865         break;
00866         }
00867     }
00868     }
00869 
00870     if ( e->type() == QEvent::Show ) {
00871     if ( d->ensureCursorVisibleInShowEvent ) {
00872         sync();
00873         ensureCursorVisible();
00874         d->ensureCursorVisibleInShowEvent = FALSE;
00875     }
00876     if ( !d->scrollToAnchor.isEmpty()  ) {
00877         scrollToAnchor( d->scrollToAnchor );
00878         d->scrollToAnchor = QString::null;
00879     }
00880     }
00881     return QWidget::event( e );
00882 }
00883 
00890 void QTextEdit::keyPressEvent( QKeyEvent *e )
00891 {
00892     changeIntervalTimer->stop();
00893     interval = 10;
00894     bool unknown = FALSE;
00895     if ( isReadOnly() ) {
00896     if ( !handleReadOnlyKeyEvent( e ) )
00897         QScrollView::keyPressEvent( e );
00898     changeIntervalTimer->start( 100, TRUE );
00899     return;
00900     }
00901 
00902 
00903     bool selChanged = FALSE;
00904     for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
00905     selChanged = doc->removeSelection( i ) || selChanged;
00906 
00907     if ( selChanged ) {
00908     cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
00909     repaintChanged();
00910     }
00911 
00912     bool clearUndoRedoInfo = TRUE;
00913 
00914 
00915     switch ( e->key() ) {
00916     case Key_Left:
00917     case Key_Right: {
00918     // a bit hacky, but can't change this without introducing new enum values for move and keeping the
00919     // correct semantics and movement for BiDi and non BiDi text.
00920     CursorAction a;
00921     if ( cursor->paragraph()->string()->isRightToLeft() == (e->key() == Key_Right) )
00922         a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
00923     else
00924         a = e->state() & ControlButton ? MoveWordForward : MoveForward;
00925     moveCursor( a, e->state() & ShiftButton );
00926     break;
00927     }
00928     case Key_Up:
00929     moveCursor( e->state() & ControlButton ? MovePgUp : MoveUp, e->state() & ShiftButton );
00930     break;
00931     case Key_Down:
00932     moveCursor( e->state() & ControlButton ? MovePgDown : MoveDown, e->state() & ShiftButton );
00933     break;
00934     case Key_Home:
00935     moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
00936     break;
00937     case Key_End:
00938     moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
00939     break;
00940     case Key_Prior:
00941     moveCursor( MovePgUp, e->state() & ShiftButton );
00942     break;
00943     case Key_Next:
00944     moveCursor( MovePgDown, e->state() & ShiftButton );
00945     break;
00946     case Key_Return: case Key_Enter:
00947     if ( doc->hasSelection( QTextDocument::Standard, FALSE ) )
00948         removeSelectedText();
00949     if ( textFormat() == Qt::RichText && ( e->state() & ControlButton ) ) {
00950         // Ctrl-Enter inserts a line break in rich text mode
00951         insert( QString( QChar( 0x2028) ), TRUE, FALSE, TRUE );
00952     } else {
00953 #ifndef QT_NO_CURSOR
00954         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
00955 #endif
00956         clearUndoRedoInfo = FALSE;
00957         doKeyboardAction( ActionReturn );
00958         emit returnPressed();
00959     }
00960     break;
00961     case Key_Delete:
00962 #if defined (Q_WS_WIN)
00963     if ( e->state() & ShiftButton ) {
00964         cut();
00965         break;
00966     } else
00967 #endif
00968         if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
00969         removeSelectedText();
00970         break;
00971     }
00972     doKeyboardAction( ActionDelete );
00973     clearUndoRedoInfo = FALSE;
00974 
00975     break;
00976     case Key_Insert:
00977     if ( e->state() & ShiftButton )
00978         paste();
00979 #if defined (Q_WS_WIN)
00980     else if ( e->state() & ControlButton )
00981         copy();
00982 #endif
00983     break;
00984     case Key_Backspace:
00985     if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
00986         removeSelectedText();
00987         break;
00988     }
00989 
00990     doKeyboardAction( ActionBackspace );
00991     clearUndoRedoInfo = FALSE;
00992 
00993     break;
00994     case Key_F16: // Copy key on Sun keyboards
00995     copy();
00996     break;
00997     case Key_F18:  // Paste key on Sun keyboards
00998     paste();
00999     break;
01000     case Key_F20:  // Cut key on Sun keyboards
01001     cut();
01002     break;
01003     default: {
01004         if ( e->text().length() &&
01005         ( !( e->state() & ControlButton ) &&
01006           !( e->state() & AltButton ) ||
01007          ( ( e->state() & ControlButton | AltButton ) == (ControlButton|AltButton) ) ) &&
01008          ( !e->ascii() || e->ascii() >= 32 || e->text() == "\t" ) ) {
01009         clearUndoRedoInfo = FALSE;
01010         if ( e->key() == Key_Tab ) {
01011             if ( textFormat() == Qt::RichText && cursor->paragraph()->isListItem() ) {
01012             clearUndoRedo();
01013             undoRedoInfo.type = UndoRedoInfo::Style;
01014             undoRedoInfo.id = cursor->paragraph()->paragId();
01015             undoRedoInfo.eid = undoRedoInfo.id;
01016             undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
01017             cursor->paragraph()->setListDepth( cursor->paragraph()->listDepth() +1 );
01018             clearUndoRedo();
01019             drawCursor( FALSE );
01020             repaintChanged();
01021             drawCursor( TRUE );
01022             break;
01023             }
01024         }
01025 
01026         if ( textFormat() == Qt::RichText && !cursor->paragraph()->isListItem() ) {
01027             if ( cursor->index() == 0 && ( e->text()[0] == '-' || e->text()[0] == '*' ) ) {
01028             clearUndoRedo();
01029             undoRedoInfo.type = UndoRedoInfo::Style;
01030             undoRedoInfo.id = cursor->paragraph()->paragId();
01031             undoRedoInfo.eid = undoRedoInfo.id;
01032             undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
01033             setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
01034             clearUndoRedo();
01035             drawCursor( FALSE );
01036             repaintChanged();
01037             drawCursor( TRUE );
01038             break;
01039             }
01040         }
01041         if ( overWrite && !cursor->atParagEnd() )
01042             cursor->remove();
01043         QString t = e->text();
01044         QTextParagraph *p = cursor->paragraph();
01045         if ( p && p->string() && p->string()->isRightToLeft() ) {
01046             QChar *c = (QChar *)t.unicode();
01047             int l = t.length();
01048             while( l-- ) {
01049             if ( c->mirrored() )
01050                 *c = c->mirroredChar();
01051             c++;
01052             }
01053         }
01054         insert( t, TRUE, FALSE, TRUE );
01055         break;
01056         } else if ( e->state() & ControlButton ) {
01057         switch ( e->key() ) {
01058         case Key_C: case Key_F16: // Copy key on Sun keyboards
01059             copy();
01060             break;
01061         case Key_V:
01062             paste();
01063             break;
01064         case Key_X:
01065             cut();
01066             break;
01067         case Key_I: case Key_T: case Key_Tab:
01068             indent();
01069             break;
01070         case Key_A:
01071 #if defined(Q_WS_X11)
01072             moveCursor( MoveLineStart, e->state() & ShiftButton );
01073 #else
01074             selectAll( TRUE );
01075 #endif
01076             break;
01077         case Key_B:
01078             moveCursor( MoveBackward, e->state() & ShiftButton );
01079             break;
01080         case Key_F:
01081             moveCursor( MoveForward, e->state() & ShiftButton );
01082             break;
01083         case Key_D:
01084             if ( doc->hasSelection( QTextDocument::Standard ) ) {
01085             removeSelectedText();
01086             break;
01087             }
01088             doKeyboardAction( ActionDelete );
01089             clearUndoRedoInfo = FALSE;
01090             break;
01091         case Key_H:
01092             if ( doc->hasSelection( QTextDocument::Standard ) ) {
01093             removeSelectedText();
01094             break;
01095             }
01096             if ( !cursor->paragraph()->prev() &&
01097              cursor->atParagStart() )
01098             break;
01099 
01100             doKeyboardAction( ActionBackspace );
01101             clearUndoRedoInfo = FALSE;
01102             break;
01103         case Key_E:
01104             moveCursor( MoveLineEnd, e->state() & ShiftButton );
01105             break;
01106         case Key_N:
01107             moveCursor( MoveDown, e->state() & ShiftButton );
01108             break;
01109         case Key_P:
01110             moveCursor( MoveUp, e->state() & ShiftButton );
01111             break;
01112         case Key_Z:
01113             if(e->state() & ShiftButton)
01114             redo();
01115             else
01116             undo();
01117             break;
01118         case Key_Y:
01119             redo();
01120             break;
01121         case Key_K:
01122             doKeyboardAction( ActionKill );
01123             break;
01124 #if defined(Q_WS_WIN)
01125         case Key_Insert:
01126             copy();
01127             break;
01128         case Key_Delete:
01129             del();
01130             break;
01131 #endif
01132         default:
01133             unknown = FALSE;
01134             break;
01135         }
01136         } else {
01137         unknown = TRUE;
01138         }
01139         }
01140     }
01141 
01142     emit cursorPositionChanged( cursor );
01143     emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
01144     if ( clearUndoRedoInfo )
01145     clearUndoRedo();
01146     changeIntervalTimer->start( 100, TRUE );
01147     if ( unknown )
01148     e->ignore();
01149 }
01150 
01156 void QTextEdit::doKeyboardAction( KeyboardAction action )
01157 {
01158     if ( isReadOnly() )
01159     return;
01160 
01161     if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
01162     return;
01163 
01164     lastFormatted = cursor->paragraph();
01165     drawCursor( FALSE );
01166     bool doUpdateCurrentFormat = TRUE;
01167 
01168     switch ( action ) {
01169     case ActionDelete:
01170     if ( !cursor->atParagEnd() ) {
01171         checkUndoRedoInfo( UndoRedoInfo::Delete );
01172         if ( !undoRedoInfo.valid() ) {
01173         undoRedoInfo.id = cursor->paragraph()->paragId();
01174         undoRedoInfo.index = cursor->index();
01175         undoRedoInfo.d->text = QString::null;
01176         }
01177         undoRedoInfo.d->text.insert( undoRedoInfo.d->text.length(), cursor->paragraph()->at( cursor->index() ), TRUE );
01178         cursor->remove();
01179     } else {
01180         clearUndoRedo();
01181         doc->setSelectionStart( QTextDocument::Temp, *cursor );
01182         cursor->gotoNextLetter();
01183         doc->setSelectionEnd( QTextDocument::Temp, *cursor );
01184         removeSelectedText( QTextDocument::Temp );
01185     }
01186     break;
01187     case ActionBackspace:
01188     if ( textFormat() == Qt::RichText && cursor->paragraph()->isListItem() && cursor->index() == 0 ) {
01189         clearUndoRedo();
01190         undoRedoInfo.type = UndoRedoInfo::Style;
01191         undoRedoInfo.id = cursor->paragraph()->paragId();
01192         undoRedoInfo.eid = undoRedoInfo.id;
01193         undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
01194         int ldepth = cursor->paragraph()->listDepth();
01195         ldepth = QMAX( ldepth-1, 0 );
01196         cursor->paragraph()->setListDepth( ldepth );
01197         if ( ldepth == 0 )
01198         cursor->paragraph()->setListItem( FALSE );
01199         clearUndoRedo();
01200         lastFormatted = cursor->paragraph();
01201         repaintChanged();
01202         drawCursor( TRUE );
01203         return;
01204     }
01205     if ( !cursor->atParagStart() ) {
01206         checkUndoRedoInfo( UndoRedoInfo::Delete );
01207         if ( !undoRedoInfo.valid() ) {
01208         undoRedoInfo.id = cursor->paragraph()->paragId();
01209         undoRedoInfo.index = cursor->index();
01210         undoRedoInfo.d->text = QString::null;
01211         }
01212         cursor->gotoPreviousLetter();
01213         undoRedoInfo.d->text.insert( 0, cursor->paragraph()->at( cursor->index() ), TRUE );
01214         undoRedoInfo.index = cursor->index();
01215         cursor->remove();
01216         lastFormatted = cursor->paragraph();
01217     } else if ( cursor->paragraph()->prev() ){
01218         clearUndoRedo();
01219         doc->setSelectionStart( QTextDocument::Temp, *cursor );
01220         cursor->gotoPreviousLetter();
01221         doc->setSelectionEnd( QTextDocument::Temp, *cursor );
01222         removeSelectedText( QTextDocument::Temp );
01223     }
01224     break;
01225     case ActionReturn:
01226     checkUndoRedoInfo( UndoRedoInfo::Return );
01227     if ( !undoRedoInfo.valid() ) {
01228         undoRedoInfo.id = cursor->paragraph()->paragId();
01229         undoRedoInfo.index = cursor->index();
01230         undoRedoInfo.d->text = QString::null;
01231     }
01232     undoRedoInfo.d->text += "\n";
01233     cursor->splitAndInsertEmptyParagraph();
01234     if ( cursor->paragraph()->prev() ) {
01235         lastFormatted = cursor->paragraph()->prev();
01236         lastFormatted->invalidate( 0 );
01237     }
01238     doUpdateCurrentFormat = FALSE;
01239     break;
01240     case ActionKill:
01241         clearUndoRedo();
01242         doc->setSelectionStart( QTextDocument::Temp, *cursor );
01243         if ( cursor->atParagEnd() )
01244         cursor->gotoNextLetter();
01245         else
01246         cursor->setIndex( cursor->paragraph()->length() - 1 );
01247         doc->setSelectionEnd( QTextDocument::Temp, *cursor );
01248         removeSelectedText( QTextDocument::Temp );
01249         break;
01250     }
01251 
01252     formatMore();
01253     repaintChanged();
01254     ensureCursorVisible();
01255     drawCursor( TRUE );
01256     updateMicroFocusHint();
01257     if ( doUpdateCurrentFormat )
01258     updateCurrentFormat();
01259     setModified();
01260     emit textChanged();
01261 }
01262 
01263 void QTextEdit::readFormats( QTextCursor &c1, QTextCursor &c2, QTextString &text, bool fillStyles )
01264 {
01265     QDataStream styleStream( undoRedoInfo.styleInformation, IO_WriteOnly );
01266     c2.restoreState();
01267     c1.restoreState();
01268     int lastIndex = text.length();
01269     if ( c1.paragraph() == c2.paragraph() ) {
01270     for ( int i = c1.index(); i < c2.index(); ++i )
01271         text.insert( lastIndex + i - c1.index(), c1.paragraph()->at( i ), TRUE );
01272     if ( fillStyles ) {
01273         styleStream << (int) 1;
01274         c1.paragraph()->writeStyleInformation( styleStream );
01275     }
01276     } else {
01277     int i;
01278     for ( i = c1.index(); i < c1.paragraph()->length()-1; ++i )
01279         text.insert( lastIndex++, c1.paragraph()->at( i ), TRUE );
01280     int num = 2; // start and end, being different
01281     text += "\n"; lastIndex++;
01282     QTextParagraph *p = c1.paragraph()->next();
01283     while ( p && p != c2.paragraph() ) {
01284         for ( i = 0; i < p->length()-1; ++i )
01285         text.insert( lastIndex++ , p->at( i ), TRUE );
01286         text += "\n"; num++; lastIndex++;
01287         p = p->next();
01288     }
01289     for ( i = 0; i < c2.index(); ++i )
01290         text.insert( i + lastIndex, c2.paragraph()->at( i ), TRUE );
01291     if ( fillStyles ) {
01292         styleStream << num;
01293         for ( QTextParagraph *p = c1.paragraph(); --num >= 0; p = p->next() )
01294         p->writeStyleInformation( styleStream );
01295     }
01296     }
01297 }
01298 
01305 void QTextEdit::removeSelection( int selNum )
01306 {
01307     doc->removeSelection( selNum );
01308     repaintChanged();
01309 }
01310 
01318 void QTextEdit::removeSelectedText( int selNum )
01319 {
01320     if ( isReadOnly() )
01321     return;
01322 
01323     QTextCursor c1 = doc->selectionStartCursor( selNum );
01324     c1.restoreState();
01325     QTextCursor c2 = doc->selectionEndCursor( selNum );
01326     c2.restoreState();
01327 
01328     // ### no support for editing tables yet, plus security for broken selections
01329     if ( c1.nestedDepth() || c2.nestedDepth() )
01330     return;
01331 
01332     for ( int i = 0; i < (int)doc->numSelections(); ++i ) {
01333     if ( i == selNum )
01334         continue;
01335     doc->removeSelection( i );
01336     }
01337 
01338     drawCursor( FALSE );
01339     checkUndoRedoInfo( UndoRedoInfo::RemoveSelected );
01340     if ( !undoRedoInfo.valid() ) {
01341     doc->selectionStart( selNum, undoRedoInfo.id, undoRedoInfo.index );
01342     undoRedoInfo.d->text = QString::null;
01343     }
01344     readFormats( c1, c2, undoRedoInfo.d->text, TRUE );
01345 
01346 
01347     doc->removeSelectedText( selNum, cursor );
01348     if ( cursor->isValid() ) {
01349     ensureCursorVisible();
01350     lastFormatted = cursor->paragraph();
01351     formatMore();
01352     repaintChanged();
01353     ensureCursorVisible();
01354     drawCursor( TRUE );
01355     clearUndoRedo();
01356 #if defined(Q_WS_WIN)
01357     // there seems to be a problem with repainting or erasing the area
01358     // of the scrollview which is not the contents on windows
01359     if ( contentsHeight() < visibleHeight() )
01360         viewport()->repaint( 0, contentsHeight(), visibleWidth(), visibleHeight() - contentsHeight(), TRUE );
01361 #endif
01362 #ifndef QT_NO_CURSOR
01363     viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
01364 #endif
01365     updateMicroFocusHint();
01366     } else {
01367     delete cursor;
01368     cursor = new QTextCursor( doc );
01369     drawCursor( TRUE );
01370     viewport()->repaint( TRUE );
01371     }
01372     setModified();
01373     emit textChanged();
01374     emit selectionChanged();
01375 }
01376 
01383 void QTextEdit::moveCursor( CursorAction action, bool select )
01384 {
01385     drawCursor( FALSE );
01386     if ( select ) {
01387     if ( !doc->hasSelection( QTextDocument::Standard ) )
01388         doc->setSelectionStart( QTextDocument::Standard, *cursor );
01389     moveCursor( action );
01390     if ( doc->setSelectionEnd( QTextDocument::Standard, *cursor ) ) {
01391         cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
01392         repaintChanged();
01393     } else {
01394         drawCursor( TRUE );
01395     }
01396     ensureCursorVisible();
01397     emit selectionChanged();
01398     emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
01399     } else {
01400     bool redraw = doc->removeSelection( QTextDocument::Standard );
01401     moveCursor( action );
01402     if ( !redraw ) {
01403         ensureCursorVisible();
01404         drawCursor( TRUE );
01405     } else {
01406         cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
01407         repaintChanged();
01408         ensureCursorVisible();
01409         drawCursor( TRUE );
01410 #ifndef QT_NO_CURSOR
01411         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
01412 #endif
01413     }
01414     if ( redraw ) {
01415         emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
01416         emit selectionChanged();
01417     }
01418     }
01419 
01420     drawCursor( TRUE );
01421     updateCurrentFormat();
01422     updateMicroFocusHint();
01423 }
01424 
01428 void QTextEdit::moveCursor( CursorAction action )
01429 {
01430     switch ( action ) {
01431     case MoveBackward:
01432     cursor->gotoPreviousLetter();
01433     break;
01434     case MoveWordBackward:
01435     cursor->gotoPreviousWord();
01436     break;
01437     case MoveForward:
01438     cursor->gotoNextLetter();
01439     break;
01440     case MoveWordForward:
01441     cursor->gotoNextWord();
01442     break;
01443     case MoveUp:
01444     cursor->gotoUp();
01445     break;
01446     case MovePgUp:
01447     cursor->gotoPageUp( visibleHeight() );
01448     break;
01449     case MoveDown:
01450     cursor->gotoDown();
01451     break;
01452     case MovePgDown:
01453     cursor->gotoPageDown( visibleHeight() );
01454     break;
01455     case MoveLineStart:
01456     cursor->gotoLineStart();
01457     break;
01458     case MoveHome:
01459     cursor->gotoHome();
01460     break;
01461     case MoveLineEnd:
01462     cursor->gotoLineEnd();
01463     break;
01464     case MoveEnd:
01465     ensureFormatted( doc->lastParagraph() );
01466     cursor->gotoEnd();
01467     break;
01468     }
01469     updateMicroFocusHint();
01470     updateCurrentFormat();
01471 }
01472 
01475 void QTextEdit::resizeEvent( QResizeEvent *e )
01476 {
01477     QScrollView::resizeEvent( e );
01478     if ( doc->visibleWidth() == 0 )
01479     doResize();
01480 }
01481 
01484 void QTextEdit::viewportResizeEvent( QResizeEvent *e )
01485 {
01486     QScrollView::viewportResizeEvent( e );
01487     if ( e->oldSize().width() != e->size().width() ) {
01488     bool stayAtBottom = e->oldSize().height() != e->size().height() &&
01489            contentsY() > 0 && contentsY() >= doc->height() - e->oldSize().height();
01490     doResize();
01491     if ( stayAtBottom )
01492         scrollToBottom();
01493     }
01494 }
01495 
01503 void QTextEdit::ensureCursorVisible()
01504 {
01505     if ( !isVisible() ) {
01506     d->ensureCursorVisibleInShowEvent = TRUE;
01507     return;
01508     }
01509     lastFormatted = cursor->paragraph();
01510     formatMore();
01511     QTextStringChar *chr = cursor->paragraph()->at( cursor->index() );
01512     int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
01513     int x = cursor->paragraph()->rect().x() + chr->x + cursor->offsetX();
01514     int y = 0; int dummy;
01515     cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y );
01516     y += cursor->paragraph()->rect().y() + cursor->offsetY();
01517     int w = 1;
01518     ensureVisible( x, y + h / 2, w, h / 2 + 2 );
01519 }
01520 
01524 void QTextEdit::drawCursor( bool visible )
01525 {
01526     if ( !isUpdatesEnabled() ||
01527      !viewport()->isUpdatesEnabled() ||
01528      !cursor->paragraph() ||
01529      !cursor->paragraph()->isValid() ||
01530      !selectedText().isEmpty() ||
01531      ( visible && !hasFocus() && !viewport()->hasFocus() && !inDnD ) ||
01532      isReadOnly() )
01533     return;
01534 
01535     QPainter p( viewport() );
01536     QRect r( cursor->topParagraph()->rect() );
01537     cursor->paragraph()->setChanged( TRUE );
01538     p.translate( -contentsX() + cursor->totalOffsetX(), -contentsY() + cursor->totalOffsetY() );
01539     QPixmap *pix = 0;
01540     QColorGroup cg( colorGroup() );
01541     if ( cursor->paragraph()->background() )
01542     cg.setBrush( QColorGroup::Base, *cursor->paragraph()->background() );
01543     else if ( doc->paper() )
01544     cg.setBrush( QColorGroup::Base, *doc->paper() );
01545     p.setBrushOrigin( -contentsX(), -contentsY() );
01546     cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
01547     if ( !cursor->nestedDepth() ) {
01548     int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
01549     int dist = 5;
01550     if ( ( cursor->paragraph()->alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify )
01551         dist = 50;
01552     int x = r.x() - cursor->totalOffsetX() + cursor->x() - dist;
01553     x = QMAX( x, 0 );
01554     p.setClipRect( QRect( x - contentsX(),
01555                   r.y() - cursor->totalOffsetY() + cursor->y() - contentsY(), 2 * dist, h ) );
01556     doc->drawParagraph( &p, cursor->paragraph(), x,
01557             r.y() - cursor->totalOffsetY() + cursor->y(), 2 * dist, h, pix, cg, visible, cursor );
01558     } else {
01559     doc->drawParagraph( &p, cursor->paragraph(), r.x() - cursor->totalOffsetX(),
01560             r.y() - cursor->totalOffsetY(), r.width(), r.height(),
01561             pix, cg, visible, cursor );
01562     }
01563     cursorVisible = visible;
01564 }
01565 
01566 enum {
01567     IdUndo = 0,
01568     IdRedo = 1,
01569     IdCut = 2,
01570     IdCopy = 3,
01571     IdPaste = 4,
01572     IdClear = 5,
01573     IdSelectAll = 6
01574 };
01575 
01577 #ifndef QT_NO_WHEELEVENT
01578 void QTextEdit::contentsWheelEvent( QWheelEvent *e )
01579 {
01580     if ( isReadOnly() ) {
01581     if ( e->state() & ControlButton ) {
01582         if ( e->delta() > 0 )
01583         zoomOut();
01584         else if ( e->delta() < 0 )
01585         zoomIn();
01586         return;
01587     }
01588     }
01589     QScrollView::contentsWheelEvent( e );
01590 }
01591 #endif
01592 
01595 void QTextEdit::contentsMousePressEvent( QMouseEvent *e )
01596 {
01597     clearUndoRedo();
01598     QTextCursor oldCursor = *cursor;
01599     QTextCursor c = *cursor;
01600     mousePos = e->pos();
01601     mightStartDrag = FALSE;
01602     pressedLink = QString::null;
01603 
01604     if ( e->button() == LeftButton ) {
01605     mousePressed = TRUE;
01606     drawCursor( FALSE );
01607     placeCursor( e->pos() );
01608     ensureCursorVisible();
01609 
01610     if ( isReadOnly() && linksEnabled() ) {
01611         QTextCursor c = *cursor;
01612         placeCursor( e->pos(), &c, TRUE );
01613         if ( c.paragraph() && c.paragraph()->at( c.index() ) &&
01614          c.paragraph()->at( c.index() )->isAnchor() ) {
01615         pressedLink = c.paragraph()->at( c.index() )->anchorHref();
01616         }
01617     }
01618 
01619 #ifndef QT_NO_DRAGANDDROP
01620     if ( doc->inSelection( QTextDocument::Standard, e->pos() ) ) {
01621         mightStartDrag = TRUE;
01622         drawCursor( TRUE );
01623         dragStartTimer->start( QApplication::startDragTime(), TRUE );
01624         dragStartPos = e->pos();
01625         return;
01626     }
01627 #endif
01628 
01629     bool redraw = FALSE;
01630     if ( doc->hasSelection( QTextDocument::Standard ) ) {
01631         if ( !( e->state() & ShiftButton ) ) {
01632         redraw = doc->removeSelection( QTextDocument::Standard );
01633         doc->setSelectionStart( QTextDocument::Standard, *cursor );
01634         } else {
01635         redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
01636         }
01637     } else {
01638         if ( isReadOnly() || !( e->state() & ShiftButton ) ) {
01639         doc->setSelectionStart( QTextDocument::Standard, *cursor );
01640         } else {
01641         doc->setSelectionStart( QTextDocument::Standard, c );
01642         redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
01643         }
01644     }
01645 
01646     for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
01647         redraw = doc->removeSelection( i ) || redraw;
01648 
01649     if ( !redraw ) {
01650         drawCursor( TRUE );
01651     } else {
01652         repaintChanged();
01653 #ifndef QT_NO_CURSOR
01654         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
01655 #endif
01656     }
01657     } else if ( e->button() == MidButton ) {
01658     bool redraw = doc->removeSelection( QTextDocument::Standard );
01659     if ( !redraw ) {
01660         drawCursor( TRUE );
01661     } else {
01662         repaintChanged();
01663 #ifndef QT_NO_CURSOR
01664         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
01665 #endif
01666     }
01667     }
01668 
01669     if ( *cursor != oldCursor )
01670     updateCurrentFormat();
01671 }
01672 
01675 void QTextEdit::contentsMouseMoveEvent( QMouseEvent *e )
01676 {
01677     if ( mousePressed ) {
01678 #ifndef QT_NO_DRAGANDDROP
01679     if ( mightStartDrag ) {
01680         dragStartTimer->stop();
01681         if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() )
01682         startDrag();
01683 #ifndef QT_NO_CURSOR
01684         if ( !isReadOnly() )
01685         viewport()->setCursor( ibeamCursor );
01686 #endif
01687         return;
01688     }
01689 #endif
01690     mousePos = e->pos();
01691     handleMouseMove( mousePos );
01692     oldMousePos = mousePos;
01693     }
01694 
01695 #ifndef QT_NO_CURSOR
01696     if ( !isReadOnly() && !mousePressed ) {
01697     if ( doc->hasSelection( QTextDocument::Standard ) && doc->inSelection( QTextDocument::Standard, e->pos() ) )
01698         viewport()->setCursor( arrowCursor );
01699     else
01700         viewport()->setCursor( ibeamCursor );
01701     }
01702 #endif
01703     updateCursor( e->pos() );
01704 }
01705 
01708 void QTextEdit::contentsMouseReleaseEvent( QMouseEvent * e )
01709 {
01710     QTextCursor oldCursor = *cursor;
01711     if ( scrollTimer->isActive() )
01712     scrollTimer->stop();
01713 #ifndef QT_NO_DRAGANDDROP
01714     if ( dragStartTimer->isActive() )
01715     dragStartTimer->stop();
01716     if ( mightStartDrag ) {
01717     selectAll( FALSE );
01718     mousePressed = FALSE;
01719     }
01720 #endif
01721     if ( mousePressed ) {
01722     mousePressed = FALSE;
01723     }
01724     emit cursorPositionChanged( cursor );
01725     emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
01726     if ( oldCursor != *cursor )
01727     updateCurrentFormat();
01728     inDoubleClick = FALSE;
01729 
01730 #ifndef QT_NO_NETWORKPROTOCOL
01731     if ( !onLink.isEmpty() && onLink == pressedLink && linksEnabled() ) {
01732     QUrl u( doc->context(), onLink, TRUE );
01733     emitLinkClicked( u.toString( FALSE, FALSE ) );
01734 
01735     // emitting linkClicked() may result in that the cursor winds
01736     // up hovering over a different valid link - check this and
01737     // set the appropriate cursor shape
01738     updateCursor( e->pos() );
01739     }
01740 #endif
01741     drawCursor( TRUE );
01742     if ( !doc->hasSelection( QTextDocument::Standard, TRUE ) )
01743     doc->removeSelection( QTextDocument::Standard );
01744 
01745     emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
01746     emit selectionChanged();
01747 }
01748 
01751 void QTextEdit::contentsMouseDoubleClickEvent( QMouseEvent * )
01752 {
01753     QTextCursor c1 = *cursor;
01754     QTextCursor c2 = *cursor;
01755     if ( cursor->index() > 0 && !cursor->paragraph()->at( cursor->index()-1 )->c.isSpace() )
01756     c1.gotoPreviousWord();
01757     if ( !cursor->paragraph()->at( cursor->index() )->c.isSpace() && !cursor->atParagEnd() )
01758     c2.gotoNextWord();
01759 
01760     doc->setSelectionStart( QTextDocument::Standard, c1 );
01761     doc->setSelectionEnd( QTextDocument::Standard, c2 );
01762 
01763     *cursor = c2;
01764 
01765     repaintChanged();
01766 
01767     inDoubleClick = TRUE;
01768     mousePressed = TRUE;
01769 }
01770 
01771 #ifndef QT_NO_DRAGANDDROP
01772 
01775 void QTextEdit::contentsDragEnterEvent( QDragEnterEvent *e )
01776 {
01777     if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
01778     e->ignore();
01779     return;
01780     }
01781     e->acceptAction();
01782     inDnD = TRUE;
01783 }
01784 
01787 void QTextEdit::contentsDragMoveEvent( QDragMoveEvent *e )
01788 {
01789     if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
01790     e->ignore();
01791     return;
01792     }
01793     drawCursor( FALSE );
01794     placeCursor( e->pos(),  cursor );
01795     drawCursor( TRUE );
01796     e->acceptAction();
01797 }
01798 
01801 void QTextEdit::contentsDragLeaveEvent( QDragLeaveEvent * )
01802 {
01803     inDnD = FALSE;
01804 }
01805 
01808 void QTextEdit::contentsDropEvent( QDropEvent *e )
01809 {
01810     if ( isReadOnly() )
01811     return;
01812     inDnD = FALSE;
01813     e->acceptAction();
01814     QString text;
01815     bool intern = FALSE;
01816     if ( QTextDrag::decode( e, text ) ) {
01817     bool hasSel = doc->hasSelection( QTextDocument::Standard );
01818     bool internalDrag = e->source() == this || e->source() == viewport();
01819     int dropId, dropIndex;
01820     QTextCursor insertCursor = *cursor;
01821     dropId = cursor->paragraph()->paragId();
01822     dropIndex = cursor->index();
01823     if ( hasSel && internalDrag ) {
01824         QTextCursor c1, c2;
01825         int selStartId, selStartIndex;
01826         int selEndId, selEndIndex;
01827         c1 = doc->selectionStartCursor( QTextDocument::Standard );
01828         c1.restoreState();
01829         c2 = doc->selectionEndCursor( QTextDocument::Standard );
01830         c2.restoreState();
01831         selStartId = c1.paragraph()->paragId();
01832         selStartIndex = c1.index();
01833         selEndId = c2.paragraph()->paragId();
01834         selEndIndex = c2.index();
01835         if ( ( ( dropId > selStartId ) ||
01836            ( dropId == selStartId && dropIndex > selStartIndex ) ) &&
01837          ( ( dropId < selEndId ) ||
01838            ( dropId == selEndId && dropIndex <= selEndIndex ) ) )
01839         insertCursor = c1;
01840         if ( dropId == selEndId && dropIndex > selEndIndex ) {
01841         insertCursor = c1;
01842         if ( selStartId == selEndId ) {
01843             insertCursor.setIndex( dropIndex -
01844                        ( selEndIndex - selStartIndex ) );
01845         } else {
01846             insertCursor.setIndex( dropIndex - selEndIndex +
01847                        selStartIndex );
01848         }
01849         }
01850      }
01851 
01852     if ( internalDrag && e->action() == QDropEvent::Move ) {
01853         removeSelectedText();
01854         intern = TRUE;
01855     } else {
01856         doc->removeSelection( QTextDocument::Standard );
01857 #ifndef QT_NO_CURSOR
01858         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
01859 #endif
01860     }
01861     drawCursor( FALSE );
01862     cursor->setParagraph( insertCursor.paragraph() );
01863     cursor->setIndex( insertCursor.index() );
01864     drawCursor( TRUE );
01865     if ( !cursor->nestedDepth() ) {
01866         insert( text, FALSE, TRUE, FALSE );
01867     } else {
01868         if ( intern )
01869         undo();
01870         e->ignore();
01871     }
01872     }
01873 }
01874 
01875 #endif
01876 
01877 void QTextEdit::autoScrollTimerDone()
01878 {
01879     if ( mousePressed )
01880     handleMouseMove(  viewportToContents( viewport()->mapFromGlobal( QCursor::pos() )  ) );
01881 }
01882 
01883 void QTextEdit::handleMouseMove( const QPoint& pos )
01884 {
01885     if ( !mousePressed )
01886     return;
01887 
01888     if ( !scrollTimer->isActive() && pos.y() < contentsY() || pos.y() > contentsY() + visibleHeight() )
01889     scrollTimer->start( 100, FALSE );
01890     else if ( scrollTimer->isActive() && pos.y() >= contentsY() && pos.y() <= contentsY() + visibleHeight() )
01891     scrollTimer->stop();
01892 
01893     drawCursor( FALSE );
01894     QTextCursor oldCursor = *cursor;
01895 
01896     placeCursor( pos );
01897 
01898     if ( inDoubleClick ) {
01899     QTextCursor cl = *cursor;
01900     cl.gotoPreviousWord();
01901     QTextCursor cr = *cursor;
01902     cr.gotoNextWord();
01903 
01904     int diff = QABS( oldCursor.paragraph()->at( oldCursor.index() )->x - mousePos.x() );
01905     int ldiff = QABS( cl.paragraph()->at( cl.index() )->x - mousePos.x() );
01906     int rdiff = QABS( cr.paragraph()->at( cr.index() )->x - mousePos.x() );
01907 
01908 
01909     if ( cursor->paragraph()->lineStartOfChar( cursor->index() ) !=
01910          oldCursor.paragraph()->lineStartOfChar( oldCursor.index() ) )
01911         diff = 0xFFFFFF;
01912 
01913     if ( rdiff < diff && rdiff < ldiff )
01914         *cursor = cr;
01915     else if ( ldiff < diff && ldiff < rdiff )
01916         *cursor = cl;
01917     else
01918         *cursor = oldCursor;
01919 
01920     }
01921     ensureCursorVisible();
01922 
01923     bool redraw = FALSE;
01924     if ( doc->hasSelection( QTextDocument::Standard ) ) {
01925     redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
01926     }
01927 
01928     if ( !redraw ) {
01929     drawCursor( TRUE );
01930     } else {
01931     repaintChanged();
01932     drawCursor( TRUE );
01933     }
01934 
01935     if ( currentFormat && currentFormat->key() != cursor->paragraph()->at( cursor->index() )->format()->key() ) {
01936     currentFormat->removeRef();
01937     currentFormat = doc->formatCollection()->format( cursor->paragraph()->at( cursor->index() )->format() );
01938     if ( currentFormat->isMisspelled() ) {
01939         currentFormat->removeRef();
01940         currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
01941     }
01942     emit currentFontChanged( currentFormat->font() );
01943     emit currentColorChanged( currentFormat->color() );
01944     emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
01945     }
01946 
01947     if ( currentAlignment != cursor->paragraph()->alignment() ) {
01948     currentAlignment = cursor->paragraph()->alignment();
01949     block_set_alignment = TRUE;
01950     emit currentAlignmentChanged( currentAlignment );
01951     block_set_alignment = FALSE;
01952     }
01953 }
01954 
01964 void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c, bool link )
01965 {
01966     if ( !c )
01967     c = cursor;
01968 
01969     c->restoreState();
01970     QTextParagraph *s = doc->firstParagraph();
01971     c->place( pos, s, link );
01972     updateMicroFocusHint();
01973 }
01974 
01975 
01976 void QTextEdit::updateMicroFocusHint()
01977 {
01978     QTextCursor c( *cursor );
01979     if ( d->preeditStart != -1 )
01980     c.setIndex( d->preeditStart );
01981 
01982     if ( hasFocus() || viewport()->hasFocus() ) {
01983     int h = c.paragraph()->lineHeightOfChar( cursor->index() );
01984     if ( !readonly ) {
01985         QFont f = c.paragraph()->at( c.index() )->format()->font();
01986         setMicroFocusHint( c.x() - contentsX() + frameWidth(),
01987                    c.y() + cursor->paragraph()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
01988     }
01989     }
01990 }
01991 
01992 
01993 
01994 void QTextEdit::formatMore()
01995 {
01996     if ( !lastFormatted )
01997     return;
01998 
01999     int bottom = contentsHeight();
02000     int lastBottom = -1;
02001     int to = 20;
02002     bool firstVisible = FALSE;
02003     QRect cr( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
02004     for ( int i = 0; ( i < to || firstVisible ) && lastFormatted; ++i ) {
02005     lastFormatted->format();
02006     if ( i == 0 )
02007         firstVisible = lastFormatted->rect().intersects( cr );
02008     else if ( firstVisible )
02009         firstVisible = lastFormatted->rect().intersects( cr );
02010     bottom = QMAX( bottom, lastFormatted->rect().top() +
02011                lastFormatted->rect().height() );
02012     lastBottom = lastFormatted->rect().top() + lastFormatted->rect().height();
02013     lastFormatted = lastFormatted->next();
02014     if ( lastFormatted )
02015         lastBottom = -1;
02016     }
02017 
02018     if ( bottom > contentsHeight() ) {
02019     resizeContents( contentsWidth(), QMAX( doc->height(), bottom ) );
02020     } else if ( lastBottom != -1 && lastBottom < contentsHeight() ) {
02021     resizeContents( contentsWidth(), QMAX( doc->height(), lastBottom ) );
02022     if ( contentsHeight() < visibleHeight() )
02023         updateContents( 0, contentsHeight(), visibleWidth(),
02024                 visibleHeight() - contentsHeight() );
02025     }
02026 
02027     if ( lastFormatted )
02028     formatTimer->start( interval, TRUE );
02029     else
02030     interval = QMAX( 0, interval );
02031 }
02032 
02033 void QTextEdit::doResize()
02034 {
02035     if ( wrapMode == FixedPixelWidth )
02036     return;
02037     doc->setMinimumWidth( -1 );
02038     resizeContents( 0, 0 );
02039     doc->setWidth( visibleWidth() );
02040     doc->invalidate();
02041     lastFormatted = doc->firstParagraph();
02042     interval = 0;
02043     formatMore();
02044     repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE );
02045 }
02046 
02049 void QTextEdit::doChangeInterval()
02050 {
02051     interval = 0;
02052 }
02053 
02056 bool QTextEdit::eventFilter( QObject *o, QEvent *e )
02057 {
02058     if ( o == this || o == viewport() ) {
02059     if ( e->type() == QEvent::FocusIn ) {
02060         blinkTimer->start( QApplication::cursorFlashTime() / 2 );
02061         drawCursor( TRUE );
02062         updateMicroFocusHint();
02063     } else if ( e->type() == QEvent::FocusOut ) {
02064         blinkTimer->stop();
02065         drawCursor( FALSE );
02066     }
02067     }
02068 
02069     return QScrollView::eventFilter( o, e );
02070 }
02071 
02084 void QTextEdit::insert( const QString &text, bool indent, bool checkNewLine, bool removeSelected )
02085 {
02086     if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
02087     return;
02088     QString txt( text );
02089     drawCursor( FALSE );
02090     if ( !isReadOnly() && doc->hasSelection( QTextDocument::Standard ) && removeSelected )
02091     removeSelectedText();
02092     QTextCursor c2 = *cursor;
02093     int oldLen = 0;
02094 
02095     if ( undoEnabled && !isReadOnly() ) {
02096     checkUndoRedoInfo( UndoRedoInfo::Insert );
02097     if ( !undoRedoInfo.valid() ) {
02098         undoRedoInfo.id = cursor->paragraph()->paragId();
02099         undoRedoInfo.index = cursor->index();
02100         undoRedoInfo.d->text = QString::null;
02101     }
02102     oldLen = undoRedoInfo.d->text.length();
02103     }
02104 
02105     lastFormatted = checkNewLine && cursor->paragraph()->prev() ?
02106             cursor->paragraph()->prev() : cursor->paragraph();
02107     QTextCursor oldCursor = *cursor;
02108     cursor->insert( txt, checkNewLine );
02109     if ( doc->useFormatCollection() ) {
02110     doc->setSelectionStart( QTextDocument::Temp, oldCursor );
02111     doc->setSelectionEnd( QTextDocument::Temp, *cursor );
02112     doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
02113     doc->removeSelection( QTextDocument::Temp );
02114     }
02115 
02116     if ( indent && ( txt == "{" || txt == "}" || txt == ":" || txt == "#" ) )
02117     cursor->indent();
02118     formatMore();
02119     repaintChanged();
02120     ensureCursorVisible();
02121     drawCursor( TRUE );
02122 
02123     if ( undoEnabled && !isReadOnly() ) {
02124     undoRedoInfo.d->text += txt;
02125     if ( !doc->preProcessor() ) {
02126         for ( int i = 0; i < (int)txt.length(); ++i ) {
02127         if ( txt[ i ] != '\n' && c2.paragraph()->at( c2.index() )->format() ) {
02128             c2.paragraph()->at( c2.index() )->format()->addRef();
02129             undoRedoInfo.d->text.setFormat( oldLen + i, c2.paragraph()->at( c2.index() )->format(), TRUE );
02130         }
02131         c2.gotoNextLetter();
02132         }
02133     }
02134     }
02135 
02136     if ( !removeSelected ) {
02137     doc->setSelectionStart( QTextDocument::Standard, oldCursor );
02138     doc->setSelectionEnd( QTextDocument::Standard, *cursor );
02139     repaintChanged();
02140     }
02141     updateMicroFocusHint();
02142     setModified();
02143     emit textChanged();
02144 }
02145 
02148 void QTextEdit::insertAt( const QString &text, int para, int index )
02149 {
02150     removeSelection( QTextDocument::Standard );
02151     QTextParagraph *p = doc->paragAt( para );
02152     if ( !p )
02153     return;
02154     QTextCursor tmp = *cursor;
02155     cursor->setParagraph( p );
02156     cursor->setIndex( index );
02157     insert( text, FALSE, TRUE, FALSE );
02158     *cursor = tmp;
02159     removeSelection( QTextDocument::Standard );
02160 }
02161 
02166 void QTextEdit::insertParagraph( const QString &text, int para )
02167 {
02168     QTextParagraph *p = doc->paragAt( para );
02169     if ( p ) {
02170     QTextCursor tmp( doc );
02171     tmp.setParagraph( p );
02172     tmp.setIndex( 0 );
02173     tmp.insert( text, TRUE );
02174     tmp.splitAndInsertEmptyParagraph();
02175     repaintChanged();
02176     } else {
02177     append( text );
02178     }
02179 }
02180 
02183 void QTextEdit::removeParagraph( int para )
02184 {
02185     QTextParagraph *p = doc->paragAt( para );
02186     if ( !p )
02187     return;
02188     for ( int i = 0; i < doc->numSelections(); ++i )
02189     doc->removeSelection( i );
02190 
02191     if ( p == doc->firstParagraph() && p == doc->lastParagraph() ) {
02192     p->remove( 0, p->length() - 1 );
02193     repaintChanged();
02194     return;
02195     }
02196     drawCursor( FALSE );
02197     bool resetCursor = cursor->paragraph() == p;
02198     if ( p->prev() )
02199     p->prev()->setNext( p->next() );
02200     else
02201     doc->setFirstParagraph( p->next() );
02202     if ( p->next() )
02203     p->next()->setPrev( p->prev() );
02204     else
02205     doc->setLastParagraph( p->prev() );
02206     QTextParagraph *start = p->next();
02207     int h = p->rect().height();
02208     delete p;
02209     p = start;
02210     int dy = -h;
02211     while ( p ) {
02212     p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
02213     p->move( dy );
02214     p->invalidate( 0 );
02215     p->setEndState( -1 );
02216     p = p->next();
02217     }
02218 
02219     if ( resetCursor ) {
02220     cursor->setParagraph( doc->firstParagraph() );
02221     cursor->setIndex( 0 );
02222     }
02223     repaintChanged();
02224     drawCursor( TRUE );
02225 }
02226 
02236 void QTextEdit::undo()
02237 {
02238     // XXX FIXME The next line is here because there may be a command
02239     // that needs to be 'flushed'.  The FIXME is because I am not
02240     // 100% certain this is the right call to do this.
02241     clearUndoRedo();
02242     if ( isReadOnly() || !doc->commands()->isUndoAvailable() || !undoEnabled )
02243     return;
02244 
02245     for ( int i = 0; i < (int)doc->numSelections(); ++i )
02246     doc->removeSelection( i );
02247 
02248 #ifndef QT_NO_CURSOR
02249     viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
02250 #endif
02251 
02252     clearUndoRedo();
02253     drawCursor( FALSE );
02254     QTextCursor *c = doc->undo( cursor );
02255     if ( !c ) {
02256     drawCursor( TRUE );
02257     return;
02258     }
02259     lastFormatted = 0;
02260     ensureCursorVisible();
02261     repaintChanged();
02262     drawCursor( TRUE );
02263     updateMicroFocusHint();
02264     setModified();
02265     emit textChanged();
02266 }
02267 
02277 void QTextEdit::redo()
02278 {
02279     if ( isReadOnly() || !doc->commands()->isRedoAvailable() || !undoEnabled )
02280     return;
02281 
02282     for ( int i = 0; i < (int)doc->numSelections(); ++i )
02283     doc->removeSelection( i );
02284 
02285 #ifndef QT_NO_CURSOR
02286     viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
02287 #endif
02288 
02289     clearUndoRedo();
02290     drawCursor( FALSE );
02291     QTextCursor *c = doc->redo( cursor );
02292     if ( !c ) {
02293     drawCursor( TRUE );
02294     return;
02295     }
02296     lastFormatted = 0;
02297     ensureCursorVisible();
02298     repaintChanged();
02299     ensureCursorVisible();
02300     drawCursor( TRUE );
02301     updateMicroFocusHint();
02302     setModified();
02303     emit textChanged();
02304 }
02305 
02315 void QTextEdit::paste()
02316 {
02317 #ifndef QT_NO_CLIPBOARD
02318     if ( isReadOnly() )
02319     return;
02320     pasteSubType( "plain" );
02321     updateMicroFocusHint();
02322 #endif
02323 }
02324 
02325 void QTextEdit::checkUndoRedoInfo( UndoRedoInfo::Type t )
02326 {
02327     if ( undoRedoInfo.valid() && t != undoRedoInfo.type ) {
02328     clearUndoRedo();
02329     }
02330     undoRedoInfo.type = t;
02331 }
02332 
02339 void QTextEdit::repaintChanged()
02340 {
02341     if ( !isUpdatesEnabled() || !viewport()->isUpdatesEnabled() )
02342     return;
02343     QPainter p( viewport() );
02344     p.translate( -contentsX(), -contentsY() );
02345     paintDocument( FALSE, &p, contentsX(), contentsY(), visibleWidth(), visibleHeight() );
02346 }
02347 
02357 void QTextEdit::cut()
02358 {
02359     if ( isReadOnly() )
02360     return;
02361 
02362     QString t;
02363     if ( doc->hasSelection( QTextDocument::Standard ) &&
02364      !( t = doc->selectedText( QTextDocument::Standard, qt_enable_richtext_copy ) ).isEmpty() ) {
02365     QApplication::clipboard()->setText( t );
02366     removeSelectedText();
02367     }
02368     updateMicroFocusHint();
02369 }
02370 
02376 void QTextEdit::copy()
02377 {
02378     QString t = doc->selectedText( QTextDocument::Standard, qt_enable_richtext_copy );
02379     if ( doc->hasSelection( QTextDocument::Standard ) &&
02380      !t.isEmpty() && t.simplifyWhiteSpace() != "<selstart/>" )
02381     QApplication::clipboard()->setText( t );
02382 }
02383 
02388 void QTextEdit::indent()
02389 {
02390     if ( isReadOnly() )
02391     return;
02392 
02393     drawCursor( FALSE );
02394     if ( !doc->hasSelection( QTextDocument::Standard ) )
02395     cursor->indent();
02396     else
02397     doc->indentSelection( QTextDocument::Standard );
02398     repaintChanged();
02399     drawCursor( TRUE );
02400     setModified();
02401     emit textChanged();
02402 }
02403 
02410 bool QTextEdit::focusNextPrevChild( bool n )
02411 {
02412     if ( !isReadOnly() || !linksEnabled() )
02413     return FALSE;
02414     bool b = doc->focusNextPrevChild( n );
02415     repaintChanged();
02416     if ( b )
02417     //##### this does not work with tables. The focusIndicator
02418     //should really be a QTextCursor. Fix 3.1
02419     makeParagVisible( doc->focusIndicator.parag );
02420     return b;
02421 }
02422 
02430 void QTextEdit::setFormat( QTextFormat *f, int flags )
02431 {
02432     if ( doc->hasSelection( QTextDocument::Standard ) ) {
02433     drawCursor( FALSE );
02434     QTextCursor c1 = doc->selectionStartCursor( QTextDocument::Standard );
02435     c1.restoreState();
02436     QTextCursor c2 = doc->selectionEndCursor( QTextDocument::Standard );
02437     c2.restoreState();
02438     clearUndoRedo();
02439     undoRedoInfo.type = UndoRedoInfo::Format;
02440     undoRedoInfo.id = c1.paragraph()->paragId();
02441     undoRedoInfo.index = c1.index();
02442     undoRedoInfo.eid = c2.paragraph()->paragId();
02443     undoRedoInfo.eindex = c2.index();
02444     readFormats( c1, c2, undoRedoInfo.d->text );
02445     undoRedoInfo.format = f;
02446     undoRedoInfo.flags = flags;
02447     clearUndoRedo();
02448     doc->setFormat( QTextDocument::Standard, f, flags );
02449     repaintChanged();
02450     formatMore();
02451     drawCursor( TRUE );
02452     setModified();
02453     emit textChanged();
02454     }
02455     if ( currentFormat && currentFormat->key() != f->key() ) {
02456     currentFormat->removeRef();
02457     currentFormat = doc->formatCollection()->format( f );
02458     if ( currentFormat->isMisspelled() ) {
02459         currentFormat->removeRef();
02460         currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
02461     }
02462     emit currentFontChanged( currentFormat->font() );
02463     emit currentColorChanged( currentFormat->color() );
02464     emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
02465     if ( cursor->index() == cursor->paragraph()->length() - 1 ) {
02466         currentFormat->addRef();
02467         cursor->paragraph()->string()->setFormat( cursor->index(), currentFormat, TRUE );
02468         if ( cursor->paragraph()->length() == 1 ) {
02469         cursor->paragraph()->invalidate( 0 );
02470         cursor->paragraph()->format();
02471         repaintChanged();
02472         }
02473     }
02474     }
02475 }
02476 
02479 void QTextEdit::setPalette( const QPalette &p )
02480 {
02481     QScrollView::setPalette( p );
02482     if ( textFormat() == PlainText ) {
02483     QTextFormat *f = doc->formatCollection()->defaultFormat();
02484     f->setColor( colorGroup().text() );
02485     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
02486     }
02487 }
02488 
02502 void QTextEdit::setParagType( QStyleSheetItem::DisplayMode dm, QStyleSheetItem::ListStyle listStyle )
02503 {
02504     if ( isReadOnly() )
02505     return;
02506 
02507     drawCursor( FALSE );
02508     QTextParagraph *start = cursor->paragraph();
02509     QTextParagraph *end = start;
02510     if ( doc->hasSelection( QTextDocument::Standard ) ) {
02511     start = doc->selectionStartCursor( QTextDocument::Standard ).topParagraph();
02512     end = doc->selectionEndCursor( QTextDocument::Standard ).topParagraph();
02513     if ( end->paragId() < start->paragId() )
02514         return; // do not trust our selections
02515     }
02516 
02517     clearUndoRedo();
02518     undoRedoInfo.type = UndoRedoInfo::Style;
02519     undoRedoInfo.id = start->paragId();
02520     undoRedoInfo.eid = end->paragId();
02521     undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
02522 
02523     while ( start != end->next() ) {
02524     start->setListStyle( listStyle );
02525     if ( dm == QStyleSheetItem::DisplayListItem ) {
02526         start->setListItem( TRUE );
02527         if( start->listDepth() == 0 )
02528         start->setListDepth( 1 );
02529     } else if ( start->isListItem() ) {
02530         start->setListItem( FALSE );
02531         start->setListDepth( QMAX( start->listDepth()-1, 0 ) );
02532     }
02533     start = start->next();
02534     }
02535 
02536     clearUndoRedo();
02537     repaintChanged();
02538     formatMore();
02539     drawCursor( TRUE );
02540     setModified();
02541     emit textChanged();
02542 }
02543 
02551 void QTextEdit::setAlignment( int a )
02552 {
02553     if ( isReadOnly() || block_set_alignment )
02554     return;
02555 
02556     drawCursor( FALSE );
02557     QTextParagraph *start = cursor->paragraph();
02558     QTextParagraph *end = start;
02559     if ( doc->hasSelection( QTextDocument::Standard ) ) {
02560     start = doc->selectionStartCursor( QTextDocument::Standard ).topParagraph();
02561     end = doc->selectionEndCursor( QTextDocument::Standard ).topParagraph();
02562     if ( end->paragId() < start->paragId() )
02563         return; // do not trust our selections
02564     }
02565 
02566     clearUndoRedo();
02567     undoRedoInfo.type = UndoRedoInfo::Style;
02568     undoRedoInfo.id = start->paragId();
02569     undoRedoInfo.eid = end->paragId();
02570     undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
02571 
02572     while ( start != end->next() ) {
02573     start->setAlignment( a );
02574     start = start->next();
02575     }
02576 
02577     clearUndoRedo();
02578     repaintChanged();
02579     formatMore();
02580     drawCursor( TRUE );
02581     if ( currentAlignment != a ) {
02582     currentAlignment = a;
02583     emit currentAlignmentChanged( currentAlignment );
02584     }
02585     setModified();
02586     emit textChanged();
02587 }
02588 
02589 void QTextEdit::updateCurrentFormat()
02590 {
02591     int i = cursor->index();
02592     if ( i > 0 )
02593     --i;
02594     if ( doc->useFormatCollection() &&
02595      ( !currentFormat || currentFormat->key() != cursor->paragraph()->at( i )->format()->key() ) ) {
02596     if ( currentFormat )
02597         currentFormat->removeRef();
02598     currentFormat = doc->formatCollection()->format( cursor->paragraph()->at( i )->format() );
02599     if ( currentFormat->isMisspelled() ) {
02600         currentFormat->removeRef();
02601         currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
02602     }
02603     emit currentFontChanged( currentFormat->font() );
02604     emit currentColorChanged( currentFormat->color() );
02605     emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
02606     }
02607 
02608     if ( currentAlignment != cursor->paragraph()->alignment() ) {
02609     currentAlignment = cursor->paragraph()->alignment();
02610     block_set_alignment = TRUE;
02611     emit currentAlignmentChanged( currentAlignment );
02612     block_set_alignment = FALSE;
02613     }
02614 }
02615 
02623 void QTextEdit::setItalic( bool b )
02624 {
02625     QTextFormat f( *currentFormat );
02626     f.setItalic( b );
02627     QTextFormat *f2 = doc->formatCollection()->format( &f );
02628     setFormat( f2, QTextFormat::Italic );
02629 }
02630 
02638 void QTextEdit::setBold( bool b )
02639 {
02640     QTextFormat f( *currentFormat );
02641     f.setBold( b );
02642     QTextFormat *f2 = doc->formatCollection()->format( &f );
02643     setFormat( f2, QTextFormat::Bold );
02644 }
02645 
02653 void QTextEdit::setUnderline( bool b )
02654 {
02655     QTextFormat f( *currentFormat );
02656     f.setUnderline( b );
02657     QTextFormat *f2 = doc->formatCollection()->format( &f );
02658     setFormat( f2, QTextFormat::Underline );
02659 }
02660 
02667 void QTextEdit::setFamily( const QString &fontFamily )
02668 {
02669     QTextFormat f( *currentFormat );
02670     f.setFamily( fontFamily );
02671     QTextFormat *f2 = doc->formatCollection()->format( &f );
02672     setFormat( f2, QTextFormat::Family );
02673 }
02674 
02684 void QTextEdit::setPointSize( int s )
02685 {
02686     QTextFormat f( *currentFormat );
02687     f.setPointSize( s );
02688     QTextFormat *f2 = doc->formatCollection()->format( &f );
02689     setFormat( f2, QTextFormat::Size );
02690 }
02691 
02698 void QTextEdit::setColor( const QColor &c )
02699 {
02700     QTextFormat f( *currentFormat );
02701     f.setColor( c );
02702     QTextFormat *f2 = doc->formatCollection()->format( &f );
02703     setFormat( f2, QTextFormat::Color );
02704 }
02705 
02712 void QTextEdit::setVerticalAlignment( VerticalAlignment a )
02713 {
02714     QTextFormat f( *currentFormat );
02715     f.setVAlign( (QTextFormat::VerticalAlignment)a );
02716     QTextFormat *f2 = doc->formatCollection()->format( &f );
02717     setFormat( f2, QTextFormat::VAlign );
02718 }
02719 
02720 void QTextEdit::setFontInternal( const QFont &f_ )
02721 {
02722     QTextFormat f( *currentFormat );
02723     f.setFont( f_ );
02724     QTextFormat *f2 = doc->formatCollection()->format( &f );
02725     setFormat( f2, QTextFormat::Font );
02726 }
02727 
02728 
02729 QString QTextEdit::text() const
02730 {
02731     if ( isReadOnly() )
02732     return doc->originalText();
02733     return doc->text();
02734 }
02735 
02744 QString QTextEdit::text( int para ) const
02745 {
02746     return doc->text( para );
02747 }
02748 
02769 void QTextEdit::setText( const QString &text, const QString &context )
02770 {
02771     if ( !isModified() && isReadOnly() &&
02772      this->context() == context && this->text() == text )
02773     return;
02774 
02775     emit undoAvailable( FALSE );
02776     emit redoAvailable( FALSE );
02777     undoRedoInfo.clear();
02778     doc->commands()->clear();
02779 
02780     lastFormatted = 0;
02781     cursor->restoreState();
02782     doc->setText( text, context );
02783 
02784     if ( wrapMode == FixedPixelWidth ) {
02785     resizeContents( wrapWidth, 0 );
02786     doc->setWidth( wrapWidth );
02787     doc->setMinimumWidth( wrapWidth );
02788     } else {
02789     doc->setMinimumWidth( -1 );
02790     resizeContents( 0, 0 );
02791     }
02792 
02793     lastFormatted = doc->firstParagraph();
02794     delete cursor;
02795     cursor = new QTextCursor( doc );
02796     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
02797 
02798     if ( isModified() )
02799     setModified( FALSE );
02800     emit textChanged();
02801     formatMore();
02802     updateCurrentFormat();
02803     d->scrollToAnchor = QString::null;
02804 }
02805 
02863 bool QTextEdit::find( const QString &expr, bool cs, bool wo, bool forward,
02864               int *para, int *index )
02865 {
02866     drawCursor( FALSE );
02867 #ifndef QT_NO_CURSOR
02868     viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
02869 #endif
02870     QTextCursor findcur = *cursor;
02871     if ( para && index ) {
02872     if ( doc->paragAt( *para ) )
02873         findcur.gotoPosition( doc->paragAt(*para), *index );
02874     else
02875         findcur.gotoEnd();
02876     } else if ( doc->hasSelection( QTextDocument::Standard ) ){
02877     // maks sure we do not find the same selection again
02878     if ( forward )
02879         findcur.gotoNextLetter();
02880     else
02881         findcur.gotoPreviousLetter();
02882     }
02883     removeSelection( QTextDocument::Standard );
02884     bool found = doc->find( findcur, expr, cs, wo, forward );
02885     if ( found ) {
02886     if ( para )
02887         *para = findcur.paragraph()->paragId();
02888     if ( index )
02889         *index = findcur.index();
02890     *cursor = findcur;
02891     repaintChanged();
02892     ensureCursorVisible();
02893     }
02894     drawCursor( TRUE );
02895     return found;
02896 }
02897 
02898 void QTextEdit::blinkCursor()
02899 {
02900     if ( !cursorVisible )
02901     return;
02902     bool cv = cursorVisible;
02903     blinkCursorVisible = !blinkCursorVisible;
02904     drawCursor( blinkCursorVisible );
02905     cursorVisible = cv;
02906 }
02907 
02914 void QTextEdit::setCursorPosition( int para, int index )
02915 {
02916     QTextParagraph *p = doc->paragAt( para );
02917     if ( !p )
02918     return;
02919 
02920     if ( index > p->length() - 1 )
02921     index = p->length() - 1;
02922 
02923     drawCursor( FALSE );
02924     cursor->setParagraph( p );
02925     cursor->setIndex( index );
02926     ensureCursorVisible();
02927     drawCursor( TRUE );
02928     updateCurrentFormat();
02929     emit cursorPositionChanged( cursor );
02930     emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
02931 }
02932 
02941 void QTextEdit::getCursorPosition( int *para, int *index ) const
02942 {
02943     if ( !para || !index )
02944     return;
02945     *para = cursor->paragraph()->paragId();
02946     *index = cursor->index();
02947 }
02948 
02964 void QTextEdit::setSelection( int paraFrom, int indexFrom,
02965                   int paraTo, int indexTo, int selNum )
02966 {
02967     if ( doc->hasSelection( selNum ) ) {
02968     doc->removeSelection( selNum );
02969     repaintChanged();
02970     }
02971     if ( selNum > doc->numSelections() - 1 )
02972     doc->addSelection( selNum );
02973     QTextParagraph *p1 = doc->paragAt( paraFrom );
02974     if ( !p1 )
02975     return;
02976     QTextParagraph *p2 = doc->paragAt( paraTo );
02977     if ( !p2 )
02978     return;
02979 
02980     if ( indexFrom > p1->length() - 1 )
02981     indexFrom = p1->length() - 1;
02982     if ( indexTo > p2->length() - 1 )
02983     indexTo = p2->length() - 1;
02984 
02985     drawCursor( FALSE );
02986     QTextCursor c = *cursor;
02987     QTextCursor oldCursor = *cursor;
02988     c.setParagraph( p1 );
02989     c.setIndex( indexFrom );
02990     cursor->setParagraph( p2 );
02991     cursor->setIndex( indexTo );
02992     doc->setSelectionStart( selNum, c );
02993     doc->setSelectionEnd( selNum, *cursor );
02994     repaintChanged();
02995     ensureCursorVisible();
02996     if ( selNum != QTextDocument::Standard )
02997     *cursor = oldCursor;
02998     drawCursor( TRUE );
02999 }
03000 
03021 void QTextEdit::getSelection( int *paraFrom, int *indexFrom,
03022                   int *paraTo, int *indexTo, int selNum ) const
03023 {
03024     if ( !paraFrom || !paraTo || !indexFrom || !indexTo )
03025     return;
03026     if ( !doc->hasSelection( selNum ) ) {
03027     *paraFrom = -1;
03028     *indexFrom = -1;
03029     *paraTo = -1;
03030     *indexTo = -1;
03031     return;
03032     }
03033 
03034     doc->selectionStart( selNum, *paraFrom, *indexFrom );
03035     doc->selectionEnd( selNum, *paraTo, *indexTo );
03036 }
03037 
03055 void QTextEdit::setTextFormat( TextFormat format )
03056 {
03057     doc->setTextFormat( format );
03058 }
03059 
03060 Qt::TextFormat QTextEdit::textFormat() const
03061 {
03062     return doc->textFormat();
03063 }
03064 
03069 int QTextEdit::paragraphs() const
03070 {
03071     return doc->lastParagraph()->paragId() + 1;
03072 }
03073 
03079 int QTextEdit::linesOfParagraph( int para ) const
03080 {
03081     QTextParagraph *p = doc->paragAt( para );
03082     if ( !p )
03083     return -1;
03084     return p->lines();
03085 }
03086 
03092 int QTextEdit::paragraphLength( int para ) const
03093 {
03094     QTextParagraph *p = doc->paragAt( para );
03095     if ( !p )
03096     return -1;
03097     return p->length() - 1;
03098 }
03099 
03108 int QTextEdit::lines() const
03109 {
03110     QTextParagraph *p = doc->firstParagraph();
03111     int l = 0;
03112     while ( p ) {
03113     l += p->lines();
03114     p = p->next();
03115     }
03116 
03117     return l;
03118 }
03119 
03128 int QTextEdit::lineOfChar( int para, int index )
03129 {
03130     QTextParagraph *p = doc->paragAt( para );
03131     if ( !p )
03132     return -1;
03133 
03134     int idx, line;
03135     QTextStringChar *c = p->lineStartOfChar( index, &idx, &line );
03136     if ( !c )
03137     return -1;
03138 
03139     return line;
03140 }
03141 
03142 void QTextEdit::setModified( bool m )
03143 {
03144     bool oldModified = modified;
03145     modified = m;
03146     if ( modified && doc->oTextValid )
03147     doc->invalidateOriginalText();
03148     if ( oldModified != modified )
03149     emit modificationChanged( modified );
03150 }
03151 
03156 bool QTextEdit::isModified() const
03157 {
03158     return modified;
03159 }
03160 
03161 void QTextEdit::setModified()
03162 {
03163     if ( !isModified() )
03164     setModified( TRUE );
03165 }
03166 
03173 bool QTextEdit::italic() const
03174 {
03175     return currentFormat->font().italic();
03176 }
03177 
03184 bool QTextEdit::bold() const
03185 {
03186     return currentFormat->font().bold();
03187 }
03188 
03196 bool QTextEdit::underline() const
03197 {
03198     return currentFormat->font().underline();
03199 }
03200 
03207 QString QTextEdit::family() const
03208 {
03209     return currentFormat->font().family();
03210 }
03211 
03219 int QTextEdit::pointSize() const
03220 {
03221     return currentFormat->font().pointSize();
03222 }
03223 
03230 QColor QTextEdit::color() const
03231 {
03232     return currentFormat->color();
03233 }
03234 
03242 QFont QTextEdit::font() const
03243 {
03244     return currentFormat->font();
03245 }
03246 
03253 int QTextEdit::alignment() const
03254 {
03255     return currentAlignment;
03256 }
03257 
03258 void QTextEdit::startDrag()
03259 {
03260 #ifndef QT_NO_DRAGANDDROP
03261     mousePressed = FALSE;
03262     inDoubleClick = FALSE;
03263     QDragObject *drag = new QTextDrag( doc->selectedText( QTextDocument::Standard, qt_enable_richtext_copy ), viewport() );
03264     if ( isReadOnly() ) {
03265     drag->dragCopy();
03266     } else {
03267     if ( drag->drag() && QDragObject::target() != this && QDragObject::target() != viewport() )
03268         removeSelectedText();
03269     }
03270 #endif
03271 }
03272 
03282 void QTextEdit::selectAll( bool select )
03283 {
03284     if ( !select )
03285     doc->removeSelection( QTextDocument::Standard );
03286     else
03287     doc->selectAll( QTextDocument::Standard );
03288     repaintChanged();
03289     emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
03290     emit selectionChanged();
03291 #ifndef QT_NO_CURSOR
03292     viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
03293 #endif
03294 }
03295 
03296 void QTextEdit::UndoRedoInfo::clear()
03297 {
03298     if ( valid() ) {
03299     if ( type == Insert || type == Return )
03300         doc->addCommand( new QTextInsertCommand( doc, id, index, d->text.rawData(), styleInformation ) );
03301     else if ( type == Format )
03302         doc->addCommand( new QTextFormatCommand( doc, id, index, eid, eindex, d->text.rawData(), format, flags ) );
03303     else if ( type == Style )
03304         doc->addCommand( new QTextStyleCommand( doc, id, eid, styleInformation ) );
03305     else if ( type != Invalid ) {
03306         doc->addCommand( new QTextDeleteCommand( doc, id, index, d->text.rawData(), styleInformation ) );
03307     }
03308     }
03309     type = Invalid;
03310     d->text = QString::null;
03311     id = -1;
03312     index = -1;
03313     styleInformation = QByteArray();
03314 }
03315 
03316 
03326 void QTextEdit::del()
03327 {
03328     if ( doc->hasSelection( QTextDocument::Standard ) ) {
03329     removeSelectedText();
03330     return;
03331     }
03332 
03333     doKeyboardAction( ActionDelete );
03334 }
03335 
03336 
03337 QTextEdit::UndoRedoInfo::UndoRedoInfo( QTextDocument *dc )
03338     : type( Invalid ), doc( dc )
03339 {
03340     d = new QUndoRedoInfoPrivate;
03341     d->text = QString::null;
03342     id = -1;
03343     index = -1;
03344 }
03345 
03346 QTextEdit::UndoRedoInfo::~UndoRedoInfo()
03347 {
03348     delete d;
03349 }
03350 
03351 bool QTextEdit::UndoRedoInfo::valid() const
03352 {
03353     return id >= 0 &&  type != Invalid;
03354 }
03355 
03362 void QTextEdit::resetFormat()
03363 {
03364     setAlignment( Qt3::AlignAuto );
03365     setParagType( QStyleSheetItem::DisplayBlock, QStyleSheetItem::ListDisc );
03366     setFormat( doc->formatCollection()->defaultFormat(), QTextFormat::Format );
03367 }
03368 
03374 QStyleSheet* QTextEdit::styleSheet() const
03375 {
03376     return doc->styleSheet();
03377 }
03378 
03385 void QTextEdit::setStyleSheet( QStyleSheet* styleSheet )
03386 {
03387     doc->setStyleSheet( styleSheet );
03388 }
03389 
03398 void QTextEdit::setPaper( const QBrush& pap )
03399 {
03400     doc->setPaper( new QBrush( pap ) );
03401     viewport()->setBackgroundColor( pap.color() );
03402     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
03403 }
03404 
03405 QBrush QTextEdit::paper() const
03406 {
03407     if ( doc->paper() )
03408     return *doc->paper();
03409     return QBrush();
03410 }
03411 
03420 void QTextEdit::setLinkUnderline( bool b )
03421 {
03422     doc->setUnderlineLinks( b );
03423 }
03424 
03425 bool QTextEdit::linkUnderline() const
03426 {
03427     return doc->underlineLinks();
03428 }
03429 
03436 void QTextEdit::setMimeSourceFactory( QMimeSourceFactory* factory )
03437 {
03438     doc->setMimeSourceFactory( factory );
03439 }
03440 
03447 QMimeSourceFactory* QTextEdit::mimeSourceFactory() const
03448 {
03449     return doc->mimeSourceFactory();
03450 }
03451 
03457 int QTextEdit::heightForWidth( int w ) const
03458 {
03459     int oldw = doc->width();
03460     doc->doLayout( 0, w );
03461     int h = doc->height();
03462     doc->setWidth( oldw );
03463     doc->invalidate();
03464     ( (QTextEdit*)this )->formatMore();
03465     return h;
03466 }
03467 
03472 void QTextEdit::append( const QString &text )
03473 {
03474     // flush and clear the undo/redo stack if necessary
03475     undoRedoInfo.clear();
03476     doc->commands()->clear();
03477 
03478     doc->removeSelection( QTextDocument::Standard );
03479     TextFormat f = doc->textFormat();
03480     if ( f == AutoText ) {
03481     if ( QStyleSheet::mightBeRichText( text ) )
03482         f = RichText;
03483     else
03484         f = PlainText;
03485     }
03486 
03487     drawCursor( FALSE );
03488     QTextCursor oldc( *cursor );
03489     ensureFormatted( doc->lastParagraph() );
03490     bool atBottom = contentsY() >= contentsHeight() - visibleHeight();
03491     cursor->gotoEnd();
03492     if ( cursor->index() > 0 )
03493     cursor->splitAndInsertEmptyParagraph();
03494     QTextCursor oldCursor2 = *cursor;
03495 
03496     if ( f == Qt::PlainText ) {
03497     cursor->insert( text, TRUE );
03498     if ( doc->useFormatCollection() &&
03499          currentFormat != cursor->paragraph()->at( cursor->index() )->format() ) {
03500         doc->setSelectionStart( QTextDocument::Temp, oldCursor2 );
03501         doc->setSelectionEnd( QTextDocument::Temp, *cursor );
03502         doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
03503         doc->removeSelection( QTextDocument::Temp );
03504     }
03505     } else {
03506     if ( cursor->paragraph()->prev() )
03507         cursor->paragraph()->prev()->invalidate(0); // vertical margins might have to change
03508     doc->setRichTextInternal( text );
03509     }
03510     formatMore();
03511     repaintChanged();
03512     if ( atBottom )
03513         scrollToBottom();
03514     *cursor = oldc;
03515     if ( !isReadOnly() )
03516     cursorVisible = TRUE;
03517     setModified();
03518     emit textChanged();
03519 }
03520 
03525 bool QTextEdit::hasSelectedText() const
03526 {
03527     return doc->hasSelection( QTextDocument::Standard );
03528 }
03529 
03541 QString QTextEdit::selectedText() const
03542 {
03543     return doc->selectedText( QTextDocument::Standard );
03544 }
03545 
03546 bool QTextEdit::handleReadOnlyKeyEvent( QKeyEvent *e )
03547 {
03548     switch( e->key() ) {
03549     case Key_Down:
03550     setContentsPos( contentsX(), contentsY() + 10 );
03551     break;
03552     case Key_Up:
03553     setContentsPos( contentsX(), contentsY() - 10 );
03554     break;
03555     case Key_Left:
03556     setContentsPos( contentsX() - 10, contentsY() );
03557     break;
03558     case Key_Right:
03559     setContentsPos( contentsX() + 10, contentsY() );
03560     break;
03561     case Key_PageUp:
03562     setContentsPos( contentsX(), contentsY() - visibleHeight() );
03563     break;
03564     case Key_PageDown:
03565     setContentsPos( contentsX(), contentsY() + visibleHeight() );
03566     break;
03567     case Key_Home:
03568     setContentsPos( contentsX(), 0 );
03569     break;
03570     case Key_End:
03571     setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
03572     break;
03573     case Key_F16: // Copy key on Sun keyboards
03574     copy();
03575     break;
03576 #ifndef QT_NO_NETWORKPROTOCOL
03577     case Key_Return:
03578     case Key_Enter:
03579     case Key_Space: {
03580     if ( !doc->focusIndicator.href.isEmpty() ) {
03581         QUrl u( doc->context(), doc->focusIndicator.href, TRUE );
03582         emitLinkClicked( u.toString( FALSE, FALSE ) );
03583 #ifndef QT_NO_CURSOR
03584         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
03585 #endif
03586     }
03587     } break;
03588 #endif
03589     default:
03590     if ( e->state() & ControlButton ) {
03591         switch ( e->key() ) {
03592         case Key_C: case Key_F16: // Copy key on Sun keyboards
03593         copy();
03594         break;
03595         }
03596     }
03597     return FALSE;
03598     }
03599     return TRUE;
03600 }
03601 
03609 QString QTextEdit::context() const
03610 {
03611     return doc->context();
03612 }
03613 
03623 QString QTextEdit::documentTitle() const
03624 {
03625     return doc->attributes()[ "title" ];
03626 }
03627 
03628 void QTextEdit::makeParagVisible( QTextParagraph *p )
03629 {
03630     setContentsPos( contentsX(), QMIN( p->rect().y(), contentsHeight() - visibleHeight() ) );
03631 }
03632 
03639 void QTextEdit::scrollToAnchor( const QString& name )
03640 {
03641     if ( !isVisible() ) {
03642     d->scrollToAnchor = name;
03643     return;
03644     }
03645     if ( name.isEmpty() )
03646     return;
03647     sync();
03648     QTextCursor cursor( doc );
03649     QTextParagraph* last = doc->lastParagraph();
03650     for (;;) {
03651     QTextStringChar* c = cursor.paragraph()->at( cursor.index() );
03652     if( c->isAnchor() ) {
03653         QString a = c->anchorName();
03654         if ( a == name ||
03655          (a.contains( '#' ) && QStringList::split( '#', a ).contains( name ) ) ) {
03656         setContentsPos( contentsX(), QMIN( cursor.paragraph()->rect().top() + cursor.totalOffsetY(), contentsHeight() - visibleHeight() ) );
03657         break;
03658         }
03659     }
03660     if ( cursor.paragraph() == last && cursor.atParagEnd()  )
03661         break;
03662     cursor.gotoNextLetter();
03663     }
03664 }
03665 
03671 QString QTextEdit::anchorAt( const QPoint& pos )
03672 {
03673     QTextCursor c( doc );
03674     placeCursor( pos, &c );
03675     return c.paragraph()->at( c.index() )->anchorHref();
03676 }
03677 
03678 void QTextEdit::documentWidthChanged( int w )
03679 {
03680     resizeContents( QMAX( visibleWidth(), w), contentsHeight() );
03681 }
03682 
03688 void QTextEdit::updateStyles()
03689 {
03690 }
03691 
03692 void QTextEdit::setDocument( QTextDocument *dc )
03693 {
03694     if ( dc == doc )
03695     return;
03696     doc = dc;
03697     delete cursor;
03698     cursor = new QTextCursor( doc );
03699     clearUndoRedo();
03700     undoRedoInfo.doc = doc;
03701     lastFormatted = 0;
03702 }
03703 
03704 #ifndef QT_NO_CLIPBOARD
03705 
03716 void QTextEdit::pasteSubType( const QCString& subtype )
03717 {
03718     QCString st = subtype;
03719     QString t = QApplication::clipboard()->text(st);
03720     if ( doc->hasSelection( QTextDocument::Standard ) )
03721     removeSelectedText();
03722     if ( !t.isEmpty() ) {
03723     if ( t.startsWith( "<selstart/>" ) ) {
03724         t.remove( 0, 11 );
03725         QTextCursor oldC = *cursor;
03726         lastFormatted = cursor->paragraph();
03727         if ( lastFormatted->prev() )
03728         lastFormatted = lastFormatted->prev();
03729         doc->setRichTextInternal( t, cursor );
03730 
03731         if ( undoEnabled && !isReadOnly() ) {
03732         doc->setSelectionStart( QTextDocument::Temp, oldC );
03733         doc->setSelectionEnd( QTextDocument::Temp, *cursor );
03734 
03735         checkUndoRedoInfo( UndoRedoInfo::Insert );
03736         if ( !undoRedoInfo.valid() ) {
03737             undoRedoInfo.id = oldC.paragraph()->paragId();
03738             undoRedoInfo.index = oldC.index();
03739             undoRedoInfo.d->text = QString::null;
03740         }
03741         int oldLen = undoRedoInfo.d->text.length();
03742         if ( !doc->preProcessor() ) {
03743             QString txt = doc->selectedText( QTextDocument::Temp );
03744             undoRedoInfo.d->text += txt;
03745             for ( int i = 0; i < (int)txt.length(); ++i ) {
03746             if ( txt[ i ] != '\n' && oldC.paragraph()->at( oldC.index() )->format() ) {
03747                 oldC.paragraph()->at( oldC.index() )->format()->addRef();
03748                 undoRedoInfo.d->text.
03749                 setFormat( oldLen + i, oldC.paragraph()->at( oldC.index() )->format(), TRUE );
03750             }
03751             oldC.gotoNextLetter();
03752             }
03753         }
03754         undoRedoInfo.clear();
03755         removeSelection( QTextDocument::Temp );
03756         }
03757 
03758         formatMore();
03759         setModified();
03760         emit textChanged();
03761         repaintChanged();
03762         ensureCursorVisible();
03763         return;
03764     }
03765 
03766 #if defined(Q_OS_WIN32)
03767     // Need to convert CRLF to LF
03768     int index = t.find( QString::fromLatin1("\r\n"), 0 );
03769     while ( index != -1 ) {
03770         t.replace( index, 2, QChar('\n') );
03771         index = t.find( "\r\n", index );
03772     }
03773 #elif defined(Q_OS_MAC)
03774     //need to convert CR to LF
03775     for( unsigned int index = 0; index < t.length(); index++ )
03776         if(t[index] == '\r')
03777         t[index] = '\n';
03778 #endif
03779     for ( int i=0; (uint) i<t.length(); i++ ) {
03780         if ( t[ i ] < ' ' && t[ i ] != '\n' && t[ i ] != '\t' )
03781         t[ i ] = ' ';
03782     }
03783     if ( !t.isEmpty() )
03784         insert( t, FALSE, TRUE, TRUE );
03785     }
03786 }
03787 
03788 #ifndef QT_NO_MIMECLIPBOARD
03789 
03795 void QTextEdit::pasteSpecial( const QPoint& pt )
03796 {
03797     QCString st = pickSpecial( QApplication::clipboard()->data(), TRUE, pt );
03798     if ( !st.isEmpty() )
03799     pasteSubType( st );
03800 }
03801 #endif
03802 #ifndef QT_NO_MIME
03803 QCString QTextEdit::pickSpecial( QMimeSource* ms, bool always_ask, const QPoint& pt )
03804 {
03805     if ( ms )  {
03806 #ifndef QT_NO_POPUPMENU
03807     QPopupMenu popup( this, "qt_pickspecial_menu" );
03808     QString fmt;
03809     int n = 0;
03810     QDict<void> done;
03811     for (int i = 0; !( fmt = ms->format( i ) ).isNull(); i++) {
03812         int semi = fmt.find( ";" );
03813         if ( semi >= 0 )
03814         fmt = fmt.left( semi );
03815         if ( fmt.left( 5 ) == "text/" ) {
03816         fmt = fmt.mid( 5 );
03817         if ( !done.find( fmt ) ) {
03818             done.insert( fmt,(void*)1 );
03819             popup.insertItem( fmt, i );
03820             n++;
03821         }
03822         }
03823     }
03824     if ( n ) {
03825         int i = n ==1 && !always_ask ? popup.idAt( 0 ) : popup.exec( pt );
03826         if ( i >= 0 )
03827         return popup.text(i).latin1();
03828     }
03829 #else
03830     QString fmt;
03831     for (int i = 0; !( fmt = ms->format( i ) ).isNull(); i++) {
03832         int semi = fmt.find( ";" );
03833         if ( semi >= 0 )
03834         fmt = fmt.left( semi );
03835         if ( fmt.left( 5 ) == "text/" ) {
03836         fmt = fmt.mid( 5 );
03837         return fmt.latin1();
03838         }
03839     }
03840 #endif
03841     }
03842     return QCString();
03843 }
03844 #endif // QT_NO_MIME
03845 #endif // QT_NO_CLIPBOARD
03846 
03887 void QTextEdit::setWordWrap( WordWrap mode )
03888 {
03889     if ( wrapMode == mode )
03890     return;
03891     wrapMode = mode;
03892     switch ( mode ) {
03893     case NoWrap:
03894     document()->formatter()->setWrapEnabled( FALSE );
03895     document()->formatter()->setWrapAtColumn( -1 );
03896     doc->setWidth( visibleWidth() );
03897     doc->setMinimumWidth( -1 );
03898     doc->invalidate();
03899     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
03900     lastFormatted = doc->firstParagraph();
03901     interval = 0;
03902     formatMore();
03903     break;
03904     case WidgetWidth:
03905     document()->formatter()->setWrapEnabled( TRUE );
03906     document()->formatter()->setWrapAtColumn( -1 );
03907     doResize();
03908     break;
03909     case FixedPixelWidth:
03910     document()->formatter()->setWrapEnabled( TRUE );
03911     document()->formatter()->setWrapAtColumn( -1 );
03912     if ( wrapWidth < 0 )
03913         wrapWidth = 200;
03914     setWrapColumnOrWidth( wrapWidth );
03915     break;
03916     case FixedColumnWidth:
03917     if ( wrapWidth < 0 )
03918         wrapWidth = 80;
03919     document()->formatter()->setWrapEnabled( TRUE );
03920     document()->formatter()->setWrapAtColumn( wrapWidth );
03921     setWrapColumnOrWidth( wrapWidth );
03922     break;
03923     }
03924 }
03925 
03926 QTextEdit::WordWrap QTextEdit::wordWrap() const
03927 {
03928     return wrapMode;
03929 }
03930 
03943 void QTextEdit::setWrapColumnOrWidth( int value )
03944 {
03945     wrapWidth = value;
03946     if ( wrapMode == FixedColumnWidth ) {
03947     document()->formatter()->setWrapAtColumn( wrapWidth );
03948     resizeContents( 0, 0 );
03949     doc->setWidth( visibleWidth() );
03950     doc->setMinimumWidth( -1 );
03951     } else if (wrapMode == FixedPixelWidth ) {
03952     document()->formatter()->setWrapAtColumn( -1 );
03953     resizeContents( wrapWidth, 0 );
03954     doc->setWidth( wrapWidth );
03955     doc->setMinimumWidth( wrapWidth );
03956     } else {
03957     return;
03958     }
03959     doc->invalidate();
03960     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
03961     lastFormatted = doc->firstParagraph();
03962     interval = 0;
03963     formatMore();
03964 }
03965 
03966 int QTextEdit::wrapColumnOrWidth() const
03967 {
03968     if ( wrapMode == WidgetWidth )
03969     return visibleWidth();
03970     return wrapWidth;
03971 }
03972 
03973 
03999 void QTextEdit::setWrapPolicy( WrapPolicy policy )
04000 {
04001     if ( wPolicy == policy )
04002     return;
04003     wPolicy = policy;
04004     QTextFormatter *formatter;
04005     if ( policy == AtWhiteSpace )
04006     formatter = new QTextFormatterBreakWords;
04007     else
04008     formatter = new QTextFormatterBreakInWords;
04009     formatter->setWrapAtColumn( document()->formatter()->wrapAtColumn() );
04010     formatter->setWrapEnabled( document()->formatter()->isWrapEnabled( 0 ) );
04011     document()->setFormatter( formatter );
04012     doc->invalidate();
04013     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
04014     lastFormatted = doc->firstParagraph();
04015     interval = 0;
04016     formatMore();
04017 }
04018 
04019 QTextEdit::WrapPolicy QTextEdit::wrapPolicy() const
04020 {
04021     return wPolicy;
04022 }
04023 
04031 void QTextEdit::clear()
04032 {
04033     // make clear undoable
04034     doc->selectAll( QTextDocument::Temp );
04035     removeSelectedText( QTextDocument::Temp );
04036 
04037     setContentsPos( 0, 0 );
04038     if ( cursor->isValid() )
04039     cursor->restoreState();
04040     doc->clear( TRUE );
04041     delete cursor;
04042     cursor = new QTextCursor( doc );
04043     lastFormatted = 0;
04044     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
04045 
04046     emit cursorPositionChanged( cursor );
04047     emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
04048 }
04049 
04050 int QTextEdit::undoDepth() const
04051 {
04052     return document()->undoDepth();
04053 }
04054 
04061 int QTextEdit::length() const
04062 {
04063     return document()->length();
04064 }
04065 
04072 int QTextEdit::tabStopWidth() const
04073 {
04074     return document()->tabStopWidth();
04075 }
04076 
04077 void QTextEdit::setUndoDepth( int d )
04078 {
04079     document()->setUndoDepth( d );
04080 }
04081 
04082 void QTextEdit::setTabStopWidth( int ts )
04083 {
04084     document()->setTabStops( ts );
04085     doc->invalidate();
04086     lastFormatted = doc->firstParagraph();
04087     interval = 0;
04088     formatMore();
04089     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
04090 }
04091 
04094 QSize QTextEdit::sizeHint() const
04095 {
04096     // ### calculate a reasonable one
04097     return QSize( 100, 100 );
04098 }
04099 
04100 void QTextEdit::clearUndoRedo()
04101 {
04102     undoRedoInfo.clear();
04103     emit undoAvailable( doc->commands()->isUndoAvailable() );
04104     emit redoAvailable( doc->commands()->isRedoAvailable() );
04105 }
04106 
04122 bool QTextEdit::getFormat( int para, int index, QFont *font, QColor *color, VerticalAlignment *verticalAlignment )
04123 {
04124     if ( !font || !color )
04125     return FALSE;
04126     QTextParagraph *p = doc->paragAt( para );
04127     if ( !p )
04128     return FALSE;
04129     if ( index < 0 || index >= p->length() )
04130     return FALSE;
04131     *font = p->at( index )->format()->font();
04132     *color = p->at( index )->format()->color();
04133     *verticalAlignment = (VerticalAlignment)p->at( index )->format()->vAlign();
04134     return TRUE;
04135 }
04136 
04155 bool QTextEdit::getParagraphFormat( int para, QFont *font, QColor *color,
04156                     VerticalAlignment *verticalAlignment, int *alignment,
04157                     QStyleSheetItem::DisplayMode *displayMode,
04158                     QStyleSheetItem::ListStyle *listStyle,
04159                     int *listDepth )
04160 {
04161     if ( !font || !color || !alignment || !displayMode || !listStyle )
04162     return FALSE;
04163     QTextParagraph *p = doc->paragAt( para );
04164     if ( !p )
04165     return FALSE;
04166     *font = p->at(0)->format()->font();
04167     *color = p->at(0)->format()->color();
04168     *verticalAlignment = (VerticalAlignment)p->at(0)->format()->vAlign();
04169     *alignment = p->alignment();
04170     *displayMode = p->isListItem() ? QStyleSheetItem::DisplayListItem : QStyleSheetItem::DisplayBlock;
04171     *listStyle = p->listStyle();
04172     *listDepth = p->listDepth();
04173     return TRUE;
04174 }
04175 
04176 
04177 
04187 QPopupMenu *QTextEdit::createPopupMenu( const QPoint& pos )
04188 {
04189 #ifndef QT_NO_POPUPMENU
04190     QPopupMenu *popup = new QPopupMenu( this, "qt_edit_menu" );
04191     if ( !isReadOnly() ) {
04192     d->id[ IdUndo ] = popup->insertItem( tr( "&Undo" ) + ACCEL_KEY( Z ) );
04193     d->id[ IdRedo ] = popup->insertItem( tr( "&Redo" ) + ACCEL_KEY( Y ) );
04194     popup->insertSeparator();
04195     }
04196 #ifndef QT_NO_CLIPBOARD
04197     if ( !isReadOnly() )
04198     d->id[ IdCut ] = popup->insertItem( tr( "Cu&t" ) + ACCEL_KEY( X ) );
04199     d->id[ IdCopy ] = popup->insertItem( tr( "&Copy" ) + ACCEL_KEY( C ) );
04200     if ( !isReadOnly() )
04201     d->id[ IdPaste ] = popup->insertItem( tr( "&Paste" ) + ACCEL_KEY( V ) );
04202 #endif
04203     if ( !isReadOnly() ) {
04204     d->id[ IdClear ] = popup->insertItem( tr( "Clear" ) );
04205     popup->insertSeparator();
04206     }
04207 #if defined(Q_WS_X11)
04208     d->id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) );
04209 #else
04210     d->id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) + ACCEL_KEY( A ) );
04211 #endif
04212     popup->setItemEnabled( d->id[ IdUndo ], !isReadOnly() && doc->commands()->isUndoAvailable() );
04213     popup->setItemEnabled( d->id[ IdRedo ], !isReadOnly() && doc->commands()->isRedoAvailable() );
04214 #ifndef QT_NO_CLIPBOARD
04215     popup->setItemEnabled( d->id[ IdCut ], !isReadOnly() && doc->hasSelection( QTextDocument::Standard, TRUE ) );
04216     popup->setItemEnabled( d->id[ IdCopy ], doc->hasSelection( QTextDocument::Standard, TRUE ) );
04217     popup->setItemEnabled( d->id[ IdPaste ], !isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
04218 #endif
04219     popup->setItemEnabled( d->id[ IdClear ], !isReadOnly() && !text().isEmpty() );
04220     popup->setItemEnabled( d->id[ IdSelectAll ], (bool)text().length() );
04221     return popup;
04222 #else
04223     return 0;
04224 #endif
04225 }
04226 
04238 QPopupMenu *QTextEdit::createPopupMenu()
04239 {
04240     return 0;
04241 }
04242 
04245 void QTextEdit::setFont( const QFont &f )
04246 {
04247     QFont old( QScrollView::font() );
04248     QScrollView::setFont( f );
04249     doc->setMinimumWidth( -1 );
04250     doc->setDefaultFormat( f, doc->formatCollection()->defaultFormat()->color() );
04251     lastFormatted = doc->firstParagraph();
04252     formatMore();
04253     repaintChanged();
04254 }
04255 
04288 void QTextEdit::zoomIn( int range )
04289 {
04290     QFont f( QScrollView::font() );
04291     f.setPointSize( f.pointSize() + range );
04292     setFont( f );
04293 }
04294 
04302 void QTextEdit::zoomOut( int range )
04303 {
04304     QFont f( QScrollView::font() );
04305     f.setPointSize( QMAX( 1, f.pointSize() - range ) );
04306     setFont( f );
04307 }
04308 
04314 void QTextEdit::zoomTo( int size )
04315 {
04316     QFont f( QScrollView::font() );
04317     f.setPointSize( size );
04318     setFont( f );
04319 }
04320 
04335 void QTextEdit::sync()
04336 {
04337     while ( lastFormatted ) {
04338     lastFormatted->format();
04339     lastFormatted = lastFormatted->next();
04340     }
04341     resizeContents( contentsWidth(), doc->height() );
04342 }
04343 
04346 void QTextEdit::setEnabled( bool b )
04347 {
04348     QScrollView::setEnabled( b );
04349     if ( !b ) {
04350     blinkTimer->stop();
04351     drawCursor( FALSE );
04352     }
04353     if ( textFormat() == PlainText ) {
04354     QTextFormat *f = doc->formatCollection()->defaultFormat();
04355     f->setColor( colorGroup().text() );
04356     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
04357     }
04358     if ( b ) {
04359     blinkTimer->start( QApplication::cursorFlashTime() / 2 );
04360     drawCursor( TRUE );
04361     }
04362 }
04363 
04373 void QTextEdit::setSelectionAttributes( int selNum, const QColor &back, bool invertText )
04374 {
04375     if ( selNum < 1 )
04376     return;
04377     if ( selNum > doc->numSelections() )
04378     doc->addSelection( selNum );
04379     doc->setSelectionColor( selNum, back );
04380     doc->setInvertSelectionText( selNum, invertText );
04381 }
04382 
04384 void QTextEdit::windowActivationChange( bool )
04385 {
04386     if ( !isVisible() )
04387     return;
04388 
04389     if ( palette().active() != palette().inactive() )
04390     updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
04391 }
04392 
04393 void QTextEdit::setReadOnly( bool b )
04394 {
04395     if ( readonly == b )
04396     return;
04397     readonly = b;
04398 #ifndef QT_NO_CURSOR
04399     if ( readonly )
04400     viewport()->setCursor( arrowCursor );
04401     else
04402     viewport()->setCursor( ibeamCursor );
04403 #endif
04404 }
04405 
04409 void QTextEdit::scrollToBottom()
04410 {
04411     sync();
04412     setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
04413 }
04414 
04419 QRect QTextEdit::paragraphRect( int para ) const
04420 {
04421     QTextEdit *that = (QTextEdit *)this;
04422     that->sync();
04423     QTextParagraph *p = doc->paragAt( para );
04424     if ( !p )
04425     return QRect( -1, -1, -1, -1 );
04426     return p->rect();
04427 }
04428 
04434 int QTextEdit::paragraphAt( const QPoint &pos ) const
04435 {
04436     QTextCursor c( doc );
04437     c.place( pos, doc->firstParagraph() );
04438     if ( c.paragraph() )
04439     return c.paragraph()->paragId();
04440     return -1;
04441 }
04442 
04450 int QTextEdit::charAt( const QPoint &pos, int *para ) const
04451 {
04452     QTextCursor c( doc );
04453     c.place( pos, doc->firstParagraph() );
04454     if ( c.paragraph() ) {
04455     if ( para )
04456         *para = c.paragraph()->paragId();
04457     return c.index();
04458     }
04459     return -1;
04460 }
04461 
04464 void QTextEdit::setParagraphBackgroundColor( int para, const QColor &bg )
04465 {
04466     QTextParagraph *p = doc->paragAt( para );
04467     if ( !p )
04468     return;
04469     p->setBackgroundColor( bg );
04470     repaintChanged();
04471 }
04472 
04477 void QTextEdit::clearParagraphBackground( int para )
04478 {
04479     QTextParagraph *p = doc->paragAt( para );
04480     if ( !p )
04481     return;
04482     p->clearBackgroundColor();
04483     repaintChanged();
04484 }
04485 
04491 QColor QTextEdit::paragraphBackgroundColor( int para ) const
04492 {
04493     QTextParagraph *p = doc->paragAt( para );
04494     if ( !p )
04495     return QColor();
04496     QColor *c = p->backgroundColor();
04497     if ( c )
04498     return *c;
04499     return QColor();
04500 }
04501 
04508 void QTextEdit::setUndoRedoEnabled( bool b )
04509 {
04510     undoEnabled = b;
04511 }
04512 
04513 bool QTextEdit::isUndoRedoEnabled() const
04514 {
04515     return undoEnabled;
04516 }
04517 
04520 bool QTextEdit::isUndoAvailable() const
04521 {
04522     return doc->commands()->isUndoAvailable() || undoRedoInfo.valid();
04523 }
04524 
04527 bool QTextEdit::isRedoAvailable() const
04528 {
04529     return doc->commands()->isRedoAvailable();
04530 }
04531 
04532 void QTextEdit::ensureFormatted( QTextParagraph *p )
04533 {
04534     while ( !p->isValid() ) {
04535     if ( !lastFormatted )
04536         return;
04537     formatMore();
04538     }
04539 }
04540 
04542 void QTextEdit::updateCursor( const QPoint & pos )
04543 {
04544     if ( isReadOnly() && linksEnabled() ) {
04545     QTextCursor c = *cursor;
04546     placeCursor( pos, &c, TRUE );
04547 
04548 #ifndef QT_NO_NETWORKPROTOCOL
04549     if ( c.paragraph() && c.paragraph()->at( c.index() ) &&
04550          c.paragraph()->at( c.index() )->isAnchor() &&
04551          !c.paragraph()->at( c.index() )->anchorHref().isEmpty() ) {
04552         if ( c.index() < c.paragraph()->length() - 1 )
04553         onLink = c.paragraph()->at( c.index() )->anchorHref();
04554         else
04555         onLink = QString::null;
04556 
04557 #ifndef QT_NO_CURSOR
04558         viewport()->setCursor( onLink.isEmpty() ? arrowCursor : pointingHandCursor );
04559 #endif
04560         QUrl u( doc->context(), onLink, TRUE );
04561         emitHighlighted( u.toString( FALSE, FALSE ) );
04562     } else {
04563 #ifndef QT_NO_CURSOR
04564         viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
04565 #endif
04566         onLink = QString::null;
04567         emitHighlighted( QString::null );
04568     }
04569 #endif
04570     }
04571 }
04572 
04573 void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c )
04574 {
04575     placeCursor( pos, c, FALSE );
04576 }

Generated on Sat Nov 5 16:17:07 2005 for OPIE by  doxygen 1.4.2