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