src/qt3support/itemviews/q3table.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qglobal.h"
       
    43 #if defined(Q_CC_BOR)
       
    44 // needed for qsort() because of a std namespace problem on Borland
       
    45 #include "qplatformdefs.h"
       
    46 #endif
       
    47 
       
    48 #include "q3table.h"
       
    49 
       
    50 
       
    51 #include <qpainter.h>
       
    52 #include <qlineedit.h>
       
    53 #include <qcursor.h>
       
    54 #include <qapplication.h>
       
    55 #include <qtimer.h>
       
    56 #include <qicon.h>
       
    57 #include <q3combobox.h>
       
    58 #include <qstyleoption.h>
       
    59 #include <qcheckbox.h>
       
    60 #include <q3dragobject.h>
       
    61 #include <qevent.h>
       
    62 #include <q3listbox.h>
       
    63 #include <qstyle.h>
       
    64 #include <q3datatable.h>
       
    65 #include <qvalidator.h>
       
    66 #include <q3button.h>
       
    67 
       
    68 #include <stdlib.h>
       
    69 #include <limits.h>
       
    70 
       
    71 QT_BEGIN_NAMESPACE
       
    72 
       
    73 using namespace Qt;
       
    74 
       
    75 class Q3HeaderData;
       
    76 extern bool qt_get_null_label_bit(Q3HeaderData *data, int section);
       
    77 extern void qt_set_null_label_bit(Q3HeaderData *data, int section, bool b);
       
    78 
       
    79 static bool qt_update_cell_widget = true;
       
    80 static bool qt_table_clipper_enabled = true;
       
    81 #ifndef QT_INTERNAL_TABLE
       
    82 Q_COMPAT_EXPORT
       
    83 #endif
       
    84 void qt_set_table_clipper_enabled(bool enabled)
       
    85 {
       
    86     qt_table_clipper_enabled = enabled;
       
    87 }
       
    88 
       
    89 class Q_COMPAT_EXPORT Q3TableHeader : public Q3Header
       
    90 {
       
    91     friend class Q3Table;
       
    92     Q_OBJECT
       
    93 
       
    94 public:
       
    95     enum SectionState {
       
    96         Normal,
       
    97         Bold,
       
    98         Selected
       
    99     };
       
   100 
       
   101     Q3TableHeader(int, Q3Table *t, QWidget* parent=0, const char* name=0);
       
   102     ~Q3TableHeader() {};
       
   103     void addLabel(const QString &s, int size);
       
   104     void setLabel(int section, const QString & s, int size = -1);
       
   105     void setLabel(int section, const QIconSet & iconset, const QString & s,
       
   106                    int size = -1);
       
   107 
       
   108     void setLabels(const QStringList & labels);
       
   109 
       
   110     void removeLabel(int section);
       
   111 
       
   112     void setSectionState(int s, SectionState state);
       
   113     void setSectionStateToAll(SectionState state);
       
   114     SectionState sectionState(int s) const;
       
   115 
       
   116     int sectionSize(int section) const;
       
   117     int sectionPos(int section) const;
       
   118     int sectionAt(int section) const;
       
   119 
       
   120     void setSectionStretchable(int s, bool b);
       
   121     bool isSectionStretchable(int s) const;
       
   122 
       
   123     void updateCache();
       
   124 
       
   125 signals:
       
   126     void sectionSizeChanged(int s);
       
   127 
       
   128 protected:
       
   129     void paintEvent(QPaintEvent *e);
       
   130     void paintSection(QPainter *p, int index, const QRect& fr);
       
   131     void mousePressEvent(QMouseEvent *e);
       
   132     void mouseMoveEvent(QMouseEvent *e);
       
   133     void mouseReleaseEvent(QMouseEvent *e);
       
   134     void mouseDoubleClickEvent(QMouseEvent *e);
       
   135     void resizeEvent(QResizeEvent *e);
       
   136 
       
   137 private slots:
       
   138     void doAutoScroll();
       
   139     void sectionWidthChanged(int col, int os, int ns);
       
   140     void indexChanged(int sec, int oldIdx, int newIdx);
       
   141     void updateStretches();
       
   142     void updateWidgetStretches();
       
   143 
       
   144 private:
       
   145     void updateSelections();
       
   146     void saveStates();
       
   147     void setCaching(bool b);
       
   148     void swapSections(int oldIdx, int newIdx, bool swapTable = true);
       
   149     bool doSelection(QMouseEvent *e);
       
   150     void sectionLabelChanged(int section);
       
   151     void resizeArrays(int n);
       
   152 
       
   153 private:
       
   154     Q3MemArray<int> states, oldStates;
       
   155     Q3MemArray<bool> stretchable;
       
   156     Q3MemArray<int> sectionSizes, sectionPoses;
       
   157     bool mousePressed;
       
   158     int pressPos, startPos, endPos;
       
   159     Q3Table *table;
       
   160     QTimer *autoScrollTimer;
       
   161     QWidget *line1, *line2;
       
   162     bool caching;
       
   163     int resizedSection;
       
   164     bool isResizing;
       
   165     int numStretches;
       
   166     QTimer *stretchTimer, *widgetStretchTimer;
       
   167     Q3TableHeaderPrivate *d;
       
   168 
       
   169     Q_DISABLE_COPY(Q3TableHeader)
       
   170 };
       
   171 
       
   172 #ifdef _WS_QWS_
       
   173 # define NO_LINE_WIDGET
       
   174 #endif
       
   175 
       
   176 
       
   177 
       
   178 struct Q3TablePrivate
       
   179 {
       
   180     Q3TablePrivate() : hasRowSpan(false), hasColSpan(false),
       
   181                       inMenuMode(false), redirectMouseEvent(false)
       
   182     {
       
   183         hiddenRows.setAutoDelete(true);
       
   184         hiddenCols.setAutoDelete(true);
       
   185     }
       
   186     uint hasRowSpan : 1;
       
   187     uint hasColSpan : 1;
       
   188     uint inMenuMode : 1;
       
   189     uint redirectMouseEvent : 1;
       
   190     Q3IntDict<int> hiddenRows, hiddenCols;
       
   191     QTimer *geomTimer;
       
   192     int lastVisRow;
       
   193     int lastVisCol;
       
   194 };
       
   195 
       
   196 struct Q3TableHeaderPrivate
       
   197 {
       
   198 #ifdef NO_LINE_WIDGET
       
   199     int oldLinePos;
       
   200 #endif
       
   201 };
       
   202 
       
   203 static bool isRowSelection(Q3Table::SelectionMode selMode)
       
   204 {
       
   205     return selMode == Q3Table::SingleRow || selMode == Q3Table::MultiRow;
       
   206 }
       
   207 
       
   208 /*!
       
   209     \class Q3TableSelection
       
   210     \brief The Q3TableSelection class provides access to a selected area in a
       
   211     Q3Table.
       
   212 
       
   213     \compat
       
   214 
       
   215     The selection is a rectangular set of cells in a Q3Table. One of
       
   216     the rectangle's cells is called the anchor cell; this is the cell
       
   217     that was selected first. The init() function sets the anchor and
       
   218     the selection rectangle to exactly this cell; the expandTo()
       
   219     function expands the selection rectangle to include additional
       
   220     cells.
       
   221 
       
   222     There are various access functions to find out about the area:
       
   223     anchorRow() and anchorCol() return the anchor's position;
       
   224     leftCol(), rightCol(), topRow() and bottomRow() return the
       
   225     rectangle's four edges. All four are part of the selection.
       
   226 
       
   227     A newly created Q3TableSelection is inactive -- isActive() returns
       
   228     false. You must use init() and expandTo() to activate it.
       
   229 
       
   230     \sa Q3Table Q3Table::addSelection() Q3Table::selection()
       
   231     Q3Table::selectCells() Q3Table::selectRow() Q3Table::selectColumn()
       
   232 */
       
   233 
       
   234 /*!
       
   235     Creates an inactive selection. Use init() and expandTo() to
       
   236     activate it.
       
   237 */
       
   238 
       
   239 Q3TableSelection::Q3TableSelection()
       
   240     : active(false), inited(false), tRow(-1), lCol(-1),
       
   241       bRow(-1), rCol(-1), aRow(-1), aCol(-1)
       
   242 {
       
   243 }
       
   244 
       
   245 /*!
       
   246     Creates an active selection, starting at \a start_row and \a
       
   247     start_col, ending at \a end_row and \a end_col.
       
   248 */
       
   249 
       
   250 Q3TableSelection::Q3TableSelection(int start_row, int start_col, int end_row, int end_col)
       
   251     : active(false), inited(false), tRow(-1), lCol(-1),
       
   252       bRow(-1), rCol(-1), aRow(-1), aCol(-1)
       
   253 {
       
   254     init(start_row, start_col);
       
   255     expandTo(end_row, end_col);
       
   256 }
       
   257 
       
   258 /*!
       
   259     Sets the selection anchor to cell \a row, \a col and the selection
       
   260     to only contain this cell. The selection is not active until
       
   261     expandTo() is called.
       
   262 
       
   263     To extend the selection to include additional cells, call
       
   264     expandTo().
       
   265 
       
   266     \sa isActive()
       
   267 */
       
   268 
       
   269 void Q3TableSelection::init(int row, int col)
       
   270 {
       
   271     aCol = lCol = rCol = col;
       
   272     aRow = tRow = bRow = row;
       
   273     active = false;
       
   274     inited = true;
       
   275 }
       
   276 
       
   277 /*!
       
   278     Expands the selection to include cell \a row, \a col. The new
       
   279     selection rectangle is the bounding rectangle of \a row, \a col
       
   280     and the previous selection rectangle. After calling this function
       
   281     the selection is active.
       
   282 
       
   283     If you haven't called init(), this function does nothing.
       
   284 
       
   285     \sa init() isActive()
       
   286 */
       
   287 
       
   288 void Q3TableSelection::expandTo(int row, int col)
       
   289 {
       
   290     if (!inited)
       
   291         return;
       
   292     active = true;
       
   293 
       
   294     if (row < aRow) {
       
   295         tRow = row;
       
   296         bRow = aRow;
       
   297     } else {
       
   298         tRow = aRow;
       
   299         bRow = row;
       
   300     }
       
   301 
       
   302     if (col < aCol) {
       
   303         lCol = col;
       
   304         rCol = aCol;
       
   305     } else {
       
   306         lCol = aCol;
       
   307         rCol = col;
       
   308     }
       
   309 }
       
   310 
       
   311 /*!
       
   312     Returns true if \a s includes the same cells as the selection;
       
   313     otherwise returns false.
       
   314 */
       
   315 
       
   316 bool Q3TableSelection::operator==(const Q3TableSelection &s) const
       
   317 {
       
   318     return (s.active == active &&
       
   319              s.tRow == tRow && s.bRow == bRow &&
       
   320              s.lCol == lCol && s.rCol == rCol);
       
   321 }
       
   322 
       
   323 /*!
       
   324     \fn bool Q3TableSelection::operator!=(const Q3TableSelection &s) const
       
   325 
       
   326     Returns true if \a s does not include the same cells as the
       
   327     selection; otherwise returns false.
       
   328 */
       
   329 
       
   330 
       
   331 /*!
       
   332     \fn int Q3TableSelection::topRow() const
       
   333 
       
   334     Returns the top row of the selection.
       
   335 
       
   336     \sa bottomRow() leftCol() rightCol()
       
   337 */
       
   338 
       
   339 /*!
       
   340     \fn int Q3TableSelection::bottomRow() const
       
   341 
       
   342     Returns the bottom row of the selection.
       
   343 
       
   344     \sa topRow() leftCol() rightCol()
       
   345 */
       
   346 
       
   347 /*!
       
   348     \fn int Q3TableSelection::leftCol() const
       
   349 
       
   350     Returns the left column of the selection.
       
   351 
       
   352     \sa topRow() bottomRow() rightCol()
       
   353 */
       
   354 
       
   355 /*!
       
   356     \fn int Q3TableSelection::rightCol() const
       
   357 
       
   358     Returns the right column of the selection.
       
   359 
       
   360     \sa topRow() bottomRow() leftCol()
       
   361 */
       
   362 
       
   363 /*!
       
   364     \fn int Q3TableSelection::anchorRow() const
       
   365 
       
   366     Returns the anchor row of the selection.
       
   367 
       
   368     \sa anchorCol() expandTo()
       
   369 */
       
   370 
       
   371 /*!
       
   372     \fn int Q3TableSelection::anchorCol() const
       
   373 
       
   374     Returns the anchor column of the selection.
       
   375 
       
   376     \sa anchorRow() expandTo()
       
   377 */
       
   378 
       
   379 /*!
       
   380     \fn int Q3TableSelection::numRows() const
       
   381 
       
   382     Returns the number of rows in the selection.
       
   383 
       
   384     \sa numCols()
       
   385 */
       
   386 int Q3TableSelection::numRows() const
       
   387 {
       
   388     return (tRow < 0) ? 0 : bRow - tRow + 1;
       
   389 }
       
   390 
       
   391 /*!
       
   392     Returns the number of columns in the selection.
       
   393 
       
   394     \sa numRows()
       
   395 */
       
   396 int Q3TableSelection::numCols() const
       
   397 {
       
   398     return (lCol < 0) ? 0 : rCol - lCol + 1;
       
   399 }
       
   400 
       
   401 /*!
       
   402     \fn bool Q3TableSelection::isActive() const
       
   403 
       
   404     Returns whether the selection is active or not. A selection is
       
   405     active after init() \e and expandTo() have been called.
       
   406 */
       
   407 
       
   408 /*!
       
   409     \fn bool Q3TableSelection::isEmpty() const
       
   410 
       
   411     Returns whether the selection is empty or not.
       
   412 
       
   413     \sa numRows(), numCols()
       
   414 */
       
   415 
       
   416 /*!
       
   417     \class Q3TableItem
       
   418     \brief The Q3TableItem class provides the cell content for Q3Table cells.
       
   419 
       
   420     \compat
       
   421 
       
   422     For many applications Q3TableItems are ideal for presenting and
       
   423     editing the contents of Q3Table cells. In situations where you need
       
   424     to create very large tables you may prefer an alternative approach
       
   425     to using Q3TableItems: see the notes on large tables.
       
   426 
       
   427     A Q3TableItem contains a cell's data, by default, a string and a
       
   428     pixmap. The table item also holds the cell's display size and how
       
   429     the data should be aligned. The table item specifies the cell's
       
   430     \l EditType and the editor used for in-place editing (by default a
       
   431     QLineEdit). If you want checkboxes use \l{Q3CheckTableItem}, and if
       
   432     you want comboboxes use \l{Q3ComboTableItem}. The \l EditType (set
       
   433     in the constructor) determines whether the cell's contents may be
       
   434     edited.
       
   435 
       
   436     If a pixmap is specified it is displayed to the left of any text.
       
   437     You can change the text or pixmap with setText() and setPixmap()
       
   438     respectively. For text you can use setWordWrap().
       
   439 
       
   440     When sorting table items the key() function is used; by default
       
   441     this returns the table item's text(). Reimplement key() to
       
   442     customize how your table items will sort.
       
   443 
       
   444     Table items are inserted into a table using Q3Table::setItem(). If
       
   445     you insert an item into a cell that already contains a table item
       
   446     the original item will be deleted.
       
   447 
       
   448     Example:
       
   449     \snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 0
       
   450 
       
   451     You can move a table item from one cell to another, in the same or
       
   452     a different table, using Q3Table::takeItem() and Q3Table::setItem()
       
   453     but see also Q3Table::swapCells().
       
   454 
       
   455     Table items can be deleted with delete in the standard way; the
       
   456     table and cell will be updated accordingly.
       
   457 
       
   458     Note, that if you have a table item that is not currently in a table
       
   459     then anything you do to that item other than insert it into a table
       
   460     will result in undefined behaviour.
       
   461 
       
   462     Reimplement createEditor() and setContentFromEditor() if you want
       
   463     to use your own widget instead of a QLineEdit for editing cell
       
   464     contents. Reimplement paint() if you want to display custom
       
   465     content.
       
   466 
       
   467     It is important to ensure that your custom widget can accept the
       
   468     keyboard focus, so that the user can use the tab key to navigate the
       
   469     table as normal. Therefore, if the widget returned by createEditor()
       
   470     does not itself accept the keyboard focus, it is necessary to
       
   471     nominate a child widget to do so on its behalf. For example, a
       
   472     QHBox with two child QLineEdit widgets may use one of them to
       
   473     accept the keyboard focus:
       
   474 
       
   475     \snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 1
       
   476 
       
   477     By default, table items may be replaced by new Q3TableItems
       
   478     during the lifetime of a Q3Table. Therefore, if you create your
       
   479     own subclass of Q3TableItem, and you want to ensure that
       
   480     this does not happen, you must call setReplaceable(false)
       
   481     in the constructor of your subclass.
       
   482 
       
   483     \img qtableitems.png Table Items
       
   484 
       
   485     \sa Q3CheckTableItem Q3ComboTableItem
       
   486 
       
   487 */
       
   488 
       
   489 /*!
       
   490     \fn Q3Table *Q3TableItem::table() const
       
   491 
       
   492     Returns the Q3Table the table item belongs to.
       
   493 
       
   494     \sa Q3Table::setItem() Q3TableItem()
       
   495 */
       
   496 
       
   497 /*!
       
   498     \enum Q3TableItem::EditType
       
   499 
       
   500     \target wheneditable
       
   501     This enum is used to define whether a cell is editable or
       
   502     read-only (in conjunction with other settings), and how the cell
       
   503     should be displayed.
       
   504 
       
   505     \value Always
       
   506     The cell always \e looks editable.
       
   507 
       
   508     Using this EditType ensures that the editor created with
       
   509     createEditor() (by default a QLineEdit) is always visible. This
       
   510     has implications for the alignment of the content: the default
       
   511     editor aligns everything (even numbers) to the left whilst
       
   512     numerical values in the cell are by default aligned to the right.
       
   513 
       
   514     If a cell with the edit type \c Always looks misaligned you could
       
   515     reimplement createEditor() for these items.
       
   516 
       
   517     \value WhenCurrent
       
   518     The cell \e looks editable only when it has keyboard focus (see
       
   519     Q3Table::setCurrentCell()).
       
   520 
       
   521     \value OnTyping
       
   522     The cell \e looks editable only when the user types in it or
       
   523     double-clicks it. It resembles the \c WhenCurrent functionality
       
   524     but is, perhaps, nicer.
       
   525 
       
   526     The \c OnTyping edit type is the default when Q3TableItem objects
       
   527     are created by the convenience functions Q3Table::setText() and
       
   528     Q3Table::setPixmap().
       
   529 
       
   530     \value Never  The cell is not editable.
       
   531 
       
   532     The cell is actually editable only if Q3Table::isRowReadOnly() is
       
   533     false for its row, Q3Table::isColumnReadOnly() is false for its
       
   534     column, and Q3Table::isReadOnly() is false.
       
   535 
       
   536     Q3ComboTableItems have an isEditable() property. This property is
       
   537     used to indicate whether the user may enter their own text or are
       
   538     restricted to choosing one of the choices in the list.
       
   539     Q3ComboTableItems may be interacted with only if they are editable
       
   540     in accordance with their EditType as described above.
       
   541 
       
   542 */
       
   543 
       
   544 /*!
       
   545     Creates a table item that is a child of table \a table with no
       
   546     text. The item has the \l EditType \a et.
       
   547 
       
   548     The table item will use a QLineEdit for its editor, will not
       
   549     word-wrap and will occupy a single cell. Insert the table item
       
   550     into a table with Q3Table::setItem().
       
   551 
       
   552     The table takes ownership of the table item, so a table item
       
   553     should not be inserted into more than one table at a time.
       
   554 */
       
   555 
       
   556 Q3TableItem::Q3TableItem(Q3Table *table, EditType et)
       
   557     : txt(), pix(), t(table), edType(et), wordwrap(false),
       
   558       tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1)
       
   559 {
       
   560     enabled = true;
       
   561 }
       
   562 
       
   563 /*!
       
   564     Creates a table item that is a child of table \a table with text
       
   565     \a text. The item has the \l EditType \a et.
       
   566 
       
   567     The table item will use a QLineEdit for its editor, will not
       
   568     word-wrap and will occupy a single cell. Insert the table item
       
   569     into a table with Q3Table::setItem().
       
   570 
       
   571     The table takes ownership of the table item, so a table item
       
   572     should not be inserted into more than one table at a time.
       
   573 */
       
   574 
       
   575 Q3TableItem::Q3TableItem(Q3Table *table, EditType et, const QString &text)
       
   576     : txt(text), pix(), t(table), edType(et), wordwrap(false),
       
   577       tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1)
       
   578 {
       
   579     enabled = true;
       
   580 }
       
   581 
       
   582 /*!
       
   583     Creates a table item that is a child of table \a table with text
       
   584     \a text and pixmap \a p. The item has the \l EditType \a et.
       
   585 
       
   586     The table item will display the pixmap to the left of the text. It
       
   587     will use a QLineEdit for editing the text, will not word-wrap and
       
   588     will occupy a single cell. Insert the table item into a table with
       
   589     Q3Table::setItem().
       
   590 
       
   591     The table takes ownership of the table item, so a table item
       
   592     should not be inserted in more than one table at a time.
       
   593 */
       
   594 
       
   595 Q3TableItem::Q3TableItem(Q3Table *table, EditType et,
       
   596                         const QString &text, const QPixmap &p)
       
   597     : txt(text), pix(p), t(table), edType(et), wordwrap(false),
       
   598       tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1)
       
   599 {
       
   600     enabled = true;
       
   601 }
       
   602 
       
   603 /*!
       
   604     The destructor deletes this item and frees all allocated
       
   605     resources.
       
   606 
       
   607     If the table item is in a table (i.e. was inserted with
       
   608     setItem()), it will be removed from the table and the cell it
       
   609     occupied.
       
   610 */
       
   611 
       
   612 Q3TableItem::~Q3TableItem()
       
   613 {
       
   614     if (table())
       
   615         table()->takeItem(this);
       
   616 }
       
   617 
       
   618 int Q3TableItem::RTTI = 0;
       
   619 
       
   620 /*!
       
   621     Returns the Run Time Type Identification value for this table item
       
   622     which for Q3TableItems is 0.
       
   623 
       
   624     When you create subclasses based on Q3TableItem make sure that each
       
   625     subclass returns a unique rtti() value. It is advisable to use
       
   626     values greater than 1000, preferably large random numbers, to
       
   627     allow for extensions to this class.
       
   628 
       
   629     \sa Q3CheckTableItem::rtti() Q3ComboTableItem::rtti()
       
   630 */
       
   631 
       
   632 int Q3TableItem::rtti() const
       
   633 {
       
   634     return RTTI;
       
   635 }
       
   636 
       
   637 /*!
       
   638     Returns the table item's pixmap or a null pixmap if no pixmap has
       
   639     been set.
       
   640 
       
   641     \sa setPixmap() text()
       
   642 */
       
   643 
       
   644 QPixmap Q3TableItem::pixmap() const
       
   645 {
       
   646     return pix;
       
   647 }
       
   648 
       
   649 
       
   650 /*!
       
   651     Returns the text of the table item or an empty string if there is
       
   652     no text.
       
   653 
       
   654     To ensure that the current value of the editor is returned,
       
   655     setContentFromEditor() is called:
       
   656     \list 1
       
   657     \i if the editMode() is \c Always, or
       
   658     \i if editMode() is \e not \c Always but the editor of the cell is
       
   659     active and the editor is not a QLineEdit.
       
   660     \endlist
       
   661 
       
   662     This means that text() returns the original text value of the item
       
   663     if the editor is a line edit, until the user commits an edit (e.g.
       
   664     by pressing Enter or Tab) in which case the new text is returned.
       
   665     For other editors (e.g. a combobox) setContentFromEditor() is
       
   666     always called so the currently display value is the one returned.
       
   667 
       
   668     \sa setText() pixmap()
       
   669 */
       
   670 
       
   671 QString Q3TableItem::text() const
       
   672 {
       
   673     QWidget *w = table()->cellWidget(rw, cl);
       
   674     if (w && (edType == Always ||
       
   675                 rtti() == Q3ComboTableItem::RTTI ||
       
   676                 rtti() == Q3CheckTableItem::RTTI))
       
   677         ((Q3TableItem*)this)->setContentFromEditor(w);
       
   678     return txt;
       
   679 }
       
   680 
       
   681 /*!
       
   682     Sets pixmap \a p to be this item's pixmap.
       
   683 
       
   684     Note that setPixmap() does not update the cell the table item
       
   685     belongs to. Use Q3Table::updateCell() to repaint the cell's
       
   686     contents.
       
   687 
       
   688     For \l{Q3ComboTableItem}s and \l{Q3CheckTableItem}s this function
       
   689     has no visible effect.
       
   690 
       
   691     \sa Q3Table::setPixmap() pixmap() setText()
       
   692 */
       
   693 
       
   694 void Q3TableItem::setPixmap(const QPixmap &p)
       
   695 {
       
   696     pix = p;
       
   697 }
       
   698 
       
   699 /*!
       
   700     Changes the table item's text to \a str.
       
   701 
       
   702     Note that setText() does not update the cell the table item
       
   703     belongs to. Use Q3Table::updateCell() to repaint the cell's
       
   704     contents.
       
   705 
       
   706     \sa Q3Table::setText() text() setPixmap() Q3Table::updateCell()
       
   707 */
       
   708 
       
   709 void Q3TableItem::setText(const QString &str)
       
   710 {
       
   711     txt = str;
       
   712 }
       
   713 
       
   714 /*!
       
   715     This virtual function is used to paint the contents of an item
       
   716     using the painter \a p in the rectangular area \a cr using the
       
   717     color group \a cg.
       
   718 
       
   719     If \a selected is true the cell is displayed in a way that
       
   720     indicates that it is highlighted.
       
   721 
       
   722     You don't usually need to use this function but if you want to
       
   723     draw custom content in a cell you will need to reimplement it.
       
   724 
       
   725     The painter passed to this function is translated so that 0, 0
       
   726     is the top-left corner of the item that is being painted.
       
   727 
       
   728     Note that the painter is not clipped by default in order to get
       
   729     maximum efficiency. If you want clipping, use
       
   730 
       
   731     \snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 2
       
   732 
       
   733 */
       
   734 
       
   735 void Q3TableItem::paint(QPainter *p, const QColorGroup &cg,
       
   736                         const QRect &cr, bool selected)
       
   737 {
       
   738     p->fillRect(0, 0, cr.width(), cr.height(),
       
   739                  selected ? cg.brush(QColorGroup::Highlight)
       
   740                           : cg.brush(QColorGroup::Base));
       
   741 
       
   742     int w = cr.width();
       
   743     int h = cr.height();
       
   744 
       
   745     int x = 0;
       
   746     if (!pix.isNull()) {
       
   747         p->drawPixmap(0, (cr.height() - pix.height()) / 2, pix);
       
   748         x = pix.width() + 2;
       
   749     }
       
   750 
       
   751     if (selected)
       
   752         p->setPen(cg.highlightedText());
       
   753     else
       
   754         p->setPen(cg.text());
       
   755     p->drawText(x + 2, 0, w - x - 4, h,
       
   756                  wordwrap ? (alignment() | WordBreak) : alignment(), text());
       
   757 }
       
   758 
       
   759 /*!
       
   760 This virtual function creates an editor which the user can
       
   761 interact with to edit the cell's contents. The default
       
   762 implementation creates a QLineEdit.
       
   763 
       
   764 If the function returns 0, the cell is read-only.
       
   765 
       
   766 The returned widget should preferably be invisible, ideally with
       
   767 Q3Table::viewport() as parent.
       
   768 
       
   769 If you reimplement this function you'll almost certainly need to
       
   770 reimplement setContentFromEditor(), and may need to reimplement
       
   771 sizeHint().
       
   772 
       
   773 \sa Q3Table::createEditor() setContentFromEditor() Q3Table::viewport() setReplaceable()
       
   774 */
       
   775 
       
   776 QWidget *Q3TableItem::createEditor() const
       
   777 {
       
   778     QLineEdit *e = new QLineEdit(table()->viewport(), "qt_tableeditor");
       
   779     e->setFrame(false);
       
   780     e->setText(text());
       
   781     return e;
       
   782 }
       
   783 
       
   784 /*!
       
   785 Whenever the content of a cell has been edited by the editor \a w,
       
   786 Q3Table calls this virtual function to copy the new values into the
       
   787 Q3TableItem.
       
   788 
       
   789 If you reimplement createEditor() and return something that is not
       
   790 a QLineEdit you will need to reimplement this function.
       
   791 
       
   792 \sa Q3Table::setCellContentFromEditor()
       
   793 */
       
   794 
       
   795 void Q3TableItem::setContentFromEditor(QWidget *w)
       
   796 {
       
   797     QLineEdit *le = qobject_cast<QLineEdit*>(w);
       
   798     if (le) {
       
   799         QString input = le->text();
       
   800         if (le->validator())
       
   801             le->validator()->fixup(input);
       
   802         setText(input);
       
   803     }
       
   804 }
       
   805 
       
   806 /*!
       
   807     The alignment function returns how the text contents of the cell
       
   808     are aligned when drawn. The default implementation aligns numbers
       
   809     to the right and any other text to the left.
       
   810 
       
   811     \sa Qt::Alignment
       
   812 */
       
   813 
       
   814 // ed: For consistency reasons a setAlignment() should be provided
       
   815 // as well.
       
   816 
       
   817 int Q3TableItem::alignment() const
       
   818 {
       
   819     bool num;
       
   820     bool ok1 = false, ok2 = false;
       
   821     (void)text().toInt(&ok1);
       
   822     if (!ok1)
       
   823         (void)text().toDouble(&ok2); // ### should be .-aligned
       
   824     num = ok1 || ok2;
       
   825 
       
   826     return (num ? AlignRight : AlignLeft) | AlignVCenter;
       
   827 }
       
   828 
       
   829 /*!
       
   830     If \a b is true, the cell's text will be wrapped over multiple
       
   831     lines, when necessary, to fit the width of the cell; otherwise the
       
   832     text will be written as a single line.
       
   833 
       
   834     \sa wordWrap() Q3Table::adjustColumn() Q3Table::setColumnStretchable()
       
   835 */
       
   836 
       
   837 void Q3TableItem::setWordWrap(bool b)
       
   838 {
       
   839     wordwrap = b;
       
   840 }
       
   841 
       
   842 /*!
       
   843     Returns true if word wrap is enabled for the cell; otherwise
       
   844     returns false.
       
   845 
       
   846     \sa setWordWrap()
       
   847 */
       
   848 
       
   849 bool Q3TableItem::wordWrap() const
       
   850 {
       
   851     return wordwrap;
       
   852 }
       
   853 
       
   854 /*! \internal */
       
   855 
       
   856 void Q3TableItem::updateEditor(int oldRow, int oldCol)
       
   857 {
       
   858     if (edType != Always)
       
   859         return;
       
   860     if (oldRow != -1 && oldCol != -1)
       
   861         table()->clearCellWidget(oldRow, oldCol);
       
   862     if (rw != -1 && cl != -1)
       
   863         table()->setCellWidget(rw, cl, createEditor());
       
   864 }
       
   865 
       
   866 /*!
       
   867     Returns the table item's edit type.
       
   868 
       
   869     This is set when the table item is constructed.
       
   870 
       
   871     \sa EditType Q3TableItem()
       
   872 */
       
   873 
       
   874 Q3TableItem::EditType Q3TableItem::editType() const
       
   875 {
       
   876     return edType;
       
   877 }
       
   878 
       
   879 /*!
       
   880     If \a b is true it is acceptable to replace the contents of the
       
   881     cell with the contents of another Q3TableItem. If \a b is false the
       
   882     contents of the cell may not be replaced by the contents of
       
   883     another table item. Table items that span more than one cell may
       
   884     not have their contents replaced by another table item.
       
   885 
       
   886     (This differs from \l EditType because EditType is concerned with
       
   887     whether the \e user is able to change the contents of a cell.)
       
   888 
       
   889     \sa isReplaceable()
       
   890 */
       
   891 
       
   892 void Q3TableItem::setReplaceable(bool b)
       
   893 {
       
   894     tcha = b;
       
   895 }
       
   896 
       
   897 /*!
       
   898     This function returns whether the contents of the cell may be
       
   899     replaced with the contents of another table item. Regardless of
       
   900     this setting, table items that span more than one cell may not
       
   901     have their contents replaced by another table item.
       
   902 
       
   903     (This differs from \l EditType because EditType is concerned with
       
   904     whether the \e user is able to change the contents of a cell.)
       
   905 
       
   906     \sa setReplaceable() EditType
       
   907 */
       
   908 
       
   909 bool Q3TableItem::isReplaceable() const
       
   910 {
       
   911     if (rowspan > 1 || colspan > 1)
       
   912         return false;
       
   913     return tcha;
       
   914 }
       
   915 
       
   916 /*!
       
   917     This virtual function returns the key that should be used for
       
   918     sorting. The default implementation returns the text() of the
       
   919     relevant item.
       
   920 
       
   921     \sa Q3Table::setSorting()
       
   922 */
       
   923 
       
   924 QString Q3TableItem::key() const
       
   925 {
       
   926     return text();
       
   927 }
       
   928 
       
   929 /*!
       
   930     This virtual function returns the size a cell needs to show its
       
   931     entire content.
       
   932 
       
   933     If you subclass Q3TableItem you will often need to reimplement this
       
   934     function.
       
   935 */
       
   936 
       
   937 QSize Q3TableItem::sizeHint() const
       
   938 {
       
   939     QSize strutSize = QApplication::globalStrut();
       
   940     if (edType == Always && table()->cellWidget(rw, cl))
       
   941         return table()->cellWidget(rw, cl)->sizeHint().expandedTo(strutSize);
       
   942 
       
   943     QSize s;
       
   944     int x = 0;
       
   945     if (!pix.isNull()) {
       
   946         s = pix.size();
       
   947         s.setWidth(s.width() + 2);
       
   948         x = pix.width() + 2;
       
   949     }
       
   950 
       
   951     QString t = text();
       
   952     if (!wordwrap && t.find(QLatin1Char('\n')) == -1)
       
   953         return QSize(s.width() + table()->fontMetrics().width(text()) + 10,
       
   954                       QMAX(s.height(), table()->fontMetrics().height())).expandedTo(strutSize);
       
   955 
       
   956     QRect r = table()->fontMetrics().boundingRect(x + 2, 0, table()->columnWidth(col()) - x - 4, 0,
       
   957                                                    wordwrap ? (alignment() | WordBreak) : alignment(),
       
   958                                                    text());
       
   959     r.setWidth(QMAX(r.width() + 10, table()->columnWidth(col())));
       
   960     return QSize(r.width(), QMAX(s.height(), r.height())).expandedTo(strutSize);
       
   961 }
       
   962 
       
   963 /*!
       
   964     Changes the extent of the Q3TableItem so that it spans multiple
       
   965     cells covering \a rs rows and \a cs columns. The top left cell is
       
   966     the original cell.
       
   967 
       
   968     \warning This function only works if the item has already been
       
   969     inserted into the table using e.g. Q3Table::setItem(). This
       
   970     function also checks to make sure if \a rs and \a cs are within
       
   971     the bounds of the table and returns without changing the span if
       
   972     they are not. In addition swapping, inserting or removing rows and
       
   973     columns that cross Q3TableItems spanning more than one cell is not
       
   974     supported.
       
   975 
       
   976     \sa rowSpan() colSpan()
       
   977 */
       
   978 
       
   979 void Q3TableItem::setSpan(int rs, int cs)
       
   980 {
       
   981     if (rs == rowspan && cs == colspan)
       
   982         return;
       
   983 
       
   984     if (!table()->d->hasRowSpan)
       
   985         table()->d->hasRowSpan = rs > 1;
       
   986     if (!table()->d->hasColSpan)
       
   987         table()->d->hasColSpan = cs > 1;
       
   988     // return if we are thinking too big...
       
   989     if (rw + rs > table()->numRows())
       
   990         return;
       
   991 
       
   992     if (cl + cs > table()->numCols())
       
   993         return;
       
   994 
       
   995     if (rw == -1 || cl == -1)
       
   996         return;
       
   997 
       
   998     int rrow = rw;
       
   999     int rcol = cl;
       
  1000     if (rowspan > 1 || colspan > 1) {
       
  1001         Q3Table* t = table();
       
  1002         t->takeItem(this);
       
  1003         t->setItem(rrow, rcol, this);
       
  1004     }
       
  1005 
       
  1006     rowspan = rs;
       
  1007     colspan = cs;
       
  1008 
       
  1009     for (int r = 0; r < rowspan; ++r) {
       
  1010         for (int c = 0; c < colspan; ++c) {
       
  1011             if (r == 0 && c == 0)
       
  1012                 continue;
       
  1013             qt_update_cell_widget = false;
       
  1014             table()->setItem(r + rw, c + cl, this);
       
  1015             qt_update_cell_widget = true;
       
  1016             rw = rrow;
       
  1017             cl = rcol;
       
  1018         }
       
  1019     }
       
  1020 
       
  1021     table()->updateCell(rw, cl);
       
  1022     QWidget *w = table()->cellWidget(rw, cl);
       
  1023     if (w)
       
  1024         w->resize(table()->cellGeometry(rw, cl).size());
       
  1025 }
       
  1026 
       
  1027 /*!
       
  1028     Returns the row span of the table item, usually 1.
       
  1029 
       
  1030     \sa setSpan() colSpan()
       
  1031 */
       
  1032 
       
  1033 int Q3TableItem::rowSpan() const
       
  1034 {
       
  1035     return rowspan;
       
  1036 }
       
  1037 
       
  1038 /*!
       
  1039     Returns the column span of the table item, usually 1.
       
  1040 
       
  1041     \sa setSpan() rowSpan()
       
  1042 */
       
  1043 
       
  1044 int Q3TableItem::colSpan() const
       
  1045 {
       
  1046     return colspan;
       
  1047 }
       
  1048 
       
  1049 /*!
       
  1050     Sets row \a r as the table item's row. Usually you do not need to
       
  1051     call this function.
       
  1052 
       
  1053     If the cell spans multiple rows, this function sets the top row
       
  1054     and retains the height of the multi-cell table item.
       
  1055 
       
  1056     \sa row() setCol() rowSpan()
       
  1057 */
       
  1058 
       
  1059 void Q3TableItem::setRow(int r)
       
  1060 {
       
  1061     rw = r;
       
  1062 }
       
  1063 
       
  1064 /*!
       
  1065     Sets column \a c as the table item's column. Usually you will not
       
  1066     need to call this function.
       
  1067 
       
  1068     If the cell spans multiple columns, this function sets the
       
  1069     left-most column and retains the width of the multi-cell table
       
  1070     item.
       
  1071 
       
  1072     \sa col() setRow() colSpan()
       
  1073 */
       
  1074 
       
  1075 void Q3TableItem::setCol(int c)
       
  1076 {
       
  1077     cl = c;
       
  1078 }
       
  1079 
       
  1080 /*!
       
  1081     Returns the row where the table item is located. If the cell spans
       
  1082     multiple rows, this function returns the top-most row.
       
  1083 
       
  1084     \sa col() setRow()
       
  1085 */
       
  1086 
       
  1087 int Q3TableItem::row() const
       
  1088 {
       
  1089     return rw;
       
  1090 }
       
  1091 
       
  1092 /*!
       
  1093     Returns the column where the table item is located. If the cell
       
  1094     spans multiple columns, this function returns the left-most
       
  1095     column.
       
  1096 
       
  1097     \sa row() setCol()
       
  1098 */
       
  1099 
       
  1100 int Q3TableItem::col() const
       
  1101 {
       
  1102     return cl;
       
  1103 }
       
  1104 
       
  1105 /*!
       
  1106     If \a b is true, the table item is enabled; if \a b is false the
       
  1107     table item is disabled.
       
  1108 
       
  1109     A disabled item doesn't respond to user interaction.
       
  1110 
       
  1111     \sa isEnabled()
       
  1112 */
       
  1113 
       
  1114 void Q3TableItem::setEnabled(bool b)
       
  1115 {
       
  1116     if (b == (bool)enabled)
       
  1117         return;
       
  1118     enabled = b;
       
  1119     table()->updateCell(row(), col());
       
  1120 }
       
  1121 
       
  1122 /*!
       
  1123     Returns true if the table item is enabled; otherwise returns false.
       
  1124 
       
  1125     \sa setEnabled()
       
  1126 */
       
  1127 
       
  1128 bool Q3TableItem::isEnabled() const
       
  1129 {
       
  1130     return (bool)enabled;
       
  1131 }
       
  1132 
       
  1133 /*!
       
  1134     \class Q3ComboTableItem
       
  1135     \brief The Q3ComboTableItem class provides a means of using
       
  1136     comboboxes in Q3Tables.
       
  1137 
       
  1138     \compat
       
  1139 
       
  1140     A Q3ComboTableItem is a table item which looks and behaves like a
       
  1141     combobox. The advantage of using Q3ComboTableItems rather than real
       
  1142     comboboxes is that a Q3ComboTableItem uses far less resources than
       
  1143     real comboboxes in \l{Q3Table}s. When the cell has the focus it
       
  1144     displays a real combobox which the user can interact with. When
       
  1145     the cell does not have the focus the cell \e looks like a
       
  1146     combobox. Only text items (i.e. no pixmaps) may be used in
       
  1147     Q3ComboTableItems.
       
  1148 
       
  1149     Q3ComboTableItem items have the edit type \c WhenCurrent (see
       
  1150     \l{EditType}). The Q3ComboTableItem's list of items is provided by
       
  1151     a QStringList passed to the constructor.
       
  1152 
       
  1153     The list of items may be changed using setStringList(). The
       
  1154     current item can be set with setCurrentItem() and retrieved with
       
  1155     currentItem(). The text of the current item can be obtained with
       
  1156     currentText(), and the text of a particular item can be retrieved
       
  1157     with text().
       
  1158 
       
  1159     If isEditable() is true the Q3ComboTableItem will permit the user
       
  1160     to either choose an existing list item, or create a new list item
       
  1161     by entering their own text; otherwise the user may only choose one
       
  1162     of the existing list items.
       
  1163 
       
  1164     To populate a table cell with a Q3ComboTableItem use
       
  1165     Q3Table::setItem().
       
  1166 
       
  1167     Q3ComboTableItems may be deleted with Q3Table::clearCell().
       
  1168 
       
  1169     Q3ComboTableItems can be distinguished from \l{Q3TableItem}s and
       
  1170     \l{Q3CheckTableItem}s using their Run Time Type Identification
       
  1171     number (see rtti()).
       
  1172 
       
  1173     \img qtableitems.png Table Items
       
  1174 
       
  1175     \sa Q3CheckTableItem Q3TableItem Q3ComboBox
       
  1176 */
       
  1177 
       
  1178 Q3ComboBox *Q3ComboTableItem::fakeCombo = 0;
       
  1179 QWidget *Q3ComboTableItem::fakeComboWidget = 0;
       
  1180 int Q3ComboTableItem::fakeRef = 0;
       
  1181 
       
  1182 /*!
       
  1183     Creates a combo table item for the table \a table. The combobox's
       
  1184     list of items is passed in the \a list argument. If \a editable is
       
  1185     true the user may type in new list items; if \a editable is false
       
  1186     the user may only select from the list of items provided.
       
  1187 
       
  1188     By default Q3ComboTableItems cannot be replaced by other table
       
  1189     items since isReplaceable() returns false by default.
       
  1190 
       
  1191     \sa Q3Table::clearCell() EditType
       
  1192 */
       
  1193 
       
  1194 Q3ComboTableItem::Q3ComboTableItem(Q3Table *table, const QStringList &list, bool editable)
       
  1195     : Q3TableItem(table, WhenCurrent, QLatin1String("")), entries(list), current(0), edit(editable)
       
  1196 {
       
  1197     setReplaceable(false);
       
  1198     if (!Q3ComboTableItem::fakeCombo) {
       
  1199         Q3ComboTableItem::fakeComboWidget = new QWidget(0, 0);
       
  1200         Q3ComboTableItem::fakeCombo = new Q3ComboBox(false, Q3ComboTableItem::fakeComboWidget, 0);
       
  1201         Q3ComboTableItem::fakeCombo->hide();
       
  1202     }
       
  1203     ++Q3ComboTableItem::fakeRef;
       
  1204     if (entries.count())
       
  1205         setText(entries.at(current));
       
  1206 }
       
  1207 
       
  1208 /*!
       
  1209     Q3ComboTableItem destructor.
       
  1210 */
       
  1211 Q3ComboTableItem::~Q3ComboTableItem()
       
  1212 {
       
  1213     if (--Q3ComboTableItem::fakeRef <= 0) {
       
  1214         delete Q3ComboTableItem::fakeComboWidget;
       
  1215         Q3ComboTableItem::fakeComboWidget = 0;
       
  1216         Q3ComboTableItem::fakeCombo = 0;
       
  1217     }
       
  1218 }
       
  1219 
       
  1220 /*!
       
  1221     Sets the list items of this Q3ComboTableItem to the strings in the
       
  1222     string list \a l.
       
  1223 */
       
  1224 
       
  1225 void Q3ComboTableItem::setStringList(const QStringList &l)
       
  1226 {
       
  1227     entries = l;
       
  1228     current = 0;
       
  1229     if (entries.count())
       
  1230         setText(entries.at(current));
       
  1231     if (table()->cellWidget(row(), col())) {
       
  1232         cb->clear();
       
  1233         cb->insertStringList(entries);
       
  1234     }
       
  1235     table()->updateCell(row(), col());
       
  1236 }
       
  1237 
       
  1238 /*! \reimp */
       
  1239 
       
  1240 QWidget *Q3ComboTableItem::createEditor() const
       
  1241 {
       
  1242     // create an editor - a combobox in our case
       
  1243     ((Q3ComboTableItem*)this)->cb = new Q3ComboBox(edit, table()->viewport(), "qt_editor_cb");
       
  1244     cb->insertStringList(entries);
       
  1245     cb->setCurrentItem(current);
       
  1246     QObject::connect(cb, SIGNAL(activated(int)), table(), SLOT(doValueChanged()));
       
  1247     return cb;
       
  1248 }
       
  1249 
       
  1250 /*! \reimp */
       
  1251 
       
  1252 void Q3ComboTableItem::setContentFromEditor(QWidget *w)
       
  1253 {
       
  1254     Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w);
       
  1255     if (cb) {
       
  1256         entries.clear();
       
  1257         for (int i = 0; i < cb->count(); ++i)
       
  1258             entries << cb->text(i);
       
  1259         current = cb->currentItem();
       
  1260         setText(cb->currentText());
       
  1261     }
       
  1262 }
       
  1263 
       
  1264 /*! \reimp */
       
  1265 
       
  1266 void Q3ComboTableItem::paint(QPainter *p, const QColorGroup &cg,
       
  1267                            const QRect &cr, bool selected)
       
  1268 {
       
  1269     fakeCombo->resize(cr.width(), cr.height());
       
  1270 
       
  1271     QPalette pal2(cg);
       
  1272     if (selected) {
       
  1273         pal2.setBrush(QPalette::Base, cg.QPalette::brush(QPalette::Highlight));
       
  1274         pal2.setColor(QPalette::Text, cg.highlightedText());
       
  1275     }
       
  1276 
       
  1277     QStyle::State flags = QStyle::State_None;
       
  1278     if(isEnabled() && table()->isEnabled())
       
  1279         flags |= QStyle::State_Enabled;
       
  1280     // Since we still have the "fakeCombo" may as well use it in this case.
       
  1281     QStyleOptionComboBox opt;
       
  1282     opt.initFrom(table());
       
  1283     opt.rect = fakeCombo->rect();
       
  1284     opt.palette = pal2;
       
  1285     opt.state &= ~QStyle::State_HasFocus;
       
  1286     opt.state &= ~QStyle::State_MouseOver;
       
  1287     opt.state |= flags;
       
  1288     opt.subControls = QStyle::SC_All;
       
  1289     opt.activeSubControls = QStyle::SC_None;
       
  1290     opt.editable = fakeCombo->editable();
       
  1291     table()->style()->drawComplexControl(QStyle::CC_ComboBox, &opt, p, fakeCombo);
       
  1292 
       
  1293     p->save();
       
  1294     QRect textR = table()->style()->subControlRect(QStyle::CC_ComboBox, &opt,
       
  1295                                                    QStyle::SC_ComboBoxEditField, fakeCombo);
       
  1296     int align = alignment(); // alignment() changes entries
       
  1297     p->drawText(textR, wordWrap() ? (align | Qt::WordBreak) : align, entries.value(current));
       
  1298     p->restore();
       
  1299 }
       
  1300 
       
  1301 /*!
       
  1302     Sets the list item \a i to be the combo table item's current list
       
  1303     item.
       
  1304 
       
  1305     \sa currentItem()
       
  1306 */
       
  1307 
       
  1308 void Q3ComboTableItem::setCurrentItem(int i)
       
  1309 {
       
  1310     QWidget *w = table()->cellWidget(row(), col());
       
  1311     Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w);
       
  1312     if (cb) {
       
  1313         cb->setCurrentItem(i);
       
  1314         current = cb->currentItem();
       
  1315         setText(cb->currentText());
       
  1316     } else {
       
  1317         if (i < 0 || i >= entries.count())
       
  1318             return;
       
  1319         current = i;
       
  1320         setText(entries.at(i));
       
  1321         table()->updateCell(row(), col());
       
  1322     }
       
  1323 }
       
  1324 
       
  1325 /*!
       
  1326     \overload
       
  1327 
       
  1328     Sets the list item whose text is \a s to be the combo table item's
       
  1329     current list item. Does nothing if no list item has the text \a s.
       
  1330 
       
  1331     \sa currentItem()
       
  1332 */
       
  1333 
       
  1334 void Q3ComboTableItem::setCurrentItem(const QString &s)
       
  1335 {
       
  1336     int i = entries.findIndex(s);
       
  1337     if (i != -1)
       
  1338         setCurrentItem(i);
       
  1339 }
       
  1340 
       
  1341 /*!
       
  1342     Returns the index of the combo table item's current list item.
       
  1343 
       
  1344     \sa setCurrentItem()
       
  1345 */
       
  1346 
       
  1347 int Q3ComboTableItem::currentItem() const
       
  1348 {
       
  1349     QWidget *w = table()->cellWidget(row(), col());
       
  1350     Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w);
       
  1351     if (cb)
       
  1352         return cb->currentItem();
       
  1353     return current;
       
  1354 }
       
  1355 
       
  1356 /*!
       
  1357     Returns the text of the combo table item's current list item.
       
  1358 
       
  1359     \sa currentItem() text()
       
  1360 */
       
  1361 
       
  1362 QString Q3ComboTableItem::currentText() const
       
  1363 {
       
  1364     QWidget *w = table()->cellWidget(row(), col());
       
  1365     Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w);
       
  1366     if (cb)
       
  1367         return cb->currentText();
       
  1368     return entries.value(current);
       
  1369 }
       
  1370 
       
  1371 /*!
       
  1372     Returns the total number of list items in the combo table item.
       
  1373 */
       
  1374 
       
  1375 int Q3ComboTableItem::count() const
       
  1376 {
       
  1377     QWidget *w = table()->cellWidget(row(), col());
       
  1378     Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w);
       
  1379     if (cb)
       
  1380         return cb->count();
       
  1381     return (int)entries.count();
       
  1382 }
       
  1383 
       
  1384 /*!
       
  1385     Returns the text of the combo's list item at index \a i.
       
  1386 
       
  1387     \sa currentText()
       
  1388 */
       
  1389 
       
  1390 QString Q3ComboTableItem::text(int i) const
       
  1391 {
       
  1392     QWidget *w = table()->cellWidget(row(), col());
       
  1393     Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w);
       
  1394     if (cb)
       
  1395         return cb->text(i);
       
  1396     return entries.value(i);
       
  1397 }
       
  1398 
       
  1399 /*!
       
  1400     If \a b is true the combo table item can be edited, i.e. the user
       
  1401     may enter a new text item themselves. If \a b is false the user may
       
  1402     may only choose one of the existing items.
       
  1403 
       
  1404     \sa isEditable()
       
  1405 */
       
  1406 
       
  1407 void Q3ComboTableItem::setEditable(bool b)
       
  1408 {
       
  1409     edit = b;
       
  1410 }
       
  1411 
       
  1412 /*!
       
  1413     Returns true if the user can add their own list items to the
       
  1414     combobox's list of items; otherwise returns false.
       
  1415 
       
  1416     \sa setEditable()
       
  1417 */
       
  1418 
       
  1419 bool Q3ComboTableItem::isEditable() const
       
  1420 {
       
  1421     return edit;
       
  1422 }
       
  1423 
       
  1424 int Q3ComboTableItem::RTTI = 1;
       
  1425 
       
  1426 /*!
       
  1427     \fn int Q3ComboTableItem::rtti() const
       
  1428 
       
  1429     Returns 1.
       
  1430 
       
  1431     Make your derived classes return their own values for rtti()to
       
  1432     distinguish between different table item subclasses. You should
       
  1433     use values greater than 1000, preferably a large random number, to
       
  1434     allow for extensions to this class.
       
  1435 
       
  1436 
       
  1437     \sa Q3TableItem::rtti()
       
  1438 */
       
  1439 
       
  1440 int Q3ComboTableItem::rtti() const
       
  1441 {
       
  1442     return RTTI;
       
  1443 }
       
  1444 
       
  1445 /*! \reimp */
       
  1446 
       
  1447 QSize Q3ComboTableItem::sizeHint() const
       
  1448 {
       
  1449     fakeCombo->insertItem(currentText());
       
  1450     fakeCombo->setCurrentItem(fakeCombo->count() - 1);
       
  1451     QSize sh = fakeCombo->sizeHint();
       
  1452     fakeCombo->removeItem(fakeCombo->count() - 1);
       
  1453     return sh.expandedTo(QApplication::globalStrut());
       
  1454 }
       
  1455 
       
  1456 /*!
       
  1457     \fn QString Q3ComboTableItem::text() const
       
  1458 
       
  1459     Returns the text of the table item or an empty string if there is
       
  1460     no text.
       
  1461 
       
  1462     \sa Q3TableItem::text()
       
  1463 */
       
  1464 
       
  1465 /*!
       
  1466     \class Q3CheckTableItem
       
  1467     \brief The Q3CheckTableItem class provides checkboxes in Q3Tables.
       
  1468 
       
  1469     \compat
       
  1470 
       
  1471     A Q3CheckTableItem is a table item which looks and behaves like a
       
  1472     checkbox. The advantage of using Q3CheckTableItems rather than real
       
  1473     checkboxes is that a Q3CheckTableItem uses far less resources than
       
  1474     a real checkbox would in a \l{Q3Table}. When the cell has the focus
       
  1475     it displays a real checkbox which the user can interact with. When
       
  1476     the cell does not have the focus the cell \e looks like a
       
  1477     checkbox. Pixmaps may not be used in Q3CheckTableItems.
       
  1478 
       
  1479     Q3CheckTableItem items have the edit type \c WhenCurrent (see
       
  1480     \l{EditType}).
       
  1481 
       
  1482     To change the checkbox's label use setText(). The checkbox can be
       
  1483     checked and unchecked with setChecked() and its state retrieved
       
  1484     using isChecked().
       
  1485 
       
  1486     To populate a table cell with a Q3CheckTableItem use
       
  1487     Q3Table::setItem().
       
  1488 
       
  1489     Q3CheckTableItems can be distinguished from \l{Q3TableItem}s and
       
  1490     \l{Q3ComboTableItem}s using their Run Time Type Identification
       
  1491     (rtti) value.
       
  1492 
       
  1493     \img qtableitems.png Table Items
       
  1494 
       
  1495     \sa rtti() EditType Q3ComboTableItem Q3TableItem QCheckBox
       
  1496 */
       
  1497 
       
  1498 /*!
       
  1499     Creates a Q3CheckTableItem with an \l{EditType} of \c WhenCurrent
       
  1500     as a child of \a table. The checkbox is initially unchecked and
       
  1501     its label is set to the string \a txt.
       
  1502 */
       
  1503 
       
  1504 Q3CheckTableItem::Q3CheckTableItem(Q3Table *table, const QString &txt)
       
  1505     : Q3TableItem(table, WhenCurrent, txt), checked(false)
       
  1506 {
       
  1507 }
       
  1508 
       
  1509 /*! \reimp */
       
  1510 
       
  1511 void Q3CheckTableItem::setText(const QString &t)
       
  1512 {
       
  1513     Q3TableItem::setText(t);
       
  1514     QWidget *w = table()->cellWidget(row(), col());
       
  1515     QCheckBox *cb = qobject_cast<QCheckBox*>(w);
       
  1516     if (cb)
       
  1517         cb->setText(t);
       
  1518 }
       
  1519 
       
  1520 
       
  1521 /*! \reimp */
       
  1522 
       
  1523 QWidget *Q3CheckTableItem::createEditor() const
       
  1524 {
       
  1525     // create an editor - a combobox in our case
       
  1526     ((Q3CheckTableItem*)this)->cb = new QCheckBox(table()->viewport(), "qt_editor_checkbox");
       
  1527     cb->setChecked(checked);
       
  1528     cb->setText(text());
       
  1529     cb->setBackgroundColor(table()->viewport()->backgroundColor());
       
  1530     cb->setAutoFillBackground(true);
       
  1531     QObject::connect(cb, SIGNAL(toggled(bool)), table(), SLOT(doValueChanged()));
       
  1532     return cb;
       
  1533 }
       
  1534 
       
  1535 /*! \reimp */
       
  1536 
       
  1537 void Q3CheckTableItem::setContentFromEditor(QWidget *w)
       
  1538 {
       
  1539     QCheckBox *cb = qobject_cast<QCheckBox*>(w);
       
  1540     if (cb)
       
  1541         checked = cb->isChecked();
       
  1542 }
       
  1543 
       
  1544 /*! \reimp */
       
  1545 
       
  1546 void Q3CheckTableItem::paint(QPainter *p, const QColorGroup &cg,
       
  1547                                 const QRect &cr, bool selected)
       
  1548 {
       
  1549     QPalette pal = cg;
       
  1550 
       
  1551     p->fillRect(0, 0, cr.width(), cr.height(),
       
  1552                  selected ? pal.brush(QPalette::Highlight)
       
  1553                           : pal.brush(QPalette::Base));
       
  1554 
       
  1555     QSize sz = QSize(table()->style()->pixelMetric(QStyle::PM_IndicatorWidth),
       
  1556                       table()->style()->pixelMetric(QStyle::PM_IndicatorHeight));
       
  1557     QPalette pal2(pal);
       
  1558     pal2.setBrush(QPalette::Window, pal.brush(QPalette::Base));
       
  1559     QStyleOptionButton opt;
       
  1560     opt.initFrom(table());
       
  1561     opt.rect.setRect(0, (cr.height() - sz.height()) / 2, sz.width(), sz.height());
       
  1562     opt.palette = pal2;
       
  1563     opt.state &= ~QStyle::State_HasFocus;
       
  1564     opt.state &= ~QStyle::State_MouseOver;
       
  1565     if(isEnabled())
       
  1566         opt.state |= QStyle::State_Enabled;
       
  1567     if (checked)
       
  1568         opt.state |= QStyle::State_On;
       
  1569     else
       
  1570         opt.state |= QStyle::State_Off;
       
  1571     if (isEnabled() && table()->isEnabled())
       
  1572         opt.state |= QStyle::State_Enabled;
       
  1573     table()->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, p, table());
       
  1574     if (selected)
       
  1575         p->setPen(pal.highlightedText().color());
       
  1576     else
       
  1577         p->setPen(pal.text().color());
       
  1578     opt.rect.setRect(0, 0, cr.width(), cr.height());
       
  1579     QRect textRect = table()->style()->subElementRect(QStyle::SE_CheckBoxContents, &opt, table());
       
  1580     p->drawText(textRect, wordWrap() ? (alignment() | Qt::WordBreak) : alignment(), text());
       
  1581 }
       
  1582 
       
  1583 /*!
       
  1584     If \a b is true the checkbox is checked; if \a b is false the
       
  1585     checkbox is unchecked.
       
  1586 
       
  1587     \sa isChecked()
       
  1588 */
       
  1589 
       
  1590 void Q3CheckTableItem::setChecked(bool b)
       
  1591 {
       
  1592     checked = b;
       
  1593     table()->updateCell(row(), col());
       
  1594     QWidget *w = table()->cellWidget(row(), col());
       
  1595     QCheckBox *cb = qobject_cast<QCheckBox*>(w);
       
  1596     if (cb)
       
  1597         cb->setChecked(b);
       
  1598 }
       
  1599 
       
  1600 /*!
       
  1601     Returns true if the checkbox table item is checked; otherwise
       
  1602     returns false.
       
  1603 
       
  1604     \sa setChecked()
       
  1605 */
       
  1606 
       
  1607 bool Q3CheckTableItem::isChecked() const
       
  1608 {
       
  1609     // #### why was this next line here. It must not be here, as
       
  1610     // #### people want to call isChecked() from within paintCell()
       
  1611     // #### and end up in an infinite loop that way
       
  1612     // table()->updateCell(row(), col());
       
  1613     QWidget *w = table()->cellWidget(row(), col());
       
  1614     QCheckBox *cb = qobject_cast<QCheckBox*>(w);
       
  1615     if (cb)
       
  1616         return cb->isChecked();
       
  1617     return checked;
       
  1618 }
       
  1619 
       
  1620 int Q3CheckTableItem::RTTI = 2;
       
  1621 
       
  1622 /*!
       
  1623     \fn int Q3CheckTableItem::rtti() const
       
  1624 
       
  1625     Returns 2.
       
  1626 
       
  1627     Make your derived classes return their own values for rtti()to
       
  1628     distinguish between different table item subclasses. You should
       
  1629     use values greater than 1000, preferably a large random number, to
       
  1630     allow for extensions to this class.
       
  1631 
       
  1632     \sa Q3TableItem::rtti()
       
  1633 */
       
  1634 
       
  1635 int Q3CheckTableItem::rtti() const
       
  1636 {
       
  1637     return RTTI;
       
  1638 }
       
  1639 
       
  1640 /*! \reimp */
       
  1641 
       
  1642 QSize Q3CheckTableItem::sizeHint() const
       
  1643 {
       
  1644     QSize sz = QSize(table()->style()->pixelMetric(QStyle::PM_IndicatorWidth),
       
  1645                       table()->style()->pixelMetric(QStyle::PM_IndicatorHeight));
       
  1646     sz.setWidth(sz.width() + 6);
       
  1647     QSize sh(Q3TableItem::sizeHint());
       
  1648     return QSize(sh.width() + sz.width(), QMAX(sh.height(), sz.height())).
       
  1649         expandedTo(QApplication::globalStrut());
       
  1650 }
       
  1651 
       
  1652 /*!
       
  1653     \class Q3Table
       
  1654     \brief The Q3Table class provides a flexible editable table widget.
       
  1655 
       
  1656     \compat
       
  1657 
       
  1658     Q3Table is easy to use, although it does have a large API because
       
  1659     of the comprehensive functionality that it provides. Q3Table
       
  1660     includes functions for manipulating \link #headers
       
  1661     headers\endlink, \link #columnsrows rows and columns\endlink,
       
  1662     \link #cells cells\endlink and \link #selections
       
  1663     selections\endlink. Q3Table also provides in-place editing and
       
  1664     drag and drop, as well as a useful set of
       
  1665     \link #signals signals\endlink. Q3Table efficiently supports very
       
  1666     large tables, for example, tables one million by one million cells
       
  1667     are perfectly possible. Q3Table is economical with memory, using
       
  1668     none for unused cells.
       
  1669 
       
  1670     \snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 3
       
  1671 
       
  1672     The first line constructs the table specifying its size in rows
       
  1673     and columns. We then insert a pixmap and some text into the \e
       
  1674     same \link #cells cell\endlink, with the pixmap appearing to the
       
  1675     left of the text. Q3Table cells can be populated with
       
  1676     \l{Q3TableItem}s, \l{Q3ComboTableItem}s or by \l{Q3CheckTableItem}s.
       
  1677     By default a vertical header appears at the left of the table
       
  1678     showing row numbers and a horizontal header appears at the top of
       
  1679     the table showing column numbers. (The numbers displayed start at
       
  1680     1, although row and column numbers within Q3Table begin at 0.)
       
  1681 
       
  1682     If you want to use mouse tracking call setMouseTracking(true) on
       
  1683     the \e viewport.
       
  1684 
       
  1685     \img qtableitems.png Table Items
       
  1686 
       
  1687     \target headers
       
  1688     \section1 Headers
       
  1689 
       
  1690     Q3Table supports a header column, e.g. to display row numbers, and
       
  1691     a header row, e.g to display column titles. To set row or column
       
  1692     labels use Q3Header::setLabel() on the pointers returned by
       
  1693     verticalHeader() and horizontalHeader() respectively. The vertical
       
  1694     header is displayed within the table's left margin whose width is
       
  1695     set with setLeftMargin(). The horizontal header is displayed
       
  1696     within the table's top margin whose height is set with
       
  1697     setTopMargin(). The table's grid can be switched off with
       
  1698     setShowGrid(). If you want to hide a horizontal header call
       
  1699     hide(), and call setTopMargin(0) so that the area the header
       
  1700     would have occupied is reduced to zero size.
       
  1701 
       
  1702     Header labels are indexed via their section numbers. Note that the
       
  1703     default behavior of Q3Header regarding section numbers is overridden
       
  1704     for Q3Table. See the explanation below in the Rows and Columns
       
  1705     section in the discussion of moving columns and rows.
       
  1706 
       
  1707     \target columnsrows
       
  1708     \section1 Rows and Columns
       
  1709 
       
  1710     Row and column sizes are set with setRowHeight() and
       
  1711     setColumnWidth(). If you want a row high enough to show the
       
  1712     tallest item in its entirety, use adjustRow(). Similarly, to make
       
  1713     a column wide enough to show the widest item use adjustColumn().
       
  1714     If you want the row height and column width to adjust
       
  1715     automatically as the height and width of the table changes use
       
  1716     setRowStretchable() and setColumnStretchable().
       
  1717 
       
  1718     Rows and columns can be hidden and shown with hideRow(),
       
  1719     hideColumn(), showRow() and showColumn(). New rows and columns are
       
  1720     inserted using insertRows() and insertColumns(). Additional rows
       
  1721     and columns are added at the  bottom (rows) or right (columns) if
       
  1722     you set setNumRows() or setNumCols() to be larger than numRows()
       
  1723     or numCols(). Existing rows and columns are removed with
       
  1724     removeRow() and removeColumn(). Multiple rows and columns can be
       
  1725     removed with removeRows() and removeColumns().
       
  1726 
       
  1727     Rows and columns can be set to be movable using
       
  1728     rowMovingEnabled() and columnMovingEnabled(). The user can drag
       
  1729     them to reorder them holding down the Ctrl key and dragging the
       
  1730     mouse. For performance reasons, the default behavior of Q3Header
       
  1731     section numbers is overridden by Q3Table. Currently in Q3Table, when
       
  1732     a row or column is dragged and reordered, the section number is
       
  1733     also changed to its new position. Therefore, there is no
       
  1734     difference between the section and the index fields in Q3Header.
       
  1735     The Q3Table Q3Header classes do not provide a mechanism for indexing
       
  1736     independently of the user interface ordering.
       
  1737 
       
  1738     The table can be sorted using sortColumn(). Users can sort a
       
  1739     column by clicking its header if setSorting() is set to true. Rows
       
  1740     can be swapped with swapRows(), columns with swapColumns() and
       
  1741     cells with swapCells().
       
  1742 
       
  1743     For editable tables (see setReadOnly()) you can set the read-only
       
  1744     property of individual rows and columns with setRowReadOnly() and
       
  1745     setColumnReadOnly(). (Whether a cell is editable or read-only
       
  1746     depends on these settings and the cell's Q3TableItem.
       
  1747 
       
  1748     The row and column which have the focus are returned by
       
  1749     currentRow() and currentColumn() respectively.
       
  1750 
       
  1751     Although many Q3Table functions operate in terms of rows and
       
  1752     columns the indexOf() function returns a single integer
       
  1753     identifying a particular cell.
       
  1754 
       
  1755     \target cells
       
  1756     \section1 Cells
       
  1757 
       
  1758     All of a Q3Table's cells are empty when the table is constructed.
       
  1759 
       
  1760     There are two approaches to populating the table's cells. The
       
  1761     first and simplest approach is to use Q3TableItems or Q3TableItem
       
  1762     subclasses. The second approach doesn't use Q3TableItems at all
       
  1763     which is useful for very large sparse tables but requires you to
       
  1764     reimplement a number of functions. We'll look at each approach in
       
  1765     turn.
       
  1766 
       
  1767     To put a string in a cell use setText(). This function will create
       
  1768     a new Q3TableItem for the cell if one doesn't already exist, and
       
  1769     displays the text in it. By default the table item's widget will
       
  1770     be a QLineEdit. A pixmap may be put in a cell with setPixmap(),
       
  1771     which also creates a table item if required. A cell may contain \e
       
  1772     both a pixmap and text; the pixmap is displayed to the left of the
       
  1773     text. Another approach is to construct a Q3TableItem or Q3TableItem
       
  1774     subclass, set its properties, then insert it into a cell with
       
  1775     setItem().
       
  1776 
       
  1777     If you want cells which contain comboboxes use the Q3ComboTableItem
       
  1778     class. Similarly if you require cells containing checkboxes use
       
  1779     the Q3CheckTableItem class. These table items look and behave just
       
  1780     like the combobox or checkbox widgets but consume far less memory.
       
  1781 
       
  1782     Q3Table takes ownership of its Q3TableItems and will delete them
       
  1783     when the table itself is destroyed. You can take ownership of a
       
  1784     table item using takeItem() which you use to move a cell's
       
  1785     contents from one cell to another, either within the same table,
       
  1786     or from one table to another. (See also, swapCells()).
       
  1787 
       
  1788     In-place editing of the text in Q3TableItems, and the values in
       
  1789     Q3ComboTableItems and Q3CheckTableItems works automatically. Cells
       
  1790     may be editable or read-only, see Q3TableItem::EditType. If you
       
  1791     want fine control over editing see beginEdit() and endEdit().
       
  1792 
       
  1793     The contents of a cell can be retrieved as a Q3TableItem using
       
  1794     item(), or as a string with text() or as a pixmap (if there is
       
  1795     one) with pixmap(). A cell's bounding rectangle is given by
       
  1796     cellGeometry(). Use updateCell() to repaint a cell, for example to
       
  1797     clear away a cell's visual representation after it has been
       
  1798     deleted with clearCell(). The table can be forced to scroll to
       
  1799     show a particular cell with ensureCellVisible(). The isSelected()
       
  1800     function indicates if a cell is selected.
       
  1801 
       
  1802     It is possible to use your own widget as a cell's widget using
       
  1803     setCellWidget(), but subclassing Q3TableItem might be a simpler
       
  1804     approach. The cell's widget (if there is one) can be removed with
       
  1805     clearCellWidget().
       
  1806 
       
  1807     \keyword notes on large tables
       
  1808     \target bigtables
       
  1809     \section2 Large tables
       
  1810 
       
  1811     For large, sparse, tables using Q3TableItems or other widgets is
       
  1812     inefficient. The solution is to \e draw the cell as it should
       
  1813     appear and to create and destroy cell editors on demand.
       
  1814 
       
  1815     This approach requires that you reimplement various functions.
       
  1816     Reimplement paintCell() to display your data, and createEditor()
       
  1817     and setCellContentFromEditor() to support in-place editing. It
       
  1818     is very important to reimplement resizeData() to have no
       
  1819     functionality, to prevent Q3Table from attempting to create a huge
       
  1820     array. You will also need to reimplement item(), setItem(),
       
  1821     takeItem(), clearCell(), and insertWidget(), cellWidget() and
       
  1822     clearCellWidget(). In almost every circumstance (for sorting,
       
  1823     removing and inserting columns and rows, etc.), you also need
       
  1824     to reimplement swapRows(), swapCells() and swapColumns(), including
       
  1825     header handling.
       
  1826 
       
  1827     If you represent active cells with a dictionary of Q3TableItems and
       
  1828     QWidgets, i.e. only store references to cells that are actually
       
  1829     used, many of the functions can be implemented with a single line
       
  1830     of code.
       
  1831 
       
  1832     For more information on cells see the Q3TableItem documenation.
       
  1833 
       
  1834     \target selections
       
  1835     \section1 Selections
       
  1836 
       
  1837     Q3Table's support single selection, multi-selection (multiple
       
  1838     cells) or no selection. The selection mode is set with
       
  1839     setSelectionMode(). Use isSelected() to determine if a particular
       
  1840     cell is selected, and isRowSelected() and isColumnSelected() to
       
  1841     see if a row or column is selected.
       
  1842 
       
  1843     Q3Table's support many simultaneous selections. You can
       
  1844     programmatically select cells with addSelection(). The number of
       
  1845     selections is given by numSelections(). The current selection is
       
  1846     returned by currentSelection(). You can remove a selection with
       
  1847     removeSelection() and remove all selections with
       
  1848     clearSelection(). Selections are Q3TableSelection objects.
       
  1849 
       
  1850     To easily add a new selection use selectCells(), selectRow() or
       
  1851     selectColumn().
       
  1852 
       
  1853     Alternatively, use addSelection() to add new selections using
       
  1854     Q3TableSelection objects. The advantage of using Q3TableSelection
       
  1855     objects is that you can call Q3TableSelection::expandTo() to resize
       
  1856     the selection and can query and compare them.
       
  1857 
       
  1858     The number of selections is given by numSelections(). The current
       
  1859     selection is returned by currentSelection(). You can remove a
       
  1860     selection with removeSelection() and remove all selections with
       
  1861     clearSelection().
       
  1862 
       
  1863     \target signals
       
  1864     \section1 Signals
       
  1865 
       
  1866     When the user clicks a cell the currentChanged() signal is
       
  1867     emitted. You can also connect to the lower level clicked(),
       
  1868     doubleClicked() and pressed() signals. If the user changes the
       
  1869     selection the selectionChanged() signal is emitted; similarly if
       
  1870     the user changes a cell's value the valueChanged() signal is
       
  1871     emitted. If the user right-clicks (or presses the appropriate
       
  1872     platform-specific key sequence) the contextMenuRequested() signal
       
  1873     is emitted. If the user drops a drag and drop object the dropped()
       
  1874     signal is emitted with the drop event.
       
  1875 */
       
  1876 
       
  1877 /*!
       
  1878     \fn void Q3Table::currentChanged(int row, int col)
       
  1879 
       
  1880     This signal is emitted when the current cell has changed to \a
       
  1881     row, \a col.
       
  1882 */
       
  1883 
       
  1884 /*!
       
  1885     \fn void Q3Table::valueChanged(int row, int col)
       
  1886 
       
  1887     This signal is emitted when the user changed the value in the cell
       
  1888     at \a row, \a col.
       
  1889 */
       
  1890 
       
  1891 /*!
       
  1892     \fn int Q3Table::currentRow() const
       
  1893 
       
  1894     Returns the current row.
       
  1895 
       
  1896     \sa currentColumn()
       
  1897 */
       
  1898 
       
  1899 /*!
       
  1900     \fn int Q3Table::currentColumn() const
       
  1901 
       
  1902     Returns the current column.
       
  1903 
       
  1904     \sa currentRow()
       
  1905 */
       
  1906 
       
  1907 /*!
       
  1908     \enum Q3Table::EditMode
       
  1909 
       
  1910     \value NotEditing  No cell is currently being edited.
       
  1911 
       
  1912     \value Editing  A cell is currently being edited. The editor was
       
  1913     initialised with the cell's contents.
       
  1914 
       
  1915     \value Replacing  A cell is currently being edited. The editor was
       
  1916     not initialised with the cell's contents.
       
  1917 */
       
  1918 
       
  1919 /*!
       
  1920     \enum Q3Table::SelectionMode
       
  1921 
       
  1922     \value NoSelection No cell can be selected by the user.
       
  1923 
       
  1924     \value Single The user may only select a single range of cells.
       
  1925 
       
  1926     \value Multi The user may select multiple ranges of cells.
       
  1927 
       
  1928     \value SingleRow The user may select one row at once.
       
  1929 
       
  1930     \value MultiRow The user may select multiple rows.
       
  1931 */
       
  1932 
       
  1933 /*!
       
  1934     \enum Q3Table::FocusStyle
       
  1935 
       
  1936     Specifies how the current cell (focus cell) is drawn.
       
  1937 
       
  1938     \value FollowStyle The current cell is drawn according to the
       
  1939     current style and the cell's background is also drawn selected, if
       
  1940     the current cell is within a selection
       
  1941 
       
  1942     \value SpreadSheet The current cell is drawn as in a spreadsheet.
       
  1943     This means, it is signified by a black rectangle around the cell,
       
  1944     and the background of the current cell is always drawn with the
       
  1945     widget's base color - even when selected.
       
  1946 
       
  1947 */
       
  1948 
       
  1949 /*!
       
  1950     \fn void Q3Table::clicked(int row, int col, int button, const QPoint &mousePos)
       
  1951 
       
  1952     This signal is emitted when mouse button \a button is clicked. The
       
  1953     cell where the event took place is at \a row, \a col, and the
       
  1954     mouse's position is in \a mousePos.
       
  1955 
       
  1956     \sa Qt::MouseButton
       
  1957 */
       
  1958 
       
  1959 /*!
       
  1960     \fn void Q3Table::doubleClicked(int row, int col, int button, const QPoint &mousePos)
       
  1961 
       
  1962     This signal is emitted when mouse button \a button is
       
  1963     double-clicked. The cell where the event took place is at \a row,
       
  1964     \a col, and the mouse's position is in \a mousePos.
       
  1965 
       
  1966     \sa Qt::MouseButton
       
  1967 */
       
  1968 
       
  1969 /*!
       
  1970     \fn void Q3Table::pressed(int row, int col, int button, const QPoint &mousePos)
       
  1971 
       
  1972     This signal is emitted when mouse button \a button is pressed. The
       
  1973     cell where the event took place is at \a row, \a col, and the
       
  1974     mouse's position is in \a mousePos.
       
  1975 
       
  1976     \sa Qt::MouseButton
       
  1977 */
       
  1978 
       
  1979 /*!
       
  1980     \fn void Q3Table::selectionChanged()
       
  1981 
       
  1982     This signal is emitted whenever a selection changes.
       
  1983 
       
  1984     \sa Q3TableSelection
       
  1985 */
       
  1986 
       
  1987 /*!
       
  1988     \fn void Q3Table::contextMenuRequested(int row, int col, const QPoint & pos)
       
  1989 
       
  1990     This signal is emitted when the user invokes a context menu with
       
  1991     the right mouse button (or with a system-specific keypress). The
       
  1992     cell where the event took place is at \a row, \a col. \a pos is
       
  1993     the position where the context menu will appear in the global
       
  1994     coordinate system. This signal is always emitted, even if the
       
  1995     contents of the cell are disabled.
       
  1996 */
       
  1997 
       
  1998 /*!
       
  1999     Creates an empty table object called \a name as a child of \a
       
  2000     parent.
       
  2001 
       
  2002     Call setNumRows() and setNumCols() to set the table size before
       
  2003     populating the table if you're using Q3TableItems.
       
  2004 */
       
  2005 
       
  2006 Q3Table::Q3Table(QWidget *parent, const char *name)
       
  2007     : Q3ScrollView(parent, name, WNoAutoErase | WStaticContents),
       
  2008       leftHeader(0), topHeader(0),
       
  2009       currentSel(0), lastSortCol(-1), sGrid(true), mRows(false), mCols(false),
       
  2010       asc(true), doSort(true), readOnly(false)
       
  2011 {
       
  2012     init(0, 0);
       
  2013 }
       
  2014 
       
  2015 /*!
       
  2016     Constructs an empty table called \a name with \a numRows rows and
       
  2017     \a numCols columns. The table is a child of \a parent.
       
  2018 
       
  2019     If you're using \l{Q3TableItem}s to populate the table's cells, you
       
  2020     can create Q3TableItem, Q3ComboTableItem and Q3CheckTableItem items
       
  2021     and insert them into the table using setItem(). (See the notes on
       
  2022     large tables for an alternative to using Q3TableItems.)
       
  2023 */
       
  2024 
       
  2025 Q3Table::Q3Table(int numRows, int numCols, QWidget *parent, const char *name)
       
  2026     : Q3ScrollView(parent, name, WNoAutoErase | WStaticContents),
       
  2027       leftHeader(0), topHeader(0),
       
  2028       currentSel(0), lastSortCol(-1), sGrid(true), mRows(false), mCols(false),
       
  2029       asc(true), doSort(true), readOnly(false)
       
  2030 {
       
  2031     init(numRows, numCols);
       
  2032 }
       
  2033 
       
  2034 /*! \internal
       
  2035 */
       
  2036 
       
  2037 void Q3Table::init(int rows, int cols)
       
  2038 {
       
  2039 #ifndef QT_NO_DRAGANDDROP
       
  2040     setDragAutoScroll(false);
       
  2041 #endif
       
  2042     d = new Q3TablePrivate;
       
  2043     d->geomTimer = new QTimer(this);
       
  2044     d->lastVisCol = 0;
       
  2045     d->lastVisRow = 0;
       
  2046     connect(d->geomTimer, SIGNAL(timeout()), this, SLOT(updateGeometriesSlot()));
       
  2047     shouldClearSelection = false;
       
  2048     dEnabled = false;
       
  2049     roRows.setAutoDelete(true);
       
  2050     roCols.setAutoDelete(true);
       
  2051     setSorting(false);
       
  2052 
       
  2053     unused = true; // It's unused, ain't it? :)
       
  2054 
       
  2055     selMode = Multi;
       
  2056 
       
  2057     contents.setAutoDelete(true);
       
  2058     widgets.setAutoDelete(true);
       
  2059 
       
  2060     // Enable clipper and set background mode
       
  2061     enableClipper(qt_table_clipper_enabled);
       
  2062 
       
  2063     viewport()->setFocusProxy(this);
       
  2064     viewport()->setFocusPolicy(Qt::WheelFocus);
       
  2065     setFocusPolicy(Qt::WheelFocus);
       
  2066 
       
  2067     viewport()->setBackgroundMode(PaletteBase);
       
  2068     setBackgroundMode(PaletteBackground, PaletteBase);
       
  2069     setResizePolicy(Manual);
       
  2070     selections.setAutoDelete(true);
       
  2071 
       
  2072     // Create headers
       
  2073     leftHeader = new Q3TableHeader(rows, this, this, "left table header");
       
  2074     leftHeader->setOrientation(Vertical);
       
  2075     leftHeader->setTracking(true);
       
  2076     leftHeader->setMovingEnabled(true);
       
  2077     topHeader = new Q3TableHeader(cols, this, this, "right table header");
       
  2078     topHeader->setOrientation(Horizontal);
       
  2079     topHeader->setTracking(true);
       
  2080     topHeader->setMovingEnabled(true);
       
  2081     if (QApplication::reverseLayout())
       
  2082         setMargins(0, fontMetrics().height() + 4, 30, 0);
       
  2083     else
       
  2084         setMargins(30, fontMetrics().height() + 4, 0, 0);
       
  2085 
       
  2086     topHeader->setUpdatesEnabled(false);
       
  2087     leftHeader->setUpdatesEnabled(false);
       
  2088     // Initialize headers
       
  2089     int i = 0;
       
  2090     for (i = 0; i < numCols(); ++i)
       
  2091         topHeader->resizeSection(i, QMAX(100, QApplication::globalStrut().height()));
       
  2092     for (i = 0; i < numRows(); ++i)
       
  2093         leftHeader->resizeSection(i, QMAX(20, QApplication::globalStrut().width()));
       
  2094     topHeader->setUpdatesEnabled(true);
       
  2095     leftHeader->setUpdatesEnabled(true);
       
  2096 
       
  2097     // Prepare for contents
       
  2098     contents.setAutoDelete(false);
       
  2099 
       
  2100     // Connect header, table and scroll bars
       
  2101     connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
       
  2102              topHeader, SLOT(setOffset(int)));
       
  2103     connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
       
  2104              leftHeader, SLOT(setOffset(int)));
       
  2105     connect(topHeader, SIGNAL(sectionSizeChanged(int)),
       
  2106              this, SLOT(columnWidthChanged(int)));
       
  2107     connect(topHeader, SIGNAL(indexChange(int,int,int)),
       
  2108              this, SLOT(columnIndexChanged(int,int,int)));
       
  2109     connect(topHeader, SIGNAL(sectionClicked(int)),
       
  2110              this, SLOT(columnClicked(int)));
       
  2111     connect(leftHeader, SIGNAL(sectionSizeChanged(int)),
       
  2112              this, SLOT(rowHeightChanged(int)));
       
  2113     connect(leftHeader, SIGNAL(indexChange(int,int,int)),
       
  2114              this, SLOT(rowIndexChanged(int,int,int)));
       
  2115 
       
  2116     // Initialize variables
       
  2117     autoScrollTimer = new QTimer(this);
       
  2118     connect(autoScrollTimer, SIGNAL(timeout()),
       
  2119              this, SLOT(doAutoScroll()));
       
  2120     curRow = curCol = 0;
       
  2121     topHeader->setSectionState(curCol, Q3TableHeader::Bold);
       
  2122     leftHeader->setSectionState(curRow, Q3TableHeader::Bold);
       
  2123     edMode = NotEditing;
       
  2124     editRow = editCol = -1;
       
  2125 
       
  2126     drawActiveSelection = true;
       
  2127 
       
  2128     installEventFilter(this);
       
  2129 
       
  2130     focusStl = SpreadSheet;
       
  2131 
       
  2132     was_visible = false;
       
  2133 
       
  2134     // initial size
       
  2135     resize(640, 480);
       
  2136 }
       
  2137 
       
  2138 /*!
       
  2139     Releases all the resources used by the Q3Table object,
       
  2140     including all \l{Q3TableItem}s and their widgets.
       
  2141 */
       
  2142 
       
  2143 Q3Table::~Q3Table()
       
  2144 {
       
  2145     setUpdatesEnabled(false);
       
  2146     contents.setAutoDelete(true);
       
  2147     contents.clear();
       
  2148     widgets.clear();
       
  2149 
       
  2150     delete d;
       
  2151 }
       
  2152 
       
  2153 void Q3Table::setReadOnly(bool b)
       
  2154 {
       
  2155     readOnly = b;
       
  2156 
       
  2157     Q3TableItem *i = item(curRow, curCol);
       
  2158     if (readOnly && isEditing()) {
       
  2159         endEdit(editRow, editCol, true, false);
       
  2160     } else if (!readOnly && i && (i->editType() == Q3TableItem::WhenCurrent
       
  2161                                   || i->editType() == Q3TableItem::Always)) {
       
  2162         editCell(curRow, curCol);
       
  2163     }
       
  2164 }
       
  2165 
       
  2166 /*!
       
  2167     If \a ro is true, row \a row is set to be read-only; otherwise the
       
  2168     row is set to be editable.
       
  2169 
       
  2170     Whether a cell in this row is editable or read-only depends on the
       
  2171     cell's EditType, and this setting.
       
  2172 
       
  2173     \sa isRowReadOnly() setColumnReadOnly() setReadOnly()
       
  2174 */
       
  2175 
       
  2176 void Q3Table::setRowReadOnly(int row, bool ro)
       
  2177 {
       
  2178     if (ro)
       
  2179         roRows.replace(row, new int(0));
       
  2180     else
       
  2181         roRows.remove(row);
       
  2182 
       
  2183     if (curRow == row) {
       
  2184         Q3TableItem *i = item(curRow, curCol);
       
  2185         if (ro && isEditing()) {
       
  2186             endEdit(editRow, editCol, true, false);
       
  2187         } else if (!ro && i && (i->editType() == Q3TableItem::WhenCurrent
       
  2188                                       || i->editType() == Q3TableItem::Always)) {
       
  2189             editCell(curRow, curCol);
       
  2190         }
       
  2191     }
       
  2192 }
       
  2193 
       
  2194 /*!
       
  2195     If \a ro is true, column \a col is set to be read-only; otherwise
       
  2196     the column is set to be editable.
       
  2197 
       
  2198     Whether a cell in this column is editable or read-only depends on
       
  2199     the cell's EditType, and this setting.
       
  2200 
       
  2201     \sa isColumnReadOnly() setRowReadOnly() setReadOnly()
       
  2202 
       
  2203 */
       
  2204 
       
  2205 void Q3Table::setColumnReadOnly(int col, bool ro)
       
  2206 {
       
  2207     if (ro)
       
  2208         roCols.replace(col, new int(0));
       
  2209     else
       
  2210         roCols.remove(col);
       
  2211 
       
  2212     if (curCol == col) {
       
  2213         Q3TableItem *i = item(curRow, curCol);
       
  2214         if (ro && isEditing()) {
       
  2215             endEdit(editRow, editCol, true, false);
       
  2216         } else if (!ro && i && (i->editType() == Q3TableItem::WhenCurrent
       
  2217                                       || i->editType() == Q3TableItem::Always)) {
       
  2218             editCell(curRow, curCol);
       
  2219         }
       
  2220     }
       
  2221 }
       
  2222 
       
  2223 /*!
       
  2224     \property Q3Table::readOnly
       
  2225     \brief whether the table is read-only
       
  2226 
       
  2227     Whether a cell in the table is editable or read-only depends on
       
  2228     the cell's \link Q3TableItem::EditType EditType\endlink, and this setting.
       
  2229 
       
  2230     \sa QWidget::enabled setColumnReadOnly() setRowReadOnly()
       
  2231 */
       
  2232 
       
  2233 bool Q3Table::isReadOnly() const
       
  2234 {
       
  2235     return readOnly;
       
  2236 }
       
  2237 
       
  2238 /*!
       
  2239     Returns true if row \a row is read-only; otherwise returns false.
       
  2240 
       
  2241     Whether a cell in this row is editable or read-only depends on the
       
  2242     cell's \link Q3TableItem::EditType EditType\endlink, and this
       
  2243     setting.
       
  2244 
       
  2245     \sa setRowReadOnly() isColumnReadOnly()
       
  2246 */
       
  2247 
       
  2248 bool Q3Table::isRowReadOnly(int row) const
       
  2249 {
       
  2250     return (roRows.find(row) != 0);
       
  2251 }
       
  2252 
       
  2253 /*!
       
  2254     Returns true if column \a col is read-only; otherwise returns
       
  2255     false.
       
  2256 
       
  2257     Whether a cell in this column is editable or read-only depends on
       
  2258     the cell's EditType, and this setting.
       
  2259 
       
  2260     \sa setColumnReadOnly() isRowReadOnly()
       
  2261 */
       
  2262 
       
  2263 bool Q3Table::isColumnReadOnly(int col) const
       
  2264 {
       
  2265     return (roCols.find(col) != 0);
       
  2266 }
       
  2267 
       
  2268 void Q3Table::setSelectionMode(SelectionMode mode)
       
  2269 {
       
  2270     if (mode == selMode)
       
  2271         return;
       
  2272     selMode = mode;
       
  2273     clearSelection();
       
  2274     if (isRowSelection(selMode) && numRows() > 0 && numCols() > 0) {
       
  2275         currentSel = new Q3TableSelection();
       
  2276         selections.append(currentSel);
       
  2277         currentSel->init(curRow, 0);
       
  2278         currentSel->expandTo(curRow, numCols() - 1);
       
  2279         repaintSelections(0, currentSel);
       
  2280     }
       
  2281 }
       
  2282 
       
  2283 /*!
       
  2284     \property Q3Table::selectionMode
       
  2285     \brief the current selection mode
       
  2286 
       
  2287     The default mode is \c Multi which allows the user to select
       
  2288     multiple ranges of cells.
       
  2289 */
       
  2290 
       
  2291 Q3Table::SelectionMode Q3Table::selectionMode() const
       
  2292 {
       
  2293     return selMode;
       
  2294 }
       
  2295 
       
  2296 /*!
       
  2297     \property Q3Table::focusStyle
       
  2298     \brief how the current (focus) cell is drawn
       
  2299 
       
  2300     The default style is \c SpreadSheet.
       
  2301 
       
  2302     \sa Q3Table::FocusStyle
       
  2303 */
       
  2304 
       
  2305 void Q3Table::setFocusStyle(FocusStyle fs)
       
  2306 {
       
  2307     focusStl = fs;
       
  2308     updateCell(curRow, curCol);
       
  2309 }
       
  2310 
       
  2311 Q3Table::FocusStyle Q3Table::focusStyle() const
       
  2312 {
       
  2313     return focusStl;
       
  2314 }
       
  2315 
       
  2316 /*!
       
  2317     This functions updates all the header states to be in sync with
       
  2318     the current selections. This should be called after
       
  2319     programmatically changing, adding or removing selections, so that
       
  2320     the headers are updated.
       
  2321 */
       
  2322 
       
  2323 void Q3Table::updateHeaderStates()
       
  2324 {
       
  2325     horizontalHeader()->setUpdatesEnabled(false);
       
  2326     verticalHeader()->setUpdatesEnabled(false);
       
  2327 
       
  2328     ((Q3TableHeader*)verticalHeader())->setSectionStateToAll(Q3TableHeader::Normal);
       
  2329     ((Q3TableHeader*)horizontalHeader())->setSectionStateToAll(Q3TableHeader::Normal);
       
  2330 
       
  2331     Q3PtrListIterator<Q3TableSelection> it(selections);
       
  2332     Q3TableSelection *s;
       
  2333     while ((s = it.current()) != 0) {
       
  2334         ++it;
       
  2335         if (s->isActive()) {
       
  2336             if (s->leftCol() == 0 &&
       
  2337                  s->rightCol() == numCols() - 1) {
       
  2338                 for (int i = 0; i < s->bottomRow() - s->topRow() + 1; ++i)
       
  2339                     leftHeader->setSectionState(s->topRow() + i, Q3TableHeader::Selected);
       
  2340             }
       
  2341             if (s->topRow() == 0 &&
       
  2342                  s->bottomRow() == numRows() - 1) {
       
  2343                 for (int i = 0; i < s->rightCol() - s->leftCol() + 1; ++i)
       
  2344                     topHeader->setSectionState(s->leftCol() + i, Q3TableHeader::Selected);
       
  2345             }
       
  2346         }
       
  2347     }
       
  2348 
       
  2349     horizontalHeader()->setUpdatesEnabled(true);
       
  2350     verticalHeader()->setUpdatesEnabled(true);
       
  2351     horizontalHeader()->repaint(false);
       
  2352     verticalHeader()->repaint(false);
       
  2353 }
       
  2354 
       
  2355 /*!
       
  2356     Returns the table's top Q3Header.
       
  2357 
       
  2358     This header contains the column labels.
       
  2359 
       
  2360     To modify a column label use Q3Header::setLabel().
       
  2361 
       
  2362     \sa verticalHeader() setTopMargin() Q3Header
       
  2363 */
       
  2364 
       
  2365 Q3Header *Q3Table::horizontalHeader() const
       
  2366 {
       
  2367     return (Q3Header*)topHeader;
       
  2368 }
       
  2369 
       
  2370 /*!
       
  2371     Returns the table's vertical Q3Header.
       
  2372 
       
  2373     This header contains the row labels.
       
  2374 
       
  2375     \sa horizontalHeader() setLeftMargin() Q3Header
       
  2376 */
       
  2377 
       
  2378 Q3Header *Q3Table::verticalHeader() const
       
  2379 {
       
  2380     return (Q3Header*)leftHeader;
       
  2381 }
       
  2382 
       
  2383 void Q3Table::setShowGrid(bool b)
       
  2384 {
       
  2385     if (sGrid == b)
       
  2386         return;
       
  2387     sGrid = b;
       
  2388     updateContents();
       
  2389 }
       
  2390 
       
  2391 /*!
       
  2392     \property Q3Table::showGrid
       
  2393     \brief whether the table's grid is displayed
       
  2394 
       
  2395     The grid is shown by default.
       
  2396 */
       
  2397 
       
  2398 bool Q3Table::showGrid() const
       
  2399 {
       
  2400     return sGrid;
       
  2401 }
       
  2402 
       
  2403 /*!
       
  2404     \property Q3Table::columnMovingEnabled
       
  2405     \brief whether columns can be moved by the user
       
  2406 
       
  2407     The default is false. Columns are moved by dragging whilst holding
       
  2408     down the Ctrl key.
       
  2409 
       
  2410     \sa rowMovingEnabled
       
  2411 */
       
  2412 
       
  2413 void Q3Table::setColumnMovingEnabled(bool b)
       
  2414 {
       
  2415     mCols = b;
       
  2416 }
       
  2417 
       
  2418 bool Q3Table::columnMovingEnabled() const
       
  2419 {
       
  2420     return mCols;
       
  2421 }
       
  2422 
       
  2423 /*!
       
  2424     \property Q3Table::rowMovingEnabled
       
  2425     \brief whether rows can be moved by the user
       
  2426 
       
  2427     The default is false. Rows are moved by dragging whilst holding
       
  2428     down the Ctrl key.
       
  2429 
       
  2430 
       
  2431     \sa columnMovingEnabled
       
  2432 */
       
  2433 
       
  2434 void Q3Table::setRowMovingEnabled(bool b)
       
  2435 {
       
  2436     mRows = b;
       
  2437 }
       
  2438 
       
  2439 bool Q3Table::rowMovingEnabled() const
       
  2440 {
       
  2441     return mRows;
       
  2442 }
       
  2443 
       
  2444 /*!
       
  2445     This is called when Q3Table's internal array needs to be resized to
       
  2446     \a len elements.
       
  2447 
       
  2448     If you don't use Q3TableItems you should reimplement this as an
       
  2449     empty method to avoid wasting memory. See the notes on large
       
  2450     tables for further details.
       
  2451 */
       
  2452 
       
  2453 void Q3Table::resizeData(int len)
       
  2454 {
       
  2455     contents.resize(len);
       
  2456     widgets.resize(len);
       
  2457 }
       
  2458 
       
  2459 /*!
       
  2460     Swaps the data in \a row1 and \a row2.
       
  2461 
       
  2462     This function is used to swap the positions of two rows. It is
       
  2463     called when the user changes the order of rows (see
       
  2464     setRowMovingEnabled()), and when rows are sorted.
       
  2465 
       
  2466     If you don't use \l{Q3TableItem}s and want your users to be able to
       
  2467     swap rows, e.g. for sorting, you will need to reimplement this
       
  2468     function. (See the notes on large tables.)
       
  2469 
       
  2470     If \a swapHeader is true, the rows' header contents is also
       
  2471     swapped.
       
  2472 
       
  2473     This function will not update the Q3Table, you will have to do
       
  2474     this manually, e.g. by calling updateContents().
       
  2475 
       
  2476     \sa swapColumns() swapCells()
       
  2477 */
       
  2478 
       
  2479 void Q3Table::swapRows(int row1, int row2, bool swapHeader)
       
  2480 {
       
  2481     if (swapHeader)
       
  2482         leftHeader->swapSections(row1, row2, false);
       
  2483 
       
  2484     Q3PtrVector<Q3TableItem> tmpContents;
       
  2485     tmpContents.resize(numCols());
       
  2486     Q3PtrVector<QWidget> tmpWidgets;
       
  2487     tmpWidgets.resize(numCols());
       
  2488     int i;
       
  2489 
       
  2490     contents.setAutoDelete(false);
       
  2491     widgets.setAutoDelete(false);
       
  2492     for (i = 0; i < numCols(); ++i) {
       
  2493         Q3TableItem *i1, *i2;
       
  2494         i1 = item(row1, i);
       
  2495         i2 = item(row2, i);
       
  2496         if (i1 || i2) {
       
  2497             tmpContents.insert(i, i1);
       
  2498             contents.remove(indexOf(row1, i));
       
  2499             contents.insert(indexOf(row1, i), i2);
       
  2500             contents.remove(indexOf(row2, i));
       
  2501             contents.insert(indexOf(row2, i), tmpContents[ i ]);
       
  2502             if (contents[ indexOf(row1, i) ])
       
  2503                 contents[ indexOf(row1, i) ]->setRow(row1);
       
  2504             if (contents[ indexOf(row2, i) ])
       
  2505                 contents[ indexOf(row2, i) ]->setRow(row2);
       
  2506         }
       
  2507 
       
  2508         QWidget *w1, *w2;
       
  2509 	w1 = cellWidget(row1, i);
       
  2510         w2 = cellWidget(row2, i);
       
  2511         if (w1 || w2) {
       
  2512             tmpWidgets.insert(i, w1);
       
  2513             widgets.remove(indexOf(row1, i));
       
  2514             widgets.insert(indexOf(row1, i), w2);
       
  2515             widgets.remove(indexOf(row2, i));
       
  2516             widgets.insert(indexOf(row2, i), tmpWidgets[ i ]);
       
  2517         }
       
  2518     }
       
  2519     contents.setAutoDelete(false);
       
  2520     widgets.setAutoDelete(true);
       
  2521 
       
  2522     updateRowWidgets(row1);
       
  2523     updateRowWidgets(row2);
       
  2524     if (curRow == row1)
       
  2525         curRow = row2;
       
  2526     else if (curRow == row2)
       
  2527         curRow = row1;
       
  2528     if (editRow == row1)
       
  2529         editRow = row2;
       
  2530     else if (editRow == row2)
       
  2531         editRow = row1;
       
  2532 }
       
  2533 
       
  2534 /*!
       
  2535     Sets the left margin to be \a m pixels wide.
       
  2536 
       
  2537     The verticalHeader(), which displays row labels, occupies this
       
  2538     margin.
       
  2539 
       
  2540     In an Arabic or Hebrew localization, the verticalHeader() will
       
  2541     appear on the right side of the table, and this call will set the
       
  2542     right margin.
       
  2543 
       
  2544     \sa leftMargin() setTopMargin() verticalHeader()
       
  2545 */
       
  2546 
       
  2547 void Q3Table::setLeftMargin(int m)
       
  2548 {
       
  2549     if (QApplication::reverseLayout())
       
  2550         setMargins(leftMargin(), topMargin(), m, bottomMargin());
       
  2551     else
       
  2552         setMargins(m, topMargin(), rightMargin(), bottomMargin());
       
  2553     updateGeometries();
       
  2554 }
       
  2555 
       
  2556 /*!
       
  2557     Sets the top margin to be \a m pixels high.
       
  2558 
       
  2559     The horizontalHeader(), which displays column labels, occupies
       
  2560     this margin.
       
  2561 
       
  2562     \sa topMargin() setLeftMargin()
       
  2563 */
       
  2564 
       
  2565 void Q3Table::setTopMargin(int m)
       
  2566 {
       
  2567     setMargins(leftMargin(), m, rightMargin(), bottomMargin());
       
  2568     updateGeometries();
       
  2569 }
       
  2570 
       
  2571 /*!
       
  2572     Swaps the data in \a col1 with \a col2.
       
  2573 
       
  2574     This function is used to swap the positions of two columns. It is
       
  2575     called when the user changes the order of columns (see
       
  2576     setColumnMovingEnabled(), and when columns are sorted.
       
  2577 
       
  2578     If you don't use \l{Q3TableItem}s and want your users to be able to
       
  2579     swap columns you will need to reimplement this function. (See the
       
  2580     notes on large tables.)
       
  2581 
       
  2582     If \a swapHeader is true, the columns' header contents is also
       
  2583     swapped.
       
  2584 
       
  2585     \sa swapCells()
       
  2586 */
       
  2587 
       
  2588 void Q3Table::swapColumns(int col1, int col2, bool swapHeader)
       
  2589 {
       
  2590     if (swapHeader)
       
  2591         topHeader->swapSections(col1, col2, false);
       
  2592 
       
  2593     Q3PtrVector<Q3TableItem> tmpContents;
       
  2594     tmpContents.resize(numRows());
       
  2595     Q3PtrVector<QWidget> tmpWidgets;
       
  2596     tmpWidgets.resize(numRows());
       
  2597     int i;
       
  2598 
       
  2599     contents.setAutoDelete(false);
       
  2600     widgets.setAutoDelete(false);
       
  2601     for (i = 0; i < numRows(); ++i) {
       
  2602         Q3TableItem *i1, *i2;
       
  2603         i1 = item(i, col1);
       
  2604         i2 = item(i, col2);
       
  2605         if (i1 || i2) {
       
  2606             tmpContents.insert(i, i1);
       
  2607             contents.remove(indexOf(i, col1));
       
  2608             contents.insert(indexOf(i, col1), i2);
       
  2609             contents.remove(indexOf(i, col2));
       
  2610             contents.insert(indexOf(i, col2), tmpContents[ i ]);
       
  2611             if (contents[ indexOf(i, col1) ])
       
  2612                 contents[ indexOf(i, col1) ]->setCol(col1);
       
  2613             if (contents[ indexOf(i, col2) ])
       
  2614                 contents[ indexOf(i, col2) ]->setCol(col2);
       
  2615         }
       
  2616 
       
  2617         QWidget *w1, *w2;
       
  2618         w1 = cellWidget(i, col1);
       
  2619         w2 = cellWidget(i, col2);
       
  2620         if (w1 || w2) {
       
  2621             tmpWidgets.insert(i, w1);
       
  2622             widgets.remove(indexOf(i, col1));
       
  2623             widgets.insert(indexOf(i, col1), w2);
       
  2624             widgets.remove(indexOf(i, col2));
       
  2625             widgets.insert(indexOf(i, col2), tmpWidgets[ i ]);
       
  2626         }
       
  2627     }
       
  2628     contents.setAutoDelete(false);
       
  2629     widgets.setAutoDelete(true);
       
  2630 
       
  2631     columnWidthChanged(col1);
       
  2632     columnWidthChanged(col2);
       
  2633     if (curCol == col1)
       
  2634         curCol = col2;
       
  2635     else if (curCol == col2)
       
  2636         curCol = col1;
       
  2637     if (editCol == col1)
       
  2638         editCol = col2;
       
  2639     else if (editCol == col2)
       
  2640         editCol = col1;
       
  2641 }
       
  2642 
       
  2643 /*!
       
  2644     Swaps the contents of the cell at \a row1, \a col1 with the
       
  2645     contents of the cell at \a row2, \a col2.
       
  2646 
       
  2647     This function is also called when the table is sorted.
       
  2648 
       
  2649     If you don't use \l{Q3TableItem}s and want your users to be able to
       
  2650     swap cells, you will need to reimplement this function. (See the
       
  2651     notes on large tables.)
       
  2652 
       
  2653     \sa swapColumns() swapRows()
       
  2654 */
       
  2655 
       
  2656 void Q3Table::swapCells(int row1, int col1, int row2, int col2)
       
  2657 {
       
  2658     contents.setAutoDelete(false);
       
  2659     widgets.setAutoDelete(false);
       
  2660     Q3TableItem *i1, *i2;
       
  2661     i1 = item(row1, col1);
       
  2662     i2 = item(row2, col2);
       
  2663     if (i1 || i2) {
       
  2664         Q3TableItem *tmp = i1;
       
  2665         contents.remove(indexOf(row1, col1));
       
  2666         contents.insert(indexOf(row1, col1), i2);
       
  2667         contents.remove(indexOf(row2, col2));
       
  2668         contents.insert(indexOf(row2, col2), tmp);
       
  2669         if (contents[ indexOf(row1, col1) ]) {
       
  2670             contents[ indexOf(row1, col1) ]->setRow(row1);
       
  2671             contents[ indexOf(row1, col1) ]->setCol(col1);
       
  2672         }
       
  2673         if (contents[ indexOf(row2, col2) ]) {
       
  2674             contents[ indexOf(row2, col2) ]->setRow(row2);
       
  2675             contents[ indexOf(row2, col2) ]->setCol(col2);
       
  2676         }
       
  2677     }
       
  2678 
       
  2679     QWidget *w1, *w2;
       
  2680     w1 = cellWidget(row1, col1);
       
  2681     w2 = cellWidget(row2, col2);
       
  2682     if (w1 || w2) {
       
  2683         QWidget *tmp = w1;
       
  2684         widgets.remove(indexOf(row1, col1));
       
  2685         widgets.insert(indexOf(row1, col1), w2);
       
  2686         widgets.remove(indexOf(row2, col2));
       
  2687         widgets.insert(indexOf(row2, col2), tmp);
       
  2688     }
       
  2689 
       
  2690     updateRowWidgets(row1);
       
  2691     updateRowWidgets(row2);
       
  2692     updateColWidgets(col1);
       
  2693     updateColWidgets(col2);
       
  2694     contents.setAutoDelete(false);
       
  2695     widgets.setAutoDelete(true);
       
  2696 }
       
  2697 
       
  2698 static bool is_child_of(QWidget *child, QWidget *parent)
       
  2699 {
       
  2700     while (child) {
       
  2701         if (child == parent)
       
  2702             return true;
       
  2703         child = child->parentWidget();
       
  2704     }
       
  2705     return false;
       
  2706 }
       
  2707 
       
  2708 /*!
       
  2709     Draws the table contents on the painter \a p. This function is
       
  2710     optimized so that it only draws the cells inside the \a cw pixels
       
  2711     wide and \a ch pixels high clipping rectangle at position \a cx,
       
  2712     \a cy.
       
  2713 
       
  2714     Additionally, drawContents() highlights the current cell.
       
  2715 */
       
  2716 
       
  2717 void Q3Table::drawContents(QPainter *p, int cx, int cy, int cw, int ch)
       
  2718 {
       
  2719     int colfirst = columnAt(cx);
       
  2720     int collast = columnAt(cx + cw);
       
  2721     int rowfirst = rowAt(cy);
       
  2722     int rowlast = rowAt(cy + ch);
       
  2723 
       
  2724     if (rowfirst == -1 || colfirst == -1) {
       
  2725         paintEmptyArea(p, cx, cy, cw, ch);
       
  2726         return;
       
  2727     }
       
  2728 
       
  2729     drawActiveSelection = hasFocus() || viewport()->hasFocus() || d->inMenuMode
       
  2730                         || is_child_of(qApp->focusWidget(), viewport())
       
  2731                         || !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this);
       
  2732     if (rowlast == -1)
       
  2733         rowlast = numRows() - 1;
       
  2734     if (collast == -1)
       
  2735         collast = numCols() - 1;
       
  2736 
       
  2737     bool currentInSelection = false;
       
  2738 
       
  2739     Q3PtrListIterator<Q3TableSelection> it( selections );
       
  2740     Q3TableSelection *s;
       
  2741     while ( ( s = it.current() ) != 0 ) {
       
  2742         ++it;
       
  2743         if (s->isActive() &&
       
  2744              curRow >= s->topRow() &&
       
  2745              curRow <= s->bottomRow() &&
       
  2746              curCol >= s->leftCol() &&
       
  2747              curCol <= s->rightCol()) {
       
  2748             currentInSelection = s->topRow() != curRow || s->bottomRow() != curRow || s->leftCol() != curCol || s->rightCol() != curCol;
       
  2749             break;
       
  2750         }
       
  2751     }
       
  2752 
       
  2753     // Go through the rows
       
  2754     for (int r = rowfirst; r <= rowlast; ++r) {
       
  2755         // get row position and height
       
  2756         int rowp = rowPos(r);
       
  2757         int rowh = rowHeight(r);
       
  2758 
       
  2759         // Go through the columns in row r
       
  2760         // if we know from where to where, go through [colfirst, collast],
       
  2761         // else go through all of them
       
  2762         for (int c = colfirst; c <= collast; ++c) {
       
  2763             // get position and width of column c
       
  2764             int colp, colw;
       
  2765             colp = columnPos(c);
       
  2766             colw = columnWidth(c);
       
  2767             int oldrp = rowp;
       
  2768             int oldrh = rowh;
       
  2769 
       
  2770             Q3TableItem *itm = item(r, c);
       
  2771             if (itm &&
       
  2772                  (itm->colSpan() > 1 || itm->rowSpan() > 1)) {
       
  2773                 bool goon = (r == itm->row() && c == itm->col())
       
  2774                             || (r == rowfirst && c == itm->col())
       
  2775                             || (r == itm->row() && c == colfirst);
       
  2776                 if (!goon)
       
  2777                     continue;
       
  2778                 rowp = rowPos(itm->row());
       
  2779                 rowh = 0;
       
  2780                 int i;
       
  2781                 for (i = 0; i < itm->rowSpan(); ++i)
       
  2782                     rowh += rowHeight(i + itm->row());
       
  2783                 colp = columnPos(itm->col());
       
  2784                 colw = 0;
       
  2785                 for (i = 0; i < itm->colSpan(); ++i)
       
  2786                     colw += columnWidth(i + itm->col());
       
  2787             }
       
  2788 
       
  2789             // Translate painter and draw the cell
       
  2790             p->translate(colp, rowp);
       
  2791             bool selected = isSelected(r, c);
       
  2792             if (focusStl != FollowStyle && selected && !currentInSelection &&
       
  2793                  r == curRow && c == curCol )
       
  2794                 selected = false;
       
  2795             paintCell(p, r, c, QRect(colp, rowp, colw, rowh), selected);
       
  2796             p->translate(-colp, -rowp);
       
  2797 
       
  2798             rowp = oldrp;
       
  2799             rowh = oldrh;
       
  2800 
       
  2801             QWidget *w = cellWidget(r, c);
       
  2802             QRect cg(cellGeometry(r, c));
       
  2803             if (w && w->geometry() != QRect(contentsToViewport(cg.topLeft()), cg.size() - QSize(1, 1))) {
       
  2804                 moveChild(w, colp, rowp);
       
  2805                 w->resize(cg.size() - QSize(1, 1));
       
  2806             }
       
  2807         }
       
  2808     }
       
  2809     d->lastVisCol = collast;
       
  2810     d->lastVisRow = rowlast;
       
  2811 
       
  2812     // draw indication of current cell
       
  2813     QRect focusRect = cellGeometry(curRow, curCol);
       
  2814     p->translate(focusRect.x(), focusRect.y());
       
  2815     paintFocus(p, focusRect);
       
  2816     p->translate(-focusRect.x(), -focusRect.y());
       
  2817 
       
  2818     // Paint empty rects
       
  2819     paintEmptyArea(p, cx, cy, cw, ch);
       
  2820 
       
  2821     drawActiveSelection = true;
       
  2822 }
       
  2823 
       
  2824 /*!
       
  2825     \reimp
       
  2826 
       
  2827     (Implemented to get rid of a compiler warning.)
       
  2828 */
       
  2829 
       
  2830 void Q3Table::drawContents(QPainter *)
       
  2831 {
       
  2832 }
       
  2833 
       
  2834 /*!
       
  2835     Returns the geometry of cell \a row, \a col in the cell's
       
  2836     coordinate system. This is a convenience function useful in
       
  2837     paintCell(). It is equivalent to QRect(QPoint(0,0), cellGeometry(
       
  2838     row, col).size());
       
  2839 
       
  2840     \sa cellGeometry()
       
  2841 */
       
  2842 
       
  2843 QRect Q3Table::cellRect(int row, int col) const
       
  2844 {
       
  2845     return QRect(QPoint(0,0), cellGeometry(row, col).size());
       
  2846 }
       
  2847 
       
  2848 /*!
       
  2849     \overload
       
  2850 
       
  2851     Use the other paintCell() function. This function is only included
       
  2852     for backwards compatibility.
       
  2853 */
       
  2854 
       
  2855 void Q3Table::paintCell(QPainter* p, int row, int col,
       
  2856                         const QRect &cr, bool selected)
       
  2857 {
       
  2858     if (cr.width() == 0 || cr.height() == 0)
       
  2859         return;
       
  2860 #if defined(Q_WS_WIN)
       
  2861     const QColorGroup &cg = (!drawActiveSelection && style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus) ? palette().inactive() : colorGroup());
       
  2862 #else
       
  2863     const QColorGroup &cg = colorGroup();
       
  2864 #endif
       
  2865 
       
  2866     Q3TableItem *itm = item(row, col);
       
  2867     QColorGroup cg2(cg);
       
  2868     if (itm && !itm->isEnabled())
       
  2869         cg2 = palette().disabled();
       
  2870 
       
  2871     paintCell(p, row, col, cr, selected, cg2);
       
  2872 }
       
  2873 
       
  2874 /*!
       
  2875     Paints the cell at \a row, \a col on the painter \a p. The painter
       
  2876     has already been translated to the cell's origin. \a cr describes
       
  2877     the cell coordinates in the content coordinate system.
       
  2878 
       
  2879     If \a selected is true the cell is highlighted.
       
  2880 
       
  2881     \a cg is the colorgroup which should be used to draw the cell
       
  2882     content.
       
  2883 
       
  2884     If you want to draw custom cell content, for example right-aligned
       
  2885     text, you must either reimplement paintCell(), or subclass
       
  2886     Q3TableItem and reimplement Q3TableItem::paint() to do the custom
       
  2887     drawing.
       
  2888 
       
  2889     If you're using a Q3TableItem subclass, for example, to store a
       
  2890     data structure, then reimplementing Q3TableItem::paint() may be the
       
  2891     best approach. For data you want to draw immediately, e.g. data
       
  2892     retrieved from a database, it is probably best to reimplement
       
  2893     paintCell(). Note that if you reimplement paintCell(), i.e. don't
       
  2894     use \l{Q3TableItem}s, you must reimplement other functions: see the
       
  2895     notes on large tables.
       
  2896 
       
  2897     Note that the painter is not clipped by default in order to get
       
  2898     maximum efficiency. If you want clipping, use code like this:
       
  2899 
       
  2900     \snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 4
       
  2901 */
       
  2902 
       
  2903 void Q3Table::paintCell(QPainter *p, int row, int col,
       
  2904                         const QRect &cr, bool selected, const QColorGroup &cg)
       
  2905 {
       
  2906     if (focusStl == SpreadSheet && selected &&
       
  2907          row == curRow &&
       
  2908          col == curCol && (hasFocus() || viewport()->hasFocus()))
       
  2909         selected = false;
       
  2910 
       
  2911     QPalette pal = cg;
       
  2912     int w = cr.width();
       
  2913     int h = cr.height();
       
  2914     int x2 = w - 1;
       
  2915     int y2 = h - 1;
       
  2916 
       
  2917 
       
  2918     Q3TableItem *itm = item(row, col);
       
  2919     if (itm) {
       
  2920         p->save();
       
  2921         itm->paint(p, pal, cr, selected);
       
  2922         p->restore();
       
  2923     } else {
       
  2924         p->fillRect(0, 0, w, h, selected ? pal.brush(QPalette::Highlight) : pal.brush(QPalette::Base));
       
  2925     }
       
  2926 
       
  2927     if (sGrid) {
       
  2928         // Draw our lines
       
  2929         QPen pen(p->pen());
       
  2930         int gridColor =        style()->styleHint(QStyle::SH_Table_GridLineColor, 0, this);
       
  2931         if (gridColor != -1) {
       
  2932             if (palette() != pal)
       
  2933                 p->setPen(pal.mid().color());
       
  2934             else
       
  2935                 p->setPen((QRgb)gridColor);
       
  2936         } else {
       
  2937             p->setPen(pal.mid().color());
       
  2938         }
       
  2939         p->drawLine(x2, 0, x2, y2);
       
  2940         p->drawLine(0, y2, x2, y2);
       
  2941         p->setPen(pen);
       
  2942     }
       
  2943 }
       
  2944 
       
  2945 /*!
       
  2946     Draws the focus rectangle of the current cell (see currentRow(),
       
  2947     currentColumn()).
       
  2948 
       
  2949     The painter \a p is already translated to the cell's origin, while
       
  2950     \a cr specifies the cell's geometry in content coordinates.
       
  2951 */
       
  2952 
       
  2953 void Q3Table::paintFocus(QPainter *p, const QRect &cr)
       
  2954 {
       
  2955     if (!hasFocus() && !viewport()->hasFocus())
       
  2956         return;
       
  2957     QRect focusRect(0, 0, cr.width(), cr.height());
       
  2958     if (focusStyle() == SpreadSheet) {
       
  2959         p->setPen(QPen(Qt::black, 1));
       
  2960         p->setBrush(Qt::NoBrush);
       
  2961         p->drawRect(focusRect.x(), focusRect.y(), focusRect.width() - 1, focusRect.height() - 1);
       
  2962         p->drawRect(focusRect.x() - 1, focusRect.y() - 1, focusRect.width() + 1, focusRect.height() + 1);
       
  2963     } else {
       
  2964         QStyleOptionFocusRect opt;
       
  2965         opt.init(this);
       
  2966         opt.rect = focusRect;
       
  2967         opt.palette = palette();
       
  2968         opt.state |= QStyle::State_KeyboardFocusChange;
       
  2969         if (isSelected(curRow, curCol, false)) {
       
  2970             opt.state |= QStyle::State_FocusAtBorder;
       
  2971             opt.backgroundColor = palette().highlight().color();
       
  2972         } else {
       
  2973             opt.state |= QStyle::State_None;
       
  2974             opt.backgroundColor = palette().base().color();
       
  2975         }
       
  2976         style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this);
       
  2977     }
       
  2978 }
       
  2979 
       
  2980 /*!
       
  2981     This function fills the \a cw pixels wide and \a ch pixels high
       
  2982     rectangle starting at position \a cx, \a cy with the background
       
  2983     color using the painter \a p.
       
  2984 
       
  2985     paintEmptyArea() is invoked by drawContents() to erase or fill
       
  2986     unused areas.
       
  2987 */
       
  2988 
       
  2989 void Q3Table::paintEmptyArea(QPainter *p, int cx, int cy, int cw, int ch)
       
  2990 {
       
  2991     // Regions work with shorts, so avoid an overflow and adjust the
       
  2992     // table size to the visible size
       
  2993     QSize ts(tableSize());
       
  2994     ts.setWidth(QMIN(ts.width(), visibleWidth()));
       
  2995     ts.setHeight(QMIN(ts.height(), visibleHeight()));
       
  2996 
       
  2997     // Region of the rect we should draw, calculated in viewport
       
  2998     // coordinates, as a region can't handle bigger coordinates
       
  2999     contentsToViewport2(cx, cy, cx, cy);
       
  3000     QRegion reg(QRect(cx, cy, cw, ch));
       
  3001 
       
  3002     // Subtract the table from it
       
  3003     reg = reg.subtracted(QRect(QPoint(0, 0), ts));
       
  3004 
       
  3005     // And draw the rectangles (transformed inc contents coordinates as needed)
       
  3006     Q3MemArray<QRect> r = reg.rects();
       
  3007     for (int i = 0; i < (int)r.count(); ++i)
       
  3008         p->fillRect(QRect(viewportToContents2(r[i].topLeft()),r[i].size()), viewport()->backgroundBrush());
       
  3009 }
       
  3010 
       
  3011 /*!
       
  3012     Returns the Q3TableItem representing the contents of the cell at \a
       
  3013     row, \a col.
       
  3014 
       
  3015     If \a row or \a col are out of range or no content has been set
       
  3016     for this cell, item() returns 0.
       
  3017 
       
  3018     If you don't use \l{Q3TableItem}s you may need to reimplement this
       
  3019     function: see the notes on large tables.
       
  3020 
       
  3021     \sa setItem()
       
  3022 */
       
  3023 
       
  3024 Q3TableItem *Q3Table::item(int row, int col) const
       
  3025 {
       
  3026     if (row < 0 || col < 0 || row > numRows() - 1 ||
       
  3027          col > numCols() - 1 || row * col >= (int)contents.size())
       
  3028         return 0;
       
  3029 
       
  3030     return contents[ indexOf(row, col) ];        // contents array lookup
       
  3031 }
       
  3032 
       
  3033 /*!
       
  3034     Inserts the table item \a item into the table at row \a row,
       
  3035     column \a col, and repaints the cell. If a table item already
       
  3036     exists in this cell it is deleted and replaced with \a item. The
       
  3037     table takes ownership of the table item.
       
  3038 
       
  3039     If you don't use \l{Q3TableItem}s you may need to reimplement this
       
  3040     function: see the notes on large tables.
       
  3041 
       
  3042     \sa item() takeItem()
       
  3043 */
       
  3044 
       
  3045 void Q3Table::setItem(int row, int col, Q3TableItem *item)
       
  3046 {
       
  3047     if (!item)
       
  3048         return;
       
  3049 
       
  3050     if ((int)contents.size() != numRows() * numCols())
       
  3051         resizeData(numRows() * numCols());
       
  3052 
       
  3053     int orow = item->row();
       
  3054     int ocol = item->col();
       
  3055     clearCell(row, col);
       
  3056 
       
  3057     contents.insert(indexOf(row, col), item);
       
  3058     item->setRow(row);
       
  3059     item->setCol(col);
       
  3060     item->t = this;
       
  3061     updateCell(row, col);
       
  3062     if (qt_update_cell_widget)
       
  3063         item->updateEditor(orow, ocol);
       
  3064 
       
  3065     if (row == curRow && col == curCol && item->editType() == Q3TableItem::WhenCurrent) {
       
  3066         if (beginEdit(row, col, false))
       
  3067             setEditMode(Editing, row, col);
       
  3068     }
       
  3069 }
       
  3070 
       
  3071 /*!
       
  3072     Removes the Q3TableItem at \a row, \a col.
       
  3073 
       
  3074     If you don't use \l{Q3TableItem}s you may need to reimplement this
       
  3075     function: see the notes on large tables.
       
  3076 */
       
  3077 
       
  3078 void Q3Table::clearCell(int row, int col)
       
  3079 {
       
  3080     if ((int)contents.size() != numRows() * numCols())
       
  3081         resizeData(numRows() * numCols());
       
  3082     clearCellWidget(row, col);
       
  3083     contents.setAutoDelete(true);
       
  3084     contents.remove(indexOf(row, col));
       
  3085     contents.setAutoDelete(false);
       
  3086 }
       
  3087 
       
  3088 /*!
       
  3089     Sets the text in the cell at \a row, \a col to \a text.
       
  3090 
       
  3091     If the cell does not contain a table item a Q3TableItem is created
       
  3092     with an \link Q3TableItem::EditType EditType\endlink of \c OnTyping,
       
  3093     otherwise the existing table item's text (if any) is replaced with
       
  3094     \a text.
       
  3095 
       
  3096     \sa text() setPixmap() setItem() Q3TableItem::setText()
       
  3097 */
       
  3098 
       
  3099 void Q3Table::setText(int row, int col, const QString &text)
       
  3100 {
       
  3101     Q3TableItem *itm = item(row, col);
       
  3102     if (itm) {
       
  3103         itm->setText(text);
       
  3104         itm->updateEditor(row, col);
       
  3105         updateCell(row, col);
       
  3106     } else {
       
  3107         Q3TableItem *i = new Q3TableItem(this, Q3TableItem::OnTyping,
       
  3108                                         text, QPixmap());
       
  3109         setItem(row, col, i);
       
  3110     }
       
  3111 }
       
  3112 
       
  3113 /*!
       
  3114     Sets the pixmap in the cell at \a row, \a col to \a pix.
       
  3115 
       
  3116     If the cell does not contain a table item a Q3TableItem is created
       
  3117     with an \link Q3TableItem::EditType EditType\endlink of \c OnTyping,
       
  3118     otherwise the existing table item's pixmap (if any) is replaced
       
  3119     with \a pix.
       
  3120 
       
  3121     Note that \l{Q3ComboTableItem}s and \l{Q3CheckTableItem}s don't show
       
  3122     pixmaps.
       
  3123 
       
  3124     \sa pixmap() setText() setItem() Q3TableItem::setPixmap()
       
  3125 */
       
  3126 
       
  3127 void Q3Table::setPixmap(int row, int col, const QPixmap &pix)
       
  3128 {
       
  3129     Q3TableItem *itm = item(row, col);
       
  3130     if (itm) {
       
  3131         itm->setPixmap(pix);
       
  3132         updateCell(row, col);
       
  3133     } else {
       
  3134         Q3TableItem *i = new Q3TableItem(this, Q3TableItem::OnTyping,
       
  3135                                         QString(), pix);
       
  3136         setItem(row, col, i);
       
  3137     }
       
  3138 }
       
  3139 
       
  3140 /*!
       
  3141     Returns the text in the cell at \a row, \a col, or an empty string
       
  3142     if the relevant item does not exist or has no text.
       
  3143 
       
  3144     \sa setText() setPixmap()
       
  3145 */
       
  3146 
       
  3147 QString Q3Table::text(int row, int col) const
       
  3148 {
       
  3149     Q3TableItem *itm = item(row, col);
       
  3150     if (itm)
       
  3151         return itm->text();
       
  3152     return QString();
       
  3153 }
       
  3154 
       
  3155 /*!
       
  3156     Returns the pixmap set for the cell at \a row, \a col, or a
       
  3157     null-pixmap if the cell contains no pixmap.
       
  3158 
       
  3159     \sa setPixmap()
       
  3160 */
       
  3161 
       
  3162 QPixmap Q3Table::pixmap(int row, int col) const
       
  3163 {
       
  3164     Q3TableItem *itm = item(row, col);
       
  3165     if (itm)
       
  3166         return itm->pixmap();
       
  3167     return QPixmap();
       
  3168 }
       
  3169 
       
  3170 /*!
       
  3171     Moves the focus to the cell at \a row, \a col.
       
  3172 
       
  3173     \sa currentRow() currentColumn()
       
  3174 */
       
  3175 
       
  3176 void Q3Table::setCurrentCell(int row, int col)
       
  3177 {
       
  3178     setCurrentCell(row, col, true, true);
       
  3179 }
       
  3180 
       
  3181 // need to use a define, as leftMargin() is protected
       
  3182 #define VERTICALMARGIN \
       
  3183 (QApplication::reverseLayout() ? \
       
  3184        rightMargin() \
       
  3185        : \
       
  3186        leftMargin() \
       
  3187 )
       
  3188 
       
  3189 /*!
       
  3190     \reimp
       
  3191 */
       
  3192 QVariant Q3Table::inputMethodQuery(Qt::InputMethodQuery query) const
       
  3193 {
       
  3194     if (query == Qt::ImMicroFocus)
       
  3195         return QRect(columnPos(curCol) + leftMargin() - contentsX(), rowPos(curRow) + topMargin() - contentsY(),
       
  3196                      columnWidth(curCol), rowHeight(curRow));
       
  3197     return QWidget::inputMethodQuery(query);
       
  3198 
       
  3199 }
       
  3200 
       
  3201 /*! \internal */
       
  3202 
       
  3203 void Q3Table::setCurrentCell(int row, int col, bool updateSelections, bool ensureVisible)
       
  3204 {
       
  3205     Q3TableItem *oldItem = item(curRow, curCol);
       
  3206 
       
  3207     if (row > numRows() - 1)
       
  3208         row = numRows() - 1;
       
  3209     if (col > numCols() - 1)
       
  3210         col = numCols() - 1;
       
  3211 
       
  3212     if (curRow == row && curCol == col)
       
  3213         return;
       
  3214 
       
  3215 
       
  3216     Q3TableItem *itm = oldItem;
       
  3217     if (itm && itm->editType() != Q3TableItem::Always && itm->editType() != Q3TableItem::Never)
       
  3218         endEdit(curRow, curCol, true, false);
       
  3219     int oldRow = curRow;
       
  3220     int oldCol = curCol;
       
  3221     curRow = row;
       
  3222     curCol = col;
       
  3223     repaintCell(oldRow, oldCol);
       
  3224     repaintCell(curRow, curCol);
       
  3225     if (ensureVisible)
       
  3226         ensureCellVisible(curRow, curCol);
       
  3227     emit currentChanged(row, col);
       
  3228 
       
  3229     if (oldCol != curCol) {
       
  3230         if (!isColumnSelected(oldCol))
       
  3231             topHeader->setSectionState(oldCol, Q3TableHeader::Normal);
       
  3232         else if (isRowSelection(selectionMode()))
       
  3233             topHeader->setSectionState(oldCol, Q3TableHeader::Selected);
       
  3234         topHeader->setSectionState(curCol, isColumnSelected(curCol, true) ?
       
  3235                                     Q3TableHeader::Selected : Q3TableHeader::Bold);
       
  3236     }
       
  3237 
       
  3238     if (oldRow != curRow) {
       
  3239         if (!isRowSelected(oldRow))
       
  3240             leftHeader->setSectionState(oldRow, Q3TableHeader::Normal);
       
  3241         leftHeader->setSectionState(curRow, isRowSelected(curRow, true) ?
       
  3242                                      Q3TableHeader::Selected : Q3TableHeader::Bold);
       
  3243     }
       
  3244 
       
  3245     itm = item(curRow, curCol);
       
  3246 
       
  3247 
       
  3248     if (cellWidget(oldRow, oldCol) &&
       
  3249          cellWidget(oldRow, oldCol)->hasFocus())
       
  3250         viewport()->setFocus();
       
  3251 
       
  3252     if (itm && itm->editType() == Q3TableItem::WhenCurrent) {
       
  3253         if (beginEdit(curRow, curCol, false))
       
  3254             setEditMode(Editing, row, col);
       
  3255     } else if (itm && itm->editType() == Q3TableItem::Always) {
       
  3256         if (cellWidget(itm->row(), itm->col()))
       
  3257             cellWidget(itm->row(), itm->col())->setFocus();
       
  3258     }
       
  3259 
       
  3260     if (updateSelections && isRowSelection(selectionMode()) &&
       
  3261          !isSelected(curRow, curCol, false)) {
       
  3262         if (selectionMode() == Q3Table::SingleRow)
       
  3263             clearSelection();
       
  3264         currentSel = new Q3TableSelection();
       
  3265         selections.append(currentSel);
       
  3266         currentSel->init(curRow, 0);
       
  3267         currentSel->expandTo(curRow, numCols() - 1);
       
  3268         repaintSelections(0, currentSel);
       
  3269     }
       
  3270 }
       
  3271 
       
  3272 /*!
       
  3273     Scrolls the table until the cell at \a row, \a col becomes
       
  3274     visible.
       
  3275 */
       
  3276 
       
  3277 void Q3Table::ensureCellVisible(int row, int col)
       
  3278 {
       
  3279     if (!updatesEnabled() || !viewport()->updatesEnabled())
       
  3280         return;
       
  3281     int cw = columnWidth(col);
       
  3282     int rh = rowHeight(row);
       
  3283     if (cw < visibleWidth())
       
  3284         ensureVisible(columnPos(col) + cw / 2, rowPos(row) + rh / 2, cw / 2, rh / 2);
       
  3285     else
       
  3286         ensureVisible(columnPos(col), rowPos(row) + rh / 2, 0, rh / 2);
       
  3287 }
       
  3288 
       
  3289 /*!
       
  3290     Returns true if the cell at \a row, \a col is selected; otherwise
       
  3291     returns false.
       
  3292 
       
  3293     \sa isRowSelected() isColumnSelected()
       
  3294 */
       
  3295 
       
  3296 bool Q3Table::isSelected(int row, int col) const
       
  3297 {
       
  3298     return isSelected(row, col, true);
       
  3299 }
       
  3300 
       
  3301 /*! \internal */
       
  3302 
       
  3303 bool Q3Table::isSelected(int row, int col, bool includeCurrent) const
       
  3304 {
       
  3305     Q3PtrListIterator<Q3TableSelection> it(selections);
       
  3306     Q3TableSelection *s;
       
  3307     while ((s = it.current()) != 0) {
       
  3308         ++it;
       
  3309         if (s->isActive() &&
       
  3310              row >= s->topRow() &&
       
  3311              row <= s->bottomRow() &&
       
  3312              col >= s->leftCol() &&
       
  3313              col <= s->rightCol())
       
  3314             return true;
       
  3315         if (includeCurrent && row == currentRow() && col == currentColumn())
       
  3316             return true;
       
  3317     }
       
  3318     return false;
       
  3319 }
       
  3320 
       
  3321 /*!
       
  3322     Returns true if row \a row is selected; otherwise returns false.
       
  3323 
       
  3324     If \a full is false (the default), 'row is selected' means that at
       
  3325     least one cell in the row is selected. If \a full is true, then 'row
       
  3326     is selected' means every cell in the row is selected.
       
  3327 
       
  3328     \sa isColumnSelected() isSelected()
       
  3329 */
       
  3330 
       
  3331 bool Q3Table::isRowSelected(int row, bool full) const
       
  3332 {
       
  3333     if (!full) {
       
  3334         Q3PtrListIterator<Q3TableSelection> it(selections);
       
  3335         Q3TableSelection *s;
       
  3336         while ((s = it.current()) != 0) {
       
  3337             ++it;
       
  3338             if (s->isActive() &&
       
  3339                  row >= s->topRow() &&
       
  3340                  row <= s->bottomRow())
       
  3341             return true;
       
  3342         if (row == currentRow())
       
  3343             return true;
       
  3344         }
       
  3345     } else {
       
  3346         Q3PtrListIterator<Q3TableSelection> it(selections);
       
  3347         Q3TableSelection *s;
       
  3348         while ((s = it.current()) != 0) {
       
  3349             ++it;
       
  3350             if (s->isActive() &&
       
  3351                  row >= s->topRow() &&
       
  3352                  row <= s->bottomRow() &&
       
  3353                  s->leftCol() == 0 &&
       
  3354                  s->rightCol() == numCols() - 1)
       
  3355                 return true;
       
  3356         }
       
  3357     }
       
  3358     return false;
       
  3359 }
       
  3360 
       
  3361 /*!
       
  3362     Returns true if column \a col is selected; otherwise returns false.
       
  3363 
       
  3364     If \a full is false (the default), 'column is selected' means that
       
  3365     at least one cell in the column is selected. If \a full is true,
       
  3366     then 'column is selected' means every cell in the column is
       
  3367     selected.
       
  3368 
       
  3369     \sa isRowSelected() isSelected()
       
  3370 */
       
  3371 
       
  3372 bool Q3Table::isColumnSelected(int col, bool full) const
       
  3373 {
       
  3374     if (!full) {
       
  3375         Q3PtrListIterator<Q3TableSelection> it(selections);
       
  3376         Q3TableSelection *s;
       
  3377         while ((s = it.current()) != 0) {
       
  3378             ++it;
       
  3379             if (s->isActive() &&
       
  3380                  col >= s->leftCol() &&
       
  3381                  col <= s->rightCol())
       
  3382             return true;
       
  3383         if (col == currentColumn())
       
  3384             return true;
       
  3385         }
       
  3386     } else {
       
  3387         Q3PtrListIterator<Q3TableSelection> it(selections);
       
  3388         Q3TableSelection *s;
       
  3389         while ((s = it.current()) != 0) {
       
  3390             ++it;
       
  3391             if (s->isActive() &&
       
  3392                  col >= s->leftCol() &&
       
  3393                  col <= s->rightCol() &&
       
  3394                  s->topRow() == 0 &&
       
  3395                  s->bottomRow() == numRows() - 1)
       
  3396                 return true;
       
  3397         }
       
  3398     }
       
  3399     return false;
       
  3400 }
       
  3401 
       
  3402 /*!
       
  3403     \property Q3Table::numSelections
       
  3404     \brief The number of selections.
       
  3405 
       
  3406     \sa currentSelection()
       
  3407 */
       
  3408 
       
  3409 int Q3Table::numSelections() const
       
  3410 {
       
  3411     return selections.count();
       
  3412 }
       
  3413 
       
  3414 /*!
       
  3415     Returns selection number \a num, or an inactive Q3TableSelection if \a
       
  3416     num is out of range (see Q3TableSelection::isActive()).
       
  3417 */
       
  3418 
       
  3419 Q3TableSelection Q3Table::selection(int num) const
       
  3420 {
       
  3421     if (num < 0 || num >= (int)selections.count())
       
  3422         return Q3TableSelection();
       
  3423 
       
  3424     Q3TableSelection *s = ((Q3Table*)this)->selections.at(num);
       
  3425     return *s;
       
  3426 }
       
  3427 
       
  3428 /*!
       
  3429     Adds a selection described by \a s to the table and returns its
       
  3430     number or -1 if the selection is invalid.
       
  3431 
       
  3432     Remember to call Q3TableSelection::init() and
       
  3433     Q3TableSelection::expandTo() to make the selection valid (see also
       
  3434     Q3TableSelection::isActive(), or use the
       
  3435     Q3TableSelection(int,int,int,int) constructor).
       
  3436 
       
  3437     \sa numSelections() removeSelection() clearSelection()
       
  3438 */
       
  3439 
       
  3440 int Q3Table::addSelection(const Q3TableSelection &s)
       
  3441 {
       
  3442     if (!s.isActive())
       
  3443         return -1;
       
  3444 
       
  3445     const int maxr = numRows()-1;
       
  3446     const int maxc = numCols()-1;
       
  3447     currentSel = new Q3TableSelection(QMIN(s.anchorRow(), maxr), QMIN(s.anchorCol(), maxc),
       
  3448                                     QMIN(s.bottomRow(), maxr), QMIN(s.rightCol(), maxc));
       
  3449 
       
  3450     selections.append(currentSel);
       
  3451 
       
  3452     repaintSelections(0, currentSel, true, true);
       
  3453 
       
  3454     emit selectionChanged();
       
  3455 
       
  3456     return selections.count() - 1;
       
  3457 }
       
  3458 
       
  3459 /*!
       
  3460     If the table has a selection, \a s, this selection is removed from
       
  3461     the table.
       
  3462 
       
  3463     \sa addSelection() numSelections()
       
  3464 */
       
  3465 
       
  3466 void Q3Table::removeSelection(const Q3TableSelection &s)
       
  3467 {
       
  3468     selections.setAutoDelete(false);
       
  3469     for (Q3TableSelection *sel = selections.first(); sel; sel = selections.next()) {
       
  3470         if (s == *sel) {
       
  3471             selections.removeRef(sel);
       
  3472             repaintSelections(sel, 0, true, true);
       
  3473             if (sel == currentSel)
       
  3474                 currentSel = 0;
       
  3475             delete sel;
       
  3476         }
       
  3477     }
       
  3478     selections.setAutoDelete(true);
       
  3479     emit selectionChanged();
       
  3480 }
       
  3481 
       
  3482 /*!
       
  3483     \overload
       
  3484 
       
  3485     Removes selection number \a num from the table.
       
  3486 
       
  3487     \sa numSelections() addSelection() clearSelection()
       
  3488 */
       
  3489 
       
  3490 void Q3Table::removeSelection(int num)
       
  3491 {
       
  3492     if (num < 0 || num >= (int)selections.count())
       
  3493         return;
       
  3494 
       
  3495     Q3TableSelection *s = selections.at(num);
       
  3496     if (s == currentSel)
       
  3497         currentSel = 0;
       
  3498     selections.removeRef(s);
       
  3499     repaintContents(false);
       
  3500 }
       
  3501 
       
  3502 /*!
       
  3503     Returns the number of the current selection or -1 if there is no
       
  3504     current selection.
       
  3505 
       
  3506     \sa numSelections()
       
  3507 */
       
  3508 
       
  3509 int Q3Table::currentSelection() const
       
  3510 {
       
  3511     if (!currentSel)
       
  3512         return -1;
       
  3513     return ((Q3Table*)this)->selections.findRef(currentSel);
       
  3514 }
       
  3515 
       
  3516 /*! Selects the range starting at \a start_row and \a start_col and
       
  3517   ending at \a end_row and \a end_col.
       
  3518 
       
  3519   \sa Q3TableSelection
       
  3520 */
       
  3521 
       
  3522 void Q3Table::selectCells(int start_row, int start_col, int end_row, int end_col)
       
  3523 {
       
  3524     const int maxr = numRows()-1;
       
  3525     const int maxc = numCols()-1;
       
  3526 
       
  3527     start_row = QMIN(maxr, QMAX(0, start_row));
       
  3528     start_col = QMIN(maxc, QMAX(0, start_col));
       
  3529     end_row = QMIN(maxr, end_row);
       
  3530     end_col = QMIN(maxc, end_col);
       
  3531     Q3TableSelection sel(start_row, start_col, end_row, end_col);
       
  3532     addSelection(sel);
       
  3533 }
       
  3534 
       
  3535 /*! Selects the row \a row.
       
  3536 
       
  3537   \sa Q3TableSelection
       
  3538 */
       
  3539 
       
  3540 void Q3Table::selectRow(int row)
       
  3541 {
       
  3542     row = QMIN(numRows()-1, row);
       
  3543     if (row < 0)
       
  3544         return;
       
  3545     if (selectionMode() == SingleRow) {
       
  3546         setCurrentCell(row, currentColumn());
       
  3547     } else {
       
  3548         Q3TableSelection sel(row, 0, row, numCols() - 1);
       
  3549         addSelection(sel);
       
  3550     }
       
  3551 }
       
  3552 
       
  3553 /*! Selects the column \a col.
       
  3554 
       
  3555   \sa Q3TableSelection
       
  3556 */
       
  3557 
       
  3558 void Q3Table::selectColumn(int col)
       
  3559 {
       
  3560     col = QMIN(numCols()-1, col);
       
  3561     if (col < 0)
       
  3562         return;
       
  3563     Q3TableSelection sel(0, col, numRows() - 1, col);
       
  3564     addSelection(sel);
       
  3565 }
       
  3566 
       
  3567 /*! \reimp
       
  3568 */
       
  3569 void Q3Table::contentsMousePressEvent(QMouseEvent* e)
       
  3570 {
       
  3571     contentsMousePressEventEx(e);
       
  3572 }
       
  3573 
       
  3574 void Q3Table::contentsMousePressEventEx(QMouseEvent* e)
       
  3575 {
       
  3576     shouldClearSelection = false;
       
  3577     if (isEditing()) {
       
  3578         if (!cellGeometry(editRow, editCol).contains(e->pos())) {
       
  3579             endEdit(editRow, editCol, true, edMode != Editing);
       
  3580         } else {
       
  3581             e->ignore();
       
  3582             return;
       
  3583         }
       
  3584     }
       
  3585 
       
  3586     d->redirectMouseEvent = false;
       
  3587 
       
  3588     int tmpRow = rowAt(e->pos().y());
       
  3589     int tmpCol = columnAt(e->pos().x());
       
  3590     pressedRow = tmpRow;
       
  3591     pressedCol = tmpCol;
       
  3592     fixRow(tmpRow, e->pos().y());
       
  3593     fixCol(tmpCol, e->pos().x());
       
  3594     startDragCol = -1;
       
  3595     startDragRow = -1;
       
  3596 
       
  3597     if (isSelected(tmpRow, tmpCol)) {
       
  3598         startDragCol = tmpCol;
       
  3599         startDragRow = tmpRow;
       
  3600         dragStartPos = e->pos();
       
  3601     }
       
  3602 
       
  3603     Q3TableItem *itm = item(pressedRow, pressedCol);
       
  3604     if (itm && !itm->isEnabled()) {
       
  3605         emit pressed(tmpRow, tmpCol, e->button(), e->pos());
       
  3606         return;
       
  3607     }
       
  3608 
       
  3609     if ((e->state() & ShiftButton) == ShiftButton) {
       
  3610           int oldRow = curRow;
       
  3611           int oldCol = curCol;
       
  3612         setCurrentCell(tmpRow, tmpCol, selMode == SingleRow, true);
       
  3613         if (selMode != NoSelection && selMode != SingleRow) {
       
  3614             if (!currentSel) {
       
  3615                 currentSel = new Q3TableSelection();
       
  3616                 selections.append(currentSel);
       
  3617                 if (!isRowSelection(selectionMode()))
       
  3618                     currentSel->init(oldRow, oldCol);
       
  3619                 else
       
  3620                     currentSel->init(oldRow, 0);
       
  3621             }
       
  3622             Q3TableSelection oldSelection = *currentSel;
       
  3623             if (!isRowSelection(selectionMode()))
       
  3624                 currentSel->expandTo(tmpRow, tmpCol);
       
  3625             else
       
  3626                 currentSel->expandTo(tmpRow, numCols() - 1);
       
  3627             repaintSelections(&oldSelection, currentSel);
       
  3628             emit selectionChanged();
       
  3629         }
       
  3630     } else if ((e->state() & ControlButton) == ControlButton) {
       
  3631         setCurrentCell(tmpRow, tmpCol, false, true);
       
  3632         if (selMode != NoSelection) {
       
  3633             if (selMode == Single || (selMode == SingleRow && !isSelected(tmpRow, tmpCol, false)))
       
  3634                 clearSelection();
       
  3635             if (!(selMode == SingleRow && isSelected(tmpRow, tmpCol, false))) {
       
  3636                 currentSel = new Q3TableSelection();
       
  3637                 selections.append(currentSel);
       
  3638                 if (!isRowSelection(selectionMode())) {
       
  3639                     currentSel->init(tmpRow, tmpCol);
       
  3640                     currentSel->expandTo(tmpRow, tmpCol);
       
  3641                 } else {
       
  3642                     currentSel->init(tmpRow, 0);
       
  3643                     currentSel->expandTo(tmpRow, numCols() - 1);
       
  3644                     repaintSelections(0, currentSel);
       
  3645                 }
       
  3646                 emit selectionChanged();
       
  3647             }
       
  3648         }
       
  3649     } else {
       
  3650         setCurrentCell(tmpRow, tmpCol, false, true);
       
  3651         Q3TableItem *itm = item(tmpRow, tmpCol);
       
  3652         if (itm && itm->editType() == Q3TableItem::WhenCurrent) {
       
  3653             QWidget *w = cellWidget(tmpRow, tmpCol);
       
  3654             if (qobject_cast<Q3ComboBox*>(w) || qobject_cast<QAbstractButton*>(w)) {
       
  3655                 QMouseEvent ev(e->type(), w->mapFromGlobal(e->globalPos()),
       
  3656                                 e->globalPos(), e->button(), e->state());
       
  3657                 QApplication::sendPostedEvents(w, 0);
       
  3658                 QApplication::sendEvent(w, &ev);
       
  3659                 d->redirectMouseEvent = true;
       
  3660             }
       
  3661         }
       
  3662         if (isSelected(tmpRow, tmpCol, false)) {
       
  3663             shouldClearSelection = true;
       
  3664         } else {
       
  3665             bool b = signalsBlocked();
       
  3666             if (selMode != NoSelection)
       
  3667                 blockSignals(true);
       
  3668             clearSelection();
       
  3669             blockSignals(b);
       
  3670             if (selMode != NoSelection) {
       
  3671                 currentSel = new Q3TableSelection();
       
  3672                 selections.append(currentSel);
       
  3673                 if (!isRowSelection(selectionMode())) {
       
  3674                     currentSel->init(tmpRow, tmpCol);
       
  3675                     currentSel->expandTo(tmpRow, tmpCol);
       
  3676                 } else {
       
  3677                     currentSel->init(tmpRow, 0);
       
  3678                     currentSel->expandTo(tmpRow, numCols() - 1);
       
  3679                     repaintSelections(0, currentSel);
       
  3680                 }
       
  3681                 emit selectionChanged();
       
  3682             }
       
  3683         }
       
  3684     }
       
  3685 
       
  3686     emit pressed(tmpRow, tmpCol, e->button(), e->pos());
       
  3687 }
       
  3688 
       
  3689 /*! \reimp
       
  3690 */
       
  3691 
       
  3692 void Q3Table::contentsMouseDoubleClickEvent(QMouseEvent *e)
       
  3693 {
       
  3694     if (e->button() != LeftButton)
       
  3695         return;
       
  3696     if (!isRowSelection(selectionMode()))
       
  3697         clearSelection();
       
  3698     int tmpRow = rowAt(e->pos().y());
       
  3699     int tmpCol = columnAt(e->pos().x());
       
  3700     Q3TableItem *itm = item(tmpRow, tmpCol);
       
  3701     if (itm && !itm->isEnabled())
       
  3702         return;
       
  3703     if (tmpRow != -1 && tmpCol != -1) {
       
  3704         if (beginEdit(tmpRow, tmpCol, false))
       
  3705             setEditMode(Editing, tmpRow, tmpCol);
       
  3706     }
       
  3707 
       
  3708     emit doubleClicked(tmpRow, tmpCol, e->button(), e->pos());
       
  3709 }
       
  3710 
       
  3711 /*!
       
  3712     Sets the current edit mode to \a mode, the current edit row to \a
       
  3713     row and the current edit column to \a col.
       
  3714 
       
  3715     \sa EditMode
       
  3716 */
       
  3717 
       
  3718 void Q3Table::setEditMode(EditMode mode, int row, int col)
       
  3719 {
       
  3720     edMode = mode;
       
  3721     editRow = row;
       
  3722     editCol = col;
       
  3723 }
       
  3724 
       
  3725 
       
  3726 /*! \reimp
       
  3727 */
       
  3728 
       
  3729 void Q3Table::contentsMouseMoveEvent(QMouseEvent *e)
       
  3730 {
       
  3731     if ((e->state() & MouseButtonMask) == NoButton)
       
  3732         return;
       
  3733     int tmpRow = rowAt(e->pos().y());
       
  3734     int tmpCol = columnAt(e->pos().x());
       
  3735     fixRow(tmpRow, e->pos().y());
       
  3736     fixCol(tmpCol, e->pos().x());
       
  3737 
       
  3738 #ifndef QT_NO_DRAGANDDROP
       
  3739     if (dragEnabled() && startDragRow != -1 && startDragCol != -1) {
       
  3740         if (QPoint(dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance())
       
  3741             startDrag();
       
  3742         return;
       
  3743     }
       
  3744 #endif
       
  3745     if (selectionMode() == MultiRow && (e->state() & ControlButton) == ControlButton)
       
  3746         shouldClearSelection = false;
       
  3747 
       
  3748     if (shouldClearSelection) {
       
  3749         clearSelection();
       
  3750         if (selMode != NoSelection) {
       
  3751             currentSel = new Q3TableSelection();
       
  3752             selections.append(currentSel);
       
  3753             if (!isRowSelection(selectionMode()))
       
  3754                 currentSel->init(tmpRow, tmpCol);
       
  3755             else
       
  3756                 currentSel->init(tmpRow, 0);
       
  3757             emit selectionChanged();
       
  3758         }
       
  3759         shouldClearSelection = false;
       
  3760     }
       
  3761 
       
  3762     QPoint pos = mapFromGlobal(e->globalPos());
       
  3763     pos -= QPoint(leftHeader->width(), topHeader->height());
       
  3764     autoScrollTimer->stop();
       
  3765     doAutoScroll();
       
  3766     if (pos.x() < 0 || pos.x() > visibleWidth() || pos.y() < 0 || pos.y() > visibleHeight())
       
  3767         autoScrollTimer->start(100, true);
       
  3768 }
       
  3769 
       
  3770 /*! \internal
       
  3771  */
       
  3772 
       
  3773 void Q3Table::doValueChanged()
       
  3774 {
       
  3775     emit valueChanged(editRow, editCol);
       
  3776 }
       
  3777 
       
  3778 /*! \internal
       
  3779 */
       
  3780 
       
  3781 void Q3Table::doAutoScroll()
       
  3782 {
       
  3783     QPoint pos = QCursor::pos();
       
  3784     pos = mapFromGlobal(pos);
       
  3785     pos -= QPoint(leftHeader->width(), topHeader->height());
       
  3786 
       
  3787     int tmpRow = curRow;
       
  3788     int tmpCol = curCol;
       
  3789     if (pos.y() < 0)
       
  3790         tmpRow--;
       
  3791     else if (pos.y() > visibleHeight())
       
  3792         tmpRow++;
       
  3793     if (pos.x() < 0)
       
  3794         tmpCol--;
       
  3795     else if (pos.x() > visibleWidth())
       
  3796         tmpCol++;
       
  3797 
       
  3798     pos += QPoint(contentsX(), contentsY());
       
  3799     if (tmpRow == curRow)
       
  3800         tmpRow = rowAt(pos.y());
       
  3801     if (tmpCol == curCol)
       
  3802         tmpCol = columnAt(pos.x());
       
  3803     pos -= QPoint(contentsX(), contentsY());
       
  3804 
       
  3805     fixRow(tmpRow, pos.y());
       
  3806     fixCol(tmpCol, pos.x());
       
  3807 
       
  3808     if (tmpRow < 0 || tmpRow > numRows() - 1)
       
  3809         tmpRow = currentRow();
       
  3810     if (tmpCol < 0 || tmpCol > numCols() - 1)
       
  3811         tmpCol = currentColumn();
       
  3812 
       
  3813     ensureCellVisible(tmpRow, tmpCol);
       
  3814 
       
  3815     if (currentSel && selMode != NoSelection) {
       
  3816         Q3TableSelection oldSelection = *currentSel;
       
  3817         bool useOld = true;
       
  3818         if (selMode != SingleRow) {
       
  3819             if (!isRowSelection(selectionMode())) {
       
  3820                 currentSel->expandTo(tmpRow, tmpCol);
       
  3821             } else {
       
  3822                 currentSel->expandTo(tmpRow, numCols() - 1);
       
  3823             }
       
  3824         } else {
       
  3825             bool currentInSelection = tmpRow == curRow && isSelected(tmpRow, tmpCol);
       
  3826             if (!currentInSelection) {
       
  3827                 useOld = false;
       
  3828                 clearSelection();
       
  3829                 currentSel = new Q3TableSelection();
       
  3830                 selections.append(currentSel);
       
  3831                 currentSel->init(tmpRow, 0);
       
  3832                 currentSel->expandTo(tmpRow, numCols() - 1);
       
  3833                 repaintSelections(0, currentSel);
       
  3834             } else {
       
  3835                 currentSel->expandTo(tmpRow, numCols() - 1);
       
  3836             }
       
  3837         }
       
  3838         setCurrentCell(tmpRow, tmpCol, false, true);
       
  3839         repaintSelections(useOld ? &oldSelection : 0, currentSel);
       
  3840         if (currentSel && oldSelection != *currentSel)
       
  3841             emit selectionChanged();
       
  3842     } else {
       
  3843         setCurrentCell(tmpRow, tmpCol, false, true);
       
  3844     }
       
  3845 
       
  3846     if (pos.x() < 0 || pos.x() > visibleWidth() || pos.y() < 0 || pos.y() > visibleHeight())
       
  3847         autoScrollTimer->start(100, true);
       
  3848 }
       
  3849 
       
  3850 /*! \reimp
       
  3851 */
       
  3852 
       
  3853 void Q3Table::contentsMouseReleaseEvent(QMouseEvent *e)
       
  3854 {
       
  3855     if (pressedRow == curRow && pressedCol == curCol)
       
  3856         emit clicked(curRow, curCol, e->button(), e->pos());
       
  3857 
       
  3858     if (e->button() != LeftButton)
       
  3859         return;
       
  3860     if (shouldClearSelection) {
       
  3861         int tmpRow = rowAt(e->pos().y());
       
  3862         int tmpCol = columnAt(e->pos().x());
       
  3863         fixRow(tmpRow, e->pos().y());
       
  3864         fixCol(tmpCol, e->pos().x());
       
  3865         clearSelection();
       
  3866         if (selMode != NoSelection) {
       
  3867             currentSel = new Q3TableSelection();
       
  3868             selections.append(currentSel);
       
  3869             if (!isRowSelection(selectionMode())) {
       
  3870                 currentSel->init(tmpRow, tmpCol);
       
  3871             } else {
       
  3872                 currentSel->init(tmpRow, 0);
       
  3873                 currentSel->expandTo(tmpRow, numCols() - 1);
       
  3874                 repaintSelections(0, currentSel);
       
  3875             }
       
  3876             emit selectionChanged();
       
  3877         }
       
  3878         shouldClearSelection = false;
       
  3879     }
       
  3880     autoScrollTimer->stop();
       
  3881 
       
  3882     if (d->redirectMouseEvent && pressedRow == curRow && pressedCol == curCol &&
       
  3883          item(pressedRow, pressedCol) && item(pressedRow, pressedCol)->editType() ==
       
  3884          Q3TableItem::WhenCurrent) {
       
  3885         QWidget *w = cellWidget(pressedRow, pressedCol);
       
  3886         if (w) {
       
  3887             QMouseEvent ev(e->type(), w->mapFromGlobal(e->globalPos()),
       
  3888                             e->globalPos(), e->button(), e->state());
       
  3889             QApplication::sendPostedEvents(w, 0);
       
  3890             bool old = w->testAttribute(Qt::WA_NoMousePropagation);
       
  3891             w->setAttribute(Qt::WA_NoMousePropagation, true);
       
  3892             QApplication::sendEvent(w, &ev);
       
  3893             w->setAttribute(Qt::WA_NoMousePropagation, old);
       
  3894         }
       
  3895     }
       
  3896 }
       
  3897 
       
  3898 /*!
       
  3899   \reimp
       
  3900 */
       
  3901 
       
  3902 void Q3Table::contentsContextMenuEvent(QContextMenuEvent *e)
       
  3903 {
       
  3904     if (!receivers(SIGNAL(contextMenuRequested(int,int,QPoint)))) {
       
  3905         e->ignore();
       
  3906         return;
       
  3907     }
       
  3908     if (e->reason() == QContextMenuEvent::Keyboard) {
       
  3909         QRect r = cellGeometry(curRow, curCol);
       
  3910         emit contextMenuRequested(curRow, curCol, viewport()->mapToGlobal(contentsToViewport(r.center())));
       
  3911     } else {
       
  3912         int tmpRow = rowAt(e->pos().y());
       
  3913         int tmpCol = columnAt(e->pos().x());
       
  3914         emit contextMenuRequested(tmpRow, tmpCol, e->globalPos());
       
  3915     }
       
  3916 }
       
  3917 
       
  3918 
       
  3919 /*! \reimp
       
  3920 */
       
  3921 
       
  3922 bool Q3Table::eventFilter(QObject *o, QEvent *e)
       
  3923 {
       
  3924     switch (e->type()) {
       
  3925     case QEvent::KeyPress: {
       
  3926         Q3TableItem *itm = item(curRow, curCol);
       
  3927         QWidget *editorWidget = cellWidget(editRow, editCol);
       
  3928 
       
  3929         if (isEditing() && editorWidget && o == editorWidget) {
       
  3930             itm = item(editRow, editCol);
       
  3931             QKeyEvent *ke = (QKeyEvent*)e;
       
  3932             if (ke->key() == Key_Escape) {
       
  3933                 if (!itm || itm->editType() == Q3TableItem::OnTyping)
       
  3934                     endEdit(editRow, editCol, false, edMode != Editing);
       
  3935                 return true;
       
  3936             }
       
  3937 
       
  3938             if ((ke->state() == NoButton || ke->state() == Keypad)
       
  3939                 && (ke->key() == Key_Return || ke->key() == Key_Enter)) {
       
  3940                 if (!itm || itm->editType() == Q3TableItem::OnTyping)
       
  3941                     endEdit(editRow, editCol, true, edMode != Editing);
       
  3942                 activateNextCell();
       
  3943                 return true;
       
  3944             }
       
  3945 
       
  3946             if (ke->key() == Key_Tab || ke->key() == Key_BackTab) {
       
  3947                 if (ke->state() & Qt::ControlButton)
       
  3948                     return false;
       
  3949                 if (!itm || itm->editType() == Q3TableItem::OnTyping)
       
  3950                     endEdit(editRow, editCol, true, edMode != Editing);
       
  3951                 if ((ke->key() == Key_Tab) && !(ke->state() & ShiftButton)) {
       
  3952                     if (currentColumn() >= numCols() - 1)
       
  3953                         return true;
       
  3954                     int cc  = QMIN(numCols() - 1, currentColumn() + 1);
       
  3955                     while (cc < numCols()) {
       
  3956                         Q3TableItem *i = item(currentRow(), cc);
       
  3957                         if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
       
  3958                             break;
       
  3959                         ++cc;
       
  3960                     }
       
  3961                     setCurrentCell(currentRow(), cc);
       
  3962                 } else { // Key_BackTab
       
  3963                     if (currentColumn() == 0)
       
  3964                         return true;
       
  3965                     int cc  = QMAX(0, currentColumn() - 1);
       
  3966                     while (cc >= 0) {
       
  3967                         Q3TableItem *i = item(currentRow(), cc);
       
  3968                         if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
       
  3969                             break;
       
  3970                         --cc;
       
  3971                     }
       
  3972                     setCurrentCell(currentRow(), cc);
       
  3973                 }
       
  3974                 itm = item(curRow, curCol);
       
  3975                 if (beginEdit(curRow, curCol, false))
       
  3976                     setEditMode(Editing, curRow, curCol);
       
  3977                 return true;
       
  3978             }
       
  3979 
       
  3980             if ((edMode == Replacing ||
       
  3981                    (itm && itm->editType() == Q3TableItem::WhenCurrent)) &&
       
  3982                  (ke->key() == Key_Up || ke->key() == Key_Prior ||
       
  3983                    ke->key() == Key_Home || ke->key() == Key_Down ||
       
  3984                    ke->key() == Key_Next || ke->key() == Key_End ||
       
  3985                    ke->key() == Key_Left || ke->key() == Key_Right)) {
       
  3986                 if (!itm || itm->editType() == Q3TableItem::OnTyping) {
       
  3987                     endEdit(editRow, editCol, true, edMode != Editing);
       
  3988                 }
       
  3989                 keyPressEvent(ke);
       
  3990                 return true;
       
  3991             }
       
  3992         } else {
       
  3993             QObjectList l = viewport()->queryList("QWidget");
       
  3994             if (l.contains(o)) {
       
  3995                 QKeyEvent *ke = (QKeyEvent*)e;
       
  3996                 if ((ke->state() & ControlButton) == ControlButton ||
       
  3997                      (ke->key() != Key_Left && ke->key() != Key_Right &&
       
  3998                        ke->key() != Key_Up && ke->key() != Key_Down &&
       
  3999                        ke->key() != Key_Prior && ke->key() != Key_Next &&
       
  4000                        ke->key() != Key_Home && ke->key() != Key_End))
       
  4001                     return false;
       
  4002                 keyPressEvent((QKeyEvent*)e);
       
  4003                 return true;
       
  4004             }
       
  4005         }
       
  4006 
       
  4007         } break;
       
  4008     case QEvent::FocusOut: {
       
  4009         QWidget *editorWidget = cellWidget(editRow, editCol);
       
  4010         if (isEditing() && editorWidget && o == editorWidget && ((QFocusEvent*)e)->reason() != Qt::PopupFocusReason) {
       
  4011             // if the editor is the parent of the new focus widget, do nothing
       
  4012             QWidget *w = QApplication::focusWidget();
       
  4013             while (w) {
       
  4014                 w = w->parentWidget();
       
  4015                 if (w == editorWidget)
       
  4016                     break;
       
  4017             }
       
  4018             if (w)
       
  4019                 break;
       
  4020             // otherwise, end editing
       
  4021             Q3TableItem *itm = item(editRow, editCol);
       
  4022             if (!itm || itm->editType() == Q3TableItem::OnTyping) {
       
  4023                 endEdit(editRow, editCol, true, edMode != Editing);
       
  4024                 return true;
       
  4025             }
       
  4026         }
       
  4027         break;
       
  4028     }
       
  4029 #ifndef QT_NO_WHEELEVENT
       
  4030     case QEvent::Wheel:
       
  4031         if (o == this || o == viewport()) {
       
  4032             QWheelEvent* we = (QWheelEvent*)e;
       
  4033             scrollBy(0, -we->delta());
       
  4034             we->accept();
       
  4035             return true;
       
  4036         }
       
  4037 #endif
       
  4038     default:
       
  4039         break;
       
  4040     }
       
  4041 
       
  4042     return Q3ScrollView::eventFilter(o, e);
       
  4043 }
       
  4044 
       
  4045 void Q3Table::fixCell(int &row, int &col, int key)
       
  4046 {
       
  4047     if (rowHeight(row) > 0 && columnWidth(col) > 0)
       
  4048         return;
       
  4049     if (rowHeight(row) <= 0) {
       
  4050         if (key == Key_Down ||
       
  4051              key == Key_Next ||
       
  4052              key == Key_End) {
       
  4053             while (row < numRows() && rowHeight(row) <= 0)
       
  4054                 row++;
       
  4055             if (rowHeight(row) <= 0)
       
  4056                 row = curRow;
       
  4057         } else if (key == Key_Up ||
       
  4058                     key == Key_Prior ||
       
  4059                     key == Key_Home)
       
  4060             while (row >= 0 && rowHeight(row) <= 0)
       
  4061                 row--;
       
  4062             if (rowHeight(row) <= 0)
       
  4063                 row = curRow;
       
  4064     } else if (columnWidth(col) <= 0) {
       
  4065         if (key == Key_Left) {
       
  4066             while (col >= 0 && columnWidth(col) <= 0)
       
  4067                 col--;
       
  4068             if (columnWidth(col) <= 0)
       
  4069                 col = curCol;
       
  4070         } else if (key == Key_Right) {
       
  4071             while (col < numCols() && columnWidth(col) <= 0)
       
  4072                 col++;
       
  4073             if (columnWidth(col) <= 0)
       
  4074                 col = curCol;
       
  4075         }
       
  4076     }
       
  4077 }
       
  4078 
       
  4079 /*! \reimp
       
  4080 */
       
  4081 
       
  4082 void Q3Table::keyPressEvent(QKeyEvent* e)
       
  4083 {
       
  4084     if (isEditing() && item(editRow, editCol) &&
       
  4085          item(editRow, editCol)->editType() == Q3TableItem::OnTyping)
       
  4086         return;
       
  4087 
       
  4088     int tmpRow = curRow;
       
  4089     int tmpCol = curCol;
       
  4090     int oldRow = tmpRow;
       
  4091     int oldCol = tmpCol;
       
  4092 
       
  4093     bool navigationKey = false;
       
  4094     int r;
       
  4095     switch (e->key()) {
       
  4096     case Key_Left:
       
  4097         tmpCol = QMAX(0, tmpCol - 1);
       
  4098         navigationKey = true;
       
  4099         break;
       
  4100     case Key_Right:
       
  4101         tmpCol = QMIN(numCols() - 1, tmpCol + 1);
       
  4102         navigationKey = true;
       
  4103         break;
       
  4104     case Key_Up:
       
  4105         tmpRow = QMAX(0, tmpRow - 1);
       
  4106         navigationKey = true;
       
  4107         break;
       
  4108     case Key_Down:
       
  4109         tmpRow = QMIN(numRows() - 1, tmpRow + 1);
       
  4110         navigationKey = true;
       
  4111         break;
       
  4112     case Key_Prior:
       
  4113         r = QMAX(0, rowAt(rowPos(tmpRow) - visibleHeight()));
       
  4114         if (r < tmpRow || tmpRow < 0)
       
  4115             tmpRow = r;
       
  4116         navigationKey = true;
       
  4117         break;
       
  4118     case Key_Next:
       
  4119         r = QMIN(numRows() - 1, rowAt(rowPos(tmpRow) + visibleHeight()));
       
  4120         if (r > tmpRow)
       
  4121             tmpRow = r;
       
  4122         else
       
  4123             tmpRow = numRows() - 1;
       
  4124         navigationKey = true;
       
  4125         break;
       
  4126     case Key_Home:
       
  4127         tmpRow = 0;
       
  4128         navigationKey = true;
       
  4129         break;
       
  4130     case Key_End:
       
  4131         tmpRow = numRows() - 1;
       
  4132         navigationKey = true;
       
  4133         break;
       
  4134     case Key_F2:
       
  4135         if (beginEdit(tmpRow, tmpCol, false))
       
  4136             setEditMode(Editing, tmpRow, tmpCol);
       
  4137         break;
       
  4138     case Key_Enter: case Key_Return:
       
  4139         activateNextCell();
       
  4140         return;
       
  4141     case Key_Tab: case Key_BackTab:
       
  4142         if ((e->key() == Key_Tab) && !(e->state() & ShiftButton)) {
       
  4143             if (currentColumn() >= numCols() - 1)
       
  4144                 return;
       
  4145             int cc  = QMIN(numCols() - 1, currentColumn() + 1);
       
  4146             while (cc < numCols()) {
       
  4147                 Q3TableItem *i = item(currentRow(), cc);
       
  4148                 if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
       
  4149                     break;
       
  4150                 ++cc;
       
  4151             }
       
  4152             setCurrentCell(currentRow(), cc);
       
  4153         } else { // Key_BackTab
       
  4154             if (currentColumn() == 0)
       
  4155                 return;
       
  4156             int cc  = QMAX(0, currentColumn() - 1);
       
  4157             while (cc >= 0) {
       
  4158                 Q3TableItem *i = item(currentRow(), cc);
       
  4159                 if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
       
  4160                     break;
       
  4161                 --cc;
       
  4162             }
       
  4163             setCurrentCell(currentRow(), cc);
       
  4164         }
       
  4165         return;
       
  4166     case Key_Escape:
       
  4167         e->ignore();
       
  4168         return;
       
  4169     default: // ... or start in-place editing
       
  4170         if (e->text()[ 0 ].isPrint()) {
       
  4171             Q3TableItem *itm = item(tmpRow, tmpCol);
       
  4172             if (!itm || itm->editType() == Q3TableItem::OnTyping) {
       
  4173                 QWidget *w = beginEdit(tmpRow, tmpCol,
       
  4174                                         itm ? itm->isReplaceable() : true);
       
  4175                 if (w) {
       
  4176                     setEditMode((!itm || (itm && itm->isReplaceable())
       
  4177                                    ? Replacing : Editing), tmpRow, tmpCol);
       
  4178                     QApplication::sendEvent(w, e);
       
  4179                     return;
       
  4180                 }
       
  4181             }
       
  4182         }
       
  4183         e->ignore();
       
  4184         return;
       
  4185     }
       
  4186 
       
  4187     if (navigationKey) {
       
  4188         fixCell(tmpRow, tmpCol, e->key());
       
  4189         if ((e->state() & ShiftButton) == ShiftButton &&
       
  4190              selMode != NoSelection && selMode != SingleRow) {
       
  4191             bool justCreated = false;
       
  4192             setCurrentCell(tmpRow, tmpCol, false, true);
       
  4193             if (!currentSel) {
       
  4194                 justCreated = true;
       
  4195                 currentSel = new Q3TableSelection();
       
  4196                 selections.append(currentSel);
       
  4197                 if (!isRowSelection(selectionMode()))
       
  4198                     currentSel->init(oldRow, oldCol);
       
  4199                 else
       
  4200                     currentSel->init(oldRow < 0 ? 0 : oldRow, 0);
       
  4201             }
       
  4202             Q3TableSelection oldSelection = *currentSel;
       
  4203             if (!isRowSelection(selectionMode()))
       
  4204                 currentSel->expandTo(tmpRow, tmpCol);
       
  4205             else
       
  4206                 currentSel->expandTo(tmpRow, numCols() - 1);
       
  4207             repaintSelections(justCreated ? 0 : &oldSelection, currentSel);
       
  4208             emit selectionChanged();
       
  4209         } else {
       
  4210             setCurrentCell(tmpRow, tmpCol, false, true);
       
  4211             if (!isRowSelection(selectionMode())) {
       
  4212                 clearSelection();
       
  4213             } else {
       
  4214                 bool currentInSelection = tmpRow == oldRow && isSelected(tmpRow, tmpCol, false);
       
  4215                 if (!currentInSelection) {
       
  4216                     bool hasOldSel = false;
       
  4217                     Q3TableSelection oldSelection;
       
  4218                     if (selectionMode() == MultiRow) {
       
  4219                         bool b = signalsBlocked();
       
  4220                         blockSignals(true);
       
  4221                         clearSelection();
       
  4222                         blockSignals(b);
       
  4223                     } else {
       
  4224                         if (currentSel) {
       
  4225                             oldSelection = *currentSel;
       
  4226                             hasOldSel = true;
       
  4227                             selections.removeRef(currentSel);
       
  4228                             leftHeader->setSectionState(oldSelection.topRow(), Q3TableHeader::Normal);
       
  4229                         }
       
  4230                     }
       
  4231                     currentSel = new Q3TableSelection();
       
  4232                     selections.append(currentSel);
       
  4233                     currentSel->init(tmpRow, 0);
       
  4234                     currentSel->expandTo(tmpRow, numCols() - 1);
       
  4235                     repaintSelections(hasOldSel ? &oldSelection : 0, currentSel, !hasOldSel);
       
  4236                     emit selectionChanged();
       
  4237                 }
       
  4238             }
       
  4239         }
       
  4240     } else {
       
  4241         setCurrentCell(tmpRow, tmpCol, false, true);
       
  4242     }
       
  4243 }
       
  4244 
       
  4245 /*! \reimp
       
  4246 */
       
  4247 
       
  4248 void Q3Table::focusInEvent(QFocusEvent*)
       
  4249 {
       
  4250     d->inMenuMode = false;
       
  4251     QWidget *editorWidget = cellWidget(editRow, editCol);
       
  4252     updateCell(curRow, curCol);
       
  4253     if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this))
       
  4254         repaintSelections();
       
  4255     if (isEditing() && editorWidget)
       
  4256         editorWidget->setFocus();
       
  4257 
       
  4258 }
       
  4259 
       
  4260 
       
  4261 /*! \reimp
       
  4262 */
       
  4263 
       
  4264 void Q3Table::focusOutEvent(QFocusEvent *e)
       
  4265 {
       
  4266     updateCell(curRow, curCol);
       
  4267     if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
       
  4268         d->inMenuMode =
       
  4269             e->reason() == Qt::PopupFocusReason ||
       
  4270             (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
       
  4271         if (!d->inMenuMode)
       
  4272             repaintSelections();
       
  4273     }
       
  4274 }
       
  4275 
       
  4276 /*! \reimp
       
  4277 */
       
  4278 
       
  4279 QSize Q3Table::sizeHint() const
       
  4280 {
       
  4281     if (cachedSizeHint().isValid())
       
  4282         return cachedSizeHint();
       
  4283 
       
  4284     constPolish();
       
  4285 
       
  4286     QSize s = tableSize();
       
  4287     QSize sh;
       
  4288     if (s.width() < 500 && s.height() < 500) {
       
  4289         sh = QSize(tableSize().width() + VERTICALMARGIN + 5,
       
  4290                     tableSize().height() + topMargin() + 5);
       
  4291     } else {
       
  4292             sh = Q3ScrollView::sizeHint();
       
  4293             if (!topHeader->isHidden())
       
  4294                 sh.setHeight(sh.height() + topHeader->height());
       
  4295             if (!leftHeader->isHidden())
       
  4296                 sh.setWidth(sh.width() + leftHeader->width());
       
  4297     }
       
  4298     setCachedSizeHint(sh);
       
  4299     return sh;
       
  4300 }
       
  4301 
       
  4302 /*! \reimp
       
  4303 */
       
  4304 
       
  4305 void Q3Table::viewportResizeEvent(QResizeEvent *e)
       
  4306 {
       
  4307     Q3ScrollView::viewportResizeEvent(e);
       
  4308     updateGeometries();
       
  4309 }
       
  4310 
       
  4311 /*! \reimp
       
  4312 */
       
  4313 
       
  4314 void Q3Table::showEvent(QShowEvent *e)
       
  4315 {
       
  4316     Q3ScrollView::showEvent(e);
       
  4317     QRect r(cellGeometry(numRows() - 1, numCols() - 1));
       
  4318     resizeContents(r.right() + 1, r.bottom() + 1);
       
  4319     updateGeometries();
       
  4320 }
       
  4321 
       
  4322 /*! \reimp
       
  4323 */
       
  4324 
       
  4325 void Q3Table::paintEvent(QPaintEvent *e)
       
  4326 {
       
  4327     QRect topLeftCorner = QStyle::visualRect(layoutDirection(), rect(), QRect(frameWidth(), frameWidth(), VERTICALMARGIN, topMargin()));
       
  4328     erase(topLeftCorner); // erase instead of widget on top
       
  4329     Q3ScrollView::paintEvent(e);
       
  4330 
       
  4331 #ifdef Q_OS_WINCE
       
  4332     QPainter p(this);
       
  4333     p.drawLine(topLeftCorner.bottomLeft(), topLeftCorner.bottomRight());
       
  4334     p.drawLine(topLeftCorner.bottomRight(), topLeftCorner.topRight());
       
  4335 #endif
       
  4336 }
       
  4337 
       
  4338 static bool inUpdateCell = false;
       
  4339 
       
  4340 /*!
       
  4341     Repaints the cell at \a row, \a col.
       
  4342 */
       
  4343 
       
  4344 void Q3Table::updateCell(int row, int col)
       
  4345 {
       
  4346     if (inUpdateCell || row < 0 || col < 0)
       
  4347         return;
       
  4348     inUpdateCell = true;
       
  4349     QRect cg = cellGeometry(row, col);
       
  4350     QRect r(contentsToViewport(QPoint(cg.x() - 2, cg.y() - 2)),
       
  4351              QSize(cg.width() + 4, cg.height() + 4));
       
  4352     viewport()->update(r);
       
  4353     inUpdateCell = false;
       
  4354 }
       
  4355 
       
  4356 void Q3Table::repaintCell(int row, int col)
       
  4357 {
       
  4358     if (row == -1 || col == -1)
       
  4359         return;
       
  4360     QRect cg = cellGeometry(row, col);
       
  4361     QRect r(QPoint(cg.x() - 2, cg.y() - 2),
       
  4362              QSize(cg.width() + 4, cg.height() + 4));
       
  4363     repaintContents(r, false);
       
  4364 }
       
  4365 
       
  4366 void Q3Table::contentsToViewport2(int x, int y, int& vx, int& vy)
       
  4367 {
       
  4368     const QPoint v = contentsToViewport2(QPoint(x, y));
       
  4369     vx = v.x();
       
  4370     vy = v.y();
       
  4371 }
       
  4372 
       
  4373 QPoint Q3Table::contentsToViewport2(const QPoint &p)
       
  4374 {
       
  4375     return QPoint(p.x() - contentsX(),
       
  4376                    p.y() - contentsY());
       
  4377 }
       
  4378 
       
  4379 QPoint Q3Table::viewportToContents2(const QPoint& vp)
       
  4380 {
       
  4381     return QPoint(vp.x() + contentsX(),
       
  4382                    vp.y() + contentsY());
       
  4383 }
       
  4384 
       
  4385 void Q3Table::viewportToContents2(int vx, int vy, int& x, int& y)
       
  4386 {
       
  4387     const QPoint c = viewportToContents2(QPoint(vx, vy));
       
  4388     x = c.x();
       
  4389     y = c.y();
       
  4390 }
       
  4391 
       
  4392 /*!
       
  4393     This function should be called whenever the column width of \a col
       
  4394     has been changed. It updates the geometry of any affected columns
       
  4395     and repaints the table to reflect the changes it has made.
       
  4396 */
       
  4397 
       
  4398 void Q3Table::columnWidthChanged(int col)
       
  4399 {
       
  4400     int p = columnPos(col);
       
  4401     if (d->hasColSpan)
       
  4402         p = contentsX();
       
  4403     updateContents(p, contentsY(), contentsWidth(), visibleHeight());
       
  4404     QSize s(tableSize());
       
  4405     int w = contentsWidth();
       
  4406     resizeContents(s.width(), s.height());
       
  4407     if (contentsWidth() < w)
       
  4408         repaintContents(s.width(), contentsY(),
       
  4409                          w - s.width() + 1, visibleHeight(), true);
       
  4410     else
       
  4411         repaintContents(w, contentsY(),
       
  4412                          s.width() - w + 1, visibleHeight(), false);
       
  4413 
       
  4414     // update widgets that are affected by this change
       
  4415     if (widgets.size()) {
       
  4416         int last = isHidden() ? numCols() - 1 : d->lastVisCol;
       
  4417         for (int c = col; c <= last; ++c)
       
  4418             updateColWidgets(c);
       
  4419     }
       
  4420     delayedUpdateGeometries();
       
  4421 }
       
  4422 
       
  4423 /*!
       
  4424     This function should be called whenever the row height of \a row
       
  4425     has been changed. It updates the geometry of any affected rows and
       
  4426     repaints the table to reflect the changes it has made.
       
  4427 */
       
  4428 
       
  4429 void Q3Table::rowHeightChanged(int row)
       
  4430 {
       
  4431     int p = rowPos(row);
       
  4432     if (d->hasRowSpan)
       
  4433         p = contentsY();
       
  4434     updateContents(contentsX(), p, visibleWidth(), contentsHeight());
       
  4435     QSize s(tableSize());
       
  4436     int h = contentsHeight();
       
  4437     resizeContents(s.width(), s.height());
       
  4438     if (contentsHeight() < h) {
       
  4439         repaintContents(contentsX(), contentsHeight(),
       
  4440                          visibleWidth(), h - s.height() + 1, true);
       
  4441     } else {
       
  4442         repaintContents(contentsX(), h,
       
  4443                          visibleWidth(), s.height() - h + 1, false);
       
  4444     }
       
  4445 
       
  4446     // update widgets that are affected by this change
       
  4447     if (widgets.size()) {
       
  4448         d->lastVisRow = rowAt(contentsY() + visibleHeight() + (s.height() - h + 1));
       
  4449         int last = isHidden() ? numRows() - 1 : d->lastVisRow;
       
  4450         for (int r = row; r <= last; ++r)
       
  4451             updateRowWidgets(r);
       
  4452     }
       
  4453     delayedUpdateGeometries();
       
  4454 }
       
  4455 
       
  4456 /*! \internal */
       
  4457 
       
  4458 void Q3Table::updateRowWidgets(int row)
       
  4459 {
       
  4460     for (int i = 0; i < numCols(); ++i) {
       
  4461         QWidget *w = cellWidget(row, i);
       
  4462         if (!w)
       
  4463             continue;
       
  4464         moveChild(w, columnPos(i), rowPos(row));
       
  4465         w->resize(columnWidth(i) - 1, rowHeight(row) - 1);
       
  4466     }
       
  4467 }
       
  4468 
       
  4469 /*! \internal */
       
  4470 
       
  4471 void Q3Table::updateColWidgets(int col)
       
  4472 {
       
  4473     for (int i = 0; i < numRows(); ++i) {
       
  4474         QWidget *w = cellWidget(i, col);
       
  4475         if (!w)
       
  4476             continue;
       
  4477         moveChild(w, columnPos(col), rowPos(i));
       
  4478         w->resize(columnWidth(col) - 1, rowHeight(i) - 1);
       
  4479     }
       
  4480 }
       
  4481 
       
  4482 /*!
       
  4483     This function is called when column order is to be changed, i.e.
       
  4484     when the user moved the column header \a section from \a fromIndex
       
  4485     to \a toIndex.
       
  4486 
       
  4487     If you want to change the column order programmatically, call
       
  4488     swapRows() or swapColumns();
       
  4489 
       
  4490     \sa Q3Header::indexChange() rowIndexChanged()
       
  4491 */
       
  4492 
       
  4493 void Q3Table::columnIndexChanged(int, int fromIndex, int toIndex)
       
  4494 {
       
  4495     if (doSort && lastSortCol == fromIndex && topHeader)
       
  4496         topHeader->setSortIndicator(toIndex, topHeader->sortIndicatorOrder());
       
  4497     repaintContents(contentsX(), contentsY(),
       
  4498                      visibleWidth(), visibleHeight(), false);
       
  4499 }
       
  4500 
       
  4501 /*!
       
  4502     This function is called when the order of the rows is to be
       
  4503     changed, i.e. the user moved the row header section \a section
       
  4504     from \a fromIndex to \a toIndex.
       
  4505 
       
  4506     If you want to change the order programmatically, call swapRows()
       
  4507     or swapColumns();
       
  4508 
       
  4509     \sa Q3Header::indexChange() columnIndexChanged()
       
  4510 */
       
  4511 
       
  4512 void Q3Table::rowIndexChanged(int, int, int)
       
  4513 {
       
  4514     repaintContents(contentsX(), contentsY(),
       
  4515                      visibleWidth(), visibleHeight(), false);
       
  4516 }
       
  4517 
       
  4518 /*!
       
  4519     This function is called when the column \a col has been clicked.
       
  4520     The default implementation sorts this column if sorting() is true.
       
  4521 */
       
  4522 
       
  4523 void Q3Table::columnClicked(int col)
       
  4524 {
       
  4525     if (!sorting())
       
  4526         return;
       
  4527 
       
  4528     if (col == lastSortCol) {
       
  4529         asc = !asc;
       
  4530     } else {
       
  4531         lastSortCol = col;
       
  4532         asc = true;
       
  4533     }
       
  4534     sortColumn(lastSortCol, asc);
       
  4535 }
       
  4536 
       
  4537 /*!
       
  4538     \property Q3Table::sorting
       
  4539     \brief whether a click on the header of a column sorts that column
       
  4540 
       
  4541     \sa sortColumn()
       
  4542 */
       
  4543 
       
  4544 void Q3Table::setSorting(bool b)
       
  4545 {
       
  4546     doSort = b;
       
  4547     if (topHeader)
       
  4548          topHeader->setSortIndicator(b ? lastSortCol : -1);
       
  4549 }
       
  4550 
       
  4551 bool Q3Table::sorting() const
       
  4552 {
       
  4553     return doSort;
       
  4554 }
       
  4555 
       
  4556 static bool inUpdateGeometries = false;
       
  4557 
       
  4558 void Q3Table::delayedUpdateGeometries()
       
  4559 {
       
  4560     d->geomTimer->start(0, true);
       
  4561 }
       
  4562 
       
  4563 void Q3Table::updateGeometriesSlot()
       
  4564 {
       
  4565     updateGeometries();
       
  4566 }
       
  4567 
       
  4568 /*!
       
  4569     This function updates the geometries of the left and top header.
       
  4570     You do not normally need to call this function.
       
  4571 */
       
  4572 
       
  4573 void Q3Table::updateGeometries()
       
  4574 {
       
  4575     if (inUpdateGeometries)
       
  4576         return;
       
  4577     inUpdateGeometries = true;
       
  4578     QSize ts = tableSize();
       
  4579     if (topHeader->offset() &&
       
  4580          ts.width() < topHeader->offset() + topHeader->width())
       
  4581         horizontalScrollBar()->setValue(ts.width() - topHeader->width());
       
  4582     if (leftHeader->offset() &&
       
  4583          ts.height() < leftHeader->offset() + leftHeader->height())
       
  4584         verticalScrollBar()->setValue(ts.height() - leftHeader->height());
       
  4585 
       
  4586     leftHeader->setGeometry(QStyle::visualRect(layoutDirection(), rect(), QRect(frameWidth(), topMargin() + frameWidth(),
       
  4587                              VERTICALMARGIN, visibleHeight())));
       
  4588     topHeader->setGeometry(QStyle::visualRect(layoutDirection(), rect(), QRect(VERTICALMARGIN + frameWidth(), frameWidth(),
       
  4589                                                       visibleWidth(), topMargin())));
       
  4590     horizontalScrollBar()->raise();
       
  4591     verticalScrollBar()->raise();
       
  4592     topHeader->updateStretches();
       
  4593     leftHeader->updateStretches();
       
  4594     inUpdateGeometries = false;
       
  4595 }
       
  4596 
       
  4597 /*!
       
  4598     Returns the width of column \a col.
       
  4599 
       
  4600     \sa setColumnWidth() rowHeight()
       
  4601 */
       
  4602 
       
  4603 int Q3Table::columnWidth(int col) const
       
  4604 {
       
  4605     return topHeader->sectionSize(col);
       
  4606 }
       
  4607 
       
  4608 /*!
       
  4609     Returns the height of row \a row.
       
  4610 
       
  4611     \sa setRowHeight() columnWidth()
       
  4612 */
       
  4613 
       
  4614 int Q3Table::rowHeight(int row) const
       
  4615 {
       
  4616     return leftHeader->sectionSize(row);
       
  4617 }
       
  4618 
       
  4619 /*!
       
  4620     Returns the x-coordinate of the column \a col in content
       
  4621     coordinates.
       
  4622 
       
  4623     \sa columnAt() rowPos()
       
  4624 */
       
  4625 
       
  4626 int Q3Table::columnPos(int col) const
       
  4627 {
       
  4628     return topHeader->sectionPos(col);
       
  4629 }
       
  4630 
       
  4631 /*!
       
  4632     Returns the y-coordinate of the row \a row in content coordinates.
       
  4633 
       
  4634     \sa rowAt() columnPos()
       
  4635 */
       
  4636 
       
  4637 int Q3Table::rowPos(int row) const
       
  4638 {
       
  4639     return leftHeader->sectionPos(row);
       
  4640 }
       
  4641 
       
  4642 /*!
       
  4643     Returns the number of the column at position \a x. \a x must be
       
  4644     given in content coordinates.
       
  4645 
       
  4646     \sa columnPos() rowAt()
       
  4647 */
       
  4648 
       
  4649 int Q3Table::columnAt(int x) const
       
  4650 {
       
  4651     return topHeader->sectionAt(x);
       
  4652 }
       
  4653 
       
  4654 /*!
       
  4655     Returns the number of the row at position \a y. \a y must be given
       
  4656     in content coordinates.
       
  4657 
       
  4658     \sa rowPos() columnAt()
       
  4659 */
       
  4660 
       
  4661 int Q3Table::rowAt(int y) const
       
  4662 {
       
  4663     return leftHeader->sectionAt(y);
       
  4664 }
       
  4665 
       
  4666 /*!
       
  4667     Returns the bounding rectangle of the cell at \a row, \a col in
       
  4668     content coordinates.
       
  4669 */
       
  4670 
       
  4671 QRect Q3Table::cellGeometry(int row, int col) const
       
  4672 {
       
  4673     Q3TableItem *itm = item(row, col);
       
  4674 
       
  4675     if (!itm || (itm->rowSpan() == 1 && itm->colSpan() == 1))
       
  4676         return QRect(columnPos(col), rowPos(row),
       
  4677                       columnWidth(col), rowHeight(row));
       
  4678 
       
  4679     while (row != itm->row())
       
  4680         row--;
       
  4681     while (col != itm->col())
       
  4682         col--;
       
  4683 
       
  4684     QRect rect(columnPos(col), rowPos(row),
       
  4685                 columnWidth(col), rowHeight(row));
       
  4686 
       
  4687     for (int r = 1; r < itm->rowSpan(); ++r)
       
  4688         rect.setHeight(rect.height() + rowHeight(r + row));
       
  4689 
       
  4690     for (int c = 1; c < itm->colSpan(); ++c)
       
  4691         rect.setWidth(rect.width() + columnWidth(c + col));
       
  4692 
       
  4693     return rect;
       
  4694 }
       
  4695 
       
  4696 /*!
       
  4697     Returns the size of the table.
       
  4698 
       
  4699     This is the same as the coordinates of the bottom-right edge of
       
  4700     the last table cell.
       
  4701 */
       
  4702 
       
  4703 QSize Q3Table::tableSize() const
       
  4704 {
       
  4705     return QSize(columnPos(numCols() - 1) + columnWidth(numCols() - 1),
       
  4706                   rowPos(numRows() - 1) + rowHeight(numRows() - 1));
       
  4707 }
       
  4708 
       
  4709 /*!
       
  4710     \property Q3Table::numRows
       
  4711     \brief The number of rows in the table
       
  4712 
       
  4713     \sa numCols
       
  4714 */
       
  4715 
       
  4716 int Q3Table::numRows() const
       
  4717 {
       
  4718     return leftHeader->count();
       
  4719 }
       
  4720 
       
  4721 /*!
       
  4722     \property Q3Table::numCols
       
  4723     \brief The number of columns in the table
       
  4724 
       
  4725     \sa numRows
       
  4726 */
       
  4727 
       
  4728 int Q3Table::numCols() const
       
  4729 {
       
  4730     return topHeader->count();
       
  4731 }
       
  4732 
       
  4733 void Q3Table::saveContents(Q3PtrVector<Q3TableItem> &tmp,
       
  4734                            Q3PtrVector<Q3Table::TableWidget> &tmp2)
       
  4735 {
       
  4736     int nCols = numCols();
       
  4737     if (editRow != -1 && editCol != -1)
       
  4738         endEdit(editRow, editCol, false, edMode != Editing);
       
  4739     tmp.resize(contents.size());
       
  4740     tmp2.resize(widgets.size());
       
  4741     int i;
       
  4742     for (i = 0; i < (int)tmp.size(); ++i) {
       
  4743         Q3TableItem *item = contents[ i ];
       
  4744         if (item && (item->row() * nCols) + item->col() == i)
       
  4745             tmp.insert(i, item);
       
  4746         else
       
  4747             tmp.insert(i, 0);
       
  4748     }
       
  4749     for (i = 0; i < (int)tmp2.size(); ++i) {
       
  4750         QWidget *w = widgets[ i ];
       
  4751         if (w)
       
  4752             tmp2.insert(i, new TableWidget(w, i / nCols, i % nCols));
       
  4753         else
       
  4754             tmp2.insert(i, 0);
       
  4755     }
       
  4756 }
       
  4757 
       
  4758 void Q3Table::updateHeaderAndResizeContents(Q3TableHeader *header,
       
  4759                                             int num, int rowCol,
       
  4760                                             int width, bool &updateBefore)
       
  4761 {
       
  4762     updateBefore = rowCol < num;
       
  4763     if (rowCol > num) {
       
  4764         header->Q3Header::resizeArrays(rowCol);
       
  4765         header->Q3TableHeader::resizeArrays(rowCol);
       
  4766         int old = num;
       
  4767         clearSelection(false);
       
  4768         int i = 0;
       
  4769         for (i = old; i < rowCol; ++i)
       
  4770             header->addLabel(QString(), width);
       
  4771     } else {
       
  4772         clearSelection(false);
       
  4773         if (header == leftHeader) {
       
  4774             while (numRows() > rowCol)
       
  4775                 header->removeLabel(numRows() - 1);
       
  4776         } else {
       
  4777             while (numCols() > rowCol)
       
  4778                 header->removeLabel(numCols() - 1);
       
  4779         }
       
  4780     }
       
  4781 
       
  4782     contents.setAutoDelete(false);
       
  4783     contents.clear();
       
  4784     contents.setAutoDelete(true);
       
  4785     widgets.setAutoDelete(false);
       
  4786     widgets.clear();
       
  4787     widgets.setAutoDelete(true);
       
  4788     resizeData(numRows() * numCols());
       
  4789 
       
  4790     // keep numStretches in sync
       
  4791     int n = 0;
       
  4792     for (uint i = 0; i < header->stretchable.size(); i++)
       
  4793         n += (header->stretchable.at(i) & 1); // avoid cmp
       
  4794      header->numStretches = n;
       
  4795 }
       
  4796 
       
  4797 void Q3Table::restoreContents(Q3PtrVector<Q3TableItem> &tmp,
       
  4798                               Q3PtrVector<Q3Table::TableWidget> &tmp2)
       
  4799 {
       
  4800     int i;
       
  4801     int nCols = numCols();
       
  4802     for (i = 0; i < (int)tmp.size(); ++i) {
       
  4803         Q3TableItem *it = tmp[ i ];
       
  4804         if (it) {
       
  4805             int idx = (it->row() * nCols) + it->col();
       
  4806             if ((uint)idx < contents.size() &&
       
  4807                  it->row() == idx /  nCols && it->col() == idx % nCols) {
       
  4808                 contents.insert(idx, it);
       
  4809                 if (it->rowSpan() > 1 || it->colSpan() > 1) {
       
  4810                     int ridx, iidx;
       
  4811                     for (int irow = 0; irow < it->rowSpan(); irow++) {
       
  4812                         ridx = idx + irow * nCols;
       
  4813                         for (int icol = 0; icol < it->colSpan(); icol++) {
       
  4814                             iidx = ridx + icol;
       
  4815                             if (idx != iidx && (uint)iidx < contents.size())
       
  4816                                 contents.insert(iidx, it);
       
  4817                         }
       
  4818                     }
       
  4819 
       
  4820                 }
       
  4821             } else {
       
  4822                 delete it;
       
  4823             }
       
  4824         }
       
  4825     }
       
  4826     for (i = 0; i < (int)tmp2.size(); ++i) {
       
  4827         TableWidget *w = tmp2[ i ];
       
  4828         if (w) {
       
  4829             int idx = (w->row * nCols) + w->col;
       
  4830             if ((uint)idx < widgets.size() &&
       
  4831                  w->row == idx / nCols && w->col == idx % nCols)
       
  4832                 widgets.insert(idx, w->wid);
       
  4833             else
       
  4834                 delete w->wid;
       
  4835             delete w;
       
  4836         }
       
  4837     }
       
  4838 }
       
  4839 
       
  4840 void Q3Table::finishContentsResze(bool updateBefore)
       
  4841 {
       
  4842     QRect r(cellGeometry(numRows() - 1, numCols() - 1));
       
  4843     resizeContents(r.right() + 1, r.bottom() + 1);
       
  4844     updateGeometries();
       
  4845     if (updateBefore)
       
  4846         repaintContents(contentsX(), contentsY(),
       
  4847                          visibleWidth(), visibleHeight(), true);
       
  4848     else
       
  4849         repaintContents(contentsX(), contentsY(),
       
  4850                          visibleWidth(), visibleHeight(), false);
       
  4851 
       
  4852     if (isRowSelection(selectionMode())) {
       
  4853         int r = curRow;
       
  4854         curRow = -1;
       
  4855         setCurrentCell(r, curCol);
       
  4856     }
       
  4857 }
       
  4858 
       
  4859 void Q3Table::setNumRows(int r)
       
  4860 {
       
  4861     if (r < 0)
       
  4862         return;
       
  4863 
       
  4864     if (r < numRows()) {
       
  4865         // Removed rows are no longer hidden, and should thus be removed from "hiddenRows"
       
  4866         for (int rr = numRows()-1; rr >= r; --rr) {
       
  4867             if (d->hiddenRows.find(rr))
       
  4868                 d->hiddenRows.remove(rr);
       
  4869         }
       
  4870     }
       
  4871 
       
  4872     fontChange(font()); // invalidate the sizeHintCache
       
  4873 
       
  4874     Q3PtrVector<Q3TableItem> tmp;
       
  4875     Q3PtrVector<TableWidget> tmp2;
       
  4876     saveContents(tmp, tmp2);
       
  4877 
       
  4878     bool updatesEnabled = leftHeader->updatesEnabled();
       
  4879     if (updatesEnabled)
       
  4880         leftHeader->setUpdatesEnabled(false);
       
  4881 
       
  4882     bool updateBefore;
       
  4883     updateHeaderAndResizeContents(leftHeader, numRows(), r, 20, updateBefore);
       
  4884 
       
  4885     int w = fontMetrics().width(QString::number(r) + QLatin1Char('W'));
       
  4886     if (VERTICALMARGIN > 0 && w > VERTICALMARGIN)
       
  4887         setLeftMargin(w);
       
  4888 
       
  4889     restoreContents(tmp, tmp2);
       
  4890 
       
  4891     leftHeader->calculatePositions();
       
  4892     finishContentsResze(updateBefore);
       
  4893     if (updatesEnabled) {
       
  4894         leftHeader->setUpdatesEnabled(true);
       
  4895         leftHeader->update();
       
  4896     }
       
  4897     leftHeader->updateCache();
       
  4898     if (curRow >= numRows()) {
       
  4899         curRow = numRows() - 1;
       
  4900         if (curRow < 0)
       
  4901             curCol = -1;
       
  4902         else
       
  4903             repaintCell(curRow, curCol);
       
  4904     }
       
  4905 
       
  4906     if (curRow > numRows())
       
  4907         curRow = numRows();
       
  4908 }
       
  4909 
       
  4910 void Q3Table::setNumCols(int c)
       
  4911 {
       
  4912     if (c < 0)
       
  4913         return;
       
  4914 
       
  4915     if (c < numCols()) {
       
  4916         // Removed columns are no longer hidden, and should thus be removed from "hiddenCols"
       
  4917         for (int cc = numCols()-1; cc >= c; --cc) {
       
  4918             if (d->hiddenCols.find(cc))
       
  4919                 d->hiddenCols.remove(cc);
       
  4920         }
       
  4921     }
       
  4922 
       
  4923     fontChange(font()); // invalidate the sizeHintCache
       
  4924 
       
  4925     Q3PtrVector<Q3TableItem> tmp;
       
  4926     Q3PtrVector<TableWidget> tmp2;
       
  4927     saveContents(tmp, tmp2);
       
  4928 
       
  4929     bool updatesEnabled = topHeader->updatesEnabled();
       
  4930     if (updatesEnabled)
       
  4931         topHeader->setUpdatesEnabled(false);
       
  4932 
       
  4933     bool updateBefore;
       
  4934     updateHeaderAndResizeContents(topHeader, numCols(), c, 100, updateBefore);
       
  4935 
       
  4936     restoreContents(tmp, tmp2);
       
  4937 
       
  4938     topHeader->calculatePositions();
       
  4939     finishContentsResze(updateBefore);
       
  4940     if (updatesEnabled) {
       
  4941         topHeader->setUpdatesEnabled(true);
       
  4942         topHeader->update();
       
  4943     }
       
  4944     topHeader->updateCache();
       
  4945     if (curCol >= numCols()) {
       
  4946         curCol = numCols() - 1;
       
  4947         if (curCol < 0)
       
  4948             curRow = -1;
       
  4949         else
       
  4950             repaintCell(curRow, curCol);
       
  4951     }
       
  4952 }
       
  4953 
       
  4954 /*! Sets the section labels of the verticalHeader() to \a labels */
       
  4955 
       
  4956 void Q3Table::setRowLabels(const QStringList &labels)
       
  4957 {
       
  4958     leftHeader->setLabels(labels);
       
  4959 }
       
  4960 
       
  4961 /*! Sets the section labels of the horizontalHeader() to \a labels */
       
  4962 
       
  4963 void Q3Table::setColumnLabels(const QStringList &labels)
       
  4964 {
       
  4965    topHeader->setLabels(labels);
       
  4966 }
       
  4967 
       
  4968 /*!
       
  4969     This function returns the widget which should be used as an editor
       
  4970     for the contents of the cell at \a row, \a col.
       
  4971 
       
  4972     If \a initFromCell is true, the editor is used to edit the current
       
  4973     contents of the cell (so the editor widget should be initialized
       
  4974     with this content). If \a initFromCell is false, the content of
       
  4975     the cell is replaced with the new content which the user entered
       
  4976     into the widget created by this function.
       
  4977 
       
  4978     The default functionality is as follows: if \a initFromCell is
       
  4979     true or the cell has a Q3TableItem and the table item's
       
  4980     Q3TableItem::isReplaceable() is false then the cell is asked to
       
  4981     create an appropriate editor (using Q3TableItem::createEditor()).
       
  4982     Otherwise a QLineEdit is used as the editor.
       
  4983 
       
  4984     If you want to create your own editor for certain cells, implement
       
  4985     a custom Q3TableItem subclass and reimplement
       
  4986     Q3TableItem::createEditor().
       
  4987 
       
  4988     If you are not using \l{Q3TableItem}s and you don't want to use a
       
  4989     QLineEdit as the default editor, subclass Q3Table and reimplement
       
  4990     this function with code like this:
       
  4991     \snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 5
       
  4992     Ownership of the editor widget is transferred to the caller.
       
  4993 
       
  4994     If you reimplement this function return 0 for read-only cells. You
       
  4995     will need to reimplement setCellContentFromEditor() to retrieve
       
  4996     the data the user entered.
       
  4997 
       
  4998     \sa Q3TableItem::createEditor()
       
  4999 */
       
  5000 
       
  5001 QWidget *Q3Table::createEditor(int row, int col, bool initFromCell) const
       
  5002 {
       
  5003     if (isReadOnly() || isRowReadOnly(row) || isColumnReadOnly(col))
       
  5004         return 0;
       
  5005 
       
  5006     QWidget *e = 0;
       
  5007 
       
  5008     // the current item in the cell should be edited if possible
       
  5009     Q3TableItem *i = item(row, col);
       
  5010     if (initFromCell || (i && !i->isReplaceable())) {
       
  5011         if (i) {
       
  5012             if (i->editType() == Q3TableItem::Never)
       
  5013                 return 0;
       
  5014 
       
  5015             e = i->createEditor();
       
  5016             if (!e)
       
  5017                 return 0;
       
  5018         }
       
  5019     }
       
  5020 
       
  5021     // no contents in the cell yet, so open the default editor
       
  5022     if (!e) {
       
  5023         e = new QLineEdit(viewport(), "qt_lineeditor");
       
  5024         ((QLineEdit*)e)->setFrame(false);
       
  5025     }
       
  5026 
       
  5027     return e;
       
  5028 }
       
  5029 
       
  5030 /*!
       
  5031     This function is called to start in-place editing of the cell at
       
  5032     \a row, \a col. Editing is achieved by creating an editor
       
  5033     (createEditor() is called) and setting the cell's editor with
       
  5034     setCellWidget() to the newly created editor. (After editing is
       
  5035     complete endEdit() will be called to replace the cell's content
       
  5036     with the editor's content.) If \a replace is true the editor will
       
  5037     start empty; otherwise it will be initialized with the cell's
       
  5038     content (if any), i.e. the user will be modifying the original
       
  5039     cell content.
       
  5040 
       
  5041     \sa endEdit()
       
  5042 */
       
  5043 
       
  5044 QWidget *Q3Table::beginEdit(int row, int col, bool replace)
       
  5045 {
       
  5046     if (isReadOnly() || isRowReadOnly(row) || isColumnReadOnly(col))
       
  5047         return 0;
       
  5048     if ( row < 0 || row >= numRows() || col < 0 || col >= numCols() )
       
  5049         return 0;
       
  5050     Q3TableItem *itm = item(row, col);
       
  5051     if (itm && !itm->isEnabled())
       
  5052         return 0;
       
  5053     if (cellWidget(row, col))
       
  5054         return 0;
       
  5055     ensureCellVisible(row, col);
       
  5056     QWidget *e = createEditor(row, col, !replace);
       
  5057     if (!e)
       
  5058         return 0;
       
  5059     setCellWidget(row, col, e);
       
  5060     e->setActiveWindow();
       
  5061     e->setFocus();
       
  5062     updateCell(row, col);
       
  5063     return e;
       
  5064 }
       
  5065 
       
  5066 /*!
       
  5067     This function is called when in-place editing of the cell at \a
       
  5068     row, \a col is requested to stop.
       
  5069 
       
  5070     If the cell is not being edited or \a accept is false the function
       
  5071     returns and the cell's contents are left unchanged.
       
  5072 
       
  5073     If \a accept is true the content of the editor must be transferred
       
  5074     to the relevant cell. If \a replace is true the current content of
       
  5075     this cell should be replaced by the content of the editor (this
       
  5076     means removing the current Q3TableItem of the cell and creating a
       
  5077     new one for the cell). Otherwise (if possible) the content of the
       
  5078     editor should just be set to the existing Q3TableItem of this cell.
       
  5079 
       
  5080     setCellContentFromEditor() is called to replace the contents of
       
  5081     the cell with the contents of the cell's editor.
       
  5082 
       
  5083     Finally clearCellWidget() is called to remove the editor widget.
       
  5084 
       
  5085     \sa setCellContentFromEditor(), beginEdit()
       
  5086 */
       
  5087 
       
  5088 void Q3Table::endEdit(int row, int col, bool accept, bool replace)
       
  5089 {
       
  5090     QWidget *editor = cellWidget(row, col);
       
  5091     if (!editor)
       
  5092         return;
       
  5093 
       
  5094     if (!accept) {
       
  5095         if (row == editRow && col == editCol)
       
  5096             setEditMode(NotEditing, -1, -1);
       
  5097         clearCellWidget(row, col);
       
  5098         updateCell(row, col);
       
  5099         viewport()->setFocus();
       
  5100         updateCell(row, col);
       
  5101         return;
       
  5102     }
       
  5103 
       
  5104     Q3TableItem *i = item(row, col);
       
  5105     QString oldContent;
       
  5106     if (i)
       
  5107         oldContent = i->text();
       
  5108 
       
  5109     if (!i || replace) {
       
  5110         setCellContentFromEditor(row, col);
       
  5111         i = item(row, col);
       
  5112     } else {
       
  5113         i->setContentFromEditor(editor);
       
  5114     }
       
  5115 
       
  5116     if (row == editRow && col == editCol)
       
  5117         setEditMode(NotEditing, -1, -1);
       
  5118 
       
  5119     viewport()->setFocus();
       
  5120     updateCell(row, col);
       
  5121 
       
  5122     if (!i || (oldContent != i->text()))
       
  5123         emit valueChanged(row, col);
       
  5124 
       
  5125     clearCellWidget(row, col);
       
  5126 }
       
  5127 
       
  5128 /*!
       
  5129     This function is called to replace the contents of the cell at \a
       
  5130     row, \a col with the contents of the cell's editor.
       
  5131 
       
  5132     If there already exists a Q3TableItem for the cell,
       
  5133     it calls Q3TableItem::setContentFromEditor() on this Q3TableItem.
       
  5134 
       
  5135     If, for example, you want to create different \l{Q3TableItem}s
       
  5136     depending on the contents of the editor, you might reimplement
       
  5137     this function.
       
  5138 
       
  5139     If you want to work without \l{Q3TableItem}s, you will need to
       
  5140     reimplement this function to save the data the user entered into
       
  5141     your data structure. (See the notes on large tables.)
       
  5142 
       
  5143     \sa Q3TableItem::setContentFromEditor() createEditor()
       
  5144 */
       
  5145 
       
  5146 void Q3Table::setCellContentFromEditor(int row, int col)
       
  5147 {
       
  5148     QWidget *editor = cellWidget(row, col);
       
  5149     if (!editor)
       
  5150         return;
       
  5151 
       
  5152     Q3TableItem *i = item(row, col);
       
  5153     if (i) {
       
  5154         i->setContentFromEditor(editor);
       
  5155     } else {
       
  5156         QLineEdit *le = qobject_cast<QLineEdit*>(editor);
       
  5157         if (le)
       
  5158             setText(row, col, le->text());
       
  5159     }
       
  5160 }
       
  5161 
       
  5162 /*!
       
  5163     Returns true if the \l EditMode is \c Editing or \c Replacing;
       
  5164     otherwise (i.e. the \l EditMode is \c NotEditing) returns false.
       
  5165 
       
  5166     \sa Q3Table::EditMode
       
  5167 */
       
  5168 
       
  5169 bool Q3Table::isEditing() const
       
  5170 {
       
  5171     return edMode != NotEditing;
       
  5172 }
       
  5173 
       
  5174 /*!
       
  5175     Returns the current edit mode
       
  5176 
       
  5177     \sa Q3Table::EditMode
       
  5178 */
       
  5179 
       
  5180 Q3Table::EditMode Q3Table::editMode() const
       
  5181 {
       
  5182     return edMode;
       
  5183 }
       
  5184 
       
  5185 /*!
       
  5186     Returns the current edited row
       
  5187 */
       
  5188 
       
  5189 int Q3Table::currEditRow() const
       
  5190 {
       
  5191     return editRow;
       
  5192 }
       
  5193 
       
  5194 /*!
       
  5195     Returns the current edited column
       
  5196 */
       
  5197 
       
  5198 int Q3Table::currEditCol() const
       
  5199 {
       
  5200     return editCol;
       
  5201 }
       
  5202 
       
  5203 /*!
       
  5204     Returns a single integer which identifies a particular \a row and \a
       
  5205     col by mapping the 2D table to a 1D array.
       
  5206 
       
  5207     This is useful, for example, if you have a sparse table and want to
       
  5208     use a Q3IntDict to map integers to the cells that are used.
       
  5209 */
       
  5210 
       
  5211 int Q3Table::indexOf(int row, int col) const
       
  5212 {
       
  5213     return (row * numCols()) + col;
       
  5214 }
       
  5215 
       
  5216 /*! \internal
       
  5217 */
       
  5218 
       
  5219 void Q3Table::repaintSelections(Q3TableSelection *oldSelection,
       
  5220                                 Q3TableSelection *newSelection,
       
  5221                                 bool updateVertical, bool updateHorizontal)
       
  5222 {
       
  5223     if (!oldSelection && !newSelection)
       
  5224         return;
       
  5225     if (oldSelection && newSelection && *oldSelection == *newSelection)
       
  5226         return;
       
  5227     if (oldSelection && !oldSelection->isActive())
       
  5228          oldSelection = 0;
       
  5229 
       
  5230     bool optimizeOld = false;
       
  5231     bool optimizeNew = false;
       
  5232 
       
  5233     QRect old;
       
  5234     if (oldSelection)
       
  5235         old = rangeGeometry(oldSelection->topRow(),
       
  5236                              oldSelection->leftCol(),
       
  5237                              oldSelection->bottomRow(),
       
  5238                              oldSelection->rightCol(),
       
  5239                              optimizeOld);
       
  5240     else
       
  5241         old = QRect(0, 0, 0, 0);
       
  5242 
       
  5243     QRect cur;
       
  5244     if (newSelection)
       
  5245         cur = rangeGeometry(newSelection->topRow(),
       
  5246                              newSelection->leftCol(),
       
  5247                              newSelection->bottomRow(),
       
  5248                              newSelection->rightCol(),
       
  5249                              optimizeNew);
       
  5250     else
       
  5251         cur = QRect(0, 0, 0, 0);
       
  5252     int i;
       
  5253 
       
  5254     if (!optimizeOld || !optimizeNew ||
       
  5255          old.width() > SHRT_MAX || old.height() > SHRT_MAX ||
       
  5256          cur.width() > SHRT_MAX || cur.height() > SHRT_MAX) {
       
  5257         QRect rr = cur.united(old);
       
  5258         repaintContents(rr, false);
       
  5259     } else {
       
  5260         old = QRect(contentsToViewport2(old.topLeft()), old.size());
       
  5261         cur = QRect(contentsToViewport2(cur.topLeft()), cur.size());
       
  5262         QRegion r1(old);
       
  5263         QRegion r2(cur);
       
  5264         QRegion r3 = r1.subtracted(r2);
       
  5265         QRegion r4 = r2.subtracted(r1);
       
  5266 
       
  5267         for (i = 0; i < (int)r3.rects().count(); ++i) {
       
  5268             QRect r(r3.rects()[ i ]);
       
  5269             r = QRect(viewportToContents2(r.topLeft()), r.size());
       
  5270             repaintContents(r, false);
       
  5271         }
       
  5272         for (i = 0; i < (int)r4.rects().count(); ++i) {
       
  5273             QRect r(r4.rects()[ i ]);
       
  5274             r = QRect(viewportToContents2(r.topLeft()), r.size());
       
  5275             repaintContents(r, false);
       
  5276         }
       
  5277     }
       
  5278 
       
  5279     int top, left, bottom, right;
       
  5280     {
       
  5281         int oldTopRow = oldSelection ? oldSelection->topRow() : numRows() - 1;
       
  5282         int newTopRow = newSelection ? newSelection->topRow() : numRows() - 1;
       
  5283         top = QMIN(oldTopRow, newTopRow);
       
  5284     }
       
  5285 
       
  5286     {
       
  5287         int oldLeftCol = oldSelection ? oldSelection->leftCol() : numCols() - 1;
       
  5288         int newLeftCol = newSelection ? newSelection->leftCol() : numCols() - 1;
       
  5289         left = QMIN(oldLeftCol, newLeftCol);
       
  5290     }
       
  5291 
       
  5292     {
       
  5293         int oldBottomRow = oldSelection ? oldSelection->bottomRow() : 0;
       
  5294         int newBottomRow = newSelection ? newSelection->bottomRow() : 0;
       
  5295         bottom = QMAX(oldBottomRow, newBottomRow);
       
  5296     }
       
  5297 
       
  5298     {
       
  5299         int oldRightCol = oldSelection ? oldSelection->rightCol() : 0;
       
  5300         int newRightCol = newSelection ? newSelection->rightCol() : 0;
       
  5301         right = QMAX(oldRightCol, newRightCol);
       
  5302     }
       
  5303 
       
  5304     if (updateHorizontal && numCols() > 0 && left >= 0 && !isRowSelection(selectionMode())) {
       
  5305         register int *s = &topHeader->states.data()[left];
       
  5306         for (i = left; i <= right; ++i) {
       
  5307             if (!isColumnSelected(i))
       
  5308                 *s = Q3TableHeader::Normal;
       
  5309             else if (isColumnSelected(i, true))
       
  5310                 *s = Q3TableHeader::Selected;
       
  5311             else
       
  5312                 *s = Q3TableHeader::Bold;
       
  5313             ++s;
       
  5314         }
       
  5315         topHeader->repaint(false);
       
  5316     }
       
  5317 
       
  5318     if (updateVertical && numRows() > 0 && top >= 0) {
       
  5319         register int *s = &leftHeader->states.data()[top];
       
  5320         for (i = top; i <= bottom; ++i) {
       
  5321             if (!isRowSelected(i))
       
  5322                 *s = Q3TableHeader::Normal;
       
  5323             else if (isRowSelected(i, true))
       
  5324                 *s = Q3TableHeader::Selected;
       
  5325             else
       
  5326                 *s = Q3TableHeader::Bold;
       
  5327             ++s;
       
  5328         }
       
  5329         leftHeader->repaint(false);
       
  5330     }
       
  5331 }
       
  5332 
       
  5333 /*!
       
  5334     Repaints all selections
       
  5335 */
       
  5336 
       
  5337 void Q3Table::repaintSelections()
       
  5338 {
       
  5339     if (selections.isEmpty())
       
  5340         return;
       
  5341 
       
  5342     QRect r;
       
  5343     for (Q3TableSelection *s = selections.first(); s; s = selections.next()) {
       
  5344         bool b;
       
  5345         r = r.united(rangeGeometry(s->topRow(),
       
  5346                                     s->leftCol(),
       
  5347                                     s->bottomRow(),
       
  5348                                     s->rightCol(), b));
       
  5349     }
       
  5350 
       
  5351     repaintContents(r, false);
       
  5352 }
       
  5353 
       
  5354 /*!
       
  5355     Clears all selections and repaints the appropriate regions if \a
       
  5356     repaint is true.
       
  5357 
       
  5358     \sa removeSelection()
       
  5359 */
       
  5360 
       
  5361 void Q3Table::clearSelection(bool repaint)
       
  5362 {
       
  5363     if (selections.isEmpty())
       
  5364         return;
       
  5365     bool needRepaint = !selections.isEmpty();
       
  5366 
       
  5367     QRect r;
       
  5368     for (Q3TableSelection *s = selections.first(); s; s = selections.next()) {
       
  5369         bool b;
       
  5370         r = r.united(rangeGeometry(s->topRow(),
       
  5371                                    s->leftCol(),
       
  5372                                    s->bottomRow(),
       
  5373                                    s->rightCol(), b));
       
  5374     }
       
  5375 
       
  5376     currentSel = 0;
       
  5377     selections.clear();
       
  5378 
       
  5379     if (needRepaint && repaint)
       
  5380         repaintContents(r, false);
       
  5381 
       
  5382     leftHeader->setSectionStateToAll(Q3TableHeader::Normal);
       
  5383     leftHeader->repaint(false);
       
  5384     if (!isRowSelection(selectionMode())) {
       
  5385         topHeader->setSectionStateToAll(Q3TableHeader::Normal);
       
  5386         topHeader->repaint(false);
       
  5387     }
       
  5388     topHeader->setSectionState(curCol, Q3TableHeader::Bold);
       
  5389     leftHeader->setSectionState(curRow, Q3TableHeader::Bold);
       
  5390     emit selectionChanged();
       
  5391 }
       
  5392 
       
  5393 /*! \internal
       
  5394 */
       
  5395 
       
  5396 QRect Q3Table::rangeGeometry(int topRow, int leftCol,
       
  5397                              int bottomRow, int rightCol, bool &optimize)
       
  5398 {
       
  5399     topRow = QMAX(topRow, rowAt(contentsY()));
       
  5400     leftCol = QMAX(leftCol, columnAt(contentsX()));
       
  5401     int ra = rowAt(contentsY() + visibleHeight());
       
  5402     if (ra != -1)
       
  5403         bottomRow = QMIN(bottomRow, ra);
       
  5404     int ca = columnAt(contentsX() + visibleWidth());
       
  5405     if (ca != -1)
       
  5406         rightCol = QMIN(rightCol, ca);
       
  5407     optimize = true;
       
  5408     QRect rect;
       
  5409     for (int r = topRow; r <= bottomRow; ++r) {
       
  5410         for (int c = leftCol; c <= rightCol; ++c) {
       
  5411             rect = rect.united(cellGeometry(r, c));
       
  5412             Q3TableItem *i = item(r, c);
       
  5413             if (i && (i->rowSpan() > 1 || i->colSpan() > 1))
       
  5414                 optimize = false;
       
  5415         }
       
  5416     }
       
  5417     return rect;
       
  5418 }
       
  5419 
       
  5420 /*!
       
  5421     This function is called to activate the next cell if in-place
       
  5422     editing was finished by pressing the Enter key.
       
  5423 
       
  5424     The default behaviour is to move from top to bottom, i.e. move to
       
  5425     the cell beneath the cell being edited. Reimplement this function
       
  5426     if you want different behaviour, e.g. moving from left to right.
       
  5427 */
       
  5428 
       
  5429 void Q3Table::activateNextCell()
       
  5430 {
       
  5431     int firstRow = 0;
       
  5432     while (d->hiddenRows.find(firstRow))
       
  5433         firstRow++;
       
  5434     int firstCol = 0;
       
  5435     while (d->hiddenCols.find(firstCol))
       
  5436         firstCol++;
       
  5437     int nextRow = curRow;
       
  5438     int nextCol = curCol;
       
  5439     while (d->hiddenRows.find(++nextRow)) {}
       
  5440     if (nextRow >= numRows()) {
       
  5441         nextRow = firstRow;
       
  5442         while (d->hiddenCols.find(++nextCol)) {}
       
  5443         if (nextCol >= numCols())
       
  5444             nextCol = firstCol;
       
  5445     }
       
  5446 
       
  5447     if (!currentSel || !currentSel->isActive() ||
       
  5448          (currentSel->leftCol() == currentSel->rightCol() &&
       
  5449            currentSel->topRow() == currentSel->bottomRow())) {
       
  5450         clearSelection();
       
  5451         setCurrentCell(nextRow, nextCol);
       
  5452     } else {
       
  5453         if (curRow < currentSel->bottomRow())
       
  5454             setCurrentCell(nextRow, curCol);
       
  5455         else if (curCol < currentSel->rightCol())
       
  5456             setCurrentCell(currentSel->topRow(), nextCol);
       
  5457         else
       
  5458             setCurrentCell(currentSel->topRow(), currentSel->leftCol());
       
  5459     }
       
  5460 
       
  5461 }
       
  5462 
       
  5463 /*! \internal
       
  5464 */
       
  5465 
       
  5466 void Q3Table::fixRow(int &row, int y)
       
  5467 {
       
  5468     if (row == -1) {
       
  5469         if (y < 0)
       
  5470             row = 0;
       
  5471         else
       
  5472             row = numRows() - 1;
       
  5473     }
       
  5474 }
       
  5475 
       
  5476 /*! \internal
       
  5477 */
       
  5478 
       
  5479 void Q3Table::fixCol(int &col, int x)
       
  5480 {
       
  5481     if (col == -1) {
       
  5482         if (x < 0)
       
  5483             col = 0;
       
  5484         else
       
  5485             col = numCols() - 1;
       
  5486     }
       
  5487 }
       
  5488 
       
  5489 struct SortableTableItem
       
  5490 {
       
  5491     Q3TableItem *item;
       
  5492 };
       
  5493 
       
  5494 #if defined(Q_C_CALLBACKS)
       
  5495 extern "C" {
       
  5496 #endif
       
  5497 
       
  5498 #ifdef Q_OS_WINCE
       
  5499 static int _cdecl cmpTableItems(const void *n1, const void *n2)
       
  5500 #else
       
  5501 static int cmpTableItems(const void *n1, const void *n2)
       
  5502 #endif
       
  5503 {
       
  5504     if (!n1 || !n2)
       
  5505         return 0;
       
  5506 
       
  5507     SortableTableItem *i1 = (SortableTableItem *)n1;
       
  5508     SortableTableItem *i2 = (SortableTableItem *)n2;
       
  5509 
       
  5510     return i1->item->key().localeAwareCompare(i2->item->key());
       
  5511 }
       
  5512 
       
  5513 #if defined(Q_C_CALLBACKS)
       
  5514 }
       
  5515 #endif
       
  5516 
       
  5517 /*!
       
  5518     Sorts column \a col. If \a ascending is true the sort is in
       
  5519     ascending order, otherwise the sort is in descending order.
       
  5520 
       
  5521     If \a wholeRows is true, entire rows are sorted using swapRows();
       
  5522     otherwise only cells in the column are sorted using swapCells().
       
  5523 
       
  5524     Note that if you are not using Q3TableItems you will need to
       
  5525     reimplement swapRows() and swapCells(). (See the notes on large
       
  5526     tables.)
       
  5527 
       
  5528     \sa swapRows()
       
  5529 */
       
  5530 
       
  5531 void Q3Table::sortColumn(int col, bool ascending, bool wholeRows)
       
  5532 {
       
  5533     int filledRows = 0, i;
       
  5534     for (i = 0; i < numRows(); ++i) {
       
  5535         Q3TableItem *itm = item(i, col);
       
  5536         if (itm)
       
  5537             filledRows++;
       
  5538     }
       
  5539 
       
  5540     if (!filledRows)
       
  5541         return;
       
  5542 
       
  5543     SortableTableItem *items = new SortableTableItem[ filledRows ];
       
  5544     int j = 0;
       
  5545     for (i = 0; i < numRows(); ++i) {
       
  5546         Q3TableItem *itm = item(i, col);
       
  5547         if (!itm)
       
  5548             continue;
       
  5549         items[ j++ ].item = itm;
       
  5550     }
       
  5551 
       
  5552     qsort(items, filledRows, sizeof(SortableTableItem), cmpTableItems);
       
  5553 
       
  5554     bool updatesWereEnabled = updatesEnabled();
       
  5555     if (updatesWereEnabled)
       
  5556         setUpdatesEnabled(false);
       
  5557     for (i = 0; i < numRows(); ++i) {
       
  5558         if (i < filledRows) {
       
  5559             if (ascending) {
       
  5560                 if (items[ i ].item->row() == i)
       
  5561                     continue;
       
  5562                 if (wholeRows)
       
  5563                     swapRows(items[ i ].item->row(), i);
       
  5564                 else
       
  5565                     swapCells(items[ i ].item->row(), col, i, col);
       
  5566             } else {
       
  5567                 if (items[ i ].item->row() == filledRows - i - 1)
       
  5568                     continue;
       
  5569                 if (wholeRows)
       
  5570                     swapRows(items[ i ].item->row(), filledRows - i - 1);
       
  5571                 else
       
  5572                     swapCells(items[ i ].item->row(), col,
       
  5573                                filledRows - i - 1, col);
       
  5574             }
       
  5575         }
       
  5576     }
       
  5577     if (updatesWereEnabled)
       
  5578         setUpdatesEnabled(true);
       
  5579     if (topHeader)
       
  5580          topHeader->setSortIndicator(col, ascending ? Qt::Ascending : Qt::Descending);
       
  5581 
       
  5582     if (!wholeRows)
       
  5583         repaintContents(columnPos(col), contentsY(),
       
  5584                          columnWidth(col), visibleHeight(), false);
       
  5585     else
       
  5586         repaintContents(contentsX(), contentsY(),
       
  5587                          visibleWidth(), visibleHeight(), false);
       
  5588 
       
  5589     delete [] items;
       
  5590 }
       
  5591 
       
  5592 /*!
       
  5593     Hides row \a row.
       
  5594 
       
  5595     \sa showRow() hideColumn()
       
  5596 */
       
  5597 
       
  5598 void Q3Table::hideRow(int row)
       
  5599 {
       
  5600     if (d->hiddenRows.find(row))
       
  5601         return;
       
  5602     d->hiddenRows.replace(row, new int(leftHeader->sectionSize(row)));
       
  5603     leftHeader->resizeSection(row, 0);
       
  5604     leftHeader->setResizeEnabled(false, row);
       
  5605     if (isRowStretchable(row))
       
  5606         leftHeader->numStretches--;
       
  5607     rowHeightChanged(row);
       
  5608     if (curRow == row) {
       
  5609         int r = curRow;
       
  5610         int c = curCol;
       
  5611         int k = (r >= numRows() - 1 ? Key_Up : Key_Down);
       
  5612         fixCell(r, c, k);
       
  5613         if (numRows() > 0)
       
  5614             setCurrentCell(r, c);
       
  5615     }
       
  5616 }
       
  5617 
       
  5618 /*!
       
  5619     Hides column \a col.
       
  5620 
       
  5621     \sa showColumn() hideRow()
       
  5622 */
       
  5623 
       
  5624 void Q3Table::hideColumn(int col)
       
  5625 {
       
  5626     if (!numCols() || d->hiddenCols.find(col))
       
  5627         return;
       
  5628     d->hiddenCols.replace(col, new int(topHeader->sectionSize(col)));
       
  5629     topHeader->resizeSection(col, 0);
       
  5630     topHeader->setResizeEnabled(false, col);
       
  5631     if (isColumnStretchable(col))
       
  5632         topHeader->numStretches--;
       
  5633     columnWidthChanged(col);
       
  5634     if (curCol == col) {
       
  5635         int r = curRow;
       
  5636         int c = curCol;
       
  5637         int k = (c >= numCols() - 1 ? Key_Left : Key_Right);
       
  5638         fixCell(r, c, k);
       
  5639         if (numCols() > 0)
       
  5640             setCurrentCell(r, c);
       
  5641     }
       
  5642 }
       
  5643 
       
  5644 /*!
       
  5645     Shows row \a row.
       
  5646 
       
  5647     \sa hideRow() showColumn()
       
  5648 */
       
  5649 
       
  5650 void Q3Table::showRow(int row)
       
  5651 {
       
  5652     int *h = d->hiddenRows.find(row);
       
  5653     if (h) {
       
  5654         int rh = *h;
       
  5655         d->hiddenRows.remove(row);
       
  5656         setRowHeight(row, rh);
       
  5657         if (isRowStretchable(row))
       
  5658             leftHeader->numStretches++;
       
  5659     } else if (rowHeight(row) == 0) {
       
  5660         setRowHeight(row, 20);
       
  5661     }
       
  5662     leftHeader->setResizeEnabled(true, row);
       
  5663 }
       
  5664 
       
  5665 /*!
       
  5666     Shows column \a col.
       
  5667 
       
  5668     \sa hideColumn() showRow()
       
  5669 */
       
  5670 
       
  5671 void Q3Table::showColumn(int col)
       
  5672 {
       
  5673     int *w = d->hiddenCols.find(col);
       
  5674     if (w) {
       
  5675         int cw = *w;
       
  5676         d->hiddenCols.remove(col);
       
  5677         setColumnWidth(col, cw);
       
  5678         if (isColumnStretchable(col))
       
  5679             topHeader->numStretches++;
       
  5680     } else if (columnWidth(col) == 0) {
       
  5681         setColumnWidth(col, 20);
       
  5682     }
       
  5683     topHeader->setResizeEnabled(true, col);
       
  5684 }
       
  5685 
       
  5686 /*!
       
  5687     Returns true if row \a row is hidden; otherwise returns
       
  5688     false.
       
  5689 
       
  5690     \sa hideRow(), isColumnHidden()
       
  5691 */
       
  5692 bool Q3Table::isRowHidden(int row) const
       
  5693 {
       
  5694     return d->hiddenRows.find(row);
       
  5695 }
       
  5696 
       
  5697 /*!
       
  5698     Returns true if column \a col is hidden; otherwise returns
       
  5699     false.
       
  5700 
       
  5701     \sa hideColumn(), isRowHidden()
       
  5702 */
       
  5703 bool Q3Table::isColumnHidden(int col) const
       
  5704 {
       
  5705     return d->hiddenCols.find(col);
       
  5706 }
       
  5707 
       
  5708 /*!
       
  5709     Resizes column \a col to be \a w pixels wide.
       
  5710 
       
  5711     \sa columnWidth() setRowHeight()
       
  5712 */
       
  5713 
       
  5714 void Q3Table::setColumnWidth(int col, int w)
       
  5715 {
       
  5716     int *ow = d->hiddenCols.find(col);
       
  5717     if (ow) {
       
  5718         d->hiddenCols.replace(col, new int(w));
       
  5719     } else {
       
  5720         topHeader->resizeSection(col, w);
       
  5721         columnWidthChanged(col);
       
  5722     }
       
  5723 }
       
  5724 
       
  5725 /*!
       
  5726     Resizes row \a row to be \a h pixels high.
       
  5727 
       
  5728     \sa rowHeight() setColumnWidth()
       
  5729 */
       
  5730 
       
  5731 void Q3Table::setRowHeight(int row, int h)
       
  5732 {
       
  5733     int *oh = d->hiddenRows.find(row);
       
  5734     if (oh) {
       
  5735         d->hiddenRows.replace(row, new int(h));
       
  5736     } else {
       
  5737         leftHeader->resizeSection(row, h);
       
  5738         rowHeightChanged(row);
       
  5739     }
       
  5740 }
       
  5741 
       
  5742 /*!
       
  5743     Resizes column \a col so that the column width is wide enough to
       
  5744     display the widest item the column contains.
       
  5745 
       
  5746     \sa adjustRow()
       
  5747 */
       
  5748 
       
  5749 void Q3Table::adjustColumn(int col)
       
  5750 {
       
  5751     int w;
       
  5752     if ( currentColumn() == col ) {
       
  5753         QFont f = font();
       
  5754         f.setBold(true);
       
  5755         w = topHeader->sectionSizeHint( col, QFontMetrics(f) ).width();
       
  5756     } else {
       
  5757         w = topHeader->sectionSizeHint( col, fontMetrics() ).width();
       
  5758     }
       
  5759     if (topHeader->iconSet(col))
       
  5760         w += topHeader->iconSet(col)->pixmap().width();
       
  5761     w = QMAX(w, 20);
       
  5762     for (int i = 0; i < numRows(); ++i) {
       
  5763         Q3TableItem *itm = item(i, col);
       
  5764         if (!itm) {
       
  5765             QWidget *widget = cellWidget(i, col);
       
  5766             if (widget)
       
  5767                 w = QMAX(w, widget->sizeHint().width());
       
  5768         } else {
       
  5769             if (itm->colSpan() > 1)
       
  5770                 w = QMAX(w, itm->sizeHint().width() / itm->colSpan());
       
  5771             else
       
  5772                 w = QMAX(w, itm->sizeHint().width());
       
  5773         }
       
  5774     }
       
  5775     w = QMAX(w, QApplication::globalStrut().width());
       
  5776     setColumnWidth(col, w);
       
  5777 }
       
  5778 
       
  5779 /*!
       
  5780     Resizes row \a row so that the row height is tall enough to
       
  5781     display the tallest item the row contains.
       
  5782 
       
  5783     \sa adjustColumn()
       
  5784 */
       
  5785 
       
  5786 void Q3Table::adjustRow(int row)
       
  5787 {
       
  5788     int h = 20;
       
  5789     h = QMAX(h, leftHeader->sectionSizeHint(row, leftHeader->fontMetrics()).height());
       
  5790     if (leftHeader->iconSet(row))
       
  5791         h = QMAX(h, leftHeader->iconSet(row)->pixmap().height());
       
  5792     for (int i = 0; i < numCols(); ++i) {
       
  5793         Q3TableItem *itm = item(row, i);
       
  5794         if (!itm) {
       
  5795             QWidget *widget = cellWidget(row, i);
       
  5796             if (widget)
       
  5797                 h = QMAX(h, widget->sizeHint().height());
       
  5798         } else {
       
  5799             if (itm->rowSpan() > 1)
       
  5800                 h = QMAX(h, itm->sizeHint().height() / itm->rowSpan());
       
  5801             else
       
  5802                 h = QMAX(h, itm->sizeHint().height());
       
  5803         }
       
  5804     }
       
  5805     h = QMAX(h, QApplication::globalStrut().height());
       
  5806     setRowHeight(row, h);
       
  5807 }
       
  5808 
       
  5809 /*!
       
  5810     If \a stretch is true, column \a col is set to be stretchable;
       
  5811     otherwise column \a col is set to be unstretchable.
       
  5812 
       
  5813     If the table widget's width decreases or increases stretchable
       
  5814     columns will grow narrower or wider to fit the space available as
       
  5815     completely as possible. The user cannot manually resize stretchable
       
  5816     columns.
       
  5817 
       
  5818     \sa isColumnStretchable() setRowStretchable() adjustColumn()
       
  5819 */
       
  5820 
       
  5821 void Q3Table::setColumnStretchable(int col, bool stretch)
       
  5822 {
       
  5823     topHeader->setSectionStretchable(col, stretch);
       
  5824 
       
  5825     if (stretch && d->hiddenCols.find(col))
       
  5826         topHeader->numStretches--;
       
  5827 }
       
  5828 
       
  5829 /*!
       
  5830     If \a stretch is true, row \a row is set to be stretchable;
       
  5831     otherwise row \a row is set to be unstretchable.
       
  5832 
       
  5833     If the table widget's height decreases or increases stretchable
       
  5834     rows will grow shorter or taller to fit the space available as
       
  5835     completely as possible. The user cannot manually resize
       
  5836     stretchable rows.
       
  5837 
       
  5838     \sa isRowStretchable() setColumnStretchable()
       
  5839 */
       
  5840 
       
  5841 void Q3Table::setRowStretchable(int row, bool stretch)
       
  5842 {
       
  5843     leftHeader->setSectionStretchable(row, stretch);
       
  5844 
       
  5845     if (stretch && d->hiddenRows.find(row))
       
  5846         leftHeader->numStretches--;
       
  5847 }
       
  5848 
       
  5849 /*!
       
  5850     Returns true if column \a col is stretchable; otherwise returns
       
  5851     false.
       
  5852 
       
  5853     \sa setColumnStretchable() isRowStretchable()
       
  5854 */
       
  5855 
       
  5856 bool Q3Table::isColumnStretchable(int col) const
       
  5857 {
       
  5858     return topHeader->isSectionStretchable(col);
       
  5859 }
       
  5860 
       
  5861 /*!
       
  5862     Returns true if row \a row is stretchable; otherwise returns
       
  5863     false.
       
  5864 
       
  5865     \sa setRowStretchable() isColumnStretchable()
       
  5866 */
       
  5867 
       
  5868 bool Q3Table::isRowStretchable(int row) const
       
  5869 {
       
  5870     return leftHeader->isSectionStretchable(row);
       
  5871 }
       
  5872 
       
  5873 /*!
       
  5874     Takes the table item \a i out of the table. This function does \e
       
  5875     not delete the table item. You must either delete the table item
       
  5876     yourself or put it into a table (using setItem()) which will then
       
  5877     take ownership of it.
       
  5878 
       
  5879     Use this function if you want to move an item from one cell in a
       
  5880     table to another, or to move an item from one table to another,
       
  5881     reinserting the item with setItem().
       
  5882 
       
  5883     If you want to exchange two cells use swapCells().
       
  5884 */
       
  5885 
       
  5886 void Q3Table::takeItem(Q3TableItem *i)
       
  5887 {
       
  5888     if (!i)
       
  5889         return;
       
  5890     if (i->row() != -1 && i->col() != -1) {
       
  5891         QRect rect = cellGeometry(i->row(), i->col());
       
  5892         contents.setAutoDelete(false);
       
  5893         int bottom = i->row() + i->rowSpan();
       
  5894         if (bottom > numRows())
       
  5895             bottom = numRows();
       
  5896         int right = i->col() + i->colSpan();
       
  5897         if (right > numCols())
       
  5898             right = numCols();
       
  5899         for (int r = i->row(); r < bottom; ++r) {
       
  5900             for (int c = i->col(); c < right; ++c)
       
  5901                 contents.remove(indexOf(r, c));
       
  5902         }
       
  5903         contents.setAutoDelete(true);
       
  5904         repaintContents(rect, false);
       
  5905         int orow = i->row();
       
  5906         int ocol = i->col();
       
  5907         i->setRow(-1);
       
  5908         i->setCol(-1);
       
  5909         i->updateEditor(orow, ocol);
       
  5910     }
       
  5911     i->t = 0;
       
  5912 }
       
  5913 
       
  5914 /*!
       
  5915     Sets the widget \a e to the cell at \a row, \a col and takes care of
       
  5916     placing and resizing the widget when the cell geometry changes.
       
  5917 
       
  5918     By default widgets are inserted into a vector with numRows() *
       
  5919     numCols() elements. In very large tables you will probably want to
       
  5920     store the widgets in a data structure that consumes less memory (see
       
  5921     the notes on large tables). To support the use of your own data
       
  5922     structure this function calls insertWidget() to add the widget to
       
  5923     the internal data structure. To use your own data structure
       
  5924     reimplement insertWidget(), cellWidget() and clearCellWidget().
       
  5925 
       
  5926     Cell widgets are created dynamically with the \c new operator. The
       
  5927     cell widgets are destroyed automatically once the table is
       
  5928     destroyed; the table takes ownership of the widget when using
       
  5929     setCellWidget.
       
  5930 
       
  5931 */
       
  5932 
       
  5933 void Q3Table::setCellWidget(int row, int col, QWidget *e)
       
  5934 {
       
  5935     if (!e || row >= numRows() || col >= numCols())
       
  5936         return;
       
  5937 
       
  5938     QWidget *w = cellWidget(row, col);
       
  5939     if (w && row == editRow && col == editCol)
       
  5940         endEdit(editRow, editCol, false, edMode != Editing);
       
  5941 
       
  5942     e->installEventFilter(this);
       
  5943     clearCellWidget(row, col);
       
  5944     if (e->parent() != viewport())
       
  5945         e->reparent(viewport(), QPoint(0,0));
       
  5946     Q3TableItem *itm = item(row, col);
       
  5947     if (itm && itm->row() >= 0 && itm->col() >= 0) { // get the correct row and col if the item is spanning
       
  5948         row = itm->row();
       
  5949         col = itm->col();
       
  5950     }
       
  5951     insertWidget(row, col, e);
       
  5952     QRect cr = cellGeometry(row, col);
       
  5953     e->resize(cr.size());
       
  5954     moveChild(e, cr.x(), cr.y());
       
  5955     e->show();
       
  5956 }
       
  5957 
       
  5958 /*!
       
  5959     Inserts widget \a w at \a row, \a col into the internal
       
  5960     data structure. See the documentation of setCellWidget() for
       
  5961     further details.
       
  5962 
       
  5963     If you don't use \l{Q3TableItem}s you may need to reimplement this
       
  5964     function: see the notes on large tables.
       
  5965 */
       
  5966 
       
  5967 void Q3Table::insertWidget(int row, int col, QWidget *w)
       
  5968 {
       
  5969     if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
       
  5970         return;
       
  5971 
       
  5972     if ((int)widgets.size() != numRows() * numCols())
       
  5973         widgets.resize(numRows() * numCols());
       
  5974 
       
  5975     widgets.insert(indexOf(row, col), w);
       
  5976 }
       
  5977 
       
  5978 /*!
       
  5979     Returns the widget that has been set for the cell at \a row, \a
       
  5980     col, or 0 if no widget has been set.
       
  5981 
       
  5982     If you don't use \l{Q3TableItem}s you may need to reimplement this
       
  5983     function: see the notes on large tables.
       
  5984 
       
  5985     \sa clearCellWidget() setCellWidget()
       
  5986 */
       
  5987 
       
  5988 QWidget *Q3Table::cellWidget(int row, int col) const
       
  5989 {
       
  5990     if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
       
  5991         return 0;
       
  5992 
       
  5993     if ((int)widgets.size() != numRows() * numCols())
       
  5994         ((Q3Table*)this)->widgets.resize(numRows() * numCols());
       
  5995 
       
  5996     return widgets[ indexOf(row, col) ];
       
  5997 }
       
  5998 
       
  5999 /*!
       
  6000     Removes the widget (if there is one) set for the cell at \a row,
       
  6001     \a col.
       
  6002 
       
  6003     If you don't use \l{Q3TableItem}s you may need to reimplement this
       
  6004     function: see the notes on large tables.
       
  6005 
       
  6006     This function deletes the widget at \a row, \a col. Note that the
       
  6007     widget is not deleted immediately; instead QObject::deleteLater()
       
  6008     is called on the widget to avoid problems with timing issues.
       
  6009 
       
  6010     \sa cellWidget() setCellWidget()
       
  6011 */
       
  6012 
       
  6013 void Q3Table::clearCellWidget(int row, int col)
       
  6014 {
       
  6015     if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
       
  6016         return;
       
  6017 
       
  6018     if ((int)widgets.size() != numRows() * numCols())
       
  6019         widgets.resize(numRows() * numCols());
       
  6020 
       
  6021     QWidget *w = cellWidget(row, col);
       
  6022     if (w) {
       
  6023         w->removeEventFilter(this);
       
  6024         w->hide();
       
  6025         w->deleteLater();
       
  6026     }
       
  6027     widgets.setAutoDelete(false);
       
  6028     widgets.remove(indexOf(row, col));
       
  6029     widgets.setAutoDelete(true);
       
  6030 }
       
  6031 
       
  6032 /*!
       
  6033     \fn void Q3Table::dropped (QDropEvent * e)
       
  6034 
       
  6035     This signal is emitted when a drop event occurred on the table.
       
  6036 
       
  6037     \a e contains information about the drop.
       
  6038 */
       
  6039 
       
  6040 /*!
       
  6041     If \a b is true, the table starts a drag (see dragObject()) when
       
  6042     the user presses and moves the mouse on a selected cell.
       
  6043 */
       
  6044 
       
  6045 void Q3Table::setDragEnabled(bool b)
       
  6046 {
       
  6047     dEnabled = b;
       
  6048 }
       
  6049 
       
  6050 /*!
       
  6051     If this function returns true, the table supports dragging.
       
  6052 
       
  6053     \sa setDragEnabled()
       
  6054 */
       
  6055 
       
  6056 bool Q3Table::dragEnabled() const
       
  6057 {
       
  6058     return dEnabled;
       
  6059 }
       
  6060 
       
  6061 /*!
       
  6062     Inserts \a count empty rows at row \a row. Also clears the selection(s).
       
  6063 
       
  6064     \sa insertColumns() removeRow()
       
  6065 */
       
  6066 
       
  6067 void Q3Table::insertRows(int row, int count)
       
  6068 {
       
  6069     // special case, so a call like insertRow(currentRow(), 1) also
       
  6070     // works, when we have 0 rows and currentRow() is -1
       
  6071     if (row == -1 && curRow == -1)
       
  6072         row = 0;
       
  6073     if (row < 0 || count <= 0)
       
  6074         return;
       
  6075 
       
  6076     if (curRow >= row && curRow < row + count)
       
  6077         curRow = row + count;
       
  6078 
       
  6079     --row;
       
  6080     if (row >= numRows())
       
  6081         return;
       
  6082 
       
  6083     bool updatesWereEnabled = updatesEnabled();
       
  6084     if (updatesWereEnabled)
       
  6085         setUpdatesEnabled(false);
       
  6086     bool leftHeaderUpdatesEnabled = leftHeader->updatesEnabled();
       
  6087     if (leftHeaderUpdatesEnabled)
       
  6088         leftHeader->setUpdatesEnabled(false);
       
  6089     int oldLeftMargin = leftMargin();
       
  6090 
       
  6091     setNumRows(numRows() + count);
       
  6092 
       
  6093     for (int i = numRows() - count - 1; i > row; --i)
       
  6094         leftHeader->swapSections(i, i + count);
       
  6095 
       
  6096     if (leftHeaderUpdatesEnabled)
       
  6097         leftHeader->setUpdatesEnabled(leftHeaderUpdatesEnabled);
       
  6098 
       
  6099     if (updatesWereEnabled)
       
  6100         setUpdatesEnabled(true);
       
  6101 
       
  6102     int cr = QMAX(0, currentRow());
       
  6103     int cc = QMAX(0, currentColumn());
       
  6104     if (curRow > row)
       
  6105         curRow -= count; // this is where curRow was
       
  6106     setCurrentCell(cr, cc, true, false); // without ensureCellVisible
       
  6107 
       
  6108     // Repaint the header
       
  6109     if (leftHeaderUpdatesEnabled) {
       
  6110         int y = rowPos(row) - contentsY();
       
  6111         if (leftMargin() != oldLeftMargin || d->hasRowSpan)
       
  6112             y = 0; // full repaint
       
  6113         QRect rect(0, y, leftHeader->width(), contentsHeight());
       
  6114         leftHeader->update(rect);
       
  6115     }
       
  6116 
       
  6117     if (updatesWereEnabled) {
       
  6118         int p = rowPos(row);
       
  6119         if (d->hasRowSpan)
       
  6120             p = contentsY();
       
  6121         updateContents(contentsX(), p, visibleWidth(), contentsHeight() + 1);
       
  6122     }
       
  6123 }
       
  6124 
       
  6125 /*!
       
  6126     Inserts \a count empty columns at column \a col.  Also clears the selection(s).
       
  6127 
       
  6128     \sa insertRows() removeColumn()
       
  6129 */
       
  6130 
       
  6131 void Q3Table::insertColumns(int col, int count)
       
  6132 {
       
  6133     // see comment in insertRows()
       
  6134     if (col == -1 && curCol == -1)
       
  6135         col = 0;
       
  6136     if (col < 0 || count <= 0)
       
  6137         return;
       
  6138 
       
  6139     if (curCol >= col && curCol < col + count)
       
  6140         curCol = col + count;
       
  6141 
       
  6142     --col;
       
  6143     if (col >= numCols())
       
  6144         return;
       
  6145 
       
  6146     bool updatesWereEnabled = updatesEnabled();
       
  6147     if (updatesWereEnabled)
       
  6148         setUpdatesEnabled(false);
       
  6149     bool topHeaderUpdatesEnabled = topHeader->updatesEnabled();
       
  6150     if (topHeaderUpdatesEnabled)
       
  6151         topHeader->setUpdatesEnabled(false);
       
  6152     int oldTopMargin = topMargin();
       
  6153 
       
  6154     setNumCols(numCols() + count);
       
  6155 
       
  6156     for (int i = numCols() - count - 1; i > col; --i)
       
  6157         topHeader->swapSections(i, i + count);
       
  6158 
       
  6159     if (topHeaderUpdatesEnabled)
       
  6160         topHeader->setUpdatesEnabled(true);
       
  6161     if (updatesWereEnabled)
       
  6162         setUpdatesEnabled(true);
       
  6163 
       
  6164     int cr = QMAX(0, currentRow());
       
  6165     int cc = QMAX(0, currentColumn());
       
  6166     if (curCol > col)
       
  6167         curCol -= count; // this is where curCol was
       
  6168     setCurrentCell(cr, cc, true, false); // without ensureCellVisible
       
  6169 
       
  6170     // Repaint the header
       
  6171     if (topHeaderUpdatesEnabled) {
       
  6172         int x = columnPos(col) - contentsX();
       
  6173         if (topMargin() != oldTopMargin || d->hasColSpan)
       
  6174             x = 0; // full repaint
       
  6175         QRect rect(x, 0, contentsWidth(), topHeader->height());
       
  6176         topHeader->update(rect);
       
  6177     }
       
  6178 
       
  6179     if (updatesWereEnabled) {
       
  6180         int p = columnPos(col);
       
  6181         if (d->hasColSpan)
       
  6182             p = contentsX();
       
  6183         updateContents(p, contentsY(), contentsWidth() + 1, visibleHeight());
       
  6184     }
       
  6185 }
       
  6186 
       
  6187 /*!
       
  6188     Removes row \a row, and deletes all its cells including any table
       
  6189     items and widgets the cells may contain. Also clears the selection(s).
       
  6190 
       
  6191     \sa hideRow() insertRows() removeColumn() removeRows()
       
  6192 */
       
  6193 
       
  6194 void Q3Table::removeRow(int row)
       
  6195 {
       
  6196     if (row < 0 || row >= numRows())
       
  6197         return;
       
  6198     if (row < numRows() - 1) {
       
  6199         if (d->hiddenRows.find(row))
       
  6200             d->hiddenRows.remove(row);
       
  6201 
       
  6202         for (int i = row; i < numRows() - 1; ++i)
       
  6203             ((Q3TableHeader*)verticalHeader())->swapSections(i, i + 1);
       
  6204     }
       
  6205     setNumRows(numRows() - 1);
       
  6206 }
       
  6207 
       
  6208 /*!
       
  6209     Removes the rows listed in the array \a rows, and deletes all their
       
  6210     cells including any table items and widgets the cells may contain.
       
  6211 
       
  6212     The array passed in must only contain valid rows (in the range
       
  6213     from 0 to numRows() - 1) with no duplicates, and must be sorted in
       
  6214     ascending order. Also clears the selection(s).
       
  6215 
       
  6216     \sa removeRow() insertRows() removeColumns()
       
  6217 */
       
  6218 
       
  6219 void Q3Table::removeRows(const Q3MemArray<int> &rows)
       
  6220 {
       
  6221     if (rows.count() == 0)
       
  6222         return;
       
  6223     int i;
       
  6224     for (i = 0; i < (int)rows.count() - 1; ++i) {
       
  6225         for (int j = rows[i] - i; j < rows[i + 1] - i - 1; j++) {
       
  6226             ((Q3TableHeader*)verticalHeader())->swapSections(j, j + i + 1);
       
  6227         }
       
  6228     }
       
  6229 
       
  6230     for (int j = rows[i] - i; j < numRows() - (int)rows.size(); j++)
       
  6231         ((Q3TableHeader*)verticalHeader())->swapSections(j, j + rows.count());
       
  6232 
       
  6233     setNumRows(numRows() - rows.count());
       
  6234 }
       
  6235 
       
  6236 /*!
       
  6237     Removes column \a col, and deletes all its cells including any
       
  6238     table items and widgets the cells may contain. Also clears the
       
  6239     selection(s).
       
  6240 
       
  6241     \sa removeColumns() hideColumn() insertColumns() removeRow()
       
  6242 */
       
  6243 
       
  6244 void Q3Table::removeColumn(int col)
       
  6245 {
       
  6246     if (col < 0 || col >= numCols())
       
  6247         return;
       
  6248     if (col < numCols() - 1) {
       
  6249         if (d->hiddenCols.find(col))
       
  6250             d->hiddenCols.remove(col);
       
  6251 
       
  6252         for (int i = col; i < numCols() - 1; ++i)
       
  6253             ((Q3TableHeader*)horizontalHeader())->swapSections(i, i + 1);
       
  6254     }
       
  6255     setNumCols(numCols() - 1);
       
  6256 }
       
  6257 
       
  6258 /*!
       
  6259     Removes the columns listed in the array \a cols, and deletes all
       
  6260     their cells including any table items and widgets the cells may
       
  6261     contain.
       
  6262 
       
  6263     The array passed in must only contain valid columns (in the range
       
  6264     from 0 to numCols() - 1) with no duplicates, and must be sorted in
       
  6265     ascending order. Also clears the selection(s).
       
  6266 
       
  6267    \sa removeColumn() insertColumns() removeRows()
       
  6268 */
       
  6269 
       
  6270 void Q3Table::removeColumns(const Q3MemArray<int> &cols)
       
  6271 {
       
  6272     if (cols.count() == 0)
       
  6273         return;
       
  6274     int i;
       
  6275     for (i = 0; i < (int)cols.count() - 1; ++i) {
       
  6276         for (int j = cols[i] - i; j < cols[i + 1] - i - 1; j++) {
       
  6277             ((Q3TableHeader*)horizontalHeader())->swapSections(j, j + i + 1);
       
  6278         }
       
  6279     }
       
  6280 
       
  6281     for (int j = cols[i] - i; j < numCols() - (int)cols.size(); j++)
       
  6282         ((Q3TableHeader*)horizontalHeader())->swapSections(j, j + cols.count());
       
  6283 
       
  6284     setNumCols(numCols() - cols.count());
       
  6285 }
       
  6286 
       
  6287 /*!
       
  6288     Starts editing the cell at \a row, \a col.
       
  6289 
       
  6290     If \a replace is true the content of this cell will be replaced by
       
  6291     the content of the editor when editing is finished, i.e. the user
       
  6292     will be entering new data; otherwise the current content of the
       
  6293     cell (if any) will be modified in the editor.
       
  6294 
       
  6295     \sa beginEdit()
       
  6296 */
       
  6297 
       
  6298 void Q3Table::editCell(int row, int col, bool replace)
       
  6299 {
       
  6300     if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
       
  6301         return;
       
  6302 
       
  6303     if (beginEdit(row, col, replace)) {
       
  6304         edMode = Editing;
       
  6305         editRow = row;
       
  6306         editCol = col;
       
  6307     }
       
  6308 }
       
  6309 
       
  6310 #ifndef QT_NO_DRAGANDDROP
       
  6311 
       
  6312 /*!
       
  6313     This event handler is called whenever a Q3Table object receives a
       
  6314     \l QDragEnterEvent \a e, i.e. when the user pressed the mouse
       
  6315     button to drag something.
       
  6316 
       
  6317     The focus is moved to the cell where the QDragEnterEvent occurred.
       
  6318 */
       
  6319 
       
  6320 void Q3Table::contentsDragEnterEvent(QDragEnterEvent *e)
       
  6321 {
       
  6322     oldCurrentRow = curRow;
       
  6323     oldCurrentCol = curCol;
       
  6324     int tmpRow = rowAt(e->pos().y());
       
  6325     int tmpCol = columnAt(e->pos().x());
       
  6326     fixRow(tmpRow, e->pos().y());
       
  6327     fixCol(tmpCol, e->pos().x());
       
  6328     if (e->source() != (QObject*)cellWidget(currentRow(), currentColumn()))
       
  6329         setCurrentCell(tmpRow, tmpCol, false, true);
       
  6330     e->accept();
       
  6331 }
       
  6332 
       
  6333 /*!
       
  6334     This event handler is called whenever a Q3Table object receives a
       
  6335     \l QDragMoveEvent \a e, i.e. when the user actually drags the
       
  6336     mouse.
       
  6337 
       
  6338     The focus is moved to the cell where the QDragMoveEvent occurred.
       
  6339 */
       
  6340 
       
  6341 void Q3Table::contentsDragMoveEvent(QDragMoveEvent *e)
       
  6342 {
       
  6343     int tmpRow = rowAt(e->pos().y());
       
  6344     int tmpCol = columnAt(e->pos().x());
       
  6345     fixRow(tmpRow, e->pos().y());
       
  6346     fixCol(tmpCol, e->pos().x());
       
  6347     if (e->source() != (QObject*)cellWidget(currentRow(), currentColumn()))
       
  6348         setCurrentCell(tmpRow, tmpCol, false, true);
       
  6349     e->accept();
       
  6350 }
       
  6351 
       
  6352 /*!
       
  6353     This event handler is called when a drag activity leaves \e this
       
  6354     Q3Table object with event \a e.
       
  6355 */
       
  6356 
       
  6357 void Q3Table::contentsDragLeaveEvent(QDragLeaveEvent *)
       
  6358 {
       
  6359     setCurrentCell(oldCurrentRow, oldCurrentCol, false, true);
       
  6360 }
       
  6361 
       
  6362 /*!
       
  6363     This event handler is called when the user ends a drag and drop by
       
  6364     dropping something onto \e this Q3Table and thus triggers the drop
       
  6365     event, \a e.
       
  6366 */
       
  6367 
       
  6368 void Q3Table::contentsDropEvent(QDropEvent *e)
       
  6369 {
       
  6370     setCurrentCell(oldCurrentRow, oldCurrentCol, false, true);
       
  6371     emit dropped(e);
       
  6372 }
       
  6373 
       
  6374 /*!
       
  6375     If the user presses the mouse on a selected cell, starts moving
       
  6376     (i.e. dragging), and dragEnabled() is true, this function is
       
  6377     called to obtain a drag object. A drag using this object begins
       
  6378     immediately unless dragObject() returns 0.
       
  6379 
       
  6380     By default this function returns 0. You might reimplement it and
       
  6381     create a Q3DragObject depending on the selected items.
       
  6382 
       
  6383     \sa dropped()
       
  6384 */
       
  6385 
       
  6386 Q3DragObject *Q3Table::dragObject()
       
  6387 {
       
  6388     return 0;
       
  6389 }
       
  6390 
       
  6391 /*!
       
  6392     Starts a drag.
       
  6393 
       
  6394     Usually you don't need to call or reimplement this function yourself.
       
  6395 
       
  6396     \sa dragObject()
       
  6397 */
       
  6398 
       
  6399 void Q3Table::startDrag()
       
  6400 {
       
  6401     if (startDragRow == -1 || startDragCol == -1)
       
  6402         return;
       
  6403 
       
  6404     startDragRow = startDragCol = -1;
       
  6405 
       
  6406     Q3DragObject *drag = dragObject();
       
  6407     if (!drag)
       
  6408         return;
       
  6409 
       
  6410     drag->drag();
       
  6411 }
       
  6412 
       
  6413 #endif
       
  6414 
       
  6415 /*! \internal */
       
  6416 void Q3Table::windowActivationChange(bool oldActive)
       
  6417 {
       
  6418     if (oldActive && autoScrollTimer)
       
  6419         autoScrollTimer->stop();
       
  6420 
       
  6421     if (!isVisible())
       
  6422         return;
       
  6423 
       
  6424     if (palette().active() != palette().inactive())
       
  6425         updateContents();
       
  6426 }
       
  6427 
       
  6428 /*!
       
  6429     \internal
       
  6430 */
       
  6431 void Q3Table::setEnabled(bool b)
       
  6432 {
       
  6433     if (!b) {
       
  6434         // editor will lose focus, causing a crash deep in setEnabled(),
       
  6435         // so we'll end the edit early.
       
  6436         endEdit(editRow, editCol, true, edMode != Editing);
       
  6437     }
       
  6438     Q3ScrollView::setEnabled(b);
       
  6439 }
       
  6440 
       
  6441 
       
  6442 /*
       
  6443     \class Q3TableHeader
       
  6444     \brief The Q3TableHeader class allows for creation and manipulation
       
  6445     of table headers.
       
  6446 
       
  6447     \compat
       
  6448 
       
  6449    Q3Table uses this subclass of Q3Header for its headers. Q3Table has a
       
  6450    horizontalHeader() for displaying column labels, and a
       
  6451    verticalHeader() for displaying row labels.
       
  6452 
       
  6453 */
       
  6454 
       
  6455 /*
       
  6456     \enum Q3TableHeader::SectionState
       
  6457 
       
  6458     This enum type denotes the state of the header's text
       
  6459 
       
  6460     \value Normal the default
       
  6461     \value Bold
       
  6462     \value Selected  typically represented by showing the section "sunken"
       
  6463     or "pressed in"
       
  6464 */
       
  6465 
       
  6466 /*!
       
  6467     Creates a new table header called \a name with \a i sections. It
       
  6468     is a child of widget \a parent and attached to table \a t.
       
  6469 */
       
  6470 
       
  6471 Q3TableHeader::Q3TableHeader(int i, Q3Table *t,
       
  6472                             QWidget *parent, const char *name)
       
  6473     : Q3Header(i, parent, name), mousePressed(false), startPos(-1),
       
  6474       table(t), caching(false), resizedSection(-1),
       
  6475       numStretches(0)
       
  6476 {
       
  6477     setIsATableHeader(true);
       
  6478     d = 0;
       
  6479     states.resize(i);
       
  6480     stretchable.resize(i);
       
  6481     states.fill(Normal, -1);
       
  6482     stretchable.fill(false, -1);
       
  6483     autoScrollTimer = new QTimer(this);
       
  6484     connect(autoScrollTimer, SIGNAL(timeout()),
       
  6485              this, SLOT(doAutoScroll()));
       
  6486 #ifndef NO_LINE_WIDGET
       
  6487     line1 = new QWidget(table->viewport(), "qt_line1");
       
  6488     line1->hide();
       
  6489     line1->setBackgroundMode(PaletteText);
       
  6490     table->addChild(line1);
       
  6491     line2 = new QWidget(table->viewport(), "qt_line2");
       
  6492     line2->hide();
       
  6493     line2->setBackgroundMode(PaletteText);
       
  6494     table->addChild(line2);
       
  6495 #else
       
  6496     d = new Q3TableHeaderPrivate;
       
  6497     d->oldLinePos = -1; //outside, in contents coords
       
  6498 #endif
       
  6499     connect(this, SIGNAL(sizeChange(int,int,int)),
       
  6500              this, SLOT(sectionWidthChanged(int,int,int)));
       
  6501     connect(this, SIGNAL(indexChange(int,int,int)),
       
  6502              this, SLOT(indexChanged(int,int,int)));
       
  6503 
       
  6504     stretchTimer = new QTimer(this);
       
  6505     widgetStretchTimer = new QTimer(this);
       
  6506     connect(stretchTimer, SIGNAL(timeout()),
       
  6507              this, SLOT(updateStretches()));
       
  6508     connect(widgetStretchTimer, SIGNAL(timeout()),
       
  6509              this, SLOT(updateWidgetStretches()));
       
  6510     startPos = -1;
       
  6511 }
       
  6512 
       
  6513 /*!
       
  6514     Adds a new section, \a size pixels wide (or high for vertical
       
  6515     headers) with the label \a s. If \a size is negative the section's
       
  6516     size is calculated based on the width (or height) of the label's
       
  6517     text.
       
  6518 */
       
  6519 
       
  6520 void Q3TableHeader::addLabel(const QString &s , int size)
       
  6521 {
       
  6522     Q3Header::addLabel(s, size);
       
  6523     if (count() > (int)states.size()) {
       
  6524         int s = states.size();
       
  6525         states.resize(count());
       
  6526         stretchable.resize(count());
       
  6527         for (; s < count(); ++s) {
       
  6528             states[ s ] = Normal;
       
  6529             stretchable[ s ] = false;
       
  6530         }
       
  6531     }
       
  6532 }
       
  6533 
       
  6534 void Q3TableHeader::removeLabel(int section)
       
  6535 {
       
  6536     Q3Header::removeLabel(section);
       
  6537     if (section == (int)states.size() - 1) {
       
  6538         states.resize(states.size() - 1);
       
  6539         stretchable.resize(stretchable.size() - 1);
       
  6540     }
       
  6541 }
       
  6542 
       
  6543 void Q3TableHeader::resizeArrays(int n)
       
  6544 {
       
  6545     int old = states.size();
       
  6546     states.resize(n);
       
  6547     stretchable.resize(n);
       
  6548     if (n > old) {
       
  6549         for (int i = old; i < n; ++i) {
       
  6550             stretchable[ i ] = false;
       
  6551             states[ i ] = Normal;
       
  6552         }
       
  6553     }
       
  6554 }
       
  6555 
       
  6556 void Q3TableHeader::setLabel(int section, const QString & s, int size)
       
  6557 {
       
  6558     Q3Header::setLabel(section, s, size);
       
  6559     sectionLabelChanged(section);
       
  6560 }
       
  6561 
       
  6562 void Q3TableHeader::setLabel(int section, const QIconSet & iconset,
       
  6563                              const QString & s, int size)
       
  6564 {
       
  6565     Q3Header::setLabel(section, iconset, s, size);
       
  6566     sectionLabelChanged(section);
       
  6567 }
       
  6568 
       
  6569 /*!
       
  6570     Sets the SectionState of section \a s to \a astate.
       
  6571 
       
  6572     \sa sectionState()
       
  6573 */
       
  6574 
       
  6575 void Q3TableHeader::setSectionState(int s, SectionState astate)
       
  6576 {
       
  6577     if (s < 0 || s >= (int)states.count())
       
  6578         return;
       
  6579     if (states.data()[ s ] == astate)
       
  6580         return;
       
  6581     if (isRowSelection(table->selectionMode()) && orientation() == Horizontal)
       
  6582         return;
       
  6583 
       
  6584     states.data()[ s ] = astate;
       
  6585     if (updatesEnabled()) {
       
  6586         if (orientation() == Horizontal)
       
  6587             repaint(sectionPos(s) - offset(), 0, sectionSize(s), height(), false);
       
  6588         else
       
  6589             repaint(0, sectionPos(s) - offset(), width(), sectionSize(s), false);
       
  6590     }
       
  6591 }
       
  6592 
       
  6593 void Q3TableHeader::setSectionStateToAll(SectionState state)
       
  6594 {
       
  6595     if (isRowSelection(table->selectionMode()) && orientation() == Horizontal)
       
  6596         return;
       
  6597 
       
  6598     register int *d = (int *) states.data();
       
  6599     int n = count();
       
  6600 
       
  6601     while (n >= 4) {
       
  6602         d[0] = state;
       
  6603         d[1] = state;
       
  6604         d[2] = state;
       
  6605         d[3] = state;
       
  6606         d += 4;
       
  6607         n -= 4;
       
  6608     }
       
  6609 
       
  6610     if (n > 0) {
       
  6611         d[0] = state;
       
  6612         if (n > 1) {
       
  6613             d[1] = state;
       
  6614             if (n > 2) {
       
  6615                 d[2] = state;
       
  6616             }
       
  6617         }
       
  6618     }
       
  6619 }
       
  6620 
       
  6621 /*!
       
  6622     Returns the SectionState of section \a s.
       
  6623 
       
  6624     \sa setSectionState()
       
  6625 */
       
  6626 
       
  6627 Q3TableHeader::SectionState Q3TableHeader::sectionState(int s) const
       
  6628 {
       
  6629     return (s < 0 || s >= (int)states.count() ? Normal : (Q3TableHeader::SectionState)states[s]);
       
  6630 }
       
  6631 
       
  6632 /*! \reimp
       
  6633 */
       
  6634 
       
  6635 void Q3TableHeader::paintEvent(QPaintEvent *e)
       
  6636 {
       
  6637     QPainter p(this);
       
  6638     p.setPen(colorGroup().buttonText());
       
  6639     int pos = orientation() == Horizontal
       
  6640                      ? e->rect().left()
       
  6641                      : e->rect().top();
       
  6642     int id = mapToIndex(sectionAt(pos + offset()));
       
  6643     if (id < 0) {
       
  6644         if (pos > 0)
       
  6645             return;
       
  6646         else
       
  6647             id = 0;
       
  6648     }
       
  6649 
       
  6650     QRegion reg = e->region();
       
  6651     for (int i = id; i < count(); i++) {
       
  6652         QRect r = sRect(i);
       
  6653         reg -= r;
       
  6654         p.save();
       
  6655         if (!(orientation() == Horizontal && isRowSelection(table->selectionMode())) &&
       
  6656              (sectionState(i) == Bold || sectionState(i) == Selected)) {
       
  6657             QFont f(font());
       
  6658             f.setBold(true);
       
  6659             p.setFont(f);
       
  6660         }
       
  6661         paintSection(&p, i, r);
       
  6662         p.restore();
       
  6663         if ((orientation() == Horizontal && r. right() >= e->rect().right())
       
  6664             || (orientation() == Vertical && r. bottom() >= e->rect().bottom()))
       
  6665             return;
       
  6666     }
       
  6667     p.end();
       
  6668     if (!reg.isEmpty())
       
  6669         erase(reg);
       
  6670 }
       
  6671 
       
  6672 /*!
       
  6673     \reimp
       
  6674 
       
  6675     Paints the header section with index \a index into the rectangular
       
  6676     region \a fr on the painter \a p.
       
  6677 */
       
  6678 
       
  6679 void Q3TableHeader::paintSection(QPainter *p, int index, const QRect& fr)
       
  6680 {
       
  6681     int section = mapToSection(index);
       
  6682     if (section < 0 || cellSize(section) <= 0)
       
  6683         return;
       
  6684 
       
  6685    if (sectionState(index) != Selected ||
       
  6686          (orientation() == Horizontal && isRowSelection(table->selectionMode()))) {
       
  6687         Q3Header::paintSection(p, index, fr);
       
  6688    } else {
       
  6689        QStyleOptionHeader opt;
       
  6690        opt.palette = palette();
       
  6691        opt.rect = fr;
       
  6692        opt.state = QStyle::State_Off | (orient == Qt::Horizontal ? QStyle::State_Horizontal
       
  6693                                                                  : QStyle::State_None);
       
  6694        if (isEnabled())
       
  6695            opt.state |= QStyle::State_Enabled;
       
  6696        if (isClickEnabled()) {
       
  6697            if (sectionState(index) == Selected) {
       
  6698                opt.state |= QStyle::State_Sunken;
       
  6699                if (!mousePressed)
       
  6700                    opt.state |= QStyle::State_On;
       
  6701            }
       
  6702        }
       
  6703        if (!(opt.state & QStyle::State_Sunken))
       
  6704            opt.state |= QStyle::State_Raised;
       
  6705        style()->drawControl(QStyle::CE_HeaderSection, &opt, p, this);
       
  6706        paintSectionLabel(p, index, fr);
       
  6707    }
       
  6708 }
       
  6709 
       
  6710 static int real_pos(const QPoint &p, Qt::Orientation o)
       
  6711 {
       
  6712     if (o == Qt::Horizontal)
       
  6713         return p.x();
       
  6714     return p.y();
       
  6715 }
       
  6716 
       
  6717 /*! \reimp
       
  6718 */
       
  6719 
       
  6720 void Q3TableHeader::mousePressEvent(QMouseEvent *e)
       
  6721 {
       
  6722     if (e->button() != LeftButton)
       
  6723         return;
       
  6724     Q3Header::mousePressEvent(e);
       
  6725     mousePressed = true;
       
  6726     pressPos = real_pos(e->pos(), orientation());
       
  6727     if (!table->currentSel || (e->state() & ShiftButton) != ShiftButton)
       
  6728         startPos = -1;
       
  6729     setCaching(true);
       
  6730     resizedSection = -1;
       
  6731 #ifdef QT_NO_CURSOR
       
  6732     isResizing = false;
       
  6733 #else
       
  6734     isResizing = cursor().shape() != ArrowCursor;
       
  6735     if (!isResizing && sectionAt(pressPos) != -1)
       
  6736         doSelection(e);
       
  6737 #endif
       
  6738 }
       
  6739 
       
  6740 /*! \reimp
       
  6741 */
       
  6742 
       
  6743 void Q3TableHeader::mouseMoveEvent(QMouseEvent *e)
       
  6744 {
       
  6745     if ((e->state() & MouseButtonMask) != LeftButton // Using LeftButton simulates old behavior.
       
  6746 #ifndef QT_NO_CURSOR
       
  6747          || cursor().shape() != ArrowCursor
       
  6748 #endif
       
  6749          || ((e->state() & ControlButton) == ControlButton &&
       
  6750               (orientation() == Horizontal
       
  6751              ? table->columnMovingEnabled() : table->rowMovingEnabled()))) {
       
  6752         Q3Header::mouseMoveEvent(e);
       
  6753         return;
       
  6754     }
       
  6755 
       
  6756     if (!doSelection(e))
       
  6757         Q3Header::mouseMoveEvent(e);
       
  6758 }
       
  6759 
       
  6760 bool Q3TableHeader::doSelection(QMouseEvent *e)
       
  6761 {
       
  6762     int p = real_pos(e->pos(), orientation()) + offset();
       
  6763 
       
  6764     if (isRowSelection(table->selectionMode())) {
       
  6765         if (orientation() == Horizontal)
       
  6766             return true;
       
  6767         if (table->selectionMode() == Q3Table::SingleRow) {
       
  6768             int secAt = sectionAt(p);
       
  6769             if (secAt == -1)
       
  6770                 return true;
       
  6771             table->setCurrentCell(secAt, table->currentColumn());
       
  6772             return true;
       
  6773         }
       
  6774     }
       
  6775 
       
  6776     if (startPos == -1) {
       
  6777          int secAt = sectionAt(p);
       
  6778         if (((e->state() & ControlButton) != ControlButton && (e->state() & ShiftButton) != ShiftButton)
       
  6779             || table->selectionMode() == Q3Table::Single
       
  6780             || table->selectionMode() == Q3Table::SingleRow) {
       
  6781             startPos = p;
       
  6782             bool b = table->signalsBlocked();
       
  6783             table->blockSignals(true);
       
  6784             table->clearSelection();
       
  6785             table->blockSignals(b);
       
  6786         }
       
  6787         saveStates();
       
  6788 
       
  6789         if (table->selectionMode() != Q3Table::NoSelection) {
       
  6790             startPos = p;
       
  6791             Q3TableSelection *oldSelection = table->currentSel;
       
  6792 
       
  6793             if (orientation() == Vertical) {
       
  6794                 if (!table->isRowSelected(secAt, true)) {
       
  6795                     table->currentSel = new Q3TableSelection();
       
  6796                     table->selections.append(table->currentSel);
       
  6797                     table->currentSel->init(secAt, 0);
       
  6798                     table->currentSel->expandTo(secAt, table->numCols() - 1);
       
  6799                     emit table->selectionChanged();
       
  6800                 }
       
  6801                 table->setCurrentCell(secAt, 0);
       
  6802             } else { // orientation == Horizontal
       
  6803                 if (!table->isColumnSelected(secAt, true)) {
       
  6804                     table->currentSel = new Q3TableSelection();
       
  6805                     table->selections.append(table->currentSel);
       
  6806                     table->currentSel->init(0, secAt);
       
  6807                     table->currentSel->expandTo(table->numRows() - 1, secAt);
       
  6808                     emit table->selectionChanged();
       
  6809                 }
       
  6810                 table->setCurrentCell(0, secAt);
       
  6811             }
       
  6812 
       
  6813             if ((orientation() == Horizontal && table->isColumnSelected(secAt))
       
  6814                 || (orientation() == Vertical && table->isRowSelected(secAt))) {
       
  6815                 setSectionState(secAt, Selected);
       
  6816             }
       
  6817 
       
  6818              table->repaintSelections(oldSelection, table->currentSel,
       
  6819                                        orientation() == Horizontal,
       
  6820                                        orientation() == Vertical);
       
  6821             if (sectionAt(p) != -1)
       
  6822                  endPos = p;
       
  6823 
       
  6824              return true;
       
  6825         }
       
  6826     }
       
  6827 
       
  6828     if (sectionAt(p) != -1)
       
  6829         endPos = p;
       
  6830     if (startPos != -1) {
       
  6831         updateSelections();
       
  6832         p -= offset();
       
  6833         if (orientation() == Horizontal && (p < 0 || p > width())) {
       
  6834             doAutoScroll();
       
  6835             autoScrollTimer->start(100, true);
       
  6836         } else if (orientation() == Vertical && (p < 0 || p > height())) {
       
  6837             doAutoScroll();
       
  6838             autoScrollTimer->start(100, true);
       
  6839         }
       
  6840         return true;
       
  6841     }
       
  6842     return table->selectionMode() == Q3Table::NoSelection;
       
  6843 }
       
  6844 
       
  6845 static inline bool mayOverwriteMargin(int before, int after)
       
  6846 {
       
  6847     /*
       
  6848       0 is the only user value that we always respect. We also never
       
  6849       shrink a margin, in case the user wanted it that way.
       
  6850     */
       
  6851     return before != 0 && before < after;
       
  6852 }
       
  6853 
       
  6854 void Q3TableHeader::sectionLabelChanged(int section)
       
  6855 {
       
  6856     emit sectionSizeChanged(section);
       
  6857 
       
  6858     // this does not really belong here
       
  6859     if (orientation() == Horizontal) {
       
  6860         int h = sizeHint().height();
       
  6861         if (h != height() && mayOverwriteMargin(table->topMargin(), h))
       
  6862             table->setTopMargin(h);
       
  6863     } else {
       
  6864         int w = sizeHint().width();
       
  6865         if (w != width() && mayOverwriteMargin((QApplication::reverseLayout() ? table->rightMargin() : table->leftMargin()), w))
       
  6866             table->setLeftMargin(w);
       
  6867     }
       
  6868 }
       
  6869 
       
  6870 /*! \reimp */
       
  6871 void Q3TableHeader::mouseReleaseEvent(QMouseEvent *e)
       
  6872 {
       
  6873     if (e->button() != LeftButton)
       
  6874         return;
       
  6875     autoScrollTimer->stop();
       
  6876     mousePressed = false;
       
  6877     setCaching(false);
       
  6878     Q3Header::mouseReleaseEvent(e);
       
  6879 #ifndef NO_LINE_WIDGET
       
  6880     line1->hide();
       
  6881     line2->hide();
       
  6882 #else
       
  6883     if (d->oldLinePos >= 0)
       
  6884         if (orientation() == Horizontal)
       
  6885             table->updateContents(d->oldLinePos, table->contentsY(),
       
  6886                                    1, table->visibleHeight());
       
  6887         else
       
  6888             table->updateContents( table->contentsX(), d->oldLinePos,
       
  6889                                     table->visibleWidth(), 1);
       
  6890     d->oldLinePos = -1;
       
  6891 #endif
       
  6892     if (resizedSection != -1) {
       
  6893         emit sectionSizeChanged(resizedSection);
       
  6894         updateStretches();
       
  6895     }
       
  6896 
       
  6897     //Make sure all newly selected sections are painted one last time
       
  6898     QRect selectedRects;
       
  6899     for (int i = 0; i < count(); i++) {
       
  6900         if(sectionState(i) == Selected)
       
  6901             selectedRects |= sRect(i);
       
  6902     }
       
  6903     if(!selectedRects.isNull())
       
  6904         repaint(selectedRects);
       
  6905 }
       
  6906 
       
  6907 /*! \reimp
       
  6908 */
       
  6909 
       
  6910 void Q3TableHeader::mouseDoubleClickEvent(QMouseEvent *e)
       
  6911 {
       
  6912     if (e->button() != LeftButton)
       
  6913         return;
       
  6914     if (isResizing) {
       
  6915         int p = real_pos(e->pos(), orientation()) + offset();
       
  6916         int section = sectionAt(p);
       
  6917         if (section == -1)
       
  6918             return;
       
  6919         section--;
       
  6920         if (p >= sectionPos(count() - 1) + sectionSize(count() - 1))
       
  6921             ++section;
       
  6922         while (sectionSize(section) == 0)
       
  6923             section--;
       
  6924         if (section < 0)
       
  6925             return;
       
  6926         int oldSize = sectionSize(section);
       
  6927         if (orientation() == Horizontal) {
       
  6928             table->adjustColumn(section);
       
  6929             int newSize = sectionSize(section);
       
  6930             if (oldSize != newSize)
       
  6931                 emit sizeChange(section, oldSize, newSize);
       
  6932             for (int i = 0; i < table->numCols(); ++i) {
       
  6933                 if (table->isColumnSelected(i) && sectionSize(i) != 0)
       
  6934                     table->adjustColumn(i);
       
  6935             }
       
  6936         } else {
       
  6937             table->adjustRow(section);
       
  6938             int newSize = sectionSize(section);
       
  6939             if (oldSize != newSize)
       
  6940                 emit sizeChange(section, oldSize, newSize);
       
  6941             for (int i = 0; i < table->numRows(); ++i) {
       
  6942                 if (table->isRowSelected(i)  && sectionSize(i) != 0)
       
  6943                     table->adjustRow(i);
       
  6944             }
       
  6945         }
       
  6946     }
       
  6947 }
       
  6948 
       
  6949 /*! \reimp
       
  6950 */
       
  6951 
       
  6952 void Q3TableHeader::resizeEvent(QResizeEvent *e)
       
  6953 {
       
  6954     stretchTimer->stop();
       
  6955     widgetStretchTimer->stop();
       
  6956     Q3Header::resizeEvent(e);
       
  6957     if (numStretches == 0)
       
  6958         return;
       
  6959     stretchTimer->start(0, true);
       
  6960 }
       
  6961 
       
  6962 void Q3TableHeader::updateStretches()
       
  6963 {
       
  6964     if (numStretches == 0)
       
  6965         return;
       
  6966 
       
  6967     int dim = orientation() == Horizontal ? width() : height();
       
  6968     if (sectionPos(count() - 1) + sectionSize(count() - 1) == dim)
       
  6969         return;
       
  6970     int i;
       
  6971     int pd = dim - (sectionPos(count() - 1)
       
  6972                      + sectionSize(count() - 1));
       
  6973     bool block = signalsBlocked();
       
  6974     blockSignals(true);
       
  6975     for (i = 0; i < (int)stretchable.count(); ++i) {
       
  6976         if (!stretchable[i] ||
       
  6977              (stretchable[i] && table->d->hiddenCols[i]))
       
  6978             continue;
       
  6979         pd += sectionSize(i);
       
  6980     }
       
  6981     pd /= numStretches;
       
  6982     for (i = 0; i < (int)stretchable.count(); ++i) {
       
  6983         if (!stretchable[i] ||
       
  6984              (stretchable[i] && table->d->hiddenCols[i]))
       
  6985             continue;
       
  6986         if (i == (int)stretchable.count() - 1 &&
       
  6987              sectionPos(i) + pd < dim)
       
  6988             pd = dim - sectionPos(i);
       
  6989         resizeSection(i, QMAX(20, pd));
       
  6990     }
       
  6991     blockSignals(block);
       
  6992     table->repaintContents(false);
       
  6993     widgetStretchTimer->start(100, true);
       
  6994 }
       
  6995 
       
  6996 void Q3TableHeader::updateWidgetStretches()
       
  6997 {
       
  6998     QSize s = table->tableSize();
       
  6999     table->resizeContents(s.width(), s.height());
       
  7000     for (int i = 0; i < table->numCols(); ++i)
       
  7001         table->updateColWidgets(i);
       
  7002 }
       
  7003 
       
  7004 void Q3TableHeader::updateSelections()
       
  7005 {
       
  7006     if (table->selectionMode() == Q3Table::NoSelection ||
       
  7007          (isRowSelection(table->selectionMode()) && orientation() != Vertical ))
       
  7008         return;
       
  7009     int a = sectionAt(startPos);
       
  7010     int b = sectionAt(endPos);
       
  7011     int start = QMIN(a, b);
       
  7012     int end = QMAX(a, b);
       
  7013     register int *s = states.data();
       
  7014     for (int i = 0; i < count(); ++i) {
       
  7015         if (i < start || i > end)
       
  7016             *s = oldStates.data()[ i ];
       
  7017         else
       
  7018             *s = Selected;
       
  7019         ++s;
       
  7020     }
       
  7021     repaint(false);
       
  7022 
       
  7023     if (table->currentSel) {
       
  7024         Q3TableSelection oldSelection = *table->currentSel;
       
  7025         if (orientation() == Vertical)
       
  7026             table->currentSel->expandTo(b, table->horizontalHeader()->count() - 1);
       
  7027         else
       
  7028             table->currentSel->expandTo(table->verticalHeader()->count() - 1, b);
       
  7029         table->repaintSelections(&oldSelection, table->currentSel,
       
  7030                                   orientation() == Horizontal,
       
  7031                                   orientation() == Vertical);
       
  7032     }
       
  7033     emit table->selectionChanged();
       
  7034 }
       
  7035 
       
  7036 void Q3TableHeader::saveStates()
       
  7037 {
       
  7038     oldStates.resize(count());
       
  7039     register int *s = states.data();
       
  7040     register int *s2 = oldStates.data();
       
  7041     for (int i = 0; i < count(); ++i) {
       
  7042         *s2 = *s;
       
  7043         ++s2;
       
  7044         ++s;
       
  7045     }
       
  7046 }
       
  7047 
       
  7048 void Q3TableHeader::doAutoScroll()
       
  7049 {
       
  7050     QPoint pos = mapFromGlobal(QCursor::pos());
       
  7051     int p = real_pos(pos, orientation()) + offset();
       
  7052     if (sectionAt(p) != -1)
       
  7053         endPos = p;
       
  7054     if (orientation() == Horizontal)
       
  7055         table->ensureVisible(endPos, table->contentsY());
       
  7056     else
       
  7057         table->ensureVisible(table->contentsX(), endPos);
       
  7058     updateSelections();
       
  7059     autoScrollTimer->start(100, true);
       
  7060 }
       
  7061 
       
  7062 void Q3TableHeader::sectionWidthChanged(int col, int, int)
       
  7063 {
       
  7064     resizedSection = col;
       
  7065     if (orientation() == Horizontal) {
       
  7066 #ifndef NO_LINE_WIDGET
       
  7067         table->moveChild(line1, Q3Header::sectionPos(col) - 1,
       
  7068                           table->contentsY());
       
  7069         line1->resize(1, table->visibleHeight());
       
  7070         line1->show();
       
  7071         line1->raise();
       
  7072         table->moveChild(line2,
       
  7073                           Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1,
       
  7074                           table->contentsY());
       
  7075         line2->resize(1, table->visibleHeight());
       
  7076         line2->show();
       
  7077         line2->raise();
       
  7078 #else
       
  7079         QPainter p(table->viewport());
       
  7080         int lx = Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1;
       
  7081         int ly = table->contentsY();
       
  7082 
       
  7083         if (lx != d->oldLinePos) {
       
  7084             QPoint pt = table->contentsToViewport(QPoint(lx, ly));
       
  7085             p.drawLine(pt.x(), pt.y()+1,
       
  7086                         pt.x(), pt.y()+ table->visibleHeight());
       
  7087             if (d->oldLinePos >= 0)
       
  7088                 table->repaintContents(d->oldLinePos, table->contentsY(),
       
  7089                                        1, table->visibleHeight());
       
  7090 
       
  7091             d->oldLinePos = lx;
       
  7092         }
       
  7093 #endif
       
  7094     } else {
       
  7095 #ifndef NO_LINE_WIDGET
       
  7096         table->moveChild(line1, table->contentsX(),
       
  7097                           Q3Header::sectionPos(col) - 1);
       
  7098         line1->resize(table->visibleWidth(), 1);
       
  7099         line1->show();
       
  7100         line1->raise();
       
  7101         table->moveChild(line2, table->contentsX(),
       
  7102                           Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1);
       
  7103         line2->resize(table->visibleWidth(), 1);
       
  7104         line2->show();
       
  7105         line2->raise();
       
  7106 
       
  7107 #else
       
  7108         QPainter p(table->viewport());
       
  7109         int lx = table->contentsX();
       
  7110         int ly = Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1;
       
  7111 
       
  7112         if (ly != d->oldLinePos) {
       
  7113             QPoint pt = table->contentsToViewport(QPoint(lx, ly));
       
  7114             p.drawLine(pt.x()+1, pt.y(),
       
  7115                         pt.x() + table->visibleWidth(), pt.y());
       
  7116             if (d->oldLinePos >= 0)
       
  7117                 table->repaintContents( table->contentsX(), d->oldLinePos,
       
  7118                                         table->visibleWidth(), 1);
       
  7119             d->oldLinePos = ly;
       
  7120         }
       
  7121 
       
  7122 #endif
       
  7123     }
       
  7124 }
       
  7125 
       
  7126 /*!
       
  7127     \reimp
       
  7128 
       
  7129     Returns the size of section \a section in pixels or -1 if \a
       
  7130     section is out of range.
       
  7131 */
       
  7132 
       
  7133 int Q3TableHeader::sectionSize(int section) const
       
  7134 {
       
  7135     if (count() <= 0 || section < 0 || section >= count())
       
  7136         return -1;
       
  7137     if (caching && section < (int)sectionSizes.count())
       
  7138          return sectionSizes[ section ];
       
  7139     return Q3Header::sectionSize(section);
       
  7140 }
       
  7141 
       
  7142 /*!
       
  7143     \reimp
       
  7144 
       
  7145     Returns the start position of section \a section in pixels or -1
       
  7146     if \a section is out of range.
       
  7147 
       
  7148     \sa sectionAt()
       
  7149 */
       
  7150 
       
  7151 int Q3TableHeader::sectionPos(int section) const
       
  7152 {
       
  7153     if (count() <= 0 || section < 0 || section >= count())
       
  7154         return -1;
       
  7155     if (caching && section < (int)sectionPoses.count())
       
  7156         return sectionPoses[ section ];
       
  7157     return Q3Header::sectionPos(section);
       
  7158 }
       
  7159 
       
  7160 /*!
       
  7161     \reimp
       
  7162 
       
  7163     Returns the number of the section at index position \a pos or -1
       
  7164     if there is no section at the position given.
       
  7165 
       
  7166     \sa sectionPos()
       
  7167 */
       
  7168 
       
  7169 int Q3TableHeader::sectionAt(int pos) const
       
  7170 {
       
  7171     if (!caching || sectionSizes.count() <= 0 || sectionPoses.count() <= 0)
       
  7172         return Q3Header::sectionAt(pos);
       
  7173     if (count() <= 0 || pos > sectionPoses[ count() - 1 ] + sectionSizes[ count() - 1 ])
       
  7174         return -1;
       
  7175     int l = 0;
       
  7176     int r = count() - 1;
       
  7177     int i = ((l+r+1) / 2);
       
  7178     while (r - l) {
       
  7179         if (sectionPoses[i] > pos)
       
  7180             r = i -1;
       
  7181         else
       
  7182             l = i;
       
  7183         i = ((l+r+1) / 2);
       
  7184     }
       
  7185     if (sectionPoses[i] <= pos &&
       
  7186          pos <= sectionPoses[i] + sectionSizes[ mapToSection(i) ])
       
  7187         return mapToSection(i);
       
  7188     return -1;
       
  7189 }
       
  7190 
       
  7191 void Q3TableHeader::updateCache()
       
  7192 {
       
  7193     sectionPoses.resize(count());
       
  7194     sectionSizes.resize(count());
       
  7195     if (!caching)
       
  7196         return;
       
  7197     for (int i = 0; i < count(); ++i) {
       
  7198         sectionSizes[ i ] = Q3Header::sectionSize(i);
       
  7199         sectionPoses[ i ] = Q3Header::sectionPos(i);
       
  7200     }
       
  7201 }
       
  7202 
       
  7203 void Q3TableHeader::setCaching(bool b)
       
  7204 {
       
  7205     if (caching == b)
       
  7206         return;
       
  7207     caching = b;
       
  7208     sectionPoses.resize(count());
       
  7209     sectionSizes.resize(count());
       
  7210     if (b) {
       
  7211         for (int i = 0; i < count(); ++i) {
       
  7212             sectionSizes[ i ] = Q3Header::sectionSize(i);
       
  7213             sectionPoses[ i ] = Q3Header::sectionPos(i);
       
  7214         }
       
  7215     }
       
  7216 }
       
  7217 
       
  7218 /*!
       
  7219     If \a b is true, section \a s is stretchable; otherwise the
       
  7220     section is not stretchable.
       
  7221 
       
  7222     \sa isSectionStretchable()
       
  7223 */
       
  7224 
       
  7225 void Q3TableHeader::setSectionStretchable(int s, bool b)
       
  7226 {
       
  7227     if (stretchable[ s ] == b)
       
  7228         return;
       
  7229     stretchable[ s ] = b;
       
  7230     if (b)
       
  7231         numStretches++;
       
  7232     else
       
  7233         numStretches--;
       
  7234 }
       
  7235 
       
  7236 /*!
       
  7237     Returns true if section \a s is stretcheable; otherwise returns
       
  7238     false.
       
  7239 
       
  7240     \sa setSectionStretchable()
       
  7241 */
       
  7242 
       
  7243 bool Q3TableHeader::isSectionStretchable(int s) const
       
  7244 {
       
  7245     return stretchable[ s ];
       
  7246 }
       
  7247 
       
  7248 void Q3TableHeader::swapSections(int oldIdx, int newIdx, bool swapTable)
       
  7249 {
       
  7250     extern bool qt_qheader_label_return_null_strings; // qheader.cpp
       
  7251     qt_qheader_label_return_null_strings = true;
       
  7252 
       
  7253     QIconSet oldIconSet, newIconSet;
       
  7254     if (iconSet(oldIdx))
       
  7255         oldIconSet = *iconSet(oldIdx);
       
  7256     if (iconSet(newIdx))
       
  7257         newIconSet = *iconSet(newIdx);
       
  7258     QString oldLabel = label(oldIdx);
       
  7259     QString newLabel = label(newIdx);
       
  7260     bool sectionsHasContent = !(oldIconSet.isNull() && newIconSet.isNull()
       
  7261                             && oldLabel.isNull() && newLabel.isNull());
       
  7262     if (sectionsHasContent) {
       
  7263         Q3HeaderData *data = static_cast<Q3Header*>(this)->d;
       
  7264         bool oldNullLabel = qt_get_null_label_bit(data, oldIdx);
       
  7265         bool newNullLabel = qt_get_null_label_bit(data, newIdx);
       
  7266         setLabel(oldIdx, newIconSet, newLabel);
       
  7267         setLabel(newIdx, oldIconSet, oldLabel);
       
  7268         qt_set_null_label_bit(data, oldIdx, newNullLabel);
       
  7269         qt_set_null_label_bit(data, newIdx, oldNullLabel);
       
  7270     }
       
  7271 
       
  7272     qt_qheader_label_return_null_strings = false;
       
  7273 
       
  7274     int w1 = sectionSize(oldIdx);
       
  7275     int w2 = sectionSize(newIdx);
       
  7276     if (w1 != w2) {
       
  7277         resizeSection(oldIdx, w2);
       
  7278         resizeSection(newIdx, w1);
       
  7279     }
       
  7280 
       
  7281     if (!swapTable)
       
  7282         return;
       
  7283     if (orientation() == Horizontal)
       
  7284         table->swapColumns(oldIdx, newIdx);
       
  7285     else
       
  7286         table->swapRows(oldIdx, newIdx);
       
  7287 }
       
  7288 
       
  7289 void Q3TableHeader::indexChanged(int sec, int oldIdx, int newIdx)
       
  7290 {
       
  7291     newIdx = mapToIndex(sec);
       
  7292     if (oldIdx > newIdx)
       
  7293         moveSection(sec, oldIdx + 1);
       
  7294     else
       
  7295         moveSection(sec, oldIdx);
       
  7296 
       
  7297     if (oldIdx < newIdx) {
       
  7298         while (oldIdx < newIdx) {
       
  7299             swapSections(oldIdx, oldIdx + 1);
       
  7300             oldIdx++;
       
  7301         }
       
  7302     } else {
       
  7303         while (oldIdx > newIdx) {
       
  7304             swapSections(oldIdx - 1, oldIdx);
       
  7305             oldIdx--;
       
  7306         }
       
  7307     }
       
  7308 
       
  7309     table->repaintContents(table->contentsX(), table->contentsY(),
       
  7310                             table->visibleWidth(), table->visibleHeight());
       
  7311 }
       
  7312 
       
  7313 void Q3TableHeader::setLabels(const QStringList & labels)
       
  7314 {
       
  7315     int i = 0;
       
  7316     const int c = QMIN(count(), (int)labels.count());
       
  7317     bool updates = updatesEnabled();
       
  7318     if (updates)
       
  7319         setUpdatesEnabled(false);
       
  7320     for (QStringList::ConstIterator it = labels.begin(); i < c; ++i, ++it) {
       
  7321         if (i == c - 1) {
       
  7322             if (updates)
       
  7323                 setUpdatesEnabled(true);
       
  7324             setLabel(i, *it);
       
  7325         } else {
       
  7326             Q3Header::setLabel(i, *it);
       
  7327             emit sectionSizeChanged(i);
       
  7328         }
       
  7329     }
       
  7330 }
       
  7331 
       
  7332 QT_END_NAMESPACE
       
  7333 
       
  7334 #include "q3table.moc"