diff options
| author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 | 
|---|---|---|
| committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 | 
| commit | e9ae80694875f869892f13f4fcaf1170a00dea41 (patch) | |
| tree | aa2f8d8a217e2d376224c8d46b7397b68d35de2d /quanta/components/tableeditor/tableeditor.cpp | |
| download | tdewebdev-e9ae80694875f869892f13f4fcaf1170a00dea41.tar.gz tdewebdev-e9ae80694875f869892f13f4fcaf1170a00dea41.zip | |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdewebdev@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'quanta/components/tableeditor/tableeditor.cpp')
| -rw-r--r-- | quanta/components/tableeditor/tableeditor.cpp | 1298 | 
1 files changed, 1298 insertions, 0 deletions
| diff --git a/quanta/components/tableeditor/tableeditor.cpp b/quanta/components/tableeditor/tableeditor.cpp new file mode 100644 index 00000000..970828a2 --- /dev/null +++ b/quanta/components/tableeditor/tableeditor.cpp @@ -0,0 +1,1298 @@ +/*************************************************************************** +                           tableeditor.cpp  -  table editor dialog +    begin              : Thu 15 Apr 2004 +    copyright          : (C) 2004 by Andras Mantia <amantia@kde.org> + ***************************************************************************/ + +/*************************************************************************** + * + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; version 2 of the License. + * + ***************************************************************************/ + +//kde includes +#include <kapplication.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kparts/componentfactory.h> +#include <kpopupmenu.h> +#include <kpushbutton.h> +#include <ktexteditor/document.h> +#include <ktexteditor/editinterface.h> + +//qt includes +#include <qcheckbox.h> +#include <qiconset.h> +#include <qlineedit.h> +#include <qobject.h> +#include <qpoint.h> +#include <qrect.h> +#include <qspinbox.h> +#include <qstring.h> +#include <qtabwidget.h> +#include <qvaluevector.h> + +//own includes +#include "tagdialog.h" +#include "parser.h" +#include "node.h" +#include "tag.h" + +#include "quantacommon.h" +#include "tableitem.h" +#include "tableeditor.h" + +int newNum; + +TableEditor::TableEditor(QWidget* parent, const char* name) +  : TableEditorS(parent, name) +{ +  m_popup = new KPopupMenu(); +  m_cellEditId = m_popup->insertItem(i18n("&Edit Cell Properties"), this ,SLOT(slotEditCell())); +  m_rowEditId = m_popup->insertItem(i18n("Edit &Row Properties"), this ,SLOT(slotEditRow())); +  //  m_colEditId = m_popup->insertItem(i18n("Edit &Column Properties"), this ,SLOT(slotEditCol())); +  m_mergeSeparatorId = m_popup->insertSeparator(); +  m_mergeCellsId = m_popup->insertItem(i18n("Merge Cells"), this, SLOT(slotMergeCells())); +  m_unmergeCellsId = m_popup->insertItem(i18n("Break Merging"), this, SLOT(slotUnmergeCells())); + +  m_popup->insertSeparator(); +  m_popup->insertItem(i18n("&Insert Row"), this, SLOT(slotInsertRow())); +  m_popup->insertItem(i18n("Insert Co&lumn"), this, SLOT(slotInsertCol())); +  m_popup->insertItem(i18n("Remove Row"), this, SLOT(slotRemoveRow())); +  m_popup->insertItem(i18n("Remove Column"), this, SLOT(slotRemoveCol())); +  m_popup->insertSeparator(); +  m_popup->insertItem(i18n("Edit &Table Properties"), this, SLOT(slotEditTable())); +  m_editChildId = m_popup->insertItem(i18n("Edit Child Table"), this, SLOT(slotEditChildTable())); + +  buttonOk->setIconSet(SmallIconSet("button_ok")); +  buttonCancel->setIconSet(SmallIconSet("button_cancel")); +  buttonHelp->setIconSet(SmallIconSet("help")); + +  m_row = m_col = -1; +  m_tbody = 0L; +  m_thead = 0L; +  m_tfoot = 0L; +  m_table = 0L; +  m_dtd = 0L; +  m_write = 0L; +  m_tableDataTags = new QValueList<QValueList<TableNode> >; +  m_tableHeaderTags = new QValueList<QValueList<TableNode> >; +  m_tableFooterTags = new QValueList<QValueList<TableNode> >; +  m_tableTags = 0L; +  m_tableDataRows = new QValueList<TableNode>; +  m_tableHeaderRows = new QValueList<TableNode>; +  m_tableFooterRows = new QValueList<TableNode>; +  m_tableRows = 0L; +  m_createNodes = true; +  newNum += 7; + +  connect(headerColSpinBox, SIGNAL(valueChanged(int)), SLOT(slotAddRemoveCol(int))); +  connect(headerRowSpinBox, SIGNAL(valueChanged(int)), SLOT(slotAddRemoveRow(int))); +  connect(rowSpinBox, SIGNAL(valueChanged(int)), SLOT(slotAddRemoveRow(int))); +  connect(colSpinBox, SIGNAL(valueChanged(int)), SLOT(slotAddRemoveCol(int))); +  connect(footerRowSpinBox, SIGNAL(valueChanged(int)), SLOT(slotAddRemoveRow(int))); +  connect(footerColSpinBox, SIGNAL(valueChanged(int)), SLOT(slotAddRemoveCol(int))); +  connect(tableData, SIGNAL(contextMenuRequested(int,int,const QPoint&)), +    SLOT(slotContextMenuRequested(int,int,const QPoint&))); +  connect(pushButton7, SIGNAL(clicked()), SLOT(slotEditTable())); +  connect(pushButton7_2, SIGNAL(clicked()), SLOT(slotEditTableBody())); +  connect(pushButton7_3, SIGNAL(clicked()), SLOT(slotEditTableHeader())); +  connect(pushButton7_4, SIGNAL(clicked()), SLOT(slotEditTableFooter())); +  connect(headerTableData, SIGNAL(contextMenuRequested(int,int,const QPoint&)), +    SLOT(slotContextMenuRequested(int,int,const QPoint&))); +  connect(footerTableData, SIGNAL(contextMenuRequested(int,int,const QPoint&)), +    SLOT(slotContextMenuRequested(int,int,const QPoint&))); +  connect(tabWidget, SIGNAL(currentChanged(QWidget*)), SLOT(slotTabChanged(QWidget*))); +  connect(buttonHelp, SIGNAL(clicked()), SLOT(slotHelpInvoked())); +  connect(tableData, SIGNAL(valueChanged(int,int)), SLOT(slotEditCellText(int,int))); +  connect(headerTableData, SIGNAL(valueChanged(int,int)), SLOT(slotEditCellText(int,int))); +  connect(footerTableData, SIGNAL(valueChanged(int,int)), SLOT(slotEditCellText(int,int))); +} + +TableEditor::~TableEditor() +{ +  delete m_popup; +  delete m_tbody; +  delete m_thead; +  delete m_tfoot; +  delete m_table; +  newNum -=5; +  deleteMatrix(m_tableDataTags); +  deleteMatrix(m_tableHeaderTags); +  deleteMatrix(m_tableFooterTags); +  deleteList(m_tableDataRows); +  deleteList(m_tableHeaderRows); +  deleteList(m_tableFooterRows); +  kdDebug(24000) << "Undeleted new: " << newNum << endl; +} + +void TableEditor::slotContextMenuRequested( int row, int col, const QPoint & pos ) +{ +  m_row = row; +  m_col = col; +  m_popup->setItemEnabled(m_cellEditId, (row >=0 && col >=0)); +  m_popup->setItemEnabled(m_rowEditId, (row >=0)); +  m_popup->setItemEnabled(m_colEditId, (col >=0)); +  m_popup->setItemVisible(m_mergeSeparatorId, false); +  m_popup->setItemVisible(m_mergeCellsId, false); +  m_popup->setItemVisible(m_unmergeCellsId, false); +  if  (row >=0 && col >=0) { +    TableNode tableNode = (*m_tableTags)[m_row][m_col]; +    m_popup->setItemVisible(m_mergeSeparatorId, false); +    m_popup->setItemVisible(m_mergeCellsId, false); +     m_popup->setItemVisible(m_editChildId, false); +    if (tableNode.merged) { +      m_popup->setItemVisible(m_unmergeCellsId, true); +      m_popup->setItemVisible(m_mergeSeparatorId, true); +    } +    QTableSelection selection = m_dataTable->selection(m_dataTable->currentSelection()); +    QRect rect(QPoint(selection.topRow(), selection.leftCol()) , +               QPoint(selection.bottomRow(), selection.rightCol())); +    if (rect.isValid() && (rect.width() > 1 || rect.height() > 1) && rect.contains(m_row, m_col)) { +       m_popup->setItemVisible(m_mergeCellsId, true); +       m_popup->setItemVisible(m_mergeSeparatorId, true); +    } +    if (m_dataTable->item(m_row, m_col) && !m_dataTable->item(m_row, m_col)->pixmap().isNull()) { +       m_popup->setItemVisible(m_editChildId, true); +    } +  } +  m_popup->popup(pos); +} + + +void TableEditor::slotEditCell() +{ +  Tag *tag = (*m_tableTags)[m_row][m_col].node->tag; +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd, "td"), tag, m_baseURL); +  int many = 0; +  if (dlg.exec()) { +    for (int row = 0; row < m_dataTable->numRows(); row++) +      for (int col = 0; col < m_dataTable->numCols(); col++) { +        many++; +       if (m_dataTable->isSelected(row, col)) { +         (*m_tableTags)[row][col].node->tag->modifyAttributes(dlg.getAttributes()); +	 configureCell(row, col, (*m_tableTags)[row][col].node); +	 } +      } +    if (!many) { +      (*m_tableTags)[m_row][m_col].node->tag->modifyAttributes(dlg.getAttributes()); +      configureCell(m_row, m_col, (*m_tableTags)[m_row][m_col].node); +    } +    //TODO: add/remove columns/rows if the colspan/rowspan attribute is changed +  } +} + +void TableEditor::slotEditCellText( int r, int ) +{ +   m_dataTable->adjustRow(r); +} + + +void TableEditor::slotEditRow() +{ +  Tag *tag = (*m_tableRows)[m_row].node->tag; +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd,"tr"), tag, m_baseURL); +  if (dlg.exec()) { +    tag->modifyAttributes(dlg.getAttributes()); +  } +} + + +void TableEditor::slotEditCol() +{ +  KMessageBox::information(this, i18n("Edit col: %1").arg(m_col + 1)); +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd,"col")); +  dlg.exec(); +} + + +void TableEditor::slotEditTable() +{ +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd,"table"), m_table, m_baseURL); +  if (dlg.exec()) { +    m_table->modifyAttributes(dlg.getAttributes()); +  } +} + + +void TableEditor::slotEditTableBody() +{ +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd,"tbody"), m_tbody, m_baseURL); +  if (dlg.exec()) { +    m_tbody->modifyAttributes(dlg.getAttributes()); +  } +} + + +bool TableEditor::setTableArea( int bLine, int bCol, int eLine, int eCol, Parser *docParser ) +{ +  const uint pInitialTableSize = 20; + +  m_bLine = bLine; +  m_bCol = bCol; +  m_eLine = eLine; +  m_eCol = eCol; +  m_createNodes = false; //don't create the cell and row content when adding a new cell/row +  Node *node = docParser->nodeAt(bLine, bCol + 1); +  Node *lastNode = docParser->nodeAt(eLine, eCol); +  if (node) +    kdDebug(24000) << "node = " << node->tag->name << endl; +  if (lastNode) +    kdDebug(24000) << "lastnode = " << lastNode->tag->name << endl; +  if (!node || !lastNode) +    return false; +  m_write = node->tag->write(); +  m_dtd = node->tag->dtd(); +  if ( !QuantaCommon::closesTag(node->tag, lastNode->tag) ) { +    return false; +  } +  int nCol, nRow, maxCol; +  nCol = nRow = maxCol = 0; +  bool countRows = false; +  bool missingBody = false; +  m_rowSpin = 0L; +  m_colSpin = 0L; +  m_dataTable = 0L; +  QValueList<TableNode> tableRowTags; +  QValueVector< QValueVector<TableNode> > mergeMatrix; +  mergeMatrix.resize(pInitialTableSize); +  for (uint i = 0; i < pInitialTableSize; i++) +    mergeMatrix[i].resize(pInitialTableSize); +  TableNode tableNode; +  Node *n = node; +  while (n != lastNode->nextSibling()) +  { +    QString tagName = n->tag->name.lower(); +    if (tagName == "table") +    { +      if (m_table && m_dataTable && nRow > 0 && nCol > 0) //nested table! +      { +        int line, col; +        n->tag->beginPos(line, col); +        NestedTable table; +        table.row = nRow -1; +        table.col = nCol - 1; +        table.bLine = line; +        table.bCol = col; +        if (n->next && QuantaCommon::closesTag(n->tag, n->next->tag)) { +          n->next->tag->endPos(table.eLine, table.eCol); +          table.node = n; +          table.nestedData = m_write->text(table.bLine, table.bCol, table.eLine, table.eCol); +          m_nestedTables.append(table); +          m_dataTable->item(nRow -1, nCol -1)->setPixmap(QIconSet(UserIcon("quick_table")).pixmap()); +          m_dataTable->updateCell(nRow - 1, nCol - 1); +        } +        n = n->next; +      } else +      { +        m_table = new Tag(*(n->tag)); +        newNum++; +      } +    } +    else if (tagName == "thead") +    { +      headerCheckBox->setChecked(true); +      countRows = true; +      m_rowSpin = headerRowSpinBox; +      m_colSpin = headerColSpinBox; +      m_dataTable= headerTableData; +      m_tableTags = m_tableHeaderTags; +      m_tableRows = m_tableHeaderRows; +      if (m_thead) { //there was already a <thead> tag in the area +        nRow = m_dataTable->numRows(); +      } else { +        m_thead = new Tag(*(n->tag)); +        newNum++; +      } +    } +    else if (tagName == "/thead") +    { +      headerRowSpinBox->setValue(nRow); +      headerColSpinBox->setValue(maxCol); +      countRows = false; +      nCol = nRow = maxCol = 0; +      m_rowSpin = 0L; +      m_colSpin = 0L; +      m_dataTable = 0L; +    } +    else if (tagName == "tfoot") +    { +      footerCheckBox->setChecked(true); +      m_rowSpin = footerRowSpinBox; +      m_colSpin = footerColSpinBox; +      m_tableTags = m_tableFooterTags; +      m_tableRows = m_tableFooterRows; +      m_dataTable = footerTableData; +      countRows = true; +      if (m_tfoot) { //there was already a <tfoot> tag in the area +        nRow = m_dataTable->numRows(); +      } else { +        m_tfoot = new Tag(*(n->tag)); +        newNum++; +      } +    } +    else if (tagName == "/tfoot") +    { +      footerRowSpinBox->setValue(nRow); +      footerColSpinBox->setValue(maxCol); +      countRows = false; +      nCol = nRow = maxCol = 0; +      m_rowSpin = 0L; +      m_colSpin = 0L; +      m_dataTable = 0L; +    } +    else if (tagName == "tbody") +    { +      m_rowSpin = rowSpinBox; +      m_colSpin = colSpinBox; +      m_tableTags = m_tableDataTags; +      m_tableRows = m_tableDataRows; +      m_dataTable = tableData; +      countRows = true; +      m_tbody = new Tag(*(n->tag)); +      newNum++; +    } +    else if (tagName == "/tbody") +    { +      rowSpinBox->setValue(nRow); +      colSpinBox->setValue(maxCol); +      countRows = false; +      nCol = nRow = maxCol = 0; +      m_tableTags = 0L; +      m_tableRows = 0L; +      m_rowSpin = 0L; +      m_colSpin = 0L; +      m_dataTable = 0L; +    } +    else if (tagName == "tr") +    { +      if (!countRows) +      { +        missingBody = true; +        m_rowSpin = rowSpinBox; +        m_colSpin = colSpinBox; +        m_tableTags = m_tableDataTags; +        m_tableRows = m_tableDataRows; +        m_dataTable = tableData; +        countRows = true; +        m_tbody = new Tag(); +        newNum++; +        m_tbody->parse("<tbody>", m_write); +      } +      nRow++; +      if ((uint)nRow >= mergeMatrix.size()) {  // Check if there are enough rows in mergeMatriz +        mergeMatrix.resize(2 * mergeMatrix.size()); +        for (uint i = mergeMatrix.size() / 2; i < mergeMatrix.size(); i++) +          mergeMatrix[i].resize(mergeMatrix[0].size()); +      } + +      m_rowSpin->setValue(nRow); +      nCol = 0; +      tableNode.node = new Node(0L); +      tableNode.node->tag = new Tag(*(n->tag)); +      newNum++; +      tableNode.merged = false; +      m_tableRows->append(tableNode); +    } +    else if (tagName == "/tr") +    { +      if (countRows) +      { +        maxCol = (nCol > maxCol) ? nCol : maxCol; +        maxCol = (maxCol == 0) ? 1 : maxCol; +        for (int col = nCol; col < maxCol; col++) +        { +          if (mergeMatrix[nRow - 1][col].node != 0L) { +            if (m_colSpin->value() < col) +                m_colSpin->setValue(col); +            TableNode tableN = mergeMatrix[nRow - 1][col]; +            Node *n = tableN.node; +            setCellText(m_dataTable, nRow - 1, col, i18n("Merged with (%1, %2).").arg(tableN.mergedRow + 1).arg(tableN.mergedCol + 1)); +            m_dataTable->item(nRow-1, col)->setEnabled(false); +            tableNode.node = new Node(0L); +            tableNode.node->tag = new Tag(*(n->tag)); +            configureCell(nRow-1,  col, tableNode.node); +            newNum++; +            tableNode.merged = true; +            tableNode.mergedRow = tableN.mergedRow; +            tableNode.mergedCol = tableN.mergedCol; +            tableRowTags.append(tableNode); +            if ((uint)nCol >= mergeMatrix[0].size())  // Check if there are enough cols +              for (uint i=0; i<mergeMatrix.size(); i++) +                mergeMatrix[i].resize(2 * mergeMatrix[i].size()); +   +          } else +          { +            tableNode.node = new Node(0L); +            newNum++; +            tableNode.node->tag = new Tag(); +            tableNode.node->tag->setDtd(m_dtd); +            tableNode.node->tag->parse("<td>", m_write); +            tableNode.merged = false; +            tableRowTags.append(tableNode); +          } +        } +        if (!tableRowTags.isEmpty()) +          m_tableTags->append(tableRowTags); +        tableRowTags.clear(); +      } +    } +    else if (tagName == "th" || tagName == "td") +    { +      if (countRows) +      { +        int col = nCol; +        while (mergeMatrix[nRow - 1][col].node != 0L) { +          if (m_colSpin->value() < col) +              m_colSpin->setValue(col); +          TableNode tableN = mergeMatrix[nRow - 1][col]; +          Node *n = tableN.node; +          setCellText(m_dataTable, nRow - 1, col, i18n("Merged with (%1, %2).").arg(tableN.mergedRow + 1).arg(tableN.mergedCol + 1)); +          m_dataTable->item(nRow-1, col)->setEnabled(false); +          tableNode.node = new Node(0L); +          tableNode.node->tag = new Tag(*(n->tag)); +          configureCell(nRow-1,  col, tableNode.node); +          newNum++; +          tableNode.merged = true; +          tableNode.mergedRow = tableN.mergedRow; +          tableNode.mergedCol = tableN.mergedCol; +          tableRowTags.append(tableNode); +          col++; +          nCol++; +          if ((uint)nCol >= mergeMatrix[0].size())  // Check if there are enough cols +            for (uint i = 0; i < mergeMatrix.size(); i++) +              mergeMatrix[i].resize(2 * mergeMatrix[i].size()); + +        } +        nCol++; +        if (m_rowSpin && m_colSpin && m_dataTable) +        { +          m_rowSpin->setValue(nRow); +          if (m_colSpin->value() < nCol) +            m_colSpin->setValue(nCol); +          setCellText(m_dataTable, nRow - 1, nCol - 1, tagContent(n)); +          tableNode.node = new Node(0L); +          tableNode.node->tag = new Tag(*(n->tag)); +	        configureCell(nRow-1,  col, tableNode.node); +          newNum++; +          tableNode.merged = false; +          tableRowTags.append(tableNode); +        } +        QString colspanValue = n->tag->attributeValue("colspan", true); +        int colValue = 1; +        int lastCol = nCol; +        if (!colspanValue.isEmpty()) +        { +          bool ok; +          colValue = colspanValue.toInt(&ok, 10); +          if (ok && colValue > 1) +          { +            nCol += (colValue - 1); +            if (m_colSpin->value() < nCol) +              m_colSpin->setValue(nCol); +            for (int i = 0; i < colValue - 1; i++) +            { +              setCellText(m_dataTable, nRow - 1, lastCol + i, i18n("Merged with (%1, %2).").arg(nRow).arg(lastCol)); +              m_dataTable->item(nRow-1, lastCol + i)->setEnabled(false); +              tableNode.node = new Node(0L); +              tableNode.node->tag = new Tag(*(n->tag)); +              configureCell(nRow-1,  col, tableNode.node); +              newNum++; +              tableNode.merged = true; +              tableNode.mergedRow = nRow - 1; +              tableNode.mergedCol = lastCol - 1; +              tableRowTags.append(tableNode); +            } +          } else +            colValue = 1; +        } +        QString rowspanValue = n->tag->attributeValue("rowspan", true); +        if (!rowspanValue.isEmpty()) +        { +          bool ok; +          int rowValue = rowspanValue.toInt(&ok, 10); +          if (ok && rowValue > 1) +          { +            lastCol--; +            // Check if there are enough columns in mergeMatriz +            if ((uint)(lastCol + colValue) >= mergeMatrix[0].size()) +              for (uint i = 0; i < mergeMatrix.size(); i++) +                mergeMatrix[i].resize(2 * mergeMatrix[i].size()); +            // Check if there are enough rows in mergeMatriz +            if ((uint)(nRow + rowValue) >= mergeMatrix.size()) { +              mergeMatrix.resize(2 * mergeMatrix.size()); +              for (uint i = mergeMatrix.size() / 2; i < mergeMatrix.size(); i++) +                mergeMatrix[i].resize(mergeMatrix[0].size()); +            } + +            for (int i = 0; i < rowValue - 1; i++) +              for (int j = 0; j < colValue; j++) { +                mergeMatrix[nRow + i][lastCol + j].mergedRow = nRow - 1; +                mergeMatrix[nRow + i][lastCol + j].mergedCol = lastCol; +                mergeMatrix[nRow + i][lastCol + j].node = n; +              } +          } +        } +      } +    } +    else if (tagName == "caption") +    { +      captionText->setText(tagContent(n)); +    } else if (tagName == "col" || tagName == "colgroup") { +      m_colTags.append(n->tag); +    } +    n = n->nextSibling(); +  } +/*  if (missingBody) { //Hm, why do we need it? I don't remember now. ;-) +      rowSpinBox->setValue(nRow); +      colSpinBox->setValue(maxCol); +  } */ +  //by default the current page is the data handling page +  m_tableTags = m_tableDataTags; +  m_tableRows = m_tableDataRows; +  m_dataTable = tableData; +  m_rowSpin = rowSpinBox; +  m_colSpin = colSpinBox; + +  //create the thead, tbody, tfoot tags if they were not present in the parsed area +  if (!m_thead) { +    m_thead = new Tag(); +    newNum++; +    m_thead->parse("<thead>", m_write); +  } +  if (!m_tfoot) { +    m_tfoot = new Tag(); +    newNum++; +    m_tfoot->parse("<tfoot>", m_write); +  } +  m_createNodes = true; //enable cell/row creation + +  configureTable(tableData); +  configureTable(headerTableData); +  configureTable(footerTableData); +  return true; +} + + +void TableEditor::setBaseURL( const KURL & url ) +{ +  m_baseURL = url; +} + + +void TableEditor::slotEditTableHeader() +{ +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd, "thead"), m_thead, m_baseURL); +  if (dlg.exec()) { +    m_thead->modifyAttributes(dlg.getAttributes()); +  } +} + + +void TableEditor::slotEditTableFooter() +{ +  TagDialog dlg(QuantaCommon::tagFromDTD(m_dtd,"tfoot"), m_tfoot, m_baseURL); +  if (dlg.exec()) { +    m_tfoot->modifyAttributes(dlg.getAttributes()); +  } +} + + +void TableEditor::slotTabChanged( QWidget *w) +{ +  int i = tabWidget->indexOf(w); +  switch (i) +  { +    case 0: { +      m_tableTags = m_tableDataTags; +      m_tableRows = m_tableDataRows; +      m_dataTable = tableData; +      m_colSpin = colSpinBox; +      m_rowSpin = rowSpinBox; +      break; +    } +   case 1: { +      m_tableTags = m_tableHeaderTags; +      m_tableRows = m_tableHeaderRows; +      m_dataTable = headerTableData; +      m_colSpin = headerColSpinBox; +      m_rowSpin = headerRowSpinBox; +      break; +    } +     case 2: { +      m_tableTags = m_tableFooterTags; +      m_tableRows = m_tableFooterRows; +      m_dataTable = footerTableData; +      m_colSpin = footerColSpinBox; +      m_rowSpin = footerRowSpinBox; +      break; +    } +  } +  configureTable(m_dataTable); +} + + +QString TableEditor::readModifiedTable() +{ +  QString tableString; +  tableString = m_table->toString(); +  if (!captionText->text().isEmpty()) { +    tableString += indent(2); +    tableString += "<" + QuantaCommon::tagCase("caption") + ">"; +    tableString += captionText->text(); +    tableString += "</" + QuantaCommon::tagCase("caption") + ">"; +  } +  for (QValueList<Tag*>::Iterator it = m_colTags.begin(); it != m_colTags.end(); ++it) { +    tableString += indent(2); +    tableString += (*it)->toString(); +  } +  if (headerCheckBox->isChecked() && headerTableData->numRows() > 0) { +    //insert the <thead> tag +    tableString += indent(2); +    tableString += m_thead->toString(); + +    kdDebug(24000) << "thead" << endl; +    m_tableTags = m_tableHeaderTags; +    m_tableRows = m_tableHeaderRows; +    m_dataTable = headerTableData; +    tableString += tableToString(); +    tableString += indent(2); +    tableString += "</" + QuantaCommon::tagCase(m_thead->name) +">"; +  } +  if (footerCheckBox->isChecked() && footerTableData->numRows() > 0) { +    //insert the <tfoot> tag +    tableString += indent(2); +    tableString += m_tfoot->toString(); + +    kdDebug(24000) << "tfoot" << endl; +    m_tableTags = m_tableFooterTags; +    m_tableRows = m_tableFooterRows; +    m_dataTable = footerTableData; +    tableString += tableToString(); +    tableString += indent(2); +    tableString += "</" + QuantaCommon::tagCase(m_tfoot->name) +">"; +  } +  //insert the <tbody> tag +  if (!m_tbody) +  { +    m_tbody = new Tag(); +    newNum++; +    m_tbody->parse("<tbody>", m_write); +  } +  tableString += indent(2); +  tableString += m_tbody->toString(); +  kdDebug(24000) << "tbody" << endl; +  m_tableTags = m_tableDataTags; +  m_tableRows = m_tableDataRows; +  m_dataTable = tableData; +  tableString += tableToString(); +  //close the <tbody> and <table> tags +  tableString += indent(2); +  tableString += "</" + QuantaCommon::tagCase(m_tbody->name) +">"; +  tableString += "\n"; +  tableString += "</" + QuantaCommon::tagCase(m_table->name) + ">"; + +  //kdDebug(24000) << tableString << endl; +  return tableString; +} + + +QString TableEditor::indent( int n ) +{ +  QString str; +  str.fill(' ', n); +  str.prepend('\n'); +  return str; +} + + +QString TableEditor::cellValue( int row, int col ) +{ + if (!m_dataTable) +    return QString::null; + QString str; + Node *node = (*m_tableTags)[row][col].node; + if (!node) +   return QString::null; + str = node->tag->toString(); + str += m_dataTable->text(row, col); + str += "</" + QuantaCommon::tagCase(node->tag->name) + ">"; + return str; +} + + +QString TableEditor::tableToString() +{ +    QString tableStr; +    for (int i = 0; i < m_dataTable->numRows(); i++) { +      tableStr += indent(4); +      Node *node = (*m_tableRows)[i].node; +      Tag *tag = 0L; +      if (node) +          tag = node->tag; +      if (tag) +        tableStr += tag->toString(); +      else +        tableStr += QuantaCommon::tagCase("<tr>"); +      for (int j = 0; j < m_dataTable->numCols(); j++)  { +        if ((*m_tableTags)[i][j].node && !(*m_tableTags)[i][j].merged) +        { +          tableStr += indent(6); +          tableStr += cellValue(i, j); +        } +      } +      tableStr += indent(4); +      if (tag) +        tableStr += "</" + QuantaCommon::tagCase(tag->name) +">"; +      else +        tableStr += QuantaCommon::tagCase("</tr>"); +    } +  return tableStr; +} + + +QString TableEditor::tagContent(Node *node) +{ +  if (!node) +    return QString::null; +  QString content; +  int bl, bc, el, ec; +  node->tag->endPos(bl, bc); +  bc++; +  if (node->next) +  { +    node->next->tag->beginPos(el, ec); +    ec--; +  } +  else +  { +    Node *n = node->nextSibling(); +    if (n) { +      n->tag->beginPos(el, ec); +      ec--; +    } else { +      return QString::null; +    } +  } + content = m_write->text(bl, bc, el, ec); + return content; +} + + +void TableEditor::slotInsertRow() +{ +  int num = m_dataTable->numRows(); +  if (m_row >= 0) +     num = m_row; +  m_dataTable->insertRows(num); +  m_dataTable->setRowHeight(num, 50); +  if (m_createNodes) { +    TableNode tableNode; +    tableNode.merged = false; +    tableNode.node = new Node(0L); +    newNum++; +    tableNode.node->tag = new Tag(); +    tableNode.node->tag->setDtd(m_dtd); +    tableNode.node->tag->parse("<tr>", m_write); +    QValueList<TableNode>::Iterator rowIt = m_tableRows->at(num); +    if (rowIt != m_tableRows->end()) +      m_tableRows->insert(rowIt, tableNode); +    else +      m_tableRows->append(tableNode); +    QValueList<TableNode> tableRowTags; +    for (int i = 0; i < m_dataTable->numCols(); i++) { +      tableNode.merged = false; +      tableNode.node = new Node(0L); +      newNum++; +      tableNode.node->tag = new Tag(); +      tableNode.node->tag->setDtd(m_dtd); +      if (m_tableTags == m_tableHeaderTags) { +        tableNode.node->tag->parse("<th>", m_write); +      } else { +        tableNode.node->tag->parse("<td>", m_write); +      } +      tableRowTags.append(tableNode); +      setCellText(m_dataTable, num, i, ""); +    } +    QValueList<QValueList<TableNode> >::Iterator it = m_tableTags->at(num); +    if (it != m_tableTags->end()) +      m_tableTags->insert(it, tableRowTags); +    else +      m_tableTags->append(tableRowTags); +  } +  m_rowSpin->setValue(m_dataTable->numRows()); +} + + +void TableEditor::slotInsertCol() +{ +  int num = m_dataTable->numCols(); +  if (m_col >= 0) +      num = m_col; +  m_dataTable->insertColumns(num); +  m_dataTable->setColumnWidth(num, 150); +  if (m_createNodes) { +    TableNode tableNode; +    int i = 0; +    for (QValueList<QValueList<TableNode> >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { +      tableNode.merged = false; +      tableNode.node = new Node(0L); +      newNum++; +      tableNode.node->tag = new Tag(); +      tableNode.node->tag->setDtd(m_dtd); +      if (m_tableTags == m_tableHeaderTags) { +        tableNode.node->tag->parse("<th>", m_write); +      } else { +        tableNode.node->tag->parse("<td>", m_write); +      } +      (*it).append(tableNode); +      setCellText(m_dataTable, i, num, ""); +      i++; +    } +  } +  m_colSpin->setValue(m_dataTable->numCols()); +} + + +void TableEditor::slotAddRemoveRow( int num ) +{ +  m_row = -1; +  int numRows = m_dataTable->numRows(); +  if (num > numRows) { +    for (int i = numRows; i < num; i++) { +      slotInsertRow(); +    } +  } +  else { +    for (int i = num; i < numRows; i++) { +      slotRemoveRow(); +    } +  } +  //TODO: change the main tag's rowspan if necessary +} + + +void TableEditor::slotAddRemoveCol( int num ) +{ +  m_col = -1; +  int numCols = m_dataTable->numCols(); +  if (num > numCols) { +    for (int i = numCols; i < num; i++) { +      slotInsertCol(); +    } +  } +  else { +    for (int i = num; i < numCols; i++) { +      slotRemoveCol(); +    } +  } +  //TODO: change the main tag's colspan if necessary} +} + +void TableEditor::slotRemoveRow() +{ +  if (m_row == -1) +    m_row = m_dataTable->numRows() - 1; +  int i = 0; +  int j = 0; +  for (QValueList<QValueList<TableNode> >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { +      j = 0; +      for (QValueList<TableNode>::Iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) { +        if ((*it2).merged && (*it2).mergedRow == m_row) { +          (*it2).merged = false; +          setCellText(m_dataTable, i, j, tagContent((*it2).node)); +          m_dataTable->item(i, j)->setEnabled(true); +          (*it2).node->tag->deleteAttribute("colspan"); +          (*it2).node->tag->deleteAttribute("rowspan"); +        } +        j++; +      } +      i++; +  } +  QValueList<TableNode*> updatedMainNodes; +  QValueList<QValueList<TableNode> >::Iterator it2 = m_tableTags->at(m_row); +  for (QValueList<TableNode>::Iterator it3 = (*it2).begin(); it3 != (*it2).end(); ++it3) { +    if ((*it3).merged) +    { +      TableNode *mainTableNode = &((*m_tableTags)[(*it3).mergedRow][(*it3).mergedCol]); +      if (mainTableNode->node && !updatedMainNodes.contains(mainTableNode)) +      { +        int rowspan =  mainTableNode->node->tag->attributeValue("rowspan", true).toInt(); +        rowspan--; +        if (rowspan > 1) +          mainTableNode->node->tag->editAttribute("rowspan", QString("%1").arg(rowspan)); +        else +          mainTableNode->node->tag->deleteAttribute("rowspan"); +        updatedMainNodes.append(mainTableNode); +      } +    } +    Node::deleteNode((*it3).node); +    (*it3).node = 0L; +    newNum--; +  } +  m_tableTags->erase(it2); +  m_dataTable->removeRow(m_row); +  QValueList<TableNode>::Iterator it = m_tableRows->at(m_row); +  Node::deleteNode((*it).node); +  newNum--; +  m_tableRows->erase(it); +  m_rowSpin->setValue(m_dataTable->numRows()); +} + + +void TableEditor::slotRemoveCol() +{ +  int i = 0; +  int j = 0; +  for (QValueList<QValueList<TableNode> >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { +      j = 0; +      for (QValueList<TableNode>::Iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) { +        if ((*it2).merged && (*it2).mergedCol == m_col) { +          (*it2).merged = false; +          setCellText(m_dataTable, i, j, tagContent((*it2).node)); +          m_dataTable->item(i, j)->setEnabled(true); +          (*it2).node->tag->deleteAttribute("colspan"); +          (*it2).node->tag->deleteAttribute("rowspan"); +        } +        j++; +      } +      i++; +  } +  if (m_col == -1) +    m_col = m_dataTable->numCols() - 1; +  QValueList<TableNode*> updatedMainNodes; +  for (QValueList<QValueList<TableNode> >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { +    QValueList<TableNode>::Iterator it2 = (*it).at(m_col); +    if ((*it2).merged) +    { +      TableNode *mainTableNode = &((*m_tableTags)[(*it2).mergedRow][(*it2).mergedCol]); +      if (mainTableNode->node && !updatedMainNodes.contains(mainTableNode)) +      { +        int colspan = mainTableNode->node->tag->attributeValue("colspan", true).toInt(); +        colspan--; +        if (colspan > 1) +          mainTableNode->node->tag->editAttribute("colspan", QString("%1").arg(colspan)); +        else +          mainTableNode->node->tag->deleteAttribute("colspan"); +        updatedMainNodes.append(mainTableNode); +      } +    } +    Node::deleteNode((*it2).node); +    newNum--; +    (*it).erase(it2); +  } + m_dataTable->removeColumn(m_col); + m_colSpin->setValue(m_dataTable->numCols()); +} + + +void TableEditor::createNewTable(Document *write, const DTDStruct *dtd) +{ +  m_write = write; +  m_dtd = dtd; +  m_table = new Tag(); +  m_table->setDtd(m_dtd); +  newNum++; +  m_table->parse("<table>", m_write); +  m_thead = new Tag(); +  m_thead->setDtd(m_dtd); +  newNum++; +  m_thead->parse("<thead>", m_write); +  m_tfoot = new Tag(); +  m_tfoot->setDtd(m_dtd); +  newNum++; +  m_tfoot->parse("<tfoot>", m_write); +  m_tbody = new Tag(); +  m_tbody->setDtd(m_dtd); +  newNum++; +  m_tbody->parse("<tbody>", m_write); +  //by default the current page is the data handling page +  m_tableTags = m_tableDataTags; +  m_tableRows = m_tableDataRows; +  m_dataTable = tableData; +  m_bLine = m_bCol = m_eLine = m_eCol = 0; +} + + +void TableEditor::deleteList( QValueList<TableNode> *table ) +{ +  for (QValueList<TableNode>::Iterator it = table->begin(); it != table->end(); ++it) { +    Node::deleteNode((*it).node); +    newNum--; +  } +  delete table; +  newNum--; +} + + +void TableEditor::deleteMatrix( QValueList<QValueList<TableNode> > *matrix ) +{ +    for (QValueList<QValueList<TableNode> >::Iterator it = matrix->begin(); it != matrix->end(); ++it) { +      for (QValueList<TableNode>::Iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) { +        Node::deleteNode((*it2).node); +        newNum--; +      } +  } +  delete matrix; +  newNum--; +} + + +void TableEditor::slotMergeCells() +{ +  slotUnmergeCells(); //first unmerge all cells from the selection + +  QTableSelection selection = m_dataTable->selection(m_dataTable->currentSelection()); +  int tRow, bRow, lCol, rCol; +  tRow = selection.topRow(); +  bRow = selection.bottomRow(); +  lCol = selection.leftCol(); +  rCol = selection.rightCol(); +  TableNode *mainTableNode = &((*m_tableTags)[tRow][lCol]); +  if (rCol - lCol > 0) +    mainTableNode->node->tag->editAttribute("colspan", QString("%1").arg(rCol - lCol + 1)); +  if (bRow - tRow > 0) +    mainTableNode->node->tag->editAttribute("rowspan", QString("%1").arg(bRow - tRow + 1)); +  for (int i = 0; i < bRow - tRow + 1; i++) +    for (int j = 0; j < rCol - lCol + 1; j++) { +      if (i != 0 || j != 0) { +        setCellText(m_dataTable, tRow + i, lCol + j, i18n("Merged with (%1, %2).").arg(tRow + 1).arg(lCol + 1)); +        m_dataTable->item(tRow + i, lCol + j)->setEnabled(false); +        TableNode *tableNode = &((*m_tableTags)[tRow + i][lCol + j]); +        Node::deleteNode(tableNode->node); +        tableNode->node = new Node(0L); +        newNum++; +        tableNode->node->tag = new Tag(*(mainTableNode->node->tag)); +        tableNode->merged = true; +        tableNode->mergedRow = tRow; +        tableNode->mergedCol = lCol; +      } +    } +} + + +void TableEditor::slotUnmergeCells() +{ +  int tRow, bRow, lCol, rCol; +  int selectionNum = m_dataTable->currentSelection(); +  if (selectionNum != -1) { +    QTableSelection selection = m_dataTable->selection(selectionNum); +    tRow = selection.topRow(); +    bRow = selection.bottomRow(); +    lCol = selection.leftCol(); +    rCol = selection.rightCol(); +  } else { +    tRow = m_row; +    bRow = m_row; +    lCol = m_col; +    rCol = m_col; +  } +  for (int row = tRow; row <= bRow; ++row) +    for (int col = lCol; col <= rCol; ++col) { +      TableNode tableNode = (*m_tableTags)[row][col]; +      if (!tableNode.merged) +        continue; +      TableNode newTableNode; +      int i = 0; +      int j = 0; +      for (QValueList<QValueList<TableNode> >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { +        j = 0; +        QValueList<TableNode>::Iterator it2 = (*it).begin(); +        while (it2 != (*it).end()) { +          if ((*it2).merged && +              tableNode.mergedRow == (*it2).mergedRow && +              tableNode.mergedCol == (*it2).mergedCol) { + +              Node::deleteNode((*it2).node); +              newNum--; +              it2 = (*it).erase(it2); +              newTableNode.merged = false; +              newTableNode.node = new Node(0L); +              newNum++; +              newTableNode.node->tag = new Tag(); +              newTableNode.node->tag->setDtd(m_dtd); +              if (m_tableTags == m_tableHeaderTags) { +                newTableNode.node->tag->parse("<th>", m_write); +              } else { +                newTableNode.node->tag->parse("<td>", m_write); +              } +              (*it).insert(it2, newTableNode); +              setCellText(m_dataTable, i, j, tagContent(newTableNode.node)); +              m_dataTable->item(i, j)->setEnabled(true); +          } else { +            ++it2; +          } +          j++; +        } +        i++; +      } +      newTableNode = (*m_tableTags)[tableNode.mergedRow][tableNode.mergedCol]; +      newTableNode.node->tag->deleteAttribute("colspan"); +      newTableNode.node->tag->deleteAttribute("rowspan"); +      //change the main node +      TableNode tmpNode = newTableNode; +      newTableNode.node = new Node(0L); +      newNum++; +      newTableNode.node->tag = new Tag(*(tmpNode.node->tag)); +      QValueList<QValueList<TableNode> >::Iterator iter1 = m_tableTags->at(tableNode.mergedRow); +      QValueList<TableNode>::Iterator iter2 = (*iter1).at(tableNode.mergedCol); +      iter2 = (*iter1).erase(iter2); +      (*iter1).insert(iter2, newTableNode); +      Node::deleteNode(tmpNode.node); +      newNum--; +    } +} + + + +void TableEditor::slotEditChildTable() +{ +  bool tempDocCreated = false; +  bool error = false; +  QValueList<NestedTable>::Iterator errorIt; +  Parser *localParser = 0L; +  Document *w = 0L; +  Node *savedBaseNode = 0L; +  NestedTable table; + +  for (QValueList<NestedTable>::Iterator it = m_nestedTables.begin(); it != m_nestedTables.end(); ++it) { +    table = *it; +    if (table.row == m_row  && table.col == m_col) { +      QString cellData = m_dataTable->text(table.row, table.col); +      int pos = cellData.find(table.nestedData); +      if (pos == -1) { +        KMessageBox::error(this, i18n("Cannot edit the child table; you probably modified the cell containing the table manually."), i18n("Cannot Read Table")); +        error = true; +        errorIt = it; +        break; +      } +      //create a new editor object and save the current state of the table there +      KTextEditor::Document *doc = +          KTextEditor::createDocument ("libkatepart", 0L, "KTextEditor::Document"); +      w = new Document(doc, 0L); +      QString tableData = readModifiedTable(); +      w->editIf->insertText(0, 0, tableData); +      localParser = new Parser(); +      savedBaseNode = baseNode; //we must save it as it's deleted in the localParser->parse(); +      baseNode = 0L; +      baseNode = localParser->parse(w); +      tempDocCreated = true; +      //try to find the child table position +      int pos2 = tableData.find(cellData); +      if (pos2 != -1) +        pos2 = tableData.find(table.nestedData, pos2); +      else { +        KMessageBox::error(this, i18n("Cannot edit the child table; you probably modified the cell containing the table manually."), i18n("Cannot Read Table")); +        error = true; +        errorIt = it; +        break; +      } +      tableData = tableData.left(pos2); +      table.bLine = tableData.contains('\n'); +      pos2 = tableData.findRev('\n'); +      if (pos2 != -1) { +        table.bCol = tableData.length() - pos2; +      } else { +        table.bCol = tableData.length(); +      } +      Node *childTableNode = localParser->nodeAt(table.bLine, table.bCol); +      if (!childTableNode->next || !QuantaCommon::closesTag(childTableNode->tag, childTableNode->next->tag)) { +        KMessageBox::error(this, i18n("Cannot find the closing tag of the child table; you have probably introduced unclosed tags in the table and have broken its consistency."), i18n("Cannot Read Table")); +        error = true; +        errorIt = it; +        break; +      } +      childTableNode->next->tag->endPos(table.eLine, table.eCol); +      TableEditor editor; +      editor.setCaption("Child Table Editor"); +      editor.setBaseURL(m_baseURL); +      editor.setTableArea(table.bLine, table.bCol, table.eLine, table.eCol, localParser); +      if (editor.exec()) { +       int length = table.nestedData.length(); +       (*it).nestedData =  editor.readModifiedTable(); +       cellData.replace(pos, length, (*it).nestedData); +       setCellText(m_dataTable, table.row, table.col, cellData); +      } +      //cleanup on success +      Node::deleteNode(baseNode); +      baseNode = savedBaseNode; +      delete localParser; +      delete w; +      return; +    } +  } +  //cleanup on error +  if (error) { +    m_nestedTables.erase(errorIt); +    m_dataTable->item(table.row, table.col)->setPixmap(QPixmap()); +    m_dataTable->updateCell(table.row, table.col); +    if (tempDocCreated) { +      Node::deleteNode(baseNode); +      baseNode = savedBaseNode; +      delete localParser; +      delete w; +    } +  } +} + + +void TableEditor::slotHelpInvoked() +{ +  kapp->invokeHelp("table-editor","quanta"); +} + +void TableEditor::configureTable( QTable * table ) +{ +  if (!table) +    return; +  for (int r=0; r<table->numRows(); r++) { +    table->adjustRow(r); +    for (int c=0; c<table->numCols(); c++) +      if (table->item(r, c)) +        table->item(r, c)->setWordWrap(true); +  } +  table->setColumnMovingEnabled(true); +  table->setRowMovingEnabled(true); +} + +void TableEditor::setCellText( QTable * table, int row, int col, const QString & text ) +{ +   table->setItem(row, col, new TableItem(table, QTableItem::OnTyping, text)); +} + +void TableEditor::configureCell(int row, int col, Node * node) +{ +   TableItem* item = (TableItem*) m_dataTable->item(row, col); +   if (!item) +     return; +   // Header (TH) or standard cell? +   item->setHeader(node->tag->name.lower() == "th"); +   // Horizontal alignment +   Qt::AlignmentFlags flags; +   QString align = node->tag->attributeValue("align", true); +   if (align == "right") +     flags = Qt::AlignRight; +   else if (align == "center") +     flags = Qt::AlignHCenter; +   else if (align == "justify") +     flags = Qt::AlignJustify; +   else if (align.isEmpty() && item->header()) +     flags = Qt::AlignHCenter;   // TH is centered by default +   else +     flags = Qt::AlignLeft; +   item->setAlignment(flags); +   // Vertical alignment +   QString valign = node->tag->attributeValue("valign", true); +   if (valign == "top") +     flags = Qt::AlignTop; +   else if (valign == "bottom") +     flags = Qt::AlignBottom; +   else flags = Qt::AlignVCenter; +   item->setVAlignment(flags); +} + +#include "tableeditor.moc" | 
