1 /**********************************************************************
2 ** $Id: qttableview.cpp,v 1.2 2002/03/09 03:13:15 jwalz Exp $
3 **
4 ** Implementation of QtTableView class
5 **
6 ** Created : 941115
7 **
8 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
9 **
10 ** This file contains a class moved out of the Qt GUI Toolkit API. It
11 ** may be used, distributed and modified without limitation.
12 **
13 **********************************************************************/
14 
15 #include "qttableview.h"
16 #if QT_VERSION >= 300
17 #ifndef QT_NO_QTTABLEVIEW
18 #include <qscrollbar.h>
19 #include <qpainter.h>
20 #include <qdrawutil.h>
21 #include <limits.h>
22 
23 enum ScrollBarDirtyFlags {
24     verGeometry	  = 0x01,
25     verSteps	  = 0x02,
26     verRange	  = 0x04,
27     verValue	  = 0x08,
28     horGeometry	  = 0x10,
29     horSteps	  = 0x20,
30     horRange	  = 0x40,
31     horValue	  = 0x80,
32     verMask	  = 0x0F,
33     horMask	  = 0xF0
34 };
35 
36 
37 #define HSBEXT horizontalScrollBar()->sizeHint().height()
38 #define VSBEXT verticalScrollBar()->sizeHint().width()
39 
40 
41 class QCornerSquare : public QWidget		// internal class
42 {
43 public:
44     QCornerSquare( QWidget *, const char* = 0 );
45     void paintEvent( QPaintEvent * );
46 };
47 
QCornerSquare(QWidget * parent,const char * name)48 QCornerSquare::QCornerSquare( QWidget *parent, const char *name )
49 	: QWidget( parent, name )
50 {
51 }
52 
paintEvent(QPaintEvent *)53 void QCornerSquare::paintEvent( QPaintEvent * )
54 {
55 }
56 
57 
58 // NOT REVISED
59 /*!
60   \class QtTableView qttableview.h
61   \brief The QtTableView class provides an abstract base for tables.
62 
63   \obsolete
64 
65   A table view consists of a number of abstract cells organized in rows
66   and columns, and a visible part called a view. The cells are identified
67   with a row index and a column index. The top-left cell is in row 0,
68   column 0.
69 
70   The behavior of the widget can be finely tuned using
71   setTableFlags(); a typical subclass will consist of little more than a
72   call to setTableFlags(), some table content manipulation and an
73   implementation of paintCell().  Subclasses that need cells with
74   variable width or height must reimplement cellHeight() and/or
75   cellWidth(). Use updateTableSize() to tell QtTableView when the
76   width or height has changed.
77 
78   When you read this documentation, it is important to understand the
79   distinctions among the four pixel coordinate systems involved.
80 
81   \list 1
82   \i The \e cell coordinates.  (0,0) is the top-left corner of a cell.
83   Cell coordinates are used by functions such as paintCell().
84 
85   \i The \e table coordinates.  (0,0) is the top-left corner of the cell at
86   row 0 and column 0. These coordinates are absolute; that is, they are
87   independent of what part of the table is visible at the moment. They are
88   used by functions such as setXOffset() or maxYOffset().
89 
90   \i The \e widget coordinates. (0,0) is the top-left corner of the widget,
91   \e including the frame.  They are used by functions such as repaint().
92 
93   \i The \e view coordinates.  (0,0) is the top-left corner of the view, \e
94   excluding the frame.  This is the least-used coordinate system; it is used by
95   functions such as viewWidth().  \endlist
96 
97   It is rather unfortunate that we have to use four different
98   coordinate systems, but there was no alternative to provide a flexible and
99   powerful base class.
100 
101   Note: The row,column indices are always given in that order,
102   i.e., first the vertical (row), then the horizontal (column). This is
103   the opposite order of all pixel operations, which take first the
104   horizontal (x) and then the vertical (y).
105 
106   <img src=qtablevw-m.png> <img src=qtablevw-w.png>
107 
108   \warning the functions setNumRows(), setNumCols(), setCellHeight(),
109   setCellWidth(), setTableFlags() and clearTableFlags() may cause
110   virtual functions such as cellWidth() and cellHeight() to be called,
111   even if autoUpdate() is FALSE.  This may cause errors if relevant
112   state variables are not initialized.
113 
114   \warning Experience has shown that use of this widget tends to cause
115   more bugs than expected and our analysis indicates that the widget's
116   very flexibility is the problem.  If QScrollView or QListBox can
117   easily be made to do the job you need, we recommend subclassing
118   those widgets rather than QtTableView. In addition, QScrollView makes
119   it easy to have child widgets inside tables, which QtTableView
120   doesn't support at all.
121 
122   \sa QScrollView
123   \link guibooks.html#fowler GUI Design Handbook: Table\endlink
124 */
125 
126 
127 /*!
128   Constructs a table view.  The \a parent, \a name and \f arguments
129   are passed to the QFrame constructor.
130 
131   The \link setTableFlags() table flags\endlink are all cleared (set to 0).
132   Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll
133   bars and \c Tbl_clipCellPainting to get safe clipping.
134 
135   The \link setCellHeight() cell height\endlink and \link setCellWidth()
136   cell width\endlink are set to 0.
137 
138   Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed;
139   see QFrame::setFrameStyle().
140 
141   Note that the \a f argument is \e not \link setTableFlags() table
142   flags \endlink but rather \link QWidget::QWidget() widget
143   flags. \endlink
144 
145 */
146 
QtTableView(QWidget * parent,const char * name,WFlags f)147 QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f )
148     : QFrame( parent, name, f )
149 {
150     nRows		 = nCols      = 0;	// zero rows/cols
151     xCellOffs		 = yCellOffs  = 0;	// zero offset
152     xCellDelta		 = yCellDelta = 0;	// zero cell offset
153     xOffs		 = yOffs      = 0;	// zero total pixel offset
154     cellH		 = cellW      = 0;	// user defined cell size
155     tFlags		 = 0;
156     vScrollBar		 = hScrollBar = 0;	// no scroll bars
157     cornerSquare	 = 0;
158     sbDirty		 = 0;
159     eraseInPaint	 = FALSE;
160     verSliding		 = FALSE;
161     verSnappingOff	 = FALSE;
162     horSliding		 = FALSE;
163     horSnappingOff	 = FALSE;
164     coveringCornerSquare = FALSE;
165     inSbUpdate		 = FALSE;
166 }
167 
168 /*!
169   Destroys the table view.
170 */
171 
~QtTableView()172 QtTableView::~QtTableView()
173 {
174     delete vScrollBar;
175     delete hScrollBar;
176     delete cornerSquare;
177 }
178 
179 
180 /*!
181   \internal
182   Reimplements QWidget::setBackgroundColor() for binary compatibility.
183   \sa setPalette()
184 */
185 
setBackgroundColor(const QColor & c)186 void QtTableView::setBackgroundColor( const QColor &c )
187 {
188     QWidget::setBackgroundColor( c );
189 }
190 
191 /*!\reimp
192 */
193 
setPalette(const QPalette & p)194 void QtTableView::setPalette( const QPalette &p )
195 {
196     QWidget::setPalette( p );
197 }
198 
199 /*!\reimp
200 */
201 
show()202 void QtTableView::show()
203 {
204     showOrHideScrollBars();
205     QWidget::show();
206 }
207 
208 
209 /*!
210   \overload void QtTableView::repaint( bool erase )
211   Repaints the entire view.
212 */
213 
214 /*!
215   Repaints the table view directly by calling paintEvent() directly
216   unless updates are disabled.
217 
218   Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a
219   (x,y) are in \e widget coordinates.
220 
221   If \a w is negative, it is replaced with <code>width() - x</code>.
222   If \a h is negative, it is replaced with <code>height() - y</code>.
223 
224   Doing a repaint() usually is faster than doing an update(), but
225   calling update() many times in a row will generate a single paint
226   event.
227 
228   At present, QtTableView is the only widget that reimplements \link
229   QWidget::repaint() repaint()\endlink.	 It does this because by
230   clearing and then repainting one cell at at time, it can make the
231   screen flicker less than it would otherwise.  */
232 
repaint(int x,int y,int w,int h,bool erase)233 void QtTableView::repaint( int x, int y, int w, int h, bool erase )
234 {
235     if ( !isVisible() || testWState(WState_BlockUpdates) )
236 	return;
237     if ( w < 0 )
238 	w = width()  - x;
239     if ( h < 0 )
240 	h = height() - y;
241     QRect r( x, y, w, h );
242     if ( r.isEmpty() )
243 	return; // nothing to do
244     QPaintEvent e( r );
245     if ( erase && backgroundMode() != NoBackground )
246 	eraseInPaint = TRUE;			// erase when painting
247     paintEvent( &e );
248     eraseInPaint = FALSE;
249 }
250 
251 /*!
252   \overload void QtTableView::repaint( const QRect &r, bool erase )
253   Replaints rectangle \a r. If \a erase is TRUE draws the background
254   using the palette's background.
255 */
256 
257 
258 /*!
259   \fn int QtTableView::numRows() const
260   Returns the number of rows in the table.
261   \sa numCols(), setNumRows()
262 */
263 
264 /*!
265   Sets the number of rows of the table to \a rows (must be non-negative).
266   Does not change topCell().
267 
268   The table repaints itself automatically if autoUpdate() is set.
269 
270   \sa numCols(), setNumCols(), numRows()
271 */
272 
setNumRows(int rows)273 void QtTableView::setNumRows( int rows )
274 {
275     if ( rows < 0 ) {
276 #if defined(QT_CHECK_RANGE)
277 	qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.",
278 		 name( "unnamed" ), rows );
279 #endif
280 	return;
281     }
282     if ( nRows == rows )
283 	return;
284 
285     if ( autoUpdate() && isVisible() ) {
286 	int oldLastVisible = lastRowVisible();
287 	int oldTopCell = topCell();
288 	nRows = rows;
289 	if ( autoUpdate() && isVisible() &&
290 	     ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) )
291 		repaint( oldTopCell != topCell() );
292     } else {
293 	// Be more careful - if destructing, bad things might happen.
294 	nRows = rows;
295     }
296     updateScrollBars( verRange );
297     updateFrameSize();
298 }
299 
300 /*!
301   \fn int QtTableView::numCols() const
302   Returns the number of columns in the table.
303   \sa numRows(), setNumCols()
304 */
305 
306 /*!
307   Sets the number of columns of the table to \a cols (must be non-negative).
308   Does not change leftCell().
309 
310   The table repaints itself automatically if autoUpdate() is set.
311 
312   \sa numCols(), numRows(), setNumRows()
313 */
314 
setNumCols(int cols)315 void QtTableView::setNumCols( int cols )
316 {
317     if ( cols < 0 ) {
318 #if defined(QT_CHECK_RANGE)
319 	qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.",
320 		 name( "unnamed" ), cols );
321 #endif
322 	return;
323     }
324     if ( nCols == cols )
325 	return;
326     int oldCols = nCols;
327     nCols = cols;
328     if ( autoUpdate() && isVisible() ) {
329 	int maxCol = lastColVisible();
330 	if ( maxCol >= oldCols || maxCol >= nCols )
331 	    repaint();
332     }
333     updateScrollBars( horRange );
334     updateFrameSize();
335 }
336 
337 
338 /*!
339   \fn int QtTableView::topCell() const
340   Returns the index of the first row in the table that is visible in
341   the view.  The index of the first row is 0.
342   \sa leftCell(), setTopCell()
343 */
344 
345 /*!
346   Scrolls the table so that \a row becomes the top row.
347   The index of the very first row is 0.
348   \sa setYOffset(), setTopLeftCell(), setLeftCell()
349 */
350 
setTopCell(int row)351 void QtTableView::setTopCell( int row )
352 {
353     setTopLeftCell( row, -1 );
354     return;
355 }
356 
357 /*!
358   \fn int QtTableView::leftCell() const
359   Returns the index of the first column in the table that is visible in
360   the view.  The index of the very leftmost column is 0.
361   \sa topCell(), setLeftCell()
362 */
363 
364 /*!
365   Scrolls the table so that \a col becomes the leftmost
366   column.  The index of the leftmost column is 0.
367   \sa setXOffset(), setTopLeftCell(), setTopCell()
368 */
369 
setLeftCell(int col)370 void QtTableView::setLeftCell( int col )
371 {
372     setTopLeftCell( -1, col );
373     return;
374 }
375 
376 /*!
377   Scrolls the table so that the cell at row \a row and colum \a
378   col becomes the top-left cell in the view.  The cell at the extreme
379   top left of the table is at position (0,0).
380   \sa setLeftCell(), setTopCell(), setOffset()
381 */
382 
setTopLeftCell(int row,int col)383 void QtTableView::setTopLeftCell( int row, int col )
384 {
385     int newX = xOffs;
386     int newY = yOffs;
387 
388     if ( col >= 0 ) {
389 	if ( cellW ) {
390 	    newX = col*cellW;
391 	    if ( newX > maxXOffset() )
392 		newX = maxXOffset();
393 	} else {
394 	    newX = 0;
395 	    while ( col )
396 		newX += cellWidth( --col );   // optimize using current! ###
397 	}
398     }
399     if ( row >= 0 ) {
400 	if ( cellH ) {
401 	    newY = row*cellH;
402 	    if ( newY > maxYOffset() )
403 		newY = maxYOffset();
404 	} else {
405 	    newY = 0;
406 	    while ( row )
407 		newY += cellHeight( --row );   // optimize using current! ###
408 	}
409     }
410     setOffset( newX, newY );
411 }
412 
413 
414 /*!
415   \fn int QtTableView::xOffset() const
416 
417   Returns the x coordinate in \e table coordinates of the pixel that is
418   currently on the left edge of the view.
419 
420   \sa setXOffset(), yOffset(), leftCell() */
421 
422 /*!
423   Scrolls the table so that \a x becomes the leftmost pixel in the view.
424   The \a x parameter is in \e table coordinates.
425 
426   The interaction with \link setTableFlags() Tbl_snapToHGrid
427   \endlink is tricky.
428 
429   \sa xOffset(), setYOffset(), setOffset(), setLeftCell()
430 */
431 
setXOffset(int x)432 void QtTableView::setXOffset( int x )
433 {
434     setOffset( x, yOffset() );
435 }
436 
437 /*!
438   \fn int QtTableView::yOffset() const
439 
440   Returns the y coordinate in \e table coordinates of the pixel that is
441   currently on the top edge of the view.
442 
443   \sa setYOffset(), xOffset(), topCell()
444 */
445 
446 
447 /*!
448   Scrolls the table so that \a y becomes the top pixel in the view.
449   The \a y parameter is in \e table coordinates.
450 
451   The interaction with \link setTableFlags() Tbl_snapToVGrid
452   \endlink is tricky.
453 
454   \sa yOffset(), setXOffset(), setOffset(), setTopCell()
455 */
456 
setYOffset(int y)457 void QtTableView::setYOffset( int y )
458 {
459     setOffset( xOffset(), y );
460 }
461 
462 /*!
463   Scrolls the table so that \a (x,y) becomes the top-left pixel
464   in the view. Parameters \a (x,y) are in \e table coordinates.
465 
466   The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink
467   is tricky.  If \a updateScrBars is TRUE, the scroll bars are
468   updated.
469 
470   \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell()
471 */
472 
setOffset(int x,int y,bool updateScrBars)473 void QtTableView::setOffset( int x, int y, bool updateScrBars )
474 {
475     if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) &&
476 	 (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) &&
477 	 (x == xOffs && y == yOffs) )
478 	return;
479 
480     if ( x < 0 )
481 	x = 0;
482     if ( y < 0 )
483 	y = 0;
484 
485     if ( cellW ) {
486 	if ( x > maxXOffset() )
487 	    x = maxXOffset();
488 	xCellOffs = x / cellW;
489 	if ( !testTableFlags(Tbl_snapToHGrid) ) {
490 	    xCellDelta	= (short)(x % cellW);
491 	} else {
492 	    x		= xCellOffs*cellW;
493 	    xCellDelta	= 0;
494 	}
495     } else {
496 	int xn=0, xcd=0, col = 0;
497 	while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) {
498 	    xn += xcd;
499 	    col++;
500 	}
501 	xCellOffs = col;
502 	if ( testTableFlags(Tbl_snapToHGrid) ) {
503 	    xCellDelta = 0;
504 	    x = xn;
505 	} else {
506 	    xCellDelta = (short)(x-xn);
507 	}
508     }
509     if ( cellH ) {
510 	if ( y > maxYOffset() )
511 	    y = maxYOffset();
512 	yCellOffs = y / cellH;
513 	if ( !testTableFlags(Tbl_snapToVGrid) ) {
514 	    yCellDelta	= (short)(y % cellH);
515 	} else {
516 	    y		= yCellOffs*cellH;
517 	    yCellDelta	= 0;
518 	}
519     } else {
520 	int yn=0, yrd=0, row=0;
521 	while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) {
522 	    yn += yrd;
523 	    row++;
524 	}
525 	yCellOffs = row;
526 	if ( testTableFlags(Tbl_snapToVGrid) ) {
527 	    yCellDelta = 0;
528 	    y = yn;
529 	} else {
530 	    yCellDelta = (short)(y-yn);
531 	}
532     }
533     int dx = (x - xOffs);
534     int dy = (y - yOffs);
535     xOffs = x;
536     yOffs = y;
537     if ( autoUpdate() && isVisible() )
538 	scroll( dx, dy );
539     if ( updateScrBars )
540 	updateScrollBars( verValue | horValue );
541 }
542 
543 
544 /*!
545   \overload int QtTableView::cellWidth() const
546 
547   Returns the column width in pixels.	Returns 0 if the columns have
548   variable widths.
549 
550   \sa setCellWidth(), cellHeight()
551 */
552 
553 /*!
554   Returns the width of column \a col in pixels.
555 
556   This function is virtual and must be reimplemented by subclasses that
557   have variable cell widths. Note that if the total table width
558   changes, updateTableSize() must be called.
559 
560   \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize()
561 */
562 
cellWidth(int)563 int QtTableView::cellWidth( int )
564 {
565     return cellW;
566 }
567 
568 
569 /*!
570   Sets the width in pixels of the table cells to \a cellWidth.
571 
572   Setting it to 0 means that the column width is variable.  When
573   set to 0 (this is the default) QtTableView calls the virtual function
574   cellWidth() to get the width.
575 
576   \sa cellWidth(), setCellHeight(), totalWidth(), numCols()
577 */
578 
setCellWidth(int cellWidth)579 void QtTableView::setCellWidth( int cellWidth )
580 {
581     if ( cellW == cellWidth )
582 	return;
583 #if defined(QT_CHECK_RANGE)
584     if ( cellWidth < 0 || cellWidth > SHRT_MAX ) {
585 	qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)",
586 		 name( "unnamed" ), cellWidth );
587 	return;
588     }
589 #endif
590     cellW = (short)cellWidth;
591 
592     updateScrollBars( horSteps | horRange );
593     if ( autoUpdate() && isVisible() )
594 	repaint();
595 
596 }
597 
598 /*!
599   \overload int QtTableView::cellHeight() const
600 
601   Returns the row height, in pixels.  Returns 0 if the rows have
602   variable heights.
603 
604   \sa setCellHeight(), cellWidth()
605 */
606 
607 
608 /*!
609   Returns the height of row \a row in pixels.
610 
611   This function is virtual and must be reimplemented by subclasses that
612   have variable cell heights.  Note that if the total table height
613   changes, updateTableSize() must be called.
614 
615   \sa setCellHeight(), cellWidth(), totalHeight()
616 */
617 
cellHeight(int)618 int QtTableView::cellHeight( int )
619 {
620     return cellH;
621 }
622 
623 /*!
624   Sets the height in pixels of the table cells to \a cellHeight.
625 
626   Setting it to 0 means that the row height is variable.  When set
627   to 0 (this is the default), QtTableView calls the virtual function
628   cellHeight() to get the height.
629 
630   \sa cellHeight(), setCellWidth(), totalHeight(), numRows()
631 */
632 
setCellHeight(int cellHeight)633 void QtTableView::setCellHeight( int cellHeight )
634 {
635     if ( cellH == cellHeight )
636 	return;
637 #if defined(QT_CHECK_RANGE)
638     if ( cellHeight < 0 || cellHeight > SHRT_MAX ) {
639 	qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)",
640 		 name( "unnamed" ), cellHeight );
641 	return;
642     }
643 #endif
644     cellH = (short)cellHeight;
645     if ( autoUpdate() && isVisible() )
646 	repaint();
647     updateScrollBars( verSteps | verRange );
648 }
649 
650 
651 /*!
652   Returns the total width of the table in pixels.
653 
654   This function is virtual and should be reimplemented by subclasses that
655   have variable cell widths and a non-trivial cellWidth() function, or a
656   large number of columns in the table.
657 
658   The default implementation may be slow for very wide tables.
659 
660   \sa cellWidth(), totalHeight() */
661 
totalWidth()662 int QtTableView::totalWidth()
663 {
664     if ( cellW ) {
665 	return cellW*nCols;
666     } else {
667 	int tw = 0;
668 	for( int i = 0 ; i < nCols ; i++ )
669 	    tw += cellWidth( i );
670 	return tw;
671     }
672 }
673 
674 /*!
675   Returns the total height of the table in pixels.
676 
677   This function is virtual and should be reimplemented by subclasses that
678   have variable cell heights and a non-trivial cellHeight() function, or a
679   large number of rows in the table.
680 
681   The default implementation may be slow for very tall tables.
682 
683   \sa cellHeight(), totalWidth()
684 */
685 
totalHeight()686 int QtTableView::totalHeight()
687 {
688     if ( cellH ) {
689 	return cellH*nRows;
690     } else {
691 	int th = 0;
692 	for( int i = 0 ; i < nRows ; i++ )
693 	    th += cellHeight( i );
694 	return th;
695     }
696 }
697 
698 
699 /*!
700   \fn uint QtTableView::tableFlags() const
701 
702   Returns the union of the table flags that are currently set.
703 
704   \sa setTableFlags(), clearTableFlags(), testTableFlags()
705 */
706 
707 /*!
708   \fn bool QtTableView::testTableFlags( uint f ) const
709 
710   Returns TRUE if any of the table flags in \a f are currently set,
711   otherwise FALSE.
712 
713   \sa setTableFlags(), clearTableFlags(), tableFlags()
714 */
715 
716 /*!
717   Sets the table flags to \a f.
718 
719   If a flag setting changes the appearance of the table, the table is
720   repainted if - and only if - autoUpdate() is TRUE.
721 
722   The table flags are mostly single bits, though there are some multibit
723   flags for convenience. Here is a complete list:
724 
725   <dl compact>
726   <dt> Tbl_vScrollBar <dd> - The table has a vertical scroll bar.
727   <dt> Tbl_hScrollBar <dd> - The table has a horizontal scroll bar.
728   <dt> Tbl_autoVScrollBar <dd> - The table has a vertical scroll bar if
729   - and only if - the table is taller than the view.
730   <dt> Tbl_autoHScrollBar <dd> The table has a horizontal scroll bar if
731   - and only if - the table is wider than the view.
732   <dt> Tbl_autoScrollBars <dd> - The union of the previous two flags.
733   <dt> Tbl_clipCellPainting <dd> - The table uses QPainter::setClipRect() to
734   make sure that paintCell() will not draw outside the cell
735   boundaries.
736   <dt> Tbl_cutCellsV <dd> - The table will never show part of a
737   cell at the bottom of the table; if there is not space for all of
738   a cell, the space is left blank.
739   <dt> Tbl_cutCellsH <dd> - The table will never show part of a
740   cell at the right side of the table; if there is not space for all of
741   a cell, the space is left blank.
742   <dt> Tbl_cutCells <dd> - The union of the previous two flags.
743   <dt> Tbl_scrollLastHCell <dd> - When the user scrolls horizontally,
744   let him/her scroll the last cell left until it is at the left
745   edge of the view.  If this flag is not set, the user can only scroll
746   to the point where the last cell is completely visible.
747   <dt> Tbl_scrollLastVCell <dd> - When the user scrolls vertically, let
748   him/her scroll the last cell up until it is at the top edge of
749   the view.  If this flag is not set, the user can only scroll to the
750   point where the last cell is completely visible.
751   <dt> Tbl_scrollLastCell <dd> - The union of the previous two flags.
752   <dt> Tbl_smoothHScrolling <dd> - The table scrolls as smoothly as
753   possible when the user scrolls horizontally. When this flag is not
754   set, scrolling is done one cell at a time.
755   <dt> Tbl_smoothVScrolling <dd> - The table scrolls as smoothly as
756   possible when scrolling vertically. When this flag is not set,
757   scrolling is done one cell at a time.
758   <dt> Tbl_smoothScrolling <dd> - The union of the previous two flags.
759   <dt> Tbl_snapToHGrid <dd> - Except when the user is actually scrolling,
760   the leftmost column shown snaps to the leftmost edge of the view.
761   <dt> Tbl_snapToVGrid <dd> - Except when the user is actually
762   scrolling, the top row snaps to the top edge of the view.
763   <dt> Tbl_snapToGrid <dd> - The union of the previous two flags.
764   </dl>
765 
766   You can specify more than one flag at a time using bitwise OR.
767 
768   Example:
769   \code
770     setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars );
771   \endcode
772 
773   \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and
774   Tbl_cutCellsV) may cause painting problems when scrollbars are
775   enabled. Do not combine cutCells and scrollbars.
776 
777 
778   \sa clearTableFlags(), testTableFlags(), tableFlags()
779 */
780 
setTableFlags(uint f)781 void QtTableView::setTableFlags( uint f )
782 {
783     f = (f ^ tFlags) & f;			// clear flags already set
784     tFlags |= f;
785 
786     bool updateOn = autoUpdate();
787     setAutoUpdate( FALSE );
788 
789     uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
790 
791     if ( f & Tbl_vScrollBar ) {
792 	setVerScrollBar( TRUE );
793     }
794     if ( f & Tbl_hScrollBar ) {
795 	setHorScrollBar( TRUE );
796     }
797     if ( f & Tbl_autoVScrollBar ) {
798 	updateScrollBars( verRange );
799     }
800     if ( f & Tbl_autoHScrollBar ) {
801 	updateScrollBars( horRange );
802     }
803     if ( f & Tbl_scrollLastHCell ) {
804 	updateScrollBars( horRange );
805     }
806     if ( f & Tbl_scrollLastVCell ) {
807 	updateScrollBars( verRange );
808     }
809     if ( f & Tbl_snapToHGrid ) {
810 	updateScrollBars( horRange );
811     }
812     if ( f & Tbl_snapToVGrid ) {
813 	updateScrollBars( verRange );
814     }
815     if ( f & Tbl_snapToGrid ) {			// Note: checks for 2 flags
816 	if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll?
817 	     (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) {
818 	    snapToGrid( (f & Tbl_snapToHGrid) != 0,	// do snapping
819 			(f & Tbl_snapToVGrid) != 0 );
820 	    repaintMask |= Tbl_snapToGrid;	// repaint table
821 	}
822     }
823 
824     if ( updateOn ) {
825 	setAutoUpdate( TRUE );
826 	updateScrollBars();
827 	if ( isVisible() && (f & repaintMask) )
828 	    repaint();
829     }
830 
831 }
832 
833 /*!
834   Clears the \link setTableFlags() table flags\endlink that are set
835   in \a f.
836 
837   Example (clears a single flag):
838   \code
839     clearTableFlags( Tbl_snapToGrid );
840   \endcode
841 
842   The default argument clears all flags.
843 
844   \sa setTableFlags(), testTableFlags(), tableFlags()
845 */
846 
clearTableFlags(uint f)847 void QtTableView::clearTableFlags( uint f )
848 {
849     f = (f ^ ~tFlags) & f;		// clear flags that are already 0
850     tFlags &= ~f;
851 
852     bool updateOn = autoUpdate();
853     setAutoUpdate( FALSE );
854 
855     uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
856 
857     if ( f & Tbl_vScrollBar ) {
858 	setVerScrollBar( FALSE );
859     }
860     if ( f & Tbl_hScrollBar ) {
861 	setHorScrollBar( FALSE );
862     }
863     if ( f & Tbl_scrollLastHCell ) {
864 	int maxX = maxXOffset();
865 	if ( xOffs > maxX ) {
866 	    setOffset( maxX, yOffs );
867 	    repaintMask |= Tbl_scrollLastHCell;
868 	}
869 	updateScrollBars( horRange );
870     }
871     if ( f & Tbl_scrollLastVCell ) {
872 	int maxY = maxYOffset();
873 	if ( yOffs > maxY ) {
874 	    setOffset( xOffs, maxY );
875 	    repaintMask |= Tbl_scrollLastVCell;
876 	}
877 	updateScrollBars( verRange );
878     }
879     if ( f & Tbl_smoothScrolling ) {	      // Note: checks for 2 flags
880 	if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll?
881 	    (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) {
882 	    snapToGrid( (f & Tbl_smoothHScrolling) != 0,      // do snapping
883 			(f & Tbl_smoothVScrolling) != 0 );
884 	    repaintMask |= Tbl_smoothScrolling;		     // repaint table
885 	}
886     }
887     if ( f & Tbl_snapToHGrid ) {
888 	updateScrollBars( horRange );
889     }
890     if ( f & Tbl_snapToVGrid ) {
891 	updateScrollBars( verRange );
892     }
893     if ( updateOn ) {
894 	setAutoUpdate( TRUE );
895 	updateScrollBars();	     // returns immediately if nothing to do
896 	if ( isVisible() && (f & repaintMask) )
897 	    repaint();
898     }
899 
900 }
901 
902 
903 /*!
904   \fn bool QtTableView::autoUpdate() const
905 
906   Returns TRUE if the view updates itself automatically whenever it
907   is changed in some way.
908 
909   \sa setAutoUpdate()
910 */
911 
912 /*!
913   Sets the auto-update option of the table view to \a enable.
914 
915   If \a enable is TRUE (this is the default), the view updates itself
916   automatically whenever it has changed in some way (for example, when a
917   \link setTableFlags() flag\endlink is changed).
918 
919   If \a enable is FALSE, the view does NOT repaint itself or update
920   its internal state variables when it is changed.  This can be
921   useful to avoid flicker during large changes and is singularly
922   useless otherwise. Disable auto-update, do the changes, re-enable
923   auto-update and call repaint().
924 
925   \warning Do not leave the view in this state for a long time
926   (i.e., between events). If, for example, the user interacts with the
927   view when auto-update is off, strange things can happen.
928 
929   Setting auto-update to TRUE does not repaint the view; you must call
930   repaint() to do this.
931 
932   \sa autoUpdate(), repaint()
933 */
934 
setAutoUpdate(bool enable)935 void QtTableView::setAutoUpdate( bool enable )
936 {
937     if ( isUpdatesEnabled() == enable )
938 	return;
939     setUpdatesEnabled( enable );
940     if ( enable ) {
941 	showOrHideScrollBars();
942 	updateScrollBars();
943     }
944 }
945 
946 
947 /*!
948   Repaints the cell at row \a row, column \a col if it is inside the view.
949 
950   If \a erase is TRUE, the relevant part of the view is cleared to the
951   background color/pixmap before the contents are repainted.
952 
953   \sa isVisible()
954 */
955 
updateCell(int row,int col,bool erase)956 void QtTableView::updateCell( int row, int col, bool erase )
957 {
958     int xPos, yPos;
959     if ( !colXPos( col, &xPos ) )
960 	return;
961     if ( !rowYPos( row, &yPos ) )
962 	return;
963     QRect uR = QRect( xPos, yPos,
964 		      cellW ? cellW : cellWidth(col),
965 		      cellH ? cellH : cellHeight(row) );
966     repaint( uR.intersect(viewRect()), erase );
967 }
968 
969 
970 /*!
971   \fn QRect QtTableView::cellUpdateRect() const
972 
973   This function should be called only from the paintCell() function in
974   subclasses. It returns the portion of a cell that actually needs to be
975   updated in \e cell coordinates. This is useful only for non-trivial
976   paintCell().
977 
978 */
979 
980 /*!
981   Returns the rectangle that is the actual table, excluding any
982   frame, in \e widget coordinates.
983 */
984 
viewRect() const985 QRect QtTableView::viewRect() const
986 {
987     return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() );
988 }
989 
990 
991 /*!
992   Returns the index of the last (bottom) row in the view.
993   The index of the first row is 0.
994 
995   If no rows are visible it returns -1.	 This can happen if the
996   view is too small for the first row and Tbl_cutCellsV is set.
997 
998   \sa lastColVisible()
999 */
1000 
lastRowVisible() const1001 int QtTableView::lastRowVisible() const
1002 {
1003     int cellMaxY;
1004     int row = findRawRow( maxViewY(), &cellMaxY );
1005     if ( row == -1 || row >= nRows ) {		// maxViewY() past end?
1006 	row = nRows - 1;			// yes: return last row
1007     } else {
1008 	if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) {
1009 	    if ( row == yCellOffs )		// cut by right margin?
1010 		return -1;			// yes, nothing in the view
1011 	    else
1012 	       row = row - 1;			// cut by margin, one back
1013 	}
1014     }
1015     return row;
1016 }
1017 
1018 /*!
1019   Returns the index of the last (right) column in the view.
1020   The index of the first column is 0.
1021 
1022   If no columns are visible it returns -1.  This can happen if the
1023   view is too narrow for the first column and Tbl_cutCellsH is set.
1024 
1025   \sa lastRowVisible()
1026 */
1027 
lastColVisible() const1028 int QtTableView::lastColVisible() const
1029 {
1030     int cellMaxX;
1031     int col = findRawCol( maxViewX(), &cellMaxX );
1032     if ( col == -1 || col >= nCols ) {		// maxViewX() past end?
1033 	col = nCols - 1;			// yes: return last col
1034     } else {
1035 	if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) {
1036 	    if ( col == xCellOffs )		// cut by bottom margin?
1037 		return -1;			// yes, nothing in the view
1038 	    else
1039 	       col = col - 1;			// cell by margin, one back
1040 	}
1041     }
1042     return col;
1043 }
1044 
1045 /*!
1046   Returns TRUE if \a row is at least partially visible.
1047   \sa colIsVisible()
1048 */
1049 
rowIsVisible(int row) const1050 bool QtTableView::rowIsVisible( int row ) const
1051 {
1052     return rowYPos( row, 0 );
1053 }
1054 
1055 /*!
1056   Returns TRUE if \a col is at least partially visible.
1057   \sa rowIsVisible()
1058 */
1059 
colIsVisible(int col) const1060 bool QtTableView::colIsVisible( int col ) const
1061 {
1062     return colXPos( col, 0 );
1063 }
1064 
1065 
1066 /*!
1067   \internal
1068   Called when both scroll bars are active at the same time. Covers the
1069   bottom left corner between the two scroll bars with an empty widget.
1070 */
1071 
coverCornerSquare(bool enable)1072 void QtTableView::coverCornerSquare( bool enable )
1073 {
1074     coveringCornerSquare = enable;
1075     if ( !cornerSquare && enable ) {
1076 	cornerSquare = new QCornerSquare( this );
1077 	Q_CHECK_PTR( cornerSquare );
1078 	cornerSquare->setGeometry( maxViewX() + frameWidth() + 1,
1079 				   maxViewY() + frameWidth() + 1,
1080                                    VSBEXT,
1081                                  HSBEXT);
1082     }
1083     if ( autoUpdate() && cornerSquare ) {
1084 	if ( enable )
1085 	    cornerSquare->show();
1086 	else
1087 	    cornerSquare->hide();
1088     }
1089 }
1090 
1091 
1092 /*!
1093   \internal
1094   Scroll the view to a position such that:
1095 
1096   If \a horizontal is TRUE, the leftmost column shown fits snugly
1097   with the left edge of the view.
1098 
1099   If \a vertical is TRUE, the top row shown fits snugly with the top
1100   of the view.
1101 
1102   You can achieve the same effect automatically by setting any of the
1103   \link setTableFlags() Tbl_snapTo*Grid \endlink table flags.
1104 */
1105 
snapToGrid(bool horizontal,bool vertical)1106 void QtTableView::snapToGrid( bool horizontal, bool vertical )
1107 {
1108     int newXCell = -1;
1109     int newYCell = -1;
1110     if ( horizontal && xCellDelta != 0 ) {
1111 	int w = cellW ? cellW : cellWidth( xCellOffs );
1112 	if ( xCellDelta >= w/2 )
1113 	    newXCell = xCellOffs + 1;
1114 	else
1115 	    newXCell = xCellOffs;
1116     }
1117     if ( vertical && yCellDelta != 0 ) {
1118 	int h = cellH ? cellH : cellHeight( yCellOffs );
1119 	if ( yCellDelta >= h/2 )
1120 	    newYCell = yCellOffs + 1;
1121 	else
1122 	    newYCell = yCellOffs;
1123     }
1124     setTopLeftCell( newYCell, newXCell );  //row,column
1125 }
1126 
1127 /*!
1128   \internal
1129   This internal slot is connected to the horizontal scroll bar's
1130   QScrollBar::valueChanged() signal.
1131 
1132   Moves the table horizontally to offset \a val without updating the
1133   scroll bar.
1134 */
1135 
horSbValue(int val)1136 void QtTableView::horSbValue( int val )
1137 {
1138     if ( horSliding ) {
1139 	horSliding = FALSE;
1140 	if ( horSnappingOff ) {
1141 	    horSnappingOff = FALSE;
1142 	    tFlags |= Tbl_snapToHGrid;
1143 	}
1144     }
1145     setOffset( val, yOffs, FALSE );
1146 }
1147 
1148 /*!
1149   \internal
1150   This internal slot is connected to the horizontal scroll bar's
1151   QScrollBar::sliderMoved() signal.
1152 
1153   Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set.
1154 */
1155 
horSbSliding(int val)1156 void QtTableView::horSbSliding( int val )
1157 {
1158     if ( testTableFlags(Tbl_snapToHGrid) &&
1159 	 testTableFlags(Tbl_smoothHScrolling) ) {
1160 	tFlags &= ~Tbl_snapToHGrid;	// turn off snapping while sliding
1161 	setOffset( val, yOffs, FALSE );
1162 	tFlags |= Tbl_snapToHGrid;	// turn on snapping again
1163     } else {
1164 	setOffset( val, yOffs, FALSE );
1165     }
1166 }
1167 
1168 /*!
1169   \internal
1170   This internal slot is connected to the horizontal scroll bar's
1171   QScrollBar::sliderReleased() signal.
1172 */
1173 
horSbSlidingDone()1174 void QtTableView::horSbSlidingDone( )
1175 {
1176     if ( testTableFlags(Tbl_snapToHGrid) &&
1177 	 testTableFlags(Tbl_smoothHScrolling) )
1178 	snapToGrid( TRUE, FALSE );
1179 }
1180 
1181 /*!
1182   \internal
1183   This internal slot is connected to the vertical scroll bar's
1184   QScrollBar::valueChanged() signal.
1185 
1186   Moves the table vertically to offset \a val without updating the
1187   scroll bar.
1188 */
1189 
verSbValue(int val)1190 void QtTableView::verSbValue( int val )
1191 {
1192     if ( verSliding ) {
1193 	verSliding = FALSE;
1194 	if ( verSnappingOff ) {
1195 	    verSnappingOff = FALSE;
1196 	    tFlags |= Tbl_snapToVGrid;
1197 	}
1198     }
1199     setOffset( xOffs, val, FALSE );
1200 }
1201 
1202 /*!
1203   \internal
1204   This internal slot is connected to the vertical scroll bar's
1205   QScrollBar::sliderMoved() signal.
1206 
1207   Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set.
1208 */
1209 
verSbSliding(int val)1210 void QtTableView::verSbSliding( int val )
1211 {
1212     if ( testTableFlags(Tbl_snapToVGrid) &&
1213 	 testTableFlags(Tbl_smoothVScrolling) ) {
1214 	tFlags &= ~Tbl_snapToVGrid;	// turn off snapping while sliding
1215 	setOffset( xOffs, val, FALSE );
1216 	tFlags |= Tbl_snapToVGrid;	// turn on snapping again
1217     } else {
1218 	setOffset( xOffs, val, FALSE );
1219     }
1220 }
1221 
1222 /*!
1223   \internal
1224   This internal slot is connected to the vertical scroll bar's
1225   QScrollBar::sliderReleased() signal.
1226 */
1227 
verSbSlidingDone()1228 void QtTableView::verSbSlidingDone( )
1229 {
1230     if ( testTableFlags(Tbl_snapToVGrid) &&
1231 	 testTableFlags(Tbl_smoothVScrolling) )
1232 	snapToGrid( FALSE, TRUE );
1233 }
1234 
1235 
1236 /*!
1237   This virtual function is called before painting of table cells
1238   is started. It can be reimplemented by subclasses that want to
1239   to set up the painter in a special way and that do not want to
1240   do so for each cell.
1241 */
1242 
setupPainter(QPainter *)1243 void QtTableView::setupPainter( QPainter * )
1244 {
1245 }
1246 
1247 /*!
1248   \fn void QtTableView::paintCell( QPainter *p, int row, int col )
1249 
1250   This pure virtual function is called to paint the single cell at \a
1251   (row,col) using \a p, which is open when paintCell() is called and
1252   must remain open.
1253 
1254   The coordinate system is \link QPainter::translate() translated \endlink
1255   so that the origin is at the top-left corner of the cell to be
1256   painted, i.e. \e cell coordinates.  Do not scale or shear the coordinate
1257   system (or if you do, restore the transformation matrix before you
1258   return).
1259 
1260   The painter is not clipped by default and for maximum efficiency. For safety,
1261   call setTableFlags(Tbl_clipCellPainting) to enable clipping.
1262 
1263   \sa paintEvent(), setTableFlags() */
1264 
1265 
1266 /*!
1267   Handles paint events, \a e, for the table view.
1268 
1269   Calls paintCell() for the cells that needs to be repainted.
1270 */
1271 
paintEvent(QPaintEvent * e)1272 void QtTableView::paintEvent( QPaintEvent *e )
1273 {
1274     QRect updateR = e->rect();			// update rectangle
1275     if ( sbDirty ) {
1276 	bool e = eraseInPaint;
1277 	updateScrollBars();
1278 	eraseInPaint = e;
1279     }
1280 
1281     QPainter paint( this );
1282 
1283     if ( !contentsRect().contains( updateR, TRUE  ) ) {// update frame ?
1284 	drawFrame( &paint );
1285 	if ( updateR.left() < frameWidth() ) 		//###
1286 	    updateR.setLeft( frameWidth() );
1287 	if ( updateR.top() < frameWidth() )
1288 	    updateR.setTop( frameWidth() );
1289     }
1290 
1291     int maxWX = maxViewX();
1292     int maxWY = maxViewY();
1293     if ( updateR.right() > maxWX )
1294 	updateR.setRight( maxWX );
1295     if ( updateR.bottom() > maxWY )
1296 	updateR.setBottom( maxWY );
1297 
1298     setupPainter( &paint );			// prepare for painting table
1299 
1300     int firstRow = findRow( updateR.y() );
1301     int firstCol = findCol( updateR.x() );
1302     int	 xStart, yStart;
1303     if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) {
1304 	paint.eraseRect( updateR ); // erase area outside cells but in view
1305 	return;
1306     }
1307     int	  maxX	= updateR.right();
1308     int	  maxY	= updateR.bottom();
1309     int	  row	= firstRow;
1310     int	  col;
1311     int	  yPos	= yStart;
1312     int	  xPos = maxX+1; // in case the while() is empty
1313     int	  nextX;
1314     int	  nextY;
1315     QRect winR = viewRect();
1316     QRect cellR;
1317     QRect cellUR;
1318 #ifndef QT_NO_TRANSFORMATIONS
1319     QWMatrix matrix;
1320 #endif
1321 
1322     while ( yPos <= maxY && row < nRows ) {
1323 	nextY = yPos + (cellH ? cellH : cellHeight( row ));
1324 	if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) )
1325 	    break;
1326 	col  = firstCol;
1327 	xPos = xStart;
1328 	while ( xPos <= maxX && col < nCols ) {
1329 	    nextX = xPos + (cellW ? cellW : cellWidth( col ));
1330 	    if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) )
1331 		break;
1332 
1333 	    cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col),
1334 				       cellH ? cellH : cellHeight(row) );
1335 	    cellUR = cellR.intersect( updateR );
1336 	    if ( cellUR.isValid() ) {
1337 		cellUpdateR = cellUR;
1338 		cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates
1339 		if ( eraseInPaint )
1340 		    paint.eraseRect( cellUR );
1341 
1342 #ifndef QT_NO_TRANSFORMATIONS
1343 		matrix.translate( xPos, yPos );
1344 		paint.setWorldMatrix( matrix );
1345 		if ( testTableFlags(Tbl_clipCellPainting) ||
1346 		     frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
1347 		    paint.setClipRect( cellUR );
1348 		    paintCell( &paint, row, col );
1349 		    paint.setClipping( FALSE );
1350 		} else {
1351 		    paintCell( &paint, row, col );
1352 		}
1353 		matrix.reset();
1354 		paint.setWorldMatrix( matrix );
1355 #else
1356 		paint.translate( xPos, yPos );
1357 		if ( testTableFlags(Tbl_clipCellPainting) ||
1358 		     frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
1359 		    paint.setClipRect( cellUR );
1360 		    paintCell( &paint, row, col );
1361 		    paint.setClipping( FALSE );
1362 		} else {
1363 		    paintCell( &paint, row, col );
1364 		}
1365 		paint.translate( -xPos, -yPos );
1366 #endif
1367 	    }
1368 	    col++;
1369 	    xPos = nextX;
1370 	}
1371 	row++;
1372 	yPos = nextY;
1373     }
1374 
1375     // while painting we have to erase any areas in the view that
1376     // are not covered by cells but are covered by the paint event
1377     // rectangle these must be erased. We know that xPos is the last
1378     // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
1379 
1380     // Note that this needs to be done regardless whether we do
1381     // eraseInPaint or not. Reason: a subclass may implement
1382     // flicker-freeness and encourage the use of repaint(FALSE).
1383     // The subclass, however, cannot draw all pixels, just those
1384     // inside the cells. So QtTableView is reponsible for all pixels
1385     // outside the cells.
1386 
1387     QRect viewR = viewRect();
1388     const QColorGroup g = colorGroup();
1389 
1390     if ( xPos <= maxX ) {
1391 	QRect r = viewR;
1392 	r.setLeft( xPos );
1393 	r.setBottom( yPos<maxY?yPos:maxY );
1394 	if ( inherits( "QMultiLineEdit" ) )
1395 	    paint.fillRect( r.intersect( updateR ), g.base() );
1396 	else
1397 	    paint.eraseRect( r.intersect( updateR ) );
1398     }
1399     if ( yPos <= maxY ) {
1400 	QRect r = viewR;
1401 	r.setTop( yPos );
1402 	if ( inherits( "QMultiLineEdit" ) )
1403 	    paint.fillRect( r.intersect( updateR ), g.base() );
1404 	else
1405 	    paint.eraseRect( r.intersect( updateR ) );
1406     }
1407 }
1408 
1409 /*!\reimp
1410 */
resizeEvent(QResizeEvent *)1411 void QtTableView::resizeEvent( QResizeEvent * )
1412 {
1413     updateScrollBars( horValue | verValue | horSteps | horGeometry | horRange |
1414 		      verSteps | verGeometry | verRange );
1415     showOrHideScrollBars();
1416     updateFrameSize();
1417     int maxX = QMIN( xOffs, maxXOffset() );			// ### can be slow
1418     int maxY = QMIN( yOffs, maxYOffset() );
1419     setOffset( maxX, maxY );
1420 }
1421 
1422 
1423 /*!
1424   Redraws all visible cells in the table view.
1425 */
1426 
updateView()1427 void QtTableView::updateView()
1428 {
1429     repaint( viewRect() );
1430 }
1431 
1432 /*!
1433   Returns a pointer to the vertical scroll bar mainly so you can
1434   connect() to its signals.  Note that the scroll bar works in pixel
1435   values; use findRow() to translate to cell numbers.
1436 */
1437 
verticalScrollBar() const1438 QScrollBar *QtTableView::verticalScrollBar() const
1439 {
1440     QtTableView *that = (QtTableView*)this; // semantic const
1441     if ( !vScrollBar ) {
1442 	QScrollBar *sb = new QScrollBar( QScrollBar::Vertical, that );
1443 #ifndef QT_NO_CURSOR
1444 	sb->setCursor( arrowCursor );
1445 #endif
1446         sb->resize( sb->sizeHint() ); // height is irrelevant
1447 	Q_CHECK_PTR(sb);
1448 	sb->setTracking( FALSE );
1449 	sb->setFocusPolicy( NoFocus );
1450 	connect( sb, SIGNAL(valueChanged(int)),
1451 		 SLOT(verSbValue(int)));
1452 	connect( sb, SIGNAL(sliderMoved(int)),
1453 		 SLOT(verSbSliding(int)));
1454 	connect( sb, SIGNAL(sliderReleased()),
1455 		 SLOT(verSbSlidingDone()));
1456 	sb->hide();
1457 	that->vScrollBar = sb;
1458 	return sb;
1459     }
1460     return vScrollBar;
1461 }
1462 
1463 /*!
1464   Returns a pointer to the horizontal scroll bar mainly so you can
1465   connect() to its signals. Note that the scroll bar works in pixel
1466   values; use findCol() to translate to cell numbers.
1467 */
1468 
horizontalScrollBar() const1469 QScrollBar *QtTableView::horizontalScrollBar() const
1470 {
1471     QtTableView *that = (QtTableView*)this; // semantic const
1472     if ( !hScrollBar ) {
1473 	QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that );
1474 #ifndef QT_NO_CURSOR
1475 	sb->setCursor( arrowCursor );
1476 #endif
1477 	sb->resize( sb->sizeHint() ); // width is irrelevant
1478 	sb->setFocusPolicy( NoFocus );
1479 	Q_CHECK_PTR(sb);
1480 	sb->setTracking( FALSE );
1481 	connect( sb, SIGNAL(valueChanged(int)),
1482 		 SLOT(horSbValue(int)));
1483 	connect( sb, SIGNAL(sliderMoved(int)),
1484 		 SLOT(horSbSliding(int)));
1485 	connect( sb, SIGNAL(sliderReleased()),
1486 		 SLOT(horSbSlidingDone()));
1487 	sb->hide();
1488 	that->hScrollBar = sb;
1489 	return sb;
1490     }
1491     return hScrollBar;
1492 }
1493 
1494 /*!
1495   Enables or disables the horizontal scroll bar, as required by
1496   setAutoUpdate() and the \link setTableFlags() table flags\endlink.
1497 */
1498 
setHorScrollBar(bool on,bool update)1499 void QtTableView::setHorScrollBar( bool on, bool update )
1500 {
1501     if ( on ) {
1502 	tFlags |= Tbl_hScrollBar;
1503 	horizontalScrollBar(); // created
1504 	if ( update )
1505 	    updateScrollBars( horMask | verMask );
1506 	else
1507 	    sbDirty = sbDirty | (horMask | verMask);
1508 	if ( testTableFlags( Tbl_vScrollBar ) )
1509 	    coverCornerSquare( TRUE );
1510 	if ( autoUpdate() )
1511 	    sbDirty = sbDirty | horMask;
1512     } else {
1513 	tFlags &= ~Tbl_hScrollBar;
1514 	if ( !hScrollBar )
1515 	    return;
1516 	coverCornerSquare( FALSE );
1517 	bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
1518 	if ( hideScrollBar )
1519 	    hScrollBar->hide();
1520 	if ( update )
1521 	    updateScrollBars( verMask );
1522 	else
1523 	    sbDirty = sbDirty | verMask;
1524 	if ( hideScrollBar && isVisible() )
1525 	    repaint( hScrollBar->x(), hScrollBar->y(),
1526 		     width() - hScrollBar->x(), hScrollBar->height() );
1527     }
1528     if ( update )
1529 	updateFrameSize();
1530 }
1531 
1532 
1533 /*!
1534   Enables or disables the vertical scroll bar, as required by
1535   setAutoUpdate() and the \link setTableFlags() table flags\endlink.
1536 */
1537 
setVerScrollBar(bool on,bool update)1538 void QtTableView::setVerScrollBar( bool on, bool update )
1539 {
1540     if ( on ) {
1541 	tFlags |= Tbl_vScrollBar;
1542 	verticalScrollBar(); // created
1543 	if ( update )
1544 	    updateScrollBars( verMask | horMask );
1545 	else
1546 	    sbDirty = sbDirty | (horMask | verMask);
1547 	if ( testTableFlags( Tbl_hScrollBar ) )
1548 	    coverCornerSquare( TRUE );
1549 	if ( autoUpdate() )
1550 	    sbDirty = sbDirty | verMask;
1551     } else {
1552 	tFlags &= ~Tbl_vScrollBar;
1553 	if ( !vScrollBar )
1554 	    return;
1555 	coverCornerSquare( FALSE );
1556 	bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
1557 	if ( hideScrollBar )
1558 	    vScrollBar->hide();
1559 	if ( update )
1560 	    updateScrollBars( horMask );
1561 	else
1562 	    sbDirty = sbDirty | horMask;
1563 	if ( hideScrollBar && isVisible() )
1564 	    repaint( vScrollBar->x(), vScrollBar->y(),
1565 		     vScrollBar->width(), height() - vScrollBar->y() );
1566     }
1567     if ( update )
1568 	updateFrameSize();
1569 }
1570 
1571 
1572 
1573 
findRawRow(int yPos,int * cellMaxY,int * cellMinY,bool goOutsideView) const1574 int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY,
1575 			    bool goOutsideView ) const
1576 {
1577     int r = -1;
1578     if ( nRows == 0 )
1579 	return r;
1580     if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) {
1581 	if ( yPos < minViewY() ) {
1582 #if defined(QT_CHECK_RANGE)
1583 	    qWarning( "QtTableView::findRawRow: (%s) internal error: "
1584 		     "yPos < minViewY() && goOutsideView "
1585 		     "not supported. (%d,%d)",
1586 		     name( "unnamed" ), yPos, yOffs );
1587 #endif
1588 	    return -1;
1589 	}
1590 	if ( cellH ) {				     // uniform cell height
1591 	    r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top
1592 	    if ( cellMaxY )
1593 		*cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1;
1594 	    if ( cellMinY )
1595 		*cellMinY = r*cellH + minViewY() - yCellDelta;
1596 	    r += yCellOffs;			     // absolute cell index
1597 	} else {				     // variable cell height
1598 	    QtTableView *tw = (QtTableView *)this;
1599 	    r	     = yCellOffs;
1600 	    int h    = minViewY() - yCellDelta; //##arnt3
1601 	    int oldH = h;
1602 	    Q_ASSERT( r < nRows );
1603 	    while ( r < nRows ) {
1604 		oldH = h;
1605 		h += tw->cellHeight( r );	     // Start of next cell
1606 		if ( yPos < h )
1607 		    break;
1608 		r++;
1609 	    }
1610 	    if ( cellMaxY )
1611 		*cellMaxY = h - 1;
1612 	    if ( cellMinY )
1613 		*cellMinY = oldH;
1614 	}
1615     }
1616     return r;
1617 
1618 }
1619 
1620 
findRawCol(int xPos,int * cellMaxX,int * cellMinX,bool goOutsideView) const1621 int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX ,
1622 			    bool goOutsideView ) const
1623 {
1624     int c = -1;
1625     if ( nCols == 0 )
1626 	return c;
1627     if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) {
1628 	if ( xPos < minViewX() ) {
1629 #if defined(QT_CHECK_RANGE)
1630 	    qWarning( "QtTableView::findRawCol: (%s) internal error: "
1631 		     "xPos < minViewX() && goOutsideView "
1632 		     "not supported. (%d,%d)",
1633 		     name( "unnamed" ), xPos, xOffs );
1634 #endif
1635 	    return -1;
1636 	}
1637 	if ( cellW ) {				// uniform cell width
1638 	    c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left
1639 	    if ( cellMaxX )
1640 		*cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1;
1641 	    if ( cellMinX )
1642 		*cellMinX = c*cellW + minViewX() - xCellDelta;
1643 	    c += xCellOffs;			// absolute cell index
1644 	} else {				// variable cell width
1645 	    QtTableView *tw = (QtTableView *)this;
1646 	    c	     = xCellOffs;
1647 	    int w    = minViewX() - xCellDelta; //##arnt3
1648 	    int oldW = w;
1649 	    Q_ASSERT( c < nCols );
1650 	    while ( c < nCols ) {
1651 		oldW = w;
1652 		w += tw->cellWidth( c );	// Start of next cell
1653 		if ( xPos < w )
1654 		    break;
1655 		c++;
1656 	    }
1657 	    if ( cellMaxX )
1658 		*cellMaxX = w - 1;
1659 	    if ( cellMinX )
1660 		*cellMinX = oldW;
1661 	}
1662     }
1663     return c;
1664 }
1665 
1666 
1667 /*!
1668   Returns the index of the row at position \a yPos, where \a yPos is in
1669   \e widget coordinates.  Returns -1 if \a yPos is outside the valid
1670   range.
1671 
1672   \sa findCol(), rowYPos()
1673 */
1674 
findRow(int yPos) const1675 int QtTableView::findRow( int yPos ) const
1676 {
1677     int cellMaxY;
1678     int row = findRawRow( yPos, &cellMaxY );
1679     if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() )
1680 	row = - 1;				//  cell cut by bottom margin
1681     if ( row >= nRows )
1682 	row = -1;
1683     return row;
1684 }
1685 
1686 
1687 /*!
1688   Returns the index of the column at position \a xPos, where \a xPos is
1689   in \e widget coordinates.  Returns -1 if \a xPos is outside the valid
1690   range.
1691 
1692   \sa findRow(), colXPos()
1693 */
1694 
findCol(int xPos) const1695 int QtTableView::findCol( int xPos ) const
1696 {
1697     int cellMaxX;
1698     int col = findRawCol( xPos, &cellMaxX );
1699     if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() )
1700 	col = - 1;				//  cell cut by right margin
1701     if ( col >= nCols )
1702 	col = -1;
1703     return col;
1704 }
1705 
1706 
1707 /*!
1708   Computes the position in the widget of row \a row.
1709 
1710   Returns TRUE and stores the result in \a *yPos (in \e widget
1711   coordinates) if the row is visible.  Returns FALSE and does not modify
1712   \a *yPos if \a row is invisible or invalid.
1713 
1714   \sa colXPos(), findRow()
1715 */
1716 
rowYPos(int row,int * yPos) const1717 bool QtTableView::rowYPos( int row, int *yPos ) const
1718 {
1719     int y;
1720     if ( row >= yCellOffs ) {
1721 	if ( cellH ) {
1722 	    int lastVisible = lastRowVisible();
1723 	    if ( row > lastVisible || lastVisible == -1 )
1724 		return FALSE;
1725 	    y = (row - yCellOffs)*cellH + minViewY() - yCellDelta;
1726 	} else {
1727 	    //##arnt3
1728 	    y = minViewY() - yCellDelta;	// y of leftmost cell in view
1729 	    int r = yCellOffs;
1730 	    QtTableView *tw = (QtTableView *)this;
1731 	    int maxY = maxViewY();
1732 	    while ( r < row && y <= maxY )
1733 		y += tw->cellHeight( r++ );
1734 	    if ( y > maxY )
1735 		return FALSE;
1736 
1737 	}
1738     } else {
1739 	return FALSE;
1740     }
1741     if ( yPos )
1742 	*yPos = y;
1743     return TRUE;
1744 }
1745 
1746 
1747 /*!
1748   Computes the position in the widget of column \a col.
1749 
1750   Returns TRUE and stores the result in \a *xPos (in \e widget
1751   coordinates) if the column is visible.  Returns FALSE and does not
1752   modify \a *xPos if \a col is invisible or invalid.
1753 
1754   \sa rowYPos(), findCol()
1755 */
1756 
colXPos(int col,int * xPos) const1757 bool QtTableView::colXPos( int col, int *xPos ) const
1758 {
1759     int x;
1760     if ( col >= xCellOffs ) {
1761 	if ( cellW ) {
1762 	    int lastVisible = lastColVisible();
1763 	    if ( col > lastVisible || lastVisible == -1 )
1764 		return FALSE;
1765 	    x = (col - xCellOffs)*cellW + minViewX() - xCellDelta;
1766 	} else {
1767 	    //##arnt3
1768 	    x = minViewX() - xCellDelta;	// x of uppermost cell in view
1769 	    int c = xCellOffs;
1770 	    QtTableView *tw = (QtTableView *)this;
1771 	    int maxX = maxViewX();
1772 	    while ( c < col && x <= maxX )
1773 		x += tw->cellWidth( c++ );
1774 	    if ( x > maxX )
1775 		return FALSE;
1776 	}
1777     } else {
1778 	return FALSE;
1779     }
1780     if ( xPos )
1781 	*xPos = x;
1782     return TRUE;
1783 }
1784 
1785 
1786 /*!
1787   Moves the visible area of the table right by \a xPixels and
1788   down by \a yPixels pixels.  Both may be negative.
1789 
1790   \warning You might find that QScrollView offers a higher-level of
1791 	functionality than using QtTableView and this function.
1792 
1793   This function is \e not the same as QWidget::scroll(); in particular,
1794   the signs of \a xPixels and \a yPixels have the reverse semantics.
1795 
1796   \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
1797   setLeftCell()
1798 */
1799 
scroll(int xPixels,int yPixels)1800 void QtTableView::scroll( int xPixels, int yPixels )
1801 {
1802     QWidget::scroll( -xPixels, -yPixels, contentsRect() );
1803 }
1804 
1805 
1806 /*!
1807   Returns the leftmost pixel of the table view in \e view
1808   coordinates.	This excludes the frame and any header.
1809 
1810   \sa maxViewY(), viewWidth(), contentsRect()
1811 */
1812 
minViewX() const1813 int QtTableView::minViewX() const
1814 {
1815     return frameWidth();
1816 }
1817 
1818 
1819 /*!
1820   Returns the top pixel of the table view in \e view
1821   coordinates.	This excludes the frame and any header.
1822 
1823   \sa maxViewX(), viewHeight(), contentsRect()
1824 */
1825 
minViewY() const1826 int QtTableView::minViewY() const
1827 {
1828     return frameWidth();
1829 }
1830 
1831 
1832 /*!
1833   Returns the rightmost pixel of the table view in \e view
1834   coordinates.	This excludes the frame and any scroll bar, but
1835   includes blank pixels to the right of the visible table data.
1836 
1837   \sa maxViewY(), viewWidth(), contentsRect()
1838 */
1839 
maxViewX() const1840 int QtTableView::maxViewX() const
1841 {
1842     return width() - 1 - frameWidth()
1843         - (tFlags & Tbl_vScrollBar ? VSBEXT
1844            : 0);
1845 }
1846 
1847 
1848 /*!
1849   Returns the bottom pixel of the table view in \e view
1850   coordinates.	This excludes the frame and any scroll bar, but
1851   includes blank pixels below the visible table data.
1852 
1853   \sa maxViewX(), viewHeight(), contentsRect()
1854 */
1855 
maxViewY() const1856 int QtTableView::maxViewY() const
1857 {
1858     return height() - 1 - frameWidth()
1859         - (tFlags & Tbl_hScrollBar ? HSBEXT
1860            : 0);
1861 }
1862 
1863 
1864 /*!
1865   Returns the width of the table view, as such, in \e view
1866   coordinates.  This does not include any header, scroll bar or frame,
1867   but it does include background pixels to the right of the table data.
1868 
1869   \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
1870 */
1871 
viewWidth() const1872 int QtTableView::viewWidth() const
1873 {
1874     return maxViewX() - minViewX() + 1;
1875 }
1876 
1877 
1878 /*!
1879   Returns the height of the table view, as such, in \e view
1880   coordinates.  This does not include any header, scroll bar or frame,
1881   but it does include background pixels below the table data.
1882 
1883   \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
1884 */
1885 
viewHeight() const1886 int QtTableView::viewHeight() const
1887 {
1888     return maxViewY() - minViewY() + 1;
1889 }
1890 
1891 
doAutoScrollBars()1892 void QtTableView::doAutoScrollBars()
1893 {
1894     int viewW = width()	 - frameWidth() - minViewX();
1895     int viewH = height() - frameWidth() - minViewY();
1896     bool vScrollOn = testTableFlags(Tbl_vScrollBar);
1897     bool hScrollOn = testTableFlags(Tbl_hScrollBar);
1898     int w = 0;
1899     int h = 0;
1900     int i;
1901 
1902     if ( testTableFlags(Tbl_autoHScrollBar) ) {
1903 	if ( cellW ) {
1904 	    w = cellW*nCols;
1905 	} else {
1906 	    i = 0;
1907 	    while ( i < nCols && w <= viewW )
1908 		w += cellWidth( i++ );
1909 	}
1910 	if ( w > viewW )
1911 	    hScrollOn = TRUE;
1912 	else
1913 	    hScrollOn = FALSE;
1914     }
1915 
1916     if ( testTableFlags(Tbl_autoVScrollBar) ) {
1917 	if ( cellH ) {
1918 	    h = cellH*nRows;
1919 	} else {
1920 	    i = 0;
1921 	    while ( i < nRows && h <= viewH )
1922 		h += cellHeight( i++ );
1923 	}
1924 
1925 	if ( h > viewH )
1926 	    vScrollOn = TRUE;
1927 	else
1928 	    vScrollOn = FALSE;
1929     }
1930 
1931     if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn )
1932 	if ( w > viewW - VSBEXT )
1933 	    hScrollOn = TRUE;
1934 
1935     if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn )
1936 	if ( h > viewH - HSBEXT )
1937 	    vScrollOn = TRUE;
1938 
1939     setHorScrollBar( hScrollOn, FALSE );
1940     setVerScrollBar( vScrollOn, FALSE );
1941     updateFrameSize();
1942 }
1943 
1944 
1945 /*!
1946   \fn void QtTableView::updateScrollBars()
1947 
1948   Updates the scroll bars' contents and presence to match the table's
1949   state.  Generally, you should not need to call this.
1950 
1951   \sa setTableFlags()
1952 */
1953 
1954 /*!
1955   Updates the scroll bars' contents and presence to match the table's
1956   state \c or \a f.
1957 
1958   \sa setTableFlags()
1959 */
1960 
updateScrollBars(uint f)1961 void QtTableView::updateScrollBars( uint f )
1962 {
1963     sbDirty = sbDirty | f;
1964     if ( inSbUpdate )
1965 	return;
1966     inSbUpdate = TRUE;
1967 
1968     if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) ||
1969 	 testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) )
1970 					// if range change and auto
1971 	doAutoScrollBars();		// turn scroll bars on/off if needed
1972 
1973     if ( !autoUpdate() ) {
1974 	inSbUpdate = FALSE;
1975 	return;
1976     }
1977     if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) &&
1978 	 !testTableFlags( Tbl_vScrollBar ) ) {
1979 	setYOffset( 0 );
1980     }
1981     if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) &&
1982 	 !testTableFlags( Tbl_hScrollBar ) ) {
1983 	setXOffset( 0 );
1984     }
1985     if ( !isVisible() ) {
1986 	inSbUpdate = FALSE;
1987 	return;
1988     }
1989 
1990     if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) {
1991 	if ( sbDirty & horGeometry )
1992 	    hScrollBar->setGeometry( 0,height() - HSBEXT,
1993                                      viewWidth() + frameWidth()*2,
1994                                    HSBEXT);
1995 
1996 	if ( sbDirty & horSteps ) {
1997 	    if ( cellW )
1998 		hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() );
1999 	    else
2000 		hScrollBar->setSteps( 16, viewWidth() );
2001 	}
2002 
2003 	if ( sbDirty & horRange )
2004 	    hScrollBar->setRange( 0, maxXOffset() );
2005 
2006 	if ( sbDirty & horValue )
2007 	    hScrollBar->setValue( xOffs );
2008 
2009 			// show scrollbar only when it has a sane geometry
2010 	if ( !hScrollBar->isVisible() )
2011 	    hScrollBar->show();
2012     }
2013 
2014     if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) {
2015 	if ( sbDirty & verGeometry )
2016 	    vScrollBar->setGeometry( width() - VSBEXT, 0,
2017                                      VSBEXT,
2018                                      viewHeight() + frameWidth()*2 );
2019 
2020 	if ( sbDirty & verSteps ) {
2021 	    if ( cellH )
2022 		vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() );
2023 	    else
2024 		vScrollBar->setSteps( 16, viewHeight() );  // fttb! ###
2025 	}
2026 
2027 	if ( sbDirty & verRange )
2028 	    vScrollBar->setRange( 0, maxYOffset() );
2029 
2030 	if ( sbDirty & verValue )
2031 	    vScrollBar->setValue( yOffs );
2032 
2033 			// show scrollbar only when it has a sane geometry
2034 	if ( !vScrollBar->isVisible() )
2035 	    vScrollBar->show();
2036     }
2037     if ( coveringCornerSquare &&
2038 	 ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) )
2039 	cornerSquare->move( maxViewX() + frameWidth() + 1,
2040 			    maxViewY() + frameWidth() + 1 );
2041 
2042     sbDirty = 0;
2043     inSbUpdate = FALSE;
2044 }
2045 
2046 
updateFrameSize()2047 void QtTableView::updateFrameSize()
2048 {
2049     int rw = width()  - ( testTableFlags(Tbl_vScrollBar) ?
2050                           VSBEXT : 0 );
2051     int rh = height() - ( testTableFlags(Tbl_hScrollBar) ?
2052                           HSBEXT : 0 );
2053     if ( rw < 0 )
2054 	rw = 0;
2055     if ( rh < 0 )
2056 	rh = 0;
2057 
2058     if ( autoUpdate() ) {
2059         int fh = frameRect().height();
2060 	int fw = frameRect().width();
2061 	setFrameRect( QRect(0,0,rw,rh) );
2062 
2063 	if ( rw != fw )
2064 	    update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh );
2065 	if ( rh != fh )
2066 	    update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 );
2067     }
2068 }
2069 
2070 
2071 /*!
2072   Returns the maximum horizontal offset within the table of the
2073   view's left edge in \e table coordinates.
2074 
2075   This is used mainly to set the horizontal scroll bar's range.
2076 
2077   \sa maxColOffset(), maxYOffset(), totalWidth()
2078 */
2079 
maxXOffset()2080 int QtTableView::maxXOffset()
2081 {
2082     int tw = totalWidth();
2083     int maxOffs;
2084     if ( testTableFlags(Tbl_scrollLastHCell) ) {
2085 	if ( nCols != 1)
2086 	    maxOffs =  tw - ( cellW ? cellW : cellWidth( nCols - 1 ) );
2087 	else
2088 	    maxOffs = tw - viewWidth();
2089     } else {
2090 	if ( testTableFlags(Tbl_snapToHGrid) ) {
2091 	    if ( cellW ) {
2092 		maxOffs =  tw - (viewWidth()/cellW)*cellW;
2093 	    } else {
2094 		int goal = tw - viewWidth();
2095 		int pos = tw;
2096 		int nextCol = nCols - 1;
2097 		int nextCellWidth = cellWidth( nextCol );
2098 		while( nextCol > 0 && pos > goal + nextCellWidth ) {
2099 		    pos -= nextCellWidth;
2100 		    nextCellWidth = cellWidth( --nextCol );
2101 		}
2102 		if ( goal + nextCellWidth == pos )
2103 		    maxOffs = goal;
2104 		 else if ( goal < pos )
2105 		   maxOffs = pos;
2106 		 else
2107 		   maxOffs = 0;
2108 	    }
2109 	} else {
2110 	    maxOffs = tw - viewWidth();
2111 	}
2112     }
2113     return maxOffs > 0 ? maxOffs : 0;
2114 }
2115 
2116 
2117 /*!
2118   Returns the maximum vertical offset within the table of the
2119   view's top edge in \e table coordinates.
2120 
2121   This is used mainly to set the vertical scroll bar's range.
2122 
2123   \sa maxRowOffset(), maxXOffset(), totalHeight()
2124 */
2125 
maxYOffset()2126 int QtTableView::maxYOffset()
2127 {
2128     int th = totalHeight();
2129     int maxOffs;
2130     if ( testTableFlags(Tbl_scrollLastVCell) ) {
2131 	if ( nRows != 1)
2132 	    maxOffs =  th - ( cellH ? cellH : cellHeight( nRows - 1 ) );
2133 	else
2134 	    maxOffs = th - viewHeight();
2135     } else {
2136 	if ( testTableFlags(Tbl_snapToVGrid) ) {
2137 	    if ( cellH ) {
2138 		maxOffs =  th - (viewHeight()/cellH)*cellH;
2139 	    } else {
2140 		int goal = th - viewHeight();
2141 		int pos = th;
2142 		int nextRow = nRows - 1;
2143 		int nextCellHeight = cellHeight( nextRow );
2144 		while( nextRow > 0 && pos > goal + nextCellHeight ) {
2145 		    pos -= nextCellHeight;
2146 		    nextCellHeight = cellHeight( --nextRow );
2147 		}
2148 		if ( goal + nextCellHeight == pos )
2149 		    maxOffs = goal;
2150 		 else if ( goal < pos )
2151 		   maxOffs = pos;
2152 		 else
2153 		   maxOffs = 0;
2154 	    }
2155 	} else {
2156 	    maxOffs = th - viewHeight();
2157 	}
2158     }
2159     return maxOffs > 0 ? maxOffs : 0;
2160 }
2161 
2162 
2163 /*!
2164   Returns the index of the last column, which may be at the left edge
2165   of the view.
2166 
2167   Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
2168   this may or may not be the last column.
2169 
2170   \sa maxXOffset(), maxRowOffset()
2171 */
2172 
maxColOffset()2173 int QtTableView::maxColOffset()
2174 {
2175     int mx = maxXOffset();
2176     if ( cellW )
2177 	return mx/cellW;
2178     else {
2179 	int xcd=0, col=0;
2180 	while ( col < nCols && mx > (xcd=cellWidth(col)) ) {
2181 	    mx -= xcd;
2182 	    col++;
2183 	}
2184 	return col;
2185     }
2186 }
2187 
2188 
2189 /*!
2190   Returns the index of the last row, which may be at the top edge of
2191   the view.
2192 
2193   Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
2194   this may or may not be the last row.
2195 
2196   \sa maxYOffset(), maxColOffset()
2197 */
2198 
maxRowOffset()2199 int QtTableView::maxRowOffset()
2200 {
2201     int my = maxYOffset();
2202     if ( cellH )
2203 	return my/cellH;
2204     else {
2205 	int ycd=0, row=0;
2206 	while ( row < nRows && my > (ycd=cellHeight(row)) ) {
2207 	    my -= ycd;
2208 	    row++;
2209 	}
2210 	return row;
2211     }
2212 }
2213 
2214 
showOrHideScrollBars()2215 void QtTableView::showOrHideScrollBars()
2216 {
2217     if ( !autoUpdate() )
2218 	return;
2219     if ( vScrollBar ) {
2220 	if ( testTableFlags(Tbl_vScrollBar) ) {
2221 	    if ( !vScrollBar->isVisible() )
2222 		sbDirty = sbDirty | verMask;
2223 	} else {
2224 	    if ( vScrollBar->isVisible() )
2225 	       vScrollBar->hide();
2226 	}
2227     }
2228     if ( hScrollBar ) {
2229 	if ( testTableFlags(Tbl_hScrollBar) ) {
2230 	    if ( !hScrollBar->isVisible() )
2231 		sbDirty = sbDirty | horMask;
2232 	} else {
2233 	    if ( hScrollBar->isVisible() )
2234 		hScrollBar->hide();
2235 	}
2236     }
2237     if ( cornerSquare ) {
2238 	if ( testTableFlags(Tbl_hScrollBar) &&
2239 	     testTableFlags(Tbl_vScrollBar) ) {
2240 	    if ( !cornerSquare->isVisible() )
2241 		cornerSquare->show();
2242 	} else {
2243 	    if ( cornerSquare->isVisible() )
2244 		cornerSquare->hide();
2245 	}
2246     }
2247 }
2248 
2249 
2250 /*!
2251   Updates the scroll bars and internal state.
2252 
2253   Call this function when the table view's total size is changed;
2254   typically because the result of cellHeight() or cellWidth() have changed.
2255 
2256   This function does not repaint the widget.
2257 */
2258 
updateTableSize()2259 void QtTableView::updateTableSize()
2260 {
2261     bool updateOn = autoUpdate();
2262     setAutoUpdate( FALSE );
2263     int xofs = xOffset();
2264     xOffs++; //so that setOffset will not return immediately
2265     setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly
2266     setAutoUpdate(updateOn);
2267 
2268     updateScrollBars( horSteps |  horRange |
2269 		      verSteps |  verRange );
2270     showOrHideScrollBars();
2271 }
2272 
2273 
2274 #endif
2275 #endif
2276