2020-09-26 09:40:54 +00:00
|
|
|
#include "desktop-widgets/filterwidget.h"
|
2020-05-18 05:20:09 +00:00
|
|
|
#include "desktop-widgets/filterconstraintwidget.h"
|
2018-10-13 09:52:08 +00:00
|
|
|
#include "desktop-widgets/simplewidgets.h"
|
2019-01-25 21:41:07 +00:00
|
|
|
#include "desktop-widgets/mainwindow.h"
|
2020-05-27 21:09:30 +00:00
|
|
|
#include "commands/command.h"
|
2019-01-20 20:01:00 +00:00
|
|
|
#include "core/qthelper.h"
|
2019-11-17 15:23:00 +00:00
|
|
|
#include "core/divelist.h"
|
2019-01-20 20:01:00 +00:00
|
|
|
#include "core/settings/qPrefUnit.h"
|
2020-05-28 05:31:51 +00:00
|
|
|
#include "qt-models/filterpresetmodel.h"
|
2018-10-13 09:52:08 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
FilterWidget::FilterWidget(QWidget* parent) :
|
2019-02-18 20:43:34 +00:00
|
|
|
QWidget(parent),
|
2020-09-12 08:29:03 +00:00
|
|
|
ignoreSignal(false),
|
|
|
|
presetModified(false)
|
2018-10-13 09:52:08 +00:00
|
|
|
{
|
2019-01-17 22:01:57 +00:00
|
|
|
ui.setupUi(this);
|
2018-12-06 19:07:47 +00:00
|
|
|
|
2020-05-18 05:20:09 +00:00
|
|
|
QMenu *newConstraintMenu = new QMenu(this);
|
|
|
|
QStringList constraintTypes = filter_constraint_type_list_translated();
|
|
|
|
for (int i = 0; i < constraintTypes.size(); ++i) {
|
|
|
|
filter_constraint_type type = filter_constraint_type_from_index(i);
|
|
|
|
newConstraintMenu->addAction(constraintTypes[i], [this, type]() { addConstraint(type); });
|
|
|
|
}
|
|
|
|
ui.addConstraintButton->setMenu(newConstraintMenu);
|
|
|
|
ui.addConstraintButton->setPopupMode(QToolButton::InstantPopup);
|
|
|
|
ui.constraintTable->setColumnStretch(4, 1); // The fifth column is were the actual constraint resides - stretch that.
|
|
|
|
|
2020-05-28 05:31:51 +00:00
|
|
|
ui.loadSetButton->setPopupMode(QToolButton::InstantPopup);
|
|
|
|
|
2020-05-28 20:19:58 +00:00
|
|
|
ui.presetTable->setModel(FilterPresetModel::instance());
|
|
|
|
ui.presetTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
ui.presetTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
2020-11-07 10:25:42 +00:00
|
|
|
ui.presetTable->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
ui.presetTable->resizeColumnsToContents();
|
2020-05-28 20:19:58 +00:00
|
|
|
|
2020-11-07 12:56:28 +00:00
|
|
|
ui.currentSet->setTextFormat(Qt::PlainText);
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
connect(ui.clear, &QToolButton::clicked, this, &FilterWidget::clearFilter);
|
|
|
|
connect(ui.close, &QToolButton::clicked, this, &FilterWidget::closeFilter);
|
|
|
|
connect(ui.fullText, &QLineEdit::textChanged, this, &FilterWidget::filterChanged);
|
|
|
|
connect(ui.fulltextStringMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FilterWidget::filterChanged);
|
|
|
|
connect(ui.presetTable, &QTableView::clicked, this, &FilterWidget::presetClicked);
|
|
|
|
connect(ui.presetTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FilterWidget::presetSelected);
|
2020-05-18 05:20:09 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
connect(&constraintModel, &FilterConstraintModel::rowsInserted, this, &FilterWidget::constraintAdded);
|
|
|
|
connect(&constraintModel, &FilterConstraintModel::rowsRemoved, this, &FilterWidget::constraintRemoved);
|
|
|
|
connect(&constraintModel, &FilterConstraintModel::dataChanged, this, &FilterWidget::constraintChanged);
|
|
|
|
connect(&constraintModel, &FilterConstraintModel::modelReset, this, &FilterWidget::constraintsReset);
|
2019-01-20 20:15:46 +00:00
|
|
|
|
2020-05-28 05:31:51 +00:00
|
|
|
// QDataWidgetMapper might be the more civilized way to keep the menus up to data.
|
|
|
|
// For now, let's be blunt and fully reload the context menu if the presets list changes.
|
|
|
|
// This gives us more flexibility in populating the menus.
|
|
|
|
QAbstractItemModel *presetModel = FilterPresetModel::instance();
|
2020-09-26 09:40:54 +00:00
|
|
|
connect(presetModel, &QAbstractItemModel::rowsInserted, this, &FilterWidget::updatePresetMenu);
|
|
|
|
connect(presetModel, &QAbstractItemModel::rowsRemoved, this, &FilterWidget::updatePresetMenu);
|
|
|
|
connect(presetModel, &QAbstractItemModel::dataChanged, this, &FilterWidget::updatePresetMenu);
|
|
|
|
connect(presetModel, &QAbstractItemModel::modelReset, this, &FilterWidget::updatePresetMenu);
|
2020-05-28 05:31:51 +00:00
|
|
|
|
2020-05-18 05:20:09 +00:00
|
|
|
clearFilter();
|
2020-05-28 05:31:51 +00:00
|
|
|
updatePresetMenu();
|
2020-05-18 05:20:09 +00:00
|
|
|
}
|
2019-01-01 17:49:56 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
FilterWidget::~FilterWidget()
|
2020-05-18 05:20:09 +00:00
|
|
|
{
|
|
|
|
}
|
2019-01-20 20:01:00 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::updatePresetMenu()
|
2020-05-28 05:31:51 +00:00
|
|
|
{
|
|
|
|
loadFilterPresetMenu.reset(new QMenu);
|
|
|
|
QAbstractItemModel *model = FilterPresetModel::instance();
|
|
|
|
int count = model->rowCount(QModelIndex());
|
|
|
|
if (count == 0) {
|
|
|
|
ui.loadSetButton->setEnabled(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ui.loadSetButton->setEnabled(true);
|
|
|
|
for (int i = 0; i < count; ++i) {
|
2020-05-28 20:19:58 +00:00
|
|
|
QModelIndex idx = model->index(i, FilterPresetModel::NAME);
|
2020-05-28 05:31:51 +00:00
|
|
|
QString name = model->data(idx, Qt::DisplayRole).value<QString>();
|
2020-11-07 20:06:54 +00:00
|
|
|
QAction *action = new QAction(loadFilterPresetMenu.get());
|
|
|
|
action->setIconText(name);
|
|
|
|
connect(action, &QAction::triggered, [this,i]() { selectPreset(i); });
|
|
|
|
loadFilterPresetMenu->addAction(action);
|
2020-05-28 05:31:51 +00:00
|
|
|
}
|
|
|
|
ui.loadSetButton->setMenu(loadFilterPresetMenu.get());
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::selectPreset(int i)
|
2020-05-28 20:19:58 +00:00
|
|
|
{
|
|
|
|
QAbstractItemModel *model = FilterPresetModel::instance();
|
|
|
|
QItemSelectionModel *selectionModel = ui.presetTable->selectionModel();
|
|
|
|
QModelIndex idx = model->index(i, 0);
|
|
|
|
selectionModel->reset();
|
|
|
|
selectionModel->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::loadPreset(int index)
|
2020-05-28 05:31:51 +00:00
|
|
|
{
|
2020-09-12 09:03:23 +00:00
|
|
|
ignoreSignal = true; // When reloading the filter UI, we get numerous constraintChanged signals. Ignore them.
|
2024-06-08 16:54:23 +00:00
|
|
|
FilterData filter = divelog.filter_presets[index].data;
|
2020-05-28 05:31:51 +00:00
|
|
|
setFilterData(filter);
|
2020-09-12 09:03:23 +00:00
|
|
|
ignoreSignal = false;
|
2020-09-12 08:29:03 +00:00
|
|
|
presetModified = false;
|
2020-05-28 05:31:51 +00:00
|
|
|
updateFilter();
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::constraintAdded(const QModelIndex &parent, int first, int last)
|
2020-05-18 05:20:09 +00:00
|
|
|
{
|
|
|
|
if (parent.isValid() || last < first)
|
|
|
|
return; // We only support one level
|
|
|
|
constraintWidgets.reserve(constraintWidgets.size() + 1 + last - first);
|
|
|
|
for (int i = last + 1; i < (int)constraintWidgets.size(); ++i)
|
|
|
|
constraintWidgets[i]->moveToRow(i);
|
|
|
|
for (int i = first; i <= last; ++i) {
|
|
|
|
QModelIndex idx = constraintModel.index(i, 0);
|
|
|
|
constraintWidgets.emplace(constraintWidgets.begin() + i, new FilterConstraintWidget(&constraintModel, idx, ui.constraintTable));
|
|
|
|
}
|
2020-09-12 08:29:03 +00:00
|
|
|
filterChanged();
|
2020-05-18 05:20:09 +00:00
|
|
|
}
|
2020-04-21 22:05:52 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::constraintRemoved(const QModelIndex &parent, int first, int last)
|
2020-05-18 05:20:09 +00:00
|
|
|
{
|
|
|
|
if (parent.isValid() || last < first)
|
|
|
|
return; // We only support one level
|
|
|
|
constraintWidgets.erase(constraintWidgets.begin() + first, constraintWidgets.begin() + last + 1);
|
|
|
|
for (int i = first; i < (int)constraintWidgets.size(); ++i)
|
|
|
|
constraintWidgets[i]->moveToRow(i);
|
2020-09-12 08:29:03 +00:00
|
|
|
filterChanged();
|
2020-05-18 05:20:09 +00:00
|
|
|
}
|
2019-01-22 08:38:57 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::presetClicked(const QModelIndex &index)
|
2020-05-28 20:19:58 +00:00
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (index.column() == FilterPresetModel::REMOVE)
|
|
|
|
Command::removeFilterPreset(index.row());
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::presetSelected(const QItemSelection &selected, const QItemSelection &)
|
2020-05-28 20:19:58 +00:00
|
|
|
{
|
|
|
|
if (selected.indexes().isEmpty())
|
|
|
|
return clearFilter();
|
|
|
|
const QModelIndex index = selected.indexes()[0];
|
|
|
|
if (!index.isValid())
|
|
|
|
return clearFilter();
|
|
|
|
loadPreset(index.row());
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::constraintChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
|
2020-05-18 05:20:09 +00:00
|
|
|
{
|
|
|
|
// Note: this may appear strange, but we don't update the widget if we get
|
|
|
|
// a constraint-changed signal from the model. The reason being that the user
|
|
|
|
// is currently editing the constraint and we don't want to bother them by
|
|
|
|
// overwriting strings with canonicalized data.
|
2020-09-12 08:29:03 +00:00
|
|
|
filterChanged();
|
2020-05-18 05:20:09 +00:00
|
|
|
}
|
2019-01-25 20:30:43 +00:00
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::constraintsReset()
|
2020-05-18 05:20:09 +00:00
|
|
|
{
|
|
|
|
constraintWidgets.clear();
|
|
|
|
int count = constraintModel.rowCount(QModelIndex());
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
QModelIndex idx = constraintModel.index(i, 0);
|
|
|
|
constraintWidgets.emplace_back(new FilterConstraintWidget(&constraintModel, idx, ui.constraintTable));
|
|
|
|
}
|
|
|
|
updateFilter();
|
2019-01-25 21:11:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::clearFilter()
|
2019-01-25 21:11:30 +00:00
|
|
|
{
|
2020-05-18 05:20:09 +00:00
|
|
|
ignoreSignal = true; // Prevent signals to force filter recalculation (TODO: check if necessary)
|
2020-09-12 08:29:03 +00:00
|
|
|
presetModified = false;
|
2020-05-28 20:19:58 +00:00
|
|
|
ui.presetTable->selectionModel()->reset(); // Note: we use reset(), because that doesn't emit signals.
|
2020-05-18 05:20:09 +00:00
|
|
|
ui.fulltextStringMode->setCurrentIndex((int)StringFilterMode::STARTSWITH);
|
|
|
|
ui.fullText->clear();
|
2020-09-06 21:58:46 +00:00
|
|
|
ui.presetTable->clearSelection();
|
2019-01-25 21:11:30 +00:00
|
|
|
ignoreSignal = false;
|
2020-05-18 05:20:09 +00:00
|
|
|
constraintModel.reload({}); // Causes a filter reload
|
2019-01-20 20:01:00 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::closeFilter()
|
2019-01-25 21:41:07 +00:00
|
|
|
{
|
2021-02-14 19:59:02 +00:00
|
|
|
MainWindow::instance()->setApplicationState(MainWindow::ApplicationState::Default);
|
2019-01-25 21:41:07 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
FilterData FilterWidget::createFilterData() const
|
2018-10-13 09:52:08 +00:00
|
|
|
{
|
2020-05-18 05:20:09 +00:00
|
|
|
FilterData filterData;
|
2020-02-16 21:31:06 +00:00
|
|
|
filterData.fulltextStringMode = (StringFilterMode)ui.fulltextStringMode->currentIndex();
|
2020-05-18 05:20:09 +00:00
|
|
|
filterData.fullText = ui.fullText->text();
|
|
|
|
filterData.constraints = constraintModel.getConstraints();
|
2020-05-27 21:09:30 +00:00
|
|
|
return filterData;
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::setFilterData(const FilterData &filterData)
|
2020-05-28 05:31:51 +00:00
|
|
|
{
|
|
|
|
ui.fulltextStringMode->setCurrentIndex((int)filterData.fulltextStringMode);
|
|
|
|
ui.fullText->setText(filterData.fullText.originalQuery);
|
|
|
|
constraintModel.reload(filterData.constraints);
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::filterChanged()
|
2020-09-12 08:29:03 +00:00
|
|
|
{
|
|
|
|
presetModified = true;
|
|
|
|
updateFilter();
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::updateFilter()
|
2020-05-27 21:09:30 +00:00
|
|
|
{
|
|
|
|
if (ignoreSignal)
|
|
|
|
return;
|
|
|
|
|
|
|
|
FilterData filterData = createFilterData();
|
2020-05-18 05:20:09 +00:00
|
|
|
DiveFilter::instance()->setFilter(filterData);
|
2020-09-12 08:29:03 +00:00
|
|
|
updatePresetLabel();
|
2019-01-01 17:49:56 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
int FilterWidget::selectedPreset() const
|
2020-09-12 07:48:25 +00:00
|
|
|
{
|
|
|
|
QModelIndexList selection = ui.presetTable->selectionModel()->selectedRows();
|
|
|
|
return selection.size() >= 1 ? selection[0].row() : -1;
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::updatePresetLabel()
|
2020-09-12 07:48:25 +00:00
|
|
|
{
|
|
|
|
int presetId = selectedPreset();
|
|
|
|
QString text;
|
2020-09-12 08:29:03 +00:00
|
|
|
if (presetId >= 0) {
|
2024-06-08 16:54:23 +00:00
|
|
|
const std::string &name = divelog.filter_presets[presetId].name;
|
|
|
|
text = QString::fromStdString(name);
|
2020-09-12 08:29:03 +00:00
|
|
|
if (presetModified)
|
|
|
|
text += " (" + tr("modified") + ")";
|
|
|
|
}
|
2020-09-12 07:48:25 +00:00
|
|
|
ui.currentSet->setText(text);
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::on_addSetButton_clicked()
|
2020-05-27 21:09:30 +00:00
|
|
|
{
|
2020-09-06 21:53:31 +00:00
|
|
|
// If there is a selected item, suggest that to the user.
|
|
|
|
// Thus, if the user selects an item and modify the filter,
|
|
|
|
// they can simply overwrite the preset.
|
2020-09-12 07:48:25 +00:00
|
|
|
int presetId = selectedPreset();
|
2024-06-08 16:54:23 +00:00
|
|
|
QString selectedPreset = presetId >= 0 ?
|
|
|
|
QString::fromStdString(divelog.filter_presets[presetId].name) :
|
|
|
|
QString();
|
2020-09-06 21:53:31 +00:00
|
|
|
|
|
|
|
AddFilterPresetDialog dialog(selectedPreset, this);
|
2020-05-27 21:09:30 +00:00
|
|
|
QString name = dialog.doit();
|
|
|
|
if (name.isEmpty())
|
|
|
|
return;
|
2024-06-08 16:54:23 +00:00
|
|
|
int idx = divelog.filter_presets.preset_id(name.toStdString());
|
2020-05-27 21:09:30 +00:00
|
|
|
if (idx >= 0)
|
|
|
|
Command::editFilterPreset(idx, createFilterData());
|
|
|
|
else
|
|
|
|
Command::createFilterPreset(name, createFilterData());
|
2020-09-12 08:29:03 +00:00
|
|
|
presetModified = false;
|
|
|
|
updatePresetLabel();
|
2020-05-27 21:09:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::showEvent(QShowEvent *event)
|
2018-11-16 14:24:11 +00:00
|
|
|
{
|
|
|
|
QWidget::showEvent(event);
|
2020-02-18 10:54:57 +00:00
|
|
|
ui.fullText->setFocus();
|
2020-05-18 05:20:09 +00:00
|
|
|
updateFilter();
|
2018-11-16 14:24:11 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::hideEvent(QHideEvent *event)
|
2018-11-16 14:24:11 +00:00
|
|
|
{
|
|
|
|
QWidget::hideEvent(event);
|
2018-12-16 19:33:37 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 09:40:54 +00:00
|
|
|
void FilterWidget::addConstraint(filter_constraint_type type)
|
2018-12-16 19:33:37 +00:00
|
|
|
{
|
2020-05-18 05:20:09 +00:00
|
|
|
constraintModel.addConstraint(type);
|
2019-02-18 20:47:20 +00:00
|
|
|
}
|