From 2c744264d64cc1d0d02167a6e7ebd4d97dd0bdde Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 13 Sep 2020 18:34:16 +0200 Subject: [PATCH] Gui: several fixes for expression search box: + rename method setMatchExact() to setExactMatch() + move handling of user-defined parameters to class ExpressionParameter + Qt::MatchExactly is not supported by QCompleter, use Qt::MatchStartsWith instead + add possibility to change match behaviour via context-menu --- src/Gui/DlgPropertyLink.cpp | 2 +- src/Gui/ExpressionCompleter.cpp | 106 +++++++++++++++++++++++++++----- src/Gui/ExpressionCompleter.h | 17 +++-- src/Gui/Tree.cpp | 2 +- 4 files changed, 105 insertions(+), 22 deletions(-) diff --git a/src/Gui/DlgPropertyLink.cpp b/src/Gui/DlgPropertyLink.cpp index 83a81b259c..89b577b754 100644 --- a/src/Gui/DlgPropertyLink.cpp +++ b/src/Gui/DlgPropertyLink.cpp @@ -76,7 +76,7 @@ DlgPropertyLink::DlgPropertyLink(QWidget* parent) ui->typeTree->hide(); ui->searchBox->installEventFilter(this); ui->searchBox->setNoProperty(true); - ui->searchBox->setMatchExact(false); + ui->searchBox->setExactMatch(Gui::ExpressionParameter::instance()->isExactMatch()); timer = new QTimer(this); timer->setSingleShot(true); diff --git a/src/Gui/ExpressionCompleter.cpp b/src/Gui/ExpressionCompleter.cpp index 66e29a8957..812ba04168 100644 --- a/src/Gui/ExpressionCompleter.cpp +++ b/src/Gui/ExpressionCompleter.cpp @@ -1,10 +1,12 @@ #include "PreCompiled.h" #ifndef _PreComp_ +#include #include #include #include #include +#include #include #endif @@ -536,11 +538,8 @@ ExpressionLineEdit::ExpressionLineEdit(QWidget *parent, bool noProperty) , completer(0) , block(true) , noProperty(noProperty) + , exactMatch(false) { - auto handle = GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Expression"); - matchExact = handle->GetBool("CompleterMatchExact", false); - connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(slotTextChanged(const QString&))); } @@ -555,7 +554,7 @@ void ExpressionLineEdit::setDocumentObject(const App::DocumentObject * currentDo completer->setWidget(this); completer->setCaseSensitivity(Qt::CaseInsensitive); #if QT_VERSION>=QT_VERSION_CHECK(5,2,0) - if (!matchExact) + if (!exactMatch) completer->setFilterMode(Qt::MatchContains); #endif connect(completer, SIGNAL(activated(QString)), this, SLOT(slotCompleteText(QString))); @@ -570,11 +569,11 @@ void ExpressionLineEdit::setNoProperty(bool enabled) { completer->setNoProperty(enabled); } -void ExpressionLineEdit::setMatchExact(bool enabled) { - matchExact = enabled; +void ExpressionLineEdit::setExactMatch(bool enabled) { + exactMatch = enabled; #if QT_VERSION>=QT_VERSION_CHECK(5,2,0) if (completer) - completer->setFilterMode(matchExact ? Qt::MatchExactly : Qt::MatchContains); + completer->setFilterMode(exactMatch ? Qt::MatchStartsWith : Qt::MatchContains); #endif } @@ -615,6 +614,34 @@ void ExpressionLineEdit::keyPressEvent(QKeyEvent *e) { QLineEdit::keyPressEvent(e); } +void ExpressionLineEdit::contextMenuEvent(QContextMenuEvent *event) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5,2,0) + QMenu *menu = createStandardContextMenu(); + menu->addSeparator(); + QAction* match = menu->addAction(tr("Exact match")); + + if (completer) { + match->setCheckable(true); + match->setChecked(completer->filterMode() == Qt::MatchStartsWith); + } + else { + match->setVisible(false); + } + + QAction* action = menu->exec(event->globalPos()); + + if (completer) { + if (action == match) + setExactMatch(match->isChecked()); + } + + delete menu; +#else + QLineEdit::contextMenuEvent(event); +#endif +} + /////////////////////////////////////////////////////////////////////// @@ -622,19 +649,16 @@ ExpressionTextEdit::ExpressionTextEdit(QWidget *parent) : QPlainTextEdit(parent) , completer(0) , block(true) + , exactMatch(false) { - auto handle = GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Expression"); - matchExact = handle->GetBool("CompleterMatchExact", false); - connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); } -void ExpressionTextEdit::setMatchExact(bool enabled) { - matchExact = enabled; +void ExpressionTextEdit::setExactMatch(bool enabled) { + exactMatch = enabled; #if QT_VERSION>=QT_VERSION_CHECK(5,2,0) if (completer) - completer->setFilterMode(matchExact ? Qt::MatchExactly : Qt::MatchContains); + completer->setFilterMode(exactMatch ? Qt::MatchStartsWith : Qt::MatchContains); #endif } @@ -648,7 +672,7 @@ void ExpressionTextEdit::setDocumentObject(const App::DocumentObject * currentDo if (currentDocObj != 0) { completer = new ExpressionCompleter(currentDocObj, this); #if QT_VERSION>=QT_VERSION_CHECK(5,2,0) - if (!matchExact) + if (!exactMatch) completer->setFilterMode(Qt::MatchContains); #endif completer->setWidget(this); @@ -697,4 +721,54 @@ void ExpressionTextEdit::keyPressEvent(QKeyEvent *e) { QPlainTextEdit::keyPressEvent(e); } +void ExpressionTextEdit::contextMenuEvent(QContextMenuEvent *event) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5,2,0) + QMenu *menu = createStandardContextMenu(); + menu->addSeparator(); + QAction* match = menu->addAction(tr("Exact match")); + + if (completer) { + match->setCheckable(true); + match->setChecked(completer->filterMode() == Qt::MatchStartsWith); + } + else { + match->setVisible(false); + } + + QAction* action = menu->exec(event->globalPos()); + + if (completer) { + if (action == match) + setExactMatch(match->isChecked()); + } + + delete menu; +#else + QPlainTextEdit::contextMenuEvent(event); +#endif +} + +/////////////////////////////////////////////////////////////////////// + +ExpressionParameter* ExpressionParameter::instance() +{ + static ExpressionParameter* inst = new ExpressionParameter(); + return inst; +} + +bool ExpressionParameter::isCaseSensitive() const +{ + auto handle = GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Expression"); + return handle->GetBool("CompleterCaseSensitive", false); +} + +bool ExpressionParameter::isExactMatch() const +{ + auto handle = GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Expression"); + return handle->GetBool("CompleterMatchExact", false); +} + #include "moc_ExpressionCompleter.cpp" diff --git a/src/Gui/ExpressionCompleter.h b/src/Gui/ExpressionCompleter.h index e0062effd2..2d291e4c60 100644 --- a/src/Gui/ExpressionCompleter.h +++ b/src/Gui/ExpressionCompleter.h @@ -68,7 +68,7 @@ public: bool completerActive() const; void hideCompleter(); void setNoProperty(bool enabled=true); - void setMatchExact(bool enabled=true); + void setExactMatch(bool enabled=true); Q_SIGNALS: void textChanged2(QString text, int pos); public Q_SLOTS: @@ -76,11 +76,12 @@ public Q_SLOTS: void slotCompleteText(const QString & completionPrefix); protected: void keyPressEvent(QKeyEvent * event); + void contextMenuEvent(QContextMenuEvent * event); private: ExpressionCompleter * completer; bool block; bool noProperty; - bool matchExact; + bool exactMatch; }; class GuiExport ExpressionTextEdit : public QPlainTextEdit { @@ -90,9 +91,10 @@ public: void setDocumentObject(const App::DocumentObject *currentDocObj); bool completerActive() const; void hideCompleter(); - void setMatchExact(bool enabled=true); + void setExactMatch(bool enabled=true); protected: void keyPressEvent(QKeyEvent * event); + void contextMenuEvent(QContextMenuEvent * event); Q_SIGNALS: void textChanged2(QString text, int pos); public Q_SLOTS: @@ -101,7 +103,14 @@ public Q_SLOTS: private: ExpressionCompleter * completer; bool block; - bool matchExact; + bool exactMatch; +}; + +class GuiExport ExpressionParameter { +public: + static ExpressionParameter *instance(); + bool isCaseSensitive() const; + bool isExactMatch() const; }; } diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index defedb0c40..138d1116fb 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -2838,7 +2838,7 @@ TreePanel::TreePanel(const char *name, QWidget* parent) this, SLOT(showEditor())); this->searchBox = new Gui::ExpressionLineEdit(this,true); - static_cast(this->searchBox)->setMatchExact(false); + static_cast(this->searchBox)->setExactMatch(Gui::ExpressionParameter::instance()->isExactMatch()); pLayout->addWidget(this->searchBox); this->searchBox->hide(); this->searchBox->installEventFilter(this);