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