Warning, file /sdk/cervisia/qttableview.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /**********************************************************************
0002 ** $Id$
0003 **
0004 ** Implementation of QtTableView class
0005 **
0006 ** Created : 941115
0007 **
0008 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
0009 **
0010 ** This file contains a class moved out of the Qt GUI Toolkit API. It
0011 ** may be used, distributed and modified without limitation.
0012 **
0013 **********************************************************************/
0014 
0015 #include "qttableview.h"
0016 #include <climits>
0017 #include <qapplication.h>
0018 #include <qdrawutil.h>
0019 #include <qevent.h>
0020 #include <qpainter.h>
0021 #include <qscrollbar.h>
0022 
0023 enum ScrollBarDirtyFlags {
0024     verGeometry = 0x01,
0025     verSteps = 0x02,
0026     verRange = 0x04,
0027     verValue = 0x08,
0028     horGeometry = 0x10,
0029     horSteps = 0x20,
0030     horRange = 0x40,
0031     horValue = 0x80,
0032     verMask = 0x0F,
0033     horMask = 0xF0
0034 };
0035 
0036 #define HSBEXT horizontalScrollBar()->sizeHint().height()
0037 #define VSBEXT verticalScrollBar()->sizeHint().width()
0038 
0039 class QCornerSquare : public QWidget // internal class
0040 {
0041 public:
0042     QCornerSquare(QWidget *);
0043 };
0044 
0045 QCornerSquare::QCornerSquare(QWidget *parent)
0046     : QWidget(parent)
0047 {
0048     setAutoFillBackground(true);
0049 }
0050 
0051 // NOT REVISED
0052 /*!
0053   \class QtTableView qttableview.h
0054   \brief The QtTableView class provides an abstract base for tables.
0055 
0056   \obsolete
0057 
0058   A table view consists of a number of abstract cells organized in rows
0059   and columns, and a visible part called a view. The cells are identified
0060   with a row index and a column index. The top-left cell is in row 0,
0061   column 0.
0062 
0063   The behavior of the widget can be finely tuned using
0064   setTableFlags(); a typical subclass will consist of little more than a
0065   call to setTableFlags(), some table content manipulation and an
0066   implementation of paintCell().  Subclasses that need cells with
0067   variable width or height must reimplement cellHeight() and/or
0068   cellWidth(). Use updateTableSize() to tell QtTableView when the
0069   width or height has changed.
0070 
0071   When you read this documentation, it is important to understand the
0072   distinctions among the four pixel coordinate systems involved.
0073 
0074   \list 1
0075   \i The \e cell coordinates.  (0,0) is the top-left corner of a cell.
0076   Cell coordinates are used by functions such as paintCell().
0077 
0078   \i The \e table coordinates.  (0,0) is the top-left corner of the cell at
0079   row 0 and column 0. These coordinates are absolute; that is, they are
0080   independent of what part of the table is visible at the moment. They are
0081   used by functions such as setXOffset() or maxYOffset().
0082 
0083   \i The \e widget coordinates. (0,0) is the top-left corner of the widget,
0084   \e including the frame.  They are used by functions such as repaint().
0085 
0086   \i The \e view coordinates.  (0,0) is the top-left corner of the view, \e
0087   excluding the frame.  This is the least-used coordinate system; it is used by
0088   functions such as viewWidth().  \endlist
0089 
0090   It is rather unfortunate that we have to use four different
0091   coordinate systems, but there was no alternative to provide a flexible and
0092   powerful base class.
0093 
0094   Note: The row,column indices are always given in that order,
0095   i.e., first the vertical (row), then the horizontal (column). This is
0096   the opposite order of all pixel operations, which take first the
0097   horizontal (x) and then the vertical (y).
0098 
0099   <img src=qtablevw-m.png> <img src=qtablevw-w.png>
0100 
0101   \warning the functions setNumRows(), setNumCols(), setCellHeight(),
0102   setCellWidth(), setTableFlags() and clearTableFlags() may cause
0103   virtual functions such as cellWidth() and cellHeight() to be called,
0104   even if autoUpdate() is 'false'.  This may cause errors if relevant
0105   state variables are not initialized.
0106 
0107   \warning Experience has shown that use of this widget tends to cause
0108   more bugs than expected and our analysis indicates that the widget's
0109   very flexibility is the problem.  If QScrollView or QListBox can
0110   easily be made to do the job you need, we recommend subclassing
0111   those widgets rather than QtTableView. In addition, QScrollView makes
0112   it easy to have child widgets inside tables, which QtTableView
0113   doesn't support at all.
0114 
0115   \sa QScrollView
0116   \link guibooks.html#fowler GUI Design Handbook: Table\endlink
0117 */
0118 
0119 /*!
0120   Constructs a table view.  The \a parent, \a name and \f arguments
0121   are passed to the QFrame constructor.
0122 
0123   The \link setTableFlags() table flags\endlink are all cleared (set to 0).
0124   Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll
0125   bars and \c Tbl_clipCellPainting to get safe clipping.
0126 
0127   The \link setCellHeight() cell height\endlink and \link setCellWidth()
0128   cell width\endlink are set to 0.
0129 
0130   Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed;
0131   see QFrame::setFrameStyle().
0132 
0133   Note that the \a f argument is \e not \link setTableFlags() table
0134   flags \endlink but rather \link QWidget::QWidget() widget
0135   flags. \endlink
0136 
0137 */
0138 
0139 QtTableView::QtTableView(QWidget *parent, const char *name)
0140     : QFrame(parent)
0141 {
0142     nRows = nCols = 0; // zero rows/cols
0143     xCellOffs = yCellOffs = 0; // zero offset
0144     xCellDelta = yCellDelta = 0; // zero cell offset
0145     xOffs = yOffs = 0; // zero total pixel offset
0146     cellH = cellW = 0; // user defined cell size
0147     tFlags = 0;
0148     vScrollBar = hScrollBar = 0; // no scroll bars
0149     cornerSquare = 0;
0150     sbDirty = 0;
0151     eraseInPaint = false;
0152     verSliding = false;
0153     verSnappingOff = false;
0154     horSliding = false;
0155     horSnappingOff = false;
0156     coveringCornerSquare = false;
0157     inSbUpdate = false;
0158 
0159     setAttribute(Qt::WA_OpaquePaintEvent, true);
0160     setObjectName(name);
0161 }
0162 
0163 /*!
0164   Destroys the table view.
0165 */
0166 
0167 QtTableView::~QtTableView()
0168 {
0169     delete vScrollBar;
0170     delete hScrollBar;
0171     delete cornerSquare;
0172 }
0173 
0174 /*!
0175   \overload void QtTableView::repaint( bool erase )
0176   Repaints the entire view.
0177 */
0178 
0179 /*!
0180   Repaints the table view directly by calling paintEvent() directly
0181   unless updates are disabled.
0182 
0183   Erases the view area \a (x,y,w,h) if \a erase is 'true'. Parameters \a
0184   (x,y) are in \e widget coordinates.
0185 
0186   If \a w is negative, it is replaced with <code>width() - x</code>.
0187   If \a h is negative, it is replaced with <code>height() - y</code>.
0188 
0189   Doing a repaint() usually is faster than doing an update(), but
0190   calling update() many times in a row will generate a single paint
0191   event.
0192 
0193   At present, QtTableView is the only widget that reimplements \link
0194   QWidget::repaint() repaint()\endlink.  It does this because by
0195   clearing and then repainting one cell at at time, it can make the
0196   screen flicker less than it would otherwise.  */
0197 
0198 void QtTableView::repaint(int x, int y, int w, int h, bool erase)
0199 {
0200     if (!isVisible())
0201         return;
0202     if (w < 0)
0203         w = width() - x;
0204     if (h < 0)
0205         h = height() - y;
0206     QRect r(x, y, w, h);
0207     if (r.isEmpty())
0208         return; // nothing to do
0209     if (erase && testAttribute(Qt::WA_OpaquePaintEvent))
0210         eraseInPaint = true; // erase when painting
0211     QWidget::repaint(r);
0212     eraseInPaint = false;
0213 }
0214 
0215 /*!
0216   \overload void QtTableView::repaint( const QRect &r, bool erase )
0217   Repaints rectangle \a r. If \a erase is 'true' draws the background
0218   using the palette's background.
0219 */
0220 
0221 /*!
0222   \fn int QtTableView::numRows() const
0223   Returns the number of rows in the table.
0224   \sa numCols(), setNumRows()
0225 */
0226 
0227 /*!
0228   Sets the number of rows of the table to \a rows (must be non-negative).
0229   Does not change topCell().
0230 
0231   The table repaints itself automatically if autoUpdate() is set.
0232 
0233   \sa numCols(), setNumCols(), numRows()
0234 */
0235 
0236 void QtTableView::setNumRows(int rows)
0237 {
0238     if (rows < 0) {
0239 #if defined(QT_CHECK_RANGE)
0240         qWarning("QtTableView::setNumRows: (%s) Negative argument %d.", name("unnamed"), rows);
0241 #endif
0242         return;
0243     }
0244     if (nRows == rows)
0245         return;
0246 
0247     if (autoUpdate() && isVisible()) {
0248         int oldLastVisible = lastRowVisible();
0249         int oldTopCell = topCell();
0250         nRows = rows;
0251         if (autoUpdate() && isVisible() && (oldLastVisible != lastRowVisible() || oldTopCell != topCell()))
0252             repaint(oldTopCell != topCell());
0253     } else {
0254         // Be more careful - if destructing, bad things might happen.
0255         nRows = rows;
0256     }
0257     updateScrollBars(verRange);
0258     updateFrameSize();
0259 }
0260 
0261 /*!
0262   \fn int QtTableView::numCols() const
0263   Returns the number of columns in the table.
0264   \sa numRows(), setNumCols()
0265 */
0266 
0267 /*!
0268   Sets the number of columns of the table to \a cols (must be non-negative).
0269   Does not change leftCell().
0270 
0271   The table repaints itself automatically if autoUpdate() is set.
0272 
0273   \sa numCols(), numRows(), setNumRows()
0274 */
0275 
0276 void QtTableView::setNumCols(int cols)
0277 {
0278     if (cols < 0) {
0279 #if defined(QT_CHECK_RANGE)
0280         qWarning("QtTableView::setNumCols: (%s) Negative argument %d.", name("unnamed"), cols);
0281 #endif
0282         return;
0283     }
0284     if (nCols == cols)
0285         return;
0286     int oldCols = nCols;
0287     nCols = cols;
0288     if (autoUpdate() && isVisible()) {
0289         int maxCol = lastColVisible();
0290         if (maxCol >= oldCols || maxCol >= nCols)
0291             repaint();
0292     }
0293     updateScrollBars(horRange);
0294     updateFrameSize();
0295 }
0296 
0297 /*!
0298   \fn int QtTableView::topCell() const
0299   Returns the index of the first row in the table that is visible in
0300   the view.  The index of the first row is 0.
0301   \sa leftCell(), setTopCell()
0302 */
0303 
0304 /*!
0305   Scrolls the table so that \a row becomes the top row.
0306   The index of the very first row is 0.
0307   \sa setYOffset(), setTopLeftCell(), setLeftCell()
0308 */
0309 
0310 void QtTableView::setTopCell(int row)
0311 {
0312     setTopLeftCell(row, -1);
0313     return;
0314 }
0315 
0316 /*!
0317   \fn int QtTableView::leftCell() const
0318   Returns the index of the first column in the table that is visible in
0319   the view.  The index of the very leftmost column is 0.
0320   \sa topCell(), setLeftCell()
0321 */
0322 
0323 /*!
0324   Scrolls the table so that \a col becomes the leftmost
0325   column.  The index of the leftmost column is 0.
0326   \sa setXOffset(), setTopLeftCell(), setTopCell()
0327 */
0328 
0329 void QtTableView::setLeftCell(int col)
0330 {
0331     setTopLeftCell(-1, col);
0332     return;
0333 }
0334 
0335 /*!
0336   Scrolls the table so that the cell at row \a row and column \a
0337   col becomes the top-left cell in the view.  The cell at the extreme
0338   top left of the table is at position (0,0).
0339   \sa setLeftCell(), setTopCell(), setOffset()
0340 */
0341 
0342 void QtTableView::setTopLeftCell(int row, int col)
0343 {
0344     int newX = xOffs;
0345     int newY = yOffs;
0346 
0347     if (col >= 0) {
0348         if (cellW) {
0349             newX = col * cellW;
0350             if (newX > maxXOffset())
0351                 newX = maxXOffset();
0352         } else {
0353             newX = 0;
0354             while (col)
0355                 newX += cellWidth(--col); // optimize using current! ###
0356         }
0357     }
0358     if (row >= 0) {
0359         if (cellH) {
0360             newY = row * cellH;
0361             if (newY > maxYOffset())
0362                 newY = maxYOffset();
0363         } else {
0364             newY = 0;
0365             while (row)
0366                 newY += cellHeight(--row); // optimize using current! ###
0367         }
0368     }
0369     setOffset(newX, newY);
0370 }
0371 
0372 /*!
0373   \fn int QtTableView::xOffset() const
0374 
0375   Returns the x coordinate in \e table coordinates of the pixel that is
0376   currently on the left edge of the view.
0377 
0378   \sa setXOffset(), yOffset(), leftCell() */
0379 
0380 /*!
0381   Scrolls the table so that \a x becomes the leftmost pixel in the view.
0382   The \a x parameter is in \e table coordinates.
0383 
0384   The interaction with \link setTableFlags() Tbl_snapToHGrid
0385   \endlink is tricky.
0386 
0387   \sa xOffset(), setYOffset(), setOffset(), setLeftCell()
0388 */
0389 
0390 void QtTableView::setXOffset(int x)
0391 {
0392     setOffset(x, yOffset());
0393 }
0394 
0395 /*!
0396   \fn int QtTableView::yOffset() const
0397 
0398   Returns the y coordinate in \e table coordinates of the pixel that is
0399   currently on the top edge of the view.
0400 
0401   \sa setYOffset(), xOffset(), topCell()
0402 */
0403 
0404 /*!
0405   Scrolls the table so that \a y becomes the top pixel in the view.
0406   The \a y parameter is in \e table coordinates.
0407 
0408   The interaction with \link setTableFlags() Tbl_snapToVGrid
0409   \endlink is tricky.
0410 
0411   \sa yOffset(), setXOffset(), setOffset(), setTopCell()
0412 */
0413 
0414 void QtTableView::setYOffset(int y)
0415 {
0416     setOffset(xOffset(), y);
0417 }
0418 
0419 /*!
0420   Scrolls the table so that \a (x,y) becomes the top-left pixel
0421   in the view. Parameters \a (x,y) are in \e table coordinates.
0422 
0423   The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink
0424   is tricky.  If \a updateScrBars is 'true', the scroll bars are
0425   updated.
0426 
0427   \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell()
0428 */
0429 
0430 void QtTableView::setOffset(int x, int y, bool updateScrBars)
0431 {
0432     if ((!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) && (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) && (x == xOffs && y == yOffs))
0433         return;
0434 
0435     if (x < 0)
0436         x = 0;
0437     if (y < 0)
0438         y = 0;
0439 
0440     if (cellW) {
0441         if (x > maxXOffset())
0442             x = maxXOffset();
0443         xCellOffs = x / cellW;
0444         if (!testTableFlags(Tbl_snapToHGrid)) {
0445             xCellDelta = (short)(x % cellW);
0446         } else {
0447             x = xCellOffs * cellW;
0448             xCellDelta = 0;
0449         }
0450     } else {
0451         int xn = 0, xcd = 0, col = 0;
0452         while (col < nCols - 1 && x >= xn + (xcd = cellWidth(col))) {
0453             xn += xcd;
0454             col++;
0455         }
0456         xCellOffs = col;
0457         if (testTableFlags(Tbl_snapToHGrid)) {
0458             xCellDelta = 0;
0459             x = xn;
0460         } else {
0461             xCellDelta = (short)(x - xn);
0462         }
0463     }
0464     if (cellH) {
0465         if (y > maxYOffset())
0466             y = maxYOffset();
0467         yCellOffs = y / cellH;
0468         if (!testTableFlags(Tbl_snapToVGrid)) {
0469             yCellDelta = (short)(y % cellH);
0470         } else {
0471             y = yCellOffs * cellH;
0472             yCellDelta = 0;
0473         }
0474     } else {
0475         int yn = 0, yrd = 0, row = 0;
0476         while (row < nRows - 1 && y >= yn + (yrd = cellHeight(row))) {
0477             yn += yrd;
0478             row++;
0479         }
0480         yCellOffs = row;
0481         if (testTableFlags(Tbl_snapToVGrid)) {
0482             yCellDelta = 0;
0483             y = yn;
0484         } else {
0485             yCellDelta = (short)(y - yn);
0486         }
0487     }
0488     int dx = (x - xOffs);
0489     int dy = (y - yOffs);
0490     xOffs = x;
0491     yOffs = y;
0492     if (autoUpdate() && isVisible())
0493         scroll(dx, dy);
0494     if (updateScrBars)
0495         updateScrollBars(verValue | horValue);
0496 }
0497 
0498 /*!
0499   \overload int QtTableView::cellWidth() const
0500 
0501   Returns the column width in pixels.   Returns 0 if the columns have
0502   variable widths.
0503 
0504   \sa setCellWidth(), cellHeight()
0505 */
0506 
0507 /*!
0508   Returns the width of column \a col in pixels.
0509 
0510   This function is virtual and must be reimplemented by subclasses that
0511   have variable cell widths. Note that if the total table width
0512   changes, updateTableSize() must be called.
0513 
0514   \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize()
0515 */
0516 
0517 int QtTableView::cellWidth(int)
0518 {
0519     return cellW;
0520 }
0521 
0522 /*!
0523   Sets the width in pixels of the table cells to \a cellWidth.
0524 
0525   Setting it to 0 means that the column width is variable.  When
0526   set to 0 (this is the default) QtTableView calls the virtual function
0527   cellWidth() to get the width.
0528 
0529   \sa cellWidth(), setCellHeight(), totalWidth(), numCols()
0530 */
0531 
0532 void QtTableView::setCellWidth(int cellWidth)
0533 {
0534     if (cellW == cellWidth)
0535         return;
0536 #if defined(QT_CHECK_RANGE)
0537     if (cellWidth < 0 || cellWidth > SHRT_MAX) {
0538         qWarning("QtTableView::setCellWidth: (%s) Argument out of range (%d)", name("unnamed"), cellWidth);
0539         return;
0540     }
0541 #endif
0542     cellW = (short)cellWidth;
0543 
0544     updateScrollBars(horSteps | horRange);
0545     if (autoUpdate() && isVisible())
0546         repaint();
0547 }
0548 
0549 /*!
0550   \overload int QtTableView::cellHeight() const
0551 
0552   Returns the row height, in pixels.  Returns 0 if the rows have
0553   variable heights.
0554 
0555   \sa setCellHeight(), cellWidth()
0556 */
0557 
0558 /*!
0559   Returns the height of row \a row in pixels.
0560 
0561   This function is virtual and must be reimplemented by subclasses that
0562   have variable cell heights.  Note that if the total table height
0563   changes, updateTableSize() must be called.
0564 
0565   \sa setCellHeight(), cellWidth(), totalHeight()
0566 */
0567 
0568 int QtTableView::cellHeight(int)
0569 {
0570     return cellH;
0571 }
0572 
0573 /*!
0574   Sets the height in pixels of the table cells to \a cellHeight.
0575 
0576   Setting it to 0 means that the row height is variable.  When set
0577   to 0 (this is the default), QtTableView calls the virtual function
0578   cellHeight() to get the height.
0579 
0580   \sa cellHeight(), setCellWidth(), totalHeight(), numRows()
0581 */
0582 
0583 void QtTableView::setCellHeight(int cellHeight)
0584 {
0585     if (cellH == cellHeight)
0586         return;
0587 #if defined(QT_CHECK_RANGE)
0588     if (cellHeight < 0 || cellHeight > SHRT_MAX) {
0589         qWarning("QtTableView::setCellHeight: (%s) Argument out of range (%d)", name("unnamed"), cellHeight);
0590         return;
0591     }
0592 #endif
0593     cellH = (short)cellHeight;
0594     if (autoUpdate() && isVisible())
0595         repaint();
0596     updateScrollBars(verSteps | verRange);
0597 }
0598 
0599 /*!
0600   Returns the total width of the table in pixels.
0601 
0602   This function is virtual and should be reimplemented by subclasses that
0603   have variable cell widths and a non-trivial cellWidth() function, or a
0604   large number of columns in the table.
0605 
0606   The default implementation may be slow for very wide tables.
0607 
0608   \sa cellWidth(), totalHeight() */
0609 
0610 int QtTableView::totalWidth()
0611 {
0612     if (cellW) {
0613         return cellW * nCols;
0614     } else {
0615         int tw = 0;
0616         for (int i = 0; i < nCols; i++)
0617             tw += cellWidth(i);
0618         return tw;
0619     }
0620 }
0621 
0622 /*!
0623   Returns the total height of the table in pixels.
0624 
0625   This function is virtual and should be reimplemented by subclasses that
0626   have variable cell heights and a non-trivial cellHeight() function, or a
0627   large number of rows in the table.
0628 
0629   The default implementation may be slow for very tall tables.
0630 
0631   \sa cellHeight(), totalWidth()
0632 */
0633 
0634 int QtTableView::totalHeight()
0635 {
0636     if (cellH) {
0637         return cellH * nRows;
0638     } else {
0639         int th = 0;
0640         for (int i = 0; i < nRows; i++)
0641             th += cellHeight(i);
0642         return th;
0643     }
0644 }
0645 
0646 /*!
0647   \fn uint QtTableView::tableFlags() const
0648 
0649   Returns the union of the table flags that are currently set.
0650 
0651   \sa setTableFlags(), clearTableFlags(), testTableFlags()
0652 */
0653 
0654 /*!
0655   \fn bool QtTableView::testTableFlags( uint f ) const
0656 
0657   Returns 'true' if any of the table flags in \a f are currently set,
0658   otherwise 'false'.
0659 
0660   \sa setTableFlags(), clearTableFlags(), tableFlags()
0661 */
0662 
0663 /*!
0664   Sets the table flags to \a f.
0665 
0666   If a flag setting changes the appearance of the table, the table is
0667   repainted if - and only if - autoUpdate() is 'true'.
0668 
0669   The table flags are mostly single bits, though there are some multibit
0670   flags for convenience. Here is a complete list:
0671 
0672   <dl compact>
0673   <dt> Tbl_vScrollBar <dd> - The table has a vertical scroll bar.
0674   <dt> Tbl_hScrollBar <dd> - The table has a horizontal scroll bar.
0675   <dt> Tbl_autoVScrollBar <dd> - The table has a vertical scroll bar if
0676   - and only if - the table is taller than the view.
0677   <dt> Tbl_autoHScrollBar <dd> The table has a horizontal scroll bar if
0678   - and only if - the table is wider than the view.
0679   <dt> Tbl_autoScrollBars <dd> - The union of the previous two flags.
0680   <dt> Tbl_clipCellPainting <dd> - The table uses QPainter::setClipRect() to
0681   make sure that paintCell() will not draw outside the cell
0682   boundaries.
0683   <dt> Tbl_cutCellsV <dd> - The table will never show part of a
0684   cell at the bottom of the table; if there is not space for all of
0685   a cell, the space is left blank.
0686   <dt> Tbl_cutCellsH <dd> - The table will never show part of a
0687   cell at the right side of the table; if there is not space for all of
0688   a cell, the space is left blank.
0689   <dt> Tbl_cutCells <dd> - The union of the previous two flags.
0690   <dt> Tbl_scrollLastHCell <dd> - When the user scrolls horizontally,
0691   let him/her scroll the last cell left until it is at the left
0692   edge of the view.  If this flag is not set, the user can only scroll
0693   to the point where the last cell is completely visible.
0694   <dt> Tbl_scrollLastVCell <dd> - When the user scrolls vertically, let
0695   him/her scroll the last cell up until it is at the top edge of
0696   the view.  If this flag is not set, the user can only scroll to the
0697   point where the last cell is completely visible.
0698   <dt> Tbl_scrollLastCell <dd> - The union of the previous two flags.
0699   <dt> Tbl_smoothHScrolling <dd> - The table scrolls as smoothly as
0700   possible when the user scrolls horizontally. When this flag is not
0701   set, scrolling is done one cell at a time.
0702   <dt> Tbl_smoothVScrolling <dd> - The table scrolls as smoothly as
0703   possible when scrolling vertically. When this flag is not set,
0704   scrolling is done one cell at a time.
0705   <dt> Tbl_smoothScrolling <dd> - The union of the previous two flags.
0706   <dt> Tbl_snapToHGrid <dd> - Except when the user is actually scrolling,
0707   the leftmost column shown snaps to the leftmost edge of the view.
0708   <dt> Tbl_snapToVGrid <dd> - Except when the user is actually
0709   scrolling, the top row snaps to the top edge of the view.
0710   <dt> Tbl_snapToGrid <dd> - The union of the previous two flags.
0711   </dl>
0712 
0713   You can specify more than one flag at a time using bitwise OR.
0714 
0715   Example:
0716   \code
0717     setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars );
0718   \endcode
0719 
0720   \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and
0721   Tbl_cutCellsV) may cause painting problems when scrollbars are
0722   enabled. Do not combine cutCells and scrollbars.
0723 
0724 
0725   \sa clearTableFlags(), testTableFlags(), tableFlags()
0726 */
0727 
0728 void QtTableView::setTableFlags(uint f)
0729 {
0730     f = (f ^ tFlags) & f; // clear flags already set
0731     tFlags |= f;
0732 
0733     bool updateOn = autoUpdate();
0734     setAutoUpdate(false);
0735 
0736     uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
0737 
0738     if (f & Tbl_vScrollBar) {
0739         setVerScrollBar(true);
0740     }
0741     if (f & Tbl_hScrollBar) {
0742         setHorScrollBar(true);
0743     }
0744     if (f & Tbl_autoVScrollBar) {
0745         updateScrollBars(verRange);
0746     }
0747     if (f & Tbl_autoHScrollBar) {
0748         updateScrollBars(horRange);
0749     }
0750     if (f & Tbl_scrollLastHCell) {
0751         updateScrollBars(horRange);
0752     }
0753     if (f & Tbl_scrollLastVCell) {
0754         updateScrollBars(verRange);
0755     }
0756     if (f & Tbl_snapToHGrid) {
0757         updateScrollBars(horRange);
0758     }
0759     if (f & Tbl_snapToVGrid) {
0760         updateScrollBars(verRange);
0761     }
0762     if (f & Tbl_snapToGrid) { // Note: checks for 2 flags
0763         if ((f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || // have to scroll?
0764             (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0) {
0765             snapToGrid((f & Tbl_snapToHGrid) != 0, // do snapping
0766                        (f & Tbl_snapToVGrid) != 0);
0767             repaintMask |= Tbl_snapToGrid; // repaint table
0768         }
0769     }
0770 
0771     if (updateOn) {
0772         setAutoUpdate(true);
0773         updateScrollBars();
0774         if (isVisible() && (f & repaintMask))
0775             repaint();
0776     }
0777 }
0778 
0779 /*!
0780   Clears the \link setTableFlags() table flags\endlink that are set
0781   in \a f.
0782 
0783   Example (clears a single flag):
0784   \code
0785     clearTableFlags( Tbl_snapToGrid );
0786   \endcode
0787 
0788   The default argument clears all flags.
0789 
0790   \sa setTableFlags(), testTableFlags(), tableFlags()
0791 */
0792 
0793 void QtTableView::clearTableFlags(uint f)
0794 {
0795     f = (f ^ ~tFlags) & f; // clear flags that are already 0
0796     tFlags &= ~f;
0797 
0798     bool updateOn = autoUpdate();
0799     setAutoUpdate(false);
0800 
0801     uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
0802 
0803     if (f & Tbl_vScrollBar) {
0804         setVerScrollBar(false);
0805     }
0806     if (f & Tbl_hScrollBar) {
0807         setHorScrollBar(false);
0808     }
0809     if (f & Tbl_scrollLastHCell) {
0810         int maxX = maxXOffset();
0811         if (xOffs > maxX) {
0812             setOffset(maxX, yOffs);
0813             repaintMask |= Tbl_scrollLastHCell;
0814         }
0815         updateScrollBars(horRange);
0816     }
0817     if (f & Tbl_scrollLastVCell) {
0818         int maxY = maxYOffset();
0819         if (yOffs > maxY) {
0820             setOffset(xOffs, maxY);
0821             repaintMask |= Tbl_scrollLastVCell;
0822         }
0823         updateScrollBars(verRange);
0824     }
0825     if (f & Tbl_smoothScrolling) { // Note: checks for 2 flags
0826         if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 || // must scroll?
0827             (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0) {
0828             snapToGrid((f & Tbl_smoothHScrolling) != 0, // do snapping
0829                        (f & Tbl_smoothVScrolling) != 0);
0830             repaintMask |= Tbl_smoothScrolling; // repaint table
0831         }
0832     }
0833     if (f & Tbl_snapToHGrid) {
0834         updateScrollBars(horRange);
0835     }
0836     if (f & Tbl_snapToVGrid) {
0837         updateScrollBars(verRange);
0838     }
0839     if (updateOn) {
0840         setAutoUpdate(true);
0841         updateScrollBars(); // returns immediately if nothing to do
0842         if (isVisible() && (f & repaintMask))
0843             repaint();
0844     }
0845 }
0846 
0847 /*!
0848   \fn bool QtTableView::autoUpdate() const
0849 
0850   Returns 'true' if the view updates itself automatically whenever it
0851   is changed in some way.
0852 
0853   \sa setAutoUpdate()
0854 */
0855 
0856 /*!
0857   Sets the auto-update option of the table view to \a enable.
0858 
0859   If \a enable is 'true' (this is the default), the view updates itself
0860   automatically whenever it has changed in some way (for example, when a
0861   \link setTableFlags() flag\endlink is changed).
0862 
0863   If \a enable is 'false', the view does NOT repaint itself or update
0864   its internal state variables when it is changed.  This can be
0865   useful to avoid flicker during large changes and is singularly
0866   useless otherwise. Disable auto-update, do the changes, re-enable
0867   auto-update and call repaint().
0868 
0869   \warning Do not leave the view in this state for a long time
0870   (i.e., between events). If, for example, the user interacts with the
0871   view when auto-update is off, strange things can happen.
0872 
0873   Setting auto-update to 'true' does not repaint the view; you must call
0874   repaint() to do this.
0875 
0876   \sa autoUpdate(), repaint()
0877 */
0878 
0879 void QtTableView::setAutoUpdate(bool enable)
0880 {
0881     if (updatesEnabled() == enable)
0882         return;
0883     setUpdatesEnabled(enable);
0884     if (enable) {
0885         showOrHideScrollBars();
0886         updateScrollBars();
0887     }
0888 }
0889 
0890 /*!
0891   Repaints the cell at row \a row, column \a col if it is inside the view.
0892 
0893   If \a erase is 'true', the relevant part of the view is cleared to the
0894   background color/pixmap before the contents are repainted.
0895 
0896   \sa isVisible()
0897 */
0898 
0899 void QtTableView::updateCell(int row, int col, bool erase)
0900 {
0901     int xPos, yPos;
0902     if (!colXPos(col, &xPos))
0903         return;
0904     if (!rowYPos(row, &yPos))
0905         return;
0906     QRect uR = QRect(xPos, yPos, cellW ? cellW : cellWidth(col), cellH ? cellH : cellHeight(row));
0907     repaint(uR.intersected(viewRect()), erase);
0908 }
0909 
0910 /*!
0911   \fn QRect QtTableView::cellUpdateRect() const
0912 
0913   This function should be called only from the paintCell() function in
0914   subclasses. It returns the portion of a cell that actually needs to be
0915   updated in \e cell coordinates. This is useful only for non-trivial
0916   paintCell().
0917 
0918 */
0919 
0920 /*!
0921   Returns the rectangle that is the actual table, excluding any
0922   frame, in \e widget coordinates.
0923 */
0924 
0925 QRect QtTableView::viewRect() const
0926 {
0927     return {frameWidth(), frameWidth(), viewWidth(), viewHeight()};
0928 }
0929 
0930 /*!
0931   Returns the index of the last (bottom) row in the view.
0932   The index of the first row is 0.
0933 
0934   If no rows are visible it returns -1.  This can happen if the
0935   view is too small for the first row and Tbl_cutCellsV is set.
0936 
0937   \sa lastColVisible()
0938 */
0939 
0940 int QtTableView::lastRowVisible() const
0941 {
0942     int cellMaxY;
0943     int row = findRawRow(maxViewY(), &cellMaxY);
0944     if (row == -1 || row >= nRows) { // maxViewY() past end?
0945         row = nRows - 1; // yes: return last row
0946     } else {
0947         if (testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY()) {
0948             if (row == yCellOffs) // cut by right margin?
0949                 return -1; // yes, nothing in the view
0950             else
0951                 row = row - 1; // cut by margin, one back
0952         }
0953     }
0954     return row;
0955 }
0956 
0957 /*!
0958   Returns the index of the last (right) column in the view.
0959   The index of the first column is 0.
0960 
0961   If no columns are visible it returns -1.  This can happen if the
0962   view is too narrow for the first column and Tbl_cutCellsH is set.
0963 
0964   \sa lastRowVisible()
0965 */
0966 
0967 int QtTableView::lastColVisible() const
0968 {
0969     int cellMaxX;
0970     int col = findRawCol(maxViewX(), &cellMaxX);
0971     if (col == -1 || col >= nCols) { // maxViewX() past end?
0972         col = nCols - 1; // yes: return last col
0973     } else {
0974         if (testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX()) {
0975             if (col == xCellOffs) // cut by bottom margin?
0976                 return -1; // yes, nothing in the view
0977             else
0978                 col = col - 1; // cell by margin, one back
0979         }
0980     }
0981     return col;
0982 }
0983 
0984 /*!
0985   Returns 'true' if \a row is at least partially visible.
0986   \sa colIsVisible()
0987 */
0988 
0989 bool QtTableView::rowIsVisible(int row) const
0990 {
0991     return rowYPos(row, 0);
0992 }
0993 
0994 /*!
0995   Returns 'true' if \a col is at least partially visible.
0996   \sa rowIsVisible()
0997 */
0998 
0999 bool QtTableView::colIsVisible(int col) const
1000 {
1001     return colXPos(col, 0);
1002 }
1003 
1004 /*!
1005   \internal
1006   Called when both scroll bars are active at the same time. Covers the
1007   bottom left corner between the two scroll bars with an empty widget.
1008 */
1009 
1010 void QtTableView::coverCornerSquare(bool enable)
1011 {
1012     coveringCornerSquare = enable;
1013     if (!cornerSquare && enable) {
1014         cornerSquare = new QCornerSquare(this);
1015         Q_CHECK_PTR(cornerSquare);
1016         cornerSquare->setGeometry(maxViewX() + frameWidth() + 1, maxViewY() + frameWidth() + 1, VSBEXT, HSBEXT);
1017     }
1018     if (autoUpdate() && cornerSquare) {
1019         if (enable)
1020             cornerSquare->show();
1021         else
1022             cornerSquare->hide();
1023     }
1024 }
1025 
1026 /*!
1027   \internal
1028   Scroll the view to a position such that:
1029 
1030   If \a horizontal is 'true', the leftmost column shown fits snugly
1031   with the left edge of the view.
1032 
1033   If \a vertical is 'true', the top row shown fits snugly with the top
1034   of the view.
1035 
1036   You can achieve the same effect automatically by setting any of the
1037   \link setTableFlags() Tbl_snapTo*Grid \endlink table flags.
1038 */
1039 
1040 void QtTableView::snapToGrid(bool horizontal, bool vertical)
1041 {
1042     int newXCell = -1;
1043     int newYCell = -1;
1044     if (horizontal && xCellDelta != 0) {
1045         int w = cellW ? cellW : cellWidth(xCellOffs);
1046         if (xCellDelta >= w / 2)
1047             newXCell = xCellOffs + 1;
1048         else
1049             newXCell = xCellOffs;
1050     }
1051     if (vertical && yCellDelta != 0) {
1052         int h = cellH ? cellH : cellHeight(yCellOffs);
1053         if (yCellDelta >= h / 2)
1054             newYCell = yCellOffs + 1;
1055         else
1056             newYCell = yCellOffs;
1057     }
1058     setTopLeftCell(newYCell, newXCell); // row,column
1059 }
1060 
1061 /*!
1062   \internal
1063   This internal slot is connected to the horizontal scroll bar's
1064   QScrollBar::valueChanged() signal.
1065 
1066   Moves the table horizontally to offset \a val without updating the
1067   scroll bar.
1068 */
1069 
1070 void QtTableView::horSbValue(int val)
1071 {
1072     if (horSliding) {
1073         horSliding = false;
1074         if (horSnappingOff) {
1075             horSnappingOff = false;
1076             tFlags |= Tbl_snapToHGrid;
1077         }
1078     }
1079     setOffset(val, yOffs, false);
1080 }
1081 
1082 /*!
1083   \internal
1084   This internal slot is connected to the horizontal scroll bar's
1085   QScrollBar::sliderMoved() signal.
1086 
1087   Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set.
1088 */
1089 
1090 void QtTableView::horSbSliding(int val)
1091 {
1092     if (testTableFlags(Tbl_snapToHGrid) && testTableFlags(Tbl_smoothHScrolling)) {
1093         tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding
1094         setOffset(val, yOffs, false);
1095         tFlags |= Tbl_snapToHGrid; // turn on snapping again
1096     } else {
1097         setOffset(val, yOffs, false);
1098     }
1099 }
1100 
1101 /*!
1102   \internal
1103   This internal slot is connected to the horizontal scroll bar's
1104   QScrollBar::sliderReleased() signal.
1105 */
1106 
1107 void QtTableView::horSbSlidingDone()
1108 {
1109     if (testTableFlags(Tbl_snapToHGrid) && testTableFlags(Tbl_smoothHScrolling))
1110         snapToGrid(true, false);
1111 }
1112 
1113 /*!
1114   \internal
1115   This internal slot is connected to the vertical scroll bar's
1116   QScrollBar::valueChanged() signal.
1117 
1118   Moves the table vertically to offset \a val without updating the
1119   scroll bar.
1120 */
1121 
1122 void QtTableView::verSbValue(int val)
1123 {
1124     if (verSliding) {
1125         verSliding = false;
1126         if (verSnappingOff) {
1127             verSnappingOff = false;
1128             tFlags |= Tbl_snapToVGrid;
1129         }
1130     }
1131     setOffset(xOffs, val, false);
1132 }
1133 
1134 /*!
1135   \internal
1136   This internal slot is connected to the vertical scroll bar's
1137   QScrollBar::sliderMoved() signal.
1138 
1139   Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set.
1140 */
1141 
1142 void QtTableView::verSbSliding(int val)
1143 {
1144     if (testTableFlags(Tbl_snapToVGrid) && testTableFlags(Tbl_smoothVScrolling)) {
1145         tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding
1146         setOffset(xOffs, val, false);
1147         tFlags |= Tbl_snapToVGrid; // turn on snapping again
1148     } else {
1149         setOffset(xOffs, val, false);
1150     }
1151 }
1152 
1153 /*!
1154   \internal
1155   This internal slot is connected to the vertical scroll bar's
1156   QScrollBar::sliderReleased() signal.
1157 */
1158 
1159 void QtTableView::verSbSlidingDone()
1160 {
1161     if (testTableFlags(Tbl_snapToVGrid) && testTableFlags(Tbl_smoothVScrolling))
1162         snapToGrid(false, true);
1163 }
1164 
1165 /*!
1166   This virtual function is called before painting of table cells
1167   is started. It can be reimplemented by subclasses that want to
1168   to set up the painter in a special way and that do not want to
1169   do so for each cell.
1170 */
1171 
1172 void QtTableView::setupPainter(QPainter *)
1173 {
1174 }
1175 
1176 /*!
1177   \fn void QtTableView::paintCell( QPainter *p, int row, int col )
1178 
1179   This pure virtual function is called to paint the single cell at \a
1180   (row,col) using \a p, which is open when paintCell() is called and
1181   must remain open.
1182 
1183   The coordinate system is \link QPainter::translate() translated \endlink
1184   so that the origin is at the top-left corner of the cell to be
1185   painted, i.e. \e cell coordinates.  Do not scale or shear the coordinate
1186   system (or if you do, restore the transformation matrix before you
1187   return).
1188 
1189   The painter is not clipped by default and for maximum efficiency. For safety,
1190   call setTableFlags(Tbl_clipCellPainting) to enable clipping.
1191 
1192   \sa paintEvent(), setTableFlags() */
1193 
1194 /*!
1195   Handles paint events, \a e, for the table view.
1196 
1197   Calls paintCell() for the cells that needs to be repainted.
1198 */
1199 
1200 void QtTableView::paintEvent(QPaintEvent *e)
1201 {
1202     QRect updateR = e->rect(); // update rectangle
1203     if (sbDirty) {
1204         bool e = eraseInPaint;
1205         updateScrollBars();
1206         eraseInPaint = e;
1207     }
1208 
1209     QPainter paint(this);
1210 
1211     if (!contentsRect().contains(updateR, true)) { // update frame ?
1212         drawFrame(&paint);
1213         if (updateR.left() < frameWidth()) //###
1214             updateR.setLeft(frameWidth());
1215         if (updateR.top() < frameWidth())
1216             updateR.setTop(frameWidth());
1217     }
1218 
1219     int maxWX = maxViewX();
1220     int maxWY = maxViewY();
1221     if (updateR.right() > maxWX)
1222         updateR.setRight(maxWX);
1223     if (updateR.bottom() > maxWY)
1224         updateR.setBottom(maxWY);
1225 
1226     setupPainter(&paint); // prepare for painting table
1227 
1228     int firstRow = findRow(updateR.y());
1229     int firstCol = findCol(updateR.x());
1230     int xStart, yStart;
1231     if (!colXPos(firstCol, &xStart) || !rowYPos(firstRow, &yStart)) {
1232         paint.eraseRect(updateR); // erase area outside cells but in view
1233         return;
1234     }
1235     int maxX = updateR.right();
1236     int maxY = updateR.bottom();
1237     int row = firstRow;
1238     int col;
1239     int yPos = yStart;
1240     int xPos = maxX + 1; // in case the while() is empty
1241     int nextX;
1242     int nextY;
1243     QRect winR = viewRect();
1244     QRect cellR;
1245     QRect cellUR;
1246 #ifndef QT_NO_TRANSFORMATIONS
1247     QTransform matrix;
1248 #endif
1249 
1250     while (yPos <= maxY && row < nRows) {
1251         nextY = yPos + (cellH ? cellH : cellHeight(row));
1252         if (testTableFlags(Tbl_cutCellsV) && nextY > (maxWY + 1))
1253             break;
1254         col = firstCol;
1255         xPos = xStart;
1256         while (xPos <= maxX && col < nCols) {
1257             nextX = xPos + (cellW ? cellW : cellWidth(col));
1258             if (testTableFlags(Tbl_cutCellsH) && nextX > (maxWX + 1))
1259                 break;
1260 
1261             cellR.setRect(xPos, yPos, cellW ? cellW : cellWidth(col), cellH ? cellH : cellHeight(row));
1262             cellUR = cellR.intersected(updateR);
1263             if (cellUR.isValid()) {
1264                 cellUpdateR = cellUR;
1265                 cellUpdateR.translate(-xPos, -yPos); // cell coordinates
1266                 if (eraseInPaint)
1267                     paint.eraseRect(cellUR);
1268 
1269 #ifndef QT_NO_TRANSFORMATIONS
1270                 matrix.translate(xPos, yPos);
1271                 paint.setTransform(matrix);
1272                 if (testTableFlags(Tbl_clipCellPainting) || frameWidth() > 0 && !winR.contains(cellR)) { //##arnt
1273 #ifdef __GNUC__
1274 #warning disable clipping for now as it interferes with drawText() in DiffView::paintCell()
1275 #endif
1276                     //          paint.setClipRect( cellUpdateR );
1277                     paintCell(&paint, row, col);
1278                     //          paint.setClipping( false );
1279                 } else {
1280                     paintCell(&paint, row, col);
1281                 }
1282                 matrix.reset();
1283                 paint.setTransform(matrix);
1284 #else
1285                 paint.translate(xPos, yPos);
1286                 if (testTableFlags(Tbl_clipCellPainting) || frameWidth() > 0 && !winR.contains(cellR)) { //##arnt
1287                     paint.setClipRect(cellUpdateR);
1288                     paintCell(&paint, row, col);
1289                     paint.setClipping(false);
1290                 } else {
1291                     paintCell(&paint, row, col);
1292                 }
1293                 paint.translate(-xPos, -yPos);
1294 #endif
1295             }
1296             col++;
1297             xPos = nextX;
1298         }
1299         row++;
1300         yPos = nextY;
1301     }
1302 
1303     // while painting we have to erase any areas in the view that
1304     // are not covered by cells but are covered by the paint event
1305     // rectangle these must be erased. We know that xPos is the last
1306     // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
1307 
1308     // Note that this needs to be done regardless whether we do
1309     // eraseInPaint or not. Reason: a subclass may implement
1310     // flicker-freeness and encourage the use of repaint(false).
1311     // The subclass, however, cannot draw all pixels, just those
1312     // inside the cells. So QtTableView is responsible for all pixels
1313     // outside the cells.
1314 
1315     QRect viewR = viewRect();
1316     QPalette g = palette();
1317 
1318     if (xPos <= maxX) {
1319         QRect r = viewR;
1320         r.setLeft(xPos);
1321         r.setBottom(yPos < maxY ? yPos : maxY);
1322         if (inherits("QMultiLineEdit"))
1323             paint.fillRect(r.intersected(updateR), g.base());
1324         else
1325             paint.eraseRect(r.intersected(updateR));
1326     }
1327     if (yPos <= maxY) {
1328         QRect r = viewR;
1329         r.setTop(yPos);
1330         if (inherits("QMultiLineEdit"))
1331             paint.fillRect(r.intersected(updateR), g.base());
1332         else
1333             paint.eraseRect(r.intersected(updateR));
1334     }
1335 }
1336 
1337 /*!\reimp
1338  */
1339 void QtTableView::resizeEvent(QResizeEvent *)
1340 {
1341     updateScrollBars(horValue | verValue | horSteps | horGeometry | horRange | verSteps | verGeometry | verRange);
1342     showOrHideScrollBars();
1343     updateFrameSize();
1344     int maxX = qMin(xOffs, maxXOffset()); // ### can be slow
1345     int maxY = qMin(yOffs, maxYOffset());
1346     setOffset(maxX, maxY);
1347 }
1348 
1349 void QtTableView::showEvent(QShowEvent *e)
1350 {
1351     showOrHideScrollBars();
1352     QFrame::showEvent(e);
1353 }
1354 
1355 void QtTableView::wheelEvent(QWheelEvent *e)
1356 {
1357     if (e->orientation() == Qt::Vertical && vScrollBar && vScrollBar->isVisible())
1358         QApplication::sendEvent(vScrollBar, e);
1359 }
1360 
1361 /*!
1362   Redraws all visible cells in the table view.
1363 */
1364 
1365 void QtTableView::updateView()
1366 {
1367     repaint(viewRect());
1368 }
1369 
1370 /*!
1371   Returns a pointer to the vertical scroll bar mainly so you can
1372   connect() to its signals.  Note that the scroll bar works in pixel
1373   values; use findRow() to translate to cell numbers.
1374 */
1375 
1376 QScrollBar *QtTableView::verticalScrollBar() const
1377 {
1378     auto that = (QtTableView *)this; // semantic const
1379     if (!vScrollBar) {
1380         auto sb = new QScrollBar(Qt::Vertical, that);
1381         sb->setAttribute(Qt::WA_NoMousePropagation);
1382         sb->setAutoFillBackground(true);
1383 #ifndef QT_NO_CURSOR
1384         sb->setCursor(Qt::ArrowCursor);
1385 #endif
1386         sb->resize(sb->sizeHint()); // height is irrelevant
1387         Q_CHECK_PTR(sb);
1388         sb->setTracking(false);
1389         sb->setFocusPolicy(Qt::NoFocus);
1390         connect(sb, SIGNAL(valueChanged(int)), SLOT(verSbValue(int)));
1391         connect(sb, SIGNAL(sliderMoved(int)), SLOT(verSbSliding(int)));
1392         connect(sb, SIGNAL(sliderReleased()), SLOT(verSbSlidingDone()));
1393         sb->hide();
1394         that->vScrollBar = sb;
1395         return sb;
1396     }
1397     return vScrollBar;
1398 }
1399 
1400 /*!
1401   Returns a pointer to the horizontal scroll bar mainly so you can
1402   connect() to its signals. Note that the scroll bar works in pixel
1403   values; use findCol() to translate to cell numbers.
1404 */
1405 
1406 QScrollBar *QtTableView::horizontalScrollBar() const
1407 {
1408     auto that = (QtTableView *)this; // semantic const
1409     if (!hScrollBar) {
1410         auto sb = new QScrollBar(Qt::Horizontal, that);
1411         sb->setAutoFillBackground(true);
1412 #ifndef QT_NO_CURSOR
1413         sb->setCursor(Qt::ArrowCursor);
1414 #endif
1415         sb->resize(sb->sizeHint()); // width is irrelevant
1416         sb->setFocusPolicy(Qt::NoFocus);
1417         Q_CHECK_PTR(sb);
1418         sb->setTracking(false);
1419         connect(sb, SIGNAL(valueChanged(int)), SLOT(horSbValue(int)));
1420         connect(sb, SIGNAL(sliderMoved(int)), SLOT(horSbSliding(int)));
1421         connect(sb, SIGNAL(sliderReleased()), SLOT(horSbSlidingDone()));
1422         sb->hide();
1423         that->hScrollBar = sb;
1424         return sb;
1425     }
1426     return hScrollBar;
1427 }
1428 
1429 /*!
1430   Enables or disables the horizontal scroll bar, as required by
1431   setAutoUpdate() and the \link setTableFlags() table flags\endlink.
1432 */
1433 
1434 void QtTableView::setHorScrollBar(bool on, bool update)
1435 {
1436     if (on) {
1437         tFlags |= Tbl_hScrollBar;
1438         horizontalScrollBar(); // created
1439         if (update)
1440             updateScrollBars(horMask | verMask);
1441         else
1442             sbDirty = sbDirty | (horMask | verMask);
1443         if (testTableFlags(Tbl_vScrollBar))
1444             coverCornerSquare(true);
1445         if (autoUpdate())
1446             sbDirty = sbDirty | horMask;
1447     } else {
1448         tFlags &= ~Tbl_hScrollBar;
1449         if (!hScrollBar)
1450             return;
1451         coverCornerSquare(false);
1452         bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
1453         if (hideScrollBar)
1454             hScrollBar->hide();
1455         if (update)
1456             updateScrollBars(verMask);
1457         else
1458             sbDirty = sbDirty | verMask;
1459         if (hideScrollBar && isVisible())
1460             repaint(hScrollBar->x(), hScrollBar->y(), width() - hScrollBar->x(), hScrollBar->height());
1461     }
1462     if (update)
1463         updateFrameSize();
1464 }
1465 
1466 /*!
1467   Enables or disables the vertical scroll bar, as required by
1468   setAutoUpdate() and the \link setTableFlags() table flags\endlink.
1469 */
1470 
1471 void QtTableView::setVerScrollBar(bool on, bool update)
1472 {
1473     if (on) {
1474         tFlags |= Tbl_vScrollBar;
1475         verticalScrollBar(); // created
1476         if (update)
1477             updateScrollBars(verMask | horMask);
1478         else
1479             sbDirty = sbDirty | (horMask | verMask);
1480         if (testTableFlags(Tbl_hScrollBar))
1481             coverCornerSquare(true);
1482         if (autoUpdate())
1483             sbDirty = sbDirty | verMask;
1484     } else {
1485         tFlags &= ~Tbl_vScrollBar;
1486         if (!vScrollBar)
1487             return;
1488         coverCornerSquare(false);
1489         bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
1490         if (hideScrollBar)
1491             vScrollBar->hide();
1492         if (update)
1493             updateScrollBars(horMask);
1494         else
1495             sbDirty = sbDirty | horMask;
1496         if (hideScrollBar && isVisible())
1497             repaint(vScrollBar->x(), vScrollBar->y(), vScrollBar->width(), height() - vScrollBar->y());
1498     }
1499     if (update)
1500         updateFrameSize();
1501 }
1502 
1503 int QtTableView::findRawRow(int yPos, int *cellMaxY, int *cellMinY, bool goOutsideView) const
1504 {
1505     int r = -1;
1506     if (nRows == 0)
1507         return r;
1508     if (goOutsideView || yPos >= minViewY() && yPos <= maxViewY()) {
1509         if (yPos < minViewY()) {
1510 #if defined(QT_CHECK_RANGE)
1511             qWarning(
1512                 "QtTableView::findRawRow: (%s) internal error: "
1513                 "yPos < minViewY() && goOutsideView "
1514                 "not supported. (%d,%d)",
1515                 name("unnamed"),
1516                 yPos,
1517                 yOffs);
1518 #endif
1519             return -1;
1520         }
1521         if (cellH) { // uniform cell height
1522             r = (yPos - minViewY() + yCellDelta) / cellH; // cell offs from top
1523             if (cellMaxY)
1524                 *cellMaxY = (r + 1) * cellH + minViewY() - yCellDelta - 1;
1525             if (cellMinY)
1526                 *cellMinY = r * cellH + minViewY() - yCellDelta;
1527             r += yCellOffs; // absolute cell index
1528         } else { // variable cell height
1529             auto tw = (QtTableView *)this;
1530             r = yCellOffs;
1531             int h = minViewY() - yCellDelta; //##arnt3
1532             int oldH = h;
1533             Q_ASSERT(r < nRows);
1534             while (r < nRows) {
1535                 oldH = h;
1536                 h += tw->cellHeight(r); // Start of next cell
1537                 if (yPos < h)
1538                     break;
1539                 r++;
1540             }
1541             if (cellMaxY)
1542                 *cellMaxY = h - 1;
1543             if (cellMinY)
1544                 *cellMinY = oldH;
1545         }
1546     }
1547     return r;
1548 }
1549 
1550 int QtTableView::findRawCol(int xPos, int *cellMaxX, int *cellMinX, bool goOutsideView) const
1551 {
1552     int c = -1;
1553     if (nCols == 0)
1554         return c;
1555     if (goOutsideView || xPos >= minViewX() && xPos <= maxViewX()) {
1556         if (xPos < minViewX()) {
1557 #if defined(QT_CHECK_RANGE)
1558             qWarning(
1559                 "QtTableView::findRawCol: (%s) internal error: "
1560                 "xPos < minViewX() && goOutsideView "
1561                 "not supported. (%d,%d)",
1562                 name("unnamed"),
1563                 xPos,
1564                 xOffs);
1565 #endif
1566             return -1;
1567         }
1568         if (cellW) { // uniform cell width
1569             c = (xPos - minViewX() + xCellDelta) / cellW; // cell offs from left
1570             if (cellMaxX)
1571                 *cellMaxX = (c + 1) * cellW + minViewX() - xCellDelta - 1;
1572             if (cellMinX)
1573                 *cellMinX = c * cellW + minViewX() - xCellDelta;
1574             c += xCellOffs; // absolute cell index
1575         } else { // variable cell width
1576             auto tw = (QtTableView *)this;
1577             c = xCellOffs;
1578             int w = minViewX() - xCellDelta; //##arnt3
1579             int oldW = w;
1580             Q_ASSERT(c < nCols);
1581             while (c < nCols) {
1582                 oldW = w;
1583                 w += tw->cellWidth(c); // Start of next cell
1584                 if (xPos < w)
1585                     break;
1586                 c++;
1587             }
1588             if (cellMaxX)
1589                 *cellMaxX = w - 1;
1590             if (cellMinX)
1591                 *cellMinX = oldW;
1592         }
1593     }
1594     return c;
1595 }
1596 
1597 /*!
1598   Returns the index of the row at position \a yPos, where \a yPos is in
1599   \e widget coordinates.  Returns -1 if \a yPos is outside the valid
1600   range.
1601 
1602   \sa findCol(), rowYPos()
1603 */
1604 
1605 int QtTableView::findRow(int yPos) const
1606 {
1607     int cellMaxY;
1608     int row = findRawRow(yPos, &cellMaxY);
1609     if (testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY())
1610         row = -1; //  cell cut by bottom margin
1611     if (row >= nRows)
1612         row = -1;
1613     return row;
1614 }
1615 
1616 /*!
1617   Returns the index of the column at position \a xPos, where \a xPos is
1618   in \e widget coordinates.  Returns -1 if \a xPos is outside the valid
1619   range.
1620 
1621   \sa findRow(), colXPos()
1622 */
1623 
1624 int QtTableView::findCol(int xPos) const
1625 {
1626     int cellMaxX;
1627     int col = findRawCol(xPos, &cellMaxX);
1628     if (testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX())
1629         col = -1; //  cell cut by right margin
1630     if (col >= nCols)
1631         col = -1;
1632     return col;
1633 }
1634 
1635 /*!
1636   Computes the position in the widget of row \a row.
1637 
1638   Returns 'true' and stores the result in \a *yPos (in \e widget
1639   coordinates) if the row is visible.  Returns 'false' and does not modify
1640   \a *yPos if \a row is invisible or invalid.
1641 
1642   \sa colXPos(), findRow()
1643 */
1644 
1645 bool QtTableView::rowYPos(int row, int *yPos) const
1646 {
1647     int y;
1648     if (row >= yCellOffs) {
1649         if (cellH) {
1650             int lastVisible = lastRowVisible();
1651             if (row > lastVisible || lastVisible == -1)
1652                 return false;
1653             y = (row - yCellOffs) * cellH + minViewY() - yCellDelta;
1654         } else {
1655             //##arnt3
1656             y = minViewY() - yCellDelta; // y of leftmost cell in view
1657             int r = yCellOffs;
1658             auto tw = (QtTableView *)this;
1659             int maxY = maxViewY();
1660             while (r < row && y <= maxY)
1661                 y += tw->cellHeight(r++);
1662             if (y > maxY)
1663                 return false;
1664         }
1665     } else {
1666         return false;
1667     }
1668     if (yPos)
1669         *yPos = y;
1670     return true;
1671 }
1672 
1673 /*!
1674   Computes the position in the widget of column \a col.
1675 
1676   Returns 'true' and stores the result in \a *xPos (in \e widget
1677   coordinates) if the column is visible.  Returns 'false' and does not
1678   modify \a *xPos if \a col is invisible or invalid.
1679 
1680   \sa rowYPos(), findCol()
1681 */
1682 
1683 bool QtTableView::colXPos(int col, int *xPos) const
1684 {
1685     int x;
1686     if (col >= xCellOffs) {
1687         if (cellW) {
1688             int lastVisible = lastColVisible();
1689             if (col > lastVisible || lastVisible == -1)
1690                 return false;
1691             x = (col - xCellOffs) * cellW + minViewX() - xCellDelta;
1692         } else {
1693             //##arnt3
1694             x = minViewX() - xCellDelta; // x of uppermost cell in view
1695             int c = xCellOffs;
1696             auto tw = (QtTableView *)this;
1697             int maxX = maxViewX();
1698             while (c < col && x <= maxX)
1699                 x += tw->cellWidth(c++);
1700             if (x > maxX)
1701                 return false;
1702         }
1703     } else {
1704         return false;
1705     }
1706     if (xPos)
1707         *xPos = x;
1708     return true;
1709 }
1710 
1711 /*!
1712   Moves the visible area of the table right by \a xPixels and
1713   down by \a yPixels pixels.  Both may be negative.
1714 
1715   \warning You might find that QScrollView offers a higher-level of
1716     functionality than using QtTableView and this function.
1717 
1718   This function is \e not the same as QWidget::scroll(); in particular,
1719   the signs of \a xPixels and \a yPixels have the reverse semantics.
1720 
1721   \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
1722   setLeftCell()
1723 */
1724 
1725 void QtTableView::scroll(int xPixels, int yPixels)
1726 {
1727     QWidget::scroll(-xPixels, -yPixels, contentsRect());
1728 }
1729 
1730 /*!
1731   Returns the leftmost pixel of the table view in \e view
1732   coordinates.  This excludes the frame and any header.
1733 
1734   \sa maxViewY(), viewWidth(), contentsRect()
1735 */
1736 
1737 int QtTableView::minViewX() const
1738 {
1739     return frameWidth();
1740 }
1741 
1742 /*!
1743   Returns the top pixel of the table view in \e view
1744   coordinates.  This excludes the frame and any header.
1745 
1746   \sa maxViewX(), viewHeight(), contentsRect()
1747 */
1748 
1749 int QtTableView::minViewY() const
1750 {
1751     return frameWidth();
1752 }
1753 
1754 /*!
1755   Returns the rightmost pixel of the table view in \e view
1756   coordinates.  This excludes the frame and any scroll bar, but
1757   includes blank pixels to the right of the visible table data.
1758 
1759   \sa maxViewY(), viewWidth(), contentsRect()
1760 */
1761 
1762 int QtTableView::maxViewX() const
1763 {
1764     return width() - 1 - frameWidth() - (tFlags & Tbl_vScrollBar ? VSBEXT : 0);
1765 }
1766 
1767 /*!
1768   Returns the bottom pixel of the table view in \e view
1769   coordinates.  This excludes the frame and any scroll bar, but
1770   includes blank pixels below the visible table data.
1771 
1772   \sa maxViewX(), viewHeight(), contentsRect()
1773 */
1774 
1775 int QtTableView::maxViewY() const
1776 {
1777     return height() - 1 - frameWidth() - (tFlags & Tbl_hScrollBar ? HSBEXT : 0);
1778 }
1779 
1780 /*!
1781   Returns the width of the table view, as such, in \e view
1782   coordinates.  This does not include any header, scroll bar or frame,
1783   but it does include background pixels to the right of the table data.
1784 
1785   \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
1786 */
1787 
1788 int QtTableView::viewWidth() const
1789 {
1790     return maxViewX() - minViewX() + 1;
1791 }
1792 
1793 /*!
1794   Returns the height of the table view, as such, in \e view
1795   coordinates.  This does not include any header, scroll bar or frame,
1796   but it does include background pixels below the table data.
1797 
1798   \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
1799 */
1800 
1801 int QtTableView::viewHeight() const
1802 {
1803     return maxViewY() - minViewY() + 1;
1804 }
1805 
1806 void QtTableView::doAutoScrollBars()
1807 {
1808     int viewW = width() - frameWidth() - minViewX();
1809     int viewH = height() - frameWidth() - minViewY();
1810     bool vScrollOn = testTableFlags(Tbl_vScrollBar);
1811     bool hScrollOn = testTableFlags(Tbl_hScrollBar);
1812     int w = 0;
1813     int h = 0;
1814     int i;
1815 
1816     if (testTableFlags(Tbl_autoHScrollBar)) {
1817         if (cellW) {
1818             w = cellW * nCols;
1819         } else {
1820             i = 0;
1821             while (i < nCols && w <= viewW)
1822                 w += cellWidth(i++);
1823         }
1824         if (w > viewW)
1825             hScrollOn = true;
1826         else
1827             hScrollOn = false;
1828     }
1829 
1830     if (testTableFlags(Tbl_autoVScrollBar)) {
1831         if (cellH) {
1832             h = cellH * nRows;
1833         } else {
1834             i = 0;
1835             while (i < nRows && h <= viewH)
1836                 h += cellHeight(i++);
1837         }
1838 
1839         if (h > viewH)
1840             vScrollOn = true;
1841         else
1842             vScrollOn = false;
1843     }
1844 
1845     if (testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn)
1846         if (w > viewW - VSBEXT)
1847             hScrollOn = true;
1848 
1849     if (testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn)
1850         if (h > viewH - HSBEXT)
1851             vScrollOn = true;
1852 
1853     setHorScrollBar(hScrollOn, false);
1854     setVerScrollBar(vScrollOn, false);
1855     updateFrameSize();
1856 }
1857 
1858 /*!
1859   \fn void QtTableView::updateScrollBars()
1860 
1861   Updates the scroll bars' contents and presence to match the table's
1862   state.  Generally, you should not need to call this.
1863 
1864   \sa setTableFlags()
1865 */
1866 
1867 /*!
1868   Updates the scroll bars' contents and presence to match the table's
1869   state \c or \a f.
1870 
1871   \sa setTableFlags()
1872 */
1873 
1874 void QtTableView::updateScrollBars(uint f)
1875 {
1876     sbDirty = sbDirty | f;
1877     if (inSbUpdate)
1878         return;
1879     inSbUpdate = true;
1880 
1881     if (testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) || testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange))
1882         // if range change and auto
1883         doAutoScrollBars(); // turn scroll bars on/off if needed
1884 
1885     if (!autoUpdate()) {
1886         inSbUpdate = false;
1887         return;
1888     }
1889     if (yOffset() > 0 && testTableFlags(Tbl_autoVScrollBar) && !testTableFlags(Tbl_vScrollBar)) {
1890         setYOffset(0);
1891     }
1892     if (xOffset() > 0 && testTableFlags(Tbl_autoHScrollBar) && !testTableFlags(Tbl_hScrollBar)) {
1893         setXOffset(0);
1894     }
1895     if (!isVisible()) {
1896         inSbUpdate = false;
1897         return;
1898     }
1899 
1900     if (testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0) {
1901         if (sbDirty & horGeometry)
1902             hScrollBar->setGeometry(0, height() - HSBEXT, viewWidth() + frameWidth() * 2, HSBEXT);
1903 
1904         if (sbDirty & horSteps) {
1905             if (cellW)
1906                 hScrollBar->setSingleStep(qMin((int)cellW, viewWidth() / 2));
1907             else
1908                 hScrollBar->setSingleStep(16);
1909 
1910             hScrollBar->setPageStep(viewWidth());
1911         }
1912 
1913         if (sbDirty & horRange)
1914             hScrollBar->setRange(0, maxXOffset());
1915 
1916         if (sbDirty & horValue)
1917             hScrollBar->setValue(xOffs);
1918 
1919         // show scrollbar only when it has a sane geometry
1920         if (!hScrollBar->isVisible())
1921             hScrollBar->show();
1922     }
1923 
1924     if (testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0) {
1925         if (sbDirty & verGeometry)
1926             vScrollBar->setGeometry(width() - VSBEXT, 0, VSBEXT, viewHeight() + frameWidth() * 2);
1927 
1928         if (sbDirty & verSteps) {
1929             if (cellH)
1930                 vScrollBar->setSingleStep(qMin((int)cellH, viewHeight() / 2));
1931             else
1932                 vScrollBar->setSingleStep(16); // fttb! ###
1933 
1934             vScrollBar->setPageStep(viewHeight());
1935         }
1936 
1937         if (sbDirty & verRange)
1938             vScrollBar->setRange(0, maxYOffset());
1939 
1940         if (sbDirty & verValue)
1941             vScrollBar->setValue(yOffs);
1942 
1943         // show scrollbar only when it has a sane geometry
1944         if (!vScrollBar->isVisible())
1945             vScrollBar->show();
1946     }
1947     if (coveringCornerSquare && ((sbDirty & verGeometry) || (sbDirty & horGeometry)))
1948         cornerSquare->move(maxViewX() + frameWidth() + 1, maxViewY() + frameWidth() + 1);
1949 
1950     sbDirty = 0;
1951     inSbUpdate = false;
1952 }
1953 
1954 void QtTableView::updateFrameSize()
1955 {
1956     int rw = width() - (testTableFlags(Tbl_vScrollBar) ? VSBEXT : 0);
1957     int rh = height() - (testTableFlags(Tbl_hScrollBar) ? HSBEXT : 0);
1958     if (rw < 0)
1959         rw = 0;
1960     if (rh < 0)
1961         rh = 0;
1962 
1963     if (autoUpdate()) {
1964         int fh = frameRect().height();
1965         int fw = frameRect().width();
1966         setFrameRect(QRect(0, 0, rw, rh));
1967 
1968         if (rw != fw)
1969             update(qMin(fw, rw) - frameWidth() - 2, 0, frameWidth() + 4, rh);
1970         if (rh != fh)
1971             update(0, qMin(fh, rh) - frameWidth() - 2, rw, frameWidth() + 4);
1972     }
1973 }
1974 
1975 /*!
1976   Returns the maximum horizontal offset within the table of the
1977   view's left edge in \e table coordinates.
1978 
1979   This is used mainly to set the horizontal scroll bar's range.
1980 
1981   \sa maxColOffset(), maxYOffset(), totalWidth()
1982 */
1983 
1984 int QtTableView::maxXOffset()
1985 {
1986     int tw = totalWidth();
1987     int maxOffs;
1988     if (testTableFlags(Tbl_scrollLastHCell)) {
1989         if (nCols != 1)
1990             maxOffs = tw - (cellW ? cellW : cellWidth(nCols - 1));
1991         else
1992             maxOffs = tw - viewWidth();
1993     } else {
1994         if (testTableFlags(Tbl_snapToHGrid)) {
1995             if (cellW) {
1996                 maxOffs = tw - (viewWidth() / cellW) * cellW;
1997             } else {
1998                 int goal = tw - viewWidth();
1999                 int pos = tw;
2000                 int nextCol = nCols - 1;
2001                 int nextCellWidth = cellWidth(nextCol);
2002                 while (nextCol > 0 && pos > goal + nextCellWidth) {
2003                     pos -= nextCellWidth;
2004                     nextCellWidth = cellWidth(--nextCol);
2005                 }
2006                 if (goal + nextCellWidth == pos)
2007                     maxOffs = goal;
2008                 else if (goal < pos)
2009                     maxOffs = pos;
2010                 else
2011                     maxOffs = 0;
2012             }
2013         } else {
2014             maxOffs = tw - viewWidth();
2015         }
2016     }
2017     return maxOffs > 0 ? maxOffs : 0;
2018 }
2019 
2020 /*!
2021   Returns the maximum vertical offset within the table of the
2022   view's top edge in \e table coordinates.
2023 
2024   This is used mainly to set the vertical scroll bar's range.
2025 
2026   \sa maxRowOffset(), maxXOffset(), totalHeight()
2027 */
2028 
2029 int QtTableView::maxYOffset()
2030 {
2031     int th = totalHeight();
2032     int maxOffs;
2033     if (testTableFlags(Tbl_scrollLastVCell)) {
2034         if (nRows != 1)
2035             maxOffs = th - (cellH ? cellH : cellHeight(nRows - 1));
2036         else
2037             maxOffs = th - viewHeight();
2038     } else {
2039         if (testTableFlags(Tbl_snapToVGrid)) {
2040             if (cellH) {
2041                 maxOffs = th - (viewHeight() / cellH) * cellH;
2042             } else {
2043                 int goal = th - viewHeight();
2044                 int pos = th;
2045                 int nextRow = nRows - 1;
2046                 int nextCellHeight = cellHeight(nextRow);
2047                 while (nextRow > 0 && pos > goal + nextCellHeight) {
2048                     pos -= nextCellHeight;
2049                     nextCellHeight = cellHeight(--nextRow);
2050                 }
2051                 if (goal + nextCellHeight == pos)
2052                     maxOffs = goal;
2053                 else if (goal < pos)
2054                     maxOffs = pos;
2055                 else
2056                     maxOffs = 0;
2057             }
2058         } else {
2059             maxOffs = th - viewHeight();
2060         }
2061     }
2062     return maxOffs > 0 ? maxOffs : 0;
2063 }
2064 
2065 /*!
2066   Returns the index of the last column, which may be at the left edge
2067   of the view.
2068 
2069   Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
2070   this may or may not be the last column.
2071 
2072   \sa maxXOffset(), maxRowOffset()
2073 */
2074 
2075 int QtTableView::maxColOffset()
2076 {
2077     int mx = maxXOffset();
2078     if (cellW)
2079         return mx / cellW;
2080     else {
2081         int xcd = 0, col = 0;
2082         while (col < nCols && mx > (xcd = cellWidth(col))) {
2083             mx -= xcd;
2084             col++;
2085         }
2086         return col;
2087     }
2088 }
2089 
2090 /*!
2091   Returns the index of the last row, which may be at the top edge of
2092   the view.
2093 
2094   Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
2095   this may or may not be the last row.
2096 
2097   \sa maxYOffset(), maxColOffset()
2098 */
2099 
2100 int QtTableView::maxRowOffset()
2101 {
2102     int my = maxYOffset();
2103     if (cellH)
2104         return my / cellH;
2105     else {
2106         int ycd = 0, row = 0;
2107         while (row < nRows && my > (ycd = cellHeight(row))) {
2108             my -= ycd;
2109             row++;
2110         }
2111         return row;
2112     }
2113 }
2114 
2115 void QtTableView::showOrHideScrollBars()
2116 {
2117     if (!autoUpdate())
2118         return;
2119     if (vScrollBar) {
2120         if (testTableFlags(Tbl_vScrollBar)) {
2121             if (!vScrollBar->isVisible())
2122                 sbDirty = sbDirty | verMask;
2123         } else {
2124             if (vScrollBar->isVisible())
2125                 vScrollBar->hide();
2126         }
2127     }
2128     if (hScrollBar) {
2129         if (testTableFlags(Tbl_hScrollBar)) {
2130             if (!hScrollBar->isVisible())
2131                 sbDirty = sbDirty | horMask;
2132         } else {
2133             if (hScrollBar->isVisible())
2134                 hScrollBar->hide();
2135         }
2136     }
2137     if (cornerSquare) {
2138         if (testTableFlags(Tbl_hScrollBar) && testTableFlags(Tbl_vScrollBar)) {
2139             if (!cornerSquare->isVisible())
2140                 cornerSquare->show();
2141         } else {
2142             if (cornerSquare->isVisible())
2143                 cornerSquare->hide();
2144         }
2145     }
2146 }
2147 
2148 /*!
2149   Updates the scroll bars and internal state.
2150 
2151   Call this function when the table view's total size is changed;
2152   typically because the result of cellHeight() or cellWidth() have changed.
2153 
2154   This function does not repaint the widget.
2155 */
2156 
2157 void QtTableView::updateTableSize()
2158 {
2159     bool updateOn = autoUpdate();
2160     setAutoUpdate(false);
2161     int xofs = xOffset();
2162     xOffs++; // so that setOffset will not return immediately
2163     setOffset(xofs, yOffset(), false); // to calculate internal state correctly
2164     setAutoUpdate(updateOn);
2165 
2166     updateScrollBars(horSteps | horRange | verSteps | verRange);
2167     showOrHideScrollBars();
2168 }