]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Task 2.7: Code completion and parameters creation (not finished)
authorvsv <vsv@opencascade.com>
Fri, 25 May 2018 12:42:27 +0000 (15:42 +0300)
committervsv <vsv@opencascade.com>
Fri, 25 May 2018 12:42:46 +0000 (15:42 +0300)
src/ModuleBase/ModuleBase_ParamSpinBox.cpp
src/ModuleBase/ModuleBase_ParamSpinBox.h
src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp
src/ModuleBase/ModuleBase_WidgetExprEditor.cpp

index 37d888213e2b456dd8bc191f0c19aad0eb7508d3..4438684664dc273d3b71b17d9c12aaaed609cfd8 100644 (file)
@@ -28,7 +28,6 @@
 #include <ModelAPI_Tools.h>
 
 #include <QKeyEvent>
-#include <QLineEdit>
 #include <QLocale>
 #include <QRegExp>
 #include <QToolTip>
 
 #include <QStringListModel>
 #include <QCompleter>
+#include <QAbstractItemView>
 #include <QShortcut>
 
 #include <string>
 #include <iostream>
 
-//#define DEBUG_COMPLETE_WITH_PARAMETERS
-
 ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrecision)
-    : ModuleBase_DoubleSpinBox(theParent, thePrecision),
-      myAcceptVariables(true)
+  : QAbstractSpinBox(theParent),
+  myPrecision(thePrecision),
+  myIsEquation(false),
+  myAcceptVariables(true),
+  myDecimals(3),
+  mySingleStep(1),
+  myMinimum(DBL_MIN),
+  myMaximum(DBL_MAX)
 {
-#ifdef DEBUG_COMPLETE_WITH_PARAMETERS
   myCompleter = new QCompleter(this);
-  myCompleter->setWidget(this);
+  myCompleter->setWidget(lineEdit());
   myCompleter->setCompletionMode(QCompleter::PopupCompletion);
 
   myCompleterModel = new QStringListModel(this);
@@ -57,20 +60,24 @@ ModuleBase_ParamSpinBox::ModuleBase_ParamSpinBox(QWidget* theParent, int thePrec
   // Use sorted model to accelerate completion (QCompleter will use binary search)
   myCompleter->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
   myCompleter->setCaseSensitivity(Qt::CaseInsensitive);
+  connect(myCompleter, SIGNAL(highlighted(const QString&)),
+    this, SLOT(insertCompletion(const QString&)));
 
-  lineEdit()->setCompleter(myCompleter);
-#endif
+  //  connectSignalsAndSlots();
+  myEnabledBaseColor = palette().color(QPalette::Active, QPalette::Base);
+  connect(lineEdit(), SIGNAL(textChanged(const QString&)),
+    this, SLOT(onTextChanged(const QString&)));
 
-  connectSignalsAndSlots();
+  myValidator = new QDoubleValidator(this);
+  myValidator->setLocale(locale());
+  myValidator->setRange(myMinimum, myMaximum);
 }
 
 void ModuleBase_ParamSpinBox::setCompletionList(QStringList& theList)
 {
-#ifdef DEBUG_COMPLETE_WITH_PARAMETERS
   theList.sort();
   theList.removeDuplicates();
   myCompleterModel->setStringList(theList);
-#endif
 }
 
 /*!
@@ -91,43 +98,53 @@ ModuleBase_ParamSpinBox::~ModuleBase_ParamSpinBox()
  */
 void ModuleBase_ParamSpinBox::stepBy(int steps)
 {
-  if ((!myTextValue.isEmpty()) && hasVariable())
+  if (hasVariable())
     return;
 
-  ModuleBase_DoubleSpinBox::stepBy(steps);
-}
-
-/*!
- \brief Connect signals and slots.
- */
-void ModuleBase_ParamSpinBox::connectSignalsAndSlots()
-{
-  connect(this, SIGNAL(valueChanged(const QString&)),
-          this, SLOT(onTextChanged(const QString&)));
+  double aVal = lineEdit()->text().toDouble();
+  aVal += steps * mySingleStep;
+  setValue(aVal);
+  QAbstractSpinBox::stepBy(steps);
 }
 
-void ModuleBase_ParamSpinBox::onTextChanged(const QString& text)
+void ModuleBase_ParamSpinBox::onTextChanged(const QString& theText)
 {
-  myTextValue = text;
-  emit textChanged(text);
+  myIsEquation = hasVariable(theText);
+  emit textChanged(theText);
 }
 
-double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
-{
-  if (!hasVariable(theText))
-    return ModuleBase_DoubleSpinBox::valueFromText(theText);
-
-  // small hack: return hash of the string to initiate valuesChanged signal
-  return qHash(theText);
-}
 
-QString ModuleBase_ParamSpinBox::textFromValue (double theValue) const
-{
-  if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){
-    return myTextValue;
-  }
-  return ModuleBase_DoubleSpinBox::textFromValue(theValue);
-}
+///*!
+// \brief Connect signals and slots.
+// */
+//void ModuleBase_ParamSpinBox::connectSignalsAndSlots()
+//{
+//  connect(this, SIGNAL(valueChanged(const QString&)),
+//          this, SLOT(onTextChanged(const QString&)));
+//}
+//
+//void ModuleBase_ParamSpinBox::onTextChanged(const QString& text)
+//{
+//  myTextValue = text;
+//  emit textChanged(text);
+//}
+//
+//double ModuleBase_ParamSpinBox::valueFromText(const QString& theText) const
+//{
+//  if (!hasVariable(theText))
+//    return ModuleBase_DoubleSpinBox::valueFromText(theText);
+//
+//  // small hack: return hash of the string to initiate valuesChanged signal
+//  return qHash(theText);
+//}
+//
+//QString ModuleBase_ParamSpinBox::textFromValue (double theValue) const
+//{
+//  if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)){
+//    return myTextValue;
+//  }
+//  return ModuleBase_DoubleSpinBox::textFromValue(theValue);
+//}
 
 /*!
  \brief This function is used to determine whether input is valid.
@@ -139,13 +156,9 @@ QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) cons
 {
   // Trying to interpret the current input text as a numeric value
   if (!hasVariable(str))
-    return ModuleBase_DoubleSpinBox::validate(str, pos);
+    return myValidator->validate(str, pos);
 
-  QValidator::State res = QValidator::Invalid;
-  if (isAcceptVariables()) {
-    res = QValidator::Acceptable;
-  }
-  return res;
+  return isAcceptVariables() ? QValidator::Acceptable : QValidator::Invalid;
 }
 
 /*!
@@ -154,13 +167,25 @@ QValidator::State ModuleBase_ParamSpinBox::validate(QString& str, int& pos) cons
 
  The new value is ignored if the spinbox has a variable.
  */
