File indexing completed on 2024-05-12 16:41:06

0001 /********************************************************************************************
0002   Copyright (C) 2008 by Mathias Soeken (msoeken@informatik.uni-bremen.de)
0003             (C) 2005-2006 by Holger Danielsson (holger.danielsson@t-online.de)
0004             (C) 2012 by Michel Ludwig (michel.ludwig@kdemail.net)
0005  ********************************************************************************************/
0006 
0007 /***************************************************************************
0008  *                                                                         *
0009  *   This program is free software; you can redistribute it and/or modify  *
0010  *   it under the terms of the GNU General Public License as published by  *
0011  *   the Free Software Foundation; either version 2 of the License, or     *
0012  *   (at your option) any later version.                                   *
0013  *                                                                         *
0014  ***************************************************************************/
0015 
0016 #include "newtabulardialog.h"
0017 
0018 #include <algorithm>
0019 
0020 #include <QAction>
0021 #include <QCheckBox>
0022 #include <QColorDialog>
0023 #include <QComboBox>
0024 #include <QIcon>
0025 #include <QFrame>
0026 #include <QGridLayout>
0027 #include <QGroupBox>
0028 #include <QHBoxLayout>
0029 #include <QHeaderView>
0030 #include <QLabel>
0031 #include <QList>
0032 #include <QMenu>
0033 #include <QMouseEvent>
0034 #include <QPainter>
0035 #include <QPaintEvent>
0036 #include <QPushButton>
0037 #include <QSpinBox>
0038 #include <QTableWidget>
0039 #include <QToolBar>
0040 #include <QVBoxLayout>
0041 
0042 #include <KConfigGroup>
0043 #include <KLocalizedString>
0044 #include <KMessageBox>
0045 
0046 #include "codecompletion.h"
0047 #include "kiledebug.h"
0048 #include "latexcmd.h"
0049 
0050 #include "multicolumnborderhelper.h"
0051 #include "selectcoloraction.h"
0052 #include "selectframeaction.h"
0053 #include "tabularcell.h"
0054 #include "tabularcelldelegate.h"
0055 #include "tabularheaderitem.h"
0056 #include "tabularproperties.h"
0057 #include "tabulartable.h"
0058 
0059 namespace KileDialog {
0060 
0061 NewTabularDialog::NewTabularDialog(const QString &environment, KileDocument::LatexCommands *commands, KConfig *config, QWidget *parent)
0062     : Wizard(config, parent),
0063       m_latexCommands(commands),
0064       m_clCurrentBackground(Qt::white),
0065       m_clCurrentForeground(Qt::black),
0066       m_defaultEnvironment(environment)
0067 {
0068     setWindowTitle(i18n("Tabular Environments"));
0069 
0070     QWidget *page = new QWidget(this);
0071     QVBoxLayout *pageLayout = new QVBoxLayout();
0072     page->setLayout(pageLayout);
0073 
0074     m_Table = new TabularTable(page);
0075 
0076     m_tbFormat = new QToolBar(page);
0077     m_tbFormat->setMovable(false);
0078     m_tbFormat->setFloatable(false);
0079     m_tbFormat->setOrientation(Qt::Horizontal);
0080 
0081     m_acLeft = addAction(QIcon::fromTheme("format-justify-left"), i18n("Align Left"), SLOT(slotAlignLeft()), page);
0082     m_acCenter = addAction(QIcon::fromTheme("format-justify-center"), i18n("Align Center"), SLOT(slotAlignCenter()), page);
0083     m_acRight = addAction(QIcon::fromTheme("format-justify-right"), i18n("Align Right"), SLOT(slotAlignRight()), page);
0084     m_tbFormat->addSeparator();
0085     m_acBold = addAction(QIcon::fromTheme("format-text-bold"), i18n("Bold"), SLOT(slotBold()), page);
0086     m_acItalic = addAction(QIcon::fromTheme("format-text-italic"), i18n("Italic"), SLOT(slotItalic()), page);
0087     m_acUnderline = addAction(QIcon::fromTheme("format-text-underline"), i18n("Underline"), SLOT(slotUnderline()), page);
0088     m_tbFormat->addSeparator();
0089     m_acJoin = addAction(QIcon::fromTheme("joincells"), i18n("Join Cells"), SLOT(slotJoinCells()), page);
0090     m_acSplit = addAction(QIcon::fromTheme("splitcells"), i18n("Split Cells"), SLOT(slotSplitCells()), page);
0091     m_acSplit->setEnabled(false);
0092     m_acFrame = new SelectFrameAction(i18n("Edit Frame"), m_tbFormat);
0093     connect(m_acFrame, SIGNAL(borderSelected(int)), this, SLOT(slotFrame(int)));
0094     m_tbFormat->addAction(m_acFrame);
0095     m_tbFormat->addSeparator();
0096 
0097     m_acBackground = new SelectColorAction(QIcon::fromTheme("format-fill-color"), i18n("Background Color"), page);
0098     m_acBackground->setIcon(generateColorIcon(true));
0099     connect(m_acBackground, SIGNAL(triggered(bool)), this, SLOT(slotCurrentBackground()));
0100     connect(m_acBackground, SIGNAL(colorSelected(QColor)), this, SLOT(slotBackground(QColor)));
0101     m_tbFormat->addAction(m_acBackground);
0102     m_acForeground = new SelectColorAction(QIcon::fromTheme("format-stroke-color"), i18n("Text Color"), page);
0103     m_acForeground->setIcon(generateColorIcon(false));
0104     connect(m_acForeground, SIGNAL(colorSelected(QColor)), this, SLOT(slotForeground(QColor)));
0105     connect(m_acForeground, SIGNAL(triggered(bool)), this, SLOT(slotCurrentForeground()));
0106     m_tbFormat->addAction(m_acForeground);
0107 
0108     m_tbFormat->addSeparator();
0109     m_acClearText = addAction(QIcon::fromTheme("edit-clear"), i18n("Clear Text"), SLOT(slotClearText()), page); // FIXME icon
0110     m_acClearAttributes = addAction(QIcon::fromTheme("edit-clear"), i18n("Clear Attributes"), SLOT(slotClearAttributes()), page); // FIXME icon
0111     m_acClearAll = addAction(QIcon::fromTheme("edit-clear"), i18n("Clear All"), SLOT(slotClearAll()), page);
0112     m_tbFormat->addSeparator();
0113     m_acPaste = addAction(QIcon::fromTheme("edit-paste"), i18n("Paste content from clipboard"), m_Table, SLOT(paste()), page);
0114 
0115     /* checkable items */
0116     m_acLeft->setCheckable(true);
0117     m_acCenter->setCheckable(true);
0118     m_acRight->setCheckable(true);
0119     m_acBold->setCheckable(true);
0120     m_acItalic->setCheckable(true);
0121     m_acUnderline->setCheckable(true);
0122 
0123     QGroupBox *configPage = new QGroupBox(i18n("Environment"), page);
0124     QGridLayout *configPageLayout = new QGridLayout();
0125     configPage->setLayout(configPageLayout);
0126 
0127     QLabel *label = new QLabel(i18n("Name:"), configPage);
0128     m_cmbName = new QComboBox(configPage);
0129     label->setBuddy(m_cmbName);
0130     configPageLayout->addWidget(label, 0, 0);
0131     configPageLayout->addWidget(m_cmbName, 0, 1);
0132     label = new QLabel(i18n("Parameter:"), configPage);
0133     m_cmbParameter = new QComboBox(configPage);
0134     label->setBuddy(m_cmbParameter);
0135     configPageLayout->addWidget(label, 1, 0);
0136     configPageLayout->addWidget(m_cmbParameter, 1, 1);
0137 
0138     label = new QLabel(i18n("Number of rows:"), configPage);
0139     m_sbRows = new QSpinBox(configPage);
0140     m_sbRows->setMinimum(1);
0141     m_sbRows->setValue(3);
0142     label->setBuddy(m_sbRows);
0143     configPageLayout->addWidget(label, 0, 2);
0144     configPageLayout->addWidget(m_sbRows, 0, 3);
0145     label = new QLabel(i18n("Number of cols:"), configPage);
0146     m_sbCols = new QSpinBox(configPage);
0147     m_sbCols->setMinimum(1);
0148     m_sbCols->setValue(3);
0149     label->setBuddy(m_sbCols);
0150     configPageLayout->addWidget(label, 1, 2);
0151     configPageLayout->addWidget(m_sbCols, 1, 3);
0152 
0153     m_cbStarred = new QCheckBox(i18n("Use starred version"), configPage);
0154     label = new QLabel(i18n("Table width:"), configPage);
0155     m_leTableWidth = new QLineEdit(configPage);
0156     m_leTableWidth->setEnabled(false);
0157     connect(m_cbStarred, SIGNAL(stateChanged(int)), this, SLOT(slotStarredChanged()));
0158     label->setBuddy(m_leTableWidth);
0159     m_cbCenter = new QCheckBox(i18n("Center"), configPage);
0160     m_cbCenter->setChecked(true);
0161     m_cbBooktabs = new QCheckBox(i18n("Use booktabs package"), configPage);
0162     m_cbBullets = new QCheckBox(i18n("Insert bullets"), configPage);
0163     m_cbBullets->setChecked(true);
0164     configPageLayout->addWidget(m_cbStarred, 2, 0, 1, 2);
0165     configPageLayout->addWidget(label, 2, 2, 1, 1);
0166     configPageLayout->addWidget(m_leTableWidth, 2, 3, 1, 1);
0167     configPageLayout->addWidget(m_cbCenter, 3, 0, 1, 2);
0168     configPageLayout->addWidget(m_cbBooktabs, 3, 2, 1, 2);
0169     configPageLayout->addWidget(m_cbBullets, 4, 0, 1, 2);
0170 
0171     // whats this texts
0172     m_Table->setWhatsThis(i18n("Input data. Enter text when a cell is selected. When return is pressed, the adjacent cell will become selected."));
0173     m_cmbName->setWhatsThis(i18n("Choose an environment."));
0174     m_cmbParameter->setWhatsThis(i18n("Optional parameter for the chosen environment."));
0175     m_sbRows->setWhatsThis(i18n("Choose the number of table rows."));
0176     m_sbCols->setWhatsThis(i18n("Choose the number of table columns."));
0177     m_cbCenter->setWhatsThis(i18n("The tabular will be centered."));
0178     m_cbBooktabs->setWhatsThis(i18n("Use line commands of the booktabs package."));
0179     m_cbStarred->setWhatsThis(i18n("Use the starred version of this environment."));
0180     m_leTableWidth->setWhatsThis(i18n("Set the width of the table."));
0181     m_cbBullets->setWhatsThis(i18n("Insert bullets in each cell. Alt+Ctrl+Right and Alt+Ctrl+Left will move very quickly from one cell to another."));
0182     m_acBold->setWhatsThis(i18n("Set bold font series."));
0183     m_acItalic->setWhatsThis(i18n("Set italic font shape."));
0184     m_acUnderline->setWhatsThis(i18n("Set underlined font shape."));
0185     m_acLeft->setWhatsThis(i18n("The text will be aligned at the left border of the cell."));
0186     m_acCenter->setWhatsThis(i18n("The text will be centered."));
0187     m_acRight->setWhatsThis(i18n("The text will be aligned at the right border of the cell."));
0188     m_acJoin->setWhatsThis(i18n("Joins adjacent cells when they are in the same row."));
0189     m_acSplit->setWhatsThis(i18n("Splits joined cells."));
0190     m_acFrame->setWhatsThis(i18n("Choose the border for the selected cells. When clicking on the button, the current border will be applied to the selected cells."));
0191     m_acBackground->setWhatsThis(i18n("Choose a background color (needs color package)."));
0192     m_acForeground->setWhatsThis(i18n("Choose a text color (needs color package)."));
0193     m_acClearText->setWhatsThis(i18n("Clears the text of the selected cells but keeps attributes such as alignment and font shape."));
0194     m_acClearAttributes->setWhatsThis(i18n("Resets the attributes of the selected cells to the default values but keeps the text."));
0195     m_acClearAll->setWhatsThis(i18n("Clears the text of the selected cells and resets the attributes."));
0196     m_acPaste->setWhatsThis(i18n("Pastes a table stored in the clipboard into this wizard."));
0197 
0198     pageLayout->addWidget(m_tbFormat);
0199     pageLayout->addWidget(m_Table);
0200     pageLayout->addWidget(configPage);
0201     pageLayout->addWidget(buttonBox());
0202     setLayout(pageLayout);
0203 
0204     initEnvironments();
0205     updateColsAndRows();
0206     m_Table->item(0, 0)->setSelected(true);
0207 
0208     connect(m_Table, &KileDialog::TabularTable::itemSelectionChanged, this, &NewTabularDialog::slotItemSelectionChanged);
0209     connect(m_Table, &KileDialog::TabularTable::rowAppended, this, &NewTabularDialog::slotRowAppended);
0210     connect(m_Table, &KileDialog::TabularTable::colAppended, this, &NewTabularDialog::slotColAppended);
0211     connect(m_cmbName, static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::textActivated), this, &NewTabularDialog::slotEnvironmentChanged);
0212     connect(m_sbCols, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewTabularDialog::updateColsAndRows);
0213     connect(m_sbRows, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewTabularDialog::updateColsAndRows);
0214     connect(m_Table->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &NewTabularDialog::slotHeaderCustomContextMenuRequested);
0215     connect(this, &QDialog::accepted, this, &NewTabularDialog::slotAccepted);
0216 }
0217 
0218 NewTabularDialog::~NewTabularDialog()
0219 {
0220 }
0221 
0222 const QStringList& NewTabularDialog::requiredPackages() const
0223 {
0224     return m_requiredPackages;
0225 }
0226 
0227 QString NewTabularDialog::environment() const
0228 {
0229     return m_cmbName->currentText();
0230 }
0231 
0232 void NewTabularDialog::initEnvironments()
0233 {
0234     /* read all tabular environments and insert them into the combobox */
0235     QStringList list;
0236     QStringList::ConstIterator it;
0237     m_latexCommands->commandList(list, KileDocument::CmdAttrTabular, false);
0238     m_cmbName->addItems(list);
0239 
0240     // set default environment
0241     int index = m_cmbName->findText(m_defaultEnvironment);
0242     if(index != -1) {
0243         m_cmbName->setCurrentIndex(index);
0244     } else {
0245         if(m_defaultEnvironment == "array") {
0246             m_cmbName->insertItem(0, "array");
0247             m_cmbName->setCurrentIndex(0);
0248         }
0249     }
0250 
0251     // refresh other gui elements regarding environment combo box
0252     slotEnvironmentChanged(m_cmbName->currentText());
0253 }
0254 
0255 QAction * NewTabularDialog::addAction(const QIcon &icon, const QString &text, const char *method, QObject *parent)
0256 {
0257     return addAction(icon, text, this, method, parent);
0258 }
0259 
0260 QAction * NewTabularDialog::addAction(const QIcon &icon, const QString &text, QObject *receiver, const char *method, QObject *parent)
0261 {
0262     QAction *action = new QAction(icon, text, parent);
0263     connect(action, SIGNAL(triggered(bool)), receiver, method);
0264     m_tbFormat->addAction(action);
0265 
0266     return action;
0267 }
0268 
0269 void NewTabularDialog::alignItems(int alignment)
0270 {
0271     QList<int> checkColumns;
0272 
0273     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0274         item->setTextAlignment(alignment | Qt::AlignVCenter);
0275 
0276         int column = item->column();
0277         if(!checkColumns.contains(column)) {
0278             checkColumns.append(column);
0279         }
0280     }
0281 
0282     foreach(int column, checkColumns) {
0283         if(checkForColumnAlignment(column)) {
0284             static_cast<TabularHeaderItem*>(m_Table->horizontalHeaderItem(column))->setAlignment(alignment);
0285         }
0286     }
0287 
0288     slotItemSelectionChanged();
0289 }
0290 
0291 bool NewTabularDialog::checkForColumnAlignment(int column)
0292 {
0293     int alignment = m_Table->item(0, column)->textAlignment();
0294 
0295     for(int row = 1; row < m_Table->rowCount(); ++row) {
0296         if(m_Table->item(row, column)->textAlignment() != alignment) {
0297             return false;
0298         }
0299     }
0300 
0301     return true;
0302 }
0303 
0304 QIcon NewTabularDialog::generateColorIcon(bool background) const
0305 {
0306     QString iconName = background ? "format-fill-color" : "format-stroke-color";
0307     const int iconSize = style()->pixelMetric(QStyle::PM_ToolBarIconSize);
0308     QPixmap pixmap = QIcon::fromTheme(iconName).pixmap(iconSize);
0309 
0310     QPainter painter(&pixmap);
0311     QColor color = background ? m_clCurrentBackground : m_clCurrentForeground;
0312     painter.fillRect(1, pixmap.height() - 7, pixmap.width() - 2, 6, color);
0313     painter.end();
0314 
0315     return QIcon(pixmap);
0316 }
0317 
0318 bool NewTabularDialog::canJoin() const
0319 {
0320     const QList<QTableWidgetItem*> selectedItems = m_Table->selectedItems();
0321     if(selectedItems.count() < 2) {
0322         KILE_DEBUG_MAIN << "cannot join cells, because selectedItems.count() < 2";
0323         return false;
0324     }
0325 
0326     /* check whether all selected items are in the same row */
0327     int row = selectedItems[0]->row();
0328     for(int i = 1; i < selectedItems.count(); ++i) {
0329         if(selectedItems[i]->row() != row) {
0330             KILE_DEBUG_MAIN << "cannot join cells, because of different rows";
0331             return false;
0332         }
0333     }
0334 
0335     /* check whether all selected items are adjacent */
0336     QList<int> columns;
0337     for(QTableWidgetItem* item : selectedItems) {
0338         columns.append(item->column());
0339     }
0340     std::sort(columns.begin(), columns.end());
0341     if((columns.last() - columns.first()) != (columns.size() - 1)) {
0342         KILE_DEBUG_MAIN << "cannot join cells, because not all cells are adjacent";
0343         return false;
0344     }
0345 
0346     return true;
0347 }
0348 
0349 int NewTabularDialog::exec()
0350 {
0351     show();
0352     return Wizard::exec();
0353 }
0354 
0355 void NewTabularDialog::slotAccepted()
0356 {
0357     int rows = m_Table->rowCount();
0358     int columns = m_Table->columnCount();
0359     TabularProperties properties;
0360 
0361     //BEGIN preprocessing colors and border
0362     QColor firstColor;
0363     bool topBorder = true;
0364     for(int row = 0; row < rows; ++row) {
0365         bool sameColor = true;
0366         bool borderUnderRow = true;
0367         {
0368             const QBrush backgroundBrush = m_Table->item(row, 0)->background();
0369             if(backgroundBrush.style() != Qt::NoBrush) {
0370                 firstColor = backgroundBrush.color();
0371             }
0372         }
0373         for(int column = 0; column < columns; ++column) {
0374             TabularCell *cell = static_cast<TabularCell*>(m_Table->item(row, column));
0375 
0376             // Adjust right and bottom border for current item
0377             if(column < columns - 1) {
0378                 TabularCell *next = static_cast<TabularCell*>(m_Table->item(row, column + 1));
0379                 if(next->border() & TabularCell::Left) {
0380                     cell->setBorder(cell->border() | TabularCell::Right);
0381                 }
0382             }
0383             if(row < rows - 1) {
0384                 TabularCell *next = static_cast<TabularCell*>(m_Table->item(row + 1, column));
0385                 if(next->border() & TabularCell::Top) {
0386                     cell->setBorder(cell->border() | TabularCell::Bottom);
0387                 }
0388             }
0389 
0390             const QBrush backgroundBrush = m_Table->item(row, column)->background();
0391             if(backgroundBrush.style() != Qt::NoBrush) {
0392                 QColor currentColor = backgroundBrush.color();
0393                 properties.addColor(currentColor);
0394                 if(currentColor != firstColor) {
0395                     sameColor = false;
0396                 }
0397             }
0398 
0399             const QBrush foregroundBrush = m_Table->item(row, column)->foreground();
0400             if(foregroundBrush.style() != Qt::NoBrush) {
0401                 properties.addColor(foregroundBrush.color());
0402             }
0403 
0404             if(!(cell->border() & TabularCell::Bottom)) {
0405                 borderUnderRow = false;
0406             }
0407             if (row == 0 && !(cell->border() & TabularCell::Top)) {
0408                 topBorder = false;
0409             }
0410         }
0411         if(sameColor) {
0412             properties.addRowColor(row, firstColor);
0413         }
0414         if(borderUnderRow) {
0415             properties.addBorderUnderRow(row);
0416         }
0417     }
0418 
0419     if(topBorder) {
0420         properties.setHasTopBorder();
0421     }
0422 
0423     bool leftBorder = true;
0424     for(int column = 0; column < columns; ++column) {
0425         bool borderBesideColumn = true;
0426         for(int row = 0; row < rows; ++row) {
0427             TabularCell *cell = static_cast<TabularCell*>(m_Table->item(row, column));
0428 
0429             if(!(cell->border() & TabularCell::Right)) {
0430                 borderBesideColumn = false;
0431             }
0432             if (column == 0 && !(cell->border() & TabularCell::Left)) {
0433                 leftBorder = false;
0434             }
0435         }
0436         if(borderBesideColumn) {
0437             properties.addBorderBesideColumn(column);
0438         }
0439     }
0440 
0441     if(leftBorder) {
0442         properties.setHasLeftBorder();
0443     }
0444     //END
0445 
0446     /* bullet */
0447     if(m_cbBullets->isChecked()) {
0448         properties.setBullet(s_bullet);
0449     }
0450 
0451     /* environment */
0452     QString environmentFormatted = m_cmbName->currentText();
0453     QString tableWidth;
0454     if(m_cbStarred->isEnabled() && m_cbStarred->isChecked()) {
0455         environmentFormatted += '*';
0456     }
0457 
0458     // Environment needs a width
0459     if(m_leTableWidth->isEnabled()) {
0460         tableWidth = '{' + m_leTableWidth->text() + '}';
0461     }
0462 
0463     /* build table parameter */
0464     QString tableParameter;
0465     if(m_cmbParameter->currentIndex() != 0) {
0466         tableParameter = '[' + m_cmbParameter->currentText() + ']';
0467     }
0468 
0469     /* build table alignment */
0470     QString tableAlignment = QString('{');
0471     if(properties.hasLeftBorder()) {
0472         tableAlignment += '|';
0473     }
0474     for(int column = 0; column < columns; ++column) {
0475         TabularHeaderItem *headerItem = static_cast<TabularHeaderItem*>(m_Table->horizontalHeaderItem(column));
0476         if(headerItem->suppressSpace()) {
0477             tableAlignment += QString("@{%1}").arg(properties.bullet());
0478         } else if(headerItem->dontSuppressSpace()) {
0479             tableAlignment += QString("!{%1}").arg(properties.bullet());
0480         }
0481         if(headerItem->insertBefore()) {
0482             tableAlignment += QString(">{%1}").arg(properties.bullet());
0483         }
0484 
0485         switch(headerItem->alignment()) {
0486         case Qt::AlignLeft:
0487             tableAlignment += 'l';
0488             break;
0489         case Qt::AlignHCenter:
0490             tableAlignment += 'c';
0491             break;
0492         case Qt::AlignRight:
0493             tableAlignment += 'r';
0494             break;
0495         case TabularHeaderItem::AlignP:
0496             tableAlignment += QString("p{%1}").arg(properties.bullet());
0497             break;
0498         case TabularHeaderItem::AlignB:
0499             tableAlignment += QString("b{%1}").arg(properties.bullet());
0500             break;
0501         case TabularHeaderItem::AlignM:
0502             tableAlignment += QString("m{%1}").arg(properties.bullet());
0503             break;
0504         case TabularHeaderItem::AlignX:
0505             tableAlignment += 'X';
0506             break;
0507         }
0508 
0509         if(headerItem->insertAfter()) {
0510             tableAlignment += QString("<{%1}").arg(properties.bullet());
0511         }
0512 
0513         if(properties.hasBorderBesideColumn(column)) {
0514             tableAlignment += '|';
0515         }
0516     }
0517     tableAlignment += '}';
0518 
0519     /* build top border */
0520     QString topBorderStr;
0521     if(properties.hasTopBorder()) {
0522         if(m_cbBooktabs->isChecked()) { // we need a toprule with booktabs here
0523             topBorderStr = "\\toprule";
0524         }
0525         else {
0526             topBorderStr = "\\hline";
0527         }
0528     }
0529     else {
0530         MultiColumnBorderHelper topBorderHelper;
0531         for(int column = 0; column < columns; ++column) {
0532             TabularCell *cell = static_cast<TabularCell*>(m_Table->item(0, column));
0533             if(cell->border() & TabularCell::Top) {
0534                 topBorderHelper.addColumn(column);
0535             }
0536         }
0537         topBorderHelper.finish();
0538         topBorderStr = topBorderHelper.toLaTeX();
0539     }
0540 
0541     if(m_cbCenter->isChecked()) {
0542         m_td.tagBegin += "\\begin{center}\n";
0543     }
0544 
0545     m_td.tagBegin += QString("\\begin{%1}%2%3%4%5\n")
0546                      .arg(environmentFormatted, tableWidth, tableParameter, tableAlignment, topBorderStr);
0547 
0548     /* required packages */
0549     m_requiredPackages.clear();
0550     if(properties.requiredPackages().count()) {
0551         m_td.tagBegin += "% use packages: " + properties.requiredPackages().join(",") + '\n';
0552         m_requiredPackages << properties.requiredPackages();
0553     }
0554 
0555     QColor rowColor;
0556     for(int row = 0; row < rows; ++row) {
0557         rowColor = properties.rowColor(row);
0558         if(rowColor.isValid()) {
0559             m_td.tagBegin += "\\rowcolor{" + properties.colorName(rowColor) + "}\n";
0560         }
0561         MultiColumnBorderHelper columnBorderHelper;
0562         for(int column = 0; column < columns;) {
0563             TabularCell *cell = static_cast<TabularCell*>(m_Table->item(row, column));
0564             QString content = cell->toLaTeX(properties);
0565             int columnSpan = m_Table->columnSpan(row, column);
0566 
0567             if(!properties.hasBorderUnderRow(row) && (cell->border() & TabularCell::Bottom)) {
0568                 for(int c2 = 0; c2 < columnSpan; ++c2) {
0569                     columnBorderHelper.addColumn(column + c2);
0570                 }
0571             }
0572 
0573             QString sep = " & ";
0574             if(column + columnSpan >= columns) {
0575                 QString end;
0576                 sep.clear();
0577                 if(properties.hasBorderUnderRow(row)) {
0578                     if(m_cbBooktabs->isChecked()) { // we need a midrule with booktabs.
0579                         if(row < rows-1) {
0580                             end = "\\midrule";
0581                         }
0582                         else { // last line gets a bottomrule
0583                             end = "\\bottomrule";
0584                         }
0585                     }
0586                     else {
0587                         end = "\\hline";
0588                     }
0589                 }
0590                 else {
0591                     columnBorderHelper.finish();
0592                     end = columnBorderHelper.toLaTeX();
0593                 }
0594                 if(row < rows - 1 || !end.isEmpty()) {
0595                     sep = "\\\\";
0596                 }
0597                 sep += end + '\n';
0598             }
0599             m_td.tagBegin += content + sep;
0600 
0601             column += columnSpan;
0602         }
0603     }
0604 
0605     m_td.tagEnd += QString("\\end{%1}\n").arg(environmentFormatted);
0606 
0607     if(m_cbCenter->isChecked()) {
0608         m_td.tagEnd += "\\end{center}\n";
0609     }
0610 
0611     QHashIterator<QString, QString> itColorName(properties.colorNames());
0612     QString colorNames = "";
0613     while(itColorName.hasNext()) {
0614         itColorName.next();
0615         colorNames += "\\definecolor{" + itColorName.value() + "}{rgb}{";
0616         QColor color(itColorName.key());
0617         colorNames += QString::number(color.redF()) + ','
0618                       + QString::number(color.greenF()) + ','
0619                       + QString::number(color.blueF()) + "}\n";
0620     }
0621     m_td.tagBegin = colorNames + m_td.tagBegin;
0622 
0623     if(properties.useMultiColumn()) {
0624         m_td.tagBegin = "\\newcommand{\\mc}[3]{\\multicolumn{#1}{#2}{#3}}\n"
0625                         + m_td.tagBegin;
0626     }
0627 
0628     /* use {} if mc was defined */
0629     if(properties.useMultiColumn()) {
0630         m_td.tagBegin = "{%\n" + m_td.tagBegin;
0631         m_td.tagEnd += "}%\n";
0632     }
0633 }
0634 
0635 void NewTabularDialog::updateColsAndRows()
0636 {
0637     int addedCols = m_sbCols->value() - m_Table->columnCount();
0638     int addedRows = m_sbRows->value() - m_Table->rowCount();
0639 
0640     // check whether content could be deleted when shrinking the table
0641     if(addedCols < 0) {
0642         bool hasContent = false;
0643         for(int column = m_Table->columnCount() + addedCols; column < m_Table->columnCount(); ++column) {
0644             for(int row = 0; row < m_Table->rowCount(); ++row) {
0645                 if(m_Table->item(row, column) && !(m_Table->item(row, column)->text().isEmpty())) {
0646                     hasContent = true;
0647                     break;
0648                 }
0649             }
0650             if(hasContent) break;
0651         }
0652 
0653         if(hasContent) {
0654             if(KMessageBox::questionTwoActions(m_Table, i18n("Setting the new size for the table will delete content. Are you sure to set the new size?"), i18n("Resizing table"),
0655                                                KStandardGuiItem::ok(), KStandardGuiItem::cancel()) == KMessageBox::SecondaryAction) {
0656                 m_sbCols->setValue(m_Table->columnCount());
0657                 return;
0658             }
0659         }
0660     }
0661 
0662     // check whether content could be deleted when shrinking the table
0663     if(addedRows < 0) {
0664         bool hasContent = false;
0665         for(int row = m_Table->rowCount() + addedRows; row < m_Table->rowCount(); ++row) {
0666             for(int column = 0; column < m_Table->columnCount(); ++column) {
0667                 if(m_Table->item(row, column) && !(m_Table->item(row, column)->text().isEmpty())) {
0668                     hasContent = true;
0669                     break;
0670                 }
0671             }
0672             if(hasContent) break;
0673         }
0674 
0675         if(hasContent) {
0676             if(KMessageBox::questionTwoActions(m_Table, i18n("Setting the new size for the table will delete content. Are you sure to set the new size?"), i18n("Resizing table"),
0677                                                KStandardGuiItem::ok(), KStandardGuiItem::cancel()) == KMessageBox::SecondaryAction) {
0678                 m_sbRows->setValue(m_Table->rowCount());
0679                 return;
0680             }
0681         }
0682     }
0683 
0684     m_Table->setColumnCount(m_sbCols->value());
0685     m_Table->setRowCount(m_sbRows->value());
0686 
0687     if(addedCols > 0) {
0688         for(int i = m_Table->columnCount() - addedCols; i < m_Table->columnCount(); ++i) {
0689             TabularHeaderItem *headerItem = new TabularHeaderItem(m_Table->horizontalHeader());
0690             connect(headerItem, SIGNAL(alignColumn(int)), this, SLOT(slotAlignColumn(int)));
0691             m_Table->setHorizontalHeaderItem(i, headerItem);
0692 
0693             // each cell should be an item. This is necessary for selection checking
0694             for(int row = 0; row < m_Table->rowCount(); ++row) {
0695                 QTableWidgetItem *item = new TabularCell(QString());
0696                 item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0697                 m_Table->setItem(row, i, item);
0698             }
0699         }
0700     }
0701 
0702     if(addedRows > 0) {
0703         for(int i = m_Table->rowCount() - addedRows; i < m_Table->rowCount(); ++i) {
0704             m_Table->resizeRowToContents(i);
0705 
0706             // each cell should be an item. This is necessary for selection checking
0707             for(int column = 0; column < m_Table->columnCount(); ++column) {
0708                 QTableWidgetItem *item = new TabularCell(QString());
0709                 item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0710                 m_Table->setItem(i, column, item);
0711             }
0712         }
0713     }
0714 }
0715 
0716 void NewTabularDialog::slotEnvironmentChanged(const QString &environment)
0717 {
0718     // clear parameter combobox
0719     m_cmbParameter->clear();
0720     m_cmbParameter->setEnabled(false);
0721     // disable table width line edit
0722     m_leTableWidth->setEnabled(false);
0723 
0724     // look for environment parameter in dictionary
0725     KileDocument::LatexCmdAttributes attr;
0726     if(m_latexCommands->commandAttributes(environment, attr)) {
0727         // starred version
0728         m_cbStarred->setEnabled(attr.starred);
0729         slotStarredChanged();
0730 
0731         // option
0732         if(attr.option.indexOf('[') == 0) {
0733             QStringList optionlist = attr.option.split("");
0734             optionlist.removeAll("");
0735             if(optionlist.count() > 2) {
0736                 // ok, let's enable it
0737                 m_cmbParameter->setEnabled(true);
0738                 m_cmbParameter->addItem(QString());
0739                 // insert some options
0740                 for(int i = 1; i < optionlist.count() - 1; ++i) {
0741                     m_cmbParameter->addItem(optionlist[i]);
0742                 }
0743             }
0744         }
0745 
0746         // enable table width line edit if needed
0747         if( attr.parameter.indexOf('{') == 0 ) {
0748             m_leTableWidth->setEnabled(true);
0749         }
0750     }
0751 
0752     // has X alignment
0753     bool hasXAlignment = (environment == "tabularx" || environment == "xtabular");
0754     for(int column = 0; column < m_Table->columnCount(); ++column) {
0755         static_cast<TabularHeaderItem*>(m_Table->horizontalHeaderItem(column))->setHasXAlignment(hasXAlignment);
0756     }
0757 }
0758 
0759 void NewTabularDialog::slotItemSelectionChanged()
0760 {
0761     /* unset some items */
0762     m_acLeft->setChecked(false);
0763     m_acCenter->setChecked(false);
0764     m_acRight->setChecked(false);
0765 
0766     /* set all font format items and eventually unset them later */
0767     m_acBold->setChecked(true);
0768     m_acItalic->setChecked(true);
0769     m_acUnderline->setChecked(true);
0770 
0771     /* nothing selected, nothing to do! */
0772     QList<QTableWidgetItem*> selectedItems = m_Table->selectedItems();
0773     if(selectedItems.count() == 0) return;
0774 
0775     /* check for alignment */
0776     int alignment = selectedItems[0]->textAlignment();
0777     bool sameAlignment = true;
0778     for(int i = 1; i < selectedItems.count(); ++i) {
0779         if(selectedItems[i]->textAlignment() != alignment) {
0780             sameAlignment = false;
0781             break;
0782         }
0783     }
0784     if(sameAlignment) {
0785         m_acLeft->setChecked(alignment & Qt::AlignLeft);
0786         m_acCenter->setChecked(alignment & Qt::AlignHCenter);
0787         m_acRight->setChecked(alignment & Qt::AlignRight);
0788     }
0789 
0790     /* check for font format */
0791     bool unsetBold = false;
0792     bool unsetItalic = false;
0793     bool unsetUnderline = false;
0794     foreach(QTableWidgetItem *item, selectedItems) {
0795         if(!unsetBold && !item->font().bold()) {
0796             m_acBold->setChecked(false);
0797             unsetBold = true;
0798         }
0799         if(!unsetItalic && !item->font().italic()) {
0800             m_acItalic->setChecked(false);
0801             unsetItalic = true;
0802         }
0803         if(!unsetUnderline && !item->font().underline()) {
0804             m_acUnderline->setChecked(false);
0805             unsetUnderline = true;
0806         }
0807         if(unsetBold && unsetItalic && unsetUnderline) {
0808             break;
0809         }
0810     }
0811 
0812     m_acJoin->setEnabled(canJoin());
0813 
0814     /* split action */
0815     m_acSplit->setEnabled(selectedItems.count() == 1 &&
0816                           m_Table->columnSpan(selectedItems[0]->row(), selectedItems[0]->column()) > 1);
0817 }
0818 
0819 void NewTabularDialog::slotHeaderCustomContextMenuRequested(const QPoint &pos)
0820 {
0821     int logicalIndex = m_Table->horizontalHeader()->logicalIndexAt(pos);
0822     if(logicalIndex == -1) return;
0823 
0824     QMenu *popup = static_cast<TabularHeaderItem*>(m_Table->horizontalHeaderItem(logicalIndex))->popupMenu();
0825     popup->exec(m_Table->horizontalHeader()->mapToGlobal(pos));
0826 }
0827 
0828 void NewTabularDialog::slotAlignColumn(int alignment)
0829 {
0830     TabularHeaderItem *headerItem = static_cast<TabularHeaderItem*>(sender());
0831 
0832     // find column
0833     for(int column = 0; column < m_Table->columnCount(); ++column) {
0834         if(m_Table->horizontalHeaderItem(column) == headerItem) {
0835             for(int row = 0; row < m_Table->rowCount(); ++row) {
0836                 m_Table->item(row, column)->setTextAlignment(Qt::AlignVCenter | alignment);
0837             }
0838 
0839             break;
0840         }
0841     }
0842 }
0843 
0844 void NewTabularDialog::slotAlignLeft()
0845 {
0846     alignItems(Qt::AlignLeft);
0847 }
0848 
0849 void NewTabularDialog::slotAlignCenter()
0850 {
0851     alignItems(Qt::AlignHCenter);
0852 }
0853 
0854 void NewTabularDialog::slotAlignRight()
0855 {
0856     alignItems(Qt::AlignRight);
0857 }
0858 
0859 void NewTabularDialog::slotBold()
0860 {
0861     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0862         QFont font = item->font();
0863         font.setBold(!font.bold());
0864         item->setFont(font);
0865     }
0866     slotItemSelectionChanged();
0867 }
0868 
0869 void NewTabularDialog::slotItalic()
0870 {
0871     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0872         QFont font = item->font();
0873         font.setItalic(!font.italic());
0874         item->setFont(font);
0875     }
0876     slotItemSelectionChanged();
0877 }
0878 
0879 void NewTabularDialog::slotUnderline()
0880 {
0881     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0882         QFont font = item->font();
0883         font.setUnderline(!font.underline());
0884         item->setFont(font);
0885     }
0886     slotItemSelectionChanged();
0887 }
0888 
0889 void NewTabularDialog::slotJoinCells()
0890 {
0891     if(!canJoin()) return;
0892 
0893     const QList<QTableWidgetItem*> selectedItems = m_Table->selectedItems();
0894     int row = selectedItems[0]->row();
0895 
0896     QList<int> columns;
0897     for(QTableWidgetItem* item : selectedItems) {
0898         columns.append(item->column());
0899     }
0900     std::sort(columns.begin(), columns.end());
0901 
0902     int newColumnSpan = columns.size();
0903 
0904     /* check for already joined cells in range */
0905     foreach(int column, columns) {
0906         int thisColumnSpan = m_Table->columnSpan(row, column);
0907         if(thisColumnSpan > 1) {
0908             newColumnSpan = qMax(newColumnSpan, thisColumnSpan + column - columns.first());
0909             m_Table->setSpan(row, column, 1, 1);
0910         }
0911     }
0912 
0913     /* everything's fine -> join the cells */
0914     m_Table->setSpan(row, columns.first(), 1, newColumnSpan);
0915 
0916     slotItemSelectionChanged();
0917 }
0918 
0919 void NewTabularDialog::slotSplitCells()
0920 {
0921     /* one item has to be selected */
0922     if(m_Table->selectedItems().count() != 1) return;
0923 
0924     QTableWidgetItem *selectedItem = m_Table->selectedItems()[0];
0925 
0926     if(m_Table->columnSpan(selectedItem->row(), selectedItem->column()) > 1) {
0927         m_Table->setSpan(selectedItem->row(), selectedItem->column(), 1, 1);
0928     }
0929 
0930     slotItemSelectionChanged();
0931 }
0932 
0933 void NewTabularDialog::slotFrame(int border)
0934 {
0935     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0936         static_cast<TabularCell*>(item)->setBorder(border);
0937     }
0938 }
0939 
0940 void NewTabularDialog::slotBackground(const QColor &color)
0941 {
0942     m_clCurrentBackground = color;
0943     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0944         item->setBackground(color);
0945     }
0946     m_acBackground->setIcon(generateColorIcon(true));
0947     m_acForeground->setIcon(generateColorIcon(false));
0948 }
0949 
0950 void NewTabularDialog::slotForeground(const QColor &color)
0951 {
0952     m_clCurrentForeground = color;
0953     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0954         item->setForeground(color);
0955     }
0956     m_acBackground->setIcon(generateColorIcon(true));
0957     m_acForeground->setIcon(generateColorIcon(false));
0958 }
0959 
0960 void NewTabularDialog::slotCurrentBackground()
0961 {
0962     slotBackground(m_clCurrentBackground);
0963 }
0964 
0965 void NewTabularDialog::slotCurrentForeground()
0966 {
0967     slotForeground(m_clCurrentForeground);
0968 }
0969 
0970 void NewTabularDialog::slotClearText()
0971 {
0972     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0973         item->setText(QString());
0974     }
0975 }
0976 
0977 void NewTabularDialog::slotClearAttributes()
0978 {
0979     foreach(QTableWidgetItem *item, m_Table->selectedItems()) {
0980         item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0981         QFont font = item->font();
0982         font.setBold(false);
0983         font.setItalic(false);
0984         font.setUnderline(false);
0985         item->setFont(font);
0986         item->setBackground(QBrush());
0987         item->setForeground(QBrush());
0988     }
0989 }
0990 
0991 void NewTabularDialog::slotClearAll()
0992 {
0993     slotClearText();
0994     slotClearAttributes();
0995 }
0996 
0997 void NewTabularDialog::slotRowAppended()
0998 {
0999     const int newValue = m_sbRows->value() + 1;
1000 
1001     m_sbRows->setMaximum(qMax(m_sbRows->maximum(), newValue));
1002     m_sbRows->setValue(newValue);
1003 
1004     updateColsAndRows();
1005 }
1006 
1007 void NewTabularDialog::slotColAppended()
1008 {
1009     const int newValue = m_sbCols->value() + 1;
1010 
1011     m_sbCols->setMaximum(qMax(m_sbCols->maximum(), newValue));
1012     m_sbCols->setValue(newValue);
1013 
1014     updateColsAndRows();
1015 }
1016 
1017 }
1018 
1019 void KileDialog::NewTabularDialog::slotStarredChanged()
1020 {
1021     m_leTableWidth->setEnabled(m_cbStarred->isChecked() && m_cbStarred->isEnabled());
1022 }