Salome HOME
Merge remote-tracking branch 'remotes/origin/master' into SolveSpace
authorazv <azv@opencascade.com>
Fri, 23 May 2014 11:44:12 +0000 (15:44 +0400)
committerazv <azv@opencascade.com>
Fri, 23 May 2014 11:44:12 +0000 (15:44 +0400)
59 files changed:
linux_env.sh
src/Config/Config_FeatureMessage.cpp
src/Config/Config_FeatureMessage.h
src/Config/Config_FeatureReader.cpp
src/Config/Config_FeatureReader.h
src/Config/Config_Keywords.h
src/Config/Config_ModuleReader.cpp
src/ConstructionPlugin/plugin-Construction.xml
src/Events/CMakeLists.txt
src/Events/Events_Loop.cpp
src/Events/Events_Loop.h
src/Events/Events_MessageGroup.h [new file with mode: 0644]
src/Model/Model_Data.cpp
src/Model/Model_Document.cpp
src/Model/Model_Document.h
src/Model/Model_Events.cpp
src/Model/Model_Events.h
src/Model/Model_Object.cpp
src/Model/Model_Object.h
src/Model/Model_PluginManager.cpp
src/Model/Model_PluginManager.h
src/ModelAPI/ModelAPI_Feature.h
src/ModelAPI/ModelAPI_PluginManager.cpp
src/ModuleBase/CMakeLists.txt
src/ModuleBase/ModuleBase_Operation.cpp
src/ModuleBase/ModuleBase_Operation.h
src/ModuleBase/ModuleBase_WidgetPoint2D.cpp
src/PartSet/PartSet_Listener.cpp
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_OperationEditLine.cpp
src/PartSet/PartSet_OperationEditLine.h
src/PartSet/PartSet_OperationSketch.cpp
src/PartSet/PartSet_OperationSketch.h
src/PartSet/PartSet_OperationSketchBase.cpp
src/PartSet/PartSet_OperationSketchBase.h
src/PartSet/PartSet_OperationSketchLine.cpp
src/PartSet/PartSet_OperationSketchLine.h
src/PartSetPlugin/plugin-PartSet.xml
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/XGUI/XGUI_ActionsMgr.cpp
src/XGUI/XGUI_ActionsMgr.h
src/XGUI/XGUI_Command.cpp
src/XGUI/XGUI_Command.h
src/XGUI/XGUI_ContextMenuMgr.cpp
src/XGUI/XGUI_Displayer.cpp
src/XGUI/XGUI_Displayer.h
src/XGUI/XGUI_DocumentDataModel.cpp
src/XGUI/XGUI_MainWindow.cpp
src/XGUI/XGUI_MainWindow.h
src/XGUI/XGUI_ObjectsBrowser.cpp
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_OperationMgr.h
src/XGUI/XGUI_PartDataModel.cpp
src/XGUI/XGUI_PropertyPanel.cpp
src/XGUI/XGUI_Viewer.cpp
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_Workshop.h

index 4466e33553acbf71c2c99283360fcc87b4ab907c..5e0a7f8ab22616a8aa4ffda2d80e40a5e1a43b6e 100644 (file)
@@ -86,7 +86,10 @@ export CSF_SHMessage=${CAS_ROOT_DIR}/src/SHMessage
 export CSF_XSMessage=${CAS_ROOT_DIR}/src/XSMessage 
 # Variable for Font : 
 export CSF_MDTVFontDirectory=${CAS_ROOT_DIR}/src/FontMFT 
-export CSF_MDTVTexturesDirectory=${CAS_ROOT_DIR}/src/Textures 
+export CSF_MDTVTexturesDirectory=${CAS_ROOT_DIR}/src/Textures
+# Defaults
+export CSF_PluginDefaults=${CAS_ROOT_DIR}/src/StdResource 
+export CSF_StandardDefaults=${CAS_ROOT_DIR}/src/StdResource
 # Activation of OCCT Kernel multithreading :
 export MMGT_REENTRANT=1
 # this variable only needed for DRAWEXE
index 9408522e6a9f90c4ce1fcbead4f96ff3cf7217b8..7b0f603371f6c7823df85b0e33fb086efefe7322 100644 (file)
@@ -14,6 +14,11 @@ Config_FeatureMessage::Config_FeatureMessage(const Events_ID theId, const void*
 
   myGroupId = "";
   myWorkbenchId = "";
+  myPluginLibrary = "";
+
+  myInternal = false;
+  myUseInput = false;
+  myNestedFeatures = "";
 }
 
 const std::string& Config_FeatureMessage::icon() const
@@ -101,11 +106,21 @@ bool Config_FeatureMessage::isUseInput() const
   return myUseInput;
 }
 
+bool Config_FeatureMessage::isInternal() const
+{
+  return myInternal;
+}
+
 void Config_FeatureMessage::setUseInput(bool isUseInput)
 {
   myUseInput = isUseInput;
 }
 
+void Config_FeatureMessage::setInternal(bool isInternal)
+{
+  myInternal = isInternal;
+}
+
 const std::string& Config_FeatureMessage::nestedFeatures() const
 {
   return myNestedFeatures;
index 99116d707e0f9be53ace04483b9d9c3b627d5dc8..9328e0690775df4e1fb7bdc44ba625477bb3a846 100644 (file)
@@ -27,6 +27,7 @@ class Config_FeatureMessage: public Events_Message
   std::string myPluginLibrary;  //Name of feature's library\r
 \r
   bool myUseInput; //Action is being checked until user commit the operation\r
+  bool myInternal; //Internal feature without GUI representation\r
   std::string myNestedFeatures;\r
 \r
 public:\r
@@ -45,6 +46,7 @@ public:
   CONFIG_EXPORT const std::string& pluginLibrary() const;\r
   CONFIG_EXPORT const std::string& nestedFeatures() const;\r
   CONFIG_EXPORT bool isUseInput() const;\r
+  CONFIG_EXPORT bool isInternal() const;\r
 \r
   CONFIG_EXPORT void setIcon(const std::string& icon);\r
   CONFIG_EXPORT void setId(const std::string& id);\r
@@ -56,6 +58,7 @@ public:
   CONFIG_EXPORT void setPluginLibrary(const std::string& thePluginLibrary);\r
   CONFIG_EXPORT void setNestedFeatures(const std::string& theNestedFeatures);\r
   CONFIG_EXPORT void setUseInput(bool isUseInput);\r
+  CONFIG_EXPORT void setInternal(bool isInternal);\r
 };\r
 \r
 #endif // CONFIG_MESSAGE_H\r
index 78e485e912d1b5e294d160c57b380e57273aff39..6e6bbb85f6f7abdbb656619f58b35bce114f308c 100644 (file)
@@ -17,6 +17,7 @@
 #include <libxml/xmlstring.h>
 
 #include <string>
+#include <algorithm>
 
 #ifdef _DEBUG
 #include <iostream>
@@ -72,12 +73,28 @@ bool Config_FeatureReader::processChildren(xmlNodePtr theNode)
 void Config_FeatureReader::fillFeature(xmlNodePtr theRoot, Config_FeatureMessage& outFtMessage)
 {
   outFtMessage.setId(getProperty(theRoot, _ID));
+  outFtMessage.setPluginLibrary(myLibraryName);
+  outFtMessage.setNestedFeatures(getProperty(theRoot, FEATURE_NESTED));
+  bool isFtInternal = isInternalFeature(theRoot);
+  outFtMessage.setInternal(isFtInternal);
+  if(isFtInternal) {
+    //Internal feature has no visual representation.
+    return;
+  }
   outFtMessage.setText(getProperty(theRoot, FEATURE_TEXT));
   outFtMessage.setTooltip(getProperty(theRoot, FEATURE_TOOLTIP));
   outFtMessage.setIcon(getProperty(theRoot, FEATURE_ICON));
   outFtMessage.setKeysequence(getProperty(theRoot, FEATURE_KEYSEQUENCE));
   outFtMessage.setGroupId(myLastGroup);
   outFtMessage.setWorkbenchId(myLastWorkbench);
-  outFtMessage.setPluginLibrary(myLibraryName);
-  outFtMessage.setNestedFeatures(getProperty(theRoot, FEATURE_NESTED));
+}
+
+bool Config_FeatureReader::isInternalFeature(xmlNodePtr theRoot)
+{
+  std::string prop = getProperty(theRoot, FEATURE_INTERNAL);
+  std::transform(prop.begin(), prop.end(), prop.begin(), ::tolower);
+  if(prop.empty() || prop == "false" || prop == "0") {
+    return false;
+  }
+  return true;
 }
index e4e7c63db8590674f4feb7c61fe0688083a1c7e8..1add8438d464da227b792435783df3907af2ce2c 100644 (file)
@@ -31,6 +31,7 @@ protected:
   bool processChildren(xmlNodePtr aNode);
 
   void fillFeature(xmlNodePtr theRoot, Config_FeatureMessage& outFeatureMessage);
+  bool isInternalFeature(xmlNodePtr theRoot);
 
 private:
   std::string myLastWorkbench;
index 281248f858314326cc871cef581e3d655f054355..2056a658bff44d66ffcb4630482371009760d120 100644 (file)
@@ -34,11 +34,12 @@ const static char* _ID = "id";
 //const static char* WORKBENCH_ID = "id";
 //const static char* GROUP_ID = "id";
 //const static char* FEATURE_ID = "id";
-const static char* FEATURE_TEXT = "text";
+const static char* FEATURE_TEXT = "title";
 const static char* FEATURE_TOOLTIP = "tooltip";
 const static char* FEATURE_ICON = "icon";
 const static char* FEATURE_KEYSEQUENCE = "keysequence";
 const static char* FEATURE_NESTED = "nested";
+const static char* FEATURE_INTERNAL = "internal";
 const static char* SOURCE_FILE = "path";
 
 
index e6fdeffdeb9414aa9b37c72e6b8191c7b611fd45..c533e3e3e92b69565f2a5494ee1bbdb9aeaef5d6 100644 (file)
@@ -84,9 +84,6 @@ std::list<std::string> Config_ModuleReader::importPlugin(const std::string& theP
 
 void Config_ModuleReader::loadLibrary(const std::string theLibName)
 {
-#ifdef _DEBUG
-  std::cout << "Config_ModuleReader::loading library... "  << theLibName.c_str() << std::endl;
-#endif
   std::string aFileName = library(theLibName);
   if (aFileName.empty())
     return;
index 912d04e0ca636ce6e2acd9dfd7598ccde8300029..8e86996877b49bbee33942038b5b299bee4152fb 100644 (file)
@@ -1,11 +1,11 @@
 <plugin>
   <workbench id="Construction">
     <group id="Basic">
-      <feature id="Point" text="Point" tooltip="Create a new point" icon=":icons/point.png">
+      <feature id="Point" title="Point" tooltip="Create a new point" icon=":icons/point.png">
         <source path="point_widget.xml"/>
       </feature>
-      <feature id="Axis" text="Axis" tooltip="Create a new axis" icon=":icons/axis.png" keysequence=""/>
-      <feature id="Plane" text="Plane" tooltip="Create a new plane" icon=":icons/plane.png" keysequence=""/>
+      <feature id="Axis" title="Axis" tooltip="Create a new axis" icon=":icons/axis.png" keysequence="" internal="true"/>
+      <feature id="Plane" title="Plane" tooltip="Create a new plane" icon=":icons/plane.png" keysequence="" internal="true"/>
     </group>
   </workbench>  
 </plugin>
index 89a27f31c8a51a7bfc3b92920942925b95d0a7c2..af4155f4268119e19d78b8f3a0241823fb22e9de 100644 (file)
@@ -3,6 +3,7 @@ INCLUDE(Common)
 SET(PROJECT_HEADERS
     Events.h
     Events_Message.h
+    Events_MessageGroup.h 
     Events_Listener.h
     Events_Loop.h
     Events_Error.h
index 6c8bb476070ed381339cef59b6a08774678a1f95..40917a64f710c5b7d7c815fb3e8f62313ed0bd0d 100644 (file)
@@ -3,6 +3,7 @@
 // Author:     Mikhail PONIKAROV
 
 #include <Events_Loop.h>
+#include <Events_MessageGroup.h>
 
 #include <string>
 #include <cstring>
@@ -32,9 +33,24 @@ Events_ID Events_Loop::eventByName(const char* theName)
   return Events_ID(aResult);
 }
 
-void Events_Loop::send(Events_Message& theMessage)
+void Events_Loop::send(Events_Message& theMessage, bool isGroup)
 {
-  // TO DO: make it in thread and wit husage of semaphores
+  // if it is grouped message, just accumulate it
+  if (isGroup) {
+    Events_MessageGroup* aGroup = dynamic_cast<Events_MessageGroup*>(&theMessage);
+    if (aGroup) {
+      std::map<char*, Events_MessageGroup*>::iterator aMyGroup = 
+        myGroups.find(aGroup->eventID().eventText());
+      if (aMyGroup == myGroups.end()) { // create a new group of messages for accumulation
+        myGroups[aGroup->eventID().eventText()] = aGroup->newEmpty();
+        aMyGroup = myGroups.find(aGroup->eventID().eventText());
+      }
+      aMyGroup->second->Join(*aGroup);
+      return;
+    }
+  }
+
+  // TO DO: make it in thread and with usage of semaphores
 
   map<char*, map<void*, list<Events_Listener*> > >::iterator aFindID = myListeners.find(
       theMessage.eventID().eventText());
@@ -80,3 +96,15 @@ void Events_Loop::registerListener(Events_Listener* theListener, const Events_ID
 
   aListeners.push_back(theListener);
 }
+
+void Events_Loop::flush(const Events_ID& theID)
+{
+  std::map<char*, Events_MessageGroup*>::iterator aMyGroup = 
+    myGroups.find(theID.eventText());
+  if (aMyGroup != myGroups.end()) { // really sends
+    Events_MessageGroup* aGroup = aMyGroup->second;
+    myGroups.erase(aMyGroup);
+    send(*aGroup, false);
+    delete aGroup;
+  }
+}
index 893ecb1994de3a38eb47581ffd950b128ff32c0b..d19dd4d4a39cee1fa832018961e49ea5b8702309 100644 (file)
@@ -11,6 +11,8 @@
 #include <map>
 #include <list>
 
+class Events_MessageGroup;
+
 /**\class Events_Lopp
  * \ingroup EventsLoop
  * \brief Base class that manages the receiving and sending of all
  * control back immideately.
  */
 class Events_Loop {
+  /// map from event ID to sender pointer to listeners that must be called for this
   std::map<char*, std::map<void*, std::list<Events_Listener*> > >
-    myListeners; ///< map from event ID to sender pointer to listeners that must be called for this
+    myListeners;
+
+  /// map from event ID to groupped messages (accumulated on flush)
+  std::map<char*, Events_MessageGroup*> myGroups;
 
   //! The empty constructor, will be called at startup of the application, only once
   Events_Loop() {};
@@ -35,12 +41,16 @@ public:
   EVENTS_EXPORT static Events_ID eventByName(const char* theName);
 
   //! Allows to send an event
-  EVENTS_EXPORT void send(Events_Message& theMessage);
+  //! \param isGroup is true for grouping messages if possible
+  EVENTS_EXPORT void send(Events_Message& theMessage, bool isGroup = true);
 
   //! Registers (or adds if such listener is already registered) a listener 
   //! that will be called on the event and from the defined sender
   EVENTS_EXPORT void registerListener(Events_Listener* theListener, const Events_ID theID, 
     void* theSender = 0);
+
+  //! Initializes sending of a group-message by the given ID
+  EVENTS_EXPORT void flush(const Events_ID& theID);
 };
 
 #endif
diff --git a/src/Events/Events_MessageGroup.h b/src/Events/Events_MessageGroup.h
new file mode 100644 (file)
index 0000000..b95f64d
--- /dev/null
@@ -0,0 +1,33 @@
+// File:       Events_MessageGroup.hxx
+// Created:    Thu Mar 13 2014
+// Author:     Mikhail PONIKAROV
+
+#ifndef Events_MessageGroup_HeaderFile
+#define Events_MessageGroup_HeaderFile
+
+#include <Events_Message.h>
+
+/**\class Events_Message
+ * \ingroup EventsLoop
+ * \brief Message that allows to group messages and send them later as a group of messages.
+ *
+ * Loop detects such messages and accumulates them without sending. On "flush" loop sends it
+ * as a group-message.
+ */
+class EVENTS_EXPORT Events_MessageGroup : public Events_Message {
+
+public:
+
+  //! Creates the message
+  Events_MessageGroup(const Events_ID theID, const void* theSender = 0)
+    : Events_Message(theID, theSender) {}
+  //! do nothing in the destructor yet
+  virtual ~Events_MessageGroup() {}
+
+  //! Creates a new empty group (to store it in the loop before flush)
+  virtual Events_MessageGroup* newEmpty() = 0;
+  //! Allows to join the given message with the current one
+  virtual void Join(Events_MessageGroup& theJoined) = 0;
+};
+
+#endif
index e6c5c02f2e7311aefacbe361f9733014634c9cc4..03effc8e3c9058cfb99083ea373862931075cde2 100644 (file)
@@ -12,6 +12,8 @@
 #include <GeomData_Point2D.h>
 #include <GeomData_Dir.h>
 #include <TDataStd_Name.hxx>
+#include "Model_Events.h"
+#include <Events_Loop.h>
 
 using namespace std;
 
@@ -35,6 +37,9 @@ string Model_Data::getName()
 void Model_Data::setName(string theName)
 {
   TDataStd_Name::Set(myLab, theName.c_str());
+  static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
+  Model_FeatureUpdatedMessage aMsg(myFeature, anEvent);
+  Events_Loop::loop()->send(aMsg, false);
 }
 
 void Model_Data::addAttribute(string theID, string theAttrType)
index 37f1a8673a860b8e35152136df6729f400b62037..6343d8b7b7d837fd35d5348701a136bcc9429089 100644 (file)
@@ -161,6 +161,11 @@ bool Model_Document::save(const char* theFileName)
 
 void Model_Document::close()
 {
+  boost::shared_ptr<ModelAPI_PluginManager> aPM = Model_PluginManager::get();
+  if (this != aPM->rootDocument().get() && 
+      this == aPM->currentDocument().get()) {
+    aPM->setCurrentDocument(aPM->rootDocument());
+  }
   // close all subs
   set<string>::iterator aSubIter = mySubs.begin();
   for(; aSubIter != mySubs.end(); aSubIter++)
@@ -174,12 +179,15 @@ void Model_Document::close()
 
 void Model_Document::startOperation()
 {
-  // check is it nested or not
-  if (myDoc->HasOpenCommand()) {
-    myNestedStart = myTransactionsAfterSave;
+  if (myDoc->HasOpenCommand()) { // start of nested command
+    if (myNestedNum == -1) {
+      myNestedNum = 0;
+      myDoc->InitDeltaCompaction();
+    }
+    myDoc->NewCommand();
+  } else { // start of simple command
+    myDoc->NewCommand();
   }
-  // new command for this
-  myDoc->NewCommand();
   // new command for all subs
   set<string>::iterator aSubIter = mySubs.begin();
   for(; aSubIter != mySubs.end(); aSubIter++)
@@ -188,11 +196,31 @@ void Model_Document::startOperation()
 
 void Model_Document::finishOperation()
 {
-  if (myNestedStart > myTransactionsAfterSave) // this nested transaction is owervritten
-    myNestedStart = 0;
-  // returns false if delta is empty and no transaction was made
-  myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand();
-  myTransactionsAfterSave++;
+  // just to be sure that everybody knows that changes were performed
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_DELETED));
+
+  if (myNestedNum != -1) // this nested transaction is owervritten
+    myNestedNum++;
+  if (!myDoc->HasOpenCommand()) {
+    if (myNestedNum != -1) {
+      myNestedNum -= 2; // one is just incremented before, one is left (and not empty!)
+      while(myNestedNum != -1) {
+        myIsEmptyTr.erase(myTransactionsAfterSave);
+        myTransactionsAfterSave--;
+        myNestedNum--;
+      }
+      myIsEmptyTr[myTransactionsAfterSave] = false;
+      myTransactionsAfterSave++;
+      myDoc->PerformDeltaCompaction();
+    }
+  } else {
+    // returns false if delta is empty and no transaction was made
+    myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand() && (myNestedNum == -1);
+    myTransactionsAfterSave++;
+  }
+
   // finish for all subs
   set<string>::iterator aSubIter = mySubs.begin();
   for(; aSubIter != mySubs.end(); aSubIter++)
@@ -201,6 +229,8 @@ void Model_Document::finishOperation()
 
 void Model_Document::abortOperation()
 {
+  if (myNestedNum == 0)
+    myNestedNum = -1;
   myDoc->AbortCommand();
   synchronizeFeatures();
   // abort for all subs
@@ -212,7 +242,7 @@ void Model_Document::abortOperation()
 bool Model_Document::isOperation()
 {
   // operation is opened for all documents: no need to check subs
-  return myDoc->HasOpenCommand() == Standard_True ;
+  return myDoc->HasOpenCommand() == Standard_True;
 }
 
 bool Model_Document::isModified()
@@ -223,7 +253,7 @@ bool Model_Document::isModified()
 
 bool Model_Document::canUndo()
 {
-  if (myDoc->GetAvailableUndos() > 0 && myNestedStart != myTransactionsAfterSave)
+  if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */)
     return true;
   // check other subs contains operation that can be undoed
   set<string>::iterator aSubIter = mySubs.begin();
@@ -236,6 +266,7 @@ bool Model_Document::canUndo()
 void Model_Document::undo()
 {
   myTransactionsAfterSave--;
+  if (myNestedNum > 0) myNestedNum--;
   if (!myIsEmptyTr[myTransactionsAfterSave])
     myDoc->Undo();
   synchronizeFeatures();
@@ -259,6 +290,7 @@ bool Model_Document::canRedo()
 
 void Model_Document::redo()
 {
+  if (myNestedNum != -1) myNestedNum++;
   if (!myIsEmptyTr[myTransactionsAfterSave])
     myDoc->Redo();
   myTransactionsAfterSave++;
@@ -349,8 +381,9 @@ static int RemoveFromRefArray(
   Handle(TDataStd_ReferenceArray) aRefs;
   if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) {
     if (aRefs->Length() == 1) { // just erase an array
-      if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0)
+      if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) {
         theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID());
+      }
       aResult = 0;
     } else { // reduce the array
       Handle(TDataStd_HLabelArray1) aNewArray = 
@@ -364,7 +397,7 @@ static int RemoveFromRefArray(
           aNewArray->SetValue(aCount, aRefs->Value(a));
         }
       }
-    aRefs->SetInternalArray(aNewArray);
+      aRefs->SetInternalArray(aNewArray);
     }
   }
   return aResult;
@@ -458,10 +491,13 @@ Model_Document::Model_Document(const std::string theID)
 {
   myDoc->SetUndoLimit(UNDO_LIMIT);
   myTransactionsAfterSave = 0;
-  myNestedStart = 0;
-  myDoc->SetNestedTransactionMode();
+  myNestedNum = -1;
+  //myDoc->SetNestedTransactionMode();
   // to have something in the document and avoid empty doc open/save problem
+  // in transaction for nesting correct working
+  myDoc->NewCommand();
   TDataStd_Integer::Set(myDoc->Main().Father(), 0);
+  myDoc->CommitCommand();
 }
 
 TDF_Label Model_Document::groupLabel(const string theGroup)
@@ -593,4 +629,11 @@ void Model_Document::synchronizeFeatures()
       aFLabIter.Next();
     }
   }
+  // after all updates, sends a message that groups of features were created or updated
+  boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
+    setCheckTransactions(false);
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_DELETED));
+  boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
+    setCheckTransactions(true);
 }
