]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Expression editor implementation
authorsbh <sergey.belash@opencascade.com>
Thu, 2 Apr 2015 09:27:59 +0000 (12:27 +0300)
committersbh <sergey.belash@opencascade.com>
Thu, 2 Apr 2015 09:27:59 +0000 (12:27 +0300)
src/Config/Config_Keywords.h
src/ModelAPI/ModelAPI_ResultParameters.h
src/ModuleBase/CMakeLists.txt
src/ModuleBase/ModuleBase_WidgetExprEditor.cpp [new file with mode: 0644]
src/ModuleBase/ModuleBase_WidgetExprEditor.h [new file with mode: 0644]
src/ModuleBase/ModuleBase_WidgetFactory.cpp
src/ModuleBase/ModuleBase_WidgetLineEdit.cpp
src/ParametersPlugin/plugin-Parameters.xml
src/XGUI/pictures/expression.png

index bc115a764f1ee1e1f5603126505031e3be70452f..a9f44bf63b4a5adc2a7b79184d03b00e5e0031db 100644 (file)
@@ -31,6 +31,7 @@ const static char* WDG_SHAPE_SELECTOR = "shape_selector";
 const static char* WDG_CHOICE = "choice";
 const static char* WDG_DOUBLEVALUE_EDITOR = "doublevalue_editor";
 const static char* WDG_FILE_SELECTOR= "file_selector";
+const static char* WDG_EXPR_EDITOR = "expr_editor";
 // Containers
 const static char* WDG_GROUP = "groupbox";
 const static char* WDG_CHECK_GROUP = "check_groupbox";
index 3b8bd1535e94112f2a4935ab32f1a00132988fb9..aae2a15ed116ba8daf24b5de006f5329e282500a 100644 (file)
@@ -4,8 +4,8 @@
 // Created:     07 Jul 2014
 // Author:      Vitaly SMETANNIKOV
 
-#ifndef ModelAPI_ResultParameters_H_
-#define ModelAPI_ResultParameters_H_
+#ifndef MODELAPI_RESULTPARAMETERS_H_
+#define MODELAPI_RESULTPARAMETERS_H_
 
 #include "ModelAPI_Result.h"
 
