diff options
Diffstat (limited to 'src/attic')
-rw-r--r-- | src/attic/README | 6 | ||||
-rw-r--r-- | src/attic/qtmultilineedit.cpp | 4236 | ||||
-rw-r--r-- | src/attic/qtmultilineedit.h | 363 | ||||
-rw-r--r-- | src/attic/qttableview.cpp | 2272 | ||||
-rw-r--r-- | src/attic/qttableview.h | 250 |
5 files changed, 7127 insertions, 0 deletions
diff --git a/src/attic/README b/src/attic/README new file mode 100644 index 0000000..7400da1 --- /dev/null +++ b/src/attic/README @@ -0,0 +1,6 @@ +This directory contains classes that has been obsoleted and moved out +of the Qt API. + +To use these classes, simply include them in your project. Remember to +rename the class references in your own code. + diff --git a/src/attic/qtmultilineedit.cpp b/src/attic/qtmultilineedit.cpp new file mode 100644 index 0000000..3c8f346 --- /dev/null +++ b/src/attic/qtmultilineedit.cpp @@ -0,0 +1,4236 @@ +/********************************************************************** +** +** Implementation of QtMultiLineEdit widget class +** +** Created : 961005 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file contains a class moved out of the Qt GUI Toolkit API. It +** may be used, distributed and modified without limitation. +** +**********************************************************************/ + +#include "qtmultilineedit.h" +#ifndef QT_NO_QTMULTILINEEDIT +#include "qpainter.h" +#include "qscrollbar.h" +#include "qclipboard.h" +#include "qpixmap.h" +#include "qregexp.h" +#include "qapplication.h" +#include "qdragobject.h" +#include "qpopupmenu.h" +#include "qtimer.h" +#include "qdict.h" +#include "qcursor.h" +#ifndef QT_NO_COMPAT +#include "qstyle.h" +#endif + + +class QtMultiLineEditCommand +{ +public: + enum Commands { Invalid, Begin, End, Insert, Delete }; + virtual ~QtMultiLineEditCommand() {}; + virtual Commands type() { return Invalid; }; + virtual int terminator() { return 0; } + + virtual bool merge( QtMultiLineEditCommand* ) { return FALSE;} +}; + +class QBeginCommand : public QtMultiLineEditCommand +{ + +public: + QBeginCommand() {} + int terminator() { return 1; } + Commands type() { return Begin; }; +}; + +class QEndCommand : public QtMultiLineEditCommand +{ +public: + QEndCommand() {} + int terminator() { return -1; } + Commands type() { return End; }; +}; + +// QtMultiLineEditUndoRedo methods +class QDelTextCmd : public QtMultiLineEditCommand +{ +public: + int mOffset; + QString mStr; + + // have to handle deletion of current selection + QDelTextCmd(int offset, const QString &str ) + : mOffset( offset ), + mStr ( str ) + { + } + Commands type() { return Delete; }; + + bool merge( QtMultiLineEditCommand* other) + { + if ( other->type() == type() ) { + QDelTextCmd* o = (QDelTextCmd*) other; + if ( mOffset + int(mStr.length()) == o->mOffset ) { + o->mStr.prepend( mStr ); + o->mOffset = mOffset; + return TRUE; + } + } + return FALSE; + } + + +}; + +class QInsTextCmd : public QDelTextCmd +{ + +public: + QInsTextCmd(int offset,const QString &str ) + : QDelTextCmd( offset, str ) + { + } + + Commands type() { return Insert; }; + + bool merge( QtMultiLineEditCommand* other) + { + if ( other->type() == type() ) { + QInsTextCmd* o = (QInsTextCmd*) other; + if ( mOffset == o->mOffset + int(o->mStr.length()) ) { + o->mStr += mStr; + return TRUE; + } + } + return FALSE; + } +}; + + +/* + \class QtMultiLineEdit qtmultilineedit.h + + \brief The QtMultiLineEdit widget is a simple editor for inputting text. + + \obsolete + + The QtMultiLineEdit widget provides multiple line text input and display. + It is intended for moderate amounts of text. There are no arbitrary + limitations, but if you try to handle megabytes of data, performance + will suffer. + + Per default, the edit widget does not perform any word + wrapping. This can be adjusted by calling setWordWrap(). Both + dynamic wrapping according to the visible width or a fixed number of + character or pixels is supported. + + The widget can be used to display text by calling setReadOnly(TRUE). + + The default key bindings are described in keyPressEvent(); they cannot + be customized except by inheriting the class. + + <img src=qmlined-m.png> <img src=qmlined-w.png> +*/ + +/* + \property QtMultiLineEdit::numLines + \brief the number of lines in the multi-line edit + + numLines() returns the number of lines in the editor. The count + includes any empty lines at top and bottom, so for an empty editor + this method will return 1. +*/ +/* + \property QtMultiLineEdit::atBeginning + \brief whether the cursor is at the beginning + + atBeginning() returns TRUE if the cursor is placed at the + beginning of the text. +*/ +/* + \property QtMultiLineEdit::atEnd + \brief whether the cursor is at the end + + atEnd() returns TRUE if the cursor is placed at the end of the text. +*/ +/* + \property QtMultiLineEdit::maxLineWidth + \brief the maximum line width in pixels + Returns the width in pixels of the longest text line in this editor. +*/ +/* + \property QtMultiLineEdit::alignment + \brief the alignment + + Possible values are \c AlignLeft, \c Align(H)Center and \c + AlignRight. + \sa Qt::AlignmentFlags +*/ +/* + \property QtMultiLineEdit::edited + \brief whether the text had been edited + +edited() returns the edited flag of the line edit. If this returns FALSE, +the contents has not been changed since the construction of the +QtMultiLineEdit (or the last call to setEdited( FALSE ), if any). If +it returns TRUE, the contents have been edited, or setEdited( TRUE ) +has been called. + +setEdited() sets the edited flag of this line edit to \e e. The +edited flag is never read by QtMultiLineEdit, but is changed to TRUE +whenever the user changes its contents. + +This is useful e.g. for things that need to provide a default value, +but cannot find the default at once. Just open the widget without the +best default and when the default is known, check the edited() return +value and set the line edit's contents if the user has not started +editing the line edit. Another example is to detect whether the +contents need saving. + +*/ +/* + \property QtMultiLineEdit::echoMode + \brief the echo mode +*/ +/* + \property QtMultiLineEdit::maxLength + \brief the maximum length of the text + + The currently set text length limit, or -1 if there is + no limit (this is the default). + +*/ +/* + \property QtMultiLineEdit::maxLines + \brief the maximum number of lines + The currently set line limit, or -1 if there is + no limit (the default). + + Note that excess lines are deleted from the \e bottom of the + lines. If you want teletype behaviour with lines disappearing + from the \e top as the limit is exceed, you probably just want + to use removeLine(0) prior to adding an excess line. + +*/ +/* + \property QtMultiLineEdit::hMargin + \brief the horizontal margin + The horizontal margin current set. The default is 3. +*/ +/* + \property QtMultiLineEdit::wordWrap + \brief the word wrap mode + + By default, wrapping keeps words intact. To allow breaking within + words, set the wrap policy to \c Anywhere (see setWrapPolicy() ). + + The default wrap mode is \c NoWrap. + + \sa wordWrap(), setWrapColumnOrWidth(), setWrapPolicy() +*/ +/* + \property QtMultiLineEdit::wrapColumnOrWidth + \brief the wrap width in columns or pixels + The wrap column or wrap width, depending on the word wrap + mode. + \sa setWordWrap(), setWrapColumnOrWidth() +*/ +/* + \property QtMultiLineEdit::wrapPolicy + \brief the wrap policy mode + The default is \c AtWhiteSpace. + +*/ +/* + \property QtMultiLineEdit::autoUpdate + \brief whether auto update is enabled + + autoUpdate() returns TRUE if the view updates itself automatically + whenever it is changed in some way. + + If autoUpdate() is TRUE (this is the default) then the editor updates + itself automatically whenever it has changed in some way (generally, + when text has been inserted or deleted). + + If autoUpdate() is FALSE, the view does NOT repaint itself, or update + its internal state variables itself when it is changed. This can be + useful to avoid flicker during large changes, and is singularly + useless otherwise: Disable auto-update, do the changes, re-enable + auto-update, and call repaint(). + + \warning Do not leave the view in this state for a long time + (i.e. between events ). If, for example, the user interacts with the + view when auto-update is off, strange things can happen. + + Setting auto-update to TRUE does not repaint the view, you must call + repaint() to do this (preferable repaint(FALSE) to avoid flicker). + + \sa autoUpdate() repaint() + +*/ +/* + \property QtMultiLineEdit::undoEnabled + \brief whether undo is enabled +*/ +/* + \property QtMultiLineEdit::undoDepth + \brief the undo depth + + The maximum number of operations that can be stored on the undo stack. + + \sa setUndoDepth() +*/ +/* + \property QtMultiLineEdit::readOnly + \brief whether the multi-line edit is read-only +*/ +/* + \property QtMultiLineEdit::overWriteMode + \brief the overwrite mode +*/ +/* + \property QtMultiLineEdit::text + \brief the multi-line edit's text +*/ +/* + \property QtMultiLineEdit::length + \brief the length of the text +*/ + +static const char * const arrow_xpm[] = { + " 8 8 2 1", + ". c None", + "# c #000000", + "........", + "..####..", + "..#####.", + ".....##.", + ".#..###.", + ".#####..", + ".####...", + ".#####.." +}; + +enum { + IdUndo, + IdRedo, +#ifndef QT_NO_CLIPBOARD + IdCut, + IdCopy, + IdPaste, + IdPasteSpecial, +#endif + IdClear, + IdSelectAll, + IdCount +}; + +struct QtMultiLineData +{ + QtMultiLineData() : + isHandlingEvent(FALSE), + edited(FALSE), + maxLineWidth(0), + align(Qt::AlignLeft), + maxlines(-1), + maxlinelen(-1), + maxlen(-1), + wordwrap( QtMultiLineEdit::NoWrap ), + wrapcol( -1 ), + wrappolicy( QtMultiLineEdit::AtWhiteSpace ), + // This doesn't use font bearings, as textWidthWithTabs does that. + // This is just an aesthetics value. + // It should probably be QMAX(0,3-fontMetrics().minLeftBearing()) though, + // as bearings give some border anyway. + lr_marg(3), + marg_extra(0), + echomode(QtMultiLineEdit::Normal), + val(0), + dnd_primed(FALSE), + dnd_forcecursor(FALSE), + undo( TRUE ), + undodepth( 256 ) + { + undoList.setAutoDelete( TRUE ); + redoList.setAutoDelete( TRUE ); + clearChartable(); + } + bool isHandlingEvent; + bool edited; + int maxLineWidth; + int scrollTime; + int scrollAccel; + int align; + int numlines; + int maxlines; + int maxlinelen; + int maxlen; + QtMultiLineEdit::WordWrap wordwrap; + int wrapcol; + QtMultiLineEdit::WrapPolicy wrappolicy; + int lr_marg; + int marg_extra; + QtMultiLineEdit::EchoMode echomode; + const QValidator* val; + + bool dnd_primed; // If TRUE, user has pressed + bool dnd_forcecursor; // If TRUE show cursor for DND feedback, + // even if !hasFocus() + QPtrList<QtMultiLineEditCommand> undoList; + QPtrList<QtMultiLineEditCommand> redoList; + bool undo; + int undodepth; + short chartable[256]; + void clearChartable() + { + int i = 256; + while ( i ) + chartable[--i] = 0; + } + QPixmap arrow; + QPoint dnd_startpos; + QTimer *blinkTimer, *scrollTimer; +#ifndef QT_NO_DRAGANDDROP + QTimer *dnd_timer; +#endif +}; + + +#define CLEAR_UNDO {d->undoList.clear(); emit undoAvailable( FALSE );\ + d->redoList.clear(); emit redoAvailable( FALSE );} + +void QtMultiLineEdit::addUndoCmd(QtMultiLineEditCommand* c) +{ + if ( d->undoList.isEmpty() ) + emit undoAvailable(TRUE); + else if ( c->merge( d->undoList.last() ) ) { + delete c; + return; + } + if ( int(d->undoList.count()) >= d->undodepth ) + d->undoList.removeFirst(); + d->undoList.append(c); + + if ( !d->redoList.isEmpty() ) { + d->redoList.clear(); + emit redoAvailable( FALSE ); + } +} + +void QtMultiLineEdit::addRedoCmd(QtMultiLineEditCommand* c) +{ + if ( d->redoList.isEmpty() ) + emit redoAvailable(TRUE); + d->redoList.append(c); +} + +static const int initialScrollTime = 50; // mark text scroll time +static const int initialScrollAccel = 5; // mark text scroll accel (0=fastest) +static const int scroll_margin = 16; // auto-scroll edge in DND + +#define WORD_WRAP ( d->wordwrap != QtMultiLineEdit::NoWrap ) +#define DYNAMIC_WRAP ( d->wordwrap == QtMultiLineEdit::WidgetWidth ) +#define FIXED_WIDTH_WRAP ( d->wordwrap == QtMultiLineEdit::FixedPixelWidth ) +#define FIXED_COLUMN_WRAP ( d->wordwrap == QtMultiLineEdit::FixedColumnWidth ) +#define BREAK_WITHIN_WORDS ( d->wrappolicy == QtMultiLineEdit::Anywhere ) + +static int defTabStop = 8; + +static int tabStopDist( const QFontMetrics &fm ) +{ + int dist; + dist = fm.width( QChar('x' )); + if( dist == 0 ) + dist = fm.maxWidth(); + return defTabStop*dist; +} + + +/* + Sets the distance between tab stops for all QtMultiLineEdit instances + to \a ex, which is measured in multiples of the width of a lower case 'x' + in the widget's font. The initial value is 8. + + \warning This function does not cause a redraw. It is best to call + it before any QtMultiLineEdit widgets are shown. + + \sa defaultTabStop() +*/ + +void QtMultiLineEdit::setDefaultTabStop( int ex ) +{ + defTabStop = ex; +} + + + +/* + Returns the distance between tab stops. + + \sa setDefaultTabStop(); +*/ + +int QtMultiLineEdit::defaultTabStop() +{ + return defTabStop; +} + + + + +static int textWidthWithTabs( const QFontMetrics &fm, const QString &s, uint start, uint nChars, int align ) +{ + if ( s.isEmpty() ) + return 0; + + int dist = -fm.leftBearing( s[(int)start] ); + int i = start; + int tabDist = -1; // lazy eval + while ( (uint)i < s.length() && (uint)i < start+nChars ) { + if ( s[i] == '\t' && align == Qt::AlignLeft ) { + if ( tabDist<0 ) + tabDist = tabStopDist(fm); + dist = ( (dist+tabDist+1)/tabDist ) * tabDist; + i++; + } else { + int ii = i; + while ( (uint)i < s.length() && (uint)i < start + nChars && ( align != Qt::AlignLeft || s[i] != '\t' ) ) + i++; + dist += fm.width( s.mid(ii,i-ii) ); + } + } + return dist; +} + +static int xPosToCursorPos( const QString &s, const QFontMetrics &fm, + int xPos, int width, int align ) +{ + int i = 0; + int dist; + int tabDist; + + if ( s.isEmpty() ) + return 0; + if ( xPos > width ) + xPos = width; + if ( xPos <= 0 ) + return 0; + + dist = -fm.leftBearing( s[0] ); + + if ( align == Qt::AlignCenter || align == Qt::AlignHCenter ) + dist = ( width - textWidthWithTabs( fm, s, 0, s.length(), align ) ) / 2; + else if ( align == Qt::AlignRight ) + dist = width - textWidthWithTabs( fm, s, 0, s.length(), align ); + + int distBeforeLastTab = dist; + tabDist = tabStopDist(fm); + while ( (uint)i < s.length() && dist < xPos ) { + if ( s[i] == '\t' && align == Qt::AlignLeft ) { + distBeforeLastTab = dist; + dist = (dist/tabDist + 1) * tabDist; + } else { + dist += fm.width( s[i] ); + } + i++; + } + if ( dist > xPos ) { + if ( dist > width ) { + i--; + } else { + if ( s[i-1] == '\t' && align == Qt::AlignLeft ) { // dist equals a tab stop position + if ( xPos - distBeforeLastTab < (dist - distBeforeLastTab)/2 ) + i--; + } else { + if ( fm.width(s[i-1])/2 < dist-xPos ) + i--; + } + } + } + return i; +} + +/* + Constructs a new, empty, QtMultiLineEdit with parent \a parent and + called \a name. +*/ + +QtMultiLineEdit::QtMultiLineEdit( QWidget *parent , const char *name ) + :QtTableView( parent, name, WStaticContents | WRepaintNoErase ) +{ + d = new QtMultiLineData; + QFontMetrics fm( font() ); + setCellHeight( fm.lineSpacing() ); + setNumCols( 1 ); + + contents = new QPtrList<QtMultiLineEditRow>; + contents->setAutoDelete( TRUE ); + + cursorX = 0; cursorY = 0; + curXPos = 0; + + setTableFlags( Tbl_autoVScrollBar|Tbl_autoHScrollBar| + Tbl_smoothVScrolling | + Tbl_clipCellPainting + ); + setFrameStyle( QFrame::WinPanel | QFrame::Sunken ); + setBackgroundMode( PaletteBase ); + setWFlags( WResizeNoErase ); + setKeyCompression( TRUE ); + setFocusPolicy( WheelFocus ); +#ifndef QT_NO_CURSOR + setCursor( ibeamCursor ); + verticalScrollBar()->setCursor( arrowCursor ); + horizontalScrollBar()->setCursor( arrowCursor ); +#endif + readOnly = FALSE; + cursorOn = FALSE; + markIsOn = FALSE; + dragScrolling = FALSE; + dragMarking = FALSE; + textDirty = FALSE; + wordMark = FALSE; + overWrite = FALSE; + markAnchorX = 0; + markAnchorY = 0; + markDragX = 0; + markDragY = 0; + d->blinkTimer = new QTimer( this ); + connect( d->blinkTimer, SIGNAL( timeout() ), + this, SLOT( blinkTimerTimeout() ) ); + d->scrollTimer = new QTimer( this ); + connect( d->scrollTimer, SIGNAL( timeout() ), + this, SLOT( scrollTimerTimeout() ) ); +#ifndef QT_NO_DRAGANDDROP + d->dnd_timer = new QTimer( this ); + connect( d->dnd_timer, SIGNAL( timeout() ), + this, SLOT( dndTimeout() ) ); +#endif + d->scrollTime = 0; + + dummy = TRUE; + + int w = textWidth( QString::fromLatin1("") ); + contents->append( new QtMultiLineEditRow(QString::fromLatin1(""), w) ); + (void)setNumRowsAndTruncate(); + setWidth( w ); + setAcceptDrops(TRUE); + if ( d->maxlines >= 0 && d->maxlines <= 6 ) { + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + } else { + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + } +} + +/* + \fn int QtMultiLineEdit::lineLength( int line ) const + Returns the number of characters at line number \a line. +*/ + +/* \fn QString *QtMultiLineEdit::getString( int line ) const + + Returns a pointer to the text at line \a line. +*/ + +/* \fn void QtMultiLineEdit::textChanged() + + This signal is emitted when the text is changed by an event or by a + slot. Note that the signal is not emitted when you call a non-slot + function such as insertLine(). + + \sa returnPressed() +*/ + +/* \fn void QtMultiLineEdit::returnPressed() + + This signal is emitted when the user presses the return or enter + key. It is not emitted if isReadOnly() is TRUE. + + \sa textChanged() +*/ + +/* + \fn void QtMultiLineEdit::undoAvailable (bool yes) + + This signal is emitted when the availability of undo changes. + If \a yes is TRUE, then undo() will work until + undoAvailable( FALSE ) is next emitted. +*/ + +/* + \fn void QtMultiLineEdit::redoAvailable (bool yes) + + This signal is emitted when the availability of redo changes. + If \a yes is TRUE, then redo() will work until + redoAvailable( FALSE ) is next emitted. +*/ + +/* + \fn void QtMultiLineEdit::copyAvailable (bool yes) + + This signal is emitted when the availability of cut/copy changes. + If \a yes is TRUE, then cut() and copy() will work until + copyAvailable( FALSE ) is next emitted. +*/ + + +/* + If \a on is FALSE, this multi line edit accepts text input. + Scrolling and cursor movements are accepted in any case. + + \sa isReadOnly() QWidget::setEnabled() +*/ + +void QtMultiLineEdit::setReadOnly( bool on ) +{ + if ( readOnly != on ) { + readOnly = on; +#ifndef QT_NO_CURSOR + setCursor( on ? arrowCursor : ibeamCursor ); +#endif + } +} + +/* +*/ +int QtMultiLineEdit::maxLineWidth() const +{ + return d->maxLineWidth; +} + +/* + Destroys the QtMultiLineEdit +*/ + +QtMultiLineEdit::~QtMultiLineEdit() +{ + delete contents; + delete d; +} + +static QPixmap *buffer = 0; + +static void cleanupMLBuffer() +{ + delete buffer; + buffer = 0; +} + +static QPixmap *getCacheBuffer( QSize sz ) +{ + if ( !buffer ) { + qAddPostRoutine( cleanupMLBuffer ); + buffer = new QPixmap; + } + + if ( buffer->width() < sz.width() || buffer->height() < sz.height() ) + buffer->resize( sz ); + return buffer; +} + +/* + Implements the basic drawing logic. Paints the line at row \a row + using painter \a painter. The \a col parameter is ignored. +*/ +void QtMultiLineEdit::paintCell( QPainter *painter, int row, int ) +{ + const QColorGroup & g = colorGroup(); + QFontMetrics fm( painter->font() ); + QString s = stringShown(row); + if ( s.isNull() ) { + qWarning( "QtMultiLineEdit::paintCell: (%s) no text at line %d", + name( "unnamed" ), row ); + return; + } + QRect updateR = cellUpdateRect(); + QPixmap *buffer = getCacheBuffer( updateR.size() ); + ASSERT(buffer); + buffer->fill ( g.base() ); + + QPainter p( buffer ); + p.setFont( painter->font() ); + p.translate( -updateR.left(), -updateR.top() ); + + p.setTabStops( tabStopDist(fm) ); + + int yPos = 0; + int markX1, markX2; // in x-coordinate pixels + markX1 = markX2 = 0; // avoid gcc warning + if ( markIsOn ) { + int markBeginX, markBeginY; + int markEndX, markEndY; + getMarkedRegion( &markBeginY, &markBeginX, &markEndY, &markEndX ); + if ( row >= markBeginY && row <= markEndY ) { + if ( row == markBeginY ) { + markX1 = markBeginX; + if ( row == markEndY ) // both marks on same row + markX2 = markEndX; + else + markX2 = s.length(); // mark till end of line + } else { + if ( row == markEndY ) { + markX1 = 0; + markX2 = markEndX; + } else { + markX1 = 0; // whole line is marked + markX2 = s.length(); // whole line is marked + } + } + } + } + p.setPen( g.text() ); + QtMultiLineEditRow* r = contents->at( row ); + int wcell = cellWidth() - 2*d->lr_marg;// - d->marg_extra; + int wrow = r->w; + int x = d->lr_marg - p.fontMetrics().leftBearing(s[0]); + if ( d->align == Qt::AlignCenter || d->align == Qt::AlignHCenter ) + x += (wcell - wrow) / 2; + else if ( d->align == Qt::AlignRight ) + x += wcell - wrow; + p.drawText( x, yPos, cellWidth()-d->lr_marg-x, cellHeight(), + d->align == AlignLeft?ExpandTabs:0, s ); + if ( !r->newline && BREAK_WITHIN_WORDS ) + p.drawPixmap( x + wrow - d->lr_marg - d->marg_extra, yPos, d->arrow ); +#if 0 + if ( r->newline ) + p.drawLine( d->lr_marg, yPos+cellHeight()-2, cellWidth() - d->lr_marg, yPos+cellHeight()-2); +#endif + if ( markX1 != markX2 ) { + int sLength = s.length(); + int xpos1 = mapToView( markX1, row ); + int xpos2 = mapToView( markX2, row ); + int fillxpos1 = xpos1; + int fillxpos2 = xpos2; + if ( markX1 == 0 ) + fillxpos1 -= 2; + if ( markX2 == sLength ) + fillxpos2 += 3; + p.setClipping( TRUE ); + p.setClipRect( fillxpos1 - updateR.left(), 0, + fillxpos2 - fillxpos1, cellHeight(row) ); + p.fillRect( fillxpos1, 0, fillxpos2 - fillxpos1, cellHeight(row), + g.brush( QColorGroup::Highlight ) ); + p.setPen( g.highlightedText() ); + p.drawText( x, yPos, cellWidth()-d->lr_marg-x, cellHeight(), + d->align == AlignLeft?ExpandTabs:0, s ); + p.setClipping( FALSE ); + } + + if ( row == cursorY && cursorOn && !readOnly ) { + int cursorPos = QMIN( (int)s.length(), cursorX ); + int cXPos = QMAX( mapToView( cursorPos, row ), 0 ); + int cYPos = 0; + if ( hasFocus() || d->dnd_forcecursor ) { + p.setPen( g.text() ); + /* styled? + p.drawLine( cXPos - 2, cYPos, + cXPos + 2, cYPos ); + */ + p.drawLine( cXPos, cYPos, + cXPos, cYPos + fm.height() - 2); + /* styled? + p.drawLine( cXPos - 2, cYPos + fm.height() - 2, + cXPos + 2, cYPos + fm.height() - 2); + */ + +#ifndef QT_NO_TRANSFORMATIONS + // TODO: set it other times, eg. when scrollbar moves view + QWMatrix wm = painter->worldMatrix(); + setMicroFocusHint( int(wm.dx()+cXPos), + int (wm.dy()+cYPos), + 1, fm.ascent() ); +#else + setMicroFocusHint( cXPos, + cYPos, + 1, fm.ascent() ); +#endif + } + } + p.end(); + painter->drawPixmap( updateR.left(), updateR.top(), *buffer, + 0, 0, updateR.width(), updateR.height() ); +} + + +/* + \overload + Returns the width in pixels of the string \a s. + NOTE: only appropriate for whole lines. +*/ + +int QtMultiLineEdit::textWidth( const QString &s ) +{ + int w = 0; + if ( !s.isNull() ) { + w = textWidthWithTabs( QFontMetrics( font() ), s, 0, s.length(), + d->align ); + } + return w + 2 * d->lr_marg + d->marg_extra; +} + + +/* + Returns the width in pixels of the text at line \a line. +*/ + +int QtMultiLineEdit::textWidth( int line ) +{ + if ( d->echomode == Password) { + QString s = stringShown(line); + return textWidth( s ); + } + QtMultiLineEditRow* r = contents->at(line); + return r?r->w:0; +} + +/* + Starts the cursor blinking. +*/ + +void QtMultiLineEdit::focusInEvent( QFocusEvent * ) +{ + stopAutoScroll(); + if ( !d->blinkTimer->isActive() ) + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + cursorOn = TRUE; + updateCell( cursorY, 0, FALSE ); +} + + +/*\reimp +*/ +void QtMultiLineEdit::leaveEvent( QEvent * ) +{ +} + + +/*\reimp +*/ +void QtMultiLineEdit::focusOutEvent( QFocusEvent * ) +{ + stopAutoScroll(); + d->blinkTimer->stop(); + if ( cursorOn ) { + cursorOn = FALSE; + updateCell( cursorY, 0, FALSE ); + } +} + + +/* + \reimp + Present for binary compatibility only! +*/ + +void QtMultiLineEdit::timerEvent( QTimerEvent * ) +{ + // ############ Remove in 3.0!!!!!!!! +} + +#ifndef QT_NO_DRAGANDDROP +void QtMultiLineEdit::doDrag() +{ + if ( d->dnd_timer ) { + d->dnd_timer->stop(); + } + QDragObject *drag_text = new QTextDrag(markedText(), this); + if ( readOnly ) { + drag_text->dragCopy(); + } else { + if ( drag_text->drag() && QDragObject::target() != this ) { + del(); + if ( textDirty && !d->isHandlingEvent ) + emit textChanged(); + } + } + d->dnd_primed = FALSE; +} +#endif + +/* + If there is marked text, sets \a line1, \a col1, \a line2 and \a col2 + to the start and end of the marked region and returns TRUE. Returns + FALSE if there is no marked text. + */ +bool QtMultiLineEdit::getMarkedRegion( int *line1, int *col1, + int *line2, int *col2 ) const +{ + if ( !markIsOn || !line1 || !line2 || !col1 || !col2 ) + return FALSE; + if ( markAnchorY < markDragY || + markAnchorY == markDragY && markAnchorX < markDragX) { + *line1 = markAnchorY; + *col1 = markAnchorX; + *line2 = markDragY; + *col2 = markDragX; + if ( *line2 > numLines() - 1 ) { + *line2 = numLines() - 1; + *col2 = lineLength( *line2 ); + } + } else { + *line1 = markDragY; + *col1 = markDragX; + *line2 = markAnchorY; + *col2 = markAnchorX; + if ( *line2 > numLines() - 1 ) { + *line2 = numLines() - 1; + *col2 = lineLength( *line2 ); + } + } + return markIsOn; +} + + +/* + Returns TRUE if there is marked text. +*/ + +bool QtMultiLineEdit::hasMarkedText() const +{ + return markIsOn; +} + + +/* + Returns a copy of the marked text. +*/ + +QString QtMultiLineEdit::markedText() const +{ + int markBeginX, markBeginY; + int markEndX, markEndY; + if ( !getMarkedRegion( &markBeginY, &markBeginX, &markEndY, &markEndX ) ) + return QString(); + if ( markBeginY == markEndY ) { //just one line + QString *s = getString( markBeginY ); + return s->mid( markBeginX, markEndX - markBeginX ); + } else { //multiline + QString *firstS, *lastS; + firstS = getString( markBeginY ); + lastS = getString( markEndY ); + int i; + QString tmp; + if ( firstS ) + tmp += firstS->mid(markBeginX); + if ( contents->at( markBeginY )->newline ) + tmp += '\n'; + + for( i = markBeginY + 1; i < markEndY ; i++ ) { + tmp += *getString(i); + if ( contents->at( i )->newline ) + tmp += '\n'; + } + + if ( lastS ) { + tmp += lastS->left(markEndX); + } else { + tmp.truncate(tmp.length()-1); + } + + return tmp; + } +} + + + +/* + Returns the text at line number \a line (possibly the empty string), + or a \link QString::operator!() null string\endlink if \a line is invalid. +*/ + +QString QtMultiLineEdit::textLine( int line ) const +{ + QString *s = getString(line); + if ( s ) { + if ( s->isNull() ) + return QString::fromLatin1(""); + else + return *s; + } else + return QString::null; +} + + +/* + Returns a copy of the whole text. If the multi line edit contains no + text, a + \link QString::operator!() null string\endlink + is returned. +*/ + +QString QtMultiLineEdit::text() const +{ + QString tmp; + for( int i = 0 ; i < (int)contents->count() ; i++ ) { + tmp += *getString(i); + if ( i+1 < (int)contents->count() && contents->at(i)->newline ) + tmp += '\n'; + } + return tmp; +} + + +/* + Selects all text without moving the cursor. +*/ + +void QtMultiLineEdit::selectAll() +{ + markAnchorX = 0; + markAnchorY = 0; + markDragY = numLines() - 1; + markDragX = lineLength( markDragY ); + turnMark( markDragX != markAnchorX || markDragY != markAnchorY ); + if ( autoUpdate() ) + update(); +} + + + +/* + Deselects all text (i.e. removes marking) and leaves the cursor at the + current position. +*/ + +void QtMultiLineEdit::deselect() +{ + turnMark( FALSE ); +} + + +/* + Sets the text to \a s, removing old text, if any. +*/ + +void QtMultiLineEdit::setText( const QString &s ) +{ + bool oldUndo = isUndoEnabled(); + setUndoEnabled( FALSE ); + bool oldAuto = autoUpdate(); + setAutoUpdate( FALSE ); + bool b = signalsBlocked(); + blockSignals( TRUE ); + clear(); + CLEAR_UNDO + blockSignals( b ); + insertLine( s, -1 ); + emit textChanged(); + setAutoUpdate(oldAuto); + if ( autoUpdate() ) + update(); + setUndoEnabled( oldUndo ); +} + + +/* + Appends \a s to the text. +*/ + +void QtMultiLineEdit::append( const QString &s ) +{ + bool oldUndo = isUndoEnabled(); + setUndoEnabled( FALSE ); + insertLine( s, -1 ); + setUndoEnabled( oldUndo ); + emit textChanged(); +} + +/* \reimp +Passes wheel events to the vertical scrollbar. +*/ +void QtMultiLineEdit::wheelEvent( QWheelEvent *e ){ + QApplication::sendEvent( verticalScrollBar(), e); +} + + +/* + The key press event handler converts a key press in event \a e to + some line editor action. + + Here are the default key bindings when isReadOnly() is FALSE: + \list + \i <i> Left Arrow </i> Move the cursor one character leftwards + \i <i> Right Arrow </i> Move the cursor one character rightwards + \i <i> Up Arrow </i> Move the cursor one line upwards + \i <i> Down Arrow </i> Move the cursor one line downwards + \i <i> Page Up </i> Move the cursor one page upwards + \i <i> Page Down </i> Move the cursor one page downwards + \i <i> Backspace </i> Delete the character to the left of the cursor + \i <i> Home </i> Move the cursor to the beginning of the line + \i <i> End </i> Move the cursor to the end of the line + \i <i> Delete </i> Delete the character to the right of the cursor + \i <i> Shift - Left Arrow </i> Mark text one character leftwards + \i <i> Shift - Right Arrow </i> Mark text one character rightwards + \i <i> Control-A </i> Move the cursor to the beginning of the line + \i <i> Control-B </i> Move the cursor one character leftwards + \i <i> Control-C </i> Copy the marked text to the clipboard + \i <i> Control-D </i> Delete the character to the right of the cursor + \i <i> Control-E </i> Move the cursor to the end of the line + \i <i> Control-F </i> Move the cursor one character rightwards + \i <i> Control-H </i> Delete the character to the left of the cursor + \i <i> Control-K </i> Delete to end of line + \i <i> Control-N </i> Move the cursor one line downwards + \i <i> Control-P </i> Move the cursor one line upwards + \i <i> Control-V </i> Paste the clipboard text into line edit + \i <i> Control-X </i> Cut the marked text, copy to clipboard + \i <i> Control-Z </i> Undo the last operation + \i <i> Control-Y </i> Redo the last operation + \i <i> Control - Left Arrow </i> Move the cursor one word leftwards + \i <i> Control - Right Arrow </i> Move the cursor one word rightwards + \i <i> Control - Up Arrow </i> Move the cursor one word upwards + \i <i> Control - Down Arrow </i> Move the cursor one word downwards + \i <i> Control - Home Arrow </i> Move the cursor to the beginning of the text + \i <i> Control - End Arrow </i> Move the cursor to the end of the text + \endlist + In addition, the following key bindings are used on Windows: + \list + \i <i> Shift - Delete </i> Cut the marked text, copy to clipboard + \i <i> Shift - Insert </i> Paste the clipboard text into line edit + \i <i> Control - Insert </i> Copy the marked text to the clipboard + \endlist + All other keys with valid ASCII codes insert themselves into the line. + + Here are the default key bindings when isReadOnly() is TRUE: + \list + \i <i> Left Arrow </i> Scrolls the table rightwards + \i <i> Right Arrow </i> Scrolls the table rightwards + \i <i> Up Arrow </i> Scrolls the table one line downwards + \i <i> Down Arrow </i> Scrolls the table one line upwards + \i <i> Page Up </i> Scrolls the table one page downwards + \i <i> Page Down </i> Scrolls the table one page upwards + \i <i> Control-C </i> Copy the marked text to the clipboard + \endlist + +*/ + +void QtMultiLineEdit::keyPressEvent( QKeyEvent *e ) +{ + textDirty = FALSE; + d->isHandlingEvent = TRUE; + int unknown = 0; + if ( readOnly ) { + int pageSize = viewHeight() / cellHeight(); + + switch ( e->key() ) { + case Key_Left: + setXOffset( xOffset() - viewWidth()/10 ); + break; + case Key_Right: + setXOffset( xOffset() + viewWidth()/10 ); + break; + case Key_Up: + setTopCell( topCell() - 1 ); + break; + case Key_Down: + setTopCell( topCell() + 1 ); + break; + case Key_Home: + setCursorPosition(0,0, e->state() & ShiftButton ); + break; + case Key_End: + setCursorPosition( numLines()-1, lineLength( numLines()-1 ), + e->state() & ShiftButton ); + break; + case Key_Next: + setTopCell( topCell() + pageSize ); + break; + case Key_Prior: + setTopCell( QMAX( topCell() - pageSize, 0 ) ); + break; +#ifndef QT_NO_CLIPBOARD + case Key_C: + if ( echoMode() == Normal && (e->state()&ControlButton) ) + copy(); + else + unknown++; + break; + case Key_F16: // Copy key on Sun keyboards + if ( echoMode() == Normal ) + copy(); + else + unknown++; + break; +#endif + default: + unknown++; + } + if ( unknown ) + e->ignore(); + d->isHandlingEvent = FALSE; + return; + } + if ( e->text().length() && + e->key() != Key_Return && + e->key() != Key_Enter && + e->key() != Key_Delete && + e->key() != Key_Backspace && + (!e->ascii() || e->ascii()>=32) + ) { + insert( e->text() ); + //QApplication::sendPostedEvents( this, QEvent::Paint ); + if ( textDirty ) + emit textChanged(); + d->isHandlingEvent = FALSE; + return; + } + if ( e->state() & ControlButton ) { + switch ( e->key() ) { + case Key_A: + home( e->state() & ShiftButton ); + break; + case Key_B: + cursorLeft( e->state() & ShiftButton ); + break; +#ifndef QT_NO_CLIPBOARD + case Key_C: + if ( echoMode() == Normal ) + copy(); + break; +#endif + case Key_D: + del(); + break; + case Key_E: + end( e->state() & ShiftButton ); + break; + case Key_Left: + cursorWordBackward( e->state() & ShiftButton ); + break; + case Key_Right: + cursorWordForward( e->state() & ShiftButton ); + break; + case Key_Up: + cursorUp( e->state() & ShiftButton ); + break; + case Key_Down: + cursorDown( e->state() & ShiftButton ); + break; + case Key_Home: + setCursorPosition(0,0, e->state() & ShiftButton ); + break; + case Key_End: + setCursorPosition( numLines()-1, lineLength( numLines()-1 ), + e->state() & ShiftButton ); + break; + case Key_F: + cursorRight( e->state() & ShiftButton ); + break; + case Key_H: + backspace(); + break; + case Key_K: + killLine(); + break; + case Key_N: + cursorDown( e->state() & ShiftButton ); + break; + case Key_P: + cursorUp( e->state() & ShiftButton ); + break; +#ifndef QT_NO_CLIPBOARD + case Key_V: + paste(); + break; + case Key_X: + cut(); + break; +#endif + case Key_Z: + undo(); + break; + case Key_Y: + redo(); + break; +#if defined (_WS_WIN_) + case Key_Insert: + copy(); +#endif + default: + unknown++; + } + } else { + switch ( e->key() ) { + case Key_Left: + cursorLeft( e->state() & ShiftButton ); + break; + case Key_Right: + cursorRight( e->state() & ShiftButton ); + break; + case Key_Up: + cursorUp( e->state() & ShiftButton ); + break; + case Key_Down: + cursorDown( e->state() & ShiftButton ); + break; + case Key_Backspace: + backspace(); + break; + case Key_Home: + home( e->state() & ShiftButton ); + break; + case Key_End: + end( e->state() & ShiftButton ); + break; + case Key_Delete: +#if defined (_WS_WIN_) + if ( e->state() & ShiftButton ) { + cut(); + break; + } +#endif + del(); + break; + case Key_Next: + pageDown( e->state() & ShiftButton ); + break; + case Key_Prior: + pageUp( e->state() & ShiftButton ); + break; + case Key_Enter: + case Key_Return: + newLine(); + emit returnPressed(); + break; + case Key_Tab: + insert( e->text() ); + break; +#if defined (_WS_WIN_) + case Key_Insert: + if ( e->state() & ShiftButton ) + paste(); + else + unknown++; + break; +#endif + case Key_F14: // Undo key on Sun keyboards + undo(); + break; +#ifndef QT_NO_CLIPBOARD + case Key_F16: // Copy key on Sun keyboards + if ( echoMode() == Normal ) + copy(); + break; + case Key_F18: // Paste key on Sun keyboards + paste(); + break; + case Key_F20: // Paste key on Sun keyboards + cut(); + break; +#endif + default: + unknown++; + } + } + if ( textDirty ) + emit textChanged(); + + if ( unknown ) // unknown key + e->ignore(); + + d->isHandlingEvent = FALSE; +} + + +/* + Moves the cursor one page down. If \a mark is TRUE, the text + is marked. +*/ + +void QtMultiLineEdit::pageDown( bool mark ) +{ + bool oldAuto = autoUpdate(); + if ( mark ) + setAutoUpdate( FALSE ); + + if ( partiallyInvisible( cursorY ) ) + cursorY = topCell(); + int delta = cursorY - topCell(); + int pageSize = viewHeight() / cellHeight(); + int newTopCell = QMIN( topCell() + pageSize, numLines() - 1 - pageSize ); + + if ( pageSize >= numLines() ) { // quick fix to handle small texts + newTopCell = topCell(); + } + if ( !curXPos ) + curXPos = mapToView( cursorX, cursorY ); + int oldY = cursorY; + + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + if ( newTopCell != topCell() ) { + cursorY = newTopCell + delta; + cursorX = mapFromView( curXPos, cursorY ); + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + setTopCell( newTopCell ); + } else if ( cursorY != (int)contents->count() - 1) { // just move the cursor + cursorY = QMIN( cursorY + pageSize, numLines() - 1); + cursorX = mapFromView( curXPos, cursorY ); + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + makeVisible(); + } + if ( oldAuto ) + if ( mark ) { + setAutoUpdate( TRUE ); + update(); + } else { + updateCell( oldY, 0, FALSE ); + } + if ( !mark ) + turnMark( FALSE ); +} + + +/* + Moves the cursor one page up. If \a mark is TRUE, the text + is marked. +*/ + +void QtMultiLineEdit::pageUp( bool mark ) +{ + bool oldAuto = autoUpdate(); + if ( mark ) + setAutoUpdate( FALSE ); + if ( partiallyInvisible( cursorY ) ) + cursorY = topCell(); + int delta = cursorY - topCell(); + int pageSize = viewHeight() / cellHeight(); + bool partial = delta == pageSize && viewHeight() != pageSize * cellHeight(); + int newTopCell = QMAX( topCell() - pageSize, 0 ); + if ( pageSize > numLines() ) { // quick fix to handle small texts + newTopCell = 0; + delta = 0; + } + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + if ( !curXPos ) + curXPos = mapToView( cursorX, cursorY ); + int oldY = cursorY; + if ( newTopCell != topCell() ) { + cursorY = QMIN( newTopCell + delta, numLines() - 1 ); + if ( partial ) + cursorY--; + cursorX = mapFromView( curXPos, cursorY ); + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + setTopCell( newTopCell ); + } else { // just move the cursor + cursorY = QMAX( cursorY - pageSize, 0 ); + cursorX = mapFromView( curXPos, cursorY ); + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + } + if ( oldAuto ) + if ( mark ) { + setAutoUpdate( TRUE ); + update(); + } else { + updateCell( oldY, 0, FALSE ); + } + if ( !mark ) + turnMark( FALSE ); +} + +// THE CORE INSERTION FUNCTION +void QtMultiLineEdit::insertAtAux( const QString &txt, int line, int col, bool mark ) +{ + dummy = FALSE; + d->blinkTimer->stop(); + cursorOn = TRUE; + int oldw = contentsRect().width(); + + line = QMAX( QMIN( line, numLines() - 1), 0 ); + col = QMAX( QMIN( col, lineLength( line )), 0 ); + + QString itxt = txt; + QtMultiLineEditRow *row = contents->at( line ); + if ( d->maxlen >= 0 && length() + int(txt.length()) > d->maxlen ) + itxt.truncate( d->maxlen - length() ); + + row->s.insert( uint(col), itxt ); + + if ( mark ) { + markAnchorX = col; + markAnchorY = line; + } + if ( cursorX == col && cursorY == line ) { + cursorX += itxt.length(); + } + QFontMetrics fm( font() ); + if ( !WORD_WRAP || ( col == 0 && itxt.contains('\n') == int(itxt.length())) ) + wrapLine( line, 0 ); + else if ( WORD_WRAP && itxt.find('\n')<0 && itxt.find('\t')<0 + && ( + ( DYNAMIC_WRAP && fm.width( itxt ) + row->w < contentsRect().width() - 2*d->lr_marg - d->marg_extra ) + || + ( FIXED_WIDTH_WRAP && ( d->wrapcol < 0 || fm.width( itxt ) + row->w < d->wrapcol ) ) + || + ( FIXED_COLUMN_WRAP && ( d->wrapcol < 0 || int(row->s.length()) < d->wrapcol ) ) + ) + && ( itxt.find(' ') < 0 || row->s.find(' ') >= 0 && row->s.find(' ') < col ) ){ + row->w = textWidth( row->s ); + setWidth( QMAX( maxLineWidth(), row->w) ); + updateCell( line, 0, FALSE ); + } + else { + if ( line > 0 && !contents->at( line-1)->newline ) + rebreakParagraph( line-1 ); + else + rebreakParagraph( line ); + } + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + + setNumRowsAndTruncate(); + + textDirty = TRUE; + d->edited = TRUE; + if ( autoUpdate() ) { + makeVisible(); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + if ( DYNAMIC_WRAP && oldw != contentsRect().width() ) { + setAutoUpdate( FALSE ); + rebreakAll(); + setAutoUpdate( TRUE ); + update(); + } + } +} + + +/* + Inserts \a txt at line number \a line. If \a line is less than zero, + or larger than the number of rows, the new text is put at the end. + If \a txt contains newline characters, several lines are inserted. + + The cursor position is not changed. +*/ + +void QtMultiLineEdit::insertLine( const QString &txt, int line ) +{ + QString s = txt; + int oldXPos = cursorX; + int oldYPos = cursorY; + if ( line < 0 || line >= int( contents->count() ) ) { + if ( !dummy ) + contents->append( new QtMultiLineEditRow(QString::fromLatin1(""), 0) ); + insertAt( s, numLines()-1, 0 ); + } else { + s.append('\n'); + insertAt( s, line, 0 ); + } + cursorX = oldXPos; + cursorY = oldYPos; +} + +/* + Deletes the line at line number \a line. If \a + line is less than zero, or larger than the number of lines, + no line is deleted. +*/ + +void QtMultiLineEdit::removeLine( int line ) +{ + CLEAR_UNDO + if ( line >= numLines() ) + return; + if ( cursorY >= line && cursorY > 0 ) + cursorY--; + bool updt = autoUpdate() && rowIsVisible( line ); + QtMultiLineEditRow* r = contents->at( line ); + ASSERT( r ); + bool recalc = r->w == maxLineWidth(); + contents->remove( line ); + if ( contents->count() == 0 ) { + int w = textWidth( QString::fromLatin1("") ); + contents->append( new QtMultiLineEditRow(QString::fromLatin1(""), w) ); + setWidth( w ); + dummy = TRUE; + } + if ( setNumRowsAndTruncate() ) + recalc = updt = FALSE; + if ( recalc ) + updateCellWidth(); + makeVisible(); + if (updt) + update(); + textDirty = TRUE; + d->edited = TRUE; +} + +/* + Inserts \a s at the current cursor position. +*/ +void QtMultiLineEdit::insert( const QString& s ) +{ + insert( s, FALSE ); +} + +/* + Inserts \a c at the current cursor position. + (this function is provided for backward compatibility - + it simply calls insert()). +*/ +void QtMultiLineEdit::insertChar( QChar c ) +{ + insert(c); +} + +/* + \overload + Inserts string \a str at the current cursor position. If \a mark is + TRUE the string is marked. +*/ + +void QtMultiLineEdit::insert( const QString& str, bool mark ) +{ + dummy = FALSE; + bool wasMarkedText = hasMarkedText(); + if ( wasMarkedText ) + addUndoCmd( new QBeginCommand ); + if ( wasMarkedText ) + del(); // ## Will flicker + QString *s = getString( cursorY ); + if ( cursorX > (int)s->length() ) + cursorX = s->length(); + else if ( overWrite && !wasMarkedText && cursorX < (int)s->length() ) + del(); // ## Will flicker + insertAt(str, cursorY, cursorX, mark ); + makeVisible(); + + if ( wasMarkedText ) + addUndoCmd( new QEndCommand() ); +} + +/* + Makes a line break at the current cursor position. +*/ + +void QtMultiLineEdit::newLine() +{ + insert("\n"); +} + +/* + Deletes text from the current cursor position to the end of the line. +*/ + +void QtMultiLineEdit::killLineAux() +{ + deselect(); // -sanders Don't let del() delete marked region + QtMultiLineEditRow* r = contents->at( cursorY ); + if ( cursorX == (int)r->s.length() ) { + // if (r->newline) // -sanders Only del newlines! + del(); + return; + } else { + bool recalc = r->w == maxLineWidth(); + r->s.remove( cursorX, r->s.length() ); + r->w = textWidth( r->s ); + updateCell( cursorY, 0, FALSE ); + if ( recalc ) + updateCellWidth(); + rebreakParagraph( cursorY ); // -sanders + textDirty = TRUE; + d->edited = TRUE; + } + curXPos = 0; + makeVisible(); + turnMark( FALSE ); +} + + +/* + Moves the cursor one character to the left. If \a mark is TRUE, the text + is marked. If \a wrap is TRUE, the cursor moves to the end of the + previous line if it is placed at the beginning of the current line. + + \sa cursorRight() cursorUp() cursorDown() +*/ + +void QtMultiLineEdit::cursorLeft( bool mark, bool wrap ) +{ + cursorLeft(mark,!mark,wrap); +} +void QtMultiLineEdit::cursorLeft( bool mark, bool clear_mark, bool wrap ) +{ + if ( cursorX != 0 || cursorY != 0 && wrap ) { + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + d->blinkTimer->stop(); + int ll = lineLength( cursorY ); + if ( cursorX > ll ) + cursorX = ll; + cursorOn = TRUE; + cursorX--; + if ( cursorX < 0 ) { + int oldY = cursorY; + if ( cursorY > 0 ) { + cursorY--; + cursorX = lineLength( cursorY ); + if ( cursorX > 1 && !isEndOfParagraph( cursorY ) ) + cursorX--; + } else { + cursorY = 0; //### ? + cursorX = 0; + } + updateCell( oldY, 0, FALSE ); + } + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + updateCell( cursorY, 0, FALSE ); + } + curXPos = 0; + makeVisible(); + if ( clear_mark ) + turnMark( FALSE ); +} + +/* + Moves the cursor one character to the right. If \a mark is TRUE, the text + is marked. If \a wrap is TRUE, the cursor moves to the beginning of the next + line if it is placed at the end of the current line. + \sa cursorLeft() cursorUp() cursorDown() +*/ + +void QtMultiLineEdit::cursorRight( bool mark, bool wrap ) +{ + cursorRight(mark,!mark,wrap); +} +void QtMultiLineEdit::cursorRight( bool mark, bool clear_mark, bool wrap ) +{ + int strl = lineLength( cursorY ); + if ( strl > 1 && !isEndOfParagraph( cursorY ) ) + strl--; + if ( cursorX < strl || cursorY < (int)contents->count() - 1 && wrap ) { + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + d->blinkTimer->stop(); + cursorOn = TRUE; + cursorX++; + if ( cursorX > strl ) { + int oldY = cursorY; + if ( cursorY < (int) contents->count() - 1 ) { + cursorY++; + cursorX = 0; + } else { + cursorX = lineLength( cursorY ); + } + updateCell( oldY, 0, FALSE ); + } + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + updateCell( cursorY, 0, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + } + curXPos = 0; + makeVisible(); + if ( clear_mark ) + turnMark( FALSE ); +} + +/* + Moves the cursor up one line. If \a mark is TRUE, the text + is marked. + \sa cursorDown() cursorLeft() cursorRight() +*/ + +void QtMultiLineEdit::cursorUp( bool mark ) +{ + cursorUp(mark,!mark); +} +void QtMultiLineEdit::cursorUp( bool mark, bool clear_mark ) +{ + if ( cursorY != 0 ) { + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + if ( !curXPos ) + curXPos = mapToView( cursorX, cursorY ); + int oldY = cursorY; + d->blinkTimer->stop(); + cursorOn = TRUE; + cursorY--; + if ( cursorY < 0 ) { + cursorY = 0; + } + cursorX = mapFromView( curXPos, cursorY ); + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + updateCell( oldY, 0, FALSE ); + updateCell( cursorY, 0, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + } + makeVisible(); + if ( clear_mark ) + turnMark( FALSE ); +} + +/* + Moves the cursor one line down. If \a mark is TRUE, the text + is marked. + \sa cursorUp() cursorLeft() cursorRight() +*/ + +void QtMultiLineEdit::cursorDown( bool mark ) +{ + cursorDown(mark,!mark); +} +void QtMultiLineEdit::cursorDown( bool mark, bool clear_mark ) +{ + int lastLin = contents->count() - 1; + if ( cursorY != lastLin ) { + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + if ( !curXPos ) + curXPos = mapToView( cursorX, cursorY ); + int oldY = cursorY; + d->blinkTimer->stop(); + cursorOn = TRUE; + cursorY++; + if ( cursorY > lastLin ) { + cursorY = lastLin; + } + cursorX = mapFromView( curXPos, cursorY ); + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + updateCell( oldY, 0, FALSE ); + updateCell( cursorY, 0, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + } + makeVisible(); + if ( clear_mark ) + turnMark( FALSE ); +} + +/* + Turns off marked text +*/ +void QtMultiLineEdit::turnMark( bool on ) +{ + if ( on != markIsOn ) { + markIsOn = on; + if ( echoMode() == Normal ) + emit copyAvailable( on ); + update(); + } +} + + + + +/* + Deletes the character on the left side of the text cursor and moves + the cursor one position to the left. If a text has been marked by + the user (e.g. by clicking and dragging) the cursor is put at the + beginning of the marked text and the marked text is removed. + \sa del() +*/ + +void QtMultiLineEdit::backspace() +{ + if ( hasMarkedText() ) { + del(); + } else { + if ( !atBeginning() ) { + cursorLeft( FALSE ); + del(); + } + } + makeVisible(); +} + +void QtMultiLineEdit::delAux() +{ + int markBeginX, markBeginY; + int markEndX, markEndY; + QRect oldContents = contentsRect(); + if ( getMarkedRegion( &markBeginY, &markBeginX, &markEndY, &markEndX ) ) { + turnMark( FALSE ); + textDirty = TRUE; + d->edited = TRUE; + if ( markBeginY == markEndY ) { //just one line + QtMultiLineEditRow *r = contents->at( markBeginY ); + ASSERT(r); + bool recalc = r->w == maxLineWidth(); + r->s.remove( markBeginX, markEndX - markBeginX ); + r->w = textWidth( r->s ); + cursorX = markBeginX; + cursorY = markBeginY; + + if (autoUpdate() ) + updateCell( cursorY, 0, FALSE ); + if ( recalc ) + updateCellWidth(); + } else { //multiline + bool oldAuto = autoUpdate(); + setAutoUpdate( FALSE ); + ASSERT( markBeginY >= 0); + ASSERT( markEndY < (int)contents->count() ); + + QtMultiLineEditRow *firstR, *lastR; + firstR = contents->at( markBeginY ); + lastR = contents->at( markEndY ); + ASSERT( firstR != lastR ); + firstR->s.remove( markBeginX, firstR->s.length() - markBeginX ); + lastR->s.remove( 0, markEndX ); + firstR->s.append( lastR->s ); // lastS will be removed in loop below + firstR->newline = lastR->newline; // Don't forget this -sanders + firstR->w = textWidth( firstR->s ); + + for( int i = markBeginY + 1 ; i <= markEndY ; i++ ) + contents->remove( markBeginY + 1 ); + + if ( contents->isEmpty() ) + insertLine( QString::fromLatin1(""), -1 ); + + cursorX = markBeginX; + cursorY = markBeginY; + curXPos = 0; + + setNumRowsAndTruncate(); + updateCellWidth(); + setAutoUpdate( oldAuto ); + if ( autoUpdate() ) + update(); + } + markAnchorY = markDragY = cursorY; + markAnchorX = markDragX = cursorX; + } else { + if ( !atEnd() ) { + textDirty = TRUE; + d->edited = TRUE; + QtMultiLineEditRow *r = contents->at( cursorY ); + if ( cursorX == (int) r->s.length() ) { // remove newline + QtMultiLineEditRow* other = contents->at( cursorY + 1 ); + if ( ! r->newline && cursorX ) + r->s.truncate( r->s.length()-1 ); + + bool needBreak = !r->s.isEmpty(); + r->s += other->s; + r->newline = other->newline; + contents->remove( cursorY + 1 ); + if ( needBreak ) + rebreakParagraph( cursorY, 1 ); + else + wrapLine( cursorY, 1 ); + } else { + bool recalc = r->w == maxLineWidth(); + r->s.remove( cursorX, 1 ); + rebreakParagraph( cursorY ); + if ( recalc ) + updateCellWidth(); + } + } + } + if ( DYNAMIC_WRAP && oldContents != contentsRect() ) { + if ( oldContents.width() != contentsRect().width() ) { + bool oldAuto = autoUpdate(); + setAutoUpdate( FALSE ); + rebreakAll(); + setAutoUpdate( oldAuto ); + } + if ( autoUpdate() ) + update(); + } + curXPos = 0; + makeVisible(); +} + +/* + Moves the text cursor to the left end of the line. If \a mark is + TRUE, text is marked towards the first position. If it is FALSE and + the cursor is moved, all marked text is unmarked. + + \sa end() +*/ + +void QtMultiLineEdit::home( bool mark ) +{ + if ( cursorX != 0 ) { + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + d->blinkTimer->stop(); + cursorX = 0; + cursorOn = TRUE; + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + updateCell( cursorY, 0, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + } + curXPos = 0; + if ( !mark ) + turnMark( FALSE ); + makeVisible(); +} + +/* + Moves the text cursor to the right end of the line. If \a mark is TRUE + text is marked towards the last position. If it is FALSE and the + cursor is moved, all marked text is unmarked. + + \sa home() +*/ + +void QtMultiLineEdit::end( bool mark ) +{ + int tlen = lineLength( cursorY ); + if ( cursorX != tlen ) { + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + d->blinkTimer->stop(); + cursorX = tlen; + cursorOn = TRUE; + if ( mark ) + newMark( cursorX, cursorY, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); + updateCell( cursorY, 0, FALSE ); + } + curXPos = 0; + makeVisible(); + if ( !mark ) + turnMark( FALSE ); +} + +/*\reimp +*/ +void QtMultiLineEdit::mousePressEvent( QMouseEvent *e ) +{ + stopAutoScroll(); + d->dnd_startpos = e->pos(); + + if ( e->button() == RightButton ) { + QPopupMenu *popup = new QPopupMenu( this ); + int id[ (int)IdCount ]; + id[ IdUndo ] = popup->insertItem( tr( "Undo" ) ); + id[ IdRedo ] = popup->insertItem( tr( "Redo" ) ); + popup->insertSeparator(); +#ifndef QT_NO_CLIPBOARD + id[ IdCut ] = popup->insertItem( tr( "Cut" ) ); + id[ IdCopy ] = popup->insertItem( tr( "Copy" ) ); + id[ IdPaste ] = popup->insertItem( tr( "Paste" ) ); +#ifndef QT_NO_MIMECLIPBOARD + id[ IdPasteSpecial ] = popup->insertItem( tr( "Paste special..." ) ); +#endif +#endif + id[ IdClear ] = popup->insertItem( tr( "Clear" ) ); + popup->insertSeparator(); + id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) ); + popup->setItemEnabled( id[ IdUndo ], + !this->d->undoList.isEmpty() ); + popup->setItemEnabled( id[ IdRedo ], + !this->d->redoList.isEmpty() ); +#ifndef QT_NO_CLIPBOARD + popup->setItemEnabled( id[ IdCut ], + !isReadOnly() && hasMarkedText() ); + popup->setItemEnabled( id[ IdCopy ], hasMarkedText() ); + popup->setItemEnabled( id[ IdPaste ], + !isReadOnly() && (bool)QApplication::clipboard()->text().length() ); +#ifndef QT_NO_MIMECLIPBOARD + // Any non-plain types? + QMimeSource* ms = QApplication::clipboard()->data(); + bool ps = FALSE; + if ( ms ) { + if ( !isReadOnly() ) { + const char* fmt; + for (int i=0; !ps && (fmt=ms->format(i)); i++) { + ps = qstrnicmp(fmt,"text/",5)==0 + && qstrnicmp(fmt+5,"plain",5)!=0; + } + } + } + popup->setItemEnabled( id[ IdPasteSpecial ], ps ); +#endif +#endif + popup->setItemEnabled( id[ IdClear ], + !isReadOnly() && (bool)text().length() ); + int allSelected = markIsOn && markAnchorX == 0 && markAnchorY == 0 && + markDragY == numLines() - 1 && markDragX == lineLength( markDragY ); + popup->setItemEnabled( id[ IdSelectAll ], + (bool)text().length() && !allSelected ); + + int r = popup->exec( e->globalPos() ); + delete popup; + + if ( r == id[ IdUndo ] ) + undo(); + else if ( r == id[ IdRedo ] ) + redo(); +#ifndef QT_NO_CLIPBOARD + else if ( r == id[ IdCut ] ) + cut(); + else if ( r == id[ IdCopy ] ) + copy(); + else if ( r == id[ IdPaste ] ) + paste(); +# ifndef QT_NO_MIMECLIPBOARD + else if ( r == id[ IdPasteSpecial ] ) + pasteSpecial(QCursor::pos()); +# endif +#endif + else if ( r == id[ IdClear ] ) + clear(); + else if ( r == id[ IdSelectAll ] ) + selectAll(); + return; + } + + if ( e->button() != MidButton && e->button() != LeftButton) + return; + + int newX, newY; + pixelPosToCursorPos( e->pos(), &newX, &newY ); + + if ( e->state() & ShiftButton ) { + wordMark = FALSE; + dragMarking = TRUE; + setCursorPosition( newY, newX, TRUE); + return; + } + +#ifndef QT_NO_DRAGANDDROP + if ( + inMark(newX, newY) // Click on highlighted text + && echoMode() == Normal // No DnD of passwords, etc. + && e->pos().y() < totalHeight() // Click past the end is not dragging + ) + { + // The user might be trying to drag + d->dnd_primed = TRUE; + d->dnd_timer->start( QApplication::startDragTime(), FALSE ); + } else +#endif + { + wordMark = FALSE; + dragMarking = TRUE; + setCursorPixelPosition(e->pos()); + } +} + +void QtMultiLineEdit::pixelPosToCursorPos(QPoint p, int* x, int* y) const +{ + *y = findRow( p.y() ); + if ( *y < 0 ) { + if ( p.y() < lineWidth() ) { + *y = topCell(); + } else { + *y = lastRowVisible(); + p.setX(cellWidth()); + } + } + *y = QMIN( (int)contents->count() - 1, *y ); + QFontMetrics fm( font() ); + *x = xPosToCursorPos( stringShown( *y ), fm, + p.x() - d->lr_marg + xOffset(), + cellWidth() - 2 * d->lr_marg - d->marg_extra, + d->align ); + QtMultiLineEditRow* r = contents->at( *y ); + if (r && !r->newline && ((unsigned int)*x == r->s.length()) && (*x > 0)) + --*x; +} + +void QtMultiLineEdit::setCursorPixelPosition(QPoint p, bool clear_mark) +{ + int newY; + pixelPosToCursorPos( p, &cursorX, &newY ); + curXPos = 0; + if ( clear_mark ) { + markAnchorX = cursorX; + markAnchorY = newY; + bool markWasOn = markIsOn; + turnMark( FALSE ); + if ( markWasOn ) { + cursorY = newY; + update(); + d->isHandlingEvent = FALSE; + return; + } + } + if ( cursorY != newY ) { + int oldY = cursorY; + cursorY = newY; + updateCell( oldY, 0, FALSE ); + } + updateCell( cursorY, 0, FALSE ); // ### +} + +void QtMultiLineEdit::startAutoScroll() +{ + if ( !dragScrolling ) { + d->scrollTime = initialScrollTime; + d->scrollAccel = initialScrollAccel; + d->scrollTimer->start( d->scrollTime, FALSE ); + dragScrolling = TRUE; + } +} + +void QtMultiLineEdit::stopAutoScroll() +{ + if ( dragScrolling ) { + d->scrollTimer->stop(); + dragScrolling = FALSE; + } +} + +/*\reimp +*/ +void QtMultiLineEdit::mouseMoveEvent( QMouseEvent *e ) +{ +#ifndef QT_NO_DRAGANDDROP + d->dnd_timer->stop(); + if ( d->dnd_primed && + ( d->dnd_startpos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) { + doDrag(); + return; + } +#endif + if ( !dragMarking ) + return; + if ( rect().contains( e->pos() ) ) { + stopAutoScroll(); + } else if ( !dragScrolling ) { + startAutoScroll(); + } + + int newX, newY; + pixelPosToCursorPos(e->pos(), &newX, &newY); + + if ( wordMark ) { + extendSelectionWord( newX, newY); + } + + if ( markDragX == newX && markDragY == newY ) + return; + int oldY = markDragY; + newMark( newX, newY, FALSE ); + for ( int i = QMIN(oldY,newY); i <= QMAX(oldY,newY); i++ ) + updateCell( i, 0, FALSE ); +} + +void QtMultiLineEdit::extendSelectionWord( int &newX, int&newY) +{ + QString s = stringShown( newY ); + int lim = s.length(); + if ( newX >= 0 && newX < lim ) { + int i = newX; + int startclass = charClass(s.at(i)); + if ( markAnchorY < markDragY || + ( markAnchorY == markDragY && markAnchorX < markDragX ) ) { + // going right + while ( i < lim && charClass(s.at(i)) == startclass ) + i++; + } else { + // going left + while ( i >= 0 && charClass(s.at(i)) == startclass ) + i--; + i++; + } + newX = i; + } +} + + + + +/*\reimp +*/ +void QtMultiLineEdit::mouseReleaseEvent( QMouseEvent *e ) +{ + stopAutoScroll(); +#ifndef QT_NO_DRAGANDDROP + if ( d->dnd_timer->isActive() ) { + d->dnd_timer->stop(); + d->dnd_primed = FALSE; + setCursorPixelPosition(e->pos()); + } +#endif + wordMark = FALSE; + dragMarking = FALSE; + textDirty = FALSE; + d->isHandlingEvent = TRUE; + if ( markAnchorY == markDragY && markAnchorX == markDragX ) + turnMark( FALSE ); + +#ifndef QT_NO_CLIPBOARD +#if defined(_WS_X11_) + else if ( echoMode() == Normal ) + copy(); +#endif + + if ( e->button() == MidButton && !readOnly ) { +#if defined(_WS_X11_) + paste(); // Will repaint the cursor line. +#else +#ifndef QT_NO_COMPAT + if ( style().styleHint(QStyle::SH_GUIStyle) == Qt::MotifStyle ) + paste(); +#endif +#endif + } +#endif + + d->isHandlingEvent = FALSE; + + if ( !readOnly && textDirty ) + emit textChanged(); +} + + +/*\reimp +*/ +void QtMultiLineEdit::mouseDoubleClickEvent( QMouseEvent *m ) +{ + if ( m->button() == LeftButton ) { + if ( m->state() & ShiftButton ) { + int newX = cursorX; + int newY = cursorY; + extendSelectionWord( newX, newY); + newMark( newX, newY, FALSE ); + } else { + markWord( cursorX, cursorY ); + } + dragMarking = TRUE; + wordMark = TRUE; + updateCell( cursorY, 0, FALSE ); + + } +} + +#ifndef QT_NO_DRAGANDDROP + +/* + \reimp +*/ + +void QtMultiLineEdit::dragEnterEvent( QDragEnterEvent * ) +{ + cursorOn = TRUE; + updateCell( cursorY, 0, FALSE ); +} + +/*\reimp +*/ +void QtMultiLineEdit::dragMoveEvent( QDragMoveEvent* event ) +{ + if ( readOnly ) return; + event->accept( QTextDrag::canDecode(event) ); + d->dnd_forcecursor = TRUE; + setCursorPixelPosition(event->pos(), FALSE); + d->dnd_forcecursor = FALSE; + QRect inside_margin(scroll_margin, scroll_margin, + width()-scroll_margin*2, height()-scroll_margin*2); + if ( !inside_margin.contains(event->pos()) ) { + startAutoScroll(); + } + if ( event->source() == this && event->action() == QDropEvent::Move ) + event->acceptAction(); +} + +/*\reimp +*/ +void QtMultiLineEdit::dragLeaveEvent( QDragLeaveEvent* ) +{ + if ( cursorOn ) { + cursorOn = FALSE; + updateCell( cursorY, 0, FALSE ); + } + stopAutoScroll(); +} + +/*\reimp +*/ +void QtMultiLineEdit::dropEvent( QDropEvent* event ) +{ + if ( readOnly ) return; + QString text; + QCString fmt = pickSpecial(event,FALSE,event->pos()); + if ( QTextDrag::decode(event, text, fmt) ) { + int i = -1; + while ( ( i = text.find( '\r' ) ) != -1 ) + text.replace( i,1,"" ); + if ( event->source() == this && event->action() == QDropEvent::Move ) { + event->acceptAction(); + // Careful not to tread on my own feet + int newX, newY; + pixelPosToCursorPos( event->pos(), &newX, &newY ); + if ( afterMark( newX, newY ) ) { + // The tricky case + int x1, y1, x2, y2; + getMarkedRegion( &y1, &x1, &y2, &x2 ); + if ( newY == y2 ) { + newY = y1; + newX = x1 + newX - x2; + } else { + newY -= y2 - y1; + } + addUndoCmd( new QBeginCommand ); + del(); + setCursorPosition(newY, newX); + insert(text, TRUE); + addUndoCmd( new QEndCommand ); + } else if ( beforeMark( newX, newY ) ) { + // Easy + addUndoCmd( new QBeginCommand ); + del(); + setCursorPosition(newY, newX); + insert(text, TRUE); + addUndoCmd( new QEndCommand ); + } else { + // Do nothing. + } + } else { + setCursorPixelPosition(event->pos()); + insert(text, TRUE); + } + update(); + emit textChanged(); + } +} + +#endif // QT_NO_DRAGANDDROP + + +/* + Returns TRUE if line \a line is invisible or partially invisible. +*/ + +bool QtMultiLineEdit::partiallyInvisible( int line ) +{ + int y; + if ( !rowYPos( line, &y ) ) + return TRUE; + if ( y < 0 ) + return TRUE; + else if ( y + cellHeight() - 2 > viewHeight() ) + return TRUE; + + return FALSE; +} + +/* + Scrolls such that the cursor is visible +*/ + +void QtMultiLineEdit::makeVisible() +{ + if ( !autoUpdate() ) + return; + + if ( partiallyInvisible( cursorY ) ) { + if ( cursorY >= lastRowVisible() ) + setBottomCell( cursorY ); + else + setTopCell( cursorY ); + } + int xPos = mapToView( cursorX, cursorY ); + if ( xPos < xOffset() ) { + int of = xPos - 10; //### + setXOffset( of ); + } else if ( xPos > xOffset() + viewWidth() ) { + int of = xPos - viewWidth() + 10; //### + setXOffset( of ); + } +} + +/* + Computes the character position in line \a line which corresponds + to pixel \a xPos +*/ + +int QtMultiLineEdit::mapFromView( int xPos, int line ) +{ + QString s = stringShown( line ); + if ( !s ) + return 0; + QFontMetrics fm( font() ); + int index = xPosToCursorPos( s, fm, + xPos - d->lr_marg, + cellWidth() - 2 * d->lr_marg - d->marg_extra, + d->align ); + QtMultiLineEditRow* r = contents->at( line ); + if (r && !r->newline && ((unsigned int)index == r->s.length()) && (index > 0)) + --index; + return index; +} + +/* + Computes the pixel position in line \a line which corresponds to + character position \a xIndex +*/ + +int QtMultiLineEdit::mapToView( int xIndex, int line ) +{ + QString s = stringShown( line ); + xIndex = QMIN( (int)s.length(), xIndex ); + QFontMetrics fm( font() ); + int wcell = cellWidth() - 2 * d->lr_marg;// - d->marg_extra; + int wrow = contents->at( line )->w; + int w = textWidthWithTabs( fm, s, 0, xIndex, d->align ) - 1; + if ( d->align == Qt::AlignCenter || d->align == Qt::AlignHCenter ) + w += (wcell - wrow) / 2; + else if ( d->align == Qt::AlignRight ) + w += wcell - wrow; + return d->lr_marg + w; +} + +/* + Traverses the list and finds an item with the maximum width, and + updates the internal list box structures accordingly. +*/ + +void QtMultiLineEdit::updateCellWidth() +{ + QtMultiLineEditRow* r = contents->first(); + int maxW = 0; + int w; + switch ( d->echomode ) { + case Normal: + while ( r ) { + w = r->w; + if ( w > maxW ) + maxW = w; + r = contents->next(); + } + break; + case Password: { + uint l = 0; + while ( r ) { + l = QMAX(l, r->s.length() ); + r = contents->next(); + } + QString t; + t.fill(QChar('*'), l); + maxW = textWidth(t); + } + break; + case NoEcho: + maxW = textWidth(QString::fromLatin1("")); + } + setWidth( maxW ); +} + + +/* + Sets the bottommost visible line to \a line. +*/ + +void QtMultiLineEdit::setBottomCell( int line ) +{ + int rowY = cellHeight() * line; + int newYPos = rowY + cellHeight() - viewHeight(); + setYOffset( QMAX( newYPos, 0 ) ); +} + +#ifndef QT_NO_CLIPBOARD + +/* + Copies text in MIME subtype \a subtype from the clipboard onto the current + cursor position. + Any marked text is first deleted. +*/ +void QtMultiLineEdit::pasteSubType(const QCString& subtype) +{ + QCString st = subtype; + addUndoCmd( new QBeginCommand ); + + if ( hasMarkedText() ) + del(); + QString t = QApplication::clipboard()->text(st); + if ( !t.isEmpty() ) { + if ( hasMarkedText() ) + turnMark( FALSE ); + +#if defined(_OS_WIN32_) + // Need to convert CRLF to NL + t.replace( "\r\n", "\n" ); +#endif + + for (int i=0; (uint)i<t.length(); i++) { + if ( t[i] < ' ' && t[i] != '\n' && t[i] != '\t' ) + t[i] = ' '; + } + insertAt( t, cursorY, cursorX ); + turnMark( FALSE ); + curXPos = 0; + makeVisible(); + } + if ( textDirty && !d->isHandlingEvent ) + emit textChanged(); + + addUndoCmd( new QEndCommand ); +} + +/* + Copies plain text from the clipboard onto the current cursor position. + Any marked text is first deleted. +*/ +void QtMultiLineEdit::paste() +{ + pasteSubType("plain"); +} + +#ifndef QT_NO_MIMECLIPBOARD +/* + Prompts the user for a type from a list of text types available, + Then copies text from the clipboard onto the current cursor position. + Any marked text is first deleted. +*/ +void QtMultiLineEdit::pasteSpecial(const QPoint& pt) +{ + QCString st = pickSpecial(QApplication::clipboard()->data(),TRUE,pt); + if ( !st.isEmpty() ) + pasteSubType(st); +} +#endif +#ifndef QT_NO_MIME +QCString QtMultiLineEdit::pickSpecial(QMimeSource* ms, bool always_ask, const QPoint& pt) +{ + if ( ms ) { + QPopupMenu popup(this); + QString fmt; + int n=0; + QDict<void> done; + for (int i=0; !(fmt=ms->format(i)).isNull(); i++) { + int semi=fmt.find(";"); + if ( semi >= 0 ) + fmt = fmt.left(semi); + if ( fmt.left(5) == "text/" ) { + fmt = fmt.mid(5); + if ( !done.find(fmt) ) { + done.insert(fmt,(void*)1); + popup.insertItem(fmt,i); + n++; + } + } + } + if ( n ) { + int i = n==1 && !always_ask ? popup.idAt(0) : popup.exec(pt); + if ( i >= 0 ) + return popup.text(i).latin1(); + } + } + return QCString(); +} +#endif // QT_NO_MIME +#endif // QT_NO_CLIPBOARD + + +/* + Removes all text. +*/ + +void QtMultiLineEdit::clear() +{ + addUndoCmd( new QDelTextCmd( 0, text() ) ); + setEdited( TRUE ); + contents->clear(); + cursorX = cursorY = 0; + int w = textWidth( QString::fromLatin1("") ); + contents->append( new QtMultiLineEditRow(QString::fromLatin1(""), w) ); + setNumRowsAndTruncate(); + setWidth( w ); + dummy = TRUE; + turnMark( FALSE ); + if ( autoUpdate() ) + update(); + if ( !d->isHandlingEvent ) //# && not already empty + emit textChanged(); + update(); +} + + +/*\reimp +*/ + +void QtMultiLineEdit::setFont( const QFont &font ) +{ + QWidget::setFont( font ); + d->clearChartable(); + QFontMetrics fm( font ); + setCellHeight( fm.lineSpacing() ); + for ( QtMultiLineEditRow* r = contents->first(); r; r = contents->next() ) + r->w = textWidth( r->s ); + rebreakAll(); + updateCellWidth(); +} + +/* + Sets a new marked text limit, does not repaint the widget. +*/ + +void QtMultiLineEdit::newMark( int posx, int posy, bool /*copy*/ ) +{ + if ( markIsOn && markDragX == posx && markDragY == posy && + cursorX == posx && cursorY == posy ) + return; + markDragX = posx; + markDragY = posy; + cursorX = posx; + cursorY = posy; + turnMark( markDragX != markAnchorX || markDragY != markAnchorY ); +} + +bool QtMultiLineEdit::beforeMark( int posx, int posy ) const +{ + int x1, y1, x2, y2; + if ( !getMarkedRegion( &y1, &x1, &y2, &x2 ) ) + return FALSE; + return + (y1 > posy || y1 == posy && x1 > posx) + && (y2 > posy || y2 == posy && x2 > posx); +} + +bool QtMultiLineEdit::afterMark( int posx, int posy ) const +{ + int x1, y1, x2, y2; + if ( !getMarkedRegion( &y1, &x1, &y2, &x2 ) ) + return FALSE; + return + (y1 < posy || y1 == posy && x1 < posx) + && (y2 < posy || y2 == posy && x2 < posx); +} + +bool QtMultiLineEdit::inMark( int posx, int posy ) const +{ + int x1, y1, x2, y2; + if ( !getMarkedRegion( &y1, &x1, &y2, &x2 ) ) + return FALSE; + return + (y1 < posy || y1 == posy && x1 <= posx) + && (y2 > posy || y2 == posy && x2 >= posx); +} + +/* + Marks the word at character position \a posx, \a posy. + */ +void QtMultiLineEdit::markWord( int posx, int posy ) +{ + QString& s = contents->at( posy )->s; + + int i = posx - 1; + while ( i >= 0 && s[i].isPrint() && !s[i].isSpace() ) + i--; + i++; + markAnchorY = posy; + markAnchorX = i; + + while ( s[i].isPrint() && !s[i].isSpace() ) + i++; + markDragX = i; + markDragY = posy; + turnMark( markDragX != markAnchorX || markDragY != markAnchorY ); + +#ifndef QT_NO_CLIPBOARD +#if defined(_WS_X11_) + if ( echoMode() == Normal ) + copy(); +#endif +#endif +} + +/* + This may become a protected virtual member in a future Qt. + This implementation is an example of a useful classification + that aids selection of common units like filenames and URLs. +*/ +int QtMultiLineEdit::charClass( QChar ch ) +{ + if ( !ch.isPrint() || ch.isSpace() ) return 1; + else if ( ch.isLetter() || ch=='-' || ch=='+' || ch==':' + || ch=='.' || ch=='/' || ch=='\\' + || ch=='@' || ch=='$' || ch=='~' ) return 2; + else return 3; +} + +#ifndef QT_NO_CLIPBOARD +/* + Copies the marked text to the clipboard. Will copy only + if echoMode() is Normal. +*/ + +void QtMultiLineEdit::copy() const +{ + QString t = markedText(); + if ( !t.isEmpty() && echoMode() == Normal ) { +#if defined(_WS_X11_) + disconnect( QApplication::clipboard(), SIGNAL(dataChanged()), this, 0); +#endif +#if defined(_OS_WIN32_) + // Need to convert NL to CRLF + t.replace( "\n", "\r\n" ); +#endif + QApplication::clipboard()->setText( t ); +#if defined(_WS_X11_) + connect( QApplication::clipboard(), SIGNAL(dataChanged()), + this, SLOT(clipboardChanged()) ); +#endif + } +} + +/* \obsolete + + Backward compatibility. +*/ +void QtMultiLineEdit::copyText() const +{ + copy(); +} + +/* + Copies the selected text to the clipboard and deletes the selected text. +*/ + +void QtMultiLineEdit::cut() +{ + if ( hasMarkedText() ) { + if ( echoMode() == Normal ) + copy(); + del(); + if ( textDirty && !d->isHandlingEvent ) + emit textChanged(); + } +} + +#endif + +/* + This private slot is activated when this line edit owns the clipboard and + some other widget/application takes over the clipboard. (X11 only) +*/ + +void QtMultiLineEdit::clipboardChanged() +{ +#if defined(_WS_X11_) + disconnect( QApplication::clipboard(), SIGNAL(dataChanged()), + this, SLOT(clipboardChanged()) ); + turnMark( FALSE ); + update(); +#endif +} + + +/* + Sets maxLineWidth() and maybe cellWidth() to \a w without updating the entire widget. + */ + +void QtMultiLineEdit::setWidth( int w ) +{ + if ( w ==d->maxLineWidth ) + return; + bool u = autoUpdate(); + setAutoUpdate( FALSE ); + d->maxLineWidth = w; + if ( d->align == AlignLeft ) + setCellWidth( w ); + else + setCellWidth( QMAX( w, contentsRect().width() ) ); + setAutoUpdate( u ); + if ( autoUpdate() && d->align != AlignLeft ) + update(); +} + + +/* + Sets the cursor position to character number \a col in line number \a line. + The parameters are adjusted to lie within the legal range. + + If \a mark is FALSE, the selection is cleared. otherwise it is extended + + \sa cursorPosition() +*/ + +void QtMultiLineEdit::setCursorPosition( int line, int col, bool mark ) +{ + if ( mark && !hasMarkedText() ) { + markAnchorX = cursorX; + markAnchorY = cursorY; + } + int oldY = cursorY; + cursorY = QMAX( QMIN( line, numLines() - 1), 0 ); + cursorX = QMAX( QMIN( col, lineLength( cursorY )), 0 ); + curXPos = 0; + makeVisible(); + if ( mark ) { + newMark( cursorX, cursorY, FALSE ); + for ( int i = QMIN(oldY,cursorY); i <= QMAX(oldY,cursorY); i++ ) + updateCell( i, 0, FALSE ); + } else { + updateCell( oldY, 0, FALSE ); + turnMark( FALSE ); + } +} + + + +/* \obsolete + + Use getCursorPosition() instead. +*/ + +void QtMultiLineEdit::cursorPosition( int *line, int *col ) const +{ + getCursorPosition(line,col); +} + + +/* + Returns the current line and character + position within that line, in the variables pointed to + by \a line and \a col respectively. + + \sa setCursorPosition() +*/ + +void QtMultiLineEdit::getCursorPosition( int *line, int *col ) const +{ + if ( line ) + *line = cursorY; + if ( col ) + *col = cursorX; +} + + +/* + \sa setAutoUpdate() +*/ + +bool QtMultiLineEdit::autoUpdate() const +{ + return QtTableView::autoUpdate(); +} + + +/* + Sets the auto-update option of multi-line editor to \a enable. + +*/ + +void QtMultiLineEdit::setAutoUpdate( bool enable ) +{ + QtTableView::setAutoUpdate( enable ); +} + +/* + Sets the fixed height of the QtMultiLineEdit so that \a lines text lines + are visible given the current font. + + \sa setMaxLines(), setFixedHeight() + */ +void QtMultiLineEdit::setFixedVisibleLines( int lines ) +{ + int ls = fontMetrics().lineSpacing(); + setFixedHeight( frameWidth()*2 + ls*lines ); + return; +} + + + +/* + Returns the top center point where the cursor is drawn +*/ + +QPoint QtMultiLineEdit::cursorPoint() const +{ + QPoint cp( 0, 0 ); + + QFontMetrics fm( font() ); + int col, row; + col = row = 0; + cursorPosition( &row, &col ); + QString line = textLine( row ); + ASSERT( line ); + cp.setX( d->lr_marg + textWidthWithTabs( fm, line, 0, col, d->align ) - 1 ); + cp.setY( (row * cellHeight()) + viewRect().y() ); + return cp; +} + + +/* \reimp +*/ +QSizePolicy QtMultiLineEdit::sizePolicy() const +{ + //### removeme 3.0 + return QWidget::sizePolicy(); +} + + +/*\reimp +*/ +QSize QtMultiLineEdit::sizeHint() const +{ + constPolish(); + int expected_lines; + if ( d->maxlines >= 0 && d->maxlines <= 6 ) { + expected_lines = d->maxlines; + } else { + expected_lines = 6; + } + QFontMetrics fm( font() ); + int h = fm.lineSpacing()*(expected_lines-1)+fm.height() + frameWidth()*2; + int w = fm.width('x')*35; + + int maxh = maximumSize().height(); + if ( maxh < QWIDGETSIZE_MAX ) + h = maxh; + + return QSize( w, h ).expandedTo( QApplication::globalStrut() ); +} + + +/* + Returns a size sufficient for one character, and scroll bars. +*/ + +QSize QtMultiLineEdit::minimumSizeHint() const +{ + constPolish(); + QFontMetrics fm( font() ); + int h = fm.lineSpacing() + frameWidth()*2; + int w = fm.maxWidth(); + h += frameWidth(); + w += frameWidth(); + if ( testTableFlags(Tbl_hScrollBar|Tbl_autoHScrollBar) ) + w += verticalScrollBar()->sizeHint().width(); + if ( testTableFlags(Tbl_vScrollBar|Tbl_autoVScrollBar) ) + h += horizontalScrollBar()->sizeHint().height(); + return QSize(w,h); +} + + + +/*\reimp +*/ + +void QtMultiLineEdit::resizeEvent( QResizeEvent *e ) +{ + int oldw = contentsRect().width(); + QtTableView::resizeEvent( e ); + if ( DYNAMIC_WRAP + && (e->oldSize().width() != width() + || oldw != contentsRect().width() ) ) { + bool oldAuto = autoUpdate(); + setAutoUpdate( FALSE ); + rebreakAll(); + if ( oldw != contentsRect().width() ) + rebreakAll(); + setAutoUpdate( oldAuto ); + if ( autoUpdate() ) + repaint( FALSE ); + } else if ( d->align != AlignLeft ) { + d->maxLineWidth = 0; // trigger update + updateCellWidth(); + } + if ( isVisible() ) + deselect(); +} + +/* + Sets the alignment to \a flags. Possible values are \c AlignLeft, \c + Align(H)Center and \c AlignRight. + + \sa alignment(), Qt::AlignmentFlags +*/ +void QtMultiLineEdit::setAlignment( int flags ) +{ + if ( d->align != flags ) { + d->align = flags; + update(); + } +} + +/* + Returns the alignment. + +*/ +int QtMultiLineEdit::alignment() const +{ + return d->align; +} + + +/* + Not supported at this time. + \a v is the validator to set. +*/ +void QtMultiLineEdit::setValidator( const QValidator *v ) +{ + d->val = v; + // #### validate text now +} + +/* + Not supported at this time. +*/ +const QValidator * QtMultiLineEdit::validator() const +{ + return d->val; +} + +/* \sa edited() +*/ +void QtMultiLineEdit::setEdited( bool e ) +{ + d->edited = e; +} + +/* \sa setEdited() +*/ +bool QtMultiLineEdit::edited() const +{ + return d->edited; +} + +/* \enum QtMultiLineEdit::EchoMode + + This enum type describes the ways in which QLineEdit can display its + contents. The currently defined values are: \list + + \i Normal - display characters as they are entered. This is + the default. + + \i NoEcho - do not display anything. + + \i Password - display asterisks instead of the characters + actually entered. + + \endlist + + \sa setEchoMode() echoMode() QLineEdit::EchoMode +*/ + + +/* + Sets the echo mode to \a em. The default is \c Normal. + + The display is updated according. + + \sa setEchoMode() +*/ +void QtMultiLineEdit::setEchoMode( EchoMode em ) +{ + if ( d->echomode != em ) { + d->echomode = em; + updateCellWidth(); + update(); + } +} + +/* + Returns the currently set echo mode. + + \sa setEchoMode() +*/ +QtMultiLineEdit::EchoMode QtMultiLineEdit::echoMode() const +{ + return d->echomode; +} + + +/* + Returns the string shown at line \a row, including + processing of the echoMode(). +*/ + +QString QtMultiLineEdit::stringShown(int row) const +{ + QString* s = getString(row); + if ( !s ) return QString::null; + switch ( d->echomode ) { + case Normal: + if (!*s) return QString::fromLatin1(""); + return *s; + case Password: + { + QString r; + r.fill(QChar('*'), (int)s->length()); + if ( !r ) r = QString::fromLatin1(""); + return r; + } + case NoEcho: + return QString::fromLatin1(""); + } + return QString::fromLatin1(""); +} + +/* + + \sa maxLength() +*/ +void QtMultiLineEdit::setMaxLength(int m) +{ + d->maxlen = m; +} + +/* + \sa setMaxLength() +*/ +int QtMultiLineEdit::maxLength() const +{ + return d->maxlen; +} + + +/* + Returns the length of the current text. + + \sa setMaxLength() + */ +int QtMultiLineEdit::length() const +{ + int l = 0; + for ( QtMultiLineEditRow* r = contents->first(); r; r = contents->next() ) { + l += r->s.length(); + if ( r->newline ) + ++l; + } + return l-1; +} + + +/* + Sets the maximum length of lines to \a m. Use -1 for unlimited + (the default). Existing long lines will be truncated. + + \sa maxLineLength() +*/ +void QtMultiLineEdit::setMaxLineLength(int m) +{ + bool trunc = d->maxlinelen < 0 || m < d->maxlinelen; + d->maxlinelen = m; + if ( trunc ) { + QtMultiLineEditRow* r = contents->first(); + while ( r ) { + r->s.truncate( m ); + r = contents->next(); + } + if ( cursorX > m ) cursorX = m; + if ( markAnchorX > m ) markAnchorX = m; + if ( markDragX > m ) markDragX = m; + update(); + updateCellWidth(); + } +} + +/* + Returns the currently set line length limit, or -1 if there is + no limit (this is the default). + + \sa setMaxLineLength() +*/ +int QtMultiLineEdit::maxLineLength() const +{ + return d->maxlinelen; +} + +/* + Sets the maximum number of lines to \a m. Use -1 for unlimited + (the default). Existing excess lines will be deleted. + + \sa maxLines(), numLines() +*/ +void QtMultiLineEdit::setMaxLines(int m) +{ + if ( m == 0 ) // bad value + m = -1; + d->maxlines = m; + if ( d->maxlines >= 0 && d->maxlines <= 6 ) { + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + } else { + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + } + if ( setNumRowsAndTruncate() ) { + updateCellWidth(); + update(); + } +} + +/* + \sa setMaxLines() +*/ +int QtMultiLineEdit::maxLines() const +{ + return d->maxlines; +} + +/* + Sets the horizontal margin to \a m. + + \sa hMargin() +*/ +void QtMultiLineEdit::setHMargin(int m) +{ + if ( m != d->lr_marg ) { + d->lr_marg = m; + updateCellWidth(); + update(); + } +} + +/* + + \sa setHMargin() +*/ +int QtMultiLineEdit::hMargin() const +{ + return d->lr_marg; +} + +/* + Marks the text starting at \a row_from, \a col_from and ending + at \a row_to, \a col_to. +*/ +void QtMultiLineEdit::setSelection( int row_from, int col_from, + int row_to, int col_to ) +{ + setCursorPosition( row_from, col_from, FALSE ); + setCursorPosition( row_to, col_to, TRUE ); +} + + +/* + Moves the cursor one word to the right. If \a mark is TRUE, the text + is marked. + \sa cursorWordBackward() +*/ +void QtMultiLineEdit::cursorWordForward( bool mark ) +{ + int x = cursorX; + int y = cursorY; + + if ( x == lineLength( y ) || textLine(y).at(x).isSpace() ) { + while ( x < lineLength( y ) && textLine(y).at(x).isSpace() ) + ++x; + if ( x == lineLength( y ) ) { + if ( y < (int)contents->count() - 1) { + ++y; + x = 0; + while ( x < lineLength( y ) && textLine(y).at(x).isSpace() ) + ++x; + } + } + } + else { + while ( x < lineLength( y ) && !textLine(y).at(x).isSpace() ) + ++x; + int xspace = x; + while ( xspace < lineLength( y ) && textLine(y).at(xspace).isSpace() ) + ++xspace; + if ( xspace < lineLength( y ) ) + x = xspace; + } + cursorOn = TRUE; + int oldY = cursorY; + setCursorPosition( y, x, mark ); + if ( oldY != cursorY ) + updateCell( oldY, 0, FALSE ); + updateCell( cursorY, 0, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); +} + +/* + Moves the cursor one word to the left. If \a mark is TRUE, the text + is marked. + \sa cursorWordForward() +*/ +void QtMultiLineEdit::cursorWordBackward( bool mark ) +{ + int x = cursorX; + int y = cursorY; + + while ( x > 0 && textLine(y).at(x-1).isSpace() ) + --x; + + if ( x == 0 ) { + if ( y > 0 ) { + --y; + x = lineLength( y ); + while ( x > 0 && textLine(y).at(x-1).isSpace() ) + --x; + } + } + else { + while ( x > 0 && !textLine(y).at(x-1).isSpace() ) + --x; + } + cursorOn = TRUE; + int oldY = cursorY; + setCursorPosition( y, x, mark ); + if ( oldY != cursorY ) + updateCell( oldY, 0, FALSE ); + updateCell( cursorY, 0, FALSE ); + d->blinkTimer->start( QApplication::cursorFlashTime() / 2, FALSE ); +} + +#define DO_BREAK {doBreak = TRUE; if ( lastSpace > a ) { \ +i = lastSpace; \ +linew = lastw; \ +} \ +else \ +i = QMAX( a, i-1 );} + +void QtMultiLineEdit::wrapLine( int line, int removed ) +{ + QtMultiLineEditRow* r = contents->at( line ); + int yPos; + (void) rowYPos( line, &yPos ); + QFontMetrics fm( font() ); + int i = 0; + QString s = r->s; + int a = 0; + int l = line; + int w = 0; + int nlines = 0; + int lastSpace = -1; + bool doBreak = FALSE; + int linew = 0; + int lastw = 0; + int tabDist = -1; // lazy eval + while ( i < int(s.length()) ) { + doBreak = FALSE; + if ( s[i] == '\t' && d->align == Qt::AlignLeft ) { + if ( tabDist<0 ) + tabDist = tabStopDist(fm); + linew = ( linew/tabDist + 1 ) * tabDist; + } else if ( s[i] != '\n' ) { + char c = s[i].latin1(); + if ( c > 0 ) { + if ( !d->chartable[c] ) + d->chartable[c] = fm.width( s[i] ); + linew += d->chartable[c]; + } else { + linew += fm.width( s[i] ); + } + } + if ( WORD_WRAP && + lastSpace >= a && s[i] != '\n' ) { + if ( DYNAMIC_WRAP ) { + if (linew >= contentsRect().width() - 2*d->lr_marg - d->marg_extra) { + DO_BREAK + } + } else if ( FIXED_COLUMN_WRAP ) { + if ( d->wrapcol >= 0 && i-a >= d->wrapcol ) { + DO_BREAK + } + } else if ( FIXED_WIDTH_WRAP ) { + if ( d->wrapcol >= 0 && linew > d->wrapcol - d->marg_extra ) { + DO_BREAK + } + } + } + if ( s[i] == '\n' || doBreak ) { + r->s = s.mid( a, i - a + (doBreak?1:0) ); + r->w = linew - fm.leftBearing(r->s[0]) + 2 * d->lr_marg + d->marg_extra; + if ( r->w > w ) + w = r->w; + if ( cursorY > l ) + ++cursorY; + else if ( cursorY == line && cursorX >=a && cursorX <= i + (doBreak?1:0)) { + cursorY = l; + cursorX -= a; + } + if ( markAnchorY > l ) + ++markAnchorY; + else if ( markAnchorY == line && markAnchorX >=a && markAnchorX <= i + (doBreak?1:0)) { + markAnchorY = l; + markAnchorX -= a; + } + a = i + 1; + lastSpace = a; + linew = 0; + bool oldnewline = r->newline; + r->newline = !doBreak; + r = new QtMultiLineEditRow( QString::null, 0, oldnewline ); + ++nlines; + contents->insert( l + 1, r ); + ++l; + } + if ( s[i].isSpace() || BREAK_WITHIN_WORDS ) { + lastSpace = i; + lastw = linew; + } + if ( lastSpace <= a ) + lastw = linew; + + ++i; + } + if ( a < int(s.length()) ){ + r->s = s.mid( a, i - a ); + r->w = linew - fm.leftBearing( r->s[0] ) + 2 * d->lr_marg + d->marg_extra; + } + if ( cursorY == line && cursorX >= a ) { + cursorY = l; + cursorX -= a; + } + if ( markAnchorY == line && markAnchorX >= a ) { + markAnchorY = l; + markAnchorX -= a; + } + if ( r->w > w ) + w = r->w; + + setWidth( QMAX( maxLineWidth(), w ) ); + bool oldAuto = autoUpdate(); + setAutoUpdate( FALSE ); + (void)setNumRowsAndTruncate(); + setAutoUpdate( oldAuto ); + + yPos += (nlines+1) * cellHeight(); + int sh = (nlines-removed) * cellHeight(); + if ( autoUpdate() ) { + if ( sh && yPos >= contentsRect().top() && yPos < contentsRect().bottom() ) { + int h = contentsRect().bottom() - yPos + 1; + if ( d->maxlines >= 0 ) { + int maxy; + if ( rowYPos( d->maxlines-1, &maxy ) ) { + maxy += cellHeight(); + if ( maxy < contentsRect().bottom() && maxy > yPos ) + h = maxy - yPos + 1; + } + } + QWidget::scroll( 0, sh, QRect( contentsRect().left(), yPos, + contentsRect().width(), + h ) ); + } + for (int ul = 0; ul <= nlines; ++ul ) + updateCell( line + ul, 0, FALSE ); + } +} + +void QtMultiLineEdit::rebreakParagraph( int line, int removed ) +{ + QtMultiLineEditRow* r = contents->at( line ); + if ( WORD_WRAP ) { + QtMultiLineEditRow* other = 0; + while (line < int(contents->count())-1 && !r->newline ) { + other = contents->at( line + 1 ); + if ( cursorY > line ) { + --cursorY; + if ( cursorY == line ) { + cursorX += r->s.length(); + } + } + if ( markAnchorY > line ) { + --markAnchorY; + if ( markAnchorY == line ) { + markAnchorX += r->s.length(); + } + } + r->s.append( other->s ); + r->newline = other->newline; + contents->remove( line + 1 ); + ++removed; + } + } + wrapLine( line, removed ); +} + +void QtMultiLineEdit::rebreakAll() +{ + if ( !WORD_WRAP ) + return; + d->maxLineWidth = 0; + for (int i = 0; i < int(contents->count()); ++i ) { + if ( contents->at( i )->newline && + contents->at( i )->w < contentsRect().width() - 2*d->lr_marg - d->marg_extra ) { + setWidth( QMAX( d->maxLineWidth, contents->at( i )->w ) ); + continue; + } + rebreakParagraph( i ); + while ( i < int(contents->count() ) + && !contents->at( i )->newline ) + ++i; + } +} + + +/* \enum QtMultiLineEdit::WordWrap + + This enum describes the multiline edit's word wrap mode. + + The following values are valid: + \list + \i NoWrap - no word wrap at all. + \i WidgetWidth - word wrap depending on the current + width of the editor widget + \i FixedPixelWidth - wrap according to a fix amount + of pixels ( see wrapColumnOrWidth() ) + \i FixedColumnWidth - wrap according to a fix character + column. This is useful whenever you need formatted text that + can also be displayed gracefully on devices with monospaced + fonts, for example a standard VT100 terminal. In that case + wrapColumnOrWidth() should typically be set to 80. + \endlist + + \sa setWordWrap() +*/ + +/* + Sets the word wrap mode to \a mode. + + */ +void QtMultiLineEdit::setWordWrap( WordWrap mode ) +{ + if ( mode == d->wordwrap ) + return; + d->wordwrap = mode; + + if ( BREAK_WITHIN_WORDS ) { + d->arrow = QPixmap( (const char **)arrow_xpm ); + d->marg_extra = 8; + if ( DYNAMIC_WRAP ) + clearTableFlags( Tbl_autoHScrollBar ); + else + setTableFlags( Tbl_autoHScrollBar ); + } else { + d->marg_extra = 0; + setTableFlags( Tbl_autoHScrollBar ); + } + if ( !text().isEmpty() ) + setText( text() ); +} + +/* + Returns the current word wrap mode. + + \sa setWordWrap() + */ +QtMultiLineEdit::WordWrap QtMultiLineEdit::wordWrap() const +{ + return d->wordwrap; +} + +/* + Sets the wrap column or wrap width to \a value, depending on the + word wrap mode. + + \sa setWordWrap() + */ +void QtMultiLineEdit::setWrapColumnOrWidth( int value ) +{ + if ( value == d->wrapcol ) + return; + d->wrapcol = value; + if ( wordWrap() != NoWrap ) + setText( text() ); +} + +/* + */ +int QtMultiLineEdit::wrapColumnOrWidth() const +{ + return d->wrapcol; +} + + +/* \enum QtMultiLineEdit::WrapPolicy + + Defines where text can be wrapped in word wrap mode. + + The following values are valid: + \list + \i AtWhiteSpace - break only after whitespace + \i Anywhere - break anywhere + \endlist + + \sa setWrapPolicy() +*/ + +/* + Sets the wrap \a policy, i.e. where text can be wrapped in word wrap + mode. + + \sa setWordWrap(), wrapPolicy() + */ +void QtMultiLineEdit::setWrapPolicy( WrapPolicy policy ) +{ + if ( d->wrappolicy == policy ) + return; + d->wrappolicy = policy; + WordWrap m = d->wordwrap; + if ( m != NoWrap ) { // trigger update + d->wordwrap = NoWrap; + setWordWrap( m ); + } +} + +/* + + Returns the current word wrap policy. + + \sa setWrapPolicy() + */ +QtMultiLineEdit::WrapPolicy QtMultiLineEdit::wrapPolicy() const +{ + return d->wrappolicy; +} + +/* + Returns wether \a row is the last row in a paragraph. + + This function is only interesting in word wrap mode, otherwise its + return value is always TRUE. + + \sa setWordWrap() + */ +bool QtMultiLineEdit::isEndOfParagraph( int row ) const +{ + return contents->at( row )->newline; +} + +int QtMultiLineEdit::positionToOffsetInternal( int row, int col ) const +{ + row = QMAX( QMIN( row, numLines() - 1), 0 ); // Sanity check + col = QMAX( QMIN( col, lineLength( row )), 0 ); // Sanity check + if ( row == 0 ) + return QMIN( col, lineLength( 0 )); + else { + int lastI; + lastI = lineLength( row ); + int i, tmp = 0; + + for( i = 0; i < row ; i++ ) { + tmp += lineLength( i ); + if ( contents->at( i )->newline ) + ++tmp; + } + + tmp += QMIN( lastI, col ); + + return tmp; + } + +} + +// if position is <0 = returns row 0, col 0, if position >= amount of text +// returns pointer to end of text. +void QtMultiLineEdit::offsetToPositionInternal( int position, + int *row, int *col ) const +{ + if (position <= 0) { + *row = 0; + *col = 0; + return; + } + else { + int charsLeft = position; + int i; + + for( i = 0; contents->at( i ); ++i ) { + if (lineLength( i ) < charsLeft) + charsLeft -= lineLength( i ); + else { + *row = i; + *col = charsLeft; + return; + } + if ( contents->at( i )->newline ) + --charsLeft; + } + + if (contents->at( i - 1) && !contents->at( i - 1 )->newline) { + *row = i - 1; + *col = lineLength( i - 1 ); + } + else { + *row = i; + *col = 0; + } + return; + } +} + + +/* + Processes an undo/redo command \a cmd, depending on \a undo. + */ +void QtMultiLineEdit::processCmd( QtMultiLineEditCommand* cmd, bool undo) +{ + QDelTextCmd* delcmd = (QDelTextCmd*) cmd; + bool ins = TRUE; + if (cmd->type() == QtMultiLineEditCommand::Delete ) + ins = undo; + else if (cmd->type() == QtMultiLineEditCommand::Insert ) + ins = !undo; + else + return; + + if ( ins ) { + int row, col; + offsetToPositionInternal( delcmd->mOffset, &row, &col ); + setCursorPosition( row, col, FALSE ); + insertAt( delcmd->mStr, row, col, FALSE ); + offsetToPositionInternal( delcmd->mOffset+delcmd->mStr.length(), &row, &col ); + setCursorPosition( row, col, FALSE ); + } else { // del + int row, col, rowEnd, colEnd; + offsetToPositionInternal( delcmd->mOffset, &row, &col ); + offsetToPositionInternal( delcmd->mOffset + delcmd->mStr.length(), &rowEnd, &colEnd ); + markAnchorY = row; + markAnchorX = col; + setCursorPosition( rowEnd, colEnd, FALSE ); + markDragY = rowEnd; + markDragX = colEnd; + turnMark( TRUE ); + del(); + } +} + +/* + Undoes the last text operation. + */ +void QtMultiLineEdit::undo() +{ + if ( d->undoList.isEmpty() || isReadOnly() ) + return; + textDirty = FALSE; + int macroLevel = 0; + bool before = d->undo; + d->undo = FALSE; + do { + QtMultiLineEditCommand *command = d->undoList.take(); + if ( !command ) + break; + processCmd( command, TRUE ); + macroLevel += command->terminator(); + if ( d->undoList.isEmpty() ) + emit undoAvailable( FALSE ); + addRedoCmd( command ); + } while (macroLevel != 0); + d->undo = before; + if ( textDirty ) + emit textChanged(); + textDirty = FALSE; +} + +/* + Redoes the last text operation. + */ +void QtMultiLineEdit::redo() +{ + if ( d->redoList.isEmpty() || isReadOnly() ) + return; + textDirty = FALSE; + int macroLevel = 0; + bool before = d->undo; + d->undo = FALSE; + do { + QtMultiLineEditCommand *command = d->redoList.take(); + if ( !command ) + break; + processCmd( command, FALSE ); + macroLevel += command->terminator(); + if ( d->redoList.isEmpty() ) + emit redoAvailable( FALSE ); + if ( d->undoList.isEmpty() ) + emit undoAvailable(TRUE); + d->undoList.append( command ); + } while (macroLevel != 0); + d->undo = before; + if ( textDirty ) + emit textChanged(); + textDirty = FALSE; +} + +/* + Inserts \a s at line number \a line, after character number \a col + in the line. + If \a s contains newline characters, new lines are inserted. + If \a mark is TRUE the inserted text is selected. + + The cursor position is adjusted. If the insertion position is equal to + the cursor position, the cursor is placed after the end of the new text. + + */ + +void QtMultiLineEdit::insertAt( const QString &s, int line, int col, bool mark ) +{ + if ( d->undo ) { + d->undo = FALSE; + QString itxt = s; + int offset = positionToOffsetInternal( line, col ); + if ( d->maxlen >= 0 && length() + int(s.length()) > d->maxlen ) + itxt.truncate( d->maxlen - length() ); + addUndoCmd( new QInsTextCmd( offset, itxt ) ); + insertAtAux( s, line, col, mark ); // may perform del op + d->undo = TRUE; + } + else + insertAtAux( s, line, col, mark ); // may perform del op +} + +void QtMultiLineEdit::deleteNextChar( int offset, int row, int col ) +{ + int row2, col2; + setCursorPosition( row, col, FALSE ); + offsetToPositionInternal( offset + 1, &row2, &col2 ); + setCursorPosition( row2, col2, TRUE ); + + QString str = markedText(); + addUndoCmd( new QDelTextCmd( offset, str ) ); + + setCursorPosition( row, col, FALSE ); +} + +/* + Deletes text from the current cursor position to the end of the line. +*/ + +void QtMultiLineEdit::killLine() +{ + if ( d->undo ) { + d->undo = FALSE; + int curY, curX; + cursorPosition( &curY, &curX ); + int offset = positionToOffsetInternal( curY, curX ); + QtMultiLineEditRow* r = contents->at( curY ); + deselect(); + + addUndoCmd( new QBeginCommand ); + if (curX == (int)r->s.length()) { + if ( ! atEnd() && r->newline ) + deleteNextChar( offset, curY, curX ); + } + else { + QString str = r->s.mid( curX, r->s.length() ); + addUndoCmd( new QDelTextCmd( offset, str ) ); + } + + addUndoCmd( new QEndCommand ); + killLineAux(); + d->undo = TRUE; + } + else + killLineAux(); +} + +/* + Deletes the character on the right side of the text cursor. If a + text has been marked by the user (e.g. by clicking and dragging) the + cursor is put at the beginning of the marked text and the marked + text is removed. \sa backspace() +*/ + +void QtMultiLineEdit::del() +{ + if (d->undo ) { + d->undo = FALSE; + bool oldAuto = autoUpdate(); + setAutoUpdate( FALSE ); + int markBeginX, markBeginY; + int markEndX, markEndY; + + if ( getMarkedRegion( &markBeginY, &markBeginX, &markEndY, &markEndX ) ) { + addUndoCmd( new QBeginCommand ); + int offset = positionToOffsetInternal( markBeginY, markBeginX ); + QString str = markedText(); + d->undoList.append( new QDelTextCmd( offset, str ) ); + addUndoCmd( new QEndCommand ); + } + else if ( ! atEnd() ) { + int crsorY, crsorX; + cursorPosition( &crsorY, &crsorX ); + int offset = positionToOffsetInternal( crsorY, crsorX ); + QtMultiLineEditRow* r = contents->at( crsorY ); + if (r) { + if (crsorX != (int)r->s.length()) + deleteNextChar( offset, crsorY, crsorX ); + else if (r->newline) + deleteNextChar( offset, crsorY, crsorX ); + // else noop + } + } + setAutoUpdate( oldAuto ); + delAux(); + d->undo = TRUE; + } + else + delAux(); +} + +/* + Sets undo enabled to \a enable. + + \sa isUndoEnabled() +*/ +void QtMultiLineEdit::setUndoEnabled( bool enable ) +{ + if ( d->undo == enable ) + return; + d->undo = enable; + if ( !enable ) { + CLEAR_UNDO + } +} + + +/* + Returns whether the multilineedit is currently undo enabled or not. + + \sa setUndoEnabled() + */ +bool QtMultiLineEdit::isUndoEnabled() const +{ + return d->undo; +} + + +/* + Sets the maximum number of operations that can be stored on the undo + stack to \a depth. + + \sa undoDepth() + */ +void QtMultiLineEdit::setUndoDepth( int depth ) +{ + d->undodepth = depth; +} + + +/* + */ +int QtMultiLineEdit::undoDepth() const +{ + return d->undodepth; +} + +void QtMultiLineEdit::blinkTimerTimeout() +{ + cursorOn = !cursorOn; + updateCell( cursorY, 0, FALSE ); +} + +void QtMultiLineEdit::scrollTimerTimeout() +{ + QPoint p = mapFromGlobal( QCursor::pos() ); + if ( d->scrollAccel-- <= 0 && d->scrollTime ) { + d->scrollAccel = initialScrollAccel; + d->scrollTime--; + d->scrollTimer->stop(); + d->scrollTimer->start( d->scrollTime ); + } + int l = QMAX(1,(initialScrollTime-d->scrollTime)/5); + + // auto scrolling is dual-use - for highlighting and DND + int margin = d->dnd_primed ? scroll_margin : 0; + bool mark = !d->dnd_primed; + bool clear_mark = d->dnd_primed ? FALSE : !mark; + + for (int i=0; i<l; i++) { + if ( p.y() < margin ) { + cursorUp( mark, clear_mark ); + } else if ( p.y() > height()-margin ) { + cursorDown( mark, clear_mark ); + } else if ( p.x() < margin ) { + cursorLeft( mark, clear_mark, FALSE ); + } else if ( p.x() > width()-margin ) { + cursorRight( mark, clear_mark, FALSE ); + } else { + stopAutoScroll(); + break; + } + } +} + +void QtMultiLineEdit::dndTimeout() +{ +#ifndef QT_NO_DRAGANDDROP + doDrag(); +#endif +} + +int QtMultiLineEdit::setNumRowsAndTruncate() +{ + int n = contents->count(); + int r = 0; + while ( d->maxlines >= 0 && n > d->maxlines ) { + // truncate + contents->at(n-2)->newline = TRUE; + contents->removeLast(); + if ( markAnchorY == n-1 ) + markAnchorY--; + if ( markDragY == n-1 ) + markDragY--; + if ( cursorY == n-1 ) { + cursorY--; + cursorX = contents->at(cursorY)->s.length(); + } + n--; + r++; + } + setNumRows( n ); + return r; +} + +/* \reimp +*/ +bool QtMultiLineEdit::event( QEvent * e ) +{ + if ( e->type() == QEvent::AccelOverride && !isReadOnly() ) { + QKeyEvent* ke = (QKeyEvent*) e; + if ( ke->state() & ControlButton ) { + switch ( ke->key() ) { + case Key_A: + case Key_E: +#if defined (_WS_WIN_) + case Key_Insert: +#endif + case Key_X: + case Key_V: + case Key_C: + case Key_Left: + case Key_Right: + case Key_Up: + case Key_Down: + case Key_Home: + case Key_End: + ke->accept(); + default: + break; + } + } else { + switch ( ke->key() ) { + case Key_Delete: + case Key_Home: + case Key_End: + case Key_Backspace: + ke->accept(); + default: + break; + } + } + } + return QWidget::event( e ); +} + +/* \reimp +*/ + +bool QtMultiLineEdit::focusNextPrevChild( bool ) +{ + return FALSE; +} + +#endif diff --git a/src/attic/qtmultilineedit.h b/src/attic/qtmultilineedit.h new file mode 100644 index 0000000..7d39f9f --- /dev/null +++ b/src/attic/qtmultilineedit.h @@ -0,0 +1,363 @@ +/********************************************************************** +** +** Definition of QtMultiLineEdit widget class +** +** Created : 961005 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file contains a class moved out of the Qt GUI Toolkit API. It +** may be used, distributed and modified without limitation. +** +**********************************************************************/ + +#ifndef QTMULTILINEEDIT_H +#define QTMULTILINEEDIT_H + +#ifndef QT_H +#include "qttableview.h" +#include "qstring.h" +#include "qptrlist.h" +#endif // QT_H + +#ifndef QT_NO_QTMULTILINEEDIT + +struct QtMultiLineData; +class QtMultiLineEditCommand; +class QValidator; + +class QtMultiLineEdit : public QtTableView +{ + Q_OBJECT + Q_ENUMS( EchoMode WordWrap WrapPolicy ) + Q_PROPERTY( int numLines READ numLines ) + Q_PROPERTY( bool atBeginning READ atBeginning ) + Q_PROPERTY( bool atEnd READ atEnd ) + Q_PROPERTY( int maxLineWidth READ maxLineWidth ) + Q_PROPERTY( Alignment alignment READ alignment WRITE setAlignment ) + Q_PROPERTY( bool edited READ edited WRITE setEdited DESIGNABLE false ) + Q_PROPERTY( EchoMode echoMode READ echoMode WRITE setEchoMode ) + Q_PROPERTY( int maxLength READ maxLength WRITE setMaxLength ) + Q_PROPERTY( int maxLines READ maxLines WRITE setMaxLines ) + Q_PROPERTY( int hMargin READ hMargin WRITE setHMargin ) + Q_PROPERTY( WordWrap wordWrap READ wordWrap WRITE setWordWrap ) + Q_PROPERTY( int wrapColumnOrWidth READ wrapColumnOrWidth WRITE setWrapColumnOrWidth ) + Q_PROPERTY( WrapPolicy wrapPolicy READ wrapPolicy WRITE setWrapPolicy ) + Q_PROPERTY( bool autoUpdate READ autoUpdate WRITE setAutoUpdate DESIGNABLE false ) + Q_PROPERTY( bool undoEnabled READ isUndoEnabled WRITE setUndoEnabled ) + Q_PROPERTY( int undoDepth READ undoDepth WRITE setUndoDepth ) + Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly ) + Q_PROPERTY( bool overWriteMode READ isOverwriteMode WRITE setOverwriteMode ) + Q_PROPERTY( QString text READ text WRITE setText ) + Q_PROPERTY( int length READ length ) + +public: + QtMultiLineEdit( QWidget *parent=0, const char *name=0 ); + ~QtMultiLineEdit(); + + QString textLine( int line ) const; + int numLines() const; + + QSize sizeHint() const; + QSize minimumSizeHint() const; + QSizePolicy sizePolicy() const; + + virtual void setFont( const QFont &font ); + + virtual void insertLine( const QString &s, int line = -1 ); + virtual void insertAt( const QString &s, int line, int col, bool mark = FALSE ); + virtual void removeLine( int line ); + + void cursorPosition( int *line, int *col ) const; + virtual void setCursorPosition( int line, int col, bool mark = FALSE ); + void getCursorPosition( int *line, int *col ) const; + bool atBeginning() const; + bool atEnd() const; + + virtual void setFixedVisibleLines( int lines ); + + int maxLineWidth() const; + + void setAlignment( int flags ); + int alignment() const; + + virtual void setValidator( const QValidator * ); + const QValidator * validator() const; + + void setEdited( bool ); + bool edited() const; + + void cursorWordForward( bool mark ); + void cursorWordBackward( bool mark ); + + enum EchoMode { Normal, NoEcho, Password }; + virtual void setEchoMode( EchoMode ); + EchoMode echoMode() const; + + void setMaxLength(int); + int maxLength() const; + virtual void setMaxLineLength(int); + int maxLineLength() const; + virtual void setMaxLines(int); + int maxLines() const; + virtual void setHMargin(int); + int hMargin() const; + + virtual void setSelection( int row_from, int col_from, int row_to, int col_t ); + + enum WordWrap { + NoWrap, + WidgetWidth, + FixedPixelWidth, + FixedColumnWidth + }; + void setWordWrap( WordWrap mode ); + WordWrap wordWrap() const; + void setWrapColumnOrWidth( int ); + int wrapColumnOrWidth() const; + + enum WrapPolicy { + AtWhiteSpace, + Anywhere + }; + void setWrapPolicy( WrapPolicy policy ); + WrapPolicy wrapPolicy() const; + + bool autoUpdate() const; + virtual void setAutoUpdate( bool ); + + void setUndoEnabled( bool ); + bool isUndoEnabled() const; + void setUndoDepth( int ); + int undoDepth() const; + + bool isReadOnly() const; + bool isOverwriteMode() const; + + QString text() const; + + int length() const; + + static void setDefaultTabStop( int ex ); + static int defaultTabStop(); +public slots: + virtual void setText( const QString &); + virtual void setReadOnly( bool ); + virtual void setOverwriteMode( bool ); + + void clear(); + void append( const QString &); + void deselect(); + void selectAll(); +#ifndef QT_NO_CLIPBOARD + void paste(); + void pasteSubType(const QCString& subtype); + void copyText() const; + void copy() const; + void cut(); +#endif + void insert( const QString& ); + void undo(); + void redo(); + +signals: + void textChanged(); + void returnPressed(); + void undoAvailable( bool ); + void redoAvailable( bool ); + void copyAvailable( bool ); + +protected: + void paintCell( QPainter *, int row, int col ); + bool event( QEvent * ); + + void mousePressEvent( QMouseEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + void mouseDoubleClickEvent( QMouseEvent * ); + void wheelEvent( QWheelEvent * ); + void keyPressEvent( QKeyEvent * ); + void focusInEvent( QFocusEvent * ); + void focusOutEvent( QFocusEvent * ); + void timerEvent( QTimerEvent * ); + void leaveEvent( QEvent * ); + void resizeEvent( QResizeEvent * ); + + bool focusNextPrevChild( bool ); + +#ifndef QT_NO_DRAGANDDROP + void dragMoveEvent( QDragMoveEvent* ); + void dragEnterEvent( QDragEnterEvent * ); + void dropEvent( QDropEvent* ); + void dragLeaveEvent( QDragLeaveEvent* ); +#endif + + bool hasMarkedText() const; + QString markedText() const; + int textWidth( int ); + int textWidth( const QString &); + + QPoint cursorPoint() const; + +protected: + virtual void insert( const QString&, bool mark ); + virtual void newLine(); + virtual void killLine(); + virtual void pageUp( bool mark=FALSE ); + virtual void pageDown( bool mark=FALSE ); + virtual void cursorLeft( bool mark=FALSE, bool wrap = TRUE ); + virtual void cursorRight( bool mark=FALSE, bool wrap = TRUE ); + virtual void cursorUp( bool mark=FALSE ); + virtual void cursorDown( bool mark=FALSE ); + virtual void backspace(); + virtual void del(); + virtual void home( bool mark=FALSE ); + virtual void end( bool mark=FALSE ); + + bool getMarkedRegion( int *line1, int *col1, + int *line2, int *col2 ) const; + int lineLength( int row ) const; + QString *getString( int row ) const; + bool isEndOfParagraph( int row ) const; + QString stringShown( int row ) const; + +protected: + bool cursorOn; + void insertChar( QChar ); + +private slots: + void clipboardChanged(); + void blinkTimerTimeout(); + void scrollTimerTimeout(); + void dndTimeout(); + +private: +#ifndef QT_NO_MIME + QCString pickSpecial(QMimeSource* ms, bool always_ask, const QPoint&); +#endif +#ifndef QT_NO_MIMECLIPBOARD + void pasteSpecial(const QPoint&); +#endif + struct QtMultiLineEditRow { + QtMultiLineEditRow( QString string, int width, bool nl = TRUE ) + :s(string), w(width), newline( nl ) + { + }; + QString s; + int w; + bool newline; + }; + QPtrList<QtMultiLineEditRow> *contents; + QtMultiLineData *d; + + bool readOnly; + bool dummy; + bool markIsOn; + bool dragScrolling ; + bool dragMarking; + bool textDirty; + bool wordMark; + bool overWrite; + + int cursorX; + int cursorY; + int markAnchorX; + int markAnchorY; + int markDragX; + int markDragY; + int curXPos; // cell coord of cursor + int blinkTimer; // #### not used anymore - remove in 3.0 + int scrollTimer; // #### not used anymore - remove in 3.0 + + int mapFromView( int xPos, int row ); + int mapToView( int xIndex, int row ); + + void pixelPosToCursorPos(QPoint p, int* x, int* y) const; + void setCursorPixelPosition(QPoint p, bool clear_mark=TRUE); + + void setWidth( int ); + void updateCellWidth(); + bool partiallyInvisible( int row ); + void makeVisible(); + void setBottomCell( int row ); + + void newMark( int posx, int posy, bool copy=TRUE ); + void markWord( int posx, int posy ); + void extendSelectionWord( int &newX, int&newY); + int charClass( QChar ); + void turnMark( bool on ); + bool inMark( int posx, int posy ) const; + bool beforeMark( int posx, int posy ) const; + bool afterMark( int posx, int posy ) const; + int setNumRowsAndTruncate(); + +#ifndef QT_NO_DRAGANDDROP + void doDrag(); +#endif + void startAutoScroll(); + void stopAutoScroll(); + + void cursorLeft( bool mark, bool clear_mark, bool wrap ); + void cursorRight( bool mark, bool clear_mark, bool wrap ); + void cursorUp( bool mark, bool clear_mark ); + void cursorDown( bool mark, bool clear_mark ); + + void wrapLine( int line, int removed = 0); + void rebreakParagraph( int line, int removed = 0 ); + void rebreakAll(); + void insertAtAux( const QString &s, int line, int col, bool mark = FALSE ); + void killLineAux(); + void delAux(); + int positionToOffsetInternal( int row, int col ) const; + void offsetToPositionInternal( int position, int *row, int *col ) const; + void deleteNextChar( int offset, int row, int col ); + + void addUndoCmd( QtMultiLineEditCommand* ); + void addRedoCmd( QtMultiLineEditCommand* ); + void processCmd( QtMultiLineEditCommand*, bool ); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QtMultiLineEdit( const QtMultiLineEdit & ); + QtMultiLineEdit &operator=( const QtMultiLineEdit & ); +#endif +}; + +inline bool QtMultiLineEdit::isReadOnly() const { return readOnly; } + +inline bool QtMultiLineEdit::isOverwriteMode() const { return overWrite; } + +inline void QtMultiLineEdit::setOverwriteMode( bool on ) +{ + overWrite = on; + } + +inline int QtMultiLineEdit::lineLength( int row ) const +{ + return contents->at( row )->s.length(); +} + +inline bool QtMultiLineEdit::atEnd() const +{ + return cursorY == (int)contents->count() - 1 + && cursorX == lineLength( cursorY ) ; +} + +inline bool QtMultiLineEdit::atBeginning() const +{ + return cursorY == 0 && cursorX == 0; +} + +inline QString *QtMultiLineEdit::getString( int row ) const +{ + return &(contents->at( row )->s); +} + +inline int QtMultiLineEdit::numLines() const +{ + return contents->count(); +} + +#endif // QT_NO_QTMULTILINEEDIT + +#endif // QTMULTILINEDIT_H diff --git a/src/attic/qttableview.cpp b/src/attic/qttableview.cpp new file mode 100644 index 0000000..16fc836 --- /dev/null +++ b/src/attic/qttableview.cpp @@ -0,0 +1,2272 @@ +/********************************************************************** +** +** Implementation of QtTableView class +** +** Created : 941115 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file contains a class moved out of the Qt GUI Toolkit API. It +** may be used, distributed and modified without limitation. +** +**********************************************************************/ + +#include "qttableview.h" +#ifndef QT_NO_QTTABLEVIEW +#include "qscrollbar.h" +#include "qpainter.h" +#include "qdrawutil.h" +#include <limits.h> + +enum ScrollBarDirtyFlags { + verGeometry = 0x01, + verSteps = 0x02, + verRange = 0x04, + verValue = 0x08, + horGeometry = 0x10, + horSteps = 0x20, + horRange = 0x40, + horValue = 0x80, + verMask = 0x0F, + horMask = 0xF0 +}; + + +#define HSBEXT horizontalScrollBar()->sizeHint().height() +#define VSBEXT verticalScrollBar()->sizeHint().width() + + +class QCornerSquare : public QWidget // internal class +{ +public: + QCornerSquare( QWidget *, const char* = 0 ); + void paintEvent( QPaintEvent * ); +}; + +QCornerSquare::QCornerSquare( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ +} + +void QCornerSquare::paintEvent( QPaintEvent * ) +{ +} + + +// NOT REVISED +/* + \class QtTableView qttableview.h + \brief The QtTableView class provides an abstract base for tables. + + \obsolete + + A table view consists of a number of abstract cells organized in rows + and columns, and a visible part called a view. The cells are identified + with a row index and a column index. The top-left cell is in row 0, + column 0. + + The behavior of the widget can be finely tuned using + setTableFlags(); a typical subclass will consist of little more than a + call to setTableFlags(), some table content manipulation and an + implementation of paintCell(). Subclasses that need cells with + variable width or height must reimplement cellHeight() and/or + cellWidth(). Use updateTableSize() to tell QtTableView when the + width or height has changed. + + When you read this documentation, it is important to understand the + distinctions among the four pixel coordinate systems involved. + + \list 1 + \i The \e cell coordinates. (0,0) is the top-left corner of a cell. + Cell coordinates are used by functions such as paintCell(). + + \i The \e table coordinates. (0,0) is the top-left corner of the cell at + row 0 and column 0. These coordinates are absolute; that is, they are + independent of what part of the table is visible at the moment. They are + used by functions such as setXOffset() or maxYOffset(). + + \i The \e widget coordinates. (0,0) is the top-left corner of the widget, + \e including the frame. They are used by functions such as repaint(). + + \i The \e view coordinates. (0,0) is the top-left corner of the view, \e + excluding the frame. This is the least-used coordinate system; it is used by + functions such as viewWidth(). \endlist + + It is rather unfortunate that we have to use four different + coordinate systems, but there was no alternative to provide a flexible and + powerful base class. + + Note: The row,column indices are always given in that order, + i.e., first the vertical (row), then the horizontal (column). This is + the opposite order of all pixel operations, which take first the + horizontal (x) and then the vertical (y). + + <img src=qtablevw-m.png> <img src=qtablevw-w.png> + + \warning the functions setNumRows(), setNumCols(), setCellHeight(), + setCellWidth(), setTableFlags() and clearTableFlags() may cause + virtual functions such as cellWidth() and cellHeight() to be called, + even if autoUpdate() is FALSE. This may cause errors if relevant + state variables are not initialized. + + \warning Experience has shown that use of this widget tends to cause + more bugs than expected and our analysis indicates that the widget's + very flexibility is the problem. If QScrollView or QListBox can + easily be made to do the job you need, we recommend subclassing + those widgets rather than QtTableView. In addition, QScrollView makes + it easy to have child widgets inside tables, which QtTableView + doesn't support at all. + + \sa QScrollView + \link guibooks.html#fowler GUI Design Handbook: Table\endlink +*/ + + +/* + Constructs a table view. The \a parent, \a name and \f arguments + are passed to the QFrame constructor. + + The \link setTableFlags() table flags\endlink are all cleared (set to 0). + Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll + bars and \c Tbl_clipCellPainting to get safe clipping. + + The \link setCellHeight() cell height\endlink and \link setCellWidth() + cell width\endlink are set to 0. + + Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed; + see QFrame::setFrameStyle(). + + Note that the \a f argument is \e not \link setTableFlags() table + flags \endlink but rather \link QWidget::QWidget() widget + flags. \endlink + +*/ + +QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f ) + : QFrame( parent, name, f ) +{ + nRows = nCols = 0; // zero rows/cols + xCellOffs = yCellOffs = 0; // zero offset + xCellDelta = yCellDelta = 0; // zero cell offset + xOffs = yOffs = 0; // zero total pixel offset + cellH = cellW = 0; // user defined cell size + tFlags = 0; + vScrollBar = hScrollBar = 0; // no scroll bars + cornerSquare = 0; + sbDirty = 0; + eraseInPaint = FALSE; + verSliding = FALSE; + verSnappingOff = FALSE; + horSliding = FALSE; + horSnappingOff = FALSE; + coveringCornerSquare = FALSE; + inSbUpdate = FALSE; +} + +/* + Destroys the table view. +*/ + +QtTableView::~QtTableView() +{ + delete vScrollBar; + delete hScrollBar; + delete cornerSquare; +} + + +/* + \internal + Reimplements QWidget::setBackgroundColor() for binary compatibility. + \sa setPalette() +*/ + +void QtTableView::setBackgroundColor( const QColor &c ) +{ + QWidget::setBackgroundColor( c ); +} + +/*\reimp +*/ + +void QtTableView::setPalette( const QPalette &p ) +{ + QWidget::setPalette( p ); +} + +/*\reimp +*/ + +void QtTableView::show() +{ + showOrHideScrollBars(); + QWidget::show(); +} + + +/* + \overload void QtTableView::repaint( bool erase ) + Repaints the entire view. +*/ + +/* + Repaints the table view directly by calling paintEvent() directly + unless updates are disabled. + + Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a + (x,y) are in \e widget coordinates. + + If \a w is negative, it is replaced with <code>width() - x</code>. + If \a h is negative, it is replaced with <code>height() - y</code>. + + Doing a repaint() usually is faster than doing an update(), but + calling update() many times in a row will generate a single paint + event. + + At present, QtTableView is the only widget that reimplements \link + QWidget::repaint() repaint()\endlink. It does this because by + clearing and then repainting one cell at at time, it can make the + screen flicker less than it would otherwise. */ + +void QtTableView::repaint( int x, int y, int w, int h, bool erase ) +{ + if ( !isVisible() || testWState(WState_BlockUpdates) ) + return; + if ( w < 0 ) + w = width() - x; + if ( h < 0 ) + h = height() - y; + QRect r( x, y, w, h ); + if ( r.isEmpty() ) + return; // nothing to do + QPaintEvent e( r ); + if ( erase && backgroundMode() != NoBackground ) + eraseInPaint = TRUE; // erase when painting + paintEvent( &e ); + eraseInPaint = FALSE; +} + +/* + \overload void QtTableView::repaint( const QRect &r, bool erase ) + Replaints rectangle \a r. If \a erase is TRUE draws the background + using the palette's background. +*/ + + +/* + \fn int QtTableView::numRows() const + Returns the number of rows in the table. + \sa numCols(), setNumRows() +*/ + +/* + Sets the number of rows of the table to \a rows (must be non-negative). + Does not change topCell(). + + The table repaints itself automatically if autoUpdate() is set. + + \sa numCols(), setNumCols(), numRows() +*/ + +void QtTableView::setNumRows( int rows ) +{ + if ( rows < 0 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.", + name( "unnamed" ), rows ); +#endif + return; + } + if ( nRows == rows ) + return; + + if ( autoUpdate() && isVisible() ) { + int oldLastVisible = lastRowVisible(); + int oldTopCell = topCell(); + nRows = rows; + if ( autoUpdate() && isVisible() && + ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) ) + repaint( oldTopCell != topCell() ); + } else { + // Be more careful - if destructing, bad things might happen. + nRows = rows; + } + updateScrollBars( verRange ); + updateFrameSize(); +} + +/* + \fn int QtTableView::numCols() const + Returns the number of columns in the table. + \sa numRows(), setNumCols() +*/ + +/* + Sets the number of columns of the table to \a cols (must be non-negative). + Does not change leftCell(). + + The table repaints itself automatically if autoUpdate() is set. + + \sa numCols(), numRows(), setNumRows() +*/ + +void QtTableView::setNumCols( int cols ) +{ + if ( cols < 0 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.", + name( "unnamed" ), cols ); +#endif + return; + } + if ( nCols == cols ) + return; + int oldCols = nCols; + nCols = cols; + if ( autoUpdate() && isVisible() ) { + int maxCol = lastColVisible(); + if ( maxCol >= oldCols || maxCol >= nCols ) + repaint(); + } + updateScrollBars( horRange ); + updateFrameSize(); +} + + +/* + \fn int QtTableView::topCell() const + Returns the index of the first row in the table that is visible in + the view. The index of the first row is 0. + \sa leftCell(), setTopCell() +*/ + +/* + Scrolls the table so that \a row becomes the top row. + The index of the very first row is 0. + \sa setYOffset(), setTopLeftCell(), setLeftCell() +*/ + +void QtTableView::setTopCell( int row ) +{ + setTopLeftCell( row, -1 ); + return; +} + +/* + \fn int QtTableView::leftCell() const + Returns the index of the first column in the table that is visible in + the view. The index of the very leftmost column is 0. + \sa topCell(), setLeftCell() +*/ + +/* + Scrolls the table so that \a col becomes the leftmost + column. The index of the leftmost column is 0. + \sa setXOffset(), setTopLeftCell(), setTopCell() +*/ + +void QtTableView::setLeftCell( int col ) +{ + setTopLeftCell( -1, col ); + return; +} + +/* + Scrolls the table so that the cell at row \a row and colum \a + col becomes the top-left cell in the view. The cell at the extreme + top left of the table is at position (0,0). + \sa setLeftCell(), setTopCell(), setOffset() +*/ + +void QtTableView::setTopLeftCell( int row, int col ) +{ + int newX = xOffs; + int newY = yOffs; + + if ( col >= 0 ) { + if ( cellW ) { + newX = col*cellW; + if ( newX > maxXOffset() ) + newX = maxXOffset(); + } else { + newX = 0; + while ( col ) + newX += cellWidth( --col ); // optimize using current! ### + } + } + if ( row >= 0 ) { + if ( cellH ) { + newY = row*cellH; + if ( newY > maxYOffset() ) + newY = maxYOffset(); + } else { + newY = 0; + while ( row ) + newY += cellHeight( --row ); // optimize using current! ### + } + } + setOffset( newX, newY ); +} + + +/* + \fn int QtTableView::xOffset() const + + Returns the x coordinate in \e table coordinates of the pixel that is + currently on the left edge of the view. + + \sa setXOffset(), yOffset(), leftCell() */ + +/* + Scrolls the table so that \a x becomes the leftmost pixel in the view. + The \a x parameter is in \e table coordinates. + + The interaction with \link setTableFlags() Tbl_snapToHGrid + \endlink is tricky. + + \sa xOffset(), setYOffset(), setOffset(), setLeftCell() +*/ + +void QtTableView::setXOffset( int x ) +{ + setOffset( x, yOffset() ); +} + +/* + \fn int QtTableView::yOffset() const + + Returns the y coordinate in \e table coordinates of the pixel that is + currently on the top edge of the view. + + \sa setYOffset(), xOffset(), topCell() +*/ + + +/* + Scrolls the table so that \a y becomes the top pixel in the view. + The \a y parameter is in \e table coordinates. + + The interaction with \link setTableFlags() Tbl_snapToVGrid + \endlink is tricky. + + \sa yOffset(), setXOffset(), setOffset(), setTopCell() +*/ + +void QtTableView::setYOffset( int y ) +{ + setOffset( xOffset(), y ); +} + +/* + Scrolls the table so that \a (x,y) becomes the top-left pixel + in the view. Parameters \a (x,y) are in \e table coordinates. + + The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink + is tricky. If \a updateScrBars is TRUE, the scroll bars are + updated. + + \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell() +*/ + +void QtTableView::setOffset( int x, int y, bool updateScrBars ) +{ + if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) && + (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) && + (x == xOffs && y == yOffs) ) + return; + + if ( x < 0 ) + x = 0; + if ( y < 0 ) + y = 0; + + if ( cellW ) { + if ( x > maxXOffset() ) + x = maxXOffset(); + xCellOffs = x / cellW; + if ( !testTableFlags(Tbl_snapToHGrid) ) { + xCellDelta = (short)(x % cellW); + } else { + x = xCellOffs*cellW; + xCellDelta = 0; + } + } else { + int xn=0, xcd=0, col = 0; + while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) { + xn += xcd; + col++; + } + xCellOffs = col; + if ( testTableFlags(Tbl_snapToHGrid) ) { + xCellDelta = 0; + x = xn; + } else { + xCellDelta = (short)(x-xn); + } + } + if ( cellH ) { + if ( y > maxYOffset() ) + y = maxYOffset(); + yCellOffs = y / cellH; + if ( !testTableFlags(Tbl_snapToVGrid) ) { + yCellDelta = (short)(y % cellH); + } else { + y = yCellOffs*cellH; + yCellDelta = 0; + } + } else { + int yn=0, yrd=0, row=0; + while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) { + yn += yrd; + row++; + } + yCellOffs = row; + if ( testTableFlags(Tbl_snapToVGrid) ) { + yCellDelta = 0; + y = yn; + } else { + yCellDelta = (short)(y-yn); + } + } + int dx = (x - xOffs); + int dy = (y - yOffs); + xOffs = x; + yOffs = y; + if ( autoUpdate() && isVisible() ) + scroll( dx, dy ); + if ( updateScrBars ) + updateScrollBars( verValue | horValue ); +} + + +/* + \overload int QtTableView::cellWidth() const + + Returns the column width in pixels. Returns 0 if the columns have + variable widths. + + \sa setCellWidth(), cellHeight() +*/ + +/* + Returns the width of column \a col in pixels. + + This function is virtual and must be reimplemented by subclasses that + have variable cell widths. Note that if the total table width + changes, updateTableSize() must be called. + + \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize() +*/ + +int QtTableView::cellWidth( int ) +{ + return cellW; +} + + +/* + Sets the width in pixels of the table cells to \a cellWidth. + + Setting it to 0 means that the column width is variable. When + set to 0 (this is the default) QtTableView calls the virtual function + cellWidth() to get the width. + + \sa cellWidth(), setCellHeight(), totalWidth(), numCols() +*/ + +void QtTableView::setCellWidth( int cellWidth ) +{ + if ( cellW == cellWidth ) + return; +#if defined(QT_CHECK_RANGE) + if ( cellWidth < 0 || cellWidth > SHRT_MAX ) { + qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)", + name( "unnamed" ), cellWidth ); + return; + } +#endif + cellW = (short)cellWidth; + + updateScrollBars( horSteps | horRange ); + if ( autoUpdate() && isVisible() ) + repaint(); + +} + +/* + \overload int QtTableView::cellHeight() const + + Returns the row height, in pixels. Returns 0 if the rows have + variable heights. + + \sa setCellHeight(), cellWidth() +*/ + + +/* + Returns the height of row \a row in pixels. + + This function is virtual and must be reimplemented by subclasses that + have variable cell heights. Note that if the total table height + changes, updateTableSize() must be called. + + \sa setCellHeight(), cellWidth(), totalHeight() +*/ + +int QtTableView::cellHeight( int ) +{ + return cellH; +} + +/* + Sets the height in pixels of the table cells to \a cellHeight. + + Setting it to 0 means that the row height is variable. When set + to 0 (this is the default), QtTableView calls the virtual function + cellHeight() to get the height. + + \sa cellHeight(), setCellWidth(), totalHeight(), numRows() +*/ + +void QtTableView::setCellHeight( int cellHeight ) +{ + if ( cellH == cellHeight ) + return; +#if defined(QT_CHECK_RANGE) + if ( cellHeight < 0 || cellHeight > SHRT_MAX ) { + qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)", + name( "unnamed" ), cellHeight ); + return; + } +#endif + cellH = (short)cellHeight; + if ( autoUpdate() && isVisible() ) + repaint(); + updateScrollBars( verSteps | verRange ); +} + + +/* + Returns the total width of the table in pixels. + + This function is virtual and should be reimplemented by subclasses that + have variable cell widths and a non-trivial cellWidth() function, or a + large number of columns in the table. + + The default implementation may be slow for very wide tables. + + \sa cellWidth(), totalHeight() */ + +int QtTableView::totalWidth() +{ + if ( cellW ) { + return cellW*nCols; + } else { + int tw = 0; + for( int i = 0 ; i < nCols ; i++ ) + tw += cellWidth( i ); + return tw; + } +} + +/* + Returns the total height of the table in pixels. + + This function is virtual and should be reimplemented by subclasses that + have variable cell heights and a non-trivial cellHeight() function, or a + large number of rows in the table. + + The default implementation may be slow for very tall tables. + + \sa cellHeight(), totalWidth() +*/ + +int QtTableView::totalHeight() +{ + if ( cellH ) { + return cellH*nRows; + } else { + int th = 0; + for( int i = 0 ; i < nRows ; i++ ) + th += cellHeight( i ); + return th; + } +} + + +/* + \fn uint QtTableView::tableFlags() const + + Returns the union of the table flags that are currently set. + + \sa setTableFlags(), clearTableFlags(), testTableFlags() +*/ + +/* + \fn bool QtTableView::testTableFlags( uint f ) const + + Returns TRUE if any of the table flags in \a f are currently set, + otherwise FALSE. + + \sa setTableFlags(), clearTableFlags(), tableFlags() +*/ + +/* + Sets the table flags to \a f. + + If a flag setting changes the appearance of the table, the table is + repainted if - and only if - autoUpdate() is TRUE. + + The table flags are mostly single bits, though there are some multibit + flags for convenience. Here is a complete list: + + <dl compact> + <dt> Tbl_vScrollBar <dd> - The table has a vertical scroll bar. + <dt> Tbl_hScrollBar <dd> - The table has a horizontal scroll bar. + <dt> Tbl_autoVScrollBar <dd> - The table has a vertical scroll bar if + - and only if - the table is taller than the view. + <dt> Tbl_autoHScrollBar <dd> The table has a horizontal scroll bar if + - and only if - the table is wider than the view. + <dt> Tbl_autoScrollBars <dd> - The union of the previous two flags. + <dt> Tbl_clipCellPainting <dd> - The table uses QPainter::setClipRect() to + make sure that paintCell() will not draw outside the cell + boundaries. + <dt> Tbl_cutCellsV <dd> - The table will never show part of a + cell at the bottom of the table; if there is not space for all of + a cell, the space is left blank. + <dt> Tbl_cutCellsH <dd> - The table will never show part of a + cell at the right side of the table; if there is not space for all of + a cell, the space is left blank. + <dt> Tbl_cutCells <dd> - The union of the previous two flags. + <dt> Tbl_scrollLastHCell <dd> - When the user scrolls horizontally, + let him/her scroll the last cell left until it is at the left + edge of the view. If this flag is not set, the user can only scroll + to the point where the last cell is completely visible. + <dt> Tbl_scrollLastVCell <dd> - When the user scrolls vertically, let + him/her scroll the last cell up until it is at the top edge of + the view. If this flag is not set, the user can only scroll to the + point where the last cell is completely visible. + <dt> Tbl_scrollLastCell <dd> - The union of the previous two flags. + <dt> Tbl_smoothHScrolling <dd> - The table scrolls as smoothly as + possible when the user scrolls horizontally. When this flag is not + set, scrolling is done one cell at a time. + <dt> Tbl_smoothVScrolling <dd> - The table scrolls as smoothly as + possible when scrolling vertically. When this flag is not set, + scrolling is done one cell at a time. + <dt> Tbl_smoothScrolling <dd> - The union of the previous two flags. + <dt> Tbl_snapToHGrid <dd> - Except when the user is actually scrolling, + the leftmost column shown snaps to the leftmost edge of the view. + <dt> Tbl_snapToVGrid <dd> - Except when the user is actually + scrolling, the top row snaps to the top edge of the view. + <dt> Tbl_snapToGrid <dd> - The union of the previous two flags. + </dl> + + You can specify more than one flag at a time using bitwise OR. + + Example: + \code + setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars ); + \endcode + + \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and + Tbl_cutCellsV) may cause painting problems when scrollbars are + enabled. Do not combine cutCells and scrollbars. + + + \sa clearTableFlags(), testTableFlags(), tableFlags() +*/ + +void QtTableView::setTableFlags( uint f ) +{ + f = (f ^ tFlags) & f; // clear flags already set + tFlags |= f; + + bool updateOn = autoUpdate(); + setAutoUpdate( FALSE ); + + uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; + + if ( f & Tbl_vScrollBar ) { + setVerScrollBar( TRUE ); + } + if ( f & Tbl_hScrollBar ) { + setHorScrollBar( TRUE ); + } + if ( f & Tbl_autoVScrollBar ) { + updateScrollBars( verRange ); + } + if ( f & Tbl_autoHScrollBar ) { + updateScrollBars( horRange ); + } + if ( f & Tbl_scrollLastHCell ) { + updateScrollBars( horRange ); + } + if ( f & Tbl_scrollLastVCell ) { + updateScrollBars( verRange ); + } + if ( f & Tbl_snapToHGrid ) { + updateScrollBars( horRange ); + } + if ( f & Tbl_snapToVGrid ) { + updateScrollBars( verRange ); + } + if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags + if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll? + (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) { + snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping + (f & Tbl_snapToVGrid) != 0 ); + repaintMask |= Tbl_snapToGrid; // repaint table + } + } + + if ( updateOn ) { + setAutoUpdate( TRUE ); + updateScrollBars(); + if ( isVisible() && (f & repaintMask) ) + repaint(); + } + +} + +/* + Clears the \link setTableFlags() table flags\endlink that are set + in \a f. + + Example (clears a single flag): + \code + clearTableFlags( Tbl_snapToGrid ); + \endcode + + The default argument clears all flags. + + \sa setTableFlags(), testTableFlags(), tableFlags() +*/ + +void QtTableView::clearTableFlags( uint f ) +{ + f = (f ^ ~tFlags) & f; // clear flags that are already 0 + tFlags &= ~f; + + bool updateOn = autoUpdate(); + setAutoUpdate( FALSE ); + + uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; + + if ( f & Tbl_vScrollBar ) { + setVerScrollBar( FALSE ); + } + if ( f & Tbl_hScrollBar ) { + setHorScrollBar( FALSE ); + } + if ( f & Tbl_scrollLastHCell ) { + int maxX = maxXOffset(); + if ( xOffs > maxX ) { + setOffset( maxX, yOffs ); + repaintMask |= Tbl_scrollLastHCell; + } + updateScrollBars( horRange ); + } + if ( f & Tbl_scrollLastVCell ) { + int maxY = maxYOffset(); + if ( yOffs > maxY ) { + setOffset( xOffs, maxY ); + repaintMask |= Tbl_scrollLastVCell; + } + updateScrollBars( verRange ); + } + if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags + if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll? + (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) { + snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping + (f & Tbl_smoothVScrolling) != 0 ); + repaintMask |= Tbl_smoothScrolling; // repaint table + } + } + if ( f & Tbl_snapToHGrid ) { + updateScrollBars( horRange ); + } + if ( f & Tbl_snapToVGrid ) { + updateScrollBars( verRange ); + } + if ( updateOn ) { + setAutoUpdate( TRUE ); + updateScrollBars(); // returns immediately if nothing to do + if ( isVisible() && (f & repaintMask) ) + repaint(); + } + +} + + +/* + \fn bool QtTableView::autoUpdate() const + + Returns TRUE if the view updates itself automatically whenever it + is changed in some way. + + \sa setAutoUpdate() +*/ + +/* + Sets the auto-update option of the table view to \a enable. + + If \a enable is TRUE (this is the default), the view updates itself + automatically whenever it has changed in some way (for example, when a + \link setTableFlags() flag\endlink is changed). + + If \a enable is FALSE, the view does NOT repaint itself or update + its internal state variables when it is changed. This can be + useful to avoid flicker during large changes and is singularly + useless otherwise. Disable auto-update, do the changes, re-enable + auto-update and call repaint(). + + \warning Do not leave the view in this state for a long time + (i.e., between events). If, for example, the user interacts with the + view when auto-update is off, strange things can happen. + + Setting auto-update to TRUE does not repaint the view; you must call + repaint() to do this. + + \sa autoUpdate(), repaint() +*/ + +void QtTableView::setAutoUpdate( bool enable ) +{ + if ( isUpdatesEnabled() == enable ) + return; + setUpdatesEnabled( enable ); + if ( enable ) { + showOrHideScrollBars(); + updateScrollBars(); + } +} + + +/* + Repaints the cell at row \a row, column \a col if it is inside the view. + + If \a erase is TRUE, the relevant part of the view is cleared to the + background color/pixmap before the contents are repainted. + + \sa isVisible() +*/ + +void QtTableView::updateCell( int row, int col, bool erase ) +{ + int xPos, yPos; + if ( !colXPos( col, &xPos ) ) + return; + if ( !rowYPos( row, &yPos ) ) + return; + QRect uR = QRect( xPos, yPos, + cellW ? cellW : cellWidth(col), + cellH ? cellH : cellHeight(row) ); + repaint( uR.intersect(viewRect()), erase ); +} + + +/* + \fn QRect QtTableView::cellUpdateRect() const + + This function should be called only from the paintCell() function in + subclasses. It returns the portion of a cell that actually needs to be + updated in \e cell coordinates. This is useful only for non-trivial + paintCell(). + +*/ + +/* + Returns the rectangle that is the actual table, excluding any + frame, in \e widget coordinates. +*/ + +QRect QtTableView::viewRect() const +{ + return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() ); +} + + +/* + Returns the index of the last (bottom) row in the view. + The index of the first row is 0. + + If no rows are visible it returns -1. This can happen if the + view is too small for the first row and Tbl_cutCellsV is set. + + \sa lastColVisible() +*/ + +int QtTableView::lastRowVisible() const +{ + int cellMaxY; + int row = findRawRow( maxViewY(), &cellMaxY ); + if ( row == -1 || row >= nRows ) { // maxViewY() past end? + row = nRows - 1; // yes: return last row + } else { + if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) { + if ( row == yCellOffs ) // cut by right margin? + return -1; // yes, nothing in the view + else + row = row - 1; // cut by margin, one back + } + } + return row; +} + +/* + Returns the index of the last (right) column in the view. + The index of the first column is 0. + + If no columns are visible it returns -1. This can happen if the + view is too narrow for the first column and Tbl_cutCellsH is set. + + \sa lastRowVisible() +*/ + +int QtTableView::lastColVisible() const +{ + int cellMaxX; + int col = findRawCol( maxViewX(), &cellMaxX ); + if ( col == -1 || col >= nCols ) { // maxViewX() past end? + col = nCols - 1; // yes: return last col + } else { + if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) { + if ( col == xCellOffs ) // cut by bottom margin? + return -1; // yes, nothing in the view + else + col = col - 1; // cell by margin, one back + } + } + return col; +} + +/* + Returns TRUE if \a row is at least partially visible. + \sa colIsVisible() +*/ + +bool QtTableView::rowIsVisible( int row ) const +{ + return rowYPos( row, 0 ); +} + +/* + Returns TRUE if \a col is at least partially visible. + \sa rowIsVisible() +*/ + +bool QtTableView::colIsVisible( int col ) const +{ + return colXPos( col, 0 ); +} + + +/* + \internal + Called when both scroll bars are active at the same time. Covers the + bottom left corner between the two scroll bars with an empty widget. +*/ + +void QtTableView::coverCornerSquare( bool enable ) +{ + coveringCornerSquare = enable; + if ( !cornerSquare && enable ) { + cornerSquare = new QCornerSquare( this ); + Q_CHECK_PTR( cornerSquare ); + cornerSquare->setGeometry( maxViewX() + frameWidth() + 1, + maxViewY() + frameWidth() + 1, + VSBEXT, + HSBEXT); + } + if ( autoUpdate() && cornerSquare ) { + if ( enable ) + cornerSquare->show(); + else + cornerSquare->hide(); + } +} + + +/* + \internal + Scroll the view to a position such that: + + If \a horizontal is TRUE, the leftmost column shown fits snugly + with the left edge of the view. + + If \a vertical is TRUE, the top row shown fits snugly with the top + of the view. + + You can achieve the same effect automatically by setting any of the + \link setTableFlags() Tbl_snapTo*Grid \endlink table flags. +*/ + +void QtTableView::snapToGrid( bool horizontal, bool vertical ) +{ + int newXCell = -1; + int newYCell = -1; + if ( horizontal && xCellDelta != 0 ) { + int w = cellW ? cellW : cellWidth( xCellOffs ); + if ( xCellDelta >= w/2 ) + newXCell = xCellOffs + 1; + else + newXCell = xCellOffs; + } + if ( vertical && yCellDelta != 0 ) { + int h = cellH ? cellH : cellHeight( yCellOffs ); + if ( yCellDelta >= h/2 ) + newYCell = yCellOffs + 1; + else + newYCell = yCellOffs; + } + setTopLeftCell( newYCell, newXCell ); //row,column +} + +/* + \internal + This internal slot is connected to the horizontal scroll bar's + QScrollBar::valueChanged() signal. + + Moves the table horizontally to offset \a val without updating the + scroll bar. +*/ + +void QtTableView::horSbValue( int val ) +{ + if ( horSliding ) { + horSliding = FALSE; + if ( horSnappingOff ) { + horSnappingOff = FALSE; + tFlags |= Tbl_snapToHGrid; + } + } + setOffset( val, yOffs, FALSE ); +} + +/* + \internal + This internal slot is connected to the horizontal scroll bar's + QScrollBar::sliderMoved() signal. + + Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set. +*/ + +void QtTableView::horSbSliding( int val ) +{ + if ( testTableFlags(Tbl_snapToHGrid) && + testTableFlags(Tbl_smoothHScrolling) ) { + tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding + setOffset( val, yOffs, FALSE ); + tFlags |= Tbl_snapToHGrid; // turn on snapping again + } else { + setOffset( val, yOffs, FALSE ); + } +} + +/* + \internal + This internal slot is connected to the horizontal scroll bar's + QScrollBar::sliderReleased() signal. +*/ + +void QtTableView::horSbSlidingDone( ) +{ + if ( testTableFlags(Tbl_snapToHGrid) && + testTableFlags(Tbl_smoothHScrolling) ) + snapToGrid( TRUE, FALSE ); +} + +/* + \internal + This internal slot is connected to the vertical scroll bar's + QScrollBar::valueChanged() signal. + + Moves the table vertically to offset \a val without updating the + scroll bar. +*/ + +void QtTableView::verSbValue( int val ) +{ + if ( verSliding ) { + verSliding = FALSE; + if ( verSnappingOff ) { + verSnappingOff = FALSE; + tFlags |= Tbl_snapToVGrid; + } + } + setOffset( xOffs, val, FALSE ); +} + +/* + \internal + This internal slot is connected to the vertical scroll bar's + QScrollBar::sliderMoved() signal. + + Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set. +*/ + +void QtTableView::verSbSliding( int val ) +{ + if ( testTableFlags(Tbl_snapToVGrid) && + testTableFlags(Tbl_smoothVScrolling) ) { + tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding + setOffset( xOffs, val, FALSE ); + tFlags |= Tbl_snapToVGrid; // turn on snapping again + } else { + setOffset( xOffs, val, FALSE ); + } +} + +/* + \internal + This internal slot is connected to the vertical scroll bar's + QScrollBar::sliderReleased() signal. +*/ + +void QtTableView::verSbSlidingDone( ) +{ + if ( testTableFlags(Tbl_snapToVGrid) && + testTableFlags(Tbl_smoothVScrolling) ) + snapToGrid( FALSE, TRUE ); +} + + +/* + This virtual function is called before painting of table cells + is started. It can be reimplemented by subclasses that want to + to set up the painter in a special way and that do not want to + do so for each cell. +*/ + +void QtTableView::setupPainter( QPainter * ) +{ +} + +/* + \fn void QtTableView::paintCell( QPainter *p, int row, int col ) + + This pure virtual function is called to paint the single cell at \a + (row,col) using \a p, which is open when paintCell() is called and + must remain open. + + The coordinate system is \link QPainter::translate() translated \endlink + so that the origin is at the top-left corner of the cell to be + painted, i.e. \e cell coordinates. Do not scale or shear the coordinate + system (or if you do, restore the transformation matrix before you + return). + + The painter is not clipped by default and for maximum efficiency. For safety, + call setTableFlags(Tbl_clipCellPainting) to enable clipping. + + \sa paintEvent(), setTableFlags() */ + + +/* + Handles paint events, \a e, for the table view. + + Calls paintCell() for the cells that needs to be repainted. +*/ + +void QtTableView::paintEvent( QPaintEvent *e ) +{ + QRect updateR = e->rect(); // update rectangle + if ( sbDirty ) { + bool e = eraseInPaint; + updateScrollBars(); + eraseInPaint = e; + } + + QPainter paint( this ); + + if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ? + drawFrame( &paint ); + if ( updateR.left() < frameWidth() ) //### + updateR.setLeft( frameWidth() ); + if ( updateR.top() < frameWidth() ) + updateR.setTop( frameWidth() ); + } + + int maxWX = maxViewX(); + int maxWY = maxViewY(); + if ( updateR.right() > maxWX ) + updateR.setRight( maxWX ); + if ( updateR.bottom() > maxWY ) + updateR.setBottom( maxWY ); + + setupPainter( &paint ); // prepare for painting table + + int firstRow = findRow( updateR.y() ); + int firstCol = findCol( updateR.x() ); + int xStart, yStart; + if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) { + paint.eraseRect( updateR ); // erase area outside cells but in view + return; + } + int maxX = updateR.right(); + int maxY = updateR.bottom(); + int row = firstRow; + int col; + int yPos = yStart; + int xPos = maxX+1; // in case the while() is empty + int nextX; + int nextY; + QRect winR = viewRect(); + QRect cellR; + QRect cellUR; +#ifndef QT_NO_TRANSFORMATIONS + QWMatrix matrix; +#endif + + while ( yPos <= maxY && row < nRows ) { + nextY = yPos + (cellH ? cellH : cellHeight( row )); + if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) ) + break; + col = firstCol; + xPos = xStart; + while ( xPos <= maxX && col < nCols ) { + nextX = xPos + (cellW ? cellW : cellWidth( col )); + if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) ) + break; + + cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col), + cellH ? cellH : cellHeight(row) ); + cellUR = cellR.intersect( updateR ); + if ( cellUR.isValid() ) { + cellUpdateR = cellUR; + cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates + if ( eraseInPaint ) + paint.eraseRect( cellUR ); + +#ifndef QT_NO_TRANSFORMATIONS + matrix.translate( xPos, yPos ); + paint.setWorldMatrix( matrix ); + if ( testTableFlags(Tbl_clipCellPainting) || + frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt + paint.setClipRect( cellUR ); + paintCell( &paint, row, col ); + paint.setClipping( FALSE ); + } else { + paintCell( &paint, row, col ); + } + matrix.reset(); + paint.setWorldMatrix( matrix ); +#else + paint.translate( xPos, yPos ); + if ( testTableFlags(Tbl_clipCellPainting) || + frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt + paint.setClipRect( cellUR ); + paintCell( &paint, row, col ); + paint.setClipping( FALSE ); + } else { + paintCell( &paint, row, col ); + } + paint.translate( -xPos, -yPos ); +#endif + } + col++; + xPos = nextX; + } + row++; + yPos = nextY; + } + + // while painting we have to erase any areas in the view that + // are not covered by cells but are covered by the paint event + // rectangle these must be erased. We know that xPos is the last + // x pixel updated + 1 and that yPos is the last y pixel updated + 1. + + // Note that this needs to be done regardless whether we do + // eraseInPaint or not. Reason: a subclass may implement + // flicker-freeness and encourage the use of repaint(FALSE). + // The subclass, however, cannot draw all pixels, just those + // inside the cells. So QtTableView is reponsible for all pixels + // outside the cells. + + QRect viewR = viewRect(); + const QColorGroup g = colorGroup(); + + if ( xPos <= maxX ) { + QRect r = viewR; + r.setLeft( xPos ); + r.setBottom( yPos<maxY?yPos:maxY ); + if ( inherits( "QMultiLineEdit" ) ) + paint.fillRect( r.intersect( updateR ), g.base() ); + else + paint.eraseRect( r.intersect( updateR ) ); + } + if ( yPos <= maxY ) { + QRect r = viewR; + r.setTop( yPos ); + if ( inherits( "QMultiLineEdit" ) ) + paint.fillRect( r.intersect( updateR ), g.base() ); + else + paint.eraseRect( r.intersect( updateR ) ); + } +} + +/*\reimp +*/ +void QtTableView::resizeEvent( QResizeEvent * ) +{ + updateScrollBars( horValue | verValue | horSteps | horGeometry | horRange | + verSteps | verGeometry | verRange ); + showOrHideScrollBars(); + updateFrameSize(); + int maxX = QMIN( xOffs, maxXOffset() ); // ### can be slow + int maxY = QMIN( yOffs, maxYOffset() ); + setOffset( maxX, maxY ); +} + + +/* + Redraws all visible cells in the table view. +*/ + +void QtTableView::updateView() +{ + repaint( viewRect() ); +} + +/* + Returns a pointer to the vertical scroll bar mainly so you can + connect() to its signals. Note that the scroll bar works in pixel + values; use findRow() to translate to cell numbers. +*/ + +QScrollBar *QtTableView::verticalScrollBar() const +{ + QtTableView *that = (QtTableView*)this; // semantic const + if ( !vScrollBar ) { + QScrollBar *sb = new QScrollBar( QScrollBar::Vertical, that ); +#ifndef QT_NO_CURSOR + sb->setCursor( arrowCursor ); +#endif + sb->resize( sb->sizeHint() ); // height is irrelevant + Q_CHECK_PTR(sb); + sb->setTracking( FALSE ); + sb->setFocusPolicy( NoFocus ); + connect( sb, SIGNAL(valueChanged(int)), + SLOT(verSbValue(int))); + connect( sb, SIGNAL(sliderMoved(int)), + SLOT(verSbSliding(int))); + connect( sb, SIGNAL(sliderReleased()), + SLOT(verSbSlidingDone())); + sb->hide(); + that->vScrollBar = sb; + return sb; + } + return vScrollBar; +} + +/* + Returns a pointer to the horizontal scroll bar mainly so you can + connect() to its signals. Note that the scroll bar works in pixel + values; use findCol() to translate to cell numbers. +*/ + +QScrollBar *QtTableView::horizontalScrollBar() const +{ + QtTableView *that = (QtTableView*)this; // semantic const + if ( !hScrollBar ) { + QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that ); +#ifndef QT_NO_CURSOR + sb->setCursor( arrowCursor ); +#endif + sb->resize( sb->sizeHint() ); // width is irrelevant + sb->setFocusPolicy( NoFocus ); + Q_CHECK_PTR(sb); + sb->setTracking( FALSE ); + connect( sb, SIGNAL(valueChanged(int)), + SLOT(horSbValue(int))); + connect( sb, SIGNAL(sliderMoved(int)), + SLOT(horSbSliding(int))); + connect( sb, SIGNAL(sliderReleased()), + SLOT(horSbSlidingDone())); + sb->hide(); + that->hScrollBar = sb; + return sb; + } + return hScrollBar; +} + +/* + Enables or disables the horizontal scroll bar, as required by + setAutoUpdate() and the \link setTableFlags() table flags\endlink. +*/ + +void QtTableView::setHorScrollBar( bool on, bool update ) +{ + if ( on ) { + tFlags |= Tbl_hScrollBar; + horizontalScrollBar(); // created + if ( update ) + updateScrollBars( horMask | verMask ); + else + sbDirty = sbDirty | (horMask | verMask); + if ( testTableFlags( Tbl_vScrollBar ) ) + coverCornerSquare( TRUE ); + if ( autoUpdate() ) + sbDirty = sbDirty | horMask; + } else { + tFlags &= ~Tbl_hScrollBar; + if ( !hScrollBar ) + return; + coverCornerSquare( FALSE ); + bool hideScrollBar = autoUpdate() && hScrollBar->isVisible(); + if ( hideScrollBar ) + hScrollBar->hide(); + if ( update ) + updateScrollBars( verMask ); + else + sbDirty = sbDirty | verMask; + if ( hideScrollBar && isVisible() ) + repaint( hScrollBar->x(), hScrollBar->y(), + width() - hScrollBar->x(), hScrollBar->height() ); + } + if ( update ) + updateFrameSize(); +} + + +/* + Enables or disables the vertical scroll bar, as required by + setAutoUpdate() and the \link setTableFlags() table flags\endlink. +*/ + +void QtTableView::setVerScrollBar( bool on, bool update ) +{ + if ( on ) { + tFlags |= Tbl_vScrollBar; + verticalScrollBar(); // created + if ( update ) + updateScrollBars( verMask | horMask ); + else + sbDirty = sbDirty | (horMask | verMask); + if ( testTableFlags( Tbl_hScrollBar ) ) + coverCornerSquare( TRUE ); + if ( autoUpdate() ) + sbDirty = sbDirty | verMask; + } else { + tFlags &= ~Tbl_vScrollBar; + if ( !vScrollBar ) + return; + coverCornerSquare( FALSE ); + bool hideScrollBar = autoUpdate() && vScrollBar->isVisible(); + if ( hideScrollBar ) + vScrollBar->hide(); + if ( update ) + updateScrollBars( horMask ); + else + sbDirty = sbDirty | horMask; + if ( hideScrollBar && isVisible() ) + repaint( vScrollBar->x(), vScrollBar->y(), + vScrollBar->width(), height() - vScrollBar->y() ); + } + if ( update ) + updateFrameSize(); +} + + + + +int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY, + bool goOutsideView ) const +{ + int r = -1; + if ( nRows == 0 ) + return r; + if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) { + if ( yPos < minViewY() ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QtTableView::findRawRow: (%s) internal error: " + "yPos < minViewY() && goOutsideView " + "not supported. (%d,%d)", + name( "unnamed" ), yPos, yOffs ); +#endif + return -1; + } + if ( cellH ) { // uniform cell height + r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top + if ( cellMaxY ) + *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1; + if ( cellMinY ) + *cellMinY = r*cellH + minViewY() - yCellDelta; + r += yCellOffs; // absolute cell index + } else { // variable cell height + QtTableView *tw = (QtTableView *)this; + r = yCellOffs; + int h = minViewY() - yCellDelta; //##arnt3 + int oldH = h; + Q_ASSERT( r < nRows ); + while ( r < nRows ) { + oldH = h; + h += tw->cellHeight( r ); // Start of next cell + if ( yPos < h ) + break; + r++; + } + if ( cellMaxY ) + *cellMaxY = h - 1; + if ( cellMinY ) + *cellMinY = oldH; + } + } + return r; + +} + + +int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX , + bool goOutsideView ) const +{ + int c = -1; + if ( nCols == 0 ) + return c; + if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) { + if ( xPos < minViewX() ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QtTableView::findRawCol: (%s) internal error: " + "xPos < minViewX() && goOutsideView " + "not supported. (%d,%d)", + name( "unnamed" ), xPos, xOffs ); +#endif + return -1; + } + if ( cellW ) { // uniform cell width + c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left + if ( cellMaxX ) + *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1; + if ( cellMinX ) + *cellMinX = c*cellW + minViewX() - xCellDelta; + c += xCellOffs; // absolute cell index + } else { // variable cell width + QtTableView *tw = (QtTableView *)this; + c = xCellOffs; + int w = minViewX() - xCellDelta; //##arnt3 + int oldW = w; + Q_ASSERT( c < nCols ); + while ( c < nCols ) { + oldW = w; + w += tw->cellWidth( c ); // Start of next cell + if ( xPos < w ) + break; + c++; + } + if ( cellMaxX ) + *cellMaxX = w - 1; + if ( cellMinX ) + *cellMinX = oldW; + } + } + return c; +} + + +/* + Returns the index of the row at position \a yPos, where \a yPos is in + \e widget coordinates. Returns -1 if \a yPos is outside the valid + range. + + \sa findCol(), rowYPos() +*/ + +int QtTableView::findRow( int yPos ) const +{ + int cellMaxY; + int row = findRawRow( yPos, &cellMaxY ); + if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) + row = - 1; // cell cut by bottom margin + if ( row >= nRows ) + row = -1; + return row; +} + + +/* + Returns the index of the column at position \a xPos, where \a xPos is + in \e widget coordinates. Returns -1 if \a xPos is outside the valid + range. + + \sa findRow(), colXPos() +*/ + +int QtTableView::findCol( int xPos ) const +{ + int cellMaxX; + int col = findRawCol( xPos, &cellMaxX ); + if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) + col = - 1; // cell cut by right margin + if ( col >= nCols ) + col = -1; + return col; +} + + +/* + Computes the position in the widget of row \a row. + + Returns TRUE and stores the result in \a *yPos (in \e widget + coordinates) if the row is visible. Returns FALSE and does not modify + \a *yPos if \a row is invisible or invalid. + + \sa colXPos(), findRow() +*/ + +bool QtTableView::rowYPos( int row, int *yPos ) const +{ + int y; + if ( row >= yCellOffs ) { + if ( cellH ) { + int lastVisible = lastRowVisible(); + if ( row > lastVisible || lastVisible == -1 ) + return FALSE; + y = (row - yCellOffs)*cellH + minViewY() - yCellDelta; + } else { + //##arnt3 + y = minViewY() - yCellDelta; // y of leftmost cell in view + int r = yCellOffs; + QtTableView *tw = (QtTableView *)this; + int maxY = maxViewY(); + while ( r < row && y <= maxY ) + y += tw->cellHeight( r++ ); + if ( y > maxY ) + return FALSE; + + } + } else { + return FALSE; + } + if ( yPos ) + *yPos = y; + return TRUE; +} + + +/* + Computes the position in the widget of column \a col. + + Returns TRUE and stores the result in \a *xPos (in \e widget + coordinates) if the column is visible. Returns FALSE and does not + modify \a *xPos if \a col is invisible or invalid. + + \sa rowYPos(), findCol() +*/ + +bool QtTableView::colXPos( int col, int *xPos ) const +{ + int x; + if ( col >= xCellOffs ) { + if ( cellW ) { + int lastVisible = lastColVisible(); + if ( col > lastVisible || lastVisible == -1 ) + return FALSE; + x = (col - xCellOffs)*cellW + minViewX() - xCellDelta; + } else { + //##arnt3 + x = minViewX() - xCellDelta; // x of uppermost cell in view + int c = xCellOffs; + QtTableView *tw = (QtTableView *)this; + int maxX = maxViewX(); + while ( c < col && x <= maxX ) + x += tw->cellWidth( c++ ); + if ( x > maxX ) + return FALSE; + } + } else { + return FALSE; + } + if ( xPos ) + *xPos = x; + return TRUE; +} + + +/* + Moves the visible area of the table right by \a xPixels and + down by \a yPixels pixels. Both may be negative. + + \warning You might find that QScrollView offers a higher-level of + functionality than using QtTableView and this function. + + This function is \e not the same as QWidget::scroll(); in particular, + the signs of \a xPixels and \a yPixels have the reverse semantics. + + \sa setXOffset(), setYOffset(), setOffset(), setTopCell(), + setLeftCell() +*/ + +void QtTableView::scroll( int xPixels, int yPixels ) +{ + QWidget::scroll( -xPixels, -yPixels, contentsRect() ); +} + + +/* + Returns the leftmost pixel of the table view in \e view + coordinates. This excludes the frame and any header. + + \sa maxViewY(), viewWidth(), contentsRect() +*/ + +int QtTableView::minViewX() const +{ + return frameWidth(); +} + + +/* + Returns the top pixel of the table view in \e view + coordinates. This excludes the frame and any header. + + \sa maxViewX(), viewHeight(), contentsRect() +*/ + +int QtTableView::minViewY() const +{ + return frameWidth(); +} + + +/* + Returns the rightmost pixel of the table view in \e view + coordinates. This excludes the frame and any scroll bar, but + includes blank pixels to the right of the visible table data. + + \sa maxViewY(), viewWidth(), contentsRect() +*/ + +int QtTableView::maxViewX() const +{ + return width() - 1 - frameWidth() + - (tFlags & Tbl_vScrollBar ? VSBEXT + : 0); +} + + +/* + Returns the bottom pixel of the table view in \e view + coordinates. This excludes the frame and any scroll bar, but + includes blank pixels below the visible table data. + + \sa maxViewX(), viewHeight(), contentsRect() +*/ + +int QtTableView::maxViewY() const +{ + return height() - 1 - frameWidth() + - (tFlags & Tbl_hScrollBar ? HSBEXT + : 0); +} + + +/* + Returns the width of the table view, as such, in \e view + coordinates. This does not include any header, scroll bar or frame, + but it does include background pixels to the right of the table data. + + \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect() +*/ + +int QtTableView::viewWidth() const +{ + return maxViewX() - minViewX() + 1; +} + + +/* + Returns the height of the table view, as such, in \e view + coordinates. This does not include any header, scroll bar or frame, + but it does include background pixels below the table data. + + \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect() +*/ + +int QtTableView::viewHeight() const +{ + return maxViewY() - minViewY() + 1; +} + + +void QtTableView::doAutoScrollBars() +{ + int viewW = width() - frameWidth() - minViewX(); + int viewH = height() - frameWidth() - minViewY(); + bool vScrollOn = testTableFlags(Tbl_vScrollBar); + bool hScrollOn = testTableFlags(Tbl_hScrollBar); + int w = 0; + int h = 0; + int i; + + if ( testTableFlags(Tbl_autoHScrollBar) ) { + if ( cellW ) { + w = cellW*nCols; + } else { + i = 0; + while ( i < nCols && w <= viewW ) + w += cellWidth( i++ ); + } + if ( w > viewW ) + hScrollOn = TRUE; + else + hScrollOn = FALSE; + } + + if ( testTableFlags(Tbl_autoVScrollBar) ) { + if ( cellH ) { + h = cellH*nRows; + } else { + i = 0; + while ( i < nRows && h <= viewH ) + h += cellHeight( i++ ); + } + + if ( h > viewH ) + vScrollOn = TRUE; + else + vScrollOn = FALSE; + } + + if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn ) + if ( w > viewW - VSBEXT ) + hScrollOn = TRUE; + + if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn ) + if ( h > viewH - HSBEXT ) + vScrollOn = TRUE; + + setHorScrollBar( hScrollOn, FALSE ); + setVerScrollBar( vScrollOn, FALSE ); + updateFrameSize(); +} + + +/* + \fn void QtTableView::updateScrollBars() + + Updates the scroll bars' contents and presence to match the table's + state. Generally, you should not need to call this. + + \sa setTableFlags() +*/ + +/* + Updates the scroll bars' contents and presence to match the table's + state \c or \a f. + + \sa setTableFlags() +*/ + +void QtTableView::updateScrollBars( uint f ) +{ + sbDirty = sbDirty | f; + if ( inSbUpdate ) + return; + inSbUpdate = TRUE; + + if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) || + testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) ) + // if range change and auto + doAutoScrollBars(); // turn scroll bars on/off if needed + + if ( !autoUpdate() ) { + inSbUpdate = FALSE; + return; + } + if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) && + !testTableFlags( Tbl_vScrollBar ) ) { + setYOffset( 0 ); + } + if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) && + !testTableFlags( Tbl_hScrollBar ) ) { + setXOffset( 0 ); + } + if ( !isVisible() ) { + inSbUpdate = FALSE; + return; + } + + if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) { + if ( sbDirty & horGeometry ) + hScrollBar->setGeometry( 0,height() - HSBEXT, + viewWidth() + frameWidth()*2, + HSBEXT); + + if ( sbDirty & horSteps ) { + if ( cellW ) + hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() ); + else + hScrollBar->setSteps( 16, viewWidth() ); + } + + if ( sbDirty & horRange ) + hScrollBar->setRange( 0, maxXOffset() ); + + if ( sbDirty & horValue ) + hScrollBar->setValue( xOffs ); + + // show scrollbar only when it has a sane geometry + if ( !hScrollBar->isVisible() ) + hScrollBar->show(); + } + + if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) { + if ( sbDirty & verGeometry ) + vScrollBar->setGeometry( width() - VSBEXT, 0, + VSBEXT, + viewHeight() + frameWidth()*2 ); + + if ( sbDirty & verSteps ) { + if ( cellH ) + vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() ); + else + vScrollBar->setSteps( 16, viewHeight() ); // fttb! ### + } + + if ( sbDirty & verRange ) + vScrollBar->setRange( 0, maxYOffset() ); + + if ( sbDirty & verValue ) + vScrollBar->setValue( yOffs ); + + // show scrollbar only when it has a sane geometry + if ( !vScrollBar->isVisible() ) + vScrollBar->show(); + } + if ( coveringCornerSquare && + ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) ) + cornerSquare->move( maxViewX() + frameWidth() + 1, + maxViewY() + frameWidth() + 1 ); + + sbDirty = 0; + inSbUpdate = FALSE; +} + + +void QtTableView::updateFrameSize() +{ + int rw = width() - ( testTableFlags(Tbl_vScrollBar) ? + VSBEXT : 0 ); + int rh = height() - ( testTableFlags(Tbl_hScrollBar) ? + HSBEXT : 0 ); + if ( rw < 0 ) + rw = 0; + if ( rh < 0 ) + rh = 0; + + if ( autoUpdate() ) { + int fh = frameRect().height(); + int fw = frameRect().width(); + setFrameRect( QRect(0,0,rw,rh) ); + + if ( rw != fw ) + update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh ); + if ( rh != fh ) + update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 ); + } +} + + +/* + Returns the maximum horizontal offset within the table of the + view's left edge in \e table coordinates. + + This is used mainly to set the horizontal scroll bar's range. + + \sa maxColOffset(), maxYOffset(), totalWidth() +*/ + +int QtTableView::maxXOffset() +{ + int tw = totalWidth(); + int maxOffs; + if ( testTableFlags(Tbl_scrollLastHCell) ) { + if ( nCols != 1) + maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) ); + else + maxOffs = tw - viewWidth(); + } else { + if ( testTableFlags(Tbl_snapToHGrid) ) { + if ( cellW ) { + maxOffs = tw - (viewWidth()/cellW)*cellW; + } else { + int goal = tw - viewWidth(); + int pos = tw; + int nextCol = nCols - 1; + int nextCellWidth = cellWidth( nextCol ); + while( nextCol > 0 && pos > goal + nextCellWidth ) { + pos -= nextCellWidth; + nextCellWidth = cellWidth( --nextCol ); + } + if ( goal + nextCellWidth == pos ) + maxOffs = goal; + else if ( goal < pos ) + maxOffs = pos; + else + maxOffs = 0; + } + } else { + maxOffs = tw - viewWidth(); + } + } + return maxOffs > 0 ? maxOffs : 0; +} + + +/* + Returns the maximum vertical offset within the table of the + view's top edge in \e table coordinates. + + This is used mainly to set the vertical scroll bar's range. + + \sa maxRowOffset(), maxXOffset(), totalHeight() +*/ + +int QtTableView::maxYOffset() +{ + int th = totalHeight(); + int maxOffs; + if ( testTableFlags(Tbl_scrollLastVCell) ) { + if ( nRows != 1) + maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) ); + else + maxOffs = th - viewHeight(); + } else { + if ( testTableFlags(Tbl_snapToVGrid) ) { + if ( cellH ) { + maxOffs = th - (viewHeight()/cellH)*cellH; + } else { + int goal = th - viewHeight(); + int pos = th; + int nextRow = nRows - 1; + int nextCellHeight = cellHeight( nextRow ); + while( nextRow > 0 && pos > goal + nextCellHeight ) { + pos -= nextCellHeight; + nextCellHeight = cellHeight( --nextRow ); + } + if ( goal + nextCellHeight == pos ) + maxOffs = goal; + else if ( goal < pos ) + maxOffs = pos; + else + maxOffs = 0; + } + } else { + maxOffs = th - viewHeight(); + } + } + return maxOffs > 0 ? maxOffs : 0; +} + + +/* + Returns the index of the last column, which may be at the left edge + of the view. + + Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag, + this may or may not be the last column. + + \sa maxXOffset(), maxRowOffset() +*/ + +int QtTableView::maxColOffset() +{ + int mx = maxXOffset(); + if ( cellW ) + return mx/cellW; + else { + int xcd=0, col=0; + while ( col < nCols && mx > (xcd=cellWidth(col)) ) { + mx -= xcd; + col++; + } + return col; + } +} + + +/* + Returns the index of the last row, which may be at the top edge of + the view. + + Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag, + this may or may not be the last row. + + \sa maxYOffset(), maxColOffset() +*/ + +int QtTableView::maxRowOffset() +{ + int my = maxYOffset(); + if ( cellH ) + return my/cellH; + else { + int ycd=0, row=0; + while ( row < nRows && my > (ycd=cellHeight(row)) ) { + my -= ycd; + row++; + } + return row; + } +} + + +void QtTableView::showOrHideScrollBars() +{ + if ( !autoUpdate() ) + return; + if ( vScrollBar ) { + if ( testTableFlags(Tbl_vScrollBar) ) { + if ( !vScrollBar->isVisible() ) + sbDirty = sbDirty | verMask; + } else { + if ( vScrollBar->isVisible() ) + vScrollBar->hide(); + } + } + if ( hScrollBar ) { + if ( testTableFlags(Tbl_hScrollBar) ) { + if ( !hScrollBar->isVisible() ) + sbDirty = sbDirty | horMask; + } else { + if ( hScrollBar->isVisible() ) + hScrollBar->hide(); + } + } + if ( cornerSquare ) { + if ( testTableFlags(Tbl_hScrollBar) && + testTableFlags(Tbl_vScrollBar) ) { + if ( !cornerSquare->isVisible() ) + cornerSquare->show(); + } else { + if ( cornerSquare->isVisible() ) + cornerSquare->hide(); + } + } +} + + +/* + Updates the scroll bars and internal state. + + Call this function when the table view's total size is changed; + typically because the result of cellHeight() or cellWidth() have changed. + + This function does not repaint the widget. +*/ + +void QtTableView::updateTableSize() +{ + bool updateOn = autoUpdate(); + setAutoUpdate( FALSE ); + int xofs = xOffset(); + xOffs++; //so that setOffset will not return immediately + setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly + setAutoUpdate(updateOn); + + updateScrollBars( horSteps | horRange | + verSteps | verRange ); + showOrHideScrollBars(); +} + + +#endif diff --git a/src/attic/qttableview.h b/src/attic/qttableview.h new file mode 100644 index 0000000..a5dab15 --- /dev/null +++ b/src/attic/qttableview.h @@ -0,0 +1,250 @@ +/********************************************************************** +** +** Definition of QtTableView class +** +** Created : 941115 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file contains a class moved out of the Qt GUI Toolkit API. It +** may be used, distributed and modified without limitation. +** +**********************************************************************/ + +#ifndef QTTABLEVIEW_H +#define QTTABLEVIEW_H + +#ifndef QT_H +#include "qframe.h" +#endif // QT_H + +#ifndef QT_NO_QTTABLEVIEW + +class QScrollBar; +class QCornerSquare; + + +class QtTableView : public QFrame +{ + Q_OBJECT +public: + virtual void setBackgroundColor( const QColor & ); + virtual void setPalette( const QPalette & ); + void show(); + + void repaint( bool erase=TRUE ); + void repaint( int x, int y, int w, int h, bool erase=TRUE ); + void repaint( const QRect &, bool erase=TRUE ); + +protected: + QtTableView( QWidget *parent=0, const char *name=0, WFlags f=0 ); + ~QtTableView(); + + int numRows() const; + virtual void setNumRows( int ); + int numCols() const; + virtual void setNumCols( int ); + + int topCell() const; + virtual void setTopCell( int row ); + int leftCell() const; + virtual void setLeftCell( int col ); + virtual void setTopLeftCell( int row, int col ); + + int xOffset() const; + virtual void setXOffset( int ); + int yOffset() const; + virtual void setYOffset( int ); + virtual void setOffset( int x, int y, bool updateScrBars = TRUE ); + + virtual int cellWidth( int col ); + virtual int cellHeight( int row ); + int cellWidth() const; + int cellHeight() const; + virtual void setCellWidth( int ); + virtual void setCellHeight( int ); + + virtual int totalWidth(); + virtual int totalHeight(); + + uint tableFlags() const; + bool testTableFlags( uint f ) const; + virtual void setTableFlags( uint f ); + void clearTableFlags( uint f = ~0 ); + + bool autoUpdate() const; + virtual void setAutoUpdate( bool ); + + void updateCell( int row, int column, bool erase=TRUE ); + + QRect cellUpdateRect() const; + QRect viewRect() const; + + int lastRowVisible() const; + int lastColVisible() const; + + bool rowIsVisible( int row ) const; + bool colIsVisible( int col ) const; + + QScrollBar *verticalScrollBar() const; + QScrollBar *horizontalScrollBar() const; + +private slots: + void horSbValue( int ); + void horSbSliding( int ); + void horSbSlidingDone(); + void verSbValue( int ); + void verSbSliding( int ); + void verSbSlidingDone(); + +protected: + virtual void paintCell( QPainter *, int row, int col ) = 0; + virtual void setupPainter( QPainter * ); + + void paintEvent( QPaintEvent * ); + void resizeEvent( QResizeEvent * ); + + int findRow( int yPos ) const; + int findCol( int xPos ) const; + + bool rowYPos( int row, int *yPos ) const; + bool colXPos( int col, int *xPos ) const; + + int maxXOffset(); + int maxYOffset(); + int maxColOffset(); + int maxRowOffset(); + + int minViewX() const; + int minViewY() const; + int maxViewX() const; + int maxViewY() const; + int viewWidth() const; + int viewHeight() const; + + void scroll( int xPixels, int yPixels ); + void updateScrollBars(); + void updateTableSize(); + +private: + void coverCornerSquare( bool ); + void snapToGrid( bool horizontal, bool vertical ); + virtual void setHorScrollBar( bool on, bool update = TRUE ); + virtual void setVerScrollBar( bool on, bool update = TRUE ); + void updateView(); + int findRawRow( int yPos, int *cellMaxY, int *cellMinY = 0, + bool goOutsideView = FALSE ) const; + int findRawCol( int xPos, int *cellMaxX, int *cellMinX = 0, + bool goOutsideView = FALSE ) const; + int maxColsVisible() const; + + void updateScrollBars( uint ); + void updateFrameSize(); + + void doAutoScrollBars(); + void showOrHideScrollBars(); + + int nRows; + int nCols; + int xOffs, yOffs; + int xCellOffs, yCellOffs; + short xCellDelta, yCellDelta; + short cellH, cellW; + + uint eraseInPaint : 1; + uint verSliding : 1; + uint verSnappingOff : 1; + uint horSliding : 1; + uint horSnappingOff : 1; + uint coveringCornerSquare : 1; + uint sbDirty : 8; + uint inSbUpdate : 1; + + uint tFlags; + QRect cellUpdateR; + + QScrollBar *vScrollBar; + QScrollBar *hScrollBar; + QCornerSquare *cornerSquare; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QtTableView( const QtTableView & ); + QtTableView &operator=( const QtTableView & ); +#endif +}; + + +const uint Tbl_vScrollBar = 0x00000001; +const uint Tbl_hScrollBar = 0x00000002; +const uint Tbl_autoVScrollBar = 0x00000004; +const uint Tbl_autoHScrollBar = 0x00000008; +const uint Tbl_autoScrollBars = 0x0000000C; + +const uint Tbl_clipCellPainting = 0x00000100; +const uint Tbl_cutCellsV = 0x00000200; +const uint Tbl_cutCellsH = 0x00000400; +const uint Tbl_cutCells = 0x00000600; + +const uint Tbl_scrollLastHCell = 0x00000800; +const uint Tbl_scrollLastVCell = 0x00001000; +const uint Tbl_scrollLastCell = 0x00001800; + +const uint Tbl_smoothHScrolling = 0x00002000; +const uint Tbl_smoothVScrolling = 0x00004000; +const uint Tbl_smoothScrolling = 0x00006000; + +const uint Tbl_snapToHGrid = 0x00008000; +const uint Tbl_snapToVGrid = 0x00010000; +const uint Tbl_snapToGrid = 0x00018000; + + +inline int QtTableView::numRows() const +{ return nRows; } + +inline int QtTableView::numCols() const +{ return nCols; } + +inline int QtTableView::topCell() const +{ return yCellOffs; } + +inline int QtTableView::leftCell() const +{ return xCellOffs; } + +inline int QtTableView::xOffset() const +{ return xOffs; } + +inline int QtTableView::yOffset() const +{ return yOffs; } + +inline int QtTableView::cellHeight() const +{ return cellH; } + +inline int QtTableView::cellWidth() const +{ return cellW; } + +inline uint QtTableView::tableFlags() const +{ return tFlags; } + +inline bool QtTableView::testTableFlags( uint f ) const +{ return (tFlags & f) != 0; } + +inline QRect QtTableView::cellUpdateRect() const +{ return cellUpdateR; } + +inline bool QtTableView::autoUpdate() const +{ return isUpdatesEnabled(); } + +inline void QtTableView::repaint( bool erase ) +{ repaint( 0, 0, width(), height(), erase ); } + +inline void QtTableView::repaint( const QRect &r, bool erase ) +{ repaint( r.x(), r.y(), r.width(), r.height(), erase ); } + +inline void QtTableView::updateScrollBars() +{ updateScrollBars( 0 ); } + + +#endif // QT_NO_QTTABLEVIEW + +#endif // QTTABLEVIEW_H |