#include <QLineEdit>
#include <QDoubleValidator>
#include <QVariant>
+#include <QKeyEvent>
#include <limits>
SLOT(onTextChanged( const QString& )));
connect(this, SIGNAL(valueChanged(const QString&)), this, SLOT(onValueChanged(const QString&)));
- connect(this, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
+ //connect(this, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
}
/*!
return res;
}
-#include <QKeyEvent>
void ModuleBase_DoubleSpinBox::keyPressEvent(QKeyEvent *theEvent)
{
- myProcessedEvent = 0;
-
- bool anIsModified = myIsModified;
- QDoubleSpinBox::keyPressEvent(theEvent);
-
switch (theEvent->key()) {
case Qt::Key_Enter:
case Qt::Key_Return: {
- if (anIsModified)
- myProcessedEvent = theEvent;
- /*qDebug("ModuleBase_DoubleSpinBox::keyPressEvent");
- if (anIsModified) // we should not perform this event outside
- theEvent->setAccepted(true);
- else
- theEvent->setAccepted(false);*/
+ // do not react to the Enter key, the property panel processes it
+ return;
}
break;
default:
break;
}
+ QDoubleSpinBox::keyPressEvent(theEvent);
+}
+
+bool ModuleBase_DoubleSpinBox::focusNextPrevChild(bool theIsNext)
+{
+ myIsModified = false;
+
+ emit valueStored();
+ emit focusNextPrev();
+ return QDoubleSpinBox::focusNextPrevChild(theIsNext);
}
/*!
void ModuleBase_DoubleSpinBox::onEditingFinished()
{
- myIsModified = false;
+ //myIsModified = false;
}
-bool ModuleBase_DoubleSpinBox::isEventProcessed(QKeyEvent* theEvent)
+bool ModuleBase_DoubleSpinBox::isModified() const
{
- return myProcessedEvent && myProcessedEvent == theEvent;
+ return myIsModified;
+}
+
+void ModuleBase_DoubleSpinBox::clearModified()
+{
+ myIsModified = false;
}
/// Validate current value
virtual QValidator::State validate(QString&, int&) const;
- virtual bool isEventProcessed(QKeyEvent* theEvent);
+ // Returns true if the current value is modified by has not been applyed yet
+ virtual bool isModified() const;
+
+ // Clears modified state
+ void clearModified();
+
+signals:
+ /// A signal that is emitted by the "Tab" key event. It is emitted before the key is processed.
+ void focusNextPrev();
+ void valueStored();
protected slots:
/// Called on text changed
QString removeTrailingZeroes(const QString&) const;
virtual void keyPressEvent(QKeyEvent* theEvent);
+ /// The parent method that processes the "Tab"/"SHIF + Tab" keyboard events
+ /// Emits a signal about focus change
+ /// If theIsNext is true, this function searches forward, if next is false, it searches backward.
+ virtual bool focusNextPrevChild(bool theIsNext);
+
private:
/// Is clear flag
bool myCleared;
int myPrecision;
/// Boolean value whether the spin box content is modified
bool myIsModified;
-
- QKeyEvent* myProcessedEvent;
};
#endif
activateCustom();
}
+QWidget* ModuleBase_ModelWidget::getControlAcceptingFocus(const bool isFirst)
+{
+ QWidget* aControl = 0;
+
+ QList<QWidget*> aControls = getControls();
+ int aSize = aControls.size();
+
+ if (isFirst) {
+ for (int i = 0; i < aSize && !aControl; i++) {
+ if (aControls[i]->focusPolicy() != Qt::NoFocus)
+ aControl = aControls[i];
+ }
+ }
+ else {
+ for (int i = aSize - 1; i >= 0 && !aControl; i--) {
+ if (aControls[i]->focusPolicy() != Qt::NoFocus)
+ aControl = aControls[i];
+ }
+ }
+ return aControl;
+}
+
void ModuleBase_ModelWidget::setDefaultValue(const std::string& theValue)
{
myDefaultValue = theValue;
//blockUpdateViewer(false);
}
-bool ModuleBase_ModelWidget::isEventProcessed(QKeyEvent* theEvent)
+bool ModuleBase_ModelWidget::processEnter()
{
return false;
}
/// \return a control list
virtual QList<QWidget*> getControls() const = 0;
+ /// Returns the first or the last control that can accept the focus
+ /// \param isFirst if true, the first controls is returned or the last one
+ /// \return a control from a list of controls
+ QWidget* getControlAcceptingFocus(const bool isFirst);
+
/// FocusIn events processing
virtual bool eventFilter(QObject* theObject, QEvent *theEvent);
bool isEditingMode() const { return myIsEditing; }
/// Returns true if the event is processed.
- virtual bool isEventProcessed(QKeyEvent* theEvent);
+ virtual bool processEnter();
/// Sends Update and Redisplay for the given object
/// \param theObj is updating object
/// The signal about value state modification
void valueStateChanged();
+ void focusNextPrev();
+ void valueStored();
+
protected:
/// Sets default value of widget. Normally, widget should fetch this value
/// from the xml. However, some widgets derived widgets could define it
aControlLay->addRow(myLabel, mySpinBox);
#ifdef APPLY_BY_ENTER_OR_TAB
// Apply widget value change by enter/tab event.
- connect(mySpinBox, SIGNAL(editingFinished()), this, SIGNAL(valuesChanged()));
+ //connect(mySpinBox, SIGNAL(editingFinished()), this, SIGNAL(valuesChanged()));
+ connect(mySpinBox, SIGNAL(valueStored()), this, SIGNAL(valuesChanged()));
connect(mySpinBox, SIGNAL(valueChanged(const QString&)), this, SIGNAL(valuesModified()));
+ connect(mySpinBox, SIGNAL(focusNextPrev()), this, SIGNAL(focusNextPrev()));
#else
connect(mySpinBox, SIGNAL(valueChanged(const QString&)), this, SIGNAL(valuesChanged()));
return aList;
}
-bool ModuleBase_WidgetDoubleValue::isEventProcessed(QKeyEvent* theEvent)
+bool ModuleBase_WidgetDoubleValue::processEnter()
{
- return mySpinBox->isEventProcessed(theEvent);
+ bool isModified = mySpinBox->isModified();
+ if (isModified) {
+ emit valuesChanged();
+ mySpinBox->clearModified();
+ mySpinBox->selectAll();
+ }
+ return isModified;
}
virtual QList<QWidget*> getControls() const;
/// Returns true if the event is processed.
- virtual bool isEventProcessed(QKeyEvent* theEvent);
+ virtual bool processEnter();
public slots:
// Delayed value chnged: when user starts typing something,
#include <string>
ExpressionEditor::ExpressionEditor(QWidget* theParent)
-: QPlainTextEdit(theParent), myCompletedAndSelected(false)
+: QPlainTextEdit(theParent), myCompletedAndSelected(false), myIsModified(false)
{
myCompleter = new QCompleter(this);
myCompleter->setWidget(this);
this, SLOT(insertCompletion(const QString&)));
(void) new QShortcut(QKeySequence(tr("Ctrl+Space", "Complete")),
this, SLOT(performCompletion()));
+
+ connect(this, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
+
+ setTabChangesFocus(true);
}
ExpressionEditor::~ExpressionEditor()
void ExpressionEditor::keyPressEvent(QKeyEvent* theEvent)
{
+ bool anIsModified = myIsModified;
+
if (myCompletedAndSelected && handledCompletedAndSelected(theEvent))
return;
myCompletedAndSelected = false;
switch (theEvent->key()) {
case Qt::Key_Up:
case Qt::Key_Down:
+ case Qt::Key_Escape:
case Qt::Key_Enter:
case Qt::Key_Return:
- case Qt::Key_Escape:
theEvent->ignore();
- return;
+ return;
default:
myCompleter->popup()->hide();
break;
}
}
+ else {
+ switch (theEvent->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ // do not react to the Enter key, the property panel processes it
+ return;
+ break;
+ default:
+ break;
+ }
+ }
QPlainTextEdit::keyPressEvent(theEvent);
}
return myPlaceHolderText;
}
+bool ExpressionEditor::isModified() const
+{
+ return myIsModified;
+}
+
+void ExpressionEditor::clearModified()
+{
+ myIsModified = false;
+}
+
void ExpressionEditor::paintEvent( QPaintEvent* theEvent )
{
QPlainTextEdit::paintEvent( theEvent );
}
}
+bool ExpressionEditor::focusNextPrevChild(bool theIsNext)
+{
+ if (myIsModified)
+ emit editingFinished();
+ emit valueStored();
+ emit focusNextPrev();
+ return QPlainTextEdit::focusNextPrevChild(theIsNext);
+}
+
+void ExpressionEditor::onTextChanged()
+{
+ myIsModified = true;
+ emit valueModified();
+}
ModuleBase_WidgetExprEditor::ModuleBase_WidgetExprEditor( QWidget* theParent,
aMainLay->addWidget(myEditor);
this->setLayout(aMainLay);
- connect(myEditor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
+ connect(myEditor, SIGNAL(valueModified()), this, SIGNAL(valuesModified()));
+ //connect(myEditor, SIGNAL(editingFinished()), this, SLOT(onTextChanged()));
+ connect(myEditor, SIGNAL(valueStored()), this, SLOT(onTextChanged()));
+ connect(myEditor, SIGNAL(focusNextPrev()), this, SIGNAL(focusNextPrev()));
}
ModuleBase_WidgetExprEditor::~ModuleBase_WidgetExprEditor()
return result;
}
+bool ModuleBase_WidgetExprEditor::processEnter()
+{
+ bool isModified = myEditor->isModified();
+ if (isModified) {
+ emit valuesChanged();
+ myEditor->clearModified();
+ myEditor->selectAll();
+ }
+ return isModified;
+}
+
void ModuleBase_WidgetExprEditor::onTextChanged()
{
- storeValue();
+ emit valuesChanged();
}
/// Returns placeholder list
QString placeHolderText() const;
+ // Returns true if the current value is modified by has not been applyed yet
+ bool isModified() const;
+
+ // Clears modified state
+ void clearModified();
+
public slots:
/// Insert additional string for completion
/// \param theCompletion a string to insert
/// Perform completion
void performCompletion();
+ /// A slot for processing text changed event
+ void onTextChanged();
+
+signals:
+ void editingFinished();
+ void valueModified();
+ /// A signal that is emitted by the "Tab" key event. It is emitted before the key is processed.
+ void valueStored();
+ void focusNextPrev();
+
protected:
/// Perform completion by prefix
/// \param theCompletionPrefix a prefix for looking for completion
/// Redefinition of virtual method
virtual void paintEvent( QPaintEvent* );
+ /// The parent method that processes the "Tab"/"SHIF + Tab" keyboard events
+ /// Emits a signal about focus change
+ /// If theIsNext is true, this function searches forward, if next is false, it searches backward.
+ virtual bool focusNextPrevChild(bool theIsNext);
+
private:
QStringListModel* myCompleterModel;
QCompleter* myCompleter;
bool myCompletedAndSelected;
QString myPlaceHolderText;
+
+ /// Boolean value whether the spin box content is modified
+ bool myIsModified;
};
/**
/// Redefinition of virtual method
virtual QList<QWidget*> getControls() const;
- public slots:
- /// A slot for processing text changed event
+ /// Returns true if the event is processed.
+ virtual bool processEnter();
+
+protected slots:
+ /// A slot for processing text changed event
void onTextChanged();
protected:
#ifdef APPLY_BY_ENTER_OR_TAB
// Apply widget value change by enter/tab event.
- connect(myXSpin, SIGNAL(editingFinished()), this, SLOT(onValuesChanged()));
+ //connect(myXSpin, SIGNAL(editingFinished()), this, SLOT(onValuesChanged()));
+ //connect(myXSpin, SIGNAL(focusNextPrev()), this, SLOT(onValuesChanged()));
+ connect(myXSpin, SIGNAL(valueStored()), this, SLOT(onValuesChanged()));
connect(myXSpin, SIGNAL(valueChanged(const QString&)), this, SIGNAL(valuesModified()));
+ connect(myXSpin, SIGNAL(focusNextPrev()), this, SIGNAL(focusNextPrev()));
#else
connect(myXSpin, SIGNAL(valueChanged(const QString&)), this, SLOT(onValuesChanged()));
#endif
#ifdef APPLY_BY_ENTER_OR_TAB
// Apply widget value change by enter/tab event.
- connect(myYSpin, SIGNAL(editingFinished()), this, SLOT(onValuesChanged()));
+ //connect(myYSpin, SIGNAL(editingFinished()), this, SLOT(onValuesChanged()));
+ connect(myYSpin, SIGNAL(valueStored()), this, SLOT(onValuesChanged()));
connect(myYSpin, SIGNAL(valueChanged(const QString&)), this, SIGNAL(valuesModified()));
+ connect(myYSpin, SIGNAL(focusNextPrev()), this, SIGNAL(focusNextPrev()));
#else
connect(myYSpin, SIGNAL(valueChanged(const QString&)), this, SLOT(onValuesChanged()));
#endif
emit valuesChanged();
}
-bool PartSet_WidgetPoint2D::isEventProcessed(QKeyEvent* theEvent)
+bool PartSet_WidgetPoint2D::processEnter()
{
- return myXSpin->isEventProcessed(theEvent) || myXSpin->isEventProcessed(theEvent);
+ bool isModified = myXSpin->isModified() || myYSpin->isModified();
+ if (isModified) {
+ bool isXModified = myXSpin->isModified();
+ emit valuesChanged();
+ myXSpin->clearModified();
+ myYSpin->clearModified();
+ if (isXModified)
+ myXSpin->selectAll();
+ else
+ myYSpin->selectAll();
+ }
+ return isModified;
}
double y() const;
/// Returns true if the event is processed.
- virtual bool isEventProcessed(QKeyEvent* theEvent);
+ virtual bool processEnter();
signals:
/// Signal about selection of an existing vertex from an object
// Reconnect to local slot
#ifdef APPLY_BY_ENTER_OR_TAB
// Apply widget value change by enter/tab event.
- disconnect(mySpinBox, SIGNAL(editingFinished()), this, SIGNAL(valuesChanged()));
+ //disconnect(mySpinBox, SIGNAL(editingFinished()), this, SIGNAL(valuesChanged()));
+ disconnect(mySpinBox, SIGNAL(valueStored()), this, SIGNAL(valuesChanged()));
connect(mySpinBox, SIGNAL(editingFinished()), this, SLOT(onValuesChanged()));
connect(mySpinBox, SIGNAL(valueChanged(double)), this, SIGNAL(valuesModified()));
#else
emit valuesChanged();
}
-bool PartSet_WidgetPoint2dDistance::isEventProcessed(QKeyEvent* theEvent)
+bool PartSet_WidgetPoint2dDistance::processEnter()
{
- return mySpinBox->isEventProcessed(theEvent);
+ bool isModified = mySpinBox->isModified();
+ if (isModified) {
+ emit valuesChanged();
+ mySpinBox->clearModified();
+ mySpinBox->selectAll();
+ }
+ return isModified;
}
void setSketch(CompositeFeaturePtr theSketch) { mySketch = theSketch; }
/// Returns true if the event is processed.
- virtual bool isEventProcessed(QKeyEvent* theEvent);
+ virtual bool processEnter();
public slots:
/// Process of mouse move
#include "XGUI_Workshop.h"
#include "XGUI_ErrorMgr.h"
+#include <ModuleBase_IPropertyPanel.h>
+#include <ModuleBase_ModelWidget.h>
#include "ModuleBase_Operation.h"
#include "ModuleBase_IWorkshop.h"
#include "ModuleBase_IModule.h"
}
}
-#include <ModuleBase_IPropertyPanel.h>
-#include <ModuleBase_ModelWidget.h>
bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
{
+ qDebug("XGUI_OperationMgr::onKeyReleased");
+
QObject* aSender = sender();
// Let the manager decide what to do with the given key combination.
switch (theEvent->key()) {
case Qt::Key_Return:
case Qt::Key_Enter: {
+ qDebug("XGUI_OperationMgr::onKeyReleased: Key_Return");
ModuleBase_Operation* aOperation = currentOperation();
ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
ModuleBase_ModelWidget* aActiveWgt = aPanel->activeWidget();
- if (!aActiveWgt || !aActiveWgt->isEventProcessed(theEvent)) {
+ if (!aActiveWgt || !aActiveWgt->processEnter()) {
ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(currentOperation());
if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty()) {
emit keyEnterReleased();
this, SLOT(activateNextWidget(ModuleBase_ModelWidget*)));
connect(aWidget, SIGNAL(keyReleased(QKeyEvent*)),
this, SIGNAL(keyReleased(QKeyEvent*)));
- }
-
- QWidget* aLastControl = 0;
- QList<QWidget*> aControls;
- for (int i = myWidgets.size()-1; i >= 0 && !aLastControl; i--) {
- aControls = myWidgets[i]->getControls();
- for (int j = aControls.size()-1; j >= 0 && !aLastControl; j--) {
- if (aControls[j]->focusPolicy() != Qt::NoFocus)
- aLastControl = aControls[j];
- }
- }
- if (aLastControl) {
- QToolButton* anOkBtn = findChild<QToolButton*>(PROP_PANEL_OK);
- QToolButton* aCancelBtn = findChild<QToolButton*>(PROP_PANEL_CANCEL);
-
- setTabOrder(aLastControl, anOkBtn);
- setTabOrder(anOkBtn, aCancelBtn);
+ connect(aWidget, SIGNAL(focusNextPrev()),
+ this, SLOT(onFocusNextPrev()));
}
}
ModuleBase_PageBase* XGUI_PropertyPanel::contentWidget()
{
-
return static_cast<ModuleBase_PageBase*>(myPanelPage);
}
activateWidget(NULL);
}
+void XGUI_PropertyPanel::onFocusNextPrev()
+{
+ setActiveWidget(NULL);
+}
+
+bool XGUI_PropertyPanel::focusNextPrevChild(bool theIsNext)
+{
+ // it wraps the Tabs clicking to follow in the chain:
+ // controls, last control, Apply, Cancel, first control, controls
+
+ bool isChangedFocus = false;
+ if (theIsNext) { // forward by Tab
+ QToolButton* aCancelBtn = findChild<QToolButton*>(PROP_PANEL_CANCEL);
+ if (aCancelBtn->hasFocus()) {
+ // after cancel, the first control should be focused
+ QWidget* aFirstControl = 0;
+ for (int i = 0, aSize = myWidgets.size(); i < aSize && !aFirstControl; i++)
+ aFirstControl = myWidgets[i]->getControlAcceptingFocus(true);
+ if (aFirstControl)
+ aFirstControl->setFocus();
+ isChangedFocus = true;
+ }
+ else {
+ // after the last control, the Apply button should be focused
+ QWidget* aLastControl = 0;
+ for (int i = myWidgets.size()-1; i >= 0 && !aLastControl; i--)
+ aLastControl = myWidgets[i]->getControlAcceptingFocus(false);
+ if (aLastControl && aLastControl->hasFocus()) {
+ setFocusOnOkButton();
+ isChangedFocus = true;
+ }
+ }
+ }
+ else { // backward by SHIFT + Tab
+ QToolButton* anOkBtn = findChild<QToolButton*>(PROP_PANEL_OK);
+ if (anOkBtn->hasFocus()) {
+ // after Apply, the last control should be focused
+ QWidget* aLastControl = 0;
+ for (int i = myWidgets.size()-1; i >= 0 && !aLastControl; i--)
+ aLastControl = myWidgets[i]->getControlAcceptingFocus(false);
+ if (aLastControl)
+ aLastControl->setFocus();
+ isChangedFocus = true;
+ }
+ else {
+ // after the first control, the Cancel button should be focused
+ QWidget* aFirstControl = 0;
+ for (int i = 0, aSize = myWidgets.size(); i < aSize && !aFirstControl; i++)
+ aFirstControl = myWidgets[i]->getControlAcceptingFocus(true);
+ if (aFirstControl && aFirstControl->hasFocus()) {
+ QToolButton* aCancelBtn = findChild<QToolButton*>(PROP_PANEL_CANCEL);
+ aCancelBtn->setFocus();
+ isChangedFocus = true;
+ }
+ }
+ }
+
+ if (!isChangedFocus)
+ isChangedFocus = ModuleBase_IPropertyPanel::focusNextPrevChild(theIsNext);
+
+ return isChangedFocus;
+}
+
void XGUI_PropertyPanel::activateNextWidget()
{
activateNextWidget(myActiveWidget);
}
void XGUI_PropertyPanel::activateWidget(ModuleBase_ModelWidget* theWidget)
+{
+ // Avoid activation of already actve widget. It could happen on focusIn event many times
+ setActiveWidget(theWidget);
+
+ if (myActiveWidget) {
+ emit widgetActivated(myActiveWidget);
+ } else if (!isEditingMode()) {
+ emit noMoreWidgets();
+ setFocusOnOkButton();
+ }
+}
+
+void XGUI_PropertyPanel::setActiveWidget(ModuleBase_ModelWidget* theWidget)
{
// Avoid activation of already actve widget. It could happen on focusIn event many times
if (theWidget == myActiveWidget) {
theWidget->activate();
}
myActiveWidget = theWidget;
- if (myActiveWidget) {
- emit widgetActivated(theWidget);
- } else if (!isEditingMode()) {
- emit noMoreWidgets();
setFocusOnOkButton();
- }
}
void XGUI_PropertyPanel::setFocusOnOkButton()
*/
virtual void activateWidget(ModuleBase_ModelWidget* theWidget);
+ void onFocusNextPrev();
+
+protected:
+ /// Makes the widget active, deactivate the previous, activate and hightlight the given one
+ /// \param theWidget a widget
+ void setActiveWidget(ModuleBase_ModelWidget* theWidget);
+
+ /// The parent method that processes the "Tab"/"SHIF + Tab" keyboard events
+ /// Emits a signal about focus change
+ /// If theIsNext is true, this function searches forward, if next is false, it searches backward.
+ virtual bool focusNextPrevChild(bool theIsNext);
+
protected:
/// A method called on the property panel closed
/// \param theEvent a close event