index b623713fc7ef550ae99d708c8e438e319631705e..3f5ba997f88d382f3d80ec29308c6b6c435a1a43 100644 (file)
@@ -51,6 +51,7 @@ SET(PROJECT_HEADERS
        ModuleBase_WidgetSwitch.h
        ModuleBase_WidgetToolbox.h
        ModuleBase_WidgetValidated.h
+       ModuleBase_WidgetExprEditor.h
 )
 
 SET(PROJECT_SOURCES
@@ -92,6 +93,7 @@ SET(PROJECT_SOURCES
        ModuleBase_WidgetSwitch.cpp
        ModuleBase_WidgetToolbox.cpp
        ModuleBase_WidgetValidated.cpp
+       ModuleBase_WidgetExprEditor.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/ModuleBase/ModuleBase_WidgetExprEditor.cpp b/src/ModuleBase/ModuleBase_WidgetExprEditor.cpp
new file mode 100644 (file)
index 0000000..64ca2e3
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+/*
+ * ModuleBase_WidgetExprEditor.cpp
+ *
+ *  Created on: Aug 28, 2014
+ *      Author: sbh
+ */
+
+#include <ModuleBase_WidgetExprEditor.h>
+#include <ModuleBase_Tools.h>
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Object.h>
+#include <ModelAPI_Validator.h>
+
+#include <Config_WidgetAPI.h>
+
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QObject>
+#include <QString>
+#include <QStringListModel>
+#include <QCompleter>
+#include <QSize>
+#include <QShortcut>
+#include <QScrollBar>
+
+#include <memory>
+#include <string>
+
+ExpressionEditor::ExpressionEditor(QWidget* theParent)
+: QPlainTextEdit(theParent)
+{
+  myCompleter = new QCompleter(this);
+  myCompleter->setWidget(this);
+  myCompleter->setCompletionMode(QCompleter::PopupCompletion);
+
+  myCompleterModel = new QStringListModel(this);
+  myCompleter->setModel(myCompleterModel);
+  // Use sorted model to accelerate completion (QCompleter will use binary search)
+  myCompleter->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
+  myCompleter->setCaseSensitivity(Qt::CaseInsensitive);
+
+  connect(myCompleter, SIGNAL(activated(const QString&)),
+          this,        SLOT(insertCompletion(const QString&)));
+  (void) new QShortcut(QKeySequence(tr("Ctrl+Space", "Complete")),
+                       this, SLOT(performCompletion()));
+}
+
+ExpressionEditor::~ExpressionEditor()
+{
+
+}
+
+void ExpressionEditor::setCompletionList(QStringList& theList)
+{
+  theList.sort();
+  theList.removeDuplicates();
+  myCompleterModel->setStringList(theList);
+}
+
+void ExpressionEditor::insertCompletion(const QString& theCompletion, bool isSingleWord)
+{
+  QTextCursor aCursor = textCursor();
+  int numberOfCharsToComplete = theCompletion.length() -
+      myCompleter->completionPrefix().length();
+  int insertionPosition = aCursor.position();
+  aCursor.insertText(theCompletion.right(numberOfCharsToComplete));
+  if (isSingleWord) {
+    aCursor.setPosition(insertionPosition);
+    aCursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+    myCompletedAndSelected = true;
+  }
+  setTextCursor(aCursor);
+}
+
+void ExpressionEditor::performCompletion()
+{
+  QTextCursor aCursor = textCursor();
+  aCursor.select(QTextCursor::WordUnderCursor);
+  const QString aPrefix = aCursor.selectedText();
+  if (!aPrefix.isEmpty() && aPrefix.at(aPrefix.length() - 1).isLetter()) {
+    performCompletion(aPrefix);
+  }
+}
+
+void ExpressionEditor::performCompletion(const QString& theCompletionPrefix)
+{
+  //populate model?
+  if (theCompletionPrefix != myCompleter->completionPrefix()) {
+    myCompleter->setCompletionPrefix(theCompletionPrefix);
+    myCompleter->popup()->setCurrentIndex(myCompleter->completionModel()->index(0, 0));
+  }
+  if (myCompleter->completionCount() == 1) {
+    insertCompletion(myCompleter->currentCompletion(), true);
+  } else {
+    QRect aRect = cursorRect();
+    aRect.setWidth(myCompleter->popup()->sizeHintForColumn(0)
+                  + myCompleter->popup()->verticalScrollBar()->sizeHint().width());
+    myCompleter->complete(aRect);
+  }
+}
+
+void ExpressionEditor::keyPressEvent(QKeyEvent* theEvent)
+{
+  if (myCompletedAndSelected && handledCompletedAndSelected(theEvent))
+    return;
+  myCompletedAndSelected = false;
+  if (myCompleter->popup()->isVisible()) {
+    switch (theEvent->key()) {
+      case Qt::Key_Up:
+      case Qt::Key_Down:
+      case Qt::Key_Enter:
+      case Qt::Key_Return:
+      case Qt::Key_Escape:
+        theEvent->ignore();
+        return;
+      default:
+        myCompleter->popup()->hide();
+        break;
+    }
+  }
+  QPlainTextEdit::keyPressEvent(theEvent);
+}
+
+bool ExpressionEditor::handledCompletedAndSelected(QKeyEvent* theEvent)
+{
+  myCompletedAndSelected = false;
+  QTextCursor aCursor = textCursor();
+  switch (theEvent->key()) {
+    case Qt::Key_Enter:
+    case Qt::Key_Return: aCursor.clearSelection(); break;
+    case Qt::Key_Escape: aCursor.removeSelectedText(); break;
+    default: return false;
+  }
+  setTextCursor(aCursor);
+  theEvent->accept();
+  return true;
+}
+
+ModuleBase_WidgetExprEditor::ModuleBase_WidgetExprEditor(QWidget* theParent,
+                                                     const Config_WidgetAPI* theData,
+                                                     const std::string& theParentId)
+    : ModuleBase_ModelWidget(theParent, theData, theParentId)
+{
+  QVBoxLayout* aMainLay = new QVBoxLayout(this);
+  ModuleBase_Tools::adjustMargins(aMainLay);
+
+  myEditor = new ExpressionEditor(this);
+  myEditor->setMinimumHeight(20);
+  aMainLay->addWidget(myEditor);
+  this->setLayout(aMainLay);
+
+  connect(myEditor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
+}
+
+ModuleBase_WidgetExprEditor::~ModuleBase_WidgetExprEditor()
+{
+}
+
+bool ModuleBase_WidgetExprEditor::storeValueCustom() const
+{
+  // A rare case when plugin was not loaded. 
+  if(!myFeature)
+    return false;
+  DataPtr aData = myFeature->data();
+  AttributeStringPtr aStringAttr = aData->string(attributeID());
+  QString aWidgetValue = myEditor->toPlainText();
+  aStringAttr->setValue(aWidgetValue.toStdString());
+  updateObject(myFeature);
+  return true;
+}
+
+bool ModuleBase_WidgetExprEditor::restoreValue()
+{
+  // A rare case when plugin was not loaded. 
+  if(!myFeature)
+    return false;
+  DataPtr aData = myFeature->data();
+  AttributeStringPtr aStringAttr = aData->string(attributeID());
+
+  bool isBlocked = myEditor->blockSignals(true);
+  QTextCursor aCursor = myEditor->textCursor();
+  int pos = aCursor.position();
+  std::string aRestoredStr = aStringAttr->value();
+  myEditor->setPlainText(QString::fromStdString(aRestoredStr));
+  aCursor.setPosition(pos);
+  myEditor->setTextCursor(aCursor);
+  myEditor->blockSignals(isBlocked);
+
+  return true;
+}
+
+QList<QWidget*> ModuleBase_WidgetExprEditor::getControls() const
+{
+  QList<QWidget*> result;
+  result << myEditor;
+  return result;
+}
+
+void ModuleBase_WidgetExprEditor::onTextChanged()
+{
+  storeValue();
+}
diff --git a/src/ModuleBase/ModuleBase_WidgetExprEditor.h b/src/ModuleBase/ModuleBase_WidgetExprEditor.h
new file mode 100644 (file)
index 0000000..41a209f
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+/*
+ * ModuleBase_WidgetExprEditor.h
+ *
+ *  Created on: Oct 8, 2014
+ *      Author: sbh
+ */
+
+#ifndef MODULEBASE_WIDGETEXPREDITOR_H_
+#define MODULEBASE_WIDGETEXPREDITOR_H_
+
+#include <ModuleBase.h>
+#include <ModuleBase_ModelWidget.h>
+
+#include <QList>
+#include <QString>
+#include <QStringList>
+#include <QPlainTextEdit>
+
+class QWidget;
+class QStringListModel;
+class QCompleter;
+
+class ExpressionEditor: public QPlainTextEdit
+{
+  Q_OBJECT
+
+ public:
+  explicit ExpressionEditor(QWidget* theParent = 0);
+  virtual ~ExpressionEditor();
+
+  void setCompletionList(QStringList&);
+
+ public slots:
+  void insertCompletion(const QString&, bool isSingleWord = false);
+  void performCompletion();
+
+ protected:
+  void performCompletion(const QString& theCompletionPrefix);
+  virtual void keyPressEvent(QKeyEvent* theEvent);
+  bool handledCompletedAndSelected(QKeyEvent* theEvent);
+
+ private:
+  QStringListModel* myCompleterModel;
+  QCompleter* myCompleter;
+  bool myCompletedAndSelected;
+};
+
+/**
+* \ingroup GUI
+* TODO(sbh) add doc
+*/
+class MODULEBASE_EXPORT ModuleBase_WidgetExprEditor : public ModuleBase_ModelWidget
+{
+  Q_OBJECT
+ public:
+  /// Constructor
+  /// \param theParent the parent object
+  /// \param theData the widget configuration.
+  /// \param theParentId is Id of a parent of the current attribute
+  ModuleBase_WidgetExprEditor(QWidget* theParent,
+                                const Config_WidgetAPI* theData,
+                                const std::string& theParentId);
+  virtual ~ModuleBase_WidgetExprEditor();
+
+  virtual bool restoreValue();
+
+  virtual QList<QWidget*> getControls() const;
+
+ public slots:
+   /// A slot for processing text changed event
+  void onTextChanged();
+
+protected:
+  /// Saves the internal parameters to the given feature
+  /// \return True in success
+  virtual bool storeValueCustom() const;
+
+private:
+   /// A line edit control
+  ExpressionEditor* myEditor;
+};
+
+#endif /* MODULEBASE_WIDGETEXPREDITOR_H_ */
index 93c3e7271a86ea824de85398c0f4571bf0c8774a..eedb3a390759f687d552ed6e15fcbe8a7d0e23aa 100644 (file)
 
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_OperationDescription.h>
-//#include <ModuleBase_WidgetFeatureOrAttribute.h>
-//#include <ModuleBase_WidgetFeature.h>
 #include <ModuleBase_WidgetEditor.h>
 #include <ModuleBase_WidgetSwitch.h>
 #include <ModuleBase_WidgetShapeSelector.h>
 #include <ModuleBase_WidgetDoubleValue.h>
 #include <ModuleBase_WidgetBoolValue.h>
-//#include <ModuleBase_WidgetPoint2dDistance.h>
 #include <ModuleBase_WidgetFileSelector.h>
 #include <ModuleBase_WidgetChoice.h>
 #include <ModuleBase_IWorkshop.h>
@@ -31,6 +28,7 @@
 #include <ModuleBase_PageBase.h>
 #include <ModuleBase_PageGroupBox.h>
 #include <ModuleBase_PageWidget.h>
+#include <ModuleBase_WidgetExprEditor.h>
 
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
@@ -115,53 +113,45 @@ void ModuleBase_WidgetFactory::createWidget(ModuleBase_PageBase* thePage)
   thePage->alignToTop();
 }
 
-ModuleBase_ModelWidget* ModuleBase_WidgetFactory
-::createWidgetByType(const std::string& theType, QWidget* theParent)
+ModuleBase_ModelWidget* ModuleBase_WidgetFactory::createWidgetByType(const std::string& theType,
+                                                                     QWidget* theParent)
 {
   ModuleBase_ModelWidget* result = NULL;
 
   if (theType == WDG_INFO) {
     result = new ModuleBase_WidgetLabel(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_DOUBLEVALUE) {
     result = new ModuleBase_WidgetDoubleValue(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_SHAPE_SELECTOR) {
-    result =  new ModuleBase_WidgetShapeSelector(theParent, myWorkshop, myWidgetApi, myParentId);
-
+    result = new ModuleBase_WidgetShapeSelector(theParent, myWorkshop, myWidgetApi, myParentId);
   } else if (theType == WDG_BOOLVALUE) {
     result = new ModuleBase_WidgetBoolValue(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_DOUBLEVALUE_EDITOR) {
     result = new ModuleBase_WidgetEditor(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_FILE_SELECTOR) {
     result = new ModuleBase_WidgetFileSelector(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_CHOICE) {
-    result = new ModuleBase_WidgetChoice(theParent, myWidgetApi,myParentId);
-
+    result = new ModuleBase_WidgetChoice(theParent, myWidgetApi, myParentId);
   } else if (theType == WDG_STRINGVALUE) {
-    result = new ModuleBase_WidgetLineEdit(theParent, myWidgetApi,myParentId);
-
+    result = new ModuleBase_WidgetLineEdit(theParent, myWidgetApi, myParentId);
+  } else if (theType == WDG_EXPR_EDITOR) {
+    result = new ModuleBase_WidgetExprEditor(theParent, myWidgetApi, myParentId);
   } else if (theType == WDG_MULTISELECTOR) {
-    result = new ModuleBase_WidgetMultiSelector(theParent, myWorkshop, myWidgetApi,myParentId);
-
+    result = new ModuleBase_WidgetMultiSelector(theParent, myWorkshop, myWidgetApi, myParentId);
   } else if (theType == WDG_TOOLBOX) {
     result = new ModuleBase_WidgetToolbox(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_SWITCH) {
     result = new ModuleBase_WidgetSwitch(theParent, myWidgetApi, myParentId);
-
   } else if (theType == WDG_TOOLBOX_BOX || theType == WDG_SWITCH_CASE) {
     // Do nothing for "box" and "case"
     result = NULL;
   } else {
-    result = myWorkshop->module()->createWidgetByType(theType, theParent, myWidgetApi,
-                                                      myParentId);
-#ifdef _DEBUG
-    if (!result) {qDebug("ModuleBase_WidgetFactory::fillWidget: find bad widget type");}
-#endif
+    result = myWorkshop->module()->createWidgetByType(theType, theParent, myWidgetApi, myParentId);
+    #ifdef _DEBUG
+    if (!result) {
+      qDebug("ModuleBase_WidgetFactory::fillWidget: find bad widget type");
+    }
+    #endif
   }
   if (result) {
     myModelWidgets.append(result);
index 9c4a1b00f068fd36b0ef838b9320ca9f5a9f0a5b..1f1dbd5349d34d63f97060c31ba924cdd8075f1d 100644 (file)
@@ -33,10 +33,15 @@ ModuleBase_WidgetLineEdit::ModuleBase_WidgetLineEdit(QWidget* theParent,
 {
   QFormLayout* aMainLay = new QFormLayout(this);
   ModuleBase_Tools::adjustMargins(aMainLay);
-  QString aTitle = QString::fromStdString(theData->widgetLabel());
+  QString aLabelText = QString::fromStdString(theData->widgetLabel());
+  QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
+  QLabel* aLabel = new QLabel(aLabelText, this);
+  if (!aLabelIcon.isEmpty())
+    aLabel->setPixmap(QPixmap(aLabelIcon));
+
   myLineEdit = new QLineEdit(this);
   myLineEdit->setMinimumHeight(20);
-  aMainLay->addRow(aTitle, myLineEdit);
+  aMainLay->addRow(aLabel, myLineEdit);
   this->setLayout(aMainLay);
 
   connect(myLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChanged()));
index 63ba2ab685faf77272fc85da7ff3c8276946a8dd..027f50c246e8de829531bd99f0f5f3f8190583ac 100644 (file)
@@ -4,8 +4,8 @@
   <workbench id="Part">
     <group id="Parameters">
       <feature id="Parameter" title="New Variable" tooltip="Creates a variable" icon=":pictures/expression.png">
-        <stringvalue id="variable" label="Name"/>
-        <stringvalue id="expression" icon="Value"/>
+        <stringvalue id="variable" label="Name" icon=":pictures/expression.png"/>
+        <expr_editor id="expression"/>
       </feature>
     </group>
   </workbench>
index 39dd556e638aaf646e1082eb13cf1ffbecba190b..74ab35722a14844fa64fe2d6e110eb92ea572a1d 100644 (file)
Binary files a/src/XGUI/pictures/expression.png and b/src/XGUI/pictures/expression.png differ