File indexing completed on 2024-05-12 16:35:26
0001 /* This file is part of the KDE project 0002 Copyright (C) 2006 Robert Knight <robertknight@gmail.com> 0003 (C) 2006 Tomas Mecir <mecirt@gmail.com> 0004 (C) 2002-2003 Norbert Andres <nandres@web.de> 0005 (C) 2002 Ariya Hidayat <ariya@kde.org> 0006 (C) 2002 John Dailey <dailey@vt.edu> 0007 (C) 2002 Werner Trobin <trobin@kde.org> 0008 (C) 2001-2002 Philipp Mueller <philipp.mueller@gmx.de> 0009 (C) 1999-2002 Laurent Montel <montel@kde.org> 0010 (C) 2000 David Faure <faure@kde.org> 0011 (C) 1998-2000 Torben Weis <weis@kde.org> 0012 0013 This library is free software; you can redistribute it and/or 0014 modify it under the terms of the GNU Library General Public 0015 License as published by the Free Software Foundation; either 0016 version 2 of the License, or (at your option) any later version. 0017 0018 This library is distributed in the hope that it will be useful, 0019 but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0021 Library General Public License for more details. 0022 0023 You should have received a copy of the GNU Library General Public License 0024 along with this library; see the file COPYING.LIB. If not, write to 0025 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0026 Boston, MA 02110-1301, USA. 0027 */ 0028 0029 // Local 0030 #include "SortDialog.h" 0031 0032 // Sheets 0033 #include "Map.h" 0034 #include "ui/Selection.h" 0035 #include "Sheet.h" 0036 #include "ValueConverter.h" 0037 0038 // commands 0039 #include "commands/SortManipulator.h" 0040 0041 #include <KoIcon.h> 0042 0043 // ui 0044 #include "ui_SortWidget.h" 0045 #include "ui_SortDetailsWidget.h" 0046 0047 #include <KSharedConfig> 0048 0049 // Qt 0050 #include <QStyledItemDelegate> 0051 0052 #include <algorithm> 0053 0054 using namespace Calligra::Sheets; 0055 0056 Q_DECLARE_METATYPE(Qt::CaseSensitivity) 0057 Q_DECLARE_METATYPE(Qt::SortOrder) 0058 0059 class SortDialog::Private : public QStyledItemDelegate 0060 { 0061 public: 0062 Private(SortDialog *parent = 0) 0063 : QStyledItemDelegate(parent) 0064 { 0065 } 0066 0067 QWidget *createEditor(QWidget *parent, 0068 const QStyleOptionViewItem &option, 0069 const QModelIndex &index) const override 0070 { 0071 Q_UNUSED(index) 0072 Q_UNUSED(option) 0073 if (mainWidget.m_sortHorizontal->isChecked()) /* data grouped in columns; criteria/header per row */ { 0074 if (rows.isEmpty()) { 0075 return 0; 0076 } 0077 } else if (columns.isEmpty()) { 0078 return 0; 0079 } 0080 KComboBox *const combo = new KComboBox(parent); 0081 return combo; 0082 } 0083 0084 void setEditorData(QWidget *editor, const QModelIndex &index) const override 0085 { 0086 if (!index.isValid()) { 0087 return; 0088 } 0089 KComboBox *const combo = static_cast<KComboBox*>(editor); 0090 const QAbstractItemModel *const model = index.model(); 0091 const QString itemText = model->data(index, Qt::DisplayRole).toString(); 0092 const int itemIndex = model->data(index, Qt::UserRole).toInt(); 0093 const bool hasHeader = mainWidget.m_useHeader->isChecked(); 0094 Sheet *const sheet = selection->lastSheet(); 0095 ValueConverter *const converter = sheet->map()->converter(); 0096 0097 if (mainWidget.m_sortVertical->isChecked()) /* data grouped in rows; criteria/header per column */ { 0098 // Put the old item back into the map of available items. 0099 insertIndex(itemIndex, Qt::Horizontal); 0100 0101 const int row = selection->lastRange().top(); 0102 const QList<int> indices = columns; 0103 for (int i = 0; i < indices.count(); ++i) { 0104 const int col = indices[i]; 0105 const QString columnName = i18n("Column %1", Cell::columnName(col)); 0106 const Value value = Cell(sheet, col, row).value(); 0107 const QString header = converter->asString(value).asString(); 0108 if (hasHeader) { 0109 if (header.isEmpty()) { 0110 combo->addItem('(' + columnName + ')', col); 0111 } else { 0112 combo->addItem(header, col); 0113 combo->setItemData(combo->count() - 1, columnName, Qt::ToolTipRole); 0114 } 0115 } else { 0116 combo->addItem(columnName, col); 0117 } 0118 if (col == itemIndex) { 0119 combo->setCurrentIndex(i); 0120 } 0121 } 0122 } else /* row headers */ { 0123 // Put the old item back into the map of available items. 0124 insertIndex(itemIndex, Qt::Vertical); 0125 0126 const int col = selection->lastRange().left(); 0127 const QList<int> indices = rows; 0128 for (int i = 0; i < indices.count(); ++i) { 0129 const int row = indices[i]; 0130 const QString rowName = i18n("Row %1", row); 0131 const Value value = Cell(sheet, col, row).value(); 0132 const QString header = converter->asString(value).asString(); 0133 if (hasHeader) { 0134 if (header.isEmpty()) { 0135 combo->addItem('(' + rowName + ')', row); 0136 } else { 0137 combo->addItem(header, row); 0138 combo->setItemData(combo->count() - 1, rowName, Qt::ToolTipRole); 0139 } 0140 } else { 0141 combo->addItem(rowName, row); 0142 } 0143 if (row == itemIndex) { 0144 combo->setCurrentIndex(i); 0145 } 0146 } 0147 } 0148 } 0149 0150 void setModelData(QWidget *editor, QAbstractItemModel *model, 0151 const QModelIndex &index) const override 0152 { 0153 KComboBox *const combo = static_cast<KComboBox*>(editor); 0154 const int currentIndex = combo->currentIndex(); 0155 model->setData(index, combo->itemText(currentIndex), Qt::DisplayRole); 0156 model->setData(index, combo->itemData(currentIndex), Qt::UserRole); 0157 0158 // Remove the current item from the map of available items. 0159 if (mainWidget.m_sortHorizontal->isChecked()) /* data grouped in columns; criteria/header per row */ { 0160 rows.removeAll(combo->itemData(currentIndex).toInt()); 0161 } else { 0162 columns.removeAll(combo->itemData(currentIndex).toInt()); 0163 } 0164 } 0165 0166 void updateEditorGeometry(QWidget *editor, 0167 const QStyleOptionViewItem &option, 0168 const QModelIndex &index) const override 0169 { 0170 Q_UNUSED(index) 0171 editor->setGeometry(option.rect); 0172 } 0173 0174 public: // data 0175 Selection *selection; 0176 Ui::SortWidget mainWidget; 0177 Ui::SortDetailsWidget detailsWidget; 0178 mutable QList<int> columns; 0179 mutable QList<int> rows; 0180 0181 public: 0182 /// \return \c true if all columns/rows have text values 0183 bool hasHeader(const Region ®ion, Qt::Orientation orientation) const; 0184 void createAvailableIndices(const Region ®ion, Qt::Orientation orientation); 0185 void insertIndex(int index, Qt::Orientation orientation) const; 0186 QString itemText(int index, bool useHeader) const; 0187 void initCriteria(Qt::Orientation orientation, SortDialog *parent); 0188 }; 0189 0190 bool SortDialog::Private::hasHeader(const Region ®ion, Qt::Orientation orientation) const 0191 { 0192 Sheet *const sheet = region.lastSheet(); 0193 const QRect range = region.lastRange(); 0194 if (orientation == Qt::Horizontal) /* check for column headers */ { 0195 for (int col = range.left(); col <= range.right(); ++col) { 0196 if (!Cell(sheet, col, range.top()).value().isString()) { 0197 return false; 0198 } 0199 } 0200 } else /* check for row headers */ { 0201 for (int row = range.top(); row <= range.bottom(); ++row) { 0202 if (!Cell(sheet, range.left(), row).value().isString()) { 0203 return false; 0204 } 0205 } 0206 } 0207 return true; 0208 } 0209 0210 void SortDialog::Private::createAvailableIndices(const Region ®ion, Qt::Orientation orientation) 0211 { 0212 const QRect range = region.lastRange(); 0213 if (orientation == Qt::Horizontal) /* available columns */ { 0214 for (int col = range.left(); col <= range.right(); ++col) { 0215 columns.append(col); 0216 } 0217 } else /* available rows */ { 0218 for (int row = range.top(); row <= range.bottom(); ++row) { 0219 rows.append(row); 0220 } 0221 } 0222 } 0223 0224 void SortDialog::Private::insertIndex(int index, Qt::Orientation orientation) const 0225 { 0226 if (orientation == Qt::Vertical) /* data grouped in columns; criteria/header per row */ { 0227 Q_ASSERT(1 <= index && index <= KS_colMax); 0228 QList<int>::Iterator it = std::lower_bound(rows.begin(), rows.end(), index); 0229 if (*it == index) { 0230 return; 0231 } 0232 rows.insert(it, index); 0233 } else /* data grouped in rows; criteria/header per column */ { 0234 Q_ASSERT(1 <= index && index <= KS_rowMax); 0235 QList<int>::Iterator it = std::lower_bound(columns.begin(), columns.end(), index); 0236 if (*it == index) { 0237 return; 0238 } 0239 columns.insert(it, index); 0240 } 0241 } 0242 0243 QString SortDialog::Private::itemText(int index, bool useHeader) const 0244 { 0245 Sheet *const sheet = selection->lastSheet(); 0246 ValueConverter *const converter = sheet->map()->converter(); 0247 0248 if (mainWidget.m_sortHorizontal->isChecked()) /* data grouped in columns; criteria/header per row */ { 0249 const int col = selection->lastRange().left(); 0250 const int row = index; 0251 const QString rowName = i18n("Row %1", row); 0252 if (useHeader) { 0253 const Value value = Cell(sheet, col, row).value(); 0254 const QString header = converter->asString(value).asString(); 0255 if (header.isEmpty()) { 0256 return QString('(' + rowName + ')'); 0257 } else { 0258 return header; 0259 } 0260 } else { 0261 return rowName; 0262 } 0263 } else /* data grouped in rows; criteria/header per column */ { 0264 const int col = index; 0265 const int row = selection->lastRange().top(); 0266 const QString columnName = i18n("Column %1", Cell::columnName(col)); 0267 if (useHeader) { 0268 const Value value = Cell(sheet, col, row).value(); 0269 const QString header = converter->asString(value).asString(); 0270 if (header.isEmpty()) { 0271 return QString('(' + columnName + ')'); 0272 } else { 0273 return header; 0274 } 0275 } else { 0276 return columnName; 0277 } 0278 } 0279 } 0280 0281 void SortDialog::Private::initCriteria(Qt::Orientation orientation, SortDialog *parent) 0282 { 0283 // Put the items back into the map of available items. 0284 for (int row = mainWidget.m_tableWidget->rowCount() - 1; row >= 0; --row) { 0285 QTableWidgetItem *const item = mainWidget.m_tableWidget->item(row, 0); 0286 const int index = item->data(Qt::UserRole).toInt(); 0287 insertIndex(index, orientation); 0288 mainWidget.m_tableWidget->removeRow(row); 0289 } 0290 0291 // (Re-)Insert the criteria. 0292 if (mainWidget.m_sortHorizontal->isChecked()) { 0293 while (rows.count()) { 0294 parent->addCriterion(); 0295 } 0296 } else { 0297 while (columns.count()) { 0298 parent->addCriterion(); 0299 } 0300 } 0301 0302 // Setup the buttons. 0303 mainWidget.m_addButton->setEnabled(false); 0304 mainWidget.m_removeButton->setEnabled(false); 0305 mainWidget.m_upButton->setEnabled(false); 0306 mainWidget.m_downButton->setEnabled(false); 0307 0308 // Adjust the header usage text. 0309 if (mainWidget.m_sortHorizontal->isChecked()) /* Sort horizontally */ { 0310 // data gets sorted horizontally; comparisons per row; columns get exchanged/sorted 0311 mainWidget.m_useHeader->setText(i18n("&First column contains row headers")); 0312 } else /* Sort vertically */ { 0313 // data gets sorted vertically; comparisons per column; rows get exchanged/sorted 0314 mainWidget.m_useHeader->setText(i18n("&First row contains column headers")); 0315 } 0316 } 0317 0318 0319 SortDialog::SortDialog(QWidget* parent, Selection* selection) 0320 : KoDialog(parent) 0321 , d(new Private(this)) 0322 { 0323 d->selection = selection; 0324 0325 setCaption(i18n("Sort")); 0326 setButtons(Ok | Cancel | Details | Reset); 0327 setObjectName(QLatin1String("SortDialog")); 0328 0329 QWidget *widget = new QWidget(this); 0330 d->mainWidget.setupUi(widget); 0331 setMainWidget(widget); 0332 0333 widget = new QWidget(this); 0334 d->detailsWidget.setupUi(widget); 0335 setDetailsWidget(widget); 0336 0337 // UI refinements Designer is not capable of 0338 d->mainWidget.m_addButton->setIcon(koIcon("list-add")); 0339 d->mainWidget.m_removeButton->setIcon(koIcon("list-remove")); 0340 d->mainWidget.m_upButton->setIcon(koIcon("go-up")); 0341 d->mainWidget.m_downButton->setIcon(koIcon("go-down")); 0342 QHeaderView *const header = d->mainWidget.m_tableWidget->horizontalHeader(); 0343 header->setSectionResizeMode(QHeaderView::ResizeToContents); 0344 header->setSectionResizeMode(0, QHeaderView::Stretch); 0345 d->mainWidget.m_tableWidget->setItemDelegateForColumn(0, d); 0346 0347 connect(d->mainWidget.m_useHeader, SIGNAL(toggled(bool)), 0348 this, SLOT(useHeaderChanged(bool))); 0349 connect(d->mainWidget.m_sortHorizontal, SIGNAL(toggled(bool)), 0350 this, SLOT(orientationChanged(bool))); 0351 0352 connect(d->mainWidget.m_tableWidget, SIGNAL(itemActivated(QTableWidgetItem*)), 0353 this, SLOT(itemActivated(QTableWidgetItem*))); 0354 connect(d->mainWidget.m_tableWidget, SIGNAL(itemSelectionChanged()), 0355 this, SLOT(itemSelectionChanged())); 0356 0357 connect(d->mainWidget.m_addButton, SIGNAL(clicked()), 0358 this, SLOT(addCriterion())); 0359 connect(d->mainWidget.m_removeButton, SIGNAL(clicked()), 0360 this, SLOT(removeCriterion())); 0361 connect(d->mainWidget.m_upButton, SIGNAL(clicked()), 0362 this, SLOT(moveCriterionUp())); 0363 connect(d->mainWidget.m_downButton, SIGNAL(clicked()), 0364 this, SLOT(moveCriterionDown())); 0365 0366 init(); 0367 } 0368 0369 SortDialog::~SortDialog() 0370 { 0371 delete d; 0372 } 0373 0374 void SortDialog::init() 0375 { 0376 QStringList lst; 0377 lst << i18n("January") + ',' + i18n("February") + ',' + i18n("March") + 0378 ',' + i18n("April") + ',' + i18n("May") + ',' + i18n("June") + 0379 ',' + i18n("July") + ',' + i18n("August") + ',' + i18n("September") + 0380 ',' + i18n("October") + ',' + i18n("November") + 0381 ',' + i18n("December"); 0382 0383 lst << i18n("Monday") + ',' + i18n("Tuesday") + ',' + i18n("Wednesday") + 0384 ',' + i18n("Thursday") + ',' + i18n("Friday") + ',' + i18n("Saturday") + 0385 ',' + i18n("Sunday"); 0386 0387 KSharedConfigPtr config = KSharedConfig::openConfig(); 0388 const QStringList other = config->group("Parameters").readEntry("Other list", QStringList()); 0389 QString tmp; 0390 for (QStringList::ConstIterator it = other.begin(); it != other.end(); ++it) { 0391 if ((*it) != "\\") 0392 tmp += (*it) + ", "; 0393 else if (it != other.begin()) { 0394 tmp = tmp.left(tmp.length() - 2); 0395 lst.append(tmp); 0396 tmp.clear(); 0397 } 0398 } 0399 d->detailsWidget.m_customList->insertItems(0, lst); 0400 0401 Sheet *const sheet = d->selection->lastSheet(); 0402 const QRect range = d->selection->lastRange(); 0403 const Region region(range, sheet); 0404 0405 if (region.isColumnSelected()) /* entire columns */ { 0406 d->mainWidget.m_sortHorizontal->setEnabled(false); 0407 d->mainWidget.m_sortVertical->setChecked(true); 0408 0409 const bool hasHeader = d->hasHeader(region, Qt::Horizontal); 0410 d->mainWidget.m_useHeader->setChecked(hasHeader); 0411 d->createAvailableIndices(region, Qt::Horizontal); 0412 } 0413 else if (region.isRowSelected()) /* entire rows */ { 0414 d->mainWidget.m_sortVertical->setEnabled(false); 0415 d->mainWidget.m_sortHorizontal->setChecked(true); 0416 0417 const bool hasHeader = d->hasHeader(region, Qt::Vertical); 0418 d->mainWidget.m_useHeader->setChecked(hasHeader); 0419 d->createAvailableIndices(region, Qt::Vertical); 0420 } else /* ordinary cell range */ { 0421 if (range.top() == range.bottom()) /* only one row */{ 0422 d->mainWidget.m_sortVertical->setEnabled(false); 0423 d->mainWidget.m_sortHorizontal->setChecked(true); 0424 } else if (range.left() == range.right()) /* only one column */ { 0425 d->mainWidget.m_sortHorizontal->setEnabled(false); 0426 d->mainWidget.m_sortVertical->setChecked(true); 0427 } else { 0428 const bool hasColumnHeader = d->hasHeader(region, Qt::Horizontal); 0429 const bool hasRowHeader = d->hasHeader(region, Qt::Vertical); 0430 0431 #if 0 // TODO 0432 if (hasColumnHeader && range.top() + 1 == range.bottom()) /* only one data row */ { 0433 d->mainWidget.m_sortVertical->setEnabled(false); 0434 } 0435 if (hasRowHeader && range.left() + 1 == range.right()) /* only one data column */ { 0436 d->mainWidget.m_sortHorizontal->setEnabled(false); 0437 } 0438 #endif 0439 0440 if (range.width() >= range.height()) { 0441 d->mainWidget.m_sortHorizontal->setChecked(true); 0442 d->mainWidget.m_useHeader->setChecked(hasRowHeader); 0443 } else { 0444 d->mainWidget.m_sortVertical->setChecked(true); 0445 d->mainWidget.m_useHeader->setChecked(hasColumnHeader); 0446 } 0447 } 0448 0449 // create column indices, if data can be sorted vertically 0450 if (d->mainWidget.m_sortVertical->isEnabled()) { 0451 d->createAvailableIndices(region, Qt::Horizontal); 0452 } 0453 // create row indices, if data can be sorted horizontally 0454 if (d->mainWidget.m_sortHorizontal->isEnabled()) { 0455 d->createAvailableIndices(region, Qt::Vertical); 0456 } 0457 } 0458 0459 // Initialize the criteria. 0460 slotButtonClicked(Reset); 0461 } 0462 0463 void SortDialog::orientationChanged(bool horizontal) 0464 { 0465 // Take the old, i.e. the reverse orientation. 0466 const Qt::Orientation orientation = horizontal ? Qt::Horizontal : Qt::Vertical; 0467 d->initCriteria(orientation, this); 0468 } 0469 0470 void SortDialog::accept() 0471 { 0472 Sheet *const sheet = d->selection->activeSheet(); 0473 0474 SortManipulator *const command = new SortManipulator(); 0475 command->setSheet(sheet); 0476 0477 // set parameters 0478 command->setSortRows(d->mainWidget.m_sortVertical->isChecked()); 0479 command->setSkipFirst(d->mainWidget.m_useHeader->isChecked()); 0480 command->setCopyFormat(d->detailsWidget.m_copyLayout->isChecked()); 0481 0482 const bool horizontal = d->mainWidget.m_sortHorizontal->isChecked(); 0483 const QRect range = d->selection->lastRange(); 0484 const int offset = horizontal ? range.top() : range.left(); 0485 0486 // retrieve sorting order 0487 QTableWidget *const table = d->mainWidget.m_tableWidget; 0488 for (int i = 0; i < table->rowCount(); ++i) { 0489 const int index = table->item(i, 0)->data(Qt::UserRole).toInt(); 0490 const Qt::SortOrder order = table->item(i, 1)->data(Qt::UserRole).value<Qt::SortOrder>(); 0491 const Qt::CaseSensitivity caseSensitivity = table->item(i, 2)->data(Qt::UserRole).value<Qt::CaseSensitivity>(); 0492 command->addCriterion(index - offset, order, caseSensitivity); 0493 } 0494 0495 if (d->detailsWidget.m_useCustomLists->isChecked()) { 0496 // add custom list if any 0497 QStringList clist; 0498 QString list = d->detailsWidget.m_customList->currentText(); 0499 QString tmp; 0500 int l = list.length(); 0501 for (int i = 0; i < l; ++i) { 0502 if (list[i] == ',') { 0503 clist.append(tmp.trimmed()); 0504 tmp.clear(); 0505 } else 0506 tmp += list[i]; 0507 } 0508 0509 command->setUseCustomList(true); 0510 command->setCustomList(clist); 0511 } 0512 command->add(d->selection->lastRange()); 0513 command->execute(d->selection->canvas()); 0514 0515 d->selection->emitModified(); 0516 KoDialog::accept(); 0517 } 0518 0519 void SortDialog::slotButtonClicked(int button) 0520 { 0521 if (button == Reset) { 0522 const bool horizontal = d->mainWidget.m_sortHorizontal->isChecked(); 0523 const Qt::Orientation orientation = horizontal ? Qt::Vertical : Qt::Horizontal; 0524 d->initCriteria(orientation, this); 0525 } 0526 KoDialog::slotButtonClicked(button); 0527 } 0528 0529 void SortDialog::useHeaderChanged(bool enable) 0530 { 0531 // Rename the list items. 0532 QTableWidget *const table = d->mainWidget.m_tableWidget; 0533 for (int row = 0; row < table->rowCount(); ++row) { 0534 QTableWidgetItem *const item = table->item(row, 0); 0535 const int index = item->data(Qt::UserRole).toInt(); 0536 item->setText(d->itemText(index, enable)); 0537 } 0538 } 0539 0540 void SortDialog::itemActivated(QTableWidgetItem *item) 0541 { 0542 if (item->column() == 1) /* Sort Order */ { 0543 if (item->data(Qt::UserRole).value<Qt::SortOrder>() == Qt::AscendingOrder) { 0544 item->setIcon(koIcon("view-sort-descending")); 0545 item->setText(i18n("Descending")); 0546 item->setData(Qt::UserRole, QVariant::fromValue(Qt::DescendingOrder)); 0547 } else { 0548 item->setIcon(koIcon("view-sort-ascending")); 0549 item->setText(i18n("Ascending")); 0550 item->setData(Qt::UserRole, QVariant::fromValue(Qt::AscendingOrder)); 0551 } 0552 } else if (item->column() == 2) /* Case Sensitivity */ { 0553 if (item->checkState() == Qt::Checked) { 0554 item->setCheckState(Qt::Unchecked); 0555 item->setText(i18n("Case Insensitive")); 0556 item->setData(Qt::UserRole, QVariant::fromValue(Qt::CaseInsensitive)); 0557 } else { 0558 item->setCheckState(Qt::Checked); 0559 item->setText(i18n("Case Sensitive")); 0560 item->setData(Qt::UserRole, QVariant::fromValue(Qt::CaseSensitive)); 0561 } 0562 } 0563 } 0564 0565 void SortDialog::itemSelectionChanged() 0566 { 0567 QTableWidget *const table = d->mainWidget.m_tableWidget; 0568 QList<QTableWidgetSelectionRange> ranges = table->selectedRanges(); 0569 if (ranges.count() == 0) { 0570 d->mainWidget.m_removeButton->setEnabled(false); 0571 d->mainWidget.m_upButton->setEnabled(false); 0572 d->mainWidget.m_downButton->setEnabled(false); 0573 } else { 0574 d->mainWidget.m_removeButton->setEnabled(true); 0575 bool first = false; 0576 bool last = false; 0577 for (int i = 0; i < ranges.count(); ++i) { 0578 if (ranges[i].topRow() == 0) { 0579 first = true; 0580 } 0581 if (ranges[i].bottomRow() == table->rowCount() - 1) { 0582 last = true; 0583 } 0584 if (first && last) { 0585 break; 0586 } 0587 } 0588 d->mainWidget.m_upButton->setEnabled(!first); 0589 d->mainWidget.m_downButton->setEnabled(!last); 0590 } 0591 } 0592 0593 void SortDialog::addCriterion() 0594 { 0595 QTableWidgetItem *item; 0596 const bool useHeader = d->mainWidget.m_useHeader->isChecked(); 0597 // Take the first item from the map of available items. 0598 if (d->mainWidget.m_sortVertical->isChecked()) /* data grouped in rows; criteria/header per column */ { 0599 const QList<int> keys = d->columns; 0600 if (keys.isEmpty()) { 0601 return; 0602 } else if (keys.count() == 1) { 0603 d->mainWidget.m_addButton->setEnabled(false); 0604 } 0605 const int col = d->columns.takeFirst(); 0606 item = new QTableWidgetItem(d->itemText(col, useHeader)); 0607 item->setData(Qt::UserRole, col); 0608 } else { 0609 const QList<int> keys = d->rows; 0610 if (keys.isEmpty()) { 0611 return; 0612 } else if (keys.count() == 1) { 0613 d->mainWidget.m_addButton->setEnabled(false); 0614 } 0615 const int row = d->rows.takeFirst(); 0616 item = new QTableWidgetItem(d->itemText(row, useHeader)); 0617 item->setData(Qt::UserRole, row); 0618 } 0619 // Insert the item and its default attributes in a new row. 0620 const int row = d->mainWidget.m_tableWidget->rowCount(); 0621 d->mainWidget.m_tableWidget->insertRow(row); 0622 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable); 0623 d->mainWidget.m_tableWidget->setItem(row, 0, item); 0624 item = new QTableWidgetItem(koIcon("view-sort-ascending"), i18n("Ascending")); 0625 item->setData(Qt::UserRole, Qt::AscendingOrder); 0626 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable); 0627 d->mainWidget.m_tableWidget->setItem(row, 1, item); 0628 item = new QTableWidgetItem(i18n("Case Sensitive")); 0629 item->setCheckState(Qt::Checked); 0630 item->setData(Qt::UserRole, Qt::CaseSensitive); 0631 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable); 0632 d->mainWidget.m_tableWidget->setItem(row, 2, item); 0633 } 0634 0635 bool greaterThan(const QTableWidgetSelectionRange &r1, const QTableWidgetSelectionRange &r2) 0636 { 0637 return r1.topRow() > r2.topRow(); 0638 } 0639 0640 void SortDialog::removeCriterion() 0641 { 0642 QTableWidget *const table = d->mainWidget.m_tableWidget; 0643 QList<QTableWidgetSelectionRange> ranges = table->selectedRanges(); 0644 if (ranges.isEmpty()) { 0645 return; 0646 } 0647 std::stable_sort(ranges.begin(), ranges.end(), greaterThan); 0648 for (int i = 0; i < ranges.count(); ++i) { 0649 for (int row = ranges[i].bottomRow(); row >= ranges[i].topRow(); --row) { 0650 // Reinsert the item to be removed into the map of available items. 0651 const int index = table->item(row, 0)->data(Qt::UserRole).toInt(); 0652 if (d->mainWidget.m_sortHorizontal->isChecked()) { 0653 d->insertIndex(index, Qt::Vertical); 0654 } else { 0655 d->insertIndex(index, Qt::Horizontal); 0656 } 0657 // Remove the item from the list. 0658 table->removeRow(row); 0659 } 0660 } 0661 d->mainWidget.m_addButton->setEnabled(true); 0662 } 0663 0664 void SortDialog::moveCriterionUp() 0665 { 0666 QTableWidget *const table = d->mainWidget.m_tableWidget; 0667 const QList<QTableWidgetSelectionRange> ranges = table->selectedRanges(); 0668 for (int i = 0; i < ranges.count(); ++i) { 0669 if (ranges[i].topRow() > 0) { 0670 const int srcRow = ranges[i].topRow() - 1; 0671 const int dstRow = ranges[i].bottomRow() + 1; 0672 table->insertRow(dstRow); 0673 for (int col = 0; col <= 2; ++col) { 0674 table->setItem(dstRow, col, table->takeItem(srcRow, col)); 0675 } 0676 table->removeRow(srcRow); 0677 } 0678 } 0679 itemSelectionChanged(); 0680 } 0681 0682 void SortDialog::moveCriterionDown() 0683 { 0684 QTableWidget *const table = d->mainWidget.m_tableWidget; 0685 const QList<QTableWidgetSelectionRange> ranges = table->selectedRanges(); 0686 for (int i = 0; i < ranges.count(); ++i) { 0687 if (ranges[i].bottomRow() < table->rowCount() - 1) { 0688 const int srcRow = ranges[i].bottomRow() + 2; 0689 const int dstRow = ranges[i].topRow(); 0690 table->insertRow(dstRow); 0691 for (int col = 0; col <= 2; ++col) { 0692 table->setItem(dstRow, col, table->takeItem(srcRow, col)); 0693 } 0694 table->removeRow(srcRow); 0695 } 0696 } 0697 itemSelectionChanged(); 0698 }