#include "sortdialog.h" #include "ui_sortdialog.h" #include "iconmanager.h" #include "common/unused.h" #include #include #include SortDialog::SortDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SortDialog) { ui->setupUi(this); initActions(); ui->list->header()->setSectionResizeMode(0, QHeaderView::Stretch); connect(ui->list->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateButtons())); connect(ui->list, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(itemChanged(QTreeWidgetItem*,int))); connect(ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(reset())); connect(ui->list->model(), &QAbstractItemModel::rowsInserted, [=](const QModelIndex & parent, int start, int end) { UNUSED(parent); UNUSED(end); rebuildComboForItem(ui->list->topLevelItem(start)); }); } SortDialog::~SortDialog() { delete ui; } void SortDialog::setColumns(const QStringList& columns) { originalColumns = columns; ui->list->clear(); QTreeWidgetItem* item = nullptr; for (int row = 0, total = columns.size(); row < total; ++row) { item = new QTreeWidgetItem({columns[row], "ASC"}); item->setData(2, Qt::UserRole, row); fixItemFlags(item); ui->list->insertTopLevelItem(row, item); item->setCheckState(0, Qt::Unchecked); } ui->list->setHeaderLabels({tr("Column"), tr("Order")}); updateButtons(); } QueryExecutor::SortList SortDialog::getSortOrder() const { QueryExecutor::SortList sortOrder; QTreeWidgetItem* item = nullptr; QComboBox* combo = nullptr; for (int row = 0, total = ui->list->topLevelItemCount(); row < total; ++row) { item = ui->list->topLevelItem(row); if (item->checkState(0) != Qt::Checked) continue; combo = dynamic_cast(ui->list->itemWidget(item, 1)); sortOrder << QueryExecutor::Sort((combo->currentText() == "ASC" ? Qt::AscendingOrder : Qt::DescendingOrder), item->data(2, Qt::UserRole).toInt()); } return sortOrder; } void SortDialog::setSortOrder(const QueryExecutor::SortList& sortOrder) { // Translate sort order into more usable (in here) form QHash checkedColumns; QList checkedColumnsOrder; for (const QueryExecutor::Sort& sort : sortOrder) { checkedColumns[sort.column] = sort.order; checkedColumnsOrder << sort.column; } // Select proper columns and set order bool checked; QTreeWidgetItem* item = nullptr; QComboBox* combo = nullptr; for (int row = 0, total = ui->list->topLevelItemCount(); row < total; ++row) { item = ui->list->topLevelItem(row); checked = checkedColumns.contains(item->data(2, Qt::UserRole).toInt()); item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); combo = dynamic_cast(ui->list->itemWidget(item, 1)); combo->setCurrentText(checkedColumns[row] == QueryExecutor::Sort::DESC ? "DESC" : "ASC"); } // Get selected items as an ordered list of items (in order as defined in the sort order), so we can easly relocate them QList orderedItems; for (int row : checkedColumnsOrder) orderedItems << ui->list->topLevelItem(row); // Move selected items in front, in the same order as they were mentioned in the sort order int newRow = 0; for (QTreeWidgetItem* itemToMove : orderedItems) { ui->list->takeTopLevelItem(ui->list->indexOfTopLevelItem(itemToMove)); ui->list->insertTopLevelItem(newRow++, itemToMove); } updateState(); } QToolBar* SortDialog::getToolBar(int toolbar) const { UNUSED(toolbar); return nullptr; } void SortDialog::updateState(QTreeWidgetItem* item) { QComboBox* combo = dynamic_cast(ui->list->itemWidget(item, 1)); if (!combo) return; combo->setEnabled(item->checkState(0) == Qt::Checked); } void SortDialog::updateState() { for (int row = 0, total = ui->list->topLevelItemCount(); row < total; ++row) updateState(ui->list->topLevelItem(row)); } void SortDialog::fixItemFlags(QTreeWidgetItem* item) { Qt::ItemFlags flags = item->flags(); flags |= Qt::ItemNeverHasChildren; flags |= Qt::ItemIsUserCheckable; flags ^= Qt::ItemIsDropEnabled; flags ^= Qt::ItemIsEditable; item->setFlags(flags); } void SortDialog::rebuildComboForItem(QTreeWidgetItem* item) { QComboBox* combo = new QComboBox(); combo->addItems({"ASC", "DESC"}); combo->setCurrentText(item->text(1)); combo->setEnabled(item->checkState(0) == Qt::Checked); ui->list->setItemWidget(item, 1, combo); item->setSizeHint(1, combo->sizeHint()); // bug in Qt? without this comboboxes were misaligned vertically connect(combo, &QComboBox::currentTextChanged, [item](const QString& newText) { item->setText(1, newText); }); updateSortLabel(); } void SortDialog::updateSortLabel() { QStringList entries; QTreeWidgetItem* item = nullptr; for (int row = 0, total = ui->list->topLevelItemCount(); row < total; ++row) { item = ui->list->topLevelItem(row); if (item->checkState(0) != Qt::Checked) continue; entries << item->text(0) + " " + item->text(1); } if (entries.size() == 0) { ui->sortByLabel->setVisible(false); } else { static QString label = tr("Sort by: %1"); ui->sortByLabel->setText(label.arg(entries.join(", "))); ui->sortByLabel->setVisible(true); } } void SortDialog::itemChanged(QTreeWidgetItem* item, int column) { if (column == 0) updateState(item); updateSortLabel(); } void SortDialog::reset() { setColumns(originalColumns); } void SortDialog::updateButtons() { QTreeWidgetItem* item = ui->list->currentItem(); actionMap[MOVE_UP]->setEnabled(item && ui->list->itemAbove(item) != nullptr); actionMap[MOVE_DOWN]->setEnabled(item && ui->list->itemBelow(item) != nullptr); } void SortDialog::moveCurrentUp() { QTreeWidgetItem* item = ui->list->currentItem(); if (!item) return; int row = ui->list->indexOfTopLevelItem(item); if (row < 1) return; ui->list->takeTopLevelItem(row); ui->list->insertTopLevelItem(row - 1, item); QModelIndex idx = ui->list->model()->index(row - 1, 0); ui->list->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::Rows|QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current); updateButtons(); } void SortDialog::moveCurrentDown() { QTreeWidgetItem* item = ui->list->currentItem(); if (!item) return; int row = ui->list->indexOfTopLevelItem(item); if (row + 1 >= ui->list->topLevelItemCount()) return; ui->list->takeTopLevelItem(row); ui->list->insertTopLevelItem(row + 1, item); QModelIndex idx = ui->list->model()->index(row + 1, 0); ui->list->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::Rows|QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current); updateButtons(); } void SortDialog::createActions() { createAction(MOVE_UP, ICONS.MOVE_UP, tr("Move column up"), this, SLOT(moveCurrentUp()), ui->toolbar, this); createAction(MOVE_DOWN, ICONS.MOVE_DOWN, tr("Move column down"), this, SLOT(moveCurrentDown()), ui->toolbar, this); } void SortDialog::setupDefShortcuts() { }