index b1945bae1eb878d7df5615b07e3ef4c6781d33c1..d8fee7e01f5a1978090b0ea29c250512ab8cfd16 100644 (file)
@@ -118,8 +118,8 @@ private:
   Handle_TDocStd_Document myDoc; ///< OCAF document
   /// number of transactions after the last "save" call, used for "IsModified" method
   int myTransactionsAfterSave;
-  /// number of myTransactionsAfterSave for the nested transaction start
-  int myNestedStart;
+  /// number of nested transactions performed (or -1 if not nested)
+  int myNestedNum;
   /// All features managed by this document (not only in history of OB)
   std::vector<boost::shared_ptr<ModelAPI_Feature> > myFeatures;
 
index cbf4859979003d74a98e762ac767ca08f87ef000..538305efb72d9270c76f0400bcee586efeba9697 100644 (file)
@@ -5,38 +5,31 @@
 #include <Model_Events.h>
 #include <Events_Loop.h>
 
-Model_FeatureDeletedMessage::Model_FeatureDeletedMessage(
-  const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
-  : Events_Message(messageId(), 0), myDoc(theDoc), myGroup(theGroup)
-
-{
-}
-
-const Events_ID Model_FeatureDeletedMessage::messageId()
-{
-  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURE_DELETED);
-  return MY_ID;
-}
-
-Model_FeaturesMovedMessage::Model_FeaturesMovedMessage()
-: Events_Message(messageId(), 0)
-{
-}
-
-const Events_ID Model_FeaturesMovedMessage::messageId()
-{
-  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURES_MOVED);
-  return MY_ID;
-}
-
-void Model_FeaturesMovedMessage::setFeatures(
-                                const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures)
-{
-  myFeatures = theFeatures;  
-}
-
-const std::list<boost::shared_ptr<ModelAPI_Feature> >& Model_FeaturesMovedMessage::features() const
-{
-  return myFeatures;
-}
-
+// DELETED methods
+//Events_MessageGroup* Model_FeatureDeletedMessage::newEmpty() {
+//  return new Model_FeatureDeletedMessage(myDoc, "");
+//}
+//
+//Model_FeatureDeletedMessage::Model_FeatureDeletedMessage(
+//  const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
+//  : Events_MessageGroup(messageId(), 0), myDoc(theDoc)
+//
+//{
+//  if (!theGroup.empty())
+//    myGroups.insert(theGroup);
+//}
+//
+//const Events_ID Model_FeatureDeletedMessage::messageId()
+//{
+//  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURE_DELETED);
+//  return MY_ID;
+//}
+//
+//void Model_FeatureDeletedMessage::Join(Events_MessageGroup& theJoined)
+//{
+//  Model_FeatureDeletedMessage* aJoined = dynamic_cast<Model_FeatureDeletedMessage*>(&theJoined);
+//  std::set<std::string>::iterator aGIter = aJoined->myGroups.begin();
+//  for(; aGIter != aJoined->myGroups.end(); aGIter++) {
+//    myGroups.insert(*aGIter);
+//  }
+//}
index c9c60b65ffd77a2be6b9fb3a2e4dc1c5a832da55..0bce1c980bc508eed36659bb9a3504a12d50e8c0 100644 (file)
@@ -6,11 +6,11 @@
 #define Model_Events_HeaderFile
 
 #include <Model.h>
-#include <Events_Message.h>
+#include <Events_MessageGroup.h>
 #include <Events_Loop.h>
 #include <boost/shared_ptr.hpp>
 #include <string>
-#include <list>
+#include <set>
 
 class ModelAPI_Feature;
 class ModelAPI_Document;
@@ -22,56 +22,88 @@ static const char * EVENT_FEATURE_UPDATED = "FeatureUpdated";
 /// Event ID that data of feature is deleted (comes with Model_FeatureDeletedMessage)
 static const char * EVENT_FEATURE_DELETED = "FeatureDeleted";
 /// Event ID that data of feature is updated (comes with Model_FeaturesMovedMessage)
-static const char * EVENT_FEATURES_MOVED = "FeaturesMoved";
+static const char * EVENT_FEATURE_MOVED = "FeaturesMoved";
 
-/// Message that feature was changed (used for Object Browser update)
-class Model_FeatureUpdatedMessage : public Events_Message {
-  boost::shared_ptr<ModelAPI_Feature> myFeature; ///< which feature is changed
+/// Message that feature was changed (used for Object Browser update): moved, updated and deleted
+class Model_FeatureUpdatedMessage : public Events_MessageGroup {
+  std::set<boost::shared_ptr<ModelAPI_Feature> > myFeatures; ///< which feature is changed
 public:
   /// sender is not important, all information is located in the feature
   Model_FeatureUpdatedMessage(
     const boost::shared_ptr<ModelAPI_Feature>& theFeature,
-    const Events_ID& theEvent) : Events_Message(theEvent, 0), myFeature(theFeature)
-  {}
+    const Events_ID& theEvent) : Events_MessageGroup(theEvent, 0)
+  {if (theFeature) myFeatures.insert(theFeature);}
 
   /// Returns the feature that has been updated
-  boost::shared_ptr<ModelAPI_Feature> feature() const {return myFeature;}
+  std::set<boost::shared_ptr<ModelAPI_Feature> > features() const {return myFeatures;}
+
+  //! Creates a new empty group (to store it in the loop before flush)
+  virtual Events_MessageGroup* newEmpty() {
+    boost::shared_ptr<ModelAPI_Feature> anEmptyFeature;
+    return new Model_FeatureUpdatedMessage(anEmptyFeature, eventID());
+  }
+
+  //! Allows to join the given message with the current one
+  virtual void Join(Events_MessageGroup& theJoined) {
+    Model_FeatureUpdatedMessage* aJoined = dynamic_cast<Model_FeatureUpdatedMessage*>(&theJoined);
+    std::set<boost::shared_ptr<ModelAPI_Feature> >::iterator aFIter = aJoined->myFeatures.begin();
+    for(; aFIter != aJoined->myFeatures.end(); aFIter++) {
+      myFeatures.insert(*aFIter);
+    }
+  }
 };
 
 /// Message that feature was deleted (used for Object Browser update)
