/************************************************************************ ** ** @file dialogmdatabase.cpp ** @author Roman Telezhynskyi ** @date 26 7, 2015 ** ** @brief ** @copyright ** This source code is part of the Valentina project, a pattern making ** program, whose allow create and modeling patterns of clothing. ** Copyright (C) 2015 Valentina project ** All Rights Reserved. ** ** Valentina is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Valentina is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Valentina. If not, see . ** *************************************************************************/ #include "dialogmdatabase.h" #include "../mapplication.h" #include "../vformat/knownmeasurements/vknownmeasurement.h" #include "../vformat/knownmeasurements/vknownmeasurements.h" #include "../vformat/knownmeasurements/vknownmeasurementsdatabase.h" #include "../vmisc/def.h" #include "ui_dialogmdatabase.h" #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) #include "../vmisc/compatibility.h" #endif using namespace Qt::Literals::StringLiterals; //--------------------------------------------------------------------------------------------------------------------- DialogMDataBase::DialogMDataBase(const QUuid &id, const QStringList &usedMeasurements, QWidget *parent) : QDialog(parent), ui(new Ui::DialogMDataBase), m_selectMode(true), m_usedMeasurements(usedMeasurements), m_knownId(id) { ui->setupUi(this); #if defined(Q_OS_MAC) setWindowFlags(Qt::Window); #endif InitDataBase(m_usedMeasurements); ui->treeWidget->installEventFilter(this); connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &DialogMDataBase::UpdateChecks); connect(ui->treeWidget, &QTreeWidget::itemClicked, this, &DialogMDataBase::ShowDescription); connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, &DialogMDataBase::TreeMenu); connect(ui->lineEditSearch, &QLineEdit::textChanged, this, &DialogMDataBase::FilterMeasurements); ReadSettings(); } //--------------------------------------------------------------------------------------------------------------------- DialogMDataBase::~DialogMDataBase() { WriteSettings(); delete ui; } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::GetNewNames() const -> QStringList { if (m_selectMode) { QStringList newNames; QTreeWidgetItemIterator it(ui->treeWidget, QTreeWidgetItemIterator::NoChildren | QTreeWidgetItemIterator::Checked); while (*it) { const QString name = (*it)->data(0, Qt::UserRole).toString(); if (not m_usedMeasurements.contains(name)) { newNames.append(name); } ++it; } return newNames; } return {}; } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::ImgTag(const VPatternImage &image) -> QString { if (!image.IsValid()) { return QStringLiteral(R"()"); // In case of error } QString size; if (!VFuzzyComparePossibleNulls(image.GetSizeScale(), 100.0)) { QSizeF const imaheSize = image.Size(); size = QStringLiteral(R"(width="%1" height="%2")") .arg(imaheSize.width() * image.GetSizeScale() / 100) .arg(imaheSize.height() * image.GetSizeScale() / 100); } return QStringLiteral(R"()") .arg(image.ContentType(), QString(image.ContentData()), size); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { // retranslate designer form (single inheritance approach) ui->retranslateUi(this); if (m_generalGroup) { m_generalGroup->setText(0, tr("General", "Measurement section")); } } // remember to call base class implementation QDialog::changeEvent(event); } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::eventFilter(QObject *target, QEvent *event) -> bool { if (target == ui->treeWidget && event->type() == QEvent::KeyPress) { auto *keyEvent = static_cast(event); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) switch (keyEvent->key()) { case Qt::Key_Up: { const QModelIndex model = ui->treeWidget->indexAbove(ui->treeWidget->currentIndex()); QTreeWidgetItem *item = ui->treeWidget->itemAbove(ui->treeWidget->currentItem()); ShowDescription(item, model.column()); break; } case Qt::Key_Down: { const QModelIndex model = ui->treeWidget->indexBelow(ui->treeWidget->currentIndex()); QTreeWidgetItem *item = ui->treeWidget->itemBelow(ui->treeWidget->currentItem()); ShowDescription(item, model.column()); break; } default: break; } } return QDialog::eventFilter(target, event); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::UpdateChecks(QTreeWidgetItem *item, int column) { bool diff = false; if (column != 0 && column != -1) { return; } if (item->childCount() != 0 && item->checkState(0) != Qt::PartiallyChecked && column != -1) { bool flag = false; // Check if we could change atleast one children Qt::CheckState const checkState = item->checkState(0); for (int i = 0; i < item->childCount(); ++i) { if (not m_usedMeasurements.contains(item->child(i)->data(0, Qt::UserRole).toString())) { item->child(i)->setCheckState(0, checkState); flag = true; } if (not flag) // All child in the list { item->setCheckState(0, Qt::Checked); } } } else if (item->childCount() == 0 || column == -1) { QTreeWidgetItem *parent = item->parent(); if (parent == nullptr) { return; } for (int j = 0; j < parent->childCount(); ++j) { if (j != parent->indexOfChild(item) && item->checkState(0) != parent->child(j)->checkState(0)) { diff = true; } } if (diff) { parent->setCheckState(0, Qt::PartiallyChecked); } else { parent->setCheckState(0, item->checkState(0)); } UpdateChecks(parent, -1); } } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::ShowDescription(QTreeWidgetItem *item, int column) { if ((column != 0 && column != -1) || item == nullptr || item->childCount() != 0) { ui->textEdit->clear(); return; } ui->textEdit->setHtml(ItemFullDescription(item)); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::TreeMenu(const QPoint &pos) { // Because item also will be selected need to show description const QModelIndex model = ui->treeWidget->currentIndex(); QTreeWidgetItem *item = ui->treeWidget->currentItem(); ShowDescription(item, model.column()); auto *actionCollapseAll = new QAction(tr("Collapse All"), this); connect(actionCollapseAll, &QAction::triggered, ui->treeWidget, &QTreeWidget::collapseAll); auto *actionExpandeAll = new QAction(tr("Expand All"), this); connect(actionExpandeAll, &QAction::triggered, ui->treeWidget, &QTreeWidget::expandAll); QMenu menu(this); menu.addAction(actionCollapseAll); menu.addAction(actionExpandeAll); if (m_selectMode) { QString actionName; GlobalCheckState() == Qt::Checked ? actionName = tr("Check all") : actionName = tr("Uncheck all"); auto *actionRecheck = new QAction(actionName, this); connect(actionRecheck, &QAction::triggered, this, &DialogMDataBase::Recheck); menu.addAction(actionRecheck); } menu.exec(ui->treeWidget->mapToGlobal(pos)); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::Recheck() { if (m_selectMode) { const Qt::CheckState check = GlobalCheckState(); for (auto *group : m_groups) { ChangeCheckState(group, check); } } } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::FilterMeasurements(const QString &search) { for (auto *group : m_groups) { FilterGroup(group, search); } const QList list = ui->treeWidget->selectedItems(); list.isEmpty() ? ShowDescription(nullptr, -1) : ShowDescription(list.constFirst(), 0); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::InitDataBase(const QStringList &usedMeasurements) { m_groups.clear(); if (m_knownId.isNull()) { return; } VKnownMeasurementsDatabase *db = MApplication::VApp()->KnownMeasurementsDatabase(); VKnownMeasurements const knownDB = db->KnownMeasurements(m_knownId); QMap const measurements = knownDB.OrderedGroupMeasurements(QString()); if (!measurements.isEmpty()) { m_generalGroup = InitGroup(tr("General", "Measurement section"), measurements, usedMeasurements); m_groups.append(m_generalGroup); } QStringList const groups = knownDB.Groups(); for (auto &group : groups) { QMap const groupMeasurements = knownDB.OrderedGroupMeasurements(group); m_groups.append(InitGroup(group, groupMeasurements, usedMeasurements)); } } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::InitGroup(const QString &groupName, const QMap &mlist, const QStringList &list) -> QTreeWidgetItem * { QTreeWidgetItem *group = AddGroup(groupName); auto i = mlist.constBegin(); while (i != mlist.constEnd()) { AddMeasurement(group, i.value(), list); ++i; } return group; } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::FilterGroup(QTreeWidgetItem *group, const QString &search) const { SCASSERT(group != nullptr) bool match = false; for (int i = 0; i < group->childCount(); ++i) { QTreeWidgetItem *childItem = group->child(i); const QString description = QTextDocumentFragment::fromHtml(ItemFullDescription(childItem, false)).toPlainText(); const bool hidden = not childItem->text(0).contains(search, Qt::CaseInsensitive) && not description.contains(search, Qt::CaseInsensitive); childItem->setHidden(hidden); if (not hidden) { match = true; } } group->setHidden(not group->text(0).contains(search, Qt::CaseInsensitive) && not match); } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::AddGroup(const QString &text) -> QTreeWidgetItem * { auto *group = new QTreeWidgetItem(ui->treeWidget); group->setText(0, text); group->setExpanded(true); if (m_selectMode) { group->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); group->setCheckState(0, Qt::Unchecked); group->setBackground(0, QBrush(Qt::lightGray)); } return group; } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::AddMeasurement(QTreeWidgetItem *group, const VKnownMeasurement &measurement, const QStringList &list) { SCASSERT(group != nullptr) auto *m = new QTreeWidgetItem(group); if (m_selectMode) { if (list.contains(measurement.name)) { m->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); m->setCheckState(0, Qt::Checked); m->setBackground(0, QBrush(Qt::yellow)); } else { m->setCheckState(0, Qt::Unchecked); } UpdateChecks(m, 0); } m->setText(0, measurement.name); m->setToolTip(0, measurement.fullName); m->setData(0, Qt::UserRole, measurement.name); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::ReadSettings() { restoreGeometry(MApplication::VApp()->TapeSettings()->GetDataBaseGeometry()); } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::WriteSettings() { MApplication::VApp()->TapeSettings()->SetDataBaseGeometry(saveGeometry()); } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::ItemFullDescription(QTreeWidgetItem *item, bool showImage) const -> QString { if (item == nullptr || item->childCount() != 0) { return {}; } const QString name = item->data(0, Qt::UserRole).toString(); if (name.isEmpty()) { return {}; } VKnownMeasurementsDatabase *db = MApplication::VApp()->KnownMeasurementsDatabase(); VKnownMeasurements const knownDB = db->KnownMeasurements(m_knownId); VKnownMeasurement const known = knownDB.Measurement(name); QString imgTag; if (showImage) { imgTag = ImgTag(knownDB.Image(known.diagram)); } const QString text = u"

%1
%2

" u"

%3

"_s.arg(imgTag, known.fullName, known.description); return text; } //--------------------------------------------------------------------------------------------------------------------- void DialogMDataBase::ChangeCheckState(QTreeWidgetItem *group, Qt::CheckState check) { SCASSERT(group != nullptr) group->setCheckState(0, check); } //--------------------------------------------------------------------------------------------------------------------- auto DialogMDataBase::GlobalCheckState() const -> Qt::CheckState { if (m_selectMode) { bool allUnchecked = true; bool allChecked = true; for (auto *group : m_groups) { if (group->checkState(0) == Qt::Checked) { allUnchecked = false; } if (group->checkState(0) != Qt::Checked) { allChecked = false; } } if (allUnchecked) { return Qt::Checked; } else if (allChecked) { return Qt::Unchecked; } return Qt::Checked; } return Qt::Unchecked; }