Salome HOME
Merge branch 'Dev_2.8.0'
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetEditor.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include <ModuleBase_WidgetEditor.h>
22 #include <ModuleBase_ParamSpinBox.h>
23 #include <ModuleBase_Tools.h>
24
25 #include <Config_Keywords.h>
26 #include <Config_WidgetAPI.h>
27
28 #include <Events_Loop.h>
29 #include <ModelAPI_Events.h>
30
31 #include <ModelAPI_Feature.h>
32 #include <ModelAPI_Data.h>
33 #include <ModelAPI_Object.h>
34 #include <ModelAPI_AttributeDouble.h>
35
36 #include <GeomDataAPI_Point2D.h>
37
38 #include <QApplication>
39 #include <QKeyEvent>
40 #include <QLineEdit>
41 #include <QMenu>
42 #include <QWidget>
43 #include <QWidgetAction>
44 #include <QRegExp>
45 #include <QRegExpValidator>
46 #include <QDesktopWidget>
47 #include <QDialog>
48 #include <QLayout>
49
50 // Dialog is redefined to avoid Escape key processing
51 class ModuleBase_EditorDialog : public QDialog
52 {
53 public:
54   ModuleBase_EditorDialog(QWidget* theParent, Qt::WindowFlags theFlags)
55     : QDialog(theParent, theFlags) {}
56   ~ModuleBase_EditorDialog() {}
57
58 protected:
59   // Do nothing if key pressed because it is processing on operation manager level
60   virtual void keyPressEvent(QKeyEvent* theEvent) {
61     if (theEvent->key() == Qt::Key_Escape)
62         return;
63     QDialog::keyPressEvent(theEvent);
64   }
65 };
66
67 ModuleBase_WidgetEditor::ModuleBase_WidgetEditor(QWidget* theParent,
68                                                  const Config_WidgetAPI* theData)
69 : ModuleBase_WidgetDoubleValue(theParent, theData),
70   myXPosition(-1), myYPosition(-1), myEditorDialog(0)
71 {
72 }
73
74 ModuleBase_WidgetEditor::~ModuleBase_WidgetEditor()
75 {
76 }
77
78 bool ModuleBase_WidgetEditor::editedValue(double theSpinMinValue, double theSpinMaxValue,
79                                           double& outValue, QString& outText)
80 {
81   bool isValueAccepted = false;
82
83   myEditorDialog = new ModuleBase_EditorDialog(QApplication::desktop(), Qt::FramelessWindowHint);
84
85   QHBoxLayout* aLay = new QHBoxLayout(myEditorDialog);
86   aLay->setContentsMargins(2, 2, 2, 2);
87
88   ModuleBase_ParamSpinBox* anEditor = new ModuleBase_ParamSpinBox(myEditorDialog);
89   anEditor->setMinimum(theSpinMinValue);
90   anEditor->setMaximum(theSpinMaxValue);
91   if (outText.isEmpty())
92     anEditor->setValue(outValue);
93   else
94     anEditor->setText(outText);
95
96   aLay->addWidget(anEditor);
97
98   ModuleBase_Tools::setFocus(anEditor, "ModuleBase_WidgetEditor::editedValue");
99   anEditor->selectAll();
100
101   QPoint aPoint = QCursor::pos();
102   if (myXPosition >= 0 && myYPosition >= 0)
103     aPoint = QPoint(myXPosition, myYPosition);
104
105   myEditorDialog->move(aPoint);
106   isValueAccepted = myEditorDialog->exec() == QDialog::Accepted;
107   if (isValueAccepted) {
108     outText = anEditor->text();
109     bool isDouble;
110     double aValue = outText.toDouble(&isDouble);
111     if (isDouble) {
112       outValue = aValue;
113       outText = ""; // return empty string, if it's can be converted to a double
114     }
115   }
116   delete myEditorDialog;
117   myEditorDialog = 0;
118   return isValueAccepted;
119 }
120
121 bool ModuleBase_WidgetEditor::focusTo()
122 {
123   showPopupEditor();
124   return false;
125 }
126
127 bool ModuleBase_WidgetEditor::showPopupEditor(const bool theSendSignals)
128 {
129   bool isValueAccepted = false;
130   // we need to emit the focus in event manually in order to save the widget as an active
131   // in the property panel before the mouse leave event happens in the viewer. The module
132   // ask an active widget and change the feature visualization if the widget is not the current
133   // one.  Also we need this widget as active to provide call of processEnter() applyed
134   // by operation manager to the current widget. If not, the myEditorDialog will stay opened
135   emitFocusInWidget();
136
137   // nds: it seems, that the envents processing is not necessary anymore
138   // White while all events will be processed
139   //QApplication::processEvents();
140   double aValue = mySpinBox->value();
141   QString aText;
142   if (mySpinBox->hasVariable())
143     aText = mySpinBox->text();
144
145   isValueAccepted = editedValue(mySpinBox->minimum(), mySpinBox->maximum(), aValue, aText);
146   if (isValueAccepted) {
147     if (aText.isEmpty()) {
148       if (mySpinBox->hasVariable()) {
149         // variable text should be cleared before setting value as the value
150         // will not be set if there is a varable in control
151         ModuleBase_Tools::setSpinText(mySpinBox, "");
152       }
153       ModuleBase_Tools::setSpinValue(mySpinBox, aValue);
154     } else {
155       ModuleBase_Tools::setSpinText(mySpinBox, aText);
156     }
157     if (theSendSignals) {
158       emit valuesChanged();
159       // the focus leaves the control automatically by the Enter/Esc event
160       // it is processed in operation manager
161       //emit focusOutWidget(this);
162     }
163     else
164       storeValue();
165   }
166   ModuleBase_Tools::setFocus(mySpinBox, "ModuleBase_WidgetEditor::editedValue");
167   mySpinBox->selectAll();
168   // enter is processed, so we need not anymore emit clicked signal
169   //if (theSendSignals && !myIsEditing && isValueAccepted)
170   //  emit enterClicked(this);
171
172   return isValueAccepted;
173 }
174
175 void ModuleBase_WidgetEditor::setCursorPosition(const int theX, const int theY)
176 {
177   myXPosition = theX;
178   myYPosition = theY;
179 }
180
181 bool ModuleBase_WidgetEditor::processEnter()
182 {
183   if (myEditorDialog) {
184     myEditorDialog->accept();
185     return true;
186   }
187
188   return ModuleBase_WidgetDoubleValue::processEnter();
189 }
190
191 bool ModuleBase_WidgetEditor::processEscape()
192 {
193   if (myEditorDialog) {
194     myEditorDialog->reject();
195     return true;
196   }
197
198   return ModuleBase_WidgetDoubleValue::processEscape();
199 }