-class Model_FeatureDeletedMessage : public Events_Message {
+class Model_FeatureDeletedMessage : public Events_MessageGroup {
   boost::shared_ptr<ModelAPI_Document> myDoc; ///< document owner of the feature
-  std::string myGroup; ///< group identifier that contained the deleted feature
+  std::set<std::string> myGroups; ///< group identifiers that contained the deleted feature
 public:
   /// creates a message by initialization of fields
-  Model_FeatureDeletedMessage(const boost::shared_ptr<ModelAPI_Document>& theDoc,
-    const std::string& theGroup);
+//  Model_FeatureDeletedMessage(const boost::shared_ptr<ModelAPI_Document>& theDoc,
+//    const std::string& theGroup);
 
   /// Returns the ID of this message (EVENT_FEATURE_DELETED)
-  static const Events_ID messageId();
+//  static const Events_ID messageId();
 
   /// Returns the feature that has been updated
   boost::shared_ptr<ModelAPI_Document> document() const {return myDoc;}
 
   /// Returns the group where the feature was deleted
-  const std::string& group() const {return myGroup;}
-};
+  const std::set<std::string >& groups() const {return myGroups;}
 
-/// Message that features were moved (used for the feature preview update)
-class Model_FeaturesMovedMessage : public Events_Message {
-  std::list<boost::shared_ptr<ModelAPI_Feature> > myFeatures; ///< which features are moved
-public:
-  /// creates a message by initialization of fields
-  MODEL_EXPORT Model_FeaturesMovedMessage();
+  //! Creates a new empty group (to store it in the loop before flush)
+//  virtual Events_MessageGroup* newEmpty();
+
+  //! Allows to join the given message with the current one
+//  virtual void Join(Events_MessageGroup& theJoined);
+
+  Events_MessageGroup* newEmpty() {
+    return new Model_FeatureDeletedMessage(myDoc, "");
+  }
+
+  Model_FeatureDeletedMessage(
+    const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
+    : Events_MessageGroup(messageId(), 0), myDoc(theDoc)
 
-  /// Returns the ID of this message (EVENT_FEATURES_MOVED)
-  static const Events_ID messageId();
+  {
+    if (!theGroup.empty())
+      myGroups.insert(theGroup);
+  }
 
-  /// Sets a list of features
-  MODEL_EXPORT void setFeatures(const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures);
+  const Events_ID messageId()
+  {
+    static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURE_DELETED);
+    return MY_ID;
+  }
 
-  /// Returns a list of features
-  MODEL_EXPORT const std::list<boost::shared_ptr<ModelAPI_Feature> >& features() const;
+  void Join(Events_MessageGroup& theJoined)
+  {
+    Model_FeatureDeletedMessage* aJoined = dynamic_cast<Model_FeatureDeletedMessage*>(&theJoined);
+    std::set<std::string>::iterator aGIter = aJoined->myGroups.begin();
+    for(; aGIter != aJoined->myGroups.end(); aGIter++) {
+      myGroups.insert(*aGIter);
+    }
+  }
 };
 
 #endif
index 9b39c6d2f2d02c339f0c1cc00860fea09ce82a00..269c547cf90b641ceeaa1ee7c912ac69d460520a 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "Model_Object.h"
 #include <TCollection_AsciiString.hxx>
+#include "Model_Events.h"
+#include <Events_Loop.h>
 
 boost::shared_ptr<ModelAPI_Feature> Model_Object::featureRef()
 {
@@ -17,7 +19,14 @@ std::string Model_Object::getName()
 
 void Model_Object::setName(std::string theName)
 {
-  myName->Set(theName.c_str());
+  if (myName->Get() != theName.c_str()) {
+    myName->Set(theName.c_str());
+    /*
+    static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
+    Model_FeatureUpdatedMessage aMsg(boost::shared_ptr<ModelAPI_Object>(this), anEvent);
+    Events_Loop::loop()->send(aMsg, false);
+    */
+  }
 }
 
 Model_Object::Model_Object(boost::shared_ptr<ModelAPI_Feature> theRef,
index 18314c04d6fd4e0c8bc337172d2547b0ecc4f612..8179d701d6d70c7032fdad2deba769ae3d72db08 100644 (file)
@@ -36,6 +36,17 @@ public:
   /// Returns to which group in the document must be added feature
   MODEL_EXPORT virtual const std::string& getGroup() {return myRef->getGroup();}
 
+  /// Returns document this feature belongs to
+  MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> document()
+  {return myRef->document();}
+
+  /// Returns true if feature refers to the same model data instance
+  MODEL_EXPORT virtual bool isSame(const boost::shared_ptr<ModelAPI_Feature>& theFeature)
+  {
+    boost::shared_ptr<Model_Object> anObj = boost::dynamic_pointer_cast<Model_Object>(theFeature);
+    return anObj && myRef == anObj->myRef;
+  }
+
   /// It is just a reference: don't init attributes
   MODEL_EXPORT virtual void initAttributes() {}
 
@@ -47,7 +58,7 @@ private:
   /// Constructor fully defines this object
   Model_Object(boost::shared_ptr<ModelAPI_Feature> theRef, Handle_TDataStd_Name theName);
 
-  friend class Model_Document;
+  friend class Model_Document;  
 };
 
 #endif
index 7a0a20d0a009958e1b4e4b1073aaefdbe5d00bf8..1a6cef9d82964e297c036547464e3240ac0bdeec 100644 (file)
@@ -8,6 +8,7 @@
 #include <Model_Data.h>
 #include <Model_Document.h>
 #include <Model_Application.h>
+#include <Model_Events.h>
 #include <Events_Loop.h>
 #include <Events_Error.h>
 #include <Config_FeatureMessage.h>
@@ -97,27 +98,35 @@ boost::shared_ptr<ModelAPI_Document> Model_PluginManager::copy(
 Model_PluginManager::Model_PluginManager()
 {
   myPluginsInfoLoaded = false;
-  //TODO(sbh): Implement static method to extract event id [SEID]
-  static Events_ID aFeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
-
+  myCheckTransactions = true;
   ModelAPI_PluginManager::SetPluginManager(boost::shared_ptr<ModelAPI_PluginManager>(this));
   // register the configuration reading listener
   Events_Loop* aLoop = Events_Loop::loop();
-  aLoop->registerListener(this, aFeatureEvent);
+  static Events_ID FeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
+  aLoop->registerListener(this, FeatureEvent);
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
 }
 
 void Model_PluginManager::processEvent(const Events_Message* theMessage)
 {
-  const Config_FeatureMessage* aMsg =
-    dynamic_cast<const Config_FeatureMessage*>(theMessage);
-  if (aMsg) {
-    // proccess the plugin info, load plugin
-    if (myPlugins.find(aMsg->id()) == myPlugins.end()) {
-      myPlugins[aMsg->id()] = aMsg->pluginLibrary();
+  static Events_ID FeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
+  if (theMessage->eventID() == FeatureEvent) {
+    const Config_FeatureMessage* aMsg =
+      dynamic_cast<const Config_FeatureMessage*>(theMessage);
+    if (aMsg) {
+      // proccess the plugin info, load plugin
+      if (myPlugins.find(aMsg->id()) == myPlugins.end()) {
+        myPlugins[aMsg->id()] = aMsg->pluginLibrary();
+      }
     }
+    // plugins information was started to load, so, it will be loaded
+    myPluginsInfoLoaded = true;
+  } else { // create/update/delete
+    if (myCheckTransactions && !rootDocument()->isOperation())
+      Events_Error::send("Modification of data structure outside of the transaction");
   }
-  // plugins information was started to load, so, it will be loaded
-  myPluginsInfoLoaded = true;
 }
 
 void Model_PluginManager::LoadPluginsInfo()
index aa230700a1dc5d44e33bd8020402a25ad5971a8a..4efef6a4cd5034c79e8ff69a405cc49b852ceb33 100644 (file)
@@ -26,6 +26,7 @@ class Model_PluginManager : public ModelAPI_PluginManager, public Events_Listene
   std::map<std::string, ModelAPI_Plugin*> myPluginObjs; ///< instances of the already plugins
   std::string myCurrentPluginName; ///< name of the plugin that must be loaded currently
   boost::shared_ptr<ModelAPI_Document> myCurrentDoc; ///< current working document
+  bool myCheckTransactions; ///< if true, generates error if document is updated outside of transaction
 public:
   /// Returns the root document of the application (that may contains sub-documents)
   MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> rootDocument();
@@ -51,6 +52,8 @@ public:
   MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> copy(
     boost::shared_ptr<ModelAPI_Document> theSource, std::string theID);
 
+  void setCheckTransactions(const bool theCheck) {myCheckTransactions = theCheck;}
+
   /// Is called only once, on startup of the application
   Model_PluginManager();
 
index dd98c597a02c7f466f9caa61a01ec77d804e5c38..bd726461ff4194ecec2da0f35d4c5d65e63e80aa 100644 (file)
@@ -56,6 +56,10 @@ public:
   MODELAPI_EXPORT virtual boost::shared_ptr<ModelAPI_Document> document()
   {return myDoc;}
 
+  /// Returns true if feature refers to the same model data instance
+  MODELAPI_EXPORT virtual bool isSame(const boost::shared_ptr<ModelAPI_Feature>& theFeature)
+  {return true;}
+
   /// To virtually destroy the fields of successors
   virtual ~ModelAPI_Feature() {}
 
index a8d497c7c6986d6146148f7d525e83c54b09374d..eb79b9d03d3a7e0c32e119be73a8b43204bc353c 100644 (file)
@@ -49,9 +49,6 @@ void ModelAPI_PluginManager::SetPluginManager(
 boost::shared_ptr<ModelAPI_PluginManager> ModelAPI_PluginManager::get()
 {
   if (!MY_MANAGER) { // import Model library that implements this interface of ModelAPI
-    #ifdef _DEBUG
-    std::cout << "ModelAPI_PluginManager::get: " << "Model library has not been loaded from xml." << std::endl;
-    #endif
     Config_ModuleReader::loadLibrary("Model");
   }
   return MY_MANAGER;
index b154decb009ed0e9e21ba1c885e7f0bfdeb7f47e..82f7214d88e005c820d1fda431e71c81f9b8eb81 100644 (file)
@@ -41,6 +41,8 @@ SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESO
 
 INCLUDE_DIRECTORIES(
     ${PROJECT_SOURCE_DIR}/src/Config
+    ${CMAKE_SOURCE_DIR}/src/Events
+    ${CMAKE_SOURCE_DIR}/src/Model
     ${CMAKE_SOURCE_DIR}/src/ModelAPI
     ${CMAKE_SOURCE_DIR}/src/GeomDataAPI
 )
index e742c055393a02e4d1d582406fbc71b82bc2d27a..c26eadb2a9e2d50b73ed90752ae33a91e51aebc0 100644 (file)
@@ -15,6 +15,9 @@
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Document.h>
+#include <Model_Events.h>
+
+#include <Events_Loop.h>
 
 #ifdef _DEBUG
 #include <QDebug>
@@ -29,11 +32,21 @@ ModuleBase_Operation::~ModuleBase_Operation()
 {
 }
 
+QString ModuleBase_Operation::id() const
+{
+  return getDescription()->operationId();
+}
+
 boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::feature() const
 {
   return myFeature;
 }
 
+bool ModuleBase_Operation::isNestedOperationsEnabled() const
+{
+  return true;
+}
+
 void ModuleBase_Operation::storeReal(double theValue)
 {
   if(!myFeature){
@@ -47,6 +60,7 @@ void ModuleBase_Operation::storeReal(double theValue)
   boost::shared_ptr<ModelAPI_Data> aData = myFeature->data();
   boost::shared_ptr<ModelAPI_AttributeDouble> aReal = aData->real(anId.toStdString());
   aReal->setValue(theValue);
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
 }
 
 void ModuleBase_Operation::storeCustomValue()
@@ -84,13 +98,26 @@ void ModuleBase_Operation::commitOperation()
   if (myFeature) myFeature->execute();
 }
 
-boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::createFeature()
+void ModuleBase_Operation::flushUpdated()
+{
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+}
+
+void ModuleBase_Operation::flushCreated()
+{
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+}
+
+boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::createFeature(const bool theFlushMessage)
 {
   boost::shared_ptr<ModelAPI_Document> aDoc = document();
   boost::shared_ptr<ModelAPI_Feature> aFeature = aDoc->addFeature(
                                            getDescription()->operationId().toStdString());
   if (aFeature) // TODO: generate an error if feature was not created
     aFeature->execute();
+
+  if (theFlushMessage)
+    flushCreated();
   return aFeature;
 }
 
index 43c225dd147802f48e5fc3c3bd22209d596f567a..89b369995926046420fbd3256b035f732b1623c0 100644 (file)
@@ -48,10 +48,17 @@ public:
   /// Destructor
   virtual ~ModuleBase_Operation();
 
+  // Returns operations Id from it's description
+  QString id() const;
   /// Returns the operation feature
   /// \return the feature
   boost::shared_ptr<ModelAPI_Feature> feature() const;
 
+  /// Returns whether the nested operations are enabled.
+  /// The state can depend on the operation current state.
+  /// \return enabled state
+  virtual bool isNestedOperationsEnabled() const;
+
   // Data model methods.
   /// Stores a real value in model.
   /// \param theValue - to store
@@ -70,9 +77,15 @@ protected:
   /// Virtual method called when operation committed (see commit() method for more description)
   virtual void commitOperation();
 
+  /// Send update message by loop
+  void flushUpdated();
+  /// Send created message by loop
+  void flushCreated();
+
   /// Creates an operation new feature
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 
   /// Returns the operation feature
   /// \return the feature
index d0ce1b11e50e5d7266f83a467664d6049494a1a0..4d99d01be7fccfd41897cc5c04ea5d594e8f1548 100644 (file)
@@ -6,6 +6,9 @@
 
 #include <Config_Keywords.h>
 
+#include <Events_Loop.h>
+#include <Model_Events.h>
+
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Data.h>
 #include <GeomDataAPI_Point2D.h>
@@ -68,6 +71,8 @@ bool ModuleBase_WidgetPoint2D::storeValue(boost::shared_ptr<ModelAPI_Feature> th
 
   bool isBlocked = this->blockSignals(true);
   aPoint->setValue(myXSpin->value(), myYSpin->value());
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+
   this->blockSignals(isBlocked);
   return true;
 }
index 06af416d2126fd71e46db484992169a55ae4e3f5..355142a31449d3cf0eff57d1dad009b7f04e57f9 100644 (file)
@@ -37,24 +37,34 @@ void PartSet_Listener::processEvent(const Events_Message* theMessage)
   if (aType == EVENT_FEATURE_UPDATED ||
       aType == EVENT_FEATURE_CREATED)
   {
-    const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
-    if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
-        aType == EVENT_FEATURE_CREATED) {
-      myModule->visualizePreview(aFeature, true, false);
-      myModule->activateFeature(aFeature, true);
-      myModule->workshop()->displayer()->UpdateViewer();
+    const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>
+                                                                                    (theMessage);
+    std::set<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aUpdMsg->features();
+    std::set<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
+                                                                   aLast = aFeatures.end();
+    for (; anIt != aLast; anIt++) {
+      boost::shared_ptr<ModelAPI_Feature> aFeature = *anIt;
+      if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
+          aType == EVENT_FEATURE_CREATED) {
+        myModule->visualizePreview(aFeature, true, false);
+        myModule->activateFeature(aFeature, true);
+      }
     }
+    myModule->workshop()->displayer()->UpdateViewer();
   }
   if (aType == EVENT_FEATURE_DELETED)
   {
     const Model_FeatureDeletedMessage* aDelMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
     boost::shared_ptr<ModelAPI_Document> aDoc = aDelMsg->document();
 
-    std::string aGroup = aDelMsg->group();
-    if (aDelMsg->group().compare("Sketch") == 0) { // Update only Sketch group
-      myModule->workshop()->displayer()->EraseDeletedFeatures();
-      myModule->updateCurrentPreview(aGroup);
+    std::set<std::string> aGroups = aDelMsg->groups();
+    std::set<std::string>::const_iterator anIt = aGroups.begin(), aLast = aGroups.end();
+    for (; anIt != aLast; anIt++) {
+      std::string aGroup = *anIt;
+      if (aGroup.compare("Sketch") == 0) { // Update only Sketch group
+        myModule->workshop()->displayer()->EraseDeletedFeatures();
+        myModule->updateCurrentPreview(aGroup);
+      }
     }
   }
 }
index b54dc192afca8965a7bb3250fbbdc6222cd8b3b6..63f7a1a373a1aa1ada079af3a030afb43eb502fc 100644 (file)
@@ -122,14 +122,25 @@ void PartSet_Module::onOperationStopped(ModuleBase_Operation* theOperation)
   }
 }
 
+void PartSet_Module::onContextMenuCommand(const QString& theId, bool isChecked)
+{
+  QFeatureList aFeatures = myWorkshop->selector()->selectedFeatures();
+  if (theId == "EDIT_CMD" && (aFeatures.size() > 0)) {
+    editFeature(aFeatures.first());
+  }
+}
+
 void PartSet_Module::onMousePressed(QMouseEvent* theEvent)
 {
   PartSet_OperationSketchBase* aPreviewOp = dynamic_cast<PartSet_OperationSketchBase*>(
                                        myWorkshop->operationMgr()->currentOperation());
   if (aPreviewOp)
   {
-    std::list<XGUI_ViewerPrs> aPresentations = myWorkshop->displayer()->GetViewerPrs();
-    aPreviewOp->mousePressed(theEvent, myWorkshop->viewer()->activeView(), aPresentations);
+    XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+    std::list<XGUI_ViewerPrs> aSelected = aDisplayer->GetSelected();
+    std::list<XGUI_ViewerPrs> aHighlighted = aDisplayer->GetHighlighted();
+
+    aPreviewOp->mousePressed(theEvent, myWorkshop->viewer()->activeView(), aSelected, aHighlighted);
   }
 }
 
@@ -139,8 +150,11 @@ void PartSet_Module::onMouseReleased(QMouseEvent* theEvent)
                                        myWorkshop->operationMgr()->currentOperation());
   if (aPreviewOp)
   {
-    std::list<XGUI_ViewerPrs> aPresentations = myWorkshop->displayer()->GetViewerPrs();
-    aPreviewOp->mouseReleased(theEvent, myWorkshop->viewer()->activeView(), aPresentations);
+    XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+    std::list<XGUI_ViewerPrs> aSelected = aDisplayer->GetSelected();
+    std::list<XGUI_ViewerPrs> aHighlighted = aDisplayer->GetHighlighted();
+
+    aPreviewOp->mouseReleased(theEvent, myWorkshop->viewer()->activeView(), aSelected, aHighlighted);
   }
 }
 
@@ -164,7 +178,7 @@ void PartSet_Module::onKeyRelease(QKeyEvent* theEvent)
 void PartSet_Module::onPlaneSelected(double theX, double theY, double theZ)
 {
   myWorkshop->viewer()->setViewProjection(theX, theY, theZ);
-  myWorkshop->actionsMgr()->setNestedActionsEnabled(true);
+  myWorkshop->actionsMgr()->update();
 }
 
 void PartSet_Module::onLaunchOperation(std::string theName, boost::shared_ptr<ModelAPI_Feature> theFeature)
@@ -173,10 +187,13 @@ void PartSet_Module::onLaunchOperation(std::string theName, boost::shared_ptr<Mo
   PartSet_OperationSketchBase* aPreviewOp = dynamic_cast<PartSet_OperationSketchBase*>(anOperation);
   if (aPreviewOp)
   {
-    std::list<XGUI_ViewerPrs> aPresentations = myWorkshop->displayer()->GetViewerPrs();
-    aPreviewOp->init(theFeature, aPresentations);
+    XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+      // refill the features list with avoiding of the features, obtained only by vertex shape (TODO)
+    std::list<XGUI_ViewerPrs> aSelected = aDisplayer->GetSelected(TopAbs_VERTEX);
+    std::list<XGUI_ViewerPrs> aHighlighted = aDisplayer->GetHighlighted(TopAbs_VERTEX);
+    aPreviewOp->init(theFeature, aSelected, aHighlighted);
   }
-  myWorkshop->actionsMgr()->setActionChecked(anOperation->getDescription()->operationId(), true);
+  myWorkshop->actionsMgr()->updateCheckState();
   sendOperation(anOperation);
 }
 
@@ -197,6 +214,10 @@ void PartSet_Module::onStopSelection(const std::list<XGUI_ViewerPrs>& theFeature
     }
   }
   aDisplayer->StopSelection(theFeatures, isStop, false);
+
+  XGUI_ViewerProxy* aViewer = myWorkshop->viewer();
+  aViewer->enableSelection(!isStop);
+
   aDisplayer->UpdateViewer();
 }
 
@@ -384,3 +405,13 @@ void PartSet_Module::updateCurrentPreview(const std::string& theCmdId)
   aDisplayer->UpdateViewer();
 }
 
+void PartSet_Module::editFeature(FeaturePtr theFeature)
+{
+  /*if (!theFeature)
+    return;
+
+  if (theFeature->getKind() == "Sketch") {
+    onLaunchOperation(theFeature->getKind(), theFeature);
+    visualizePreview(theFeature, true);
+  }*/
+}
index 17dc2034820d6cdef49ddde5c1ae81ce6a548c00..1766a6e02b8a31c4174001c9da14555f6437bd5f 100644 (file)
@@ -62,7 +62,8 @@ public slots:
   /// SLOT, that is called after the operation is stopped. Switched off the modfications performed
   /// by the operation start
   void onOperationStopped(ModuleBase_Operation* theOperation);
-
+  /// SLOT, that is called afetr the popup menu action clicked.
+  void onContextMenuCommand(const QString& theId, bool isChecked);
   /// SLOT, that is called by mouse press in the viewer.
   /// The mouse released point is sent to the current operation to be processed.
   /// \param theEvent the mouse event
@@ -118,6 +119,10 @@ protected:
   /// \param theOperation the operation
   void sendOperation(ModuleBase_Operation* theOperation);
 
+protected:
+  //! Edits the feature
+  void editFeature(FeaturePtr theFeature);
+
 private:
   XGUI_Workshop* myWorkshop;
   PartSet_Listener* myListener;
index 7b37976e8a0f041f2f19f85a18b9aa9ec11437dd..d69aab8e0ab2793a2c05372cb97afcbdf7b9025b 100644 (file)
@@ -7,6 +7,7 @@
 #include <PartSet_OperationSketch.h>
 
 #include <ModuleBase_OperationDescription.h>
