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