-void ModuleBase_ParamSpinBox::setValue(const double value)
+void ModuleBase_ParamSpinBox::setValue(double value)
 {
-  if (hasVariable())
-    return;
+  myIsEquation = false;
+  double aVal = value;
+  if (aVal < myMinimum)
+    aVal = myMinimum;
+  else if (aVal > myMaximum)
+    aVal = myMaximum;
+  QString aText = QString::number(aVal, 'g', myDecimals);
+  lineEdit()->setText(aText);
+  emit textChanged(aText);
+}
 
-  myTextValue = ModuleBase_DoubleSpinBox::textFromValue(value);
-  ModuleBase_DoubleSpinBox::setValue(value);
+double ModuleBase_ParamSpinBox::value() const
+{
+  //if (myIsEquation) {
+
+  //}
+  return lineEdit()->text().toDouble();
 }
 
 /*!
@@ -169,8 +194,11 @@ void ModuleBase_ParamSpinBox::setValue(const double value)
  */
 void ModuleBase_ParamSpinBox::setText(const QString& value)
 {
-  myTextValue = value;
-  lineEdit()->setText(value);
+  myIsEquation = hasVariable(value);
+  if (myAcceptVariables && myIsEquation) {
+    lineEdit()->setText(value);
+    emit textChanged(value);
+  }
 }
 
 /*!
@@ -181,6 +209,9 @@ void ModuleBase_ParamSpinBox::setText(const QString& value)
 void ModuleBase_ParamSpinBox::setAcceptVariables(const bool flag)
 {
   myAcceptVariables = flag;
+  if ((!myAcceptVariables) && myIsEquation) {
+    setValue(0);
+  }
 }
 
 /*!
@@ -193,100 +224,161 @@ bool ModuleBase_ParamSpinBox::isAcceptVariables() const
 
 bool ModuleBase_ParamSpinBox::hasVariable() const
 {
-  if (myTextValue.isEmpty())
-    return false;
-  return hasVariable(myTextValue);
+  return myIsEquation;
 }
 
 bool ModuleBase_ParamSpinBox::hasVariable(const QString& theText) const
 {
-  //const QString aDigitPattern = QString("[-+]?[0-9]*[%1]?[0-9]*([eE][-+]?[0-9]+)?");
-
-  //bool aHasDigit = false;
-  //{
-  //  QRegExp varNameMask(aDigitPattern.arg("."));
-  //  aHasDigit = varNameMask.exactMatch(theText);
-  //}
-  //if (!aHasDigit)
-  //{
-  //  QRegExp varNameMask(aDigitPattern.arg(","));
-  //  aHasDigit = varNameMask.exactMatch(theText);
-  //}
   bool isDouble = false;
   QLocale::c().toDouble(theText, &isDouble);
-
-//  theText.toDouble(&isDouble);
-//  if (isDouble) {
-//    QLocale aLoc; // create default locale
-//    QChar aDecPnt = aLoc.decimalPoint();
-//    if (aDecPnt == '.')
-//      isDouble = theText.contains(aDecPnt) || (!theText.contains(','));
-//    else if (aDecPnt == ',')
-//      isDouble = theText.contains(aDecPnt) || (!theText.contains('.'));
-//  }
   return !isDouble;
 }
 
+///*!
+// \brief This function is used to determine whether input is valid.
+// \return validating operation result
+// */
+//ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
+//                                                                double& theValue) const
+//{
+//  if (hasVariable() && !findVariable(theText, theValue)) {
+//    bool ok = false;
+//    theValue = locale().toDouble(theText, &ok);
+//    if (!ok) {
+//      return NoVariable;
+//    }
+//  }
+//  if (!checkRange(theValue)) {
+//    return Invalid;
+//  }
+//
+//  return Acceptable;
+//}
+//
+///*!
+// \brief This function is used to check that string value lies within predefined range.
+// \return check status
+// */
+//bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
+//{
+//  return theValue >= minimum() && theValue <= maximum();
+//}
+//
+///*!
+// \brief This function is used to determine whether input is a variable name and to get its value.
+// \return status of search operation
+// */
+//bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
+//                                           double& outValue) const
+//{
+//  ResultParameterPtr aParam;
+//  return ModelAPI_Tools::findVariable(FeaturePtr(), theName.toStdString(), outValue, aParam);
+//}
+
 /*!
- \brief This function is used to determine whether input is valid.
- \return validating operation result
+ \brief This function is called when the spinbox receives key press event.
  */