+#include <Model_Events.h>
 
 #include <XGUI_ViewerPrs.h>
 
@@ -34,7 +35,7 @@ using namespace std;
 PartSet_OperationEditLine::PartSet_OperationEditLine(const QString& theId,
                                                  QObject* theParent,
                                               boost::shared_ptr<ModelAPI_Feature> theFeature)
-: PartSet_OperationSketchBase(theId, theParent), mySketch(theFeature)
+: PartSet_OperationSketchBase(theId, theParent), mySketch(theFeature), myIsBlockedSelection(false)
 {
 }
 
@@ -53,10 +54,28 @@ std::list<int> PartSet_OperationEditLine::getSelectionModes(boost::shared_ptr<Mo
 }
 
 void PartSet_OperationEditLine::init(boost::shared_ptr<ModelAPI_Feature> theFeature,
-                                     const std::list<XGUI_ViewerPrs>& thePresentations)
+                                     const std::list<XGUI_ViewerPrs>& theSelected,
+                                     const std::list<XGUI_ViewerPrs>& theHighlighted)
 {
   setFeature(theFeature);
-  myFeatures = thePresentations;
+
+  if (!theHighlighted.empty()) {
+    // if there is highlighted object, we check whether it is in the list of selected objects
+    // in that case this object is a handle of the moved lines. If there no such object in the selection,
+    // the hightlighted object should moved and the selection is skipped. The skipped selection will be
+    // deselected in the viewer by blockSelection signal in the startOperation method.
+    bool isSelected = false;
+    std::list<XGUI_ViewerPrs>::const_iterator anIt = theSelected.begin(), aLast = theSelected.end();
+    for (; anIt != aLast && !isSelected; anIt++) {
+      isSelected = (*anIt).feature() == feature();
+    }
+    if (!isSelected)
+      myFeatures = theHighlighted;
+    else
+      myFeatures = theSelected;
+  }
+  else
+    myFeatures = theSelected;
 }
 
 boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::sketch() const
@@ -64,12 +83,35 @@ boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::sketch() const
   return mySketch;
 }
 
-void PartSet_OperationEditLine::mousePressed(QMouseEvent* theEvent, Handle(V3d_View) theView)
+void PartSet_OperationEditLine::mousePressed(QMouseEvent* theEvent, Handle(V3d_View) theView,
+                                             const std::list<XGUI_ViewerPrs>& /*theSelected*/,
+                                             const std::list<XGUI_ViewerPrs>& theHighlighted)
 {
-  if (!(theEvent->buttons() &  Qt::LeftButton))
-    return;
-  gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
-  myCurPoint.setPoint(aPoint);
+  if (myFeatures.size() == 1)
+  {
+    boost::shared_ptr<ModelAPI_Feature> aFeature;
+    if (!theHighlighted.empty())
+      aFeature = theHighlighted.front().feature();
+
+    if (aFeature && aFeature == feature()) { // continue the feature edit
+    }
+    else {
+      XGUI_ViewerPrs aFeaturePrs = myFeatures.front();
+      commit();
+      emit featureConstructed(feature(), FM_Deactivation);
+
+      bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
+      if(aHasShift && !theHighlighted.empty()) {
+        std::list<XGUI_ViewerPrs> aSelected;
+        aSelected.push_back(aFeaturePrs);
+        aSelected.push_back(theHighlighted.front());
+        emit setSelection(aSelected);
+      }
+      else if (aFeature) {
+        emit launchOperation(PartSet_OperationEditLine::Type(), aFeature);
+      }
+    }
+  }
 }
 
 void PartSet_OperationEditLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_View) theView)
@@ -79,6 +121,7 @@ void PartSet_OperationEditLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_Vie
 
   gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
 
+  blockSelection(true);
   if (myCurPoint.myIsInitialized) {
     double aCurX, aCurY;
     PartSet_Tools::ConvertTo2D(myCurPoint.myPoint, sketch(), theView, aCurX, aCurY);
@@ -101,22 +144,19 @@ void PartSet_OperationEditLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_Vie
       moveLinePoint(aFeature, aDeltaX, aDeltaY, LINE_ATTR_END);
     }
   }
+  flushUpdated();
   sendFeatures();
 
   myCurPoint.setPoint(aPoint);
 }
 
 void PartSet_OperationEditLine::mouseReleased(QMouseEvent* theEvent, Handle(V3d_View) theView,
-                                              const std::list<XGUI_ViewerPrs>& theSelected)
+                                              const std::list<XGUI_ViewerPrs>& /*theSelected*/,
+                                              const std::list<XGUI_ViewerPrs>& /*theHighlighted*/)
 {
   std::list<XGUI_ViewerPrs> aFeatures = myFeatures;
   if (myFeatures.size() == 1) {
-    if (theSelected.empty())
-      return;
-
-    boost::shared_ptr<ModelAPI_Feature> aFeature = theSelected.front().feature();
-    commit();
-    emit launchOperation(PartSet_OperationEditLine::Type(), aFeature);
+    blockSelection(false);
   }
   else {
     commit();
@@ -133,23 +173,40 @@ void PartSet_OperationEditLine::startOperation()
 {
   // do nothing in order to do not create a new feature
   emit multiSelectionEnabled(false);
-  emit setSelection(std::list<XGUI_ViewerPrs>());
-  emit stopSelection(myFeatures, true);
+
+  if (myFeatures.size() > 1)
+    blockSelection(true);
+
   myCurPoint.clear();
 }
 
 void PartSet_OperationEditLine::stopOperation()
 {
   emit multiSelectionEnabled(true);
-  bool isSelectFeatures = myFeatures.size() > 1;
-  emit stopSelection(myFeatures, false);
-  if (isSelectFeatures)
-    emit setSelection(myFeatures);
+
+  blockSelection(false, myFeatures.size() > 1);
 
   myFeatures.clear();
 }
 
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::createFeature()
+void PartSet_OperationEditLine::blockSelection(bool isBlocked, const bool isRestoreSelection)
+{
+  if (myIsBlockedSelection == isBlocked)
+    return;
+
+  myIsBlockedSelection = isBlocked;
+  if (isBlocked) {
+    emit setSelection(std::list<XGUI_ViewerPrs>());
+    emit stopSelection(myFeatures, true);
+  }
+  else {
+    emit stopSelection(myFeatures, false);
+    if (isRestoreSelection)
+      emit setSelection(myFeatures);
+  }
+}
+
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::createFeature(const bool /*theFlushMessage*/)
 {
   // do nothing in order to do not create a new feature
   return boost::shared_ptr<ModelAPI_Feature>();
@@ -163,6 +220,8 @@ void PartSet_OperationEditLine::moveLinePoint(boost::shared_ptr<ModelAPI_Feature
     return;
 
   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
+  if (!aData->isValid())
+    return;
   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(theAttribute));
 
@@ -171,17 +230,18 @@ void PartSet_OperationEditLine::moveLinePoint(boost::shared_ptr<ModelAPI_Feature
 
 void PartSet_OperationEditLine::sendFeatures()
 {
+  static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_MOVED);
+
   std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures;
   std::list<XGUI_ViewerPrs>::const_iterator anIt = myFeatures.begin(), aLast = myFeatures.end();
   for (; anIt != aLast; anIt++) {
     boost::shared_ptr<ModelAPI_Feature> aFeature = (*anIt).feature();
-    if (!aFeature || aFeature == feature())
+    if (!aFeature)
       continue;
-  }
 
-  static Events_ID aModuleEvent = Events_Loop::eventByName("PartSetEditEvent");
-  Model_FeaturesMovedMessage aMessage;
-  aMessage.setFeatures(aFeatures);
-  Events_Loop::loop()->send(aMessage);
+    Model_FeatureUpdatedMessage aMessage(aFeature, anEvent);
+    Events_Loop::loop()->send(aMessage);
+  }
+  Events_Loop::loop()->flush(anEvent);
 }
 
index 14fd56959cfebedd8688389b7c6140c40ca797b9..d42d0e545fb38022f6f716bd69b77935b83425bc 100644 (file)
@@ -72,28 +72,36 @@ public:
 
   /// Initializes some fields accorging to the feature
   /// \param theFeature the feature
-  /// \param thePresentations the list of additional presentations
+  /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
   virtual void init(boost::shared_ptr<ModelAPI_Feature> theFeature,
-                    const std::list<XGUI_ViewerPrs>& thePresentations);
+                    const std::list<XGUI_ViewerPrs>& theSelected,
+                    const std::list<XGUI_ViewerPrs>& theHighlighted);
 
   /// Returns the operation sketch feature
   /// \returns the sketch instance
   virtual boost::shared_ptr<ModelAPI_Feature> sketch() const;
 
   /// Processes the mouse pressed in the point
-  /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
-  virtual void mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView);
+  /// \param theView a viewer to have the viewer the eye position
+  /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
+  virtual void mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView,
+                            const std::list<XGUI_ViewerPrs>& theSelected,
+                            const std::list<XGUI_ViewerPrs>& theHighlighted);
   /// Gives the current mouse point in the viewer
-  /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
+  /// \param theView a viewer to have the viewer the eye position
   virtual void mouseMoved(QMouseEvent* theEvent, Handle_V3d_View theView);
   /// Gives the current selected objects to be processed by the operation
   /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
   /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
  virtual void mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView,
-                            const std::list<XGUI_ViewerPrs>& theSelected);
+                            const std::list<XGUI_ViewerPrs>& theSelected,
+                            const std::list<XGUI_ViewerPrs>& theHighlighted);
 protected:
   /// \brief Virtual method called when operation is started
   /// Virtual method called when operation started (see start() method for more description)
@@ -106,10 +114,18 @@ protected:
 
   /// Creates an operation new feature
   /// Returns NULL feature. This is an operation of edition, not creation.
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 
 protected:
+  /// Emits a signal about the selection blocking. Emits a signal to change the selection.
+  /// If the block is true, the signal clear selection, otherwise if restore selection flag allows,
+  /// the internal operation features are to be selected
+  /// \param isBlocked the state whether the operation is blocked or unblocked
+  /// \param isRestoreSelection the state whether the selected objects should be reselected
+  void blockSelection(bool isBlocked, const bool isRestoreSelection = true);
+
   /// \brief Save the point to the line.
   /// \param theFeature the source feature
   /// \param theDeltaX the delta for X coordinate is moved
@@ -126,6 +142,7 @@ private:
   std::list<XGUI_ViewerPrs> myFeatures; ///< the features to apply the edit operation
   Point myCurPoint; ///< the current 3D point clicked or moved
   gp_Pnt myCurPressed; ///< the current 3D point clicked or moved
+  bool myIsBlockedSelection; ///< the state of the last state of selection blocked signal
 };
 
 #endif
index d527cd0f3f1aee9d07598e9a2b2c36c40f1cbf6f..eb65c3659515f3b4d05274a1e9121905a8916345 100644 (file)
@@ -33,7 +33,7 @@ using namespace std;
 
 PartSet_OperationSketch::PartSet_OperationSketch(const QString& theId,
                                                     QObject* theParent)
-: PartSet_OperationSketchBase(theId, theParent), myIsEditMode(false)
+: PartSet_OperationSketchBase(theId, theParent)
 {
 }
 
@@ -44,51 +44,56 @@ PartSet_OperationSketch::~PartSet_OperationSketch()
 std::list<int> PartSet_OperationSketch::getSelectionModes(boost::shared_ptr<ModelAPI_Feature> theFeature) const
 {
   std::list<int> aModes;
-  if (!myIsEditMode)
+  if (!hasSketchPlane())
     aModes.push_back(TopAbs_FACE);
   else
     aModes = PartSet_OperationSketchBase::getSelectionModes(theFeature);
   return aModes;
 }
 
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketch::sketch() const
+void PartSet_OperationSketch::init(boost::shared_ptr<ModelAPI_Feature> theFeature,
+                                   const std::list<XGUI_ViewerPrs>& thePresentations)
 {
-  return feature();
+  setFeature(theFeature);
 }
 
-void PartSet_OperationSketch::mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView,
-                                           const std::list<XGUI_ViewerPrs>& theSelected)
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketch::sketch() const
 {
-  myFeatures = theSelected;
+  return feature();
 }
 
-void PartSet_OperationSketch::mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView,
-                                            const std::list<XGUI_ViewerPrs>& theSelected)
+void PartSet_OperationSketch::mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView,
+                                           const std::list<XGUI_ViewerPrs>& theSelected,
+                                           const std::list<XGUI_ViewerPrs>& theHighlighted)
 {
-  if (theSelected.empty())
-    return;
-
-  if (!myIsEditMode) {
-    XGUI_ViewerPrs aPrs = theSelected.front();
-    const TopoDS_Shape& aShape = aPrs.shape();
-    if (!aShape.IsNull()) {
-      setSketchPlane(aShape);
-      myIsEditMode = true;
+  if (!hasSketchPlane()) {
+    if (!theHighlighted.empty()) {
+      XGUI_ViewerPrs aPrs = theHighlighted.front();
+      const TopoDS_Shape& aShape = aPrs.shape();
+      if (!aShape.IsNull())
+        setSketchPlane(aShape);
     }
   }
   else {
-    if (theSelected.size() == 1) {
-      boost::shared_ptr<ModelAPI_Feature> aFeature = theSelected.front().feature();
+    // if shift button is pressed and there are some already selected objects, the operation should
+    // not be started. We just want to combine some selected objects.
+    bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
+    if (aHasShift && theSelected.size() > 0)
+      return;
+
+    if (theHighlighted.size() == 1) {
+      boost::shared_ptr<ModelAPI_Feature> aFeature = theHighlighted.front().feature();
       if (aFeature)
         emit launchOperation(PartSet_OperationEditLine::Type(), aFeature);
     }
+    else
+      myFeatures = theHighlighted;
   }
-  myFeatures.clear();
 }
 
 void PartSet_OperationSketch::mouseMoved(QMouseEvent* theEvent, Handle(V3d_View) theView)
 {
-  if (!myIsEditMode || !(theEvent->buttons() &  Qt::LeftButton) || myFeatures.empty())
+  if (!hasSketchPlane() || !(theEvent->buttons() &  Qt::LeftButton) || myFeatures.empty())
     return;
 
   if (myFeatures.size() != 1) {
@@ -107,6 +112,8 @@ std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
   boost::shared_ptr<SketchPlugin_Feature> aFeature;
 
   boost::shared_ptr<ModelAPI_Data> aData = feature()->data();
+  if (!aData->isValid())
+    return aPreviewMap;
   boost::shared_ptr<ModelAPI_AttributeRefList> aRefList =
         boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aData->attribute(SKETCH_ATTR_FEATURES));
 
@@ -129,6 +136,30 @@ void PartSet_OperationSketch::stopOperation()
   emit closeLocalContext();
 }
 
+bool PartSet_OperationSketch::isNestedOperationsEnabled() const
+{
+  return hasSketchPlane();
+}
+
+bool PartSet_OperationSketch::hasSketchPlane() const
+{
+  bool aHasPlane = false;
+
+  if (feature()) {
+    // set plane parameters to feature
+    boost::shared_ptr<ModelAPI_Data> aData = feature()->data();
+
+    boost::shared_ptr<ModelAPI_AttributeDouble> anAttr;
+    // temporary solution for main planes only
+    boost::shared_ptr<GeomDataAPI_Dir> aNormal = 
+      boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_NORM));
+    double aX = aNormal->x(), anY = aNormal->y(), aZ = aNormal->z();
+
+    aHasPlane = aNormal && !(aNormal->x() == 0 && aNormal->y() == 0 && aNormal->z() == 0);
+  }
+  return aHasPlane;
+}
+
 void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape)
 {
   if (theShape.IsNull())
@@ -147,12 +178,6 @@ void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape)
   aPlane->coefficients(anA, aB, aC, aD);
 
   boost::shared_ptr<ModelAPI_AttributeDouble> anAttr;
-  /*
-  aData->real(SKETCH_ATTR_PLANE_A)->setValue(anA);
-  aData->real(SKETCH_ATTR_PLANE_B)->setValue(aB);
-  aData->real(SKETCH_ATTR_PLANE_C)->setValue(aC);
-  aData->real(SKETCH_ATTR_PLANE_D)->setValue(aD);
-  */
   // temporary solution for main planes only
   boost::shared_ptr<GeomDataAPI_Point> anOrigin = 
     boost::dynamic_pointer_cast<GeomDataAPI_Point>(aData->attribute(SKETCH_ATTR_ORIGIN));
@@ -167,6 +192,9 @@ void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape)
     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRY));
   aDirY->setValue(aC, anA, aB);
   boost::shared_ptr<GeomAPI_Dir> aDir = aPlane->direction();
+
+  flushUpdated();
+
   emit featureConstructed(feature(), FM_Hide);
   emit closeLocalContext();
   emit planeSelected(aDir->x(), aDir->y(), aDir->z());
index fbb0eb376afba999656a2a675bb42d6e37a76f15..8f3a8fd4e856a4b898641137c8497159a50129de 100644 (file)
@@ -34,22 +34,24 @@ public:
   /// \return the selection mode
   virtual std::list<int> getSelectionModes(boost::shared_ptr<ModelAPI_Feature> theFeature) const;
 
