]> git.lyx.org Git - lyx.git/blob - src/frontends/qt2/qttableview.C
ws cleanup
[lyx.git] / src / frontends / qt2 / qttableview.C
1 /**********************************************************************
2 ** $Id: qttableview.C,v 1.3 2002/03/21 21:19:37 larsbj 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;
1310     int yStart;
1311     if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) {
1312         paint.eraseRect( updateR ); // erase area outside cells but in view
1313         return;
1314     }
1315     int   maxX  = updateR.right();
1316     int   maxY  = updateR.bottom();
1317     int   row   = firstRow;
1318     int   col;
1319     int   yPos  = yStart;
1320     int   xPos = maxX + 1; // in case the while() is empty
1321     int   nextX;
1322     int   nextY;
1323     QRect winR = viewRect();
1324     QRect cellR;
1325     QRect cellUR;
1326 #ifndef QT_NO_TRANSFORMATIONS
1327     QWMatrix matrix;
1328 #endif
1329
1330     while ( yPos <= maxY && row < nRows ) {
1331         nextY = yPos + (cellH ? cellH : cellHeight( row ));
1332         if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) )
1333             break;
1334         col  = firstCol;
1335         xPos = xStart;
1336         while ( xPos <= maxX && col < nCols ) {
1337             nextX = xPos + (cellW ? cellW : cellWidth( col ));
1338             if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) )
1339                 break;
1340
1341             cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col),
1342                                        cellH ? cellH : cellHeight(row) );
1343             cellUR = cellR.intersect( updateR );
1344             if ( cellUR.isValid() ) {
1345                 cellUpdateR = cellUR;
1346                 cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates
1347                 if ( eraseInPaint )
1348                     paint.eraseRect( cellUR );
1349
1350 #ifndef QT_NO_TRANSFORMATIONS
1351                 matrix.translate( xPos, yPos );
1352                 paint.setWorldMatrix( matrix );
1353                 if ( testTableFlags(Tbl_clipCellPainting) ||
1354                      frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
1355                     paint.setClipRect( cellUR );
1356                     paintCell( &paint, row, col );
1357                     paint.setClipping( FALSE );
1358                 } else {
1359                     paintCell( &paint, row, col );
1360                 }
1361                 matrix.reset();
1362                 paint.setWorldMatrix( matrix );
1363 #else
1364                 paint.translate( xPos, yPos );
1365                 if ( testTableFlags(Tbl_clipCellPainting) ||
1366                      frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
1367                     paint.setClipRect( cellUR );
1368                     paintCell( &paint, row, col );
1369                     paint.setClipping( FALSE );
1370                 } else {
1371                     paintCell( &paint, row, col );
1372                 }
1373                 paint.translate( -xPos, -yPos );
1374 #endif
1375             }
1376             col++;
1377             xPos = nextX;
1378         }
1379         row++;
1380         yPos = nextY;
1381     }
1382
1383     // while painting we have to erase any areas in the view that
1384     // are not covered by cells but are covered by the paint event
1385     // rectangle these must be erased. We know that xPos is the last
1386     // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
1387
1388     // Note that this needs to be done regardless whether we do
1389     // eraseInPaint or not. Reason: a subclass may implement
1390     // flicker-freeness and encourage the use of repaint(FALSE).
1391     // The subclass, however, cannot draw all pixels, just those
1392     // inside the cells. So QtTableView is reponsible for all pixels
1393     // outside the cells.
1394
1395     QRect viewR = viewRect();
1396     const QColorGroup g = colorGroup();
1397
1398     if ( xPos <= maxX ) {
1399         QRect r = viewR;
1400         r.setLeft( xPos );
1401         r.setBottom( yPos<maxY?yPos:maxY );
1402         if ( inherits( "QMultiLineEdit" ) )
1403             paint.fillRect( r.intersect( updateR ), g.base() );
1404         else
1405             paint.eraseRect( r.intersect( updateR ) );
1406     }
1407     if ( yPos <= maxY ) {
1408         QRect r = viewR;
1409         r.setTop( yPos );
1410         if ( inherits( "QMultiLineEdit" ) )
1411             paint.fillRect( r.intersect( updateR ), g.base() );
1412         else
1413             paint.eraseRect( r.intersect( updateR ) );
1414     }
1415 }
1416
1417 /*!\reimp
1418 */
1419 void QtTableView::resizeEvent( QResizeEvent * )
1420 {
1421     updateScrollBars( horValue | verValue | horSteps | horGeometry | horRange |
1422                       verSteps | verGeometry | verRange );
1423     showOrHideScrollBars();
1424     updateFrameSize();
1425     int maxX = QMIN( xOffs, maxXOffset() );                     // ### can be slow
1426     int maxY = QMIN( yOffs, maxYOffset() );
1427     setOffset( maxX, maxY );
1428 }
1429
1430
1431 /*!
1432   Redraws all visible cells in the table view.
1433 */
1434
1435 void QtTableView::updateView()
1436 {
1437     repaint( viewRect() );
1438 }
1439
1440 /*!
1441   Returns a pointer to the vertical scroll bar mainly so you can
1442   connect() to its signals.  Note that the scroll bar works in pixel
1443   values; use findRow() to translate to cell numbers.
1444 */
1445
1446 QScrollBar *QtTableView::verticalScrollBar() const
1447 {
1448     QtTableView *that = (QtTableView*)this; // semantic const
1449     if ( !vScrollBar ) {
1450         QScrollBar *sb = new QScrollBar( QScrollBar::Vertical, that );
1451 #ifndef QT_NO_CURSOR
1452         sb->setCursor( arrowCursor );
1453 #endif
1454         sb->resize( sb->sizeHint() ); // height is irrelevant
1455         Q_CHECK_PTR(sb);
1456         sb->setTracking( FALSE );
1457         sb->setFocusPolicy( NoFocus );
1458         connect( sb, SIGNAL(valueChanged(int)),
1459                  SLOT(verSbValue(int)));
1460         connect( sb, SIGNAL(sliderMoved(int)),
1461                  SLOT(verSbSliding(int)));
1462         connect( sb, SIGNAL(sliderReleased()),
1463                  SLOT(verSbSlidingDone()));
1464         sb->hide();
1465         that->vScrollBar = sb;
1466         return sb;
1467     }
1468     return vScrollBar;
1469 }
1470
1471 /*!
1472   Returns a pointer to the horizontal scroll bar mainly so you can
1473   connect() to its signals. Note that the scroll bar works in pixel
1474   values; use findCol() to translate to cell numbers.
1475 */
1476
1477 QScrollBar *QtTableView::horizontalScrollBar() const
1478 {
1479     QtTableView *that = (QtTableView*)this; // semantic const
1480     if ( !hScrollBar ) {
1481         QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that );
1482 #ifndef QT_NO_CURSOR
1483         sb->setCursor( arrowCursor );
1484 #endif
1485         sb->resize( sb->sizeHint() ); // width is irrelevant
1486         sb->setFocusPolicy( NoFocus );
1487         Q_CHECK_PTR(sb);
1488         sb->setTracking( FALSE );
1489         connect( sb, SIGNAL(valueChanged(int)),
1490                  SLOT(horSbValue(int)));
1491         connect( sb, SIGNAL(sliderMoved(int)),
1492                  SLOT(horSbSliding(int)));
1493         connect( sb, SIGNAL(sliderReleased()),
1494                  SLOT(horSbSlidingDone()));
1495         sb->hide();
1496         that->hScrollBar = sb;
1497         return sb;
1498     }
1499     return hScrollBar;
1500 }
1501
1502 /*!
1503   Enables or disables the horizontal scroll bar, as required by
1504   setAutoUpdate() and the \link setTableFlags() table flags\endlink.
1505 */
1506
1507 void QtTableView::setHorScrollBar( bool on, bool update )
1508 {
1509     if ( on ) {
1510         tFlags |= Tbl_hScrollBar;
1511         horizontalScrollBar(); // created
1512         if ( update )
1513             updateScrollBars( horMask | verMask );
1514         else
1515             sbDirty = sbDirty | (horMask | verMask);
1516         if ( testTableFlags( Tbl_vScrollBar ) )
1517             coverCornerSquare( TRUE );
1518         if ( autoUpdate() )
1519             sbDirty = sbDirty | horMask;
1520     } else {
1521         tFlags &= ~Tbl_hScrollBar;
1522         if ( !hScrollBar )
1523             return;
1524         coverCornerSquare( FALSE );
1525         bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
1526         if ( hideScrollBar )
1527             hScrollBar->hide();
1528         if ( update )
1529             updateScrollBars( verMask );
1530         else
1531             sbDirty = sbDirty | verMask;
1532         if ( hideScrollBar && isVisible() )
1533             repaint( hScrollBar->x(), hScrollBar->y(),
1534                      width() - hScrollBar->x(), hScrollBar->height() );
1535     }
1536     if ( update )
1537         updateFrameSize();
1538 }
1539
1540
1541 /*!
1542   Enables or disables the vertical scroll bar, as required by
1543   setAutoUpdate() and the \link setTableFlags() table flags\endlink.
1544 */
1545
1546 void QtTableView::setVerScrollBar( bool on, bool update )
1547 {
1548     if ( on ) {
1549         tFlags |= Tbl_vScrollBar;
1550         verticalScrollBar(); // created
1551         if ( update )
1552             updateScrollBars( verMask | horMask );
1553         else
1554             sbDirty = sbDirty | (horMask | verMask);
1555         if ( testTableFlags( Tbl_hScrollBar ) )
1556             coverCornerSquare( TRUE );
1557         if ( autoUpdate() )
1558             sbDirty = sbDirty | verMask;
1559     } else {
1560         tFlags &= ~Tbl_vScrollBar;
1561         if ( !vScrollBar )
1562             return;
1563         coverCornerSquare( FALSE );
1564         bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
1565         if ( hideScrollBar )
1566             vScrollBar->hide();
1567         if ( update )
1568             updateScrollBars( horMask );
1569         else
1570             sbDirty = sbDirty | horMask;
1571         if ( hideScrollBar && isVisible() )
1572             repaint( vScrollBar->x(), vScrollBar->y(),
1573                      vScrollBar->width(), height() - vScrollBar->y() );
1574     }
1575     if ( update )
1576         updateFrameSize();
1577 }
1578
1579
1580
1581
1582 int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY,
1583                             bool goOutsideView ) const
1584 {
1585     int r = -1;
1586     if ( nRows == 0 )
1587         return r;
1588     if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) {
1589         if ( yPos < minViewY() ) {
1590 #if defined(QT_CHECK_RANGE)
1591             qWarning( "QtTableView::findRawRow: (%s) internal error: "
1592                      "yPos < minViewY() && goOutsideView "
1593                      "not supported. (%d,%d)",
1594                      name( "unnamed" ), yPos, yOffs );
1595 #endif
1596             return -1;
1597         }
1598         if ( cellH ) {                               // uniform cell height
1599             r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top
1600             if ( cellMaxY )
1601                 *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1;
1602             if ( cellMinY )
1603                 *cellMinY = r*cellH + minViewY() - yCellDelta;
1604             r += yCellOffs;                          // absolute cell index
1605         } else {                                     // variable cell height
1606             QtTableView *tw = (QtTableView *)this;
1607             r        = yCellOffs;
1608             int h    = minViewY() - yCellDelta; //##arnt3
1609             int oldH = h;
1610             Q_ASSERT( r < nRows );
1611             while ( r < nRows ) {
1612                 oldH = h;
1613                 h += tw->cellHeight( r );            // Start of next cell
1614                 if ( yPos < h )
1615                     break;
1616                 r++;
1617             }
1618             if ( cellMaxY )
1619                 *cellMaxY = h - 1;
1620             if ( cellMinY )
1621                 *cellMinY = oldH;
1622         }
1623     }
1624     return r;
1625
1626 }
1627
1628
1629 int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX ,
1630                             bool goOutsideView ) const
1631 {
1632     int c = -1;
1633     if ( nCols == 0 )
1634         return c;
1635     if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) {
1636         if ( xPos < minViewX() ) {
1637 #if defined(QT_CHECK_RANGE)
1638             qWarning( "QtTableView::findRawCol: (%s) internal error: "
1639                      "xPos < minViewX() && goOutsideView "
1640                      "not supported. (%d,%d)",
1641                      name( "unnamed" ), xPos, xOffs );
1642 #endif
1643             return -1;
1644         }
1645         if ( cellW ) {                          // uniform cell width
1646             c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left
1647             if ( cellMaxX )
1648                 *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1;
1649             if ( cellMinX )
1650                 *cellMinX = c*cellW + minViewX() - xCellDelta;
1651             c += xCellOffs;                     // absolute cell index
1652         } else {                                // variable cell width
1653             QtTableView *tw = (QtTableView *)this;
1654             c        = xCellOffs;
1655             int w    = minViewX() - xCellDelta; //##arnt3
1656             int oldW = w;
1657             Q_ASSERT( c < nCols );
1658             while ( c < nCols ) {
1659                 oldW = w;
1660                 w += tw->cellWidth( c );        // Start of next cell
1661                 if ( xPos < w )
1662                     break;
1663                 c++;
1664             }
1665             if ( cellMaxX )
1666                 *cellMaxX = w - 1;
1667             if ( cellMinX )
1668                 *cellMinX = oldW;
1669         }
1670     }
1671     return c;
1672 }
1673
1674
1675 /*!
1676   Returns the index of the row at position \a yPos, where \a yPos is in
1677   \e widget coordinates.  Returns -1 if \a yPos is outside the valid
1678   range.
1679
1680   \sa findCol(), rowYPos()
1681 */
1682
1683 int QtTableView::findRow( int yPos ) const
1684 {
1685     int cellMaxY;
1686     int row = findRawRow( yPos, &cellMaxY );
1687     if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() )
1688         row = - 1;                              //  cell cut by bottom margin
1689     if ( row >= nRows )
1690         row = -1;
1691     return row;
1692 }
1693
1694
1695 /*!
1696   Returns the index of the column at position \a xPos, where \a xPos is
1697   in \e widget coordinates.  Returns -1 if \a xPos is outside the valid
1698   range.
1699
1700   \sa findRow(), colXPos()
1701 */
1702
1703 int QtTableView::findCol( int xPos ) const
1704 {
1705     int cellMaxX;
1706     int col = findRawCol( xPos, &cellMaxX );
1707     if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() )
1708         col = - 1;                              //  cell cut by right margin
1709     if ( col >= nCols )
1710         col = -1;
1711     return col;
1712 }
1713
1714
1715 /*!
1716   Computes the position in the widget of row \a row.
1717
1718   Returns TRUE and stores the result in \a *yPos (in \e widget
1719   coordinates) if the row is visible.  Returns FALSE and does not modify
1720   \a *yPos if \a row is invisible or invalid.
1721
1722   \sa colXPos(), findRow()
1723 */
1724
1725 bool QtTableView::rowYPos( int row, int *yPos ) const
1726 {
1727     int y;
1728     if ( row >= yCellOffs ) {
1729         if ( cellH ) {
1730             int lastVisible = lastRowVisible();
1731             if ( row > lastVisible || lastVisible == -1 )
1732                 return FALSE;
1733             y = (row - yCellOffs)*cellH + minViewY() - yCellDelta;
1734         } else {
1735             //##arnt3
1736             y = minViewY() - yCellDelta;        // y of leftmost cell in view
1737             int r = yCellOffs;
1738             QtTableView *tw = (QtTableView *)this;
1739             int maxY = maxViewY();
1740             while ( r < row && y <= maxY )
1741                 y += tw->cellHeight( r++ );
1742             if ( y > maxY )
1743                 return FALSE;
1744
1745         }
1746     } else {
1747         return FALSE;
1748     }
1749     if ( yPos )
1750         *yPos = y;
1751     return TRUE;
1752 }
1753
1754
1755 /*!
1756   Computes the position in the widget of column \a col.
1757
1758   Returns TRUE and stores the result in \a *xPos (in \e widget
1759   coordinates) if the column is visible.  Returns FALSE and does not
1760   modify \a *xPos if \a col is invisible or invalid.
1761
1762   \sa rowYPos(), findCol()
1763 */
1764
1765 bool QtTableView::colXPos( int col, int *xPos ) const
1766 {
1767     int x;
1768     if ( col >= xCellOffs ) {
1769         if ( cellW ) {
1770             int lastVisible = lastColVisible();
1771             if ( col > lastVisible || lastVisible == -1 )
1772                 return FALSE;
1773             x = (col - xCellOffs)*cellW + minViewX() - xCellDelta;
1774         } else {
1775             //##arnt3
1776             x = minViewX() - xCellDelta;        // x of uppermost cell in view
1777             int c = xCellOffs;
1778             QtTableView *tw = (QtTableView *)this;
1779             int maxX = maxViewX();
1780             while ( c < col && x <= maxX )
1781                 x += tw->cellWidth( c++ );
1782             if ( x > maxX )
1783                 return FALSE;
1784         }
1785     } else {
1786         return FALSE;
1787     }
1788     if ( xPos )
1789         *xPos = x;
1790     return TRUE;
1791 }
1792
1793
1794 /*!
1795   Moves the visible area of the table right by \a xPixels and
1796   down by \a yPixels pixels.  Both may be negative.
1797
1798   \warning You might find that QScrollView offers a higher-level of
1799         functionality than using QtTableView and this function.
1800
1801   This function is \e not the same as QWidget::scroll(); in particular,
1802   the signs of \a xPixels and \a yPixels have the reverse semantics.
1803
1804   \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
1805   setLeftCell()
1806 */
1807
1808 void QtTableView::scroll( int xPixels, int yPixels )
1809 {
1810     QWidget::scroll( -xPixels, -yPixels, contentsRect() );
1811 }
1812
1813
1814 /*!
1815   Returns the leftmost pixel of the table view in \e view
1816   coordinates.  This excludes the frame and any header.
1817
1818   \sa maxViewY(), viewWidth(), contentsRect()
1819 */
1820
1821 int QtTableView::minViewX() const
1822 {
1823     return frameWidth();
1824 }
1825
1826
1827 /*!
1828   Returns the top pixel of the table view in \e view
1829   coordinates.  This excludes the frame and any header.
1830
1831   \sa maxViewX(), viewHeight(), contentsRect()
1832 */
1833
1834 int QtTableView::minViewY() const
1835 {
1836     return frameWidth();
1837 }
1838
1839
1840 /*!
1841   Returns the rightmost pixel of the table view in \e view
1842   coordinates.  This excludes the frame and any scroll bar, but
1843   includes blank pixels to the right of the visible table data.
1844
1845   \sa maxViewY(), viewWidth(), contentsRect()
1846 */
1847
1848 int QtTableView::maxViewX() const
1849 {
1850     return width() - 1 - frameWidth()
1851         - (tFlags & Tbl_vScrollBar ? VSBEXT
1852            : 0);
1853 }
1854
1855
1856 /*!
1857   Returns the bottom pixel of the table view in \e view
1858   coordinates.  This excludes the frame and any scroll bar, but
1859   includes blank pixels below the visible table data.
1860
1861   \sa maxViewX(), viewHeight(), contentsRect()
1862 */
1863
1864 int QtTableView::maxViewY() const
1865 {
1866     return height() - 1 - frameWidth()
1867         - (tFlags & Tbl_hScrollBar ? HSBEXT
1868            : 0);
1869 }
1870
1871
1872 /*!
1873   Returns the width of the table view, as such, in \e view
1874   coordinates.  This does not include any header, scroll bar or frame,
1875   but it does include background pixels to the right of the table data.
1876
1877   \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
1878 */
1879
1880 int QtTableView::viewWidth() const
1881 {
1882     return maxViewX() - minViewX() + 1;
1883 }
1884
1885
1886 /*!
1887   Returns the height of the table view, as such, in \e view
1888   coordinates.  This does not include any header, scroll bar or frame,
1889   but it does include background pixels below the table data.
1890
1891   \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
1892 */
1893
1894 int QtTableView::viewHeight() const
1895 {
1896     return maxViewY() - minViewY() + 1;
1897 }
1898
1899
1900 void QtTableView::doAutoScrollBars()
1901 {
1902     int viewW = width()  - frameWidth() - minViewX();
1903     int viewH = height() - frameWidth() - minViewY();
1904     bool vScrollOn = testTableFlags(Tbl_vScrollBar);
1905     bool hScrollOn = testTableFlags(Tbl_hScrollBar);
1906     int w = 0;
1907     int h = 0;
1908     int i;
1909
1910     if ( testTableFlags(Tbl_autoHScrollBar) ) {
1911         if ( cellW ) {
1912             w = cellW*nCols;
1913         } else {
1914             i = 0;
1915             while ( i < nCols && w <= viewW )
1916                 w += cellWidth( i++ );
1917         }
1918         if ( w > viewW )
1919             hScrollOn = TRUE;
1920         else
1921             hScrollOn = FALSE;
1922     }
1923
1924     if ( testTableFlags(Tbl_autoVScrollBar) ) {
1925         if ( cellH ) {
1926             h = cellH*nRows;
1927         } else {
1928             i = 0;
1929             while ( i < nRows && h <= viewH )
1930                 h += cellHeight( i++ );
1931         }
1932
1933         if ( h > viewH )
1934             vScrollOn = TRUE;
1935         else
1936             vScrollOn = FALSE;
1937     }
1938
1939     if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn )
1940         if ( w > viewW - VSBEXT )
1941             hScrollOn = TRUE;
1942
1943     if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn )
1944         if ( h > viewH - HSBEXT )
1945             vScrollOn = TRUE;
1946
1947     setHorScrollBar( hScrollOn, FALSE );
1948     setVerScrollBar( vScrollOn, FALSE );
1949     updateFrameSize();
1950 }
1951
1952
1953 /*!
1954   \fn void QtTableView::updateScrollBars()
1955
1956   Updates the scroll bars' contents and presence to match the table's
1957   state.  Generally, you should not need to call this.
1958
1959   \sa setTableFlags()
1960 */
1961
1962 /*!
1963   Updates the scroll bars' contents and presence to match the table's
1964   state \c or \a f.
1965
1966   \sa setTableFlags()
1967 */
1968
1969 void QtTableView::updateScrollBars( uint f )
1970 {
1971     sbDirty = sbDirty | f;
1972     if ( inSbUpdate )
1973         return;
1974     inSbUpdate = TRUE;
1975
1976     if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) ||
1977          testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) )
1978                                         // if range change and auto
1979         doAutoScrollBars();             // turn scroll bars on/off if needed
1980
1981     if ( !autoUpdate() ) {
1982         inSbUpdate = FALSE;
1983         return;
1984     }
1985     if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) &&
1986          !testTableFlags( Tbl_vScrollBar ) ) {
1987         setYOffset( 0 );
1988     }
1989     if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) &&
1990          !testTableFlags( Tbl_hScrollBar ) ) {
1991         setXOffset( 0 );
1992     }
1993     if ( !isVisible() ) {
1994         inSbUpdate = FALSE;
1995         return;
1996     }
1997
1998     if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) {
1999         if ( sbDirty & horGeometry )
2000             hScrollBar->setGeometry( 0,height() - HSBEXT,
2001                                      viewWidth() + frameWidth()*2,
2002                                    HSBEXT);
2003
2004         if ( sbDirty & horSteps ) {
2005             if ( cellW )
2006                 hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() );
2007             else
2008                 hScrollBar->setSteps( 16, viewWidth() );
2009         }
2010
2011         if ( sbDirty & horRange )
2012             hScrollBar->setRange( 0, maxXOffset() );
2013
2014         if ( sbDirty & horValue )
2015             hScrollBar->setValue( xOffs );
2016
2017                         // show scrollbar only when it has a sane geometry
2018         if ( !hScrollBar->isVisible() )
2019             hScrollBar->show();
2020     }
2021
2022     if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) {
2023         if ( sbDirty & verGeometry )
2024             vScrollBar->setGeometry( width() - VSBEXT, 0,
2025                                      VSBEXT,
2026                                      viewHeight() + frameWidth()*2 );
2027
2028         if ( sbDirty & verSteps ) {
2029             if ( cellH )
2030                 vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() );
2031             else
2032                 vScrollBar->setSteps( 16, viewHeight() );  // fttb! ###
2033         }
2034
2035         if ( sbDirty & verRange )
2036             vScrollBar->setRange( 0, maxYOffset() );
2037
2038         if ( sbDirty & verValue )
2039             vScrollBar->setValue( yOffs );
2040
2041                         // show scrollbar only when it has a sane geometry
2042         if ( !vScrollBar->isVisible() )
2043             vScrollBar->show();
2044     }
2045     if ( coveringCornerSquare &&
2046          ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) )
2047         cornerSquare->move( maxViewX() + frameWidth() + 1,
2048                             maxViewY() + frameWidth() + 1 );
2049
2050     sbDirty = 0;
2051     inSbUpdate = FALSE;
2052 }
2053
2054
2055 void QtTableView::updateFrameSize()
2056 {
2057     int rw = width()  - ( testTableFlags(Tbl_vScrollBar) ?
2058                           VSBEXT : 0 );
2059     int rh = height() - ( testTableFlags(Tbl_hScrollBar) ?
2060                           HSBEXT : 0 );
2061     if ( rw < 0 )
2062         rw = 0;
2063     if ( rh < 0 )
2064         rh = 0;
2065
2066     if ( autoUpdate() ) {
2067         int fh = frameRect().height();
2068         int fw = frameRect().width();
2069         setFrameRect( QRect(0,0,rw,rh) );
2070
2071         if ( rw != fw )
2072             update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh );
2073         if ( rh != fh )
2074             update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 );
2075     }
2076 }
2077
2078
2079 /*!
2080   Returns the maximum horizontal offset within the table of the
2081   view's left edge in \e table coordinates.
2082
2083   This is used mainly to set the horizontal scroll bar's range.
2084
2085   \sa maxColOffset(), maxYOffset(), totalWidth()
2086 */
2087
2088 int QtTableView::maxXOffset()
2089 {
2090     int tw = totalWidth();
2091     int maxOffs;
2092     if ( testTableFlags(Tbl_scrollLastHCell) ) {
2093         if ( nCols != 1)
2094             maxOffs =  tw - ( cellW ? cellW : cellWidth( nCols - 1 ) );
2095         else
2096             maxOffs = tw - viewWidth();
2097     } else {
2098         if ( testTableFlags(Tbl_snapToHGrid) ) {
2099             if ( cellW ) {
2100                 maxOffs =  tw - (viewWidth()/cellW)*cellW;
2101             } else {
2102                 int goal = tw - viewWidth();
2103                 int pos = tw;
2104                 int nextCol = nCols - 1;
2105                 int nextCellWidth = cellWidth( nextCol );
2106                 while ( nextCol > 0 && pos > goal + nextCellWidth ) {
2107                     pos -= nextCellWidth;
2108                     nextCellWidth = cellWidth( --nextCol );
2109                 }
2110                 if ( goal + nextCellWidth == pos )
2111                     maxOffs = goal;
2112                  else if ( goal < pos )
2113                    maxOffs = pos;
2114                  else
2115                    maxOffs = 0;
2116             }
2117         } else {
2118             maxOffs = tw - viewWidth();
2119         }
2120     }
2121     return maxOffs > 0 ? maxOffs : 0;
2122 }
2123
2124
2125 /*!
2126   Returns the maximum vertical offset within the table of the
2127   view's top edge in \e table coordinates.
2128
2129   This is used mainly to set the vertical scroll bar's range.
2130
2131   \sa maxRowOffset(), maxXOffset(), totalHeight()
2132 */
2133
2134 int QtTableView::maxYOffset()
2135 {
2136     int th = totalHeight();
2137     int maxOffs;
2138     if ( testTableFlags(Tbl_scrollLastVCell) ) {
2139         if ( nRows != 1)
2140             maxOffs =  th - ( cellH ? cellH : cellHeight( nRows - 1 ) );
2141         else
2142             maxOffs = th - viewHeight();
2143     } else {
2144         if ( testTableFlags(Tbl_snapToVGrid) ) {
2145             if ( cellH ) {
2146                 maxOffs =  th - (viewHeight()/cellH)*cellH;
2147             } else {
2148                 int goal = th - viewHeight();
2149                 int pos = th;
2150                 int nextRow = nRows - 1;
2151                 int nextCellHeight = cellHeight( nextRow );
2152                 while ( nextRow > 0 && pos > goal + nextCellHeight ) {
2153                     pos -= nextCellHeight;
2154                     nextCellHeight = cellHeight( --nextRow );
2155                 }
2156                 if ( goal + nextCellHeight == pos )
2157                     maxOffs = goal;
2158                  else if ( goal < pos )
2159                    maxOffs = pos;
2160                  else
2161                    maxOffs = 0;
2162             }
2163         } else {
2164             maxOffs = th - viewHeight();
2165         }
2166     }
2167     return maxOffs > 0 ? maxOffs : 0;
2168 }
2169
2170
2171 /*!
2172   Returns the index of the last column, which may be at the left edge
2173   of the view.
2174
2175   Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
2176   this may or may not be the last column.
2177
2178   \sa maxXOffset(), maxRowOffset()
2179 */
2180
2181 int QtTableView::maxColOffset()
2182 {
2183     int mx = maxXOffset();
2184     if ( cellW )
2185         return mx/cellW;
2186     else {
2187         int xcd=0, col=0;
2188         while ( col < nCols && mx > (xcd=cellWidth(col)) ) {
2189             mx -= xcd;
2190             col++;
2191         }
2192         return col;
2193     }
2194 }
2195
2196
2197 /*!
2198   Returns the index of the last row, which may be at the top edge of
2199   the view.
2200
2201   Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
2202   this may or may not be the last row.
2203
2204   \sa maxYOffset(), maxColOffset()
2205 */
2206
2207 int QtTableView::maxRowOffset()
2208 {
2209     int my = maxYOffset();
2210     if ( cellH )
2211         return my/cellH;
2212     else {
2213         int ycd=0, row=0;
2214         while ( row < nRows && my > (ycd=cellHeight(row)) ) {
2215             my -= ycd;
2216             row++;
2217         }
2218         return row;
2219     }
2220 }
2221
2222
2223 void QtTableView::showOrHideScrollBars()
2224 {
2225     if ( !autoUpdate() )
2226         return;
2227     if ( vScrollBar ) {
2228         if ( testTableFlags(Tbl_vScrollBar) ) {
2229             if ( !vScrollBar->isVisible() )
2230                 sbDirty = sbDirty | verMask;
2231         } else {
2232             if ( vScrollBar->isVisible() )
2233                vScrollBar->hide();
2234         }
2235     }
2236     if ( hScrollBar ) {
2237         if ( testTableFlags(Tbl_hScrollBar) ) {
2238             if ( !hScrollBar->isVisible() )
2239                 sbDirty = sbDirty | horMask;
2240         } else {
2241             if ( hScrollBar->isVisible() )
2242                 hScrollBar->hide();
2243         }
2244     }
2245     if ( cornerSquare ) {
2246         if ( testTableFlags(Tbl_hScrollBar) &&
2247              testTableFlags(Tbl_vScrollBar) ) {
2248             if ( !cornerSquare->isVisible() )
2249                 cornerSquare->show();
2250         } else {
2251             if ( cornerSquare->isVisible() )
2252                 cornerSquare->hide();
2253         }
2254     }
2255 }
2256
2257
2258 /*!
2259   Updates the scroll bars and internal state.
2260
2261   Call this function when the table view's total size is changed;
2262   typically because the result of cellHeight() or cellWidth() have changed.
2263
2264   This function does not repaint the widget.
2265 */
2266
2267 void QtTableView::updateTableSize()
2268 {
2269     bool updateOn = autoUpdate();
2270     setAutoUpdate( FALSE );
2271     int xofs = xOffset();
2272     xOffs++; //so that setOffset will not return immediately
2273     setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly
2274     setAutoUpdate(updateOn);
2275
2276     updateScrollBars( horSteps |  horRange |
2277                       verSteps |  verRange );
2278     showOrHideScrollBars();
2279 }
2280
2281
2282 #endif