-ModuleBase_ParamSpinBox::State ModuleBase_ParamSpinBox::isValid(const QString& theText,
-                                                                double& theValue) const
+void ModuleBase_ParamSpinBox::keyReleaseEvent(QKeyEvent* e)
 {
-  if (hasVariable() && !findVariable(theText, theValue)) {
-    bool ok = false;
-    theValue = locale().toDouble(theText, &ok);
-    if (!ok) {
-      return NoVariable;
+  switch (e->key()) {
+  case Qt::Key_Return:
+  case Qt::Key_Enter:
+    if (myCompleter->popup()->isVisible()) {
+      myCompleter->popup()->hide();
+      myIsEquation = true;
     }
+    emit textChanged(lineEdit()->text());
+    return;
+  case Qt::Key_Space:
+    if (e->modifiers() & Qt::ControlModifier) {
+      myCompletePos = lineEdit()->cursorPosition();
+      int aStart, aEnd;
+      QString aPrefix = getPrefix(aStart, aEnd);
+      myCompleter->setCompletionPrefix(aPrefix);
+      myCompleter->complete();
+    }
+    break;
+  default:
+    QAbstractSpinBox::keyReleaseEvent(e);
   }
-  if (!checkRange(theValue)) {
-    return Invalid;
-  }
-
-  return Acceptable;
 }
 
-/*!
- \brief This function is used to check that string value lies within predefined range.
- \return check status
- */
-bool ModuleBase_ParamSpinBox::checkRange(const double theValue) const
+QString ModuleBase_ParamSpinBox::getPrefix(int& theStart, int& theEnd) const
 {
-  return theValue >= minimum() && theValue <= maximum();
+  QString aPrefix;
+  QString aText = lineEdit()->text();
+  theStart = theEnd = myCompletePos;
+  const int aLen = aText.length();
+  if (aLen > 0) {
+    if (myCompletePos > 0) {
+      int aLastChar = myCompletePos - 1;
+      QChar aChar = aText.at(aLastChar);
+      while (aChar.isLetter() || aChar.isDigit()) {
+        aPrefix.prepend(aText.at(aLastChar));
+        aLastChar--;
+        if (aLastChar < 0)
+          break;
+        aChar = aText.at(aLastChar);
+      }
+      theStart = aLastChar + 1;
+    }
+    if (myCompletePos < aLen) {
+      int aLastChar = myCompletePos;
+      QChar aChar = aText.at(aLastChar);
+      while (aChar.isLetter() || aChar.isDigit()) {
+        aPrefix.append(aText.at(aLastChar));
+        aLastChar++;
+        if (aLastChar >= aLen)
+          break;
+        aChar = aText.at(aLastChar);
+      }
+      theEnd = aLastChar;
+    }
+  }
+  return aPrefix;
 }
 
-/*!
- \brief This function is used to determine whether input is a variable name and to get its value.
- \return status of search operation
- */
-bool ModuleBase_ParamSpinBox::findVariable(const QString& theName,
-                                           double& outValue) const
+
+void ModuleBase_ParamSpinBox::insertCompletion(const QString& theText)
 {
-  ResultParameterPtr aParam;
-  return ModelAPI_Tools::findVariable(FeaturePtr(), theName.toStdString(), outValue, aParam);
+  QString aText = lineEdit()->text();
+  int aStart, aEnd;
+  QString aPrefix = getPrefix(aStart, aEnd);
+
+  QString aResult;
+  int aPrefLen = aPrefix.length();
+  if (aPrefLen == 0)
+    aResult = aText.insert(myCompletePos, theText);
+  else {
+    aResult = aText.left(aStart) + theText + aText.right(aText.length() - aEnd);
+  }
+  lineEdit()->setText(aResult);
+  myIsEquation = true;
+
+  qDebug("### aPos=%i", myCompletePos);
+  qDebug("### text=%s", qPrintable(aText));
+  qDebug("### prefix=%s", qPrintable(aPrefix));
+  qDebug("### result=%s", qPrintable(aResult));
 }
 
-/*!
- \brief This function is called when the spinbox receives key press event.
- */
-//void ModuleBase_ParamSpinBox::keyPressEvent(QKeyEvent* e)
+
+///*!
+// \brief This function is called when the spinbox receives show event.
+// */
+//void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
 //{
-//  if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
-//    QWidget::keyPressEvent(e);
-//  } else {
-//    ModuleBase_DoubleSpinBox::keyPressEvent(e);
+//  ModuleBase_DoubleSpinBox::showEvent(theEvent);
+//  if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) {
+//    setText(myTextValue);
 //  }
 //}
 
-/*!
- \brief This function is called when the spinbox receives show event.
- */
-void ModuleBase_ParamSpinBox::showEvent(QShowEvent* theEvent)
+void ModuleBase_ParamSpinBox::setValueEnabled(bool theEnable)
 {
-  ModuleBase_DoubleSpinBox::showEvent(theEvent);
-  if ((!myTextValue.isEmpty()) && hasVariable(myTextValue)) {
-    setText(myTextValue);
-  }
+  setReadOnly(!theEnable);
+
+  QPalette aPal = palette();
+  aPal.setColor(QPalette::All, QPalette::Base,
+    theEnable ? myEnabledBaseColor : aPal.color(QPalette::Disabled, QPalette::Base));
+  setPalette(aPal);
 }
index a8cfe4407c597376d92eb0b4a7edae8b978ddea5..16ab6378909e0f320d7fa08f9ee18abe73e62ad2 100644 (file)
@@ -23,9 +23,9 @@
 
 #include "ModuleBase.h"
 
-#include <ModuleBase_DoubleSpinBox.h>
-
+#include <QAbstractSpinBox>
 #include <QValidator>
+#include <QLineEdit>
 
 class QStringListModel;
 class QCompleter;
@@ -34,7 +34,7 @@ class QCompleter;
 * \ingroup GUI
 * An extension of a double spin box which let to use parameters and expressions for value definition
 */
-class MODULEBASE_EXPORT ModuleBase_ParamSpinBox : public ModuleBase_DoubleSpinBox
+class MODULEBASE_EXPORT ModuleBase_ParamSpinBox : public QAbstractSpinBox
 {
   Q_OBJECT
 
@@ -51,7 +51,7 @@ public:
    \param theParent a parent object
    \param thePrecision a precision of values display
    */
-  explicit ModuleBase_ParamSpinBox( QWidget* theParent = 0, int thePrecision = -12 );
+  ModuleBase_ParamSpinBox( QWidget* theParent = 0, int thePrecision = -12 );
 
   /// Set list of completion strings
   void setCompletionList(QStringList&);
@@ -60,15 +60,19 @@ public:
 
   virtual void stepBy(int);
 
-  virtual double valueFromText(const QString&) const;
-  virtual QString textFromValue (double value) const;
+//  virtual double valueFromText(const QString&) const;
+//  virtual QString textFromValue (double value) const;
 
   virtual QValidator::State validate(QString&, int&) const;
 
   virtual void setValue(double);
 
+  double value() const;
+
   virtual void setText(const QString&);
 
+  QString text() const { return lineEdit()->text(); }
+
   /// Set a flag about accepted variable
   void setAcceptVariables(const bool);
 
@@ -78,42 +82,81 @@ public:
   /// Returns True if the input value contains variable
   bool hasVariable() const;
 
+  double minimum() const { return myMinimum; }
+  double maximum() const { return myMaximum; }
+
+  void setMinimum(double theMin) { myMinimum = theMin; myValidator->setBottom(theMin); }
+  void setMaximum(double theMax) { myMaximum = theMax; myValidator->setTop(theMax); }
+
+  int decimals() const { return myDecimals; }
+  void setDecimals(int thePrecision) { myDecimals = thePrecision; }
+
+  double singleStep() const { return mySingleStep; }
+  void setSingleStep(double theStep) { mySingleStep = theStep; }
+
+  void setValueEnabled(bool theEnable);
+
 protected:
+  virtual void keyReleaseEvent(QKeyEvent *event);
+
+  virtual StepEnabled stepEnabled() const { return StepUpEnabled | StepDownEnabled; }
+
    /// Returns True if the given text contains variable
    /// \param theText a text string
   bool hasVariable(const QString& theText) const;
 
-  /// Returns state of the control
-  State isValid(const QString&, double&) const;
-
-  /// Returns True if the given value is within min and max of the control
-  bool checkRange(const double) const;
-
-  /// Finds a variable by its name. Returns true in success
-  /// \param theName a name of variable
-  /// \param outValue an output value of the variable
-  bool findVariable(const QString& theName, double& outValue) const;
+//  /// Returns state of the control
+//  State isValid(const QString&, double&) const;
+//
+//  /// Returns True if the given value is within min and max of the control
+//  bool checkRange(const double) const;
+//
+//  /// Finds a variable by its name. Returns true in success
+//  /// \param theName a name of variable
+//  /// \param outValue an output value of the variable
+//  bool findVariable(const QString& theName, double& outValue) const;
 
 signals:
-  void textChanged(const QString& theText);
+  void textChanged(const QString&);
+
+// protected:
+//  virtual void showEvent(QShowEvent*);
+//
+// protected slots:
+//   /// A slot called on text change
+//  void onTextChanged(const QString&);
+//
+// private:
+//  void connectSignalsAndSlots();
 
- protected:
-  virtual void showEvent(QShowEvent*);
+private slots:
+  void insertCompletion(const QString&);
 
- protected slots:
-   /// A slot called on text change
   void onTextChanged(const QString&);
 
- private:
-  void connectSignalsAndSlots();
+private:
+  QString getPrefix(int& theStart, int& theEnd) const;
 
- private:
-  QString myTextValue;
 
+  bool myIsEquation;
   bool myAcceptVariables;
 
   QStringListModel* myCompleterModel;
   QCompleter* myCompleter;
+  int myPrecision;
+
+  double myMinimum;
+  double myMaximum;
+
+  int myDecimals;
+  int myCompletePos;
+
+  double mySingleStep;
+
+  /// Cashed color of active base palette
+  QColor myEnabledBaseColor;
+
+  QDoubleValidator* myValidator;
 };
 
 #endif
index 3b5b8b455cf0633464499acd892207f194b2d523..9a66c6b51e4116689b612c53708c009c7d73400f 100644 (file)
@@ -46,7 +46,7 @@
 #include <iostream>
 #endif
 
-//#define DEBUG_COMPLETE_WITH_PARAMETERS
+#define DEBUG_COMPLETE_WITH_PARAMETERS
 
 ModuleBase_WidgetDoubleValue::ModuleBase_WidgetDoubleValue(QWidget* theParent,
                                                            const Config_WidgetAPI* theData)
index 5da885e1333d502f66d661a4eda3275dc316a790..b9099882564f192633f3a7e244af3347587748a7 100644 (file)
@@ -103,9 +103,7 @@ 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);
-  }
+  performCompletion(aPrefix);
 }
 
 void ExpressionEditor::performCompletion(const QString& theCompletionPrefix)