+  /// Initializes some fields accorging to the feature
+  /// \param theFeature the feature
+  /// \param thePresentations the list of additional presentations
+  virtual void init(boost::shared_ptr<ModelAPI_Feature> theFeature,
+                    const std::list<XGUI_ViewerPrs>& thePresentations);
+
   /// Returns the operation sketch feature
   /// \returns the sketch instance
   virtual boost::shared_ptr<ModelAPI_Feature> sketch() const;
 
   /// Processes the mouse pressed in the point
-  /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
+  /// \param theView a viewer to have the viewer the eye position
   /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
   virtual void mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView,
-                            const std::list<XGUI_ViewerPrs>& theSelected);
-  /// Processes the mouse release in the point
-  /// \param thePoint a point clicked in the viewer
-  /// \param theEvent the mouse event
-  /// \param theSelected the list of selected presentations
-  virtual void mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView,
-                             const std::list<XGUI_ViewerPrs>& theSelected);
+                            const std::list<XGUI_ViewerPrs>& theSelected,
+                            const std::list<XGUI_ViewerPrs>& theHighlighted);
   /// Gives the current mouse point in the viewer
   /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
@@ -64,6 +66,12 @@ public:
   /// Emits a signal to hide the preview of the operation
   virtual void stopOperation();
 
+  /// Returns whether the nested operations are enabled.
+  /// The state can depend on the operation current state.
+  /// It returns true after the sketch plane is choosen.
+  /// \return enabled state
+  virtual bool isNestedOperationsEnabled() const;
+
 signals:
   /// signal about the sketch plane is selected
   /// \param theX the value in the X direction of the plane
@@ -72,12 +80,15 @@ signals:
   void planeSelected(double theX, double theY, double theZ);
 
 protected:
+  /// Returns whether the sketch plane is set
+  /// \return the boolean value whether the sketch is set
+  bool hasSketchPlane() const;
+
   /// Set the plane to the current sketch
   /// \param theShape the shape
   void setSketchPlane(const TopoDS_Shape& theShape);
 
 private:
-  bool myIsEditMode; /// the edit mode of this operation
   std::list<XGUI_ViewerPrs> myFeatures; ///< the features to apply the edit operation
 };
 
index 45981e24402b8b827621b20efdb7e558e3b916c9..acf76c60a094e134b5a9691c7e1be72ad383cbbe 100644 (file)
@@ -54,9 +54,9 @@ std::list<int> PartSet_OperationSketchBase::getSelectionModes(boost::shared_ptr<
   aModes.push_back(TopAbs_EDGE);
   return aModes;
 }
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature(const bool theFlushMessage)
 {
-  boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature();
+  boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature(theFlushMessage);
   if (aFeature)
     emit featureConstructed(aFeature, FM_Activation);
   return aFeature;
@@ -64,11 +64,13 @@ boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature()
 
 
 void PartSet_OperationSketchBase::mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView,
-                                               const std::list<XGUI_ViewerPrs>& theSelected)
+                                               const std::list<XGUI_ViewerPrs>& theSelected,
+                                               const std::list<XGUI_ViewerPrs>& theHighlighted)
 {
 }
 void PartSet_OperationSketchBase::mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView,
-                                                const std::list<XGUI_ViewerPrs>& theSelected)
+                                                const std::list<XGUI_ViewerPrs>& theSelected,
+                                                const std::list<XGUI_ViewerPrs>& theHighlighted)
 {
 }
 void PartSet_OperationSketchBase::mouseMoved(QMouseEvent* theEvent, Handle(V3d_View) theView)
index 0045a8e87b1a6c19b2cf227188974d3ea7099387..5aa07c3f002c0ab90f8171e5d701c8fe629262ae 100644 (file)
@@ -55,32 +55,37 @@ public:
   virtual std::list<int> getSelectionModes(boost::shared_ptr<ModelAPI_Feature> theFeature) const = 0;
 
   /// Initializes some fields accorging to the feature
-  /// \param theFeature the feature
-  /// \param thePresentations the list of additional presentations
+  /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
   virtual void init(boost::shared_ptr<ModelAPI_Feature> theFeature,
-                    const std::list<XGUI_ViewerPrs>& thePresentations) {}
+                    const std::list<XGUI_ViewerPrs>& theSelected,
+                    const std::list<XGUI_ViewerPrs>& theHighlighted) {}
 
   /// Returns the operation sketch feature
   /// \returns the sketch instance
   virtual boost::shared_ptr<ModelAPI_Feature> sketch() const = 0;
 
   /// Processes the mouse pressed in the point
-  /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
+  /// \param theView a viewer to have the viewer the eye position
   /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
   virtual void mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView,
-                            const std::list<XGUI_ViewerPrs>& theSelected);
+                            const std::list<XGUI_ViewerPrs>& theSelected,
+                            const std::list<XGUI_ViewerPrs>& theHighlighted);
 
   /// Processes the mouse release in the point
-  /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
+  /// \param theView a viewer to have the viewer the eye position
   /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
   virtual void mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView,
-                             const std::list<XGUI_ViewerPrs>& theSelected);
+                             const std::list<XGUI_ViewerPrs>& theSelected,
+                             const std::list<XGUI_ViewerPrs>& theHighlighted);
 
   /// Processes the mouse move in the point
-  /// \param thePoint a 3D point clicked in the viewer
   /// \param theEvent the mouse event
+  /// \param theView a viewer to have the viewer the eye position
   virtual void mouseMoved(QMouseEvent* theEvent, Handle_V3d_View theView);
 
   /// Processes the key pressed in the view
@@ -119,8 +124,9 @@ protected:
   /// Creates an operation new feature
   /// In addition to the default realization it appends the created line feature to
   /// the sketch feature
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 };
 
 #endif
index 6b64cd2759cff1930c142411f11a40d44ab5d1bc..33e03c5e2c4d4c841b9148252902ee0834c3a0a2 100644 (file)
@@ -67,7 +67,8 @@ std::list<int> PartSet_OperationSketchLine::getSelectionModes(boost::shared_ptr<
 }
 
 void PartSet_OperationSketchLine::init(boost::shared_ptr<ModelAPI_Feature> theFeature,
-                                       const std::list<XGUI_ViewerPrs>& /*thePresentations*/)
+                                       const std::list<XGUI_ViewerPrs>& /*theSelected*/,
+                                       const std::list<XGUI_ViewerPrs>& /*theHighlighted*/)
 {
   if (!theFeature || theFeature->getKind() != "SketchLine")
     return;
@@ -82,7 +83,8 @@ boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::sketch() const
 }
 
 void PartSet_OperationSketchLine::mouseReleased(QMouseEvent* theEvent, Handle(V3d_View) theView,
-                                                const std::list<XGUI_ViewerPrs>& theSelected)
+                                                const std::list<XGUI_ViewerPrs>& theSelected,
+                                                const std::list<XGUI_ViewerPrs>& /*theHighlighted*/)
 {
   double aX, anY;
 
@@ -142,11 +144,15 @@ void PartSet_OperationSketchLine::mouseReleased(QMouseEvent* theEvent, Handle(V3
     case SM_FirstPoint: {
       setLinePoint(feature(), aX, anY, LINE_ATTR_START);
       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
+      flushUpdated();
+
       myPointSelectionMode = SM_SecondPoint;
     }
     break;
     case SM_SecondPoint: {
       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
+      flushUpdated();
+
       myPointSelectionMode = SM_DonePoint;
     }
     break;
@@ -165,12 +171,14 @@ void PartSet_OperationSketchLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_V
       PartSet_Tools::ConvertTo2D(aPoint, sketch(), theView, aX, anY);
       setLinePoint(feature(), aX, anY, LINE_ATTR_START);
       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
+      flushUpdated();
     }
     break;
     case SM_SecondPoint:
     {
       gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
       setLinePoint(aPoint, theView, LINE_ATTR_END);
+      flushUpdated();
     }
     break;
     case SM_DonePoint:
@@ -198,8 +206,16 @@ void PartSet_OperationSketchLine::keyReleased(const int theKey)
       emit launchOperation(PartSet_OperationSketchLine::Type(), boost::shared_ptr<ModelAPI_Feature>());
     }
     break;
+    case Qt::Key_Escape: {
+      if (myPointSelectionMode == SM_DonePoint)
+      {
+        commit();
+        emit featureConstructed(feature(), FM_Deactivation);
+      }
+      else
+        abort();
+    }
     default:
-      PartSet_OperationSketchBase::keyReleased(theKey); 
     break;
   }
 }
@@ -223,9 +239,9 @@ void PartSet_OperationSketchLine::stopOperation()
   emit multiSelectionEnabled(true);
 }
 
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature(const bool theFlushMessage)
 {
-  boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature();
+  boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature(false);
   if (sketch()) {
     boost::shared_ptr<SketchPlugin_Feature> aFeature = 
                            boost::dynamic_pointer_cast<SketchPlugin_Feature>(sketch());
@@ -243,6 +259,8 @@ boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature()
   }
 
   emit featureConstructed(aNewFeature, FM_Activation);
+  if (theFlushMessage)
+    flushCreated();
   return aNewFeature;
 }
 
index 09c33f6f452621540d8d17e9ede546f703c417e7..db20415c74cb86f54548866d6b52f83077734eb7 100644 (file)
@@ -46,21 +46,24 @@ public:
   virtual std::list<int> getSelectionModes(boost::shared_ptr<ModelAPI_Feature> theFeature) const;
 
   /// Initializes some fields accorging to the feature
-  /// \param theFeature the feature
-  /// \param thePresentations the list of additional presentations
+  /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
   virtual void init(boost::shared_ptr<ModelAPI_Feature> theFeature,
-                    const std::list<XGUI_ViewerPrs>& thePresentations);
+                    const std::list<XGUI_ViewerPrs>& theSelected,
+                    const std::list<XGUI_ViewerPrs>& theHighlighted);
 
   /// Returns the operation sketch feature
   /// \returns the sketch instance
   virtual boost::shared_ptr<ModelAPI_Feature> sketch() const;
 
   /// Gives the current selected objects to be processed by the operation
-  /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
+  /// \param theView a viewer to have the viewer the eye position
   /// \param theSelected the list of selected presentations
+  /// \param theHighlighted the list of highlighted presentations
  virtual void mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView,
-                             const std::list<XGUI_ViewerPrs>& theSelected);
+                            const std::list<XGUI_ViewerPrs>& theSelected,
+                            const std::list<XGUI_ViewerPrs>& theHighlighted);
   /// Gives the current mouse point in the viewer
   /// \param thePoint a point clicked in the viewer
   /// \param theEvent the mouse event
@@ -86,8 +89,9 @@ protected:
   /// Creates an operation new feature
   /// In addition to the default realization it appends the created line feature to
   /// the sketch feature
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 
   /// Creates a constraint on two points
   /// \param thePoint1 the first point
index 4b3391da8b846dc2cb0e0e8923da0f884b72975d..07438b2d2e62169747a0da8849c4573d63a9f909 100644 (file)
@@ -1,9 +1,9 @@
 <plugin>
   <workbench id="Part">
     <group id="Operations">
-      <feature id="Part" text="New part" tooltip="Creates a new part" icon=":pictures/part_ico.png"/>
-      <feature id="duplicate" text="Duplicate" tooltip="Duplicate selected object" icon=":icons/duplicate.png"/>
-      <feature id="remove" text="Remove"  tooltip="Remove selected object" icon=":icons/remove.png"/>
+      <feature id="Part" title="New part" tooltip="Creates a new part" icon=":pictures/part_ico.png"/>
+      <feature id="duplicate" title="Duplicate" tooltip="Duplicate selected object" icon=":icons/duplicate.png"/>
+      <feature id="remove" title="Remove"  tooltip="Remove selected object" icon=":icons/remove.png"/>
     </group>
   </workbench>
 </plugin>
index 29cf61b04a16a7c8ad45c3e60295d10fdf4c4dcf..706d85f3b1ae8258e016209da1e57b83403f6f9e 100644 (file)
@@ -1,16 +1,16 @@
 <plugin>
   <workbench id="Sketch">
     <group id="Basic">
-      <feature id="Sketch" nested="SketchLine" text="New sketch" tooltip="Create a new sketch or edit an existing sketch" icon=":icons/sketch.png">
-        <label text="Select a plane on which to create a sketch" tooltip="Select a plane on which to create a sketch"/> 
+      <feature id="Sketch" nested="SketchLine" title="New sketch" tooltip="Create a new sketch or edit an existing sketch" icon=":icons/sketch.png">
+        <label title="Select a plane on which to create a sketch" tooltip="Select a plane on which to create a sketch"/> 
       <!--icon=":pictures/x_point.png"-->
       </feature>
-      <feature id="SketchPoint" text="Point" tooltip="Create a new point" icon=":icons/point.png" />
-      <feature id="SketchLine" text="Line" tooltip="Create a new line" icon=":icons/line.png">
+      <feature id="SketchPoint" title="Point" tooltip="Create a new point" icon=":icons/point.png" internal="1"/>
+      <feature id="SketchLine" title="Line" tooltip="Create a new line" icon=":icons/line.png">
         <point_selector id="StartPoint" title="Start point" tooltip="Start point of the line"/>
         <point_selector id="EndPoint" title="End point" tooltip="End point of the line"/>
       </feature>
-      <feature id="SketchConstraintCoincidence" text="Points coincidence" tooltip="Create constraint for the coincidence of two points" icon="" />
+      <feature id="SketchConstraintCoincidence" title="Points coincidence" tooltip="Create constraint for the coincidence of two points" internal="1"/>
     </group>
   </workbench>
 </plugin>
index c8de0aa301df9376217cd20645c2654ea0830673..7edc1da33916837a0db8b89b4b5f1d4b01bcf661 100644 (file)
@@ -62,7 +62,7 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
-  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURES_MOVED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_MOVED));
 }
 
 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
@@ -73,37 +73,58 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
 void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
 {
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED) ||
-      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED) || 
+      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED))
   {
-    const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+    const Model_FeatureUpdatedMessage* anUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+    std::set< boost::shared_ptr<ModelAPI_Feature> > aFeatures = anUpdateMsg->features();
 
-    // Only sketches and constraints can be added by Create event
-    const std::string& aFeatureKind = aUpdateMsg->feature()->getKind();
-    if (aFeatureKind.compare("Sketch") == 0)
+    bool isModifiedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED);
+    if (!isModifiedEvt)
     {
-      boost::shared_ptr<SketchPlugin_Feature> aSketch =
-        boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-      changeWorkplane(aSketch);
-      return ;
-    }
-    boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
-      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
-    if (aConstraint)
-      changeConstraint(aConstraint);
-    else
-    {
-      // Sketch plugin features can be only updated
-      boost::shared_ptr<SketchPlugin_Feature> aFeature =
-        boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-      if (aFeature)
-        updateEntity(aFeature);
+      std::set< boost::shared_ptr<ModelAPI_Feature> >::iterator aFeatIter;
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
+      {
+        // Only sketches and constraints can be added by Create event
+        const std::string& aFeatureKind = (*aFeatIter)->getKind();
+        if (aFeatureKind.compare("Sketch") == 0)
+        {
+          boost::shared_ptr<SketchPlugin_Feature> aSketch =
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+          if (aSketch)
+            changeWorkplane(aSketch);
+          continue;
+        }
+        boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+          boost::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFeatIter);
+        if (aConstraint)
+          changeConstraint(aConstraint);
+        else
+        {
+          // Sketch plugin features can be only updated
+          boost::shared_ptr<SketchPlugin_Feature> aFeature =
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+          if (aFeature)
+            updateEntity(aFeature);
+        }
+      }
     }
+
+    // Solve the set of constraints
+    resolveConstraints();
   }
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
   {
     const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
+    const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
 
-    if (aDeleteMsg->group().compare("Sketch") == 0)
+    // Find "Sketch" in groups. The constraint groups should be updated when an object removed from Sketch
+    std::set<std::string>::const_iterator aFGrIter;
+    for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+      if (aFGrIter->compare("Sketch") == 0)
+        break;
+    
+    if (aFGrIter != aFeatureGroups.end())
     {
       std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
       while (aGroupIter != myGroups.end())
@@ -119,11 +140,6 @@ void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessa
       }
     }
   }
-  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURES_MOVED))
-  {
-    // Solve the set of constraints
-    resolveConstraints();
-  }
 }
 
 bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
@@ -298,6 +314,9 @@ void SketchSolver_ConstraintManager::resolveConstraints()
   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     (*aGroupIter)->resolveConstraints();
+
+  // Features may be updated => send events
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
 }
 
 
@@ -322,7 +341,11 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
 
   // Initialize workplane
   myWorkplane.h = SLVS_E_UNKNOWN;
+#ifndef NDEBUG
   assert(addWorkplane(theWorkplane));
+#else
+  addWorkplane(theWorkplane);
+#endif
 }
 
 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
index 7f0b02d9ae0e668688a24dbaaa15d1a65caf1a19..6815d81d357d7756c7285478b3f8cef717440b48 100644 (file)
@@ -5,15 +5,21 @@
 #include "XGUI_ActionsMgr.h"
 #include "XGUI_Command.h"
 #include "XGUI_Workshop.h"
-#include "XGUI_SalomeConnector.h"
+#include "XGUI_OperationMgr.h"
+
+#include <ModuleBase_Operation.h>
 
 #include <QAction>
 
+#ifdef _DEBUG
+#include <QDebug>
+#endif
+
 
 XGUI_ActionsMgr::XGUI_ActionsMgr(XGUI_Workshop* theParent)
- : QObject(theParent), myWorkshop(theParent)
+ : QObject(theParent), myOperationMgr(theParent->operationMgr())
 {
-  
+
 }
 
 XGUI_ActionsMgr::~XGUI_ActionsMgr()
