src/gui/text/qtexttable.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 QtGui 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 "qtexttable.h"
       
    43 #include "qtextcursor.h"
       
    44 #include "qtextformat.h"
       
    45 #include <qdebug.h>
       
    46 #include "qtexttable_p.h"
       
    47 #include "qvarlengtharray.h"
       
    48 #include "private/qfunctions_p.h"
       
    49 
       
    50 #include <stdlib.h>
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 
       
    54 /*!
       
    55     \class QTextTableCell
       
    56     \reentrant
       
    57 
       
    58     \brief The QTextTableCell class represents the properties of a
       
    59     cell in a QTextTable.
       
    60 
       
    61     \ingroup richtext-processing
       
    62 
       
    63     Table cells are pieces of document structure that belong to a table.
       
    64     The table orders cells into particular rows and columns; cells can
       
    65     also span multiple columns and rows.
       
    66 
       
    67     Cells are usually created when a table is inserted into a document with
       
    68     QTextCursor::insertTable(), but they are also created and destroyed when
       
    69     a table is resized.
       
    70 
       
    71     Cells contain information about their location in a table; you can
       
    72     obtain the row() and column() numbers of a cell, and its rowSpan()
       
    73     and columnSpan().
       
    74 
       
    75     The format() of a cell describes the default character format of its
       
    76     contents. The firstCursorPosition() and lastCursorPosition() functions
       
    77     are used to obtain the extent of the cell in the document.
       
    78 
       
    79     \sa QTextTable QTextTableFormat
       
    80 */
       
    81 
       
    82 /*!
       
    83     \fn QTextTableCell::QTextTableCell()
       
    84 
       
    85     Constructs an invalid table cell.
       
    86 
       
    87     \sa isValid()
       
    88 */
       
    89 
       
    90 /*!
       
    91     \fn QTextTableCell::QTextTableCell(const QTextTableCell &other)
       
    92 
       
    93     Copy constructor. Creates a new QTextTableCell object based on the
       
    94     \a other cell.
       
    95 */
       
    96 
       
    97 /*!
       
    98     \fn QTextTableCell& QTextTableCell::operator=(const QTextTableCell &other)
       
    99 
       
   100     Assigns the \a other table cell to this table cell.
       
   101 */
       
   102 
       
   103 /*!
       
   104     \since 4.2
       
   105 
       
   106     Sets the cell's character format to \a format. This can for example be used to change
       
   107     the background color of the entire cell:
       
   108 
       
   109     QTextTableCell cell = table->cellAt(2, 3);
       
   110     QTextCharFormat format = cell.format();
       
   111     format.setBackground(Qt::blue);
       
   112     cell.setFormat(format);
       
   113 
       
   114     Note that the cell's row or column span cannot be changed through this function. You have
       
   115     to use QTextTable::mergeCells and QTextTable::splitCell instead.
       
   116 
       
   117     \sa format()
       
   118 */
       
   119 void QTextTableCell::setFormat(const QTextCharFormat &format)
       
   120 {
       
   121     QTextCharFormat fmt = format;
       
   122     fmt.clearProperty(QTextFormat::ObjectIndex);
       
   123     fmt.setObjectType(QTextFormat::TableCellObject);
       
   124     QTextDocumentPrivate *p = table->docHandle();
       
   125     QTextDocumentPrivate::FragmentIterator frag(&p->fragmentMap(), fragment);
       
   126 
       
   127     QTextFormatCollection *c = p->formatCollection();
       
   128     QTextCharFormat oldFormat = c->charFormat(frag->format);
       
   129     fmt.setTableCellRowSpan(oldFormat.tableCellRowSpan());
       
   130     fmt.setTableCellColumnSpan(oldFormat.tableCellColumnSpan());
       
   131 
       
   132     p->setCharFormat(frag.position(), 1, fmt, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
       
   133 }
       
   134 
       
   135 /*!
       
   136     Returns the cell's character format.
       
   137 */
       
   138 QTextCharFormat QTextTableCell::format() const
       
   139 {
       
   140     QTextDocumentPrivate *p = table->docHandle();
       
   141     QTextFormatCollection *c = p->formatCollection();
       
   142 
       
   143     QTextCharFormat fmt = c->charFormat(tableCellFormatIndex());
       
   144     fmt.setObjectType(QTextFormat::TableCellObject);
       
   145     return fmt;
       
   146 }
       
   147 
       
   148 /*!
       
   149     \since 4.5
       
   150 
       
   151     Returns the index of the tableCell's format in the document's internal list of formats.
       
   152 
       
   153     \sa QTextDocument::allFormats()
       
   154 */
       
   155 int QTextTableCell::tableCellFormatIndex() const
       
   156 {
       
   157     QTextDocumentPrivate *p = table->docHandle();
       
   158     return QTextDocumentPrivate::FragmentIterator(&p->fragmentMap(), fragment)->format;
       
   159 }
       
   160 
       
   161 /*!
       
   162     Returns the number of the row in the table that contains this cell.
       
   163 
       
   164     \sa column()
       
   165 */
       
   166 int QTextTableCell::row() const
       
   167 {
       
   168     const QTextTablePrivate *tp = table->d_func();
       
   169     if (tp->dirty)
       
   170         tp->update();
       
   171 
       
   172     int idx = tp->findCellIndex(fragment);
       
   173     if (idx == -1)
       
   174         return idx;
       
   175     return tp->cellIndices.at(idx) / tp->nCols;
       
   176 }
       
   177 
       
   178 /*!
       
   179     Returns the number of the column in the table that contains this cell.
       
   180 
       
   181     \sa row()
       
   182 */
       
   183 int QTextTableCell::column() const
       
   184 {
       
   185     const QTextTablePrivate *tp = table->d_func();
       
   186     if (tp->dirty)
       
   187         tp->update();
       
   188 
       
   189     int idx = tp->findCellIndex(fragment);
       
   190     if (idx == -1)
       
   191         return idx;
       
   192     return tp->cellIndices.at(idx) % tp->nCols;
       
   193 }
       
   194 
       
   195 /*!
       
   196     Returns the number of rows this cell spans. The default is 1.
       
   197 
       
   198     \sa columnSpan()
       
   199 */
       
   200 int QTextTableCell::rowSpan() const
       
   201 {
       
   202     return format().tableCellRowSpan();
       
   203 }
       
   204 
       
   205 /*!
       
   206     Returns the number of columns this cell spans. The default is 1.
       
   207 
       
   208     \sa rowSpan()
       
   209 */
       
   210 int QTextTableCell::columnSpan() const
       
   211 {
       
   212     return format().tableCellColumnSpan();
       
   213 }
       
   214 
       
   215 /*!
       
   216     \fn bool QTextTableCell::isValid() const
       
   217 
       
   218     Returns true if this is a valid table cell; otherwise returns
       
   219     false.
       
   220 */
       
   221 
       
   222 
       
   223 /*!
       
   224     Returns the first valid cursor position in this cell.
       
   225 
       
   226     \sa lastCursorPosition()
       
   227 */
       
   228 QTextCursor QTextTableCell::firstCursorPosition() const
       
   229 {
       
   230     return QTextCursor(table->d_func()->pieceTable, firstPosition());
       
   231 }
       
   232 
       
   233 /*!
       
   234     Returns the last valid cursor position in this cell.
       
   235 
       
   236     \sa firstCursorPosition()
       
   237 */
       
   238 QTextCursor QTextTableCell::lastCursorPosition() const
       
   239 {
       
   240     return QTextCursor(table->d_func()->pieceTable, lastPosition());
       
   241 }
       
   242 
       
   243 
       
   244 /*!
       
   245     \internal
       
   246 
       
   247     Returns the first valid position in the document occupied by this cell.
       
   248 */
       
   249 int QTextTableCell::firstPosition() const
       
   250 {
       
   251     QTextDocumentPrivate *p = table->docHandle();
       
   252     return p->fragmentMap().position(fragment) + 1;
       
   253 }
       
   254 
       
   255 /*!
       
   256     \internal
       
   257 
       
   258     Returns the last valid position in the document occupied by this cell.
       
   259 */
       
   260 int QTextTableCell::lastPosition() const
       
   261 {
       
   262     QTextDocumentPrivate *p = table->docHandle();
       
   263     const QTextTablePrivate *td = table->d_func();
       
   264     int index = table->d_func()->findCellIndex(fragment);
       
   265     int f;
       
   266     if (index != -1)
       
   267         f = td->cells.value(index + 1, td->fragment_end);
       
   268     else
       
   269         f = td->fragment_end;
       
   270     return p->fragmentMap().position(f);
       
   271 }
       
   272 
       
   273 
       
   274 /*!
       
   275     Returns a frame iterator pointing to the beginning of the table's cell.
       
   276 
       
   277     \sa end()
       
   278 */
       
   279 QTextFrame::iterator QTextTableCell::begin() const
       
   280 {
       
   281     QTextDocumentPrivate *p = table->docHandle();
       
   282     int b = p->blockMap().findNode(firstPosition());
       
   283     int e = p->blockMap().findNode(lastPosition()+1);
       
   284     return QTextFrame::iterator(const_cast<QTextTable *>(table), b, b, e);
       
   285 }
       
   286 
       
   287 /*!
       
   288     Returns a frame iterator pointing to the end of the table's cell.
       
   289 
       
   290     \sa begin()
       
   291 */
       
   292 QTextFrame::iterator QTextTableCell::end() const
       
   293 {
       
   294     QTextDocumentPrivate *p = table->docHandle();
       
   295     int b = p->blockMap().findNode(firstPosition());
       
   296     int e = p->blockMap().findNode(lastPosition()+1);
       
   297     return QTextFrame::iterator(const_cast<QTextTable *>(table), e, b, e);
       
   298 }
       
   299 
       
   300 
       
   301 /*!
       
   302     \fn QTextCursor QTextTableCell::operator==(const QTextTableCell &other) const
       
   303 
       
   304     Returns true if this cell object and the \a other cell object
       
   305     describe the same cell; otherwise returns false.
       
   306 */
       
   307 
       
   308 /*!
       
   309     \fn QTextCursor QTextTableCell::operator!=(const QTextTableCell &other) const
       
   310 
       
   311     Returns true if this cell object and the \a other cell object
       
   312     describe different cells; otherwise returns false.
       
   313 */
       
   314 
       
   315 /*!
       
   316     \fn QTextTableCell::~QTextTableCell()
       
   317 
       
   318     Destroys the table cell.
       
   319 */
       
   320 
       
   321 QTextTablePrivate::~QTextTablePrivate()
       
   322 {
       
   323     if (grid)
       
   324         free(grid);
       
   325 }
       
   326 
       
   327 
       
   328 QTextTable *QTextTablePrivate::createTable(QTextDocumentPrivate *pieceTable, int pos, int rows, int cols, const QTextTableFormat &tableFormat)
       
   329 {
       
   330     QTextTableFormat fmt = tableFormat;
       
   331     fmt.setColumns(cols);
       
   332     QTextTable *table = qobject_cast<QTextTable *>(pieceTable->createObject(fmt));
       
   333     Q_ASSERT(table);
       
   334 
       
   335     pieceTable->beginEditBlock();
       
   336 
       
   337 //     qDebug("---> createTable: rows=%d, cols=%d at %d", rows, cols, pos);
       
   338     // add block after table
       
   339     QTextCharFormat charFmt;
       
   340     charFmt.setObjectIndex(table->objectIndex());
       
   341     charFmt.setObjectType(QTextFormat::TableCellObject);
       
   342 
       
   343 
       
   344     int charIdx = pieceTable->formatCollection()->indexForFormat(charFmt);
       
   345     int cellIdx = pieceTable->formatCollection()->indexForFormat(QTextBlockFormat());
       
   346 
       
   347     QTextTablePrivate *d = table->d_func();
       
   348     d->blockFragmentUpdates = true;
       
   349 
       
   350     d->fragment_start = pieceTable->insertBlock(QTextBeginningOfFrame, pos, cellIdx, charIdx);
       
   351     d->cells.append(d->fragment_start);
       
   352     ++pos;
       
   353 
       
   354     for (int i = 1; i < rows*cols; ++i) {
       
   355         d->cells.append(pieceTable->insertBlock(QTextBeginningOfFrame, pos, cellIdx, charIdx));
       
   356 // 	    qDebug("      addCell at %d", pos);
       
   357         ++pos;
       
   358     }
       
   359 
       
   360     d->fragment_end = pieceTable->insertBlock(QTextEndOfFrame, pos, cellIdx, charIdx);
       
   361 // 	qDebug("      addEOR at %d", pos);
       
   362     ++pos;
       
   363 
       
   364     d->blockFragmentUpdates = false;
       
   365     d->dirty = true;
       
   366 
       
   367     pieceTable->endEditBlock();
       
   368 
       
   369     return table;
       
   370 }
       
   371 
       
   372 struct QFragmentFindHelper
       
   373 {
       
   374     inline QFragmentFindHelper(int _pos, const QTextDocumentPrivate::FragmentMap &map)
       
   375         : pos(_pos), fragmentMap(map) {}
       
   376     uint pos;
       
   377     const QTextDocumentPrivate::FragmentMap &fragmentMap;
       
   378 };
       
   379 
       
   380 Q_STATIC_GLOBAL_INLINE_OPERATOR bool operator<(int fragment, const QFragmentFindHelper &helper)
       
   381 {
       
   382     return helper.fragmentMap.position(fragment) < helper.pos;
       
   383 }
       
   384 
       
   385 Q_STATIC_GLOBAL_INLINE_OPERATOR bool operator<(const QFragmentFindHelper &helper, int fragment)
       
   386 {
       
   387     return helper.pos < helper.fragmentMap.position(fragment);
       
   388 }
       
   389 
       
   390 int QTextTablePrivate::findCellIndex(int fragment) const
       
   391 {
       
   392     QFragmentFindHelper helper(pieceTable->fragmentMap().position(fragment),
       
   393                               pieceTable->fragmentMap());
       
   394     QList<int>::ConstIterator it = qBinaryFind(cells.begin(), cells.end(), helper);
       
   395     if (it == cells.end())
       
   396         return -1;
       
   397     return it - cells.begin();
       
   398 }
       
   399 
       
   400 void QTextTablePrivate::fragmentAdded(const QChar &type, uint fragment)
       
   401 {
       
   402     dirty = true;
       
   403     if (blockFragmentUpdates)
       
   404         return;
       
   405     if (type == QTextBeginningOfFrame) {
       
   406         Q_ASSERT(cells.indexOf(fragment) == -1);
       
   407         const uint pos = pieceTable->fragmentMap().position(fragment);
       
   408         QFragmentFindHelper helper(pos, pieceTable->fragmentMap());
       
   409         QList<int>::Iterator it = qLowerBound(cells.begin(), cells.end(), helper);
       
   410         cells.insert(it, fragment);
       
   411         if (!fragment_start || pos < pieceTable->fragmentMap().position(fragment_start))
       
   412             fragment_start = fragment;
       
   413         return;
       
   414     }
       
   415     QTextFramePrivate::fragmentAdded(type, fragment);
       
   416 }
       
   417 
       
   418 void QTextTablePrivate::fragmentRemoved(const QChar &type, uint fragment)
       
   419 {
       
   420     dirty = true;
       
   421     if (blockFragmentUpdates)
       
   422         return;
       
   423     if (type == QTextBeginningOfFrame) {
       
   424         Q_ASSERT(cells.indexOf(fragment) != -1);
       
   425         cells.removeAll(fragment);
       
   426         if (fragment_start == fragment && cells.size()) {
       
   427             fragment_start = cells.at(0);
       
   428         }
       
   429         if (fragment_start != fragment)
       
   430             return;
       
   431     }
       
   432     QTextFramePrivate::fragmentRemoved(type, fragment);
       
   433 }
       
   434 
       
   435 /*!
       
   436     /fn void QTextTablePrivate::update() const
       
   437 
       
   438     This function is usually called when the table is "dirty".
       
   439     It seems to update all kind of table information.
       
   440 
       
   441 */
       
   442 void QTextTablePrivate::update() const
       
   443 {
       
   444     Q_Q(const QTextTable);
       
   445     nCols = q->format().columns();
       
   446     nRows = (cells.size() + nCols-1)/nCols;
       
   447 //     qDebug(">>>> QTextTablePrivate::update, nRows=%d, nCols=%d", nRows, nCols);
       
   448 
       
   449     grid = q_check_ptr((int *)realloc(grid, nRows*nCols*sizeof(int)));
       
   450     memset(grid, 0, nRows*nCols*sizeof(int));
       
   451 
       
   452     QTextDocumentPrivate *p = pieceTable;
       
   453     QTextFormatCollection *c = p->formatCollection();
       
   454 
       
   455     cellIndices.resize(cells.size());
       
   456 
       
   457     int cell = 0;
       
   458     for (int i = 0; i < cells.size(); ++i) {
       
   459         int fragment = cells.at(i);
       
   460         QTextCharFormat fmt = c->charFormat(QTextDocumentPrivate::FragmentIterator(&p->fragmentMap(), fragment)->format);
       
   461         int rowspan = fmt.tableCellRowSpan();
       
   462         int colspan = fmt.tableCellColumnSpan();
       
   463 
       
   464         // skip taken cells
       
   465         while (cell < nRows*nCols && grid[cell])
       
   466             ++cell;
       
   467 
       
   468         int r = cell/nCols;
       
   469         int c = cell%nCols;
       
   470         cellIndices[i] = cell;
       
   471 
       
   472         if (r + rowspan > nRows) {
       
   473             grid = q_check_ptr((int *)realloc(grid, sizeof(int)*(r + rowspan)*nCols));
       
   474             memset(grid + (nRows*nCols), 0, sizeof(int)*(r+rowspan-nRows)*nCols);
       
   475             nRows = r + rowspan;
       
   476         }
       
   477 
       
   478         Q_ASSERT(c + colspan <= nCols);
       
   479         for (int ii = 0; ii < rowspan; ++ii) {
       
   480             for (int jj = 0; jj < colspan; ++jj) {
       
   481                 Q_ASSERT(grid[(r+ii)*nCols + c+jj] == 0);
       
   482                 grid[(r+ii)*nCols + c+jj] = fragment;
       
   483 //  		    qDebug("    setting cell %d span=%d/%d at %d/%d", fragment, rowspan, colspan, r+ii, c+jj);
       
   484             }
       
   485         }
       
   486     }
       
   487 //     qDebug("<<<< end: nRows=%d, nCols=%d", nRows, nCols);
       
   488 
       
   489     dirty = false;
       
   490 }
       
   491 
       
   492 
       
   493 
       
   494 
       
   495 
       
   496 /*!
       
   497     \class QTextTable
       
   498     \reentrant
       
   499 
       
   500     \brief The QTextTable class represents a table in a QTextDocument.
       
   501 
       
   502     \ingroup richtext-processing
       
   503 
       
   504     A table is a group of cells ordered into rows and columns. Each table
       
   505     contains at least one row and one column. Each cell contains a block, and
       
   506     is surrounded by a frame.
       
   507 
       
   508     Tables are usually created and inserted into a document with the
       
   509     QTextCursor::insertTable() function.
       
   510     For example, we can insert a table with three rows and two columns at the
       
   511     current cursor position in an editor using the following lines of code:
       
   512 
       
   513     \snippet doc/src/snippets/textdocument-tables/mainwindow.cpp 1
       
   514     \codeline
       
   515     \snippet doc/src/snippets/textdocument-tables/mainwindow.cpp 3
       
   516 
       
   517     The table format is either defined when the table is created or changed
       
   518     later with setFormat().
       
   519 
       
   520     The table currently being edited by the cursor is found with
       
   521     QTextCursor::currentTable(). This allows its format or dimensions to be
       
   522     changed after it has been inserted into a document.
       
   523 
       
   524     A table's size can be changed with resize(), or by using
       
   525     insertRows(), insertColumns(), removeRows(), or removeColumns().
       
   526     Use cellAt() to retrieve table cells.
       
   527 
       
   528     The starting and ending positions of table rows can be found by moving
       
   529     a cursor within a table, and using the rowStart() and rowEnd() functions
       
   530     to obtain cursors at the start and end of each row.
       
   531 
       
   532     Rows and columns within a QTextTable can be merged and split using
       
   533     the mergeCells() and splitCell() functions. However, only cells that span multiple
       
   534     rows or columns can be split. (Merging or splitting does not increase or decrease
       
   535     the number of rows and columns.) 
       
   536 
       
   537     Note that if you have merged multiple columns and rows into one cell, you will not
       
   538     be able to split the merged cell into new cells spanning over more than one row 
       
   539     or column. To be able to split cells spanning over several rows and columns you 
       
   540     need to do this over several iterations.
       
   541 
       
   542     \table 80%
       
   543     \row
       
   544         \o \inlineimage texttable-split.png Original Table
       
   545         \o Suppose we have a 2x3 table of names and addresses. To merge both
       
   546         columns in the first row we invoke mergeCells() with \a row = 0,
       
   547         \a column = 0, \a numRows = 1 and \a numColumns = 2.
       
   548         \snippet doc/src/snippets/textdocument-texttable/main.cpp 0
       
   549 
       
   550     \row
       
   551         \o \inlineimage texttable-merge.png
       
   552         \o  This gives us the following table. To split the first row of the table
       
   553         back into two cells, we invoke the splitCell() function with \a numRows
       
   554         and \a numCols = 1.
       
   555         \snippet doc/src/snippets/textdocument-texttable/main.cpp 1
       
   556 
       
   557     \row
       
   558         \o \inlineimage texttable-split.png Split Table
       
   559         \o This results in the original table.
       
   560     \endtable
       
   561 
       
   562     \sa QTextTableFormat
       
   563 */
       
   564 
       
   565 /*! \internal
       
   566  */
       
   567 QTextTable::QTextTable(QTextDocument *doc)
       
   568     : QTextFrame(*new QTextTablePrivate(doc), doc)
       
   569 {
       
   570 }
       
   571 
       
   572 /*! \internal
       
   573 
       
   574 Destroys the table.
       
   575  */
       
   576 QTextTable::~QTextTable()
       
   577 {
       
   578 }
       
   579 
       
   580 
       
   581 /*!
       
   582     \fn QTextTableCell QTextTable::cellAt(int row, int column) const
       
   583 
       
   584     Returns the table cell at the given \a row and \a column in the table.
       
   585 
       
   586     \sa columns() rows()
       
   587 */
       
   588 QTextTableCell QTextTable::cellAt(int row, int col) const
       
   589 {
       
   590     Q_D(const QTextTable);
       
   591     if (d->dirty)
       
   592         d->update();
       
   593 
       
   594     if (row < 0 || row >= d->nRows || col < 0 || col >= d->nCols)
       
   595         return QTextTableCell();
       
   596 
       
   597     return QTextTableCell(this, d->grid[row*d->nCols + col]);
       
   598 }
       
   599 
       
   600 /*!
       
   601     \overload
       
   602 
       
   603     Returns the table cell that contains the character at the given \a position
       
   604     in the document.
       
   605 */
       
   606 QTextTableCell QTextTable::cellAt(int position) const
       
   607 {
       
   608     Q_D(const QTextTable);
       
   609     if (d->dirty)
       
   610         d->update();
       
   611 
       
   612     uint pos = (uint)position;
       
   613     const QTextDocumentPrivate::FragmentMap &map = d->pieceTable->fragmentMap();
       
   614     if (position < 0 || map.position(d->fragment_start) >= pos || map.position(d->fragment_end) < pos)
       
   615         return QTextTableCell();
       
   616 
       
   617     QFragmentFindHelper helper(position, map);
       
   618     QList<int>::ConstIterator it = qLowerBound(d->cells.begin(), d->cells.end(), helper);
       
   619     if (it != d->cells.begin())
       
   620         --it;
       
   621 
       
   622     return QTextTableCell(this, *it);
       
   623 }
       
   624 
       
   625 /*!
       
   626     \fn QTextTableCell QTextTable::cellAt(const QTextCursor &cursor) const
       
   627 
       
   628     \overload
       
   629 
       
   630     Returns the table cell containing the given \a cursor.
       
   631 */
       
   632 QTextTableCell QTextTable::cellAt(const QTextCursor &c) const
       
   633 {
       
   634     return cellAt(c.position());
       
   635 }
       
   636 
       
   637 /*!
       
   638     \fn void QTextTable::resize(int rows, int columns)
       
   639 
       
   640     Resizes the table to contain the required number of \a rows and \a columns.
       
   641 
       
   642     \sa insertRows() insertColumns() removeRows() removeColumns()
       
   643 */
       
   644 void QTextTable::resize(int rows, int cols)
       
   645 {
       
   646     Q_D(QTextTable);
       
   647     if (d->dirty)
       
   648         d->update();
       
   649 
       
   650     int nRows = this->rows();
       
   651     int nCols = this->columns();
       
   652 
       
   653     if (rows == nRows && cols == nCols)
       
   654 	return;
       
   655 
       
   656     d->pieceTable->beginEditBlock();
       
   657 
       
   658     if (nCols < cols)
       
   659         insertColumns(nCols, cols - nCols);
       
   660     else if (nCols > cols)
       
   661         removeColumns(cols, nCols - cols);
       
   662 
       
   663     if (nRows < rows)
       
   664         insertRows(nRows, rows-nRows);
       
   665     else if (nRows > rows)
       
   666         removeRows(rows, nRows-rows);
       
   667 
       
   668     d->pieceTable->endEditBlock();
       
   669 }
       
   670 
       
   671 /*!
       
   672     \fn void QTextTable::insertRows(int index, int rows)
       
   673 
       
   674     Inserts a number of \a rows before the row with the specified \a index.
       
   675 
       
   676     \sa resize() insertColumns() removeRows() removeColumns() appendRows() appendColumns()
       
   677 */
       
   678 void QTextTable::insertRows(int pos, int num)
       
   679 {
       
   680     Q_D(QTextTable);
       
   681     if (num <= 0)
       
   682 	return;
       
   683 
       
   684     if (d->dirty)
       
   685         d->update();
       
   686 
       
   687     if (pos > d->nRows || pos < 0)
       
   688         pos = d->nRows;
       
   689 
       
   690 //     qDebug() << "-------- insertRows" << pos << num;
       
   691     QTextDocumentPrivate *p = d->pieceTable;
       
   692     QTextFormatCollection *c = p->formatCollection();
       
   693     p->beginEditBlock();
       
   694 
       
   695     int extended = 0;
       
   696     int insert_before = 0;
       
   697     if (pos > 0 && pos < d->nRows) {
       
   698         for (int i = 0; i < d->nCols; ++i) {
       
   699             int cell = d->grid[pos*d->nCols + i];
       
   700             if (cell == d->grid[(pos-1)*d->nCols+i]) {
       
   701                 // cell spans the insertion place, extend it
       
   702                 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
       
   703                 QTextCharFormat fmt = c->charFormat(it->format);
       
   704                 fmt.setTableCellRowSpan(fmt.tableCellRowSpan() + num);
       
   705                 p->setCharFormat(it.position(), 1, fmt);
       
   706                 extended++;
       
   707             } else if (!insert_before) {
       
   708                 insert_before = cell;
       
   709             }
       
   710         }
       
   711     } else {
       
   712         insert_before = (pos == 0 ? d->grid[0] : d->fragment_end);
       
   713     }
       
   714     if (extended < d->nCols) {
       
   715         Q_ASSERT(insert_before);
       
   716         QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), insert_before);
       
   717         QTextCharFormat fmt = c->charFormat(it->format);
       
   718         fmt.setTableCellRowSpan(1);
       
   719         fmt.setTableCellColumnSpan(1);
       
   720         Q_ASSERT(fmt.objectIndex() == objectIndex());
       
   721         int pos = it.position();
       
   722         int cfmt = p->formatCollection()->indexForFormat(fmt);
       
   723         int bfmt = p->formatCollection()->indexForFormat(QTextBlockFormat());
       
   724 //         qDebug("inserting %d cells, nCols=%d extended=%d", num*(d->nCols-extended), d->nCols, extended);
       
   725         for (int i = 0; i < num*(d->nCols-extended); ++i)
       
   726             p->insertBlock(QTextBeginningOfFrame, pos, bfmt, cfmt, QTextUndoCommand::MoveCursor);
       
   727     }
       
   728 
       
   729 //     qDebug() << "-------- end insertRows" << pos << num;
       
   730     p->endEditBlock();
       
   731 }
       
   732 
       
   733 /*!
       
   734     \fn void QTextTable::insertColumns(int index, int columns)
       
   735 
       
   736     Inserts a number of \a columns before the column with the specified \a index.
       
   737 
       
   738     \sa insertRows() resize() removeRows() removeColumns() appendRows() appendColumns()
       
   739 */
       
   740 void QTextTable::insertColumns(int pos, int num)
       
   741 {
       
   742     Q_D(QTextTable);
       
   743     if (num <= 0)
       
   744 	return;
       
   745 
       
   746     if (d->dirty)
       
   747         d->update();
       
   748 
       
   749     if (pos > d->nCols || pos < 0)
       
   750         pos = d->nCols;
       
   751 
       
   752 //     qDebug() << "-------- insertCols" << pos << num;
       
   753     QTextDocumentPrivate *p = d->pieceTable;
       
   754     QTextFormatCollection *c = p->formatCollection();
       
   755     p->beginEditBlock();
       
   756 
       
   757     for (int i = 0; i < d->nRows; ++i) {
       
   758         int cell;
       
   759         if (i == d->nRows - 1 && pos == d->nCols)
       
   760             cell = d->fragment_end;
       
   761         else
       
   762             cell = d->grid[i*d->nCols + pos];
       
   763         QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
       
   764         QTextCharFormat fmt = c->charFormat(it->format);
       
   765         if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) {
       
   766             // cell spans the insertion place, extend it
       
   767             fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num);
       
   768             p->setCharFormat(it.position(), 1, fmt);
       
   769         } else {
       
   770             fmt.setTableCellRowSpan(1);
       
   771             fmt.setTableCellColumnSpan(1);
       
   772             Q_ASSERT(fmt.objectIndex() == objectIndex());
       
   773             int position = it.position();
       
   774             int cfmt = p->formatCollection()->indexForFormat(fmt);
       
   775             int bfmt = p->formatCollection()->indexForFormat(QTextBlockFormat());
       
   776             for (int i = 0; i < num; ++i)
       
   777                 p->insertBlock(QTextBeginningOfFrame, position, bfmt, cfmt, QTextUndoCommand::MoveCursor);
       
   778         }
       
   779     }
       
   780 
       
   781     QTextTableFormat tfmt = format();
       
   782     tfmt.setColumns(tfmt.columns()+num);
       
   783     QVector<QTextLength> columnWidths = tfmt.columnWidthConstraints();
       
   784     if (! columnWidths.isEmpty()) {
       
   785         for (int i = num; i > 0; --i)
       
   786             columnWidths.insert(pos, columnWidths[qMax(0, pos-1)]);
       
   787     }
       
   788     tfmt.setColumnWidthConstraints (columnWidths);
       
   789     QTextObject::setFormat(tfmt);
       
   790 
       
   791 //     qDebug() << "-------- end insertCols" << pos << num;
       
   792     p->endEditBlock();
       
   793 }
       
   794 
       
   795 /*!
       
   796     \since 4.5
       
   797     Appends \a count rows at the bottom of the table.
       
   798 
       
   799     \sa insertColumns() insertRows() resize() removeRows() removeColumns() appendColumns()
       
   800 */
       
   801 void QTextTable::appendRows(int count)
       
   802 {
       
   803     insertRows(rows(), count);
       
   804 }
       
   805 
       
   806 /*!
       
   807     \since 4.5
       
   808     Appends \a count columns at the right side of the table.
       
   809 
       
   810     \sa insertColumns() insertRows() resize() removeRows() removeColumns() appendRows()
       
   811 */
       
   812 void QTextTable::appendColumns(int count)
       
   813 {
       
   814     insertColumns(columns(), count);
       
   815 }
       
   816 
       
   817 /*!
       
   818     \fn void QTextTable::removeRows(int index, int rows)
       
   819 
       
   820     Removes a number of \a rows starting with the row at the specified \a index.
       
   821 
       
   822     \sa insertRows(), insertColumns(), resize(), removeColumns() appendRows() appendColumns()
       
   823 */
       
   824 void QTextTable::removeRows(int pos, int num)
       
   825 {
       
   826     Q_D(QTextTable);
       
   827 //     qDebug() << "-------- removeRows" << pos << num;
       
   828 
       
   829     if (num <= 0 || pos < 0)
       
   830         return;
       
   831     if (d->dirty)
       
   832         d->update();
       
   833     if (pos >= d->nRows)
       
   834         return;
       
   835     if (pos+num > d->nRows)
       
   836         num = d->nRows - pos;
       
   837 
       
   838     QTextDocumentPrivate *p = d->pieceTable;
       
   839     QTextFormatCollection *collection = p->formatCollection();
       
   840     p->beginEditBlock();
       
   841 
       
   842     // delete whole table?
       
   843     if (pos == 0 && num == d->nRows) {
       
   844         const int pos = p->fragmentMap().position(d->fragment_start);
       
   845         p->remove(pos, p->fragmentMap().position(d->fragment_end) - pos + 1);
       
   846         p->endEditBlock();
       
   847         return;
       
   848     }
       
   849 
       
   850     p->aboutToRemoveCell(cellAt(pos, 0).firstPosition(), cellAt(pos + num - 1, d->nCols - 1).lastPosition());
       
   851 
       
   852     QList<int> touchedCells;
       
   853     for (int r = pos; r < pos + num; ++r) {
       
   854         for (int c = 0; c < d->nCols; ++c) {
       
   855             int cell = d->grid[r*d->nCols + c];
       
   856             if (touchedCells.contains(cell))
       
   857                 continue;
       
   858             touchedCells << cell;
       
   859             QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
       
   860             QTextCharFormat fmt = collection->charFormat(it->format);
       
   861             int span = fmt.tableCellRowSpan();
       
   862             if (span > 1) {
       
   863                 fmt.setTableCellRowSpan(span - 1);
       
   864                 p->setCharFormat(it.position(), 1, fmt);
       
   865             } else {
       
   866                 // remove cell
       
   867                 int index = d->cells.indexOf(cell) + 1;
       
   868                 int f_end = index < d->cells.size() ? d->cells.at(index) : d->fragment_end;
       
   869                 p->remove(it.position(), p->fragmentMap().position(f_end) - it.position());
       
   870             }
       
   871         }
       
   872     }
       
   873 
       
   874     p->endEditBlock();
       
   875 //     qDebug() << "-------- end removeRows" << pos << num;
       
   876 }
       
   877 
       
   878 /*!
       
   879     \fn void QTextTable::removeColumns(int index, int columns)
       
   880 
       
   881     Removes a number of \a columns starting with the column at the specified
       
   882     \a index.
       
   883 
       
   884     \sa insertRows() insertColumns() removeRows() resize() appendRows() appendColumns()
       
   885 */
       
   886 void QTextTable::removeColumns(int pos, int num)
       
   887 {
       
   888     Q_D(QTextTable);
       
   889 //     qDebug() << "-------- removeCols" << pos << num;
       
   890 
       
   891     if (num <= 0 || pos < 0)
       
   892 	return;
       
   893     if (d->dirty)
       
   894         d->update();
       
   895     if (pos >= d->nCols)
       
   896         return;
       
   897     if (pos + num > d->nCols)
       
   898         pos = d->nCols - num;
       
   899 
       
   900     QTextDocumentPrivate *p = d->pieceTable;
       
   901     QTextFormatCollection *collection = p->formatCollection();
       
   902     p->beginEditBlock();
       
   903 
       
   904     // delete whole table?
       
   905     if (pos == 0 && num == d->nCols) {
       
   906         const int pos = p->fragmentMap().position(d->fragment_start);
       
   907         p->remove(pos, p->fragmentMap().position(d->fragment_end) - pos + 1);
       
   908         p->endEditBlock();
       
   909         return;
       
   910     }
       
   911 
       
   912     p->aboutToRemoveCell(cellAt(0, pos).firstPosition(), cellAt(d->nRows - 1, pos + num - 1).lastPosition());
       
   913 
       
   914     QList<int> touchedCells;
       
   915     for (int r = 0; r < d->nRows; ++r) {
       
   916         for (int c = pos; c < pos + num; ++c) {
       
   917             int cell = d->grid[r*d->nCols + c];
       
   918             if (touchedCells.contains(cell))
       
   919                 continue;
       
   920             touchedCells << cell;
       
   921             QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
       
   922             QTextCharFormat fmt = collection->charFormat(it->format);
       
   923             int span = fmt.tableCellColumnSpan();
       
   924             if (span > 1) {
       
   925                 fmt.setTableCellColumnSpan(span - 1);
       
   926                 p->setCharFormat(it.position(), 1, fmt);
       
   927             } else {
       
   928                 // remove cell
       
   929                 int index = d->cells.indexOf(cell) + 1;
       
   930                 int f_end = index < d->cells.size() ? d->cells.at(index) : d->fragment_end;
       
   931                 p->remove(it.position(), p->fragmentMap().position(f_end) - it.position());
       
   932             }
       
   933         }
       
   934     }
       
   935 
       
   936     QTextTableFormat tfmt = format();
       
   937     tfmt.setColumns(tfmt.columns()-num);
       
   938     QVector<QTextLength> columnWidths = tfmt.columnWidthConstraints();
       
   939     if (columnWidths.count() > pos) {
       
   940         columnWidths.remove(pos, num);
       
   941         tfmt.setColumnWidthConstraints (columnWidths);
       
   942     }
       
   943     QTextObject::setFormat(tfmt);
       
   944 
       
   945     p->endEditBlock();
       
   946 //     qDebug() << "-------- end removeCols" << pos << num;
       
   947 }
       
   948 
       
   949 /*!
       
   950     \since 4.1
       
   951 
       
   952     Merges the cell at the specified \a row and \a column with the adjacent cells
       
   953     into one cell. The new cell will span \a numRows rows and \a numCols columns.
       
   954     If \a numRows or \a numCols is less than the current number of rows or columns
       
   955     the cell spans then this method does nothing.
       
   956 
       
   957     \sa splitCell()
       
   958 */
       
   959 void QTextTable::mergeCells(int row, int column, int numRows, int numCols)
       
   960 {
       
   961     Q_D(QTextTable);
       
   962 
       
   963     if (d->dirty)
       
   964         d->update();
       
   965 
       
   966     QTextDocumentPrivate *p = d->pieceTable;
       
   967     QTextFormatCollection *fc = p->formatCollection();
       
   968 
       
   969     const QTextTableCell cell = cellAt(row, column);
       
   970     if (!cell.isValid() || row != cell.row() || column != cell.column())
       
   971         return;
       
   972 
       
   973     QTextCharFormat fmt = cell.format();
       
   974     const int rowSpan = fmt.tableCellRowSpan();
       
   975     const int colSpan = fmt.tableCellColumnSpan();
       
   976 
       
   977     numRows = qMin(numRows, rows() - cell.row());
       
   978     numCols = qMin(numCols, columns() - cell.column());
       
   979 
       
   980     // nothing to merge?
       
   981     if (numRows < rowSpan || numCols < colSpan)
       
   982         return;
       
   983 
       
   984     // check the edges of the merge rect to make sure no cell spans the edge
       
   985     for (int r = row; r < row + numRows; ++r) {
       
   986         if (cellAt(r, column) == cellAt(r, column - 1))
       
   987             return;
       
   988         if (cellAt(r, column + numCols) == cellAt(r, column + numCols - 1))
       
   989             return;
       
   990     }
       
   991 
       
   992     for (int c = column; c < column + numCols; ++c) {
       
   993         if (cellAt(row, c) == cellAt(row - 1, c))
       
   994             return;
       
   995         if (cellAt(row + numRows, c) == cellAt(row + numRows - 1, c))
       
   996             return;
       
   997     }
       
   998 
       
   999     p->beginEditBlock();
       
  1000 
       
  1001     const int origCellPosition = cell.firstPosition() - 1;
       
  1002 
       
  1003     const int cellFragment = d->grid[row * d->nCols + column];
       
  1004 
       
  1005     // find the position at which to insert the contents of the merged cells
       
  1006     QFragmentFindHelper helper(origCellPosition, p->fragmentMap());
       
  1007     QList<int>::Iterator it = qBinaryFind(d->cells.begin(), d->cells.end(), helper);
       
  1008     Q_ASSERT(it != d->cells.end());
       
  1009     Q_ASSERT(*it == cellFragment);
       
  1010     const int insertCellIndex = it - d->cells.begin();
       
  1011     int insertFragment = d->cells.value(insertCellIndex + 1, d->fragment_end);
       
  1012     uint insertPos = p->fragmentMap().position(insertFragment);
       
  1013 
       
  1014     d->blockFragmentUpdates = true;
       
  1015 
       
  1016     bool rowHasText = cell.firstCursorPosition().block().length();
       
  1017     bool needsParagraph = rowHasText && colSpan == numCols;
       
  1018 
       
  1019     // find all cells that will be erased by the merge
       
  1020     for (int r = row; r < row + numRows; ++r) {
       
  1021         int firstColumn = r < row + rowSpan ? column + colSpan : column;
       
  1022 
       
  1023         // don't recompute the cell index for the first row
       
  1024         int firstCellIndex = r == row ? insertCellIndex + 1 : -1;
       
  1025         int cellIndex = firstCellIndex;
       
  1026 
       
  1027         for (int c = firstColumn; c < column + numCols; ++c) {
       
  1028             const int fragment = d->grid[r * d->nCols + c];
       
  1029 
       
  1030             // already handled?
       
  1031             if (fragment == cellFragment)
       
  1032                 continue;
       
  1033 
       
  1034             QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), fragment);
       
  1035             uint pos = it.position();
       
  1036 
       
  1037             if (firstCellIndex == -1) {
       
  1038                 QFragmentFindHelper helper(pos, p->fragmentMap());
       
  1039                 QList<int>::Iterator it = qBinaryFind(d->cells.begin(), d->cells.end(), helper);
       
  1040                 Q_ASSERT(it != d->cells.end());
       
  1041                 Q_ASSERT(*it == fragment);
       
  1042                 firstCellIndex = cellIndex = it - d->cells.begin();
       
  1043             }
       
  1044 
       
  1045             ++cellIndex;
       
  1046 
       
  1047             QTextCharFormat fmt = fc->charFormat(it->format);
       
  1048 
       
  1049             const int cellRowSpan = fmt.tableCellRowSpan();
       
  1050             const int cellColSpan = fmt.tableCellColumnSpan();
       
  1051 
       
  1052             // update the grid for this cell
       
  1053             for (int i = r; i < r + cellRowSpan; ++i)
       
  1054                 for (int j = c; j < c + cellColSpan; ++j)
       
  1055                     d->grid[i * d->nCols + j] = cellFragment;
       
  1056 
       
  1057             // erase the cell marker
       
  1058             p->remove(pos, 1);
       
  1059 
       
  1060             const int nextFragment = d->cells.value(cellIndex, d->fragment_end);
       
  1061             const uint nextPos = p->fragmentMap().position(nextFragment);
       
  1062 
       
  1063             Q_ASSERT(nextPos >= pos);
       
  1064 
       
  1065             // merge the contents of the cell (if not empty)
       
  1066             if (nextPos > pos) {
       
  1067                 if (needsParagraph) {
       
  1068                     needsParagraph = false;
       
  1069                     QTextCursor(p, insertPos++).insertBlock();
       
  1070                     p->move(pos + 1, insertPos, nextPos - pos);
       
  1071                 } else if (rowHasText) {
       
  1072                     QTextCursor(p, insertPos++).insertText(QLatin1String(" "));
       
  1073                     p->move(pos + 1, insertPos, nextPos - pos);
       
  1074                 } else {
       
  1075                     p->move(pos, insertPos, nextPos - pos);
       
  1076                 }
       
  1077 
       
  1078                 insertPos += nextPos - pos;
       
  1079                 rowHasText = true;
       
  1080             }
       
  1081         }
       
  1082 
       
  1083         if (rowHasText) {
       
  1084             needsParagraph = true;
       
  1085             rowHasText = false;
       
  1086         }
       
  1087 
       
  1088         // erase cells from last row
       
  1089         if (firstCellIndex >= 0) {
       
  1090             d->cellIndices.remove(firstCellIndex, cellIndex - firstCellIndex);
       
  1091             d->cells.erase(d->cells.begin() + firstCellIndex, d->cells.begin() + cellIndex);
       
  1092         }
       
  1093     }
       
  1094 
       
  1095     d->fragment_start = d->cells.first();
       
  1096 
       
  1097     fmt.setTableCellRowSpan(numRows);
       
  1098     fmt.setTableCellColumnSpan(numCols);
       
  1099     p->setCharFormat(origCellPosition, 1, fmt);
       
  1100 
       
  1101     d->blockFragmentUpdates = false;
       
  1102     d->dirty = false;
       
  1103 
       
  1104     p->endEditBlock();
       
  1105 }
       
  1106 
       
  1107 /*!
       
  1108     \overload
       
  1109     \since 4.1
       
  1110 
       
  1111     Merges the cells selected by the provided \a cursor.
       
  1112 
       
  1113     \sa splitCell()
       
  1114 */
       
  1115 void QTextTable::mergeCells(const QTextCursor &cursor)
       
  1116 {
       
  1117     if (!cursor.hasComplexSelection())
       
  1118         return;
       
  1119 
       
  1120     int firstRow, numRows, firstColumn, numColumns;
       
  1121     cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
       
  1122     mergeCells(firstRow, firstColumn, numRows, numColumns);
       
  1123 }
       
  1124 
       
  1125 /*!
       
  1126     \since 4.1
       
  1127 
       
  1128     Splits the specified cell at \a row and \a column into an array of multiple
       
  1129     cells with dimensions specified by \a numRows and \a numCols.
       
  1130 
       
  1131     \note It is only possible to split cells that span multiple rows or columns, such as rows
       
  1132     that have been merged using mergeCells().
       
  1133 
       
  1134     \sa mergeCells()
       
  1135 */
       
  1136 void QTextTable::splitCell(int row, int column, int numRows, int numCols)
       
  1137 {
       
  1138     Q_D(QTextTable);
       
  1139 
       
  1140     if (d->dirty)
       
  1141         d->update();
       
  1142 
       
  1143     QTextDocumentPrivate *p = d->pieceTable;
       
  1144     QTextFormatCollection *c = p->formatCollection();
       
  1145 
       
  1146     const QTextTableCell cell = cellAt(row, column);
       
  1147     if (!cell.isValid())
       
  1148         return;
       
  1149     row = cell.row();
       
  1150     column = cell.column();
       
  1151 
       
  1152     QTextCharFormat fmt = cell.format();
       
  1153     const int rowSpan = fmt.tableCellRowSpan();
       
  1154     const int colSpan = fmt.tableCellColumnSpan();
       
  1155 
       
  1156     // nothing to split?
       
  1157     if (numRows > rowSpan || numCols > colSpan)
       
  1158         return;
       
  1159 
       
  1160     p->beginEditBlock();
       
  1161 
       
  1162     const int origCellPosition = cell.firstPosition() - 1;
       
  1163 
       
  1164     QVarLengthArray<int> rowPositions(rowSpan);
       
  1165 
       
  1166     rowPositions[0] = cell.lastPosition();
       
  1167 
       
  1168     for (int r = row + 1; r < row + rowSpan; ++r) {
       
  1169         // find the cell before which to insert the new cell markers
       
  1170         int gridIndex = r * d->nCols + column;
       
  1171         QVector<int>::iterator it = qUpperBound(d->cellIndices.begin(), d->cellIndices.end(), gridIndex);
       
  1172         int cellIndex = it - d->cellIndices.begin();
       
  1173         int fragment = d->cells.value(cellIndex, d->fragment_end);
       
  1174         rowPositions[r - row] = p->fragmentMap().position(fragment);
       
  1175     }
       
  1176 
       
  1177     fmt.setTableCellColumnSpan(1);
       
  1178     fmt.setTableCellRowSpan(1);
       
  1179     const int fmtIndex = c->indexForFormat(fmt);
       
  1180     const int blockIndex = p->blockMap().find(cell.lastPosition())->format;
       
  1181 
       
  1182     int insertAdjustement = 0;
       
  1183     for (int i = 0; i < numRows; ++i) {
       
  1184         for (int c = 0; c < colSpan - numCols; ++c)
       
  1185             p->insertBlock(QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex);
       
  1186         insertAdjustement += colSpan - numCols;
       
  1187     }
       
  1188 
       
  1189     for (int i = numRows; i < rowSpan; ++i) {
       
  1190         for (int c = 0; c < colSpan; ++c)
       
  1191             p->insertBlock(QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex);
       
  1192         insertAdjustement += colSpan;
       
  1193     }
       
  1194 
       
  1195     fmt.setTableCellRowSpan(numRows);
       
  1196     fmt.setTableCellColumnSpan(numCols);
       
  1197     p->setCharFormat(origCellPosition, 1, fmt);
       
  1198 
       
  1199     p->endEditBlock();
       
  1200 }
       
  1201 
       
  1202 /*!
       
  1203     Returns the number of rows in the table.
       
  1204 
       
  1205     \sa columns()
       
  1206 */
       
  1207 int QTextTable::rows() const
       
  1208 {
       
  1209     Q_D(const QTextTable);
       
  1210     if (d->dirty)
       
  1211         d->update();
       
  1212 
       
  1213     return d->nRows;
       
  1214 }
       
  1215 
       
  1216 /*!
       
  1217     Returns the number of columns in the table.
       
  1218 
       
  1219     \sa rows()
       
  1220 */
       
  1221 int QTextTable::columns() const
       
  1222 {
       
  1223     Q_D(const QTextTable);
       
  1224     if (d->dirty)
       
  1225         d->update();
       
  1226 
       
  1227     return d->nCols;
       
  1228 }
       
  1229 
       
  1230 #if 0
       
  1231 void QTextTable::mergeCells(const QTextCursor &selection)
       
  1232 {
       
  1233 }
       
  1234 #endif
       
  1235 
       
  1236 /*!
       
  1237     \fn QTextCursor QTextTable::rowStart(const QTextCursor &cursor) const
       
  1238 
       
  1239     Returns a cursor pointing to the start of the row that contains the
       
  1240     given \a cursor.
       
  1241 
       
  1242     \sa rowEnd()
       
  1243 */
       
  1244 QTextCursor QTextTable::rowStart(const QTextCursor &c) const
       
  1245 {
       
  1246     Q_D(const QTextTable);
       
  1247     QTextTableCell cell = cellAt(c);
       
  1248     if (!cell.isValid())
       
  1249         return QTextCursor();
       
  1250 
       
  1251     int row = cell.row();
       
  1252     QTextDocumentPrivate *p = d->pieceTable;
       
  1253     QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), d->grid[row*d->nCols]);
       
  1254     return QTextCursor(p, it.position());
       
  1255 }
       
  1256 
       
  1257 /*!
       
  1258     \fn QTextCursor QTextTable::rowEnd(const QTextCursor &cursor) const
       
  1259 
       
  1260     Returns a cursor pointing to the end of the row that contains the given
       
  1261     \a cursor.
       
  1262 
       
  1263     \sa rowStart()
       
  1264 */
       
  1265 QTextCursor QTextTable::rowEnd(const QTextCursor &c) const
       
  1266 {
       
  1267     Q_D(const QTextTable);
       
  1268     QTextTableCell cell = cellAt(c);
       
  1269     if (!cell.isValid())
       
  1270         return QTextCursor();
       
  1271 
       
  1272     int row = cell.row() + 1;
       
  1273     int fragment = row < d->nRows ? d->grid[row*d->nCols] : d->fragment_end;
       
  1274     QTextDocumentPrivate *p = d->pieceTable;
       
  1275     QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), fragment);
       
  1276     return QTextCursor(p, it.position() - 1);
       
  1277 }
       
  1278 
       
  1279 /*!
       
  1280     \fn void QTextTable::setFormat(const QTextTableFormat &format)
       
  1281 
       
  1282     Sets the table's \a format.
       
  1283 
       
  1284     \sa format()
       
  1285 */
       
  1286 void QTextTable::setFormat(const QTextTableFormat &format)
       
  1287 {
       
  1288     QTextTableFormat fmt = format;
       
  1289     // don't try to change the number of table columns from here
       
  1290     fmt.setColumns(columns());
       
  1291     QTextObject::setFormat(fmt);
       
  1292 }
       
  1293 
       
  1294 /*!
       
  1295     \fn QTextTableFormat QTextTable::format() const
       
  1296 
       
  1297     Returns the table's format.
       
  1298 
       
  1299     \sa setFormat()
       
  1300 */
       
  1301 
       
  1302 QT_END_NAMESPACE