/*************************************************************************** tableeditor.cpp - table editor dialog begin : Thu 15 Apr 2004 copyright : (C) 2004 by Andras Mantia ***************************************************************************/ /*************************************************************************** * * 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 #include #include #include #include #include #include #include #include #include //qt includes #include #include #include #include #include #include #include #include #include #include //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(TQWidget* parent, const char* name) : TableEditorS(parent, name) { m_popup = new TDEPopupMenu(); m_cellEditId = m_popup->insertItem(i18n("&Edit Cell Properties"), this ,TQT_SLOT(slotEditCell())); m_rowEditId = m_popup->insertItem(i18n("Edit &Row Properties"), this ,TQT_SLOT(slotEditRow())); // m_colEditId = m_popup->insertItem(i18n("Edit &Column Properties"), this ,TQT_SLOT(slotEditCol())); m_mergeSeparatorId = m_popup->insertSeparator(); m_mergeCellsId = m_popup->insertItem(i18n("Merge Cells"), this, TQT_SLOT(slotMergeCells())); m_unmergeCellsId = m_popup->insertItem(i18n("Break Merging"), this, TQT_SLOT(slotUnmergeCells())); m_popup->insertSeparator(); m_popup->insertItem(i18n("&Insert Row"), this, TQT_SLOT(slotInsertRow())); m_popup->insertItem(i18n("Insert Co&lumn"), this, TQT_SLOT(slotInsertCol())); m_popup->insertItem(i18n("Remove Row"), this, TQT_SLOT(slotRemoveRow())); m_popup->insertItem(i18n("Remove Column"), this, TQT_SLOT(slotRemoveCol())); m_popup->insertSeparator(); m_popup->insertItem(i18n("Edit &Table Properties"), this, TQT_SLOT(slotEditTable())); m_editChildId = m_popup->insertItem(i18n("Edit Child Table"), this, TQT_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 TQValueList >; m_tableHeaderTags = new TQValueList >; m_tableFooterTags = new TQValueList >; m_tableTags = 0L; m_tableDataRows = new TQValueList; m_tableHeaderRows = new TQValueList; m_tableFooterRows = new TQValueList; m_tableRows = 0L; m_createNodes = true; newNum += 7; connect(headerColSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotAddRemoveCol(int))); connect(headerRowSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotAddRemoveRow(int))); connect(rowSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotAddRemoveRow(int))); connect(colSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotAddRemoveCol(int))); connect(footerRowSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotAddRemoveRow(int))); connect(footerColSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotAddRemoveCol(int))); connect(tableData, TQT_SIGNAL(contextMenuRequested(int,int,const TQPoint&)), TQT_SLOT(slotContextMenuRequested(int,int,const TQPoint&))); connect(pushButton7, TQT_SIGNAL(clicked()), TQT_SLOT(slotEditTable())); connect(pushButton7_2, TQT_SIGNAL(clicked()), TQT_SLOT(slotEditTableBody())); connect(pushButton7_3, TQT_SIGNAL(clicked()), TQT_SLOT(slotEditTableHeader())); connect(pushButton7_4, TQT_SIGNAL(clicked()), TQT_SLOT(slotEditTableFooter())); connect(headerTableData, TQT_SIGNAL(contextMenuRequested(int,int,const TQPoint&)), TQT_SLOT(slotContextMenuRequested(int,int,const TQPoint&))); connect(footerTableData, TQT_SIGNAL(contextMenuRequested(int,int,const TQPoint&)), TQT_SLOT(slotContextMenuRequested(int,int,const TQPoint&))); connect(tabWidget, TQT_SIGNAL(currentChanged(TQWidget*)), TQT_SLOT(slotTabChanged(TQWidget*))); connect(buttonHelp, TQT_SIGNAL(clicked()), TQT_SLOT(slotHelpInvoked())); connect(tableData, TQT_SIGNAL(valueChanged(int,int)), TQT_SLOT(slotEditCellText(int,int))); connect(headerTableData, TQT_SIGNAL(valueChanged(int,int)), TQT_SLOT(slotEditCellText(int,int))); connect(footerTableData, TQT_SIGNAL(valueChanged(int,int)), TQT_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 TQPoint & 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); } TQTableSelection selection = m_dataTable->selection(m_dataTable->currentSelection()); TQRect rect(TQPoint(selection.topRow(), selection.leftCol()) , TQPoint(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; TQValueList tableRowTags; TQValueVector< TQValueVector > mergeMatrix; mergeMatrix.resize(pInitialTableSize); for (uint i = 0; i < pInitialTableSize; i++) mergeMatrix[i].resize(pInitialTableSize); TableNode tableNode; Node *n = node; while (n != lastNode->nextSibling()) { TQString 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(TQIconSet(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 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 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("", 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; itag = new Tag(); tableNode.node->tag->setDtd(m_dtd); tableNode.node->tag->parse("", 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); } TQString 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; } TQString 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("", m_write); } if (!m_tfoot) { m_tfoot = new Tag(); newNum++; m_tfoot->parse("", 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( TQWidget *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); } TQString TableEditor::readModifiedTable() { TQString tableString; tableString = m_table->toString(); if (!captionText->text().isEmpty()) { tableString += indent(2); tableString += "<" + QuantaCommon::tagCase("caption") + ">"; tableString += captionText->text(); tableString += ""; } for (TQValueList::Iterator it = m_colTags.begin(); it != m_colTags.end(); ++it) { tableString += indent(2); tableString += (*it)->toString(); } if (headerCheckBox->isChecked() && headerTableData->numRows() > 0) { //insert the 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 += "name) +">"; } if (footerCheckBox->isChecked() && footerTableData->numRows() > 0) { //insert the 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 += "name) +">"; } //insert the tag if (!m_tbody) { m_tbody = new Tag(); newNum++; m_tbody->parse("", 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 and tags tableString += indent(2); tableString += "name) +">"; tableString += "\n"; tableString += "name) + ">"; //kdDebug(24000) << tableString << endl; return tableString; } TQString TableEditor::indent( int n ) { TQString str; str.fill(' ', n); str.prepend('\n'); return str; } TQString TableEditor::cellValue( int row, int col ) { if (!m_dataTable) return TQString(); TQString str; Node *node = (*m_tableTags)[row][col].node; if (!node) return TQString(); str = node->tag->toString(); str += m_dataTable->text(row, col); str += "tag->name) + ">"; return str; } TQString TableEditor::tableToString() { TQString 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(""); 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 += "name) +">"; else tableStr += QuantaCommon::tagCase(""); } return tableStr; } TQString TableEditor::tagContent(Node *node) { if (!node) return TQString(); TQString 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 TQString(); } } 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("", m_write); TQValueList::Iterator rowIt = m_tableRows->at(num); if (rowIt != m_tableRows->end()) m_tableRows->insert(rowIt, tableNode); else m_tableRows->append(tableNode); TQValueList 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("
", m_write); } else { tableNode.node->tag->parse("", m_write); } tableRowTags.append(tableNode); setCellText(m_dataTable, num, i, ""); } TQValueList >::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 (TQValueList >::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("", m_write); } else { tableNode.node->tag->parse("", 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 (TQValueList >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { j = 0; for (TQValueList::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++; } TQValueList updatedMainNodes; TQValueList >::Iterator it2 = m_tableTags->at(m_row); for (TQValueList::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", TQString("%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); TQValueList::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 (TQValueList >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { j = 0; for (TQValueList::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; TQValueList updatedMainNodes; for (TQValueList >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { TQValueList::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", TQString("%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("", m_write); m_thead = new Tag(); m_thead->setDtd(m_dtd); newNum++; m_thead->parse("", m_write); m_tfoot = new Tag(); m_tfoot->setDtd(m_dtd); newNum++; m_tfoot->parse("", m_write); m_tbody = new Tag(); m_tbody->setDtd(m_dtd); newNum++; m_tbody->parse("", 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( TQValueList *table ) { for (TQValueList::Iterator it = table->begin(); it != table->end(); ++it) { Node::deleteNode((*it).node); newNum--; } delete table; newNum--; } void TableEditor::deleteMatrix( TQValueList > *matrix ) { for (TQValueList >::Iterator it = matrix->begin(); it != matrix->end(); ++it) { for (TQValueList::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 TQTableSelection 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", TQString("%1").arg(rCol - lCol + 1)); if (bRow - tRow > 0) mainTableNode->node->tag->editAttribute("rowspan", TQString("%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) { TQTableSelection 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 (TQValueList >::Iterator it = m_tableTags->begin(); it != m_tableTags->end(); ++it) { j = 0; TQValueList::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("
", m_write); } else { newTableNode.node->tag->parse("", 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)); TQValueList >::Iterator iter1 = m_tableTags->at(tableNode.mergedRow); TQValueList::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; TQValueList::Iterator errorIt; Parser *localParser = 0L; Document *w = 0L; Node *savedBaseNode = 0L; NestedTable table; for (TQValueList::Iterator it = m_nestedTables.begin(); it != m_nestedTables.end(); ++it) { table = *it; if (table.row == m_row && table.col == m_col) { TQString 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); TQString 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(TQPixmap()); 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( TQTable * table ) { if (!table) return; for (int r=0; rnumRows(); r++) { table->adjustRow(r); for (int c=0; cnumCols(); c++) if (table->item(r, c)) table->item(r, c)->setWordWrap(true); } table->setColumnMovingEnabled(true); table->setRowMovingEnabled(true); } void TableEditor::setCellText( TQTable * table, int row, int col, const TQString & text ) { table->setItem(row, col, new TableItem(table, TQTableItem::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"); //Qt::Horizontal alignment TQt::AlignmentFlags flags; TQString align = node->tag->attributeValue("align", true); if (align == "right") flags = TQt::AlignRight; else if (align == "center") flags = TQt::AlignHCenter; else if (align == "justify") flags = TQt::AlignJustify; else if (align.isEmpty() && item->header()) flags = TQt::AlignHCenter; // TH is centered by default else flags = TQt::AlignLeft; item->setAlignment(flags); //Qt::Vertical alignment TQString valign = node->tag->attributeValue("valign", true); if (valign == "top") flags = TQt::AlignTop; else if (valign == "bottom") flags = TQt::AlignBottom; else flags = TQt::AlignVCenter; item->setVAlignment(flags); } #include "tableeditor.moc"