@@ -24,79 +30,85 @@ XGUI_ActionsMgr::~XGUI_ActionsMgr()
 void XGUI_ActionsMgr::addCommand(QAction* theCmd)
 {
   QString aId = theCmd->data().toString();
+  if(aId.isEmpty()) {
+    return;
+  }
   myActions.insert(aId, theCmd);
-  myActionsState.insert(aId, theCmd->isEnabled());
-  connect(theCmd, SIGNAL(triggered(bool)), this, SLOT(setActionsDisabled(bool)));
+  XGUI_Command* aXCmd = dynamic_cast<XGUI_Command*>(theCmd);
+  if (aXCmd) {
+    myNestedActions[aId] = aXCmd->nestedCommands();
+  }
 }
 
-void XGUI_ActionsMgr::setActionsDisabled(bool isDisabled)
+void XGUI_ActionsMgr::addNestedCommands(const QString& theId, const QStringList& theCommands)
 {
-  //Re-enable actions (just restore their state)
-  if (!isDisabled) {
-    myNestedActions.clear();
-    restoreCommandState();
-    return;
-  }
-  //Disable all actions, but caller and unblockable (defined in a xml)
-  saveCommandsState();
-
-  QString aSkippedId;
-  QAction* aToggledFeature = dynamic_cast<QAction*>(sender());
-  aSkippedId = aToggledFeature->data().toString();
+  myNestedActions[theId] = theCommands;
+}
 
-  QStringList anActionIdsList = myActions.keys();
-  foreach(QString eachKey, anActionIdsList) {
-    if (eachKey == aSkippedId) {
-      continue;
-    }
-    myActions[eachKey]->setEnabled(false);
-  }
-  if (myWorkshop->isSalomeMode()) {
-    myNestedActions = myWorkshop->salomeConnector()->nestedActions(aSkippedId);
+void XGUI_ActionsMgr::update()
+{
+  if(myOperationMgr->hasOperation()) {
+    setAllEnabled(false);
+    ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
+    QString anOperationId = anOperation->id();
+    setActionEnabled(anOperationId, true);
+    bool isNestedEnabled = anOperation->isNestedOperationsEnabled();
+    setNestedCommandsEnabled(isNestedEnabled, anOperationId);
   } else {
-    XGUI_Command* aToggledFeature = dynamic_cast<XGUI_Command*>(sender());
-    myNestedActions = aToggledFeature->unblockableCommands();
+    setAllEnabled(true);
+    setNestedCommandsEnabled(false);
   }
+  updateCheckState();
 }
 
-void XGUI_ActionsMgr::saveCommandsState()
+void XGUI_ActionsMgr::setAllEnabled(bool isEnabled)
 {
-  myActionsState.clear();
-  QStringList anActionIdsList = myActions.keys();
-  foreach(QString eachKey, anActionIdsList) {
-    myActionsState.insert(eachKey, myActions[eachKey]->isEnabled());
+  foreach(QString eachAction, myActions.keys()) {
+    setActionEnabled(eachAction, isEnabled);
   }
-
 }
 
-void XGUI_ActionsMgr::restoreCommandState()
+//!
+void XGUI_ActionsMgr::setNestedCommandsEnabled(bool theEnabled, const QString& theParent)
 {
-  QStringList anActionIdsList = myActions.keys();
-  foreach(QString eachKey, anActionIdsList) {
-    myActions[eachKey]->setEnabled(myActionsState[eachKey]);
-    myActions[eachKey]->setChecked(false);
+  QStringList ltNestedActions;
+  if(theParent.isEmpty()) { //Disable ALL nested
+    foreach(QString eachParent, myNestedActions.keys()) {
+      ltNestedActions << myNestedActions[eachParent];
+    }
+  } else {
+    ltNestedActions << myNestedActions[theParent];
+  }
+  foreach(QString eachNested, ltNestedActions) {
+    setActionEnabled(eachNested, theEnabled);
   }
 }
 
 void XGUI_ActionsMgr::setActionChecked(const QString& theId, const bool theChecked)
 {
-  if(myActions.contains(theId)) {
-    myActions[theId]->setChecked(theChecked);
+  QAction* anAction = myActions[theId];
+  if(anAction && anAction->isCheckable()) {
+    anAction->setChecked(theChecked);
   }
 }
 
-void XGUI_ActionsMgr::updateAction(const QString& theId)
+
+void XGUI_ActionsMgr::setActionEnabled(const QString& theId, const bool theEnabled)
 {
-  if(myActions.contains(theId)){
-    myActions[theId]->setEnabled(myActionsState[theId]);
-    myActions[theId]->setChecked(false);
+  QAction* anAction = myActions[theId];
+  if(anAction) {
+    anAction->setEnabled(theEnabled);
   }
 }
 
-void XGUI_ActionsMgr::setNestedActionsEnabled(bool isEnabled)
+void XGUI_ActionsMgr::updateCheckState()
 {
-  foreach(QString eachKey, myNestedActions) {
-    if (myActions.contains(eachKey))
-      myActions[eachKey]->setEnabled(isEnabled);
+  QString eachCommand = QString();
+  foreach(eachCommand, myActions.keys()) {
+    setActionChecked(eachCommand, false);
+  }
+  QStringList ltActiveCommands = myOperationMgr->operationList();
+  foreach(eachCommand, ltActiveCommands) {
+    setActionChecked(eachCommand, true);
   }
 }
index 3390a83f3b87092cf9b0d8879bafc5625fddc007..38b8e167d689f86173b6fc3936991704cae9b02f 100644 (file)
@@ -13,6 +13,7 @@
 
 class XGUI_Command;
 class XGUI_Workshop;
+class XGUI_OperationMgr;
 class QAction;
 
 class XGUI_EXPORT XGUI_ActionsMgr: public QObject
@@ -20,32 +21,42 @@ class XGUI_EXPORT XGUI_ActionsMgr: public QObject
   Q_OBJECT
 
 public:
-  XGUI_ActionsMgr(XGUI_Workshop* theParent);
+  XGUI_ActionsMgr(XGUI_Workshop* theWorkshop);
   virtual ~XGUI_ActionsMgr();
 
-
+  //! Add a command in the manager.
+  //! Please note that nested commands in the Salome mode (No XGUI_Command, pure QActions)
+  //! won't be extracted and should be added manually using the addNestedCommands method.
   void addCommand(QAction* theCmd);
-
-  void saveCommandsState();
-  void restoreCommandState();
-
-  /// Set the action is checked
-  /// \param theId - string ID of the command
-  /// \praram theChecked - the new checked state
-  void setActionChecked(const QString& theId, const bool theChecked);
-
-  void updateAction(const QString&);
-  void setNestedActionsEnabled(bool);
+  //! Sets relation between the command (with given Id) and it's nested actions.
+  void addNestedCommands(const QString& theId, const QStringList& theCommands);
 
 public slots:
-  void setActionsDisabled(bool isEnabled);
+  //! Update workbench actions according to OperationMgr state:
+  //! No active operations: all actions but nested are available
+  //! There is active operation: current operation + it's nested
+  //! are enabled, all the rest is disabled. All active commands is checked.
+  void update();
+  //! Sets all commands checked if it's operation is active.
+  void updateCheckState();
+
+protected:
+  //! Sets all actions to isEnabled state.
+  void setAllEnabled(bool isEnabled);
+  //! Sets all nested actions to isEnabled state for the command with given ID.
+  //! If ID is empty - all nested actions will be affected.
+  void setNestedCommandsEnabled(bool isEnabled, const QString& theParent = QString());
+  //! Sets the action with theId to theChecked state.
+  void setActionChecked(const QString& theId, const bool theChecked);
+  //! Sets the action with theId to theEnabled state.
+  void setActionEnabled(const QString& theId, const bool theEnabled);
 
 private:
-  QStringList myNestedActions;
   QMap<QString, QAction*> myActions;
-  QMap<QString, bool> myActionsState;
+  QMap<QString, QStringList> myNestedActions;
 
-  XGUI_Workshop* myWorkshop;
+  XGUI_OperationMgr* myOperationMgr;
 };
 
 #endif /* XGUI_ACTIONSMGR_H_ */
+
index 220e04f474b5007c1b2dabd60722aeca78c5ac1d..0ddb0ecfcd8dafc2aa6bd851b42d4094ade036cb 100644 (file)
@@ -38,6 +38,7 @@ QWidget* XGUI_Command::createWidget(QWidget* theParent)
     aButton->addAction(this);
     connect(aButton, SIGNAL(clicked()), this, SLOT(trigger()));
     connect(this, SIGNAL(toggled(bool)), aButton, SLOT(setChecked(bool)));
+    connect(this, SIGNAL(toggled(bool)), aButton, SLOT(setChecked(bool)));
     aButton->setFlat(true);
     aButton->setCheckable(myCheckable);
     this->setCheckable(myCheckable);
@@ -53,12 +54,12 @@ void XGUI_Command::connectTo(const QObject* theResiver, const char* theSlot)
     connect(this, SIGNAL(triggered(bool)), theResiver, theSlot);
 }
 
-const QStringList& XGUI_Command::unblockableCommands() const
+const QStringList& XGUI_Command::nestedCommands() const
 {
-  return myUnblockableCommands;
+  return myNestedCommands;
 }
 
-void XGUI_Command::setUnblockableCommands(const QStringList& myUnblockableCommands)
+void XGUI_Command::setNestedCommands(const QStringList& myUnblockableCommands)
 {
-  this->myUnblockableCommands = myUnblockableCommands;
+  this->myNestedCommands = myUnblockableCommands;
 }
index dbd45b43207d969a93b67916a3768bdffbe04d12..6c01e6136342d2592a8734466974cda0b303bbf3 100644 (file)
@@ -25,8 +25,8 @@ public:
     return data().toString();
   }*/
 
-  const QStringList& unblockableCommands() const;
-  void setUnblockableCommands(const QStringList& myUnblockableCommands);
+  const QStringList& nestedCommands() const;
+  void setNestedCommands(const QStringList& myUnblockableCommands);
 
   //! Connect the command to a slot
   virtual void connectTo(const QObject* theResiver, const char* theSlot);
@@ -38,7 +38,7 @@ protected:
 private:
   bool myCheckable;
   //! List of Ids of commands which WILL NOT be blocked when the command is on.
-  QStringList myUnblockableCommands;
+  QStringList myNestedCommands;
 };
 
 #endif
index 461b2dab58195409ae5e75c4bcf1372925cfa58e..38e74834ba85a9a57f655e02172a0a6e0240d6bb 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <ModelAPI_Data.h>
 #include <ModelAPI_AttributeDocRef.h>
+#include <ModelAPI_Object.h>
 
 #include <QAction>
 #include <QContextMenuEvent>
@@ -90,7 +91,8 @@ QMenu* XGUI_ContextMenuMgr::objectBrowserMenu() const
     //Process Feature
     if (aFeature) {
       if (aFeature->getKind() == "Part") {
-        boost::shared_ptr<ModelAPI_Document> aFeaDoc = aFeature->data()->docRef("PartDocument")->value();
+        ObjectPtr aObject = boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature);
+        DocumentPtr aFeaDoc = aObject->featureRef()->data()->docRef("PartDocument")->value();
         if (aMgr->currentDocument() == aFeaDoc)
           aActions.append(action("DEACTIVATE_PART_CMD"));
         else 
@@ -98,7 +100,7 @@ QMenu* XGUI_ContextMenuMgr::objectBrowserMenu() const
       } else {
         aActions.append(action("EDIT_CMD"));
       }
-       aActions.append(action("DELETE_CMD"));
+      aActions.append(action("DELETE_CMD"));
 
     // Process Root object (document)
     } else { // If feature is 0 the it means that selected root object (document)
index 7f6bb00d77885b772f7febee71cd8fac6d7fa6b7..7e5deb50ed54333a332d96c841dd1b68a05a78d0 100644 (file)
@@ -12,6 +12,7 @@
 #include <ModelAPI_Data.h>
 
 #include <AIS_InteractiveContext.hxx>
+#include <AIS_LocalContext.hxx>
 #include <AIS_ListOfInteractive.hxx>
 #include <AIS_ListIteratorOfListOfInteractive.hxx>
 
@@ -19,6 +20,8 @@
 
 #include <set>
 
+const int MOUSE_SENSITIVITY_IN_PIXEL = 10; ///< defines the local context mouse selection sensitivity
+
 XGUI_Displayer::XGUI_Displayer(XGUI_Workshop* theWorkshop)
 {
   myWorkshop = theWorkshop;
@@ -52,7 +55,7 @@ void XGUI_Displayer::Display(boost::shared_ptr<ModelAPI_Feature> theFeature,
 }*/
 
 
-std::list<XGUI_ViewerPrs> XGUI_Displayer::GetViewerPrs()
+std::list<XGUI_ViewerPrs> XGUI_Displayer::GetSelected(const int theShapeTypeToSkip)
 {
   std::set<boost::shared_ptr<ModelAPI_Feature> > aPrsFeatures;
   std::list<XGUI_ViewerPrs> aPresentations;
@@ -61,16 +64,31 @@ std::list<XGUI_ViewerPrs> XGUI_Displayer::GetViewerPrs()
   for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected()) {
     Handle(AIS_InteractiveObject) anIO = aContext->SelectedInteractive();
     TopoDS_Shape aShape = aContext->SelectedShape();
+    if (theShapeTypeToSkip >= 0 && !aShape.IsNull() && aShape.ShapeType() == theShapeTypeToSkip)
+      continue;
 
-    boost::shared_ptr<ModelAPI_Feature> aFeature;
-    FeatureToAISMap::const_iterator aFIt = myFeature2AISObjectMap.begin(),
-                                    aFLast = myFeature2AISObjectMap.end();
-    for (; aFIt != aFLast && !aFeature; aFIt++) {
-      Handle(AIS_InteractiveObject) anAIS = (*aFIt).second;
-      if (anAIS != anIO)
-        continue;
-      aFeature = (*aFIt).first;
-    }
+    boost::shared_ptr<ModelAPI_Feature> aFeature = GetFeature(anIO);
+    if (aPrsFeatures.find(aFeature) != aPrsFeatures.end())
+      continue;
+    aPresentations.push_back(XGUI_ViewerPrs(aFeature, aShape));
+    aPrsFeatures.insert(aFeature);
+  }
+  return aPresentations;
+}
+
+std::list<XGUI_ViewerPrs> XGUI_Displayer::GetHighlighted(const int theShapeTypeToSkip)
+{
+  std::set<boost::shared_ptr<ModelAPI_Feature> > aPrsFeatures;
+  std::list<XGUI_ViewerPrs> aPresentations;
+
+  Handle(AIS_InteractiveContext) aContext = AISContext();
+  for (aContext->InitDetected(); aContext->MoreDetected(); aContext->NextDetected()) {
+    Handle(AIS_InteractiveObject) anIO = aContext->DetectedInteractive();
+    TopoDS_Shape aShape = aContext->DetectedShape();
+    if (theShapeTypeToSkip >= 0 && !aShape.IsNull() && aShape.ShapeType() == theShapeTypeToSkip)
+      continue;
+
+    boost::shared_ptr<ModelAPI_Feature> aFeature = GetFeature(anIO);
     if (aPrsFeatures.find(aFeature) != aPrsFeatures.end())
       continue;
     aPresentations.push_back(XGUI_ViewerPrs(aFeature, aShape));
@@ -107,6 +125,9 @@ void XGUI_Displayer::Redisplay(boost::shared_ptr<ModelAPI_Feature> theFeature,
   if (!aContext->HasOpenedContext()) {
     aContext->ClearCurrents(false);
     aContext->OpenLocalContext(false/*use displayed objects*/, true/*allow shape decomposition*/);
+    // set mouse sensitivity
+    //aContext->SetSensitivityMode(StdSelect_SM_WINDOW);
+    //aContext->SetPixelTolerance(MOUSE_SENSITIVITY_IN_PIXEL);
   }
   // display or redisplay presentation
   Handle(AIS_Shape) anAIS;
@@ -203,7 +224,12 @@ void XGUI_Displayer::SetSelected(const std::list<XGUI_ViewerPrs>& theFeatures, c
   boost::shared_ptr<ModelAPI_Feature> aFeature;
 
   Handle(AIS_Shape) anAIS;
-  aContext->ClearSelected();
+  // we need to unhighligth objects manually in the current local context
+  // in couple with the selection clear (TODO)
+  Handle(AIS_LocalContext) aLocalContext = aContext->LocalContext();
+  if (!aLocalContext.IsNull())
+    aLocalContext->UnhilightLastDetected(myWorkshop->viewer()->activeView());
+  aContext->ClearSelected(false);
 
   for (; anIt != aLast; anIt++) {
     aFeature = (*anIt).feature();
@@ -213,6 +239,7 @@ void XGUI_Displayer::SetSelected(const std::list<XGUI_ViewerPrs>& theFeatures, c
       continue;
     aContext->AddOrRemoveSelected(anAIS, false);
   }
   if (isUpdateViewer)
     aContext->UpdateCurrentViewer();
 }
@@ -267,10 +294,24 @@ void XGUI_Displayer::EraseDeletedFeatures(const bool isUpdateViewer)
 
 void XGUI_Displayer::CloseLocalContexts(const bool isUpdateViewer)
 {
-  closeAllContexts(true);
+  CloseAllContexts(true);
+}
+
+boost::shared_ptr<ModelAPI_Feature> XGUI_Displayer::GetFeature(Handle(AIS_InteractiveObject) theIO)
+{
+  boost::shared_ptr<ModelAPI_Feature> aFeature;
+  FeatureToAISMap::const_iterator aFIt = myFeature2AISObjectMap.begin(),
+                                  aFLast = myFeature2AISObjectMap.end();
+  for (; aFIt != aFLast && !aFeature; aFIt++) {
+    Handle(AIS_InteractiveObject) anAIS = (*aFIt).second;
+    if (anAIS != theIO)
+      continue;
+    aFeature = (*aFIt).first;
+  }
+  return aFeature;
 }
 
-void XGUI_Displayer::closeAllContexts(const bool isUpdateViewer)
+void XGUI_Displayer::CloseAllContexts(const bool isUpdateViewer)
 {
   Handle(AIS_InteractiveContext) ic = AISContext();
   if (!ic.IsNull()) {
index 5973cd67e6d1ce064356503dff519a7b2514201e..4dc28389fe72f1c51ebcfdad13b442142625eb50 100644 (file)
@@ -58,9 +58,15 @@ public:
   //void Display(boost::shared_ptr<ModelAPI_Feature> theFeature, const TopoDS_Shape& theShape,
   //             const bool isUpdateViewer = true);
   
-  /// Returns a list of viewer presentations
+  /// Returns a list of viewer selected presentations
+  /// \param theShapeTypeToSkip the shapes with this type will be skipped during the result list build
   /// \return list of presentations
-  std::list<XGUI_ViewerPrs> GetViewerPrs();
+  std::list<XGUI_ViewerPrs> GetSelected(const int theShapeTypeToSkip = -1);
+
+  /// Returns a list of viewer highlited presentations
+  /// \param theShapeTypeToSkip the shapes with this type will be skipped during the result list build
+  /// \return list of presentations
+  std::list<XGUI_ViewerPrs> GetHighlighted(const int theShapeTypeToSkip = -1);
 
   /// Display the shape and activate selection of sub-shapes
   /// \param theFeature a feature instance
@@ -111,9 +117,13 @@ public:
   void UpdateViewer();
 
 protected:
+  /// Searches the feature by interactive object
+  /// \param theIO an interactive object
+  /// \return feature the feature or NULL if it not visualized
+  boost::shared_ptr<ModelAPI_Feature> GetFeature(Handle(AIS_InteractiveObject) theIO);
   /// Deactivate local selection
   /// \param isUpdateViewer the state wether the viewer should be updated immediatelly
-  void closeAllContexts(const bool isUpdateViewer);
+  void CloseAllContexts(const bool isUpdateViewer);
 
   /// Returns currently installed AIS_InteractiveContext
   Handle(AIS_InteractiveContext) AISContext() const;
index 30d3b9a0fc85be7dc854d794ae1e296df1f14344..d1ca2c2ed4b895c46237f14eeb63322c674fe33b 100644 (file)
@@ -49,73 +49,80 @@ void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage)
   // Created object event *******************
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    FeaturePtr aFeature = aUpdMsg->feature();
-    DocumentPtr aDoc = aFeature->document();
-
-    if (aDoc == myDocument) {  // If root objects
-      if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
-        // Add a new part
-        int aStart = myPartModels.size() + 1;
-        XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
-        aModel->setPartId(myPartModels.count());
-        myPartModels.append(aModel);
-        insertRow(aStart, partFolderNode());
-      } else { // Update top groups (other except parts
-        QModelIndex aIndex = myModel->findParent(aFeature);
-        int aStart = myModel->rowCount(aIndex) - 1;
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        insertRow(aStart, aIndex);
-      }
-    } else { // if sub-objects of first level nodes
-      XGUI_PartModel* aPartModel = 0;
-      QList<XGUI_PartModel*>::const_iterator aIt;
-      for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
-        if ((*aIt)->hasDocument(aDoc)) {
-          aPartModel = (*aIt);
-          break;
+    std::set<FeaturePtr> aFeatures = aUpdMsg->features();
+
+    std::set<FeaturePtr>::const_iterator aIt;
+    for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+      FeaturePtr aFeature = (*aIt);
+      DocumentPtr aDoc = aFeature->document();
+      if (aDoc == myDocument) {  // If root objects
+        if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
+          // Add a new part
+          int aStart = myPartModels.size() + 1;
+          XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
+          aModel->setPartId(myPartModels.count());
+          myPartModels.append(aModel);
+          insertRow(aStart, partFolderNode());
+        } else { // Update top groups (other except parts
+          QModelIndex aIndex = myModel->findParent(aFeature);
+          int aStart = myModel->rowCount(aIndex) - 1;
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          insertRow(aStart, aIndex);
+        }
+      } else { // if sub-objects of first level nodes
+        XGUI_PartModel* aPartModel = 0;
+        QList<XGUI_PartModel*>::const_iterator aIt;
+        for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
+          if ((*aIt)->hasDocument(aDoc)) {
+            aPartModel = (*aIt);
+            break;
+          }
+        }
+        if (aPartModel) {
+          QModelIndex aIndex = aPartModel->findParent(aFeature);
+          int aStart = aPartModel->rowCount(aIndex) - 1;
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          insertRow(aStart, aIndex);
         }
-      }
-      if (aPartModel) {
-        QModelIndex aIndex = aPartModel->findParent(aFeature);
-        int aStart = aPartModel->rowCount(aIndex) - 1;
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        insertRow(aStart, aIndex);
       }
     }
-
   // Deleted object event ***********************
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED)) {
     const Model_FeatureDeletedMessage* aUpdMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
     DocumentPtr aDoc = aUpdMsg->document();
-
-    if (aDoc == myDocument) {  // If root objects
-      if (aUpdMsg->group().compare(PARTS_GROUP) == 0) { // Updsate only Parts group
-        int aStart = myPartModels.size();
-        removeSubModel(myPartModels.size() - 1);
-        removeRow(aStart, partFolderNode());
-      } else { // Update top groups (other except parts
-        QModelIndex aIndex = myModel->findGroup(aUpdMsg->group());
-        int aStart = myModel->rowCount(aIndex);
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        removeRow(aStart, aIndex);
-      }
-    } else {
-      XGUI_PartModel* aPartModel = 0;
-      QList<XGUI_PartModel*>::const_iterator aIt;
-      for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
-        if ((*aIt)->hasDocument(aDoc)) {
-          aPartModel = (*aIt);
-          break;
+    std::set<std::string> aGroups = aUpdMsg->groups();
+
+    std::set<std::string>::const_iterator aIt;
+    for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
+      std::string aGroup = (*aIt);
+      if (aDoc == myDocument) {  // If root objects
+        if (aGroup.compare(PARTS_GROUP) == 0) { // Updsate only Parts group
+          int aStart = myPartModels.size() - 1;
+          removeSubModel(aStart);
+          removeRow(aStart, partFolderNode());
+        } else { // Update top groups (other except parts
+          QModelIndex aIndex = myModel->findGroup(aGroup);
+          int aStart = myModel->rowCount(aIndex);
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          removeRow(aStart, aIndex);
+        }
+      } else {
+        XGUI_PartModel* aPartModel = 0;
+        QList<XGUI_PartModel*>::const_iterator aIt;
+        for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
+          if ((*aIt)->hasDocument(aDoc)) {
+            aPartModel = (*aIt);
+            break;
+          }
+        }
+        if (aPartModel) {
+          QModelIndex aIndex = aPartModel->findGroup(aGroup);
+          int aStart = aPartModel->rowCount(aIndex);
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          removeRow(aStart, aIndex);
         }
-      }
-      if (aPartModel) {
-        QModelIndex aIndex = aPartModel->findGroup(aUpdMsg->group());
-        int aStart = aPartModel->rowCount(aIndex);
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        removeRow(aStart, aIndex);
       }
     }
-
   // Deleted object event ***********************
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED)) {
     //const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
index 4b8c9e0918f1ff863213d116d277b848b610dc39..1400fc0ccc7f4c502b092cbdae6bc5b93cd4532b 100644 (file)
@@ -14,6 +14,7 @@
 #include <QDockWidget>
 #include <QApplication>
 #include <QTimer>
+#include <QCloseEvent>
 
 XGUI_MainWindow::XGUI_MainWindow(QWidget* parent)
     : QMainWindow(parent), 
@@ -197,4 +198,10 @@ void XGUI_MainWindow::onViewActivated(QMdiSubWindow* theSubWnd)
     if (aAct->isCheckable())
       aAct->setChecked(aAct->text() == aWndTitle);
   }
-}
\ No newline at end of file
+}
+
+void XGUI_MainWindow::closeEvent(QCloseEvent * event)
+{
+  emit exitKeySequence();
+  event->ignore();
+}
index 9b29ec3ea17d48f77809ee283684e1e94e2b1b76..010f9e309530b3cb12289015b259a85908bfdcee 100644 (file)
@@ -11,6 +11,7 @@ class XGUI_ViewWindow;
 class QMdiArea;
 class QMdiSubWindow;
 class PyConsole_EnhConsole;
