From 23190be3e855ee23fdae8cd7edfab2d6339d427a Mon Sep 17 00:00:00 2001 From: nds Date: Tue, 26 Sep 2017 13:41:01 +0300 Subject: [PATCH] Issue #2250 Fatal error or sigsegv when I use the "Echap" key. additional correction for case: Escape click in Abort operation dialog did not close this dialog. --- src/ModuleBase/ModuleBase_ModelWidget.cpp | 5 ++ src/ModuleBase/ModuleBase_ModelWidget.h | 3 + src/ModuleBase/ModuleBase_WidgetEditor.cpp | 36 ++++++++-- src/ModuleBase/ModuleBase_WidgetEditor.h | 3 + src/XGUI/XGUI_MenuMgr.cpp | 2 +- src/XGUI/XGUI_OperationMgr.cpp | 79 ++++++++++++++++------ src/XGUI/XGUI_OperationMgr.h | 14 +++- 7 files changed, 116 insertions(+), 26 deletions(-) diff --git a/src/ModuleBase/ModuleBase_ModelWidget.cpp b/src/ModuleBase/ModuleBase_ModelWidget.cpp index fcba4e0c4..7e914b1bc 100644 --- a/src/ModuleBase/ModuleBase_ModelWidget.cpp +++ b/src/ModuleBase/ModuleBase_ModelWidget.cpp @@ -425,6 +425,11 @@ bool ModuleBase_ModelWidget::processEnter() return false; } +bool ModuleBase_ModelWidget::processEscape() +{ + return false; +} + bool ModuleBase_ModelWidget::processDelete() { // we consider that model objects eats delete key in order to diff --git a/src/ModuleBase/ModuleBase_ModelWidget.h b/src/ModuleBase/ModuleBase_ModelWidget.h index 29dc34733..8a8dfdf7b 100644 --- a/src/ModuleBase/ModuleBase_ModelWidget.h +++ b/src/ModuleBase/ModuleBase_ModelWidget.h @@ -243,6 +243,9 @@ Q_OBJECT /// Returns true if the event is processed. The default implementation is empty, returns false. virtual bool processEnter(); + /// Returns true if the event is processed. The default implementation is empty, returns false. + virtual bool processEscape(); + /// Returns true if the event is processed. The default implementation is empty, returns false. virtual bool processDelete(); diff --git a/src/ModuleBase/ModuleBase_WidgetEditor.cpp b/src/ModuleBase/ModuleBase_WidgetEditor.cpp index e70fcbb81..6fcd6cf78 100644 --- a/src/ModuleBase/ModuleBase_WidgetEditor.cpp +++ b/src/ModuleBase/ModuleBase_WidgetEditor.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,23 @@ #include #include +// Dialog is redefined to avoid Escape key processing +class ModuleBase_EditorDialog : public QDialog +{ +public: + ModuleBase_EditorDialog(QWidget* theParent, Qt::WindowFlags theFlags) + : QDialog(theParent, theFlags) {} + ~ModuleBase_EditorDialog() {} + +protected: + // Do nothing if key pressed because it is processing on operation manager level + virtual void keyPressEvent(QKeyEvent* theEvent) { + if (theEvent->key() == Qt::Key_Escape) + return; + QDialog::keyPressEvent(theEvent); + } +}; + ModuleBase_WidgetEditor::ModuleBase_WidgetEditor(QWidget* theParent, const Config_WidgetAPI* theData) : ModuleBase_WidgetDoubleValue(theParent, theData), @@ -61,7 +79,7 @@ bool ModuleBase_WidgetEditor::editedValue(double& outValue, QString& outText) { bool isValueAccepted = false; - myEditorDialog = new QDialog(QApplication::desktop(), Qt::FramelessWindowHint); + myEditorDialog = new ModuleBase_EditorDialog(QApplication::desktop(), Qt::FramelessWindowHint); QHBoxLayout* aLay = new QHBoxLayout(myEditorDialog); aLay->setContentsMargins(2, 2, 2, 2); @@ -146,9 +164,9 @@ bool ModuleBase_WidgetEditor::showPopupEditor(const bool theSendSignals) } ModuleBase_Tools::setFocus(mySpinBox, "ModuleBase_WidgetEditor::editedValue"); mySpinBox->selectAll(); - - if (theSendSignals && !myIsEditing) - emit enterClicked(this); + // enter is processed, so we need not anymore emit clicked signal + //if (theSendSignals && !myIsEditing && isValueAccepted) + // emit enterClicked(this); return isValueAccepted; } @@ -168,3 +186,13 @@ bool ModuleBase_WidgetEditor::processEnter() return ModuleBase_WidgetDoubleValue::processEnter(); } + +bool ModuleBase_WidgetEditor::processEscape() +{ + if (myEditorDialog) { + myEditorDialog->reject(); + return true; + } + + return ModuleBase_WidgetDoubleValue::processEscape(); +} diff --git a/src/ModuleBase/ModuleBase_WidgetEditor.h b/src/ModuleBase/ModuleBase_WidgetEditor.h index 84fb045d6..809ccd4ec 100644 --- a/src/ModuleBase/ModuleBase_WidgetEditor.h +++ b/src/ModuleBase/ModuleBase_WidgetEditor.h @@ -71,6 +71,9 @@ Q_OBJECT /// Returns true if the event is processed. virtual bool processEnter(); + /// Reject the current editor dialog if it is shown and returns true. + virtual bool processEscape(); + private: /// Show editor /// \param theOutValue a result value diff --git a/src/XGUI/XGUI_MenuMgr.cpp b/src/XGUI/XGUI_MenuMgr.cpp index fdb129faa..42253d5df 100755 --- a/src/XGUI/XGUI_MenuMgr.cpp +++ b/src/XGUI/XGUI_MenuMgr.cpp @@ -170,7 +170,7 @@ void XGUI_MenuMgr::createFeatureActions() aGroup->featuresInfo(); std::list >::const_iterator aFIt = aFeaturesInfo.begin(), aFLast = aFeaturesInfo.end(); - int aFSize = aFeaturesInfo.size(); + size_t aFSize = aFeaturesInfo.size(); for(int i = 0; aFIt != aFLast; aFIt++, i++) { std::shared_ptr aMessage = *aFIt; bool aUseSeparator = i == aFSize-1; diff --git a/src/XGUI/XGUI_OperationMgr.cpp b/src/XGUI/XGUI_OperationMgr.cpp index 42f892d21..8fa2501ec 100644 --- a/src/XGUI/XGUI_OperationMgr.cpp +++ b/src/XGUI/XGUI_OperationMgr.cpp @@ -90,6 +90,13 @@ public: else if (theEvent->type() == QEvent::KeyPress) { QKeyEvent* aKeyEvent = dynamic_cast(theEvent); myOperationMgr->setSHIFTPressed(aKeyEvent->modifiers() & Qt::ShiftModifier); + switch (aKeyEvent->key()) { + case Qt::Key_Escape: + isAccepted = myOperationMgr->onKeyPressed(theObject, aKeyEvent); + break; + default: + break; + } } } if (!isAccepted) @@ -104,7 +111,7 @@ private: XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent, ModuleBase_IWorkshop* theWorkshop) -: QObject(theParent), myWorkshop(theWorkshop), mySHIFTPressed(false) +: QObject(theParent), myWorkshop(theWorkshop), mySHIFTPressed(false), myActiveMessageBox(0) { /// we need to install filter to the application in order to react to 'Delete' key button /// this key can not be a short cut for a corresponded action because we need to set @@ -233,11 +240,9 @@ bool XGUI_OperationMgr::abortAllOperations() aResult = false; } else { - aResult = QMessageBox::question(qApp->activeWindow(), - tr("Abort operation"), - tr("All active operations will be aborted."), - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Cancel) == QMessageBox::Ok; + myActiveMessageBox = createMessageBox(tr("All active operations will be aborted.")); + aResult = myActiveMessageBox->exec() == QMessageBox::Ok; + myActiveMessageBox = 0; while(aResult && hasOperation()) { abortOperation(currentOperation()); } @@ -312,12 +317,11 @@ bool XGUI_OperationMgr::canStopOperation(ModuleBase_Operation* theOperation) return true; if (theOperation && theOperation->isModified()) { QString aMessage = tr("%1 operation will be aborted.").arg(theOperation->id()); - int anAnswer = QMessageBox::question(qApp->activeWindow(), - tr("Abort operation"), - aMessage, - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Cancel); - return anAnswer == QMessageBox::Ok; + + myActiveMessageBox = createMessageBox(aMessage); + int anAnswer = myActiveMessageBox->exec() == QMessageBox::Ok; + myActiveMessageBox = 0; + return anAnswer; } return true; } @@ -610,14 +614,6 @@ bool XGUI_OperationMgr::onKeyReleased(QObject *theObject, QKeyEvent* theEvent) ModuleBase_Operation* anOperation = currentOperation(); bool isAccepted = false; switch (theEvent->key()) { - case Qt::Key_Escape: { - ModuleBase_Operation* aOperation = currentOperation(); - if (aOperation) { - onAbortOperation(); - isAccepted = true; - } - } - break; case Qt::Key_Tab: case Qt::Key_Backtab: { @@ -669,6 +665,38 @@ bool XGUI_OperationMgr::onKeyReleased(QObject *theObject, QKeyEvent* theEvent) return isAccepted; } +bool XGUI_OperationMgr::onKeyPressed(QObject *theObject, QKeyEvent* theEvent) +{ + // Let the manager decide what to do with the given key combination. + ModuleBase_Operation* anOperation = currentOperation(); + bool isAccepted = false; + switch (theEvent->key()) { + case Qt::Key_Escape: { + // processing in message box + if (myActiveMessageBox) + { + myActiveMessageBox->reject(); + isAccepted = true; + } + // processing in the active widget + ModuleBase_Operation* aOperation = currentOperation(); + if (!isAccepted && aOperation) { + ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel(); + ModuleBase_ModelWidget* anActiveWgt = aPanel->activeWidget(); + if (anActiveWgt) + isAccepted = anActiveWgt && anActiveWgt->processEscape(); + } + // default Escape button functionality + if (!isAccepted && aOperation) { + onAbortOperation(); + isAccepted = true; + } + } + break; + } + return isAccepted; +} + bool XGUI_OperationMgr::onProcessEnter(QObject* theObject) { bool isAccepted = false; @@ -797,3 +825,14 @@ bool XGUI_OperationMgr::isChildObject(const QObject* theObject, const QObject* t } return isPPChild; } + +QMessageBox* XGUI_OperationMgr::createMessageBox(const QString& theMessage) +{ + QMessageBox * aMessageBox = new QMessageBox(QMessageBox::Question, + QObject::tr("Abort operation"), theMessage, QMessageBox::Ok | QMessageBox::Cancel, + qApp->activeWindow()); + aMessageBox->setDefaultButton(QMessageBox::Cancel); + aMessageBox->setEscapeButton(QMessageBox::No); // operation manager should process Esc key + + return aMessageBox; +} \ No newline at end of file diff --git a/src/XGUI/XGUI_OperationMgr.h b/src/XGUI/XGUI_OperationMgr.h index 3e6f3b099..ab282335e 100755 --- a/src/XGUI/XGUI_OperationMgr.h +++ b/src/XGUI/XGUI_OperationMgr.h @@ -31,6 +31,7 @@ #include class QKeyEvent; +class QMessageBox; class ModuleBase_IWorkshop; class XGUI_Workshop; @@ -192,6 +193,11 @@ protected: // TEMPORARY /// \param theEvent the mouse event bool onKeyReleased(QObject *theObject, QKeyEvent* theEvent); + /// SLOT, that is called by the key in the property panel is clicked. + /// \param theObject a sender of the event + /// \param theEvent the mouse event + bool onKeyPressed(QObject *theObject, QKeyEvent* theEvent); + /// The functionaly, that should be done by delete click /// Fistly the active widget processes it, then workshop. If no one does not /// process it, do nothing @@ -238,6 +244,12 @@ private: /// \param theParent a candidate to be a parent static bool isChildObject(const QObject* theObject, const QObject* theParent); + /// Creates question message box with OK/Cancel buttons, where Cancel is default button, + /// Escape is Null button + /// \param theMessage text of the message + /// \return message box + static QMessageBox* createMessageBox(const QString& theMessage); + private: typedef QList Operations; ///< definition for a list of operations Operations myOperations; ///< a stack of started operations. The active operation is on top, @@ -245,7 +257,7 @@ private: /// Current workshop ModuleBase_IWorkshop* myWorkshop; - + QMessageBox* myActiveMessageBox; XGUI_ShortCutListener* myShortCutListener; bool mySHIFTPressed; }; -- 2.39.2