From: azv Date: Fri, 23 May 2014 11:44:12 +0000 (+0400) Subject: Merge remote-tracking branch 'remotes/origin/master' into SolveSpace X-Git-Tag: V_0.2~8^2^2~2 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=fdfc221732acbce4be6b2c9c444f7c3643812811;hp=bda31925d8f395555581bbe7d4bb01c637ab4630;p=modules%2Fshaper.git Merge remote-tracking branch 'remotes/origin/master' into SolveSpace --- diff --git a/linux_env.sh b/linux_env.sh index 4466e3355..5e0a7f8ab 100644 --- a/linux_env.sh +++ b/linux_env.sh @@ -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 diff --git a/src/Config/Config_FeatureMessage.cpp b/src/Config/Config_FeatureMessage.cpp index 9408522e6..7b0f60337 100644 --- a/src/Config/Config_FeatureMessage.cpp +++ b/src/Config/Config_FeatureMessage.cpp @@ -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; diff --git a/src/Config/Config_FeatureMessage.h b/src/Config/Config_FeatureMessage.h index 99116d707..9328e0690 100644 --- a/src/Config/Config_FeatureMessage.h +++ b/src/Config/Config_FeatureMessage.h @@ -27,6 +27,7 @@ class Config_FeatureMessage: public Events_Message std::string myPluginLibrary; //Name of feature's library bool myUseInput; //Action is being checked until user commit the operation + bool myInternal; //Internal feature without GUI representation std::string myNestedFeatures; public: @@ -45,6 +46,7 @@ public: CONFIG_EXPORT const std::string& pluginLibrary() const; CONFIG_EXPORT const std::string& nestedFeatures() const; CONFIG_EXPORT bool isUseInput() const; + CONFIG_EXPORT bool isInternal() const; CONFIG_EXPORT void setIcon(const std::string& icon); CONFIG_EXPORT void setId(const std::string& id); @@ -56,6 +58,7 @@ public: CONFIG_EXPORT void setPluginLibrary(const std::string& thePluginLibrary); CONFIG_EXPORT void setNestedFeatures(const std::string& theNestedFeatures); CONFIG_EXPORT void setUseInput(bool isUseInput); + CONFIG_EXPORT void setInternal(bool isInternal); }; #endif // CONFIG_MESSAGE_H diff --git a/src/Config/Config_FeatureReader.cpp b/src/Config/Config_FeatureReader.cpp index 78e485e91..6e6bbb85f 100644 --- a/src/Config/Config_FeatureReader.cpp +++ b/src/Config/Config_FeatureReader.cpp @@ -17,6 +17,7 @@ #include #include +#include #ifdef _DEBUG #include @@ -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; } diff --git a/src/Config/Config_FeatureReader.h b/src/Config/Config_FeatureReader.h index e4e7c63db..1add8438d 100644 --- a/src/Config/Config_FeatureReader.h +++ b/src/Config/Config_FeatureReader.h @@ -31,6 +31,7 @@ protected: bool processChildren(xmlNodePtr aNode); void fillFeature(xmlNodePtr theRoot, Config_FeatureMessage& outFeatureMessage); + bool isInternalFeature(xmlNodePtr theRoot); private: std::string myLastWorkbench; diff --git a/src/Config/Config_Keywords.h b/src/Config/Config_Keywords.h index 281248f85..2056a658b 100644 --- a/src/Config/Config_Keywords.h +++ b/src/Config/Config_Keywords.h @@ -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"; diff --git a/src/Config/Config_ModuleReader.cpp b/src/Config/Config_ModuleReader.cpp index e6fdeffde..c533e3e3e 100644 --- a/src/Config/Config_ModuleReader.cpp +++ b/src/Config/Config_ModuleReader.cpp @@ -84,9 +84,6 @@ std::list 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; diff --git a/src/ConstructionPlugin/plugin-Construction.xml b/src/ConstructionPlugin/plugin-Construction.xml index 912d04e0c..8e8699687 100644 --- a/src/ConstructionPlugin/plugin-Construction.xml +++ b/src/ConstructionPlugin/plugin-Construction.xml @@ -1,11 +1,11 @@ - + - - + + diff --git a/src/Events/CMakeLists.txt b/src/Events/CMakeLists.txt index 89a27f31c..af4155f42 100644 --- a/src/Events/CMakeLists.txt +++ b/src/Events/CMakeLists.txt @@ -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 diff --git a/src/Events/Events_Loop.cpp b/src/Events/Events_Loop.cpp index 6c8bb4760..40917a64f 100644 --- a/src/Events/Events_Loop.cpp +++ b/src/Events/Events_Loop.cpp @@ -3,6 +3,7 @@ // Author: Mikhail PONIKAROV #include +#include #include #include @@ -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(&theMessage); + if (aGroup) { + std::map::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 > >::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::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; + } +} diff --git a/src/Events/Events_Loop.h b/src/Events/Events_Loop.h index 893ecb199..d19dd4d4a 100644 --- a/src/Events/Events_Loop.h +++ b/src/Events/Events_Loop.h @@ -11,6 +11,8 @@ #include #include +class Events_MessageGroup; + /**\class Events_Lopp * \ingroup EventsLoop * \brief Base class that manages the receiving and sending of all @@ -22,8 +24,12 @@ * control back immideately. */ class Events_Loop { + /// map from event ID to sender pointer to listeners that must be called for this std::map > > - 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 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 index 000000000..b95f64d87 --- /dev/null +++ b/src/Events/Events_MessageGroup.h @@ -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 + +/**\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 diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index e6c5c02f2..03effc8e3 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -12,6 +12,8 @@ #include #include #include +#include "Model_Events.h" +#include 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) diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 37f1a8673..6343d8b7b 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -161,6 +161,11 @@ bool Model_Document::save(const char* theFileName) void Model_Document::close() { + boost::shared_ptr aPM = Model_PluginManager::get(); + if (this != aPM->rootDocument().get() && + this == aPM->currentDocument().get()) { + aPM->setCurrentDocument(aPM->rootDocument()); + } // close all subs set::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::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::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::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::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::get())-> + setCheckTransactions(true); } diff --git a/src/Model/Model_Document.h b/src/Model/Model_Document.h index b1945bae1..d8fee7e01 100644 --- a/src/Model/Model_Document.h +++ b/src/Model/Model_Document.h @@ -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 > myFeatures; diff --git a/src/Model/Model_Events.cpp b/src/Model/Model_Events.cpp index cbf485997..538305efb 100644 --- a/src/Model/Model_Events.cpp +++ b/src/Model/Model_Events.cpp @@ -5,38 +5,31 @@ #include #include -Model_FeatureDeletedMessage::Model_FeatureDeletedMessage( - const boost::shared_ptr& 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 >& theFeatures) -{ - myFeatures = theFeatures; -} - -const std::list >& 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& 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(&theJoined); +// std::set::iterator aGIter = aJoined->myGroups.begin(); +// for(; aGIter != aJoined->myGroups.end(); aGIter++) { +// myGroups.insert(*aGIter); +// } +//} diff --git a/src/Model/Model_Events.h b/src/Model/Model_Events.h index c9c60b65f..0bce1c980 100644 --- a/src/Model/Model_Events.h +++ b/src/Model/Model_Events.h @@ -6,11 +6,11 @@ #define Model_Events_HeaderFile #include -#include +#include #include #include #include -#include +#include 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 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 > myFeatures; ///< which feature is changed public: /// sender is not important, all information is located in the feature Model_FeatureUpdatedMessage( const boost::shared_ptr& 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 feature() const {return myFeature;} + std::set > features() const {return myFeatures;} + + //! Creates a new empty group (to store it in the loop before flush) + virtual Events_MessageGroup* newEmpty() { + boost::shared_ptr 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(&theJoined); + std::set >::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 myDoc; ///< document owner of the feature - std::string myGroup; ///< group identifier that contained the deleted feature + std::set myGroups; ///< group identifiers that contained the deleted feature public: /// creates a message by initialization of fields - Model_FeatureDeletedMessage(const boost::shared_ptr& theDoc, - const std::string& theGroup); +// Model_FeatureDeletedMessage(const boost::shared_ptr& 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 document() const {return myDoc;} /// Returns the group where the feature was deleted - const std::string& group() const {return myGroup;} -}; + const std::set& groups() const {return myGroups;} -/// Message that features were moved (used for the feature preview update) -class Model_FeaturesMovedMessage : public Events_Message { - std::list > 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& 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 >& 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 >& features() const; + void Join(Events_MessageGroup& theJoined) + { + Model_FeatureDeletedMessage* aJoined = dynamic_cast(&theJoined); + std::set::iterator aGIter = aJoined->myGroups.begin(); + for(; aGIter != aJoined->myGroups.end(); aGIter++) { + myGroups.insert(*aGIter); + } + } }; #endif diff --git a/src/Model/Model_Object.cpp b/src/Model/Model_Object.cpp index 9b39c6d2f..269c547cf 100644 --- a/src/Model/Model_Object.cpp +++ b/src/Model/Model_Object.cpp @@ -4,6 +4,8 @@ #include "Model_Object.h" #include +#include "Model_Events.h" +#include boost::shared_ptr 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(this), anEvent); + Events_Loop::loop()->send(aMsg, false); + */ + } } Model_Object::Model_Object(boost::shared_ptr theRef, diff --git a/src/Model/Model_Object.h b/src/Model/Model_Object.h index 18314c04d..8179d701d 100644 --- a/src/Model/Model_Object.h +++ b/src/Model/Model_Object.h @@ -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 document() + {return myRef->document();} + + /// Returns true if feature refers to the same model data instance + MODEL_EXPORT virtual bool isSame(const boost::shared_ptr& theFeature) + { + boost::shared_ptr anObj = boost::dynamic_pointer_cast(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 theRef, Handle_TDataStd_Name theName); - friend class Model_Document; + friend class Model_Document; }; #endif diff --git a/src/Model/Model_PluginManager.cpp b/src/Model/Model_PluginManager.cpp index 7a0a20d0a..1a6cef9d8 100644 --- a/src/Model/Model_PluginManager.cpp +++ b/src/Model/Model_PluginManager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -97,27 +98,35 @@ boost::shared_ptr 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(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(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(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() diff --git a/src/Model/Model_PluginManager.h b/src/Model/Model_PluginManager.h index aa230700a..4efef6a4c 100644 --- a/src/Model/Model_PluginManager.h +++ b/src/Model/Model_PluginManager.h @@ -26,6 +26,7 @@ class Model_PluginManager : public ModelAPI_PluginManager, public Events_Listene std::map myPluginObjs; ///< instances of the already plugins std::string myCurrentPluginName; ///< name of the plugin that must be loaded currently boost::shared_ptr 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 rootDocument(); @@ -51,6 +52,8 @@ public: MODEL_EXPORT virtual boost::shared_ptr copy( boost::shared_ptr theSource, std::string theID); + void setCheckTransactions(const bool theCheck) {myCheckTransactions = theCheck;} + /// Is called only once, on startup of the application Model_PluginManager(); diff --git a/src/ModelAPI/ModelAPI_Feature.h b/src/ModelAPI/ModelAPI_Feature.h index dd98c597a..bd726461f 100644 --- a/src/ModelAPI/ModelAPI_Feature.h +++ b/src/ModelAPI/ModelAPI_Feature.h @@ -56,6 +56,10 @@ public: MODELAPI_EXPORT virtual boost::shared_ptr document() {return myDoc;} + /// Returns true if feature refers to the same model data instance + MODELAPI_EXPORT virtual bool isSame(const boost::shared_ptr& theFeature) + {return true;} + /// To virtually destroy the fields of successors virtual ~ModelAPI_Feature() {} diff --git a/src/ModelAPI/ModelAPI_PluginManager.cpp b/src/ModelAPI/ModelAPI_PluginManager.cpp index a8d497c7c..eb79b9d03 100644 --- a/src/ModelAPI/ModelAPI_PluginManager.cpp +++ b/src/ModelAPI/ModelAPI_PluginManager.cpp @@ -49,9 +49,6 @@ void ModelAPI_PluginManager::SetPluginManager( boost::shared_ptr 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; diff --git a/src/ModuleBase/CMakeLists.txt b/src/ModuleBase/CMakeLists.txt index b154decb0..82f7214d8 100644 --- a/src/ModuleBase/CMakeLists.txt +++ b/src/ModuleBase/CMakeLists.txt @@ -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 ) diff --git a/src/ModuleBase/ModuleBase_Operation.cpp b/src/ModuleBase/ModuleBase_Operation.cpp index e742c0553..c26eadb2a 100644 --- a/src/ModuleBase/ModuleBase_Operation.cpp +++ b/src/ModuleBase/ModuleBase_Operation.cpp @@ -15,6 +15,9 @@ #include #include #include +#include + +#include #ifdef _DEBUG #include @@ -29,11 +32,21 @@ ModuleBase_Operation::~ModuleBase_Operation() { } +QString ModuleBase_Operation::id() const +{ + return getDescription()->operationId(); +} + boost::shared_ptr 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 aData = myFeature->data(); boost::shared_ptr 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 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 ModuleBase_Operation::createFeature(const bool theFlushMessage) { boost::shared_ptr aDoc = document(); boost::shared_ptr aFeature = aDoc->addFeature( getDescription()->operationId().toStdString()); if (aFeature) // TODO: generate an error if feature was not created aFeature->execute(); + + if (theFlushMessage) + flushCreated(); return aFeature; } diff --git a/src/ModuleBase/ModuleBase_Operation.h b/src/ModuleBase/ModuleBase_Operation.h index 43c225dd1..89b369995 100644 --- a/src/ModuleBase/ModuleBase_Operation.h +++ b/src/ModuleBase/ModuleBase_Operation.h @@ -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 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 createFeature(); + virtual boost::shared_ptr createFeature(const bool theFlushMessage = true); /// Returns the operation feature /// \return the feature diff --git a/src/ModuleBase/ModuleBase_WidgetPoint2D.cpp b/src/ModuleBase/ModuleBase_WidgetPoint2D.cpp index d0ce1b11e..4d99d01be 100644 --- a/src/ModuleBase/ModuleBase_WidgetPoint2D.cpp +++ b/src/ModuleBase/ModuleBase_WidgetPoint2D.cpp @@ -6,6 +6,9 @@ #include +#include +#include + #include #include #include @@ -68,6 +71,8 @@ bool ModuleBase_WidgetPoint2D::storeValue(boost::shared_ptr 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; } diff --git a/src/PartSet/PartSet_Listener.cpp b/src/PartSet/PartSet_Listener.cpp index 06af416d2..355142a31 100644 --- a/src/PartSet/PartSet_Listener.cpp +++ b/src/PartSet/PartSet_Listener.cpp @@ -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(theMessage); - boost::shared_ptr 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 + (theMessage); + std::set > aFeatures = aUpdMsg->features(); + std::set >::const_iterator anIt = aFeatures.begin(), + aLast = aFeatures.end(); + for (; anIt != aLast; anIt++) { + boost::shared_ptr 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(theMessage); boost::shared_ptr 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 aGroups = aDelMsg->groups(); + std::set::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); + } } } } diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index b54dc192a..63f7a1a37 100644 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -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( myWorkshop->operationMgr()->currentOperation()); if (aPreviewOp) { - std::list aPresentations = myWorkshop->displayer()->GetViewerPrs(); - aPreviewOp->mousePressed(theEvent, myWorkshop->viewer()->activeView(), aPresentations); + XGUI_Displayer* aDisplayer = myWorkshop->displayer(); + std::list aSelected = aDisplayer->GetSelected(); + std::list 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 aPresentations = myWorkshop->displayer()->GetViewerPrs(); - aPreviewOp->mouseReleased(theEvent, myWorkshop->viewer()->activeView(), aPresentations); + XGUI_Displayer* aDisplayer = myWorkshop->displayer(); + std::list aSelected = aDisplayer->GetSelected(); + std::list 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 theFeature) @@ -173,10 +187,13 @@ void PartSet_Module::onLaunchOperation(std::string theName, boost::shared_ptr(anOperation); if (aPreviewOp) { - std::list 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 aSelected = aDisplayer->GetSelected(TopAbs_VERTEX); + std::list 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& 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); + }*/ +} diff --git a/src/PartSet/PartSet_Module.h b/src/PartSet/PartSet_Module.h index 17dc20348..1766a6e02 100644 --- a/src/PartSet/PartSet_Module.h +++ b/src/PartSet/PartSet_Module.h @@ -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; diff --git a/src/PartSet/PartSet_OperationEditLine.cpp b/src/PartSet/PartSet_OperationEditLine.cpp index 7b37976e8..d69aab8e0 100644 --- a/src/PartSet/PartSet_OperationEditLine.cpp +++ b/src/PartSet/PartSet_OperationEditLine.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -34,7 +35,7 @@ using namespace std; PartSet_OperationEditLine::PartSet_OperationEditLine(const QString& theId, QObject* theParent, boost::shared_ptr theFeature) -: PartSet_OperationSketchBase(theId, theParent), mySketch(theFeature) +: PartSet_OperationSketchBase(theId, theParent), mySketch(theFeature), myIsBlockedSelection(false) { } @@ -53,10 +54,28 @@ std::list PartSet_OperationEditLine::getSelectionModes(boost::shared_ptr theFeature, - const std::list& thePresentations) + const std::list& theSelected, + const std::list& 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::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 PartSet_OperationEditLine::sketch() const @@ -64,12 +83,35 @@ boost::shared_ptr 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& /*theSelected*/, + const std::list& 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 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 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& theSelected) + const std::list& /*theSelected*/, + const std::list& /*theHighlighted*/) { std::list aFeatures = myFeatures; if (myFeatures.size() == 1) { - if (theSelected.empty()) - return; - - boost::shared_ptr 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()); - 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 PartSet_OperationEditLine::createFeature() +void PartSet_OperationEditLine::blockSelection(bool isBlocked, const bool isRestoreSelection) +{ + if (myIsBlockedSelection == isBlocked) + return; + + myIsBlockedSelection = isBlocked; + if (isBlocked) { + emit setSelection(std::list()); + emit stopSelection(myFeatures, true); + } + else { + emit stopSelection(myFeatures, false); + if (isRestoreSelection) + emit setSelection(myFeatures); + } +} + +boost::shared_ptr PartSet_OperationEditLine::createFeature(const bool /*theFlushMessage*/) { // do nothing in order to do not create a new feature return boost::shared_ptr(); @@ -163,6 +220,8 @@ void PartSet_OperationEditLine::moveLinePoint(boost::shared_ptr aData = theFeature->data(); + if (!aData->isValid()) + return; boost::shared_ptr aPoint = boost::dynamic_pointer_cast(aData->attribute(theAttribute)); @@ -171,17 +230,18 @@ void PartSet_OperationEditLine::moveLinePoint(boost::shared_ptr > aFeatures; std::list::const_iterator anIt = myFeatures.begin(), aLast = myFeatures.end(); for (; anIt != aLast; anIt++) { boost::shared_ptr 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); } diff --git a/src/PartSet/PartSet_OperationEditLine.h b/src/PartSet/PartSet_OperationEditLine.h index 14fd56959..d42d0e545 100644 --- a/src/PartSet/PartSet_OperationEditLine.h +++ b/src/PartSet/PartSet_OperationEditLine.h @@ -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 theFeature, - const std::list& thePresentations); + const std::list& theSelected, + const std::list& theHighlighted); /// Returns the operation sketch feature /// \returns the sketch instance virtual boost::shared_ptr 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& theSelected, + const std::list& 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& theSelected); + const std::list& theSelected, + const std::list& 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 createFeature(); + virtual boost::shared_ptr 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 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 diff --git a/src/PartSet/PartSet_OperationSketch.cpp b/src/PartSet/PartSet_OperationSketch.cpp index d527cd0f3..eb65c3659 100644 --- a/src/PartSet/PartSet_OperationSketch.cpp +++ b/src/PartSet/PartSet_OperationSketch.cpp @@ -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 PartSet_OperationSketch::getSelectionModes(boost::shared_ptr theFeature) const { std::list aModes; - if (!myIsEditMode) + if (!hasSketchPlane()) aModes.push_back(TopAbs_FACE); else aModes = PartSet_OperationSketchBase::getSelectionModes(theFeature); return aModes; } -boost::shared_ptr PartSet_OperationSketch::sketch() const +void PartSet_OperationSketch::init(boost::shared_ptr theFeature, + const std::list& thePresentations) { - return feature(); + setFeature(theFeature); } -void PartSet_OperationSketch::mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView, - const std::list& theSelected) +boost::shared_ptr PartSet_OperationSketch::sketch() const { - myFeatures = theSelected; + return feature(); } -void PartSet_OperationSketch::mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView, - const std::list& theSelected) +void PartSet_OperationSketch::mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView, + const std::list& theSelected, + const std::list& 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 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 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 > boost::shared_ptr aFeature; boost::shared_ptr aData = feature()->data(); + if (!aData->isValid()) + return aPreviewMap; boost::shared_ptr aRefList = boost::dynamic_pointer_cast(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 aData = feature()->data(); + + boost::shared_ptr anAttr; + // temporary solution for main planes only + boost::shared_ptr aNormal = + boost::dynamic_pointer_cast(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 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 anOrigin = boost::dynamic_pointer_cast(aData->attribute(SKETCH_ATTR_ORIGIN)); @@ -167,6 +192,9 @@ void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape) boost::dynamic_pointer_cast(aData->attribute(SKETCH_ATTR_DIRY)); aDirY->setValue(aC, anA, aB); boost::shared_ptr aDir = aPlane->direction(); + + flushUpdated(); + emit featureConstructed(feature(), FM_Hide); emit closeLocalContext(); emit planeSelected(aDir->x(), aDir->y(), aDir->z()); diff --git a/src/PartSet/PartSet_OperationSketch.h b/src/PartSet/PartSet_OperationSketch.h index fbb0eb376..8f3a8fd4e 100644 --- a/src/PartSet/PartSet_OperationSketch.h +++ b/src/PartSet/PartSet_OperationSketch.h @@ -34,22 +34,24 @@ public: /// \return the selection mode virtual std::list getSelectionModes(boost::shared_ptr 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 theFeature, + const std::list& thePresentations); + /// Returns the operation sketch feature /// \returns the sketch instance virtual boost::shared_ptr 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& 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& theSelected); + const std::list& theSelected, + const std::list& 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 myFeatures; ///< the features to apply the edit operation }; diff --git a/src/PartSet/PartSet_OperationSketchBase.cpp b/src/PartSet/PartSet_OperationSketchBase.cpp index 45981e244..acf76c60a 100644 --- a/src/PartSet/PartSet_OperationSketchBase.cpp +++ b/src/PartSet/PartSet_OperationSketchBase.cpp @@ -54,9 +54,9 @@ std::list PartSet_OperationSketchBase::getSelectionModes(boost::shared_ptr< aModes.push_back(TopAbs_EDGE); return aModes; } -boost::shared_ptr PartSet_OperationSketchBase::createFeature() +boost::shared_ptr PartSet_OperationSketchBase::createFeature(const bool theFlushMessage) { - boost::shared_ptr aFeature = ModuleBase_Operation::createFeature(); + boost::shared_ptr aFeature = ModuleBase_Operation::createFeature(theFlushMessage); if (aFeature) emit featureConstructed(aFeature, FM_Activation); return aFeature; @@ -64,11 +64,13 @@ boost::shared_ptr PartSet_OperationSketchBase::createFeature() void PartSet_OperationSketchBase::mousePressed(QMouseEvent* theEvent, Handle_V3d_View theView, - const std::list& theSelected) + const std::list& theSelected, + const std::list& theHighlighted) { } void PartSet_OperationSketchBase::mouseReleased(QMouseEvent* theEvent, Handle_V3d_View theView, - const std::list& theSelected) + const std::list& theSelected, + const std::list& theHighlighted) { } void PartSet_OperationSketchBase::mouseMoved(QMouseEvent* theEvent, Handle(V3d_View) theView) diff --git a/src/PartSet/PartSet_OperationSketchBase.h b/src/PartSet/PartSet_OperationSketchBase.h index 0045a8e87..5aa07c3f0 100644 --- a/src/PartSet/PartSet_OperationSketchBase.h +++ b/src/PartSet/PartSet_OperationSketchBase.h @@ -55,32 +55,37 @@ public: virtual std::list getSelectionModes(boost::shared_ptr 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 theFeature, - const std::list& thePresentations) {} + const std::list& theSelected, + const std::list& theHighlighted) {} /// Returns the operation sketch feature /// \returns the sketch instance virtual boost::shared_ptr 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& theSelected); + const std::list& theSelected, + const std::list& 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& theSelected); + const std::list& theSelected, + const std::list& 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 createFeature(); + virtual boost::shared_ptr createFeature(const bool theFlushMessage = true); }; #endif diff --git a/src/PartSet/PartSet_OperationSketchLine.cpp b/src/PartSet/PartSet_OperationSketchLine.cpp index 6b64cd275..33e03c5e2 100644 --- a/src/PartSet/PartSet_OperationSketchLine.cpp +++ b/src/PartSet/PartSet_OperationSketchLine.cpp @@ -67,7 +67,8 @@ std::list PartSet_OperationSketchLine::getSelectionModes(boost::shared_ptr< } void PartSet_OperationSketchLine::init(boost::shared_ptr theFeature, - const std::list& /*thePresentations*/) + const std::list& /*theSelected*/, + const std::list& /*theHighlighted*/) { if (!theFeature || theFeature->getKind() != "SketchLine") return; @@ -82,7 +83,8 @@ boost::shared_ptr PartSet_OperationSketchLine::sketch() const } void PartSet_OperationSketchLine::mouseReleased(QMouseEvent* theEvent, Handle(V3d_View) theView, - const std::list& theSelected) + const std::list& theSelected, + const std::list& /*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()); } 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 PartSet_OperationSketchLine::createFeature() +boost::shared_ptr PartSet_OperationSketchLine::createFeature(const bool theFlushMessage) { - boost::shared_ptr aNewFeature = ModuleBase_Operation::createFeature(); + boost::shared_ptr aNewFeature = ModuleBase_Operation::createFeature(false); if (sketch()) { boost::shared_ptr aFeature = boost::dynamic_pointer_cast(sketch()); @@ -243,6 +259,8 @@ boost::shared_ptr PartSet_OperationSketchLine::createFeature() } emit featureConstructed(aNewFeature, FM_Activation); + if (theFlushMessage) + flushCreated(); return aNewFeature; } diff --git a/src/PartSet/PartSet_OperationSketchLine.h b/src/PartSet/PartSet_OperationSketchLine.h index 09c33f6f4..db20415c7 100644 --- a/src/PartSet/PartSet_OperationSketchLine.h +++ b/src/PartSet/PartSet_OperationSketchLine.h @@ -46,21 +46,24 @@ public: virtual std::list getSelectionModes(boost::shared_ptr 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 theFeature, - const std::list& thePresentations); + const std::list& theSelected, + const std::list& theHighlighted); /// Returns the operation sketch feature /// \returns the sketch instance virtual boost::shared_ptr 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& theSelected); + const std::list& theSelected, + const std::list& 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 createFeature(); + virtual boost::shared_ptr createFeature(const bool theFlushMessage = true); /// Creates a constraint on two points /// \param thePoint1 the first point diff --git a/src/PartSetPlugin/plugin-PartSet.xml b/src/PartSetPlugin/plugin-PartSet.xml index 4b3391da8..07438b2d2 100644 --- a/src/PartSetPlugin/plugin-PartSet.xml +++ b/src/PartSetPlugin/plugin-PartSet.xml @@ -1,9 +1,9 @@ - - - + + + diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index 29cf61b04..706d85f3b 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -1,16 +1,16 @@ - - diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp index c8de0aa30..7edc1da33 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintManager.cpp @@ -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(theMessage); + const Model_FeatureUpdatedMessage* anUpdateMsg = dynamic_cast(theMessage); + std::set< boost::shared_ptr > 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 aSketch = - boost::dynamic_pointer_cast(aUpdateMsg->feature()); - changeWorkplane(aSketch); - return ; - } - boost::shared_ptr aConstraint = - boost::dynamic_pointer_cast(aUpdateMsg->feature()); - if (aConstraint) - changeConstraint(aConstraint); - else - { - // Sketch plugin features can be only updated - boost::shared_ptr aFeature = - boost::dynamic_pointer_cast(aUpdateMsg->feature()); - if (aFeature) - updateEntity(aFeature); + std::set< boost::shared_ptr >::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 aSketch = + boost::dynamic_pointer_cast(*aFeatIter); + if (aSketch) + changeWorkplane(aSketch); + continue; + } + boost::shared_ptr aConstraint = + boost::dynamic_pointer_cast(*aFeatIter); + if (aConstraint) + changeConstraint(aConstraint); + else + { + // Sketch plugin features can be only updated + boost::shared_ptr aFeature = + boost::dynamic_pointer_cast(*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(theMessage); + const std::set& 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::const_iterator aFGrIter; + for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++) + if (aFGrIter->compare("Sketch") == 0) + break; + + if (aFGrIter != aFeatureGroups.end()) { std::vector::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 theSketch) @@ -298,6 +314,9 @@ void SketchSolver_ConstraintManager::resolveConstraints() std::vector::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() diff --git a/src/XGUI/XGUI_ActionsMgr.cpp b/src/XGUI/XGUI_ActionsMgr.cpp index 7f0b02d9a..6815d81d3 100644 --- a/src/XGUI/XGUI_ActionsMgr.cpp +++ b/src/XGUI/XGUI_ActionsMgr.cpp @@ -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 #include +#ifdef _DEBUG +#include +#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(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(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(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); } } diff --git a/src/XGUI/XGUI_ActionsMgr.h b/src/XGUI/XGUI_ActionsMgr.h index 3390a83f3..38b8e167d 100644 --- a/src/XGUI/XGUI_ActionsMgr.h +++ b/src/XGUI/XGUI_ActionsMgr.h @@ -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 myActions; - QMap myActionsState; + QMap myNestedActions; - XGUI_Workshop* myWorkshop; + XGUI_OperationMgr* myOperationMgr; }; #endif /* XGUI_ACTIONSMGR_H_ */ + diff --git a/src/XGUI/XGUI_Command.cpp b/src/XGUI/XGUI_Command.cpp index 220e04f47..0ddb0ecfc 100644 --- a/src/XGUI/XGUI_Command.cpp +++ b/src/XGUI/XGUI_Command.cpp @@ -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; } diff --git a/src/XGUI/XGUI_Command.h b/src/XGUI/XGUI_Command.h index dbd45b432..6c01e6136 100644 --- a/src/XGUI/XGUI_Command.h +++ b/src/XGUI/XGUI_Command.h @@ -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 diff --git a/src/XGUI/XGUI_ContextMenuMgr.cpp b/src/XGUI/XGUI_ContextMenuMgr.cpp index 461b2dab5..38e74834b 100644 --- a/src/XGUI/XGUI_ContextMenuMgr.cpp +++ b/src/XGUI/XGUI_ContextMenuMgr.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -90,7 +91,8 @@ QMenu* XGUI_ContextMenuMgr::objectBrowserMenu() const //Process Feature if (aFeature) { if (aFeature->getKind() == "Part") { - boost::shared_ptr aFeaDoc = aFeature->data()->docRef("PartDocument")->value(); + ObjectPtr aObject = boost::dynamic_pointer_cast(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) diff --git a/src/XGUI/XGUI_Displayer.cpp b/src/XGUI/XGUI_Displayer.cpp index 7f6bb00d7..7e5deb50e 100644 --- a/src/XGUI/XGUI_Displayer.cpp +++ b/src/XGUI/XGUI_Displayer.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -19,6 +20,8 @@ #include +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 theFeature, }*/ -std::list XGUI_Displayer::GetViewerPrs() +std::list XGUI_Displayer::GetSelected(const int theShapeTypeToSkip) { std::set > aPrsFeatures; std::list aPresentations; @@ -61,16 +64,31 @@ std::list 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 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 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_Displayer::GetHighlighted(const int theShapeTypeToSkip) +{ + std::set > aPrsFeatures; + std::list 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 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 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& theFeatures, c boost::shared_ptr 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& 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 XGUI_Displayer::GetFeature(Handle(AIS_InteractiveObject) theIO) +{ + boost::shared_ptr 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()) { diff --git a/src/XGUI/XGUI_Displayer.h b/src/XGUI/XGUI_Displayer.h index 5973cd67e..4dc28389f 100644 --- a/src/XGUI/XGUI_Displayer.h +++ b/src/XGUI/XGUI_Displayer.h @@ -58,9 +58,15 @@ public: //void Display(boost::shared_ptr 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 GetViewerPrs(); + std::list 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 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 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; diff --git a/src/XGUI/XGUI_DocumentDataModel.cpp b/src/XGUI/XGUI_DocumentDataModel.cpp index 30d3b9a0f..d1ca2c2ed 100644 --- a/src/XGUI/XGUI_DocumentDataModel.cpp +++ b/src/XGUI/XGUI_DocumentDataModel.cpp @@ -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(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::const_iterator aIt; - for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) { - if ((*aIt)->hasDocument(aDoc)) { - aPartModel = (*aIt); - break; + std::set aFeatures = aUpdMsg->features(); + + std::set::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::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(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::const_iterator aIt; - for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) { - if ((*aIt)->hasDocument(aDoc)) { - aPartModel = (*aIt); - break; + std::set aGroups = aUpdMsg->groups(); + + std::set::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::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(theMessage); diff --git a/src/XGUI/XGUI_MainWindow.cpp b/src/XGUI/XGUI_MainWindow.cpp index 4b8c9e091..1400fc0cc 100644 --- a/src/XGUI/XGUI_MainWindow.cpp +++ b/src/XGUI/XGUI_MainWindow.cpp @@ -14,6 +14,7 @@ #include #include #include +#include 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(); +} diff --git a/src/XGUI/XGUI_MainWindow.h b/src/XGUI/XGUI_MainWindow.h index 9b29ec3ea..010f9e309 100644 --- a/src/XGUI/XGUI_MainWindow.h +++ b/src/XGUI/XGUI_MainWindow.h @@ -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; diff --git a/src/XGUI/XGUI_ObjectsBrowser.cpp b/src/XGUI/XGUI_ObjectsBrowser.cpp index 352fa4ba8..702c44fef 100644 --- a/src/XGUI/XGUI_ObjectsBrowser.cpp +++ b/src/XGUI/XGUI_ObjectsBrowser.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -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(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; } diff --git a/src/XGUI/XGUI_OperationMgr.cpp b/src/XGUI/XGUI_OperationMgr.cpp index ad312dad5..2a27188c9 100644 --- a/src/XGUI/XGUI_OperationMgr.cpp +++ b/src/XGUI/XGUI_OperationMgr.cpp @@ -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 anIt(myOperations); diff --git a/src/XGUI/XGUI_OperationMgr.h b/src/XGUI/XGUI_OperationMgr.h index 169453b3a..56db2c4c5 100644 --- a/src/XGUI/XGUI_OperationMgr.h +++ b/src/XGUI/XGUI_OperationMgr.h @@ -11,6 +11,7 @@ #include #include +#include /**\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. diff --git a/src/XGUI/XGUI_PartDataModel.cpp b/src/XGUI/XGUI_PartDataModel.cpp index 6610b64c5..dc09185cc 100644 --- a/src/XGUI/XGUI_PartDataModel.cpp +++ b/src/XGUI/XGUI_PartDataModel.cpp @@ -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(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(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(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(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(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; } diff --git a/src/XGUI/XGUI_PropertyPanel.cpp b/src/XGUI/XGUI_PropertyPanel.cpp index 506748471..ccf0469cf 100644 --- a/src/XGUI/XGUI_PropertyPanel.cpp +++ b/src/XGUI/XGUI_PropertyPanel.cpp @@ -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); diff --git a/src/XGUI/XGUI_Viewer.cpp b/src/XGUI/XGUI_Viewer.cpp index 734a1a469..3d5af347a 100644 --- a/src/XGUI/XGUI_Viewer.cpp +++ b/src/XGUI/XGUI_Viewer.cpp @@ -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); diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index d095b1cb4..389f81420 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -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(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(theMessage); - FeaturePtr aFeature = aUpdMsg->feature(); - if (aFeature->getKind() == "Part") { + std::set aFeatures = aUpdMsg->features(); + + std::set::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(theMessage); - FeaturePtr aNewFeature = anUpdateMsg->feature(); + std::set aFeatures = anUpdateMsg->features(); + FeaturePtr aCurrentFeature = myOperationMgr->currentOperation()->feature(); - if(aNewFeature == aCurrentFeature) { - myPropertyPanel->updateContentWidget(aCurrentFeature); + std::set::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 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(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(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(aFeature); + aFeature = aObject->featureRef(); + } + } + aFeature->document()->removeFeature(aFeature); } + aMgr->rootDocument()->finishOperation(); } } diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index 21ee4a87b..42d893f1d 100644 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -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 myIcons; };