+class QCloseEvent;
 
 /**\class XGUI_MainWindow
  * \ingroup GUI
@@ -53,6 +54,12 @@ private slots:
   void activateView();
   void onViewActivated(QMdiSubWindow* theSubWnd);
 
+signals:
+  void exitKeySequence();
+
+protected:
+  void closeEvent(QCloseEvent* event);
+
 private:
   XGUI_MainMenu* myMenuBar;
   XGUI_Viewer* myViewer;
index 352fa4ba8dd1fdf9f0da2b0fdec87c83a2cd8e37..702c44fef8cd696cfcff8fb55c68b14ca98dfec1 100644 (file)
@@ -4,6 +4,7 @@
 #include <ModelAPI_Data.h>
 #include <ModelAPI_PluginManager.h>
 #include <ModelAPI_Document.h>
+#include <ModelAPI_Object.h>
 
 #include <QLayout>
 #include <QLabel>
@@ -82,7 +83,12 @@ void XGUI_DataTree::commitData(QWidget* theEditor)
   if (aEditor) {
     QString aRes = aEditor->text();
     FeaturePtr aFeature = mySelectedData.first();
-    aFeature->data()->setName(qPrintable(aRes));
+    aFeature->document()->startOperation();
+    if (aFeature->data())
+      aFeature->data()->setName(qPrintable(aRes));
+    else
+      boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature)->setName(qPrintable(aRes));
+    aFeature->document()->finishOperation();
   }
 }
 
@@ -289,7 +295,8 @@ void XGUI_ObjectsBrowser::onEditItem()
       // Find index which corresponds the feature
       QModelIndex aIndex;
       foreach(QModelIndex aIdx, selectedIndexes()) {
-        if (dataModel()->feature(aIdx) == aFeature) {
+        FeaturePtr aFea = dataModel()->feature(aIdx);
+        if (dataModel()->feature(aIdx)->isSame(aFeature)) {
           aIndex = aIdx;
           break;
         }
index ad312dad5c99de848390a0f352ace60621f3675f..2a27188c9e9447073a6147681c192c4fe67bcc04 100644 (file)
@@ -57,6 +57,15 @@ bool XGUI_OperationMgr::abortOperation()
   return true;
 }
 
+QStringList XGUI_OperationMgr::operationList()
+{
+  QStringList result;
+  foreach(ModuleBase_Operation* eachOperation, myOperations) {
+    result << eachOperation->id();
+  }
+  return result;
+}
+
 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
 {
   theOperation->resume();
@@ -106,11 +115,11 @@ void XGUI_OperationMgr::onOperationStopped()
   if (!aSenderOperation || !anOperation || aSenderOperation != anOperation )
     return;
 
-  emit operationStopped(anOperation);
-
   myOperations.removeAll(anOperation);
   anOperation->deleteLater();
 
+  emit operationStopped(anOperation);
+
   // get last operation which can be resumed
   ModuleBase_Operation* aResultOp = 0;
   QListIterator<ModuleBase_Operation*> anIt(myOperations);
index 169453b3afd028d40ae7bd888fb4231f5a8d1549..56db2c4c57710f5219401ff32f655cc9805e2d72 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <QList>
 #include <QObject>
+#include <QStringList>
 
 /**\class XGUI_OperationMgr
  * \ingroup GUI
@@ -46,6 +47,8 @@ public:
   /// Abort the operation and append it to the stack of operations
   /// \return the state whether the current operation is aborted
   bool abortOperation();
+  ///Returns list of all operations IDs
+  QStringList operationList();
 
 signals:
   /// Signal about an operation is started. It is emitted after the start() of operation is done.
index 6610b64c58ff15dcbbe5b5268c7224188ad021c9..dc09185cc52be72def60de75adb7ccdb4e99c953 100644 (file)
@@ -41,17 +41,17 @@ QVariant XGUI_TopDataModel::data(const QModelIndex& theIndex, int theRole) const
       return tr("Parameters") + QString(" (%1)").arg(rowCount(theIndex));
     case ParamObject:
       {
-        FeaturePtr aFeature = myDocument->feature(PARAMETERS_GROUP, theIndex.row(), true);
+        FeaturePtr aFeature = myDocument->feature(PARAMETERS_GROUP, theIndex.row());
         if (aFeature)
-          return aFeature->data()->getName().c_str();
+          return boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature)->getName().c_str();
       } 
     case ConstructFolder:
         return tr("Constructions") + QString(" (%1)").arg(rowCount(theIndex));
     case ConstructObject:
       {
-        FeaturePtr aFeature = myDocument->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+        FeaturePtr aFeature = myDocument->feature(CONSTRUCTIONS_GROUP, theIndex.row());
         if (aFeature)
-          return aFeature->data()->getName().c_str();
+          return boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature)->getName().c_str();
       }
     }
     break;
@@ -65,7 +65,7 @@ QVariant XGUI_TopDataModel::data(const QModelIndex& theIndex, int theRole) const
       return QIcon(":pictures/constr_folder.png");
     case ConstructObject:
       {
-        FeaturePtr aFeature = myDocument->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+        FeaturePtr aFeature = myDocument->feature(CONSTRUCTIONS_GROUP, theIndex.row());
         if (aFeature)
           return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
       }
@@ -152,9 +152,9 @@ FeaturePtr XGUI_TopDataModel::feature(const QModelIndex& theIndex) const
   case ConstructFolder:
     return FeaturePtr();
   case ParamObject:
-    return myDocument->feature(PARAMETERS_GROUP, theIndex.row(), true);
+    return myDocument->feature(PARAMETERS_GROUP, theIndex.row());
   case ConstructObject:
-    return myDocument->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+    return myDocument->feature(CONSTRUCTIONS_GROUP, theIndex.row());
   }
   return FeaturePtr();
 }
@@ -182,7 +182,7 @@ QModelIndex XGUI_TopDataModel::featureIndex(const FeaturePtr& theFeature) const
     int aNb = myDocument->size(aGroup);
     int aRow = -1;
     for (int i = 0; i < aNb; i++) {
-      if (myDocument->feature(aGroup, i, true) == theFeature) {
+      if (myDocument->feature(aGroup, i) == theFeature) {
         aRow = i;
         break;
       }
@@ -220,9 +220,9 @@ QVariant XGUI_PartDataModel::data(const QModelIndex& theIndex, int theRole) cons
     switch (theIndex.internalId()) {
     case MyRoot:
       {
-        FeaturePtr aFeature = myDocument->feature(PARTS_GROUP, myId, true);
+        FeaturePtr aFeature = myDocument->feature(PARTS_GROUP, myId);
         if (aFeature)
-          return aFeature->data()->getName().c_str();
+          return boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature)->getName().c_str();
       }
     case ParamsFolder:
       return tr("Parameters") + QString(" (%1)").arg(rowCount(theIndex));
@@ -232,19 +232,19 @@ QVariant XGUI_PartDataModel::data(const QModelIndex& theIndex, int theRole) cons
       return tr("Bodies") + QString(" (%1)").arg(rowCount(theIndex));
     case ParamObject:
       {
-        FeaturePtr aFeature = featureDocument()->feature(PARAMETERS_GROUP, theIndex.row(), true);
+        FeaturePtr aFeature = featureDocument()->feature(PARAMETERS_GROUP, theIndex.row());
         if (aFeature)
-          return aFeature->data()->getName().c_str();
+          return boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature)->getName().c_str();
       }
     case ConstructObject:
       {
-        FeaturePtr aFeature = featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+        FeaturePtr aFeature = featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row());
         if (aFeature)
-          return aFeature->data()->getName().c_str();
+          return boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature)->getName().c_str();
       }
     case HistoryObject:
       {
-        FeaturePtr aFeature = featureDocument()->feature(FEATURES_GROUP, theIndex.row() - 3, true);
+        FeaturePtr aFeature = featureDocument()->feature(FEATURES_GROUP, theIndex.row() - 3);
         if (aFeature)
           return aFeature->data()->getName().c_str();
       }
@@ -262,13 +262,13 @@ QVariant XGUI_PartDataModel::data(const QModelIndex& theIndex, int theRole) cons
       return QIcon(":pictures/constr_folder.png");
     case ConstructObject:
       {
-        FeaturePtr aFeature = featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+        FeaturePtr aFeature = featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row());
         if (aFeature)
           return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
       }
     case HistoryObject:
       {
-        FeaturePtr aFeature = featureDocument()->feature(FEATURES_GROUP, theIndex.row() - 3, true);
+        FeaturePtr aFeature = featureDocument()->feature(FEATURES_GROUP, theIndex.row() - 3);
         if (aFeature)
           return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
       }
@@ -292,7 +292,7 @@ QVariant XGUI_PartDataModel::headerData(int section, Qt::Orientation orientation
 int XGUI_PartDataModel::rowCount(const QModelIndex& parent) const
 {
   if (!parent.isValid()) 
-    if (myDocument->feature(PARTS_GROUP, myId, true))
+    if (myDocument->feature(PARTS_GROUP, myId))
       return 1;
     else 
       return 0;
@@ -376,20 +376,19 @@ FeaturePtr XGUI_PartDataModel::feature(const QModelIndex& theIndex) const
 {
   switch (theIndex.internalId()) {
   case MyRoot:
-    if (theIndex.row() < 3) {
-      return myDocument->feature(PARTS_GROUP, myId, true);
-    } else 
-      return featureDocument()->feature(FEATURES_GROUP, theIndex.row() - 3, true);
+    return myDocument->feature(PARTS_GROUP, myId);
   case ParamsFolder:
   case ConstructFolder:
   case BodiesFolder:
     return FeaturePtr();
   case ParamObject:
-    return featureDocument()->feature(PARAMETERS_GROUP, theIndex.row(), true);
+    return featureDocument()->feature(PARAMETERS_GROUP, theIndex.row());
   case ConstructObject:
-    return featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+    return featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row());
   //case BodiesObject:
-  //  return featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row(), true);
+  //  return featureDocument()->feature(CONSTRUCTIONS_GROUP, theIndex.row());
+  case HistoryObject:
+    return featureDocument()->feature(FEATURES_GROUP, theIndex.row() - 3); 
   }
   return FeaturePtr();
 }
@@ -430,7 +429,7 @@ QModelIndex XGUI_PartDataModel::featureIndex(const FeaturePtr& theFeature) const
     int aNb = myDocument->size(aGroup);
     int aRow = -1;
     for (int i = 0; i < aNb; i++) {
-      if (myDocument->feature(aGroup, i, true) == theFeature) {
+      if (myDocument->feature(aGroup, i) == theFeature) {
         aRow = i;
         break;
       }
index 5067484718d39a2fc1d9fbea5983ce0f6ca6da17..ccf0469cfc2944b3d30b38fce8fbc867bbfcca27 100644 (file)
@@ -24,6 +24,7 @@ XGUI_PropertyPanel::XGUI_PropertyPanel(QWidget* theParent)
   this->setWindowTitle(tr("Property Panel"));
   QAction* aViewAct = this->toggleViewAction();
   this->setObjectName(XGUI::PROP_PANEL);
+  setStyleSheet("::title { position: relative; padding-left: 5px; text-align: left center }");
 
   QWidget* aContent = new QWidget(this);
   QVBoxLayout* aMainLay = new QVBoxLayout(aContent);
index 734a1a469e48ab9ff6bbed1d29a8302e6c63ab13..3d5af347ade6fc484c4c3f65ec9856abe9ff698f 100644 (file)
@@ -506,9 +506,9 @@ void XGUI_Viewer::onMousePressed(XGUI_ViewWindow* theWindow, QMouseEvent* theEve
 */
 void XGUI_Viewer::onMouseMove(XGUI_ViewWindow* theWindow, QMouseEvent* theEvent)
 {
+  myCurPnt.setX(theEvent->x()); myCurPnt.setY(theEvent->y());
   if (!mySelectionEnabled) return;
 
-  myCurPnt.setX(theEvent->x()); myCurPnt.setY(theEvent->y());
   Handle(V3d_View) aView3d = theWindow->viewPort()->getView();
   if ( !aView3d.IsNull() ) {
     myAISContext->MoveTo(theEvent->x(), theEvent->y(), aView3d);
index d095b1cb4c35a3dfb97e05a8191b3a0f7a55b7d8..389f81420925586f6724787be794a2a9e1a964bb 100644 (file)
@@ -70,7 +70,7 @@ QString XGUI_Workshop::featureIcon(const std::string& theId)
 
 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
   : QObject(),
-  myCurrentFile(QString()),
+  myCurrentDir(QString()),
   myPartSetModule(NULL),
   mySalomeConnector(theConnector),
   myPropertyPanel(0),
@@ -92,10 +92,12 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
 
   myViewerProxy = new XGUI_ViewerProxy(this);
 
-  connect(myOperationMgr, SIGNAL(operationStarted()),  this, SLOT(onOperationStarted()));
-  connect(myOperationMgr, SIGNAL(operationResumed()),  this, SLOT(onOperationStarted()));
-  connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
-          this, SLOT(onOperationStopped(ModuleBase_Operation*)));
+  connect(myOperationMgr, SIGNAL(operationStarted()), SLOT(onOperationStarted()));
+  connect(myOperationMgr, SIGNAL(operationResumed()), SLOT(onOperationStarted()));
+  connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)), SLOT(onOperationStopped(ModuleBase_Operation*)));
+  connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
+  connect(myOperationMgr, SIGNAL(operationStarted()), myActionsMgr, SLOT(update()));
+  connect(myOperationMgr, SIGNAL(operationStopped()), myActionsMgr, SLOT(update()));
   connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&)));
 }
 
