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 }