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