@@ -188,6 +190,12 @@ void XGUI_Workshop::initMenu()
   aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"),
                                 QIcon(":pictures/close.png"), QKeySequence::Close);
   aCommand->connectTo(this, SLOT(onExit()));
+  //FIXME: SBH's test action. Can be used for some GUI tests.
+  //#ifdef _DEBUG
+  //  aCommand = aGroup->addFeature("TEST_CMD", "Test!", "Private debug button",
+  //                                QIcon(":pictures/close.png"));
+  //  aCommand->connectTo(myActionsMgr, SLOT(update()));
+  //#endif
 }
 
 //******************************************************
@@ -204,14 +212,26 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
   static Events_ID aFeatureLoadedId = Events_Loop::loop()->eventByName(EVENT_FEATURE_LOADED);
   if (theMessage->eventID() == aFeatureLoadedId) {
     const Config_FeatureMessage* aFeatureMsg = dynamic_cast<const Config_FeatureMessage*>(theMessage);
-    addFeature(aFeatureMsg);
+    if(!aFeatureMsg->isInternal()) {
+      addFeature(aFeatureMsg);
+    }
     return;
   }
   // Process creation of Part
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    FeaturePtr aFeature = aUpdMsg->feature();
-    if (aFeature->getKind() == "Part") {
+    std::set<FeaturePtr> aFeatures = aUpdMsg->features();
+
+    std::set<FeaturePtr>::const_iterator aIt;
+    bool aHasPart = false;
+    for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+      FeaturePtr aFeature = (*aIt);
+      if (aFeature->getKind() == "Part") {
+        aHasPart = true;
+        break;
+      }
+    }
+    if (aHasPart) {
       //The created part will be created in Object Browser later and we have to activate it
       // only when it is created everywere
       QTimer::singleShot(50, this, SLOT(activateLastPart()));
@@ -232,10 +252,16 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
   {
     const Model_FeatureUpdatedMessage* anUpdateMsg =
         dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    FeaturePtr aNewFeature = anUpdateMsg->feature();
+    std::set<FeaturePtr> aFeatures = anUpdateMsg->features();
+
     FeaturePtr aCurrentFeature = myOperationMgr->currentOperation()->feature();
-    if(aNewFeature == aCurrentFeature) {
-      myPropertyPanel->updateContentWidget(aCurrentFeature);
+    std::set<FeaturePtr>::const_iterator aIt;
+    for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+      FeaturePtr aNewFeature = (*aIt);
+      if(aNewFeature == aCurrentFeature) {
+        myPropertyPanel->updateContentWidget(aCurrentFeature);
+        break;
+      } 
     }
   }
   //An operation passed by message. Start it, process and commit.
@@ -286,18 +312,9 @@ void XGUI_Workshop::onOperationStarted()
 //******************************************************
 void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
 {
-  ModuleBase_Operation* aOperation = myOperationMgr->currentOperation();
-
   //!< No need for property panel
   updateCommandStatus();
   hidePropertyPanel();
-  if(myOperationMgr->operationsCount() > 1) {
-    myActionsMgr->updateAction(theOperation->getDescription()->operationId());
-    return;
-  }
-  if(!aOperation->getDescription()->xmlRepresentation().isEmpty()) { 
-    myActionsMgr->restoreCommandState();
-  }
 }
 
 /*
@@ -318,8 +335,8 @@ void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
   QString aWchName = QString::fromStdString(theMessage->workbenchId());
   QString aNestedFeatures = QString::fromStdString(theMessage->nestedFeatures());
   bool isUsePropPanel = theMessage->isUseInput();
+  QString aId = QString::fromStdString(theMessage->id());
   if (isSalomeMode()) {
-    QString aId = QString::fromStdString(theMessage->id());
     QAction* aAction = salomeConnector()->addFeature(aWchName,
                               aId,
                               QString::fromStdString(theMessage->text()),
@@ -343,12 +360,12 @@ void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
       aGroup = aPage->addGroup(aGroupName);
     }
     //Create feature...
-    XGUI_Command* aCommand = aGroup->addFeature(QString::fromStdString(theMessage->id()),
+    XGUI_Command* aCommand = aGroup->addFeature(aId,
                                                 QString::fromStdString(theMessage->text()),
                                                 QString::fromStdString(theMessage->tooltip()),
                                                 QIcon(theMessage->icon().c_str()),
                                                 QKeySequence(), isUsePropPanel);
-    aCommand->setUnblockableCommands(aNestedFeatures.split(" "));
+    aCommand->setNestedCommands(aNestedFeatures.split(" ", QString::SkipEmptyParts));
     myActionsMgr->addCommand(aCommand);
     myPartSetModule->featureCreated(aCommand);
   }
@@ -395,7 +412,10 @@ void XGUI_Workshop::onExit()
         tr("The document is modified, save before exit?"),
         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
     if(anAnswer == QMessageBox::Save) {
-      onSave();
+      bool saved = onSave();
+      if(!saved) {
+        return;
+      }
     } else if (anAnswer == QMessageBox::Cancel) {
       return;
     }
@@ -440,51 +460,63 @@ void XGUI_Workshop::onOpen()
       return;
     }
     aDoc->close();
-    myCurrentFile = "";
+    myCurrentDir = "";
   }
 
   //show file dialog, check if readable and open
-  myCurrentFile = QFileDialog::getExistingDirectory(mainWindow());
-  if(myCurrentFile.isEmpty())
+  myCurrentDir = QFileDialog::getExistingDirectory(mainWindow());
+  if(myCurrentDir.isEmpty())
     return;
-  QFileInfo aFileInfo(myCurrentFile);
+  QFileInfo aFileInfo(myCurrentDir);
   if(!aFileInfo.exists() || !aFileInfo.isReadable()) {
     QMessageBox::critical(myMainWindow, tr("Warning"), tr("Unable to open the file."));
-    myCurrentFile = "";
+    myCurrentDir = "";
     return;
   }
   QApplication::setOverrideCursor(Qt::WaitCursor);
-  aDoc->load(myCurrentFile.toLatin1().constData());
+  aDoc->load(myCurrentDir.toLatin1().constData());
   QApplication::restoreOverrideCursor();
   updateCommandStatus();
 }
 
 //******************************************************
-void XGUI_Workshop::onSave()
+bool XGUI_Workshop::onSave()
 {
-  if(myCurrentFile.isEmpty()) {
-    onSaveAs();
-    return;
+  if(myCurrentDir.isEmpty()) {
+    return onSaveAs();
   }
-  saveDocument(myCurrentFile);
+  saveDocument(myCurrentDir);
   updateCommandStatus();
+  return true;
 }
 
 //******************************************************
-void XGUI_Workshop::onSaveAs()
+bool XGUI_Workshop::onSaveAs()
 {
-  QString aTemp = myCurrentFile;
-  myCurrentFile = QFileDialog::getSaveFileName(mainWindow());
-  if(myCurrentFile.isEmpty()) {
-    myCurrentFile = aTemp;
-    return;
+  QFileDialog dialog(mainWindow());
+  dialog.setWindowTitle(tr("Select directory to save files..."));
+  dialog.setFileMode(QFileDialog::Directory);
+  dialog.setFilter(tr("Folders (*)"));
+  dialog.setOptions(QFileDialog::HideNameFilterDetails | QFileDialog::ShowDirsOnly);
+  dialog.setViewMode(QFileDialog::Detail);
+
+  if(!dialog.exec()) {
+    return false;
   }
-  QFileInfo aFileInfo(myCurrentFile);
-  if(aFileInfo.exists() && !aFileInfo.isWritable()) {
-    QMessageBox::critical(myMainWindow, tr("Warning"), tr("Unable to save the file."));
-    return;
+  QString aTempDir = dialog.selectedFiles().first();
+  QDir aDir(aTempDir);
+  if(aDir.exists() && !aDir.entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries).isEmpty()) {
+    int answer = QMessageBox::question(myMainWindow,
+                                       //: Title of the dialog which asks user if he wants to save study in existing non-empty folder
+                                       tr("Save"),
+                                       tr("The folder already contains some files, save anyway?"),
+                                       QMessageBox::Save|QMessageBox::Cancel);
+    if(answer == QMessageBox::Cancel) {
+      return false;
+    }
   }
-  onSave();
+  myCurrentDir = aTempDir;
+  return onSave();
 }
 
 //******************************************************
@@ -579,6 +611,7 @@ bool XGUI_Workshop::activateModule()
   if (!myPartSetModule)
     return false;
   myPartSetModule->createFeatures();
+  myActionsMgr->update();
   return true;
 }
 
@@ -620,6 +653,7 @@ void XGUI_Workshop::updateCommandStatus()
         aCmd->setEnabled(false);
     }
   }
+  myActionsMgr->update();
 }
 
 //******************************************************
@@ -628,6 +662,7 @@ QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
   QDockWidget* aObjDock = new QDockWidget(theParent);
   aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
   aObjDock->setWindowTitle(tr("Object browser"));
+  aObjDock->setStyleSheet("::title { position: relative; padding-left: 5px; text-align: left center }");
   myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock);
   connect(myObjectBrowser, SIGNAL(activePartChanged(FeaturePtr)), this, SLOT(changeCurrentDocument(FeaturePtr)));
   aObjDock->setWidget(myObjectBrowser);
@@ -706,9 +741,15 @@ void XGUI_Workshop::changeCurrentDocument(FeaturePtr thePart)
 {
   PluginManagerPtr aMgr = ModelAPI_PluginManager::get();
   if (thePart) {
-    boost::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = thePart->data()->docRef("PartDocument");
-    if (aDocRef)
-      aMgr->setCurrentDocument(aDocRef->value());
+    DocumentPtr aFeaDoc;
+    if (thePart->data()) {
+      aFeaDoc = thePart->data()->docRef("PartDocument")->value();
+    } else {
+      ObjectPtr aObject = boost::dynamic_pointer_cast<ModelAPI_Object>(thePart);
+      aFeaDoc = aObject->featureRef()->data()->docRef("PartDocument")->value();
+    }
+    if (aFeaDoc)
+      aMgr->setCurrentDocument(aFeaDoc);
   } else {
     aMgr->setCurrentDocument(aMgr->rootDocument());
   }
@@ -763,9 +804,29 @@ void XGUI_Workshop::deleteFeatures(QFeatureList theList)
                                                           tr("Seleted features will be deleted. Continue?"), 
                                                           QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
   if (aRes == QMessageBox::Yes) {
+    PluginManagerPtr aMgr = ModelAPI_PluginManager::get();
+    aMgr->rootDocument()->startOperation();
     foreach (FeaturePtr aFeature, theList) {
-      DocumentPtr aDoc = aFeature->data()->docRef("PartDocument")->value();
-      aDoc->removeFeature(aFeature);
+      if (aFeature->getKind() == "Part") {
+        DocumentPtr aDoc;
+        if (aFeature->data()) {
+          aDoc = aFeature->data()->docRef("PartDocument")->value();
+        } else {
+          ObjectPtr aObject = boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature);
+          aDoc = aObject->featureRef()->data()->docRef("PartDocument")->value();
+          aFeature = aObject->featureRef();
+        }
+        if (aDoc == aMgr->currentDocument()) {
+          aDoc->close();
+        }
+      } else {
+        if (!aFeature->data()) {
+          ObjectPtr aObject = boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature);
+          aFeature = aObject->featureRef();
+        }
+      }
+      aFeature->document()->removeFeature(aFeature);
     }
+    aMgr->rootDocument()->finishOperation();
   }
 }
index 21ee4a87b6cd86f755b56630bcc2a7c42b231648..42d893f1d116e3de7486a1d05be0d93545902d40 100644 (file)
@@ -113,8 +113,8 @@ public slots:
 
   void onNew();
   void onOpen();
-  void onSave();
-  void onSaveAs();
+  bool onSave();
+  bool onSaveAs();
   void onExit();
   void onUndo();
   void onRedo();
@@ -158,7 +158,6 @@ private:
   // Creates Dock widgets: Object browser and Property panel
   void createDockWidgets();
 
-  QString myCurrentFile;
   XGUI_MainWindow* myMainWindow;
   XGUI_Module* myPartSetModule;
   XGUI_ObjectsBrowser* myObjectBrowser;
@@ -172,6 +171,7 @@ private:
   XGUI_ViewerProxy* myViewerProxy;
   XGUI_ContextMenuMgr* myContextMenuMgr;
 
+  QString myCurrentDir;
   static QMap<QString, QString> myIcons;
 
 };