SET(PROJECT_HEADERS
Events.h
Events_Message.h
+ Events_MessageGroup.h
Events_Listener.h
Events_Loop.h
Events_Error.h
// Author: Mikhail PONIKAROV
#include <Events_Loop.h>
+#include <Events_MessageGroup.h>
#include <string>
#include <cstring>
return Events_ID(aResult);
}
-void Events_Loop::send(Events_Message& theMessage)
+void Events_Loop::send(Events_Message& theMessage, bool isGroup)
{
- // TO DO: make it in thread and wit husage of semaphores
+ // if it is grouped message, just accumulate it
+ if (isGroup) {
+ Events_MessageGroup* aGroup = dynamic_cast<Events_MessageGroup*>(&theMessage);
+ if (aGroup) {
+ std::map<char*, Events_MessageGroup*>::iterator aMyGroup =
+ myGroups.find(aGroup->eventID().eventText());
+ if (aMyGroup == myGroups.end()) { // create a new group of messages for accumulation
+ myGroups[aGroup->eventID().eventText()] = aGroup->newEmpty();
+ aMyGroup = myGroups.find(aGroup->eventID().eventText());
+ }
+ aMyGroup->second->Join(*aGroup);
+ return;
+ }
+ }
+
+ // TO DO: make it in thread and with usage of semaphores
map<char*, map<void*, list<Events_Listener*> > >::iterator aFindID = myListeners.find(
theMessage.eventID().eventText());
aListeners.push_back(theListener);
}
+
+void Events_Loop::flush(const Events_ID& theID)
+{
+ std::map<char*, Events_MessageGroup*>::iterator aMyGroup =
+ myGroups.find(theID.eventText());
+ if (aMyGroup != myGroups.end()) { // really sends
+ Events_MessageGroup* aGroup = aMyGroup->second;
+ myGroups.erase(aMyGroup);
+ send(*aGroup, false);
+ delete aGroup;
+ }
+}
#include <map>
#include <list>
+class Events_MessageGroup;
+
/**\class Events_Lopp
* \ingroup EventsLoop
* \brief Base class that manages the receiving and sending of all
* control back immideately.
*/
class Events_Loop {
+ /// map from event ID to sender pointer to listeners that must be called for this
std::map<char*, std::map<void*, std::list<Events_Listener*> > >
- myListeners; ///< map from event ID to sender pointer to listeners that must be called for this
+ myListeners;
+
+ /// map from event ID to groupped messages (accumulated on flush)
+ std::map<char*, Events_MessageGroup*> myGroups;
//! The empty constructor, will be called at startup of the application, only once
Events_Loop() {};
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
--- /dev/null
+// File: Events_MessageGroup.hxx
+// Created: Thu Mar 13 2014
+// Author: Mikhail PONIKAROV
+
+#ifndef Events_MessageGroup_HeaderFile
+#define Events_MessageGroup_HeaderFile
+
+#include <Events_Message.h>
+
+/**\class Events_Message
+ * \ingroup EventsLoop
+ * \brief Message that allows to group messages and send them later as a group of messages.
+ *
+ * Loop detects such messages and accumulates them without sending. On "flush" loop sends it
+ * as a group-message.
+ */
+class EVENTS_EXPORT Events_MessageGroup : public Events_Message {
+
+public:
+
+ //! Creates the message
+ Events_MessageGroup(const Events_ID theID, const void* theSender = 0)
+ : Events_Message(theID, theSender) {}
+ //! do nothing in the destructor yet
+ virtual ~Events_MessageGroup() {}
+
+ //! Creates a new empty group (to store it in the loop before flush)
+ virtual Events_MessageGroup* newEmpty() = 0;
+ //! Allows to join the given message with the current one
+ virtual void Join(Events_MessageGroup& theJoined) = 0;
+};
+
+#endif
#include <GeomData_Point2D.h>
#include <GeomData_Dir.h>
#include <TDataStd_Name.hxx>
+#include "Model_Events.h"
+#include <Events_Loop.h>
using namespace std;
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)
aFLabIter.Next();
}
}
+ // after all updates, sends a message that groups of features were created or updated
+ boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
+ setCheckTransactions(false);
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_DELETED));
+ boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
+ setCheckTransactions(true);
}
#include <Model_Events.h>
#include <Events_Loop.h>
+// DELETED methods
+Events_MessageGroup* Model_FeatureDeletedMessage::newEmpty() {
+ return new Model_FeatureDeletedMessage(myDoc, "");
+}
+
Model_FeatureDeletedMessage::Model_FeatureDeletedMessage(
const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
- : Events_Message(messageId(), 0), myDoc(theDoc), myGroup(theGroup)
+ : Events_MessageGroup(messageId(), 0), myDoc(theDoc)
{
+ if (!theGroup.empty())
+ myGroups.insert(theGroup);
}
const Events_ID Model_FeatureDeletedMessage::messageId()
return MY_ID;
}
-Model_FeaturesMovedMessage::Model_FeaturesMovedMessage()
-: Events_Message(messageId(), 0)
+void Model_FeatureDeletedMessage::Join(Events_MessageGroup& theJoined)
{
+ Model_FeatureDeletedMessage* aJoined = dynamic_cast<Model_FeatureDeletedMessage*>(&theJoined);
+ std::set<std::string>::iterator aGIter = aJoined->myGroups.begin();
+ for(; aGIter != aJoined->myGroups.end(); aGIter++) {
+ myGroups.insert(*aGIter);
+ }
}
-
-const Events_ID Model_FeaturesMovedMessage::messageId()
-{
- static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURES_MOVED);
- return MY_ID;
-}
-
-void Model_FeaturesMovedMessage::setFeatures(
- const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures)
-{
- myFeatures = theFeatures;
-}
-
-const std::list<boost::shared_ptr<ModelAPI_Feature> >& Model_FeaturesMovedMessage::features() const
-{
- return myFeatures;
-}
-
#define Model_Events_HeaderFile
#include <Model.h>
-#include <Events_Message.h>
+#include <Events_MessageGroup.h>
#include <Events_Loop.h>
#include <boost/shared_ptr.hpp>
#include <string>
-#include <list>
+#include <set>
class ModelAPI_Feature;
class ModelAPI_Document;
/// Event ID that data of feature is deleted (comes with Model_FeatureDeletedMessage)
static const char * EVENT_FEATURE_DELETED = "FeatureDeleted";
/// Event ID that data of feature is updated (comes with Model_FeaturesMovedMessage)
-static const char * EVENT_FEATURES_MOVED = "FeaturesMoved";
+static const char * EVENT_FEATURE_MOVED = "FeaturesMoved";
-/// Message that feature was changed (used for Object Browser update)
-class Model_FeatureUpdatedMessage : public Events_Message {
- boost::shared_ptr<ModelAPI_Feature> myFeature; ///< which feature is changed
+/// Message that feature was changed (used for Object Browser update): moved, updated and deleted
+class Model_FeatureUpdatedMessage : public Events_MessageGroup {
+ std::set<boost::shared_ptr<ModelAPI_Feature> > myFeatures; ///< which feature is changed
public:
/// sender is not important, all information is located in the feature
Model_FeatureUpdatedMessage(
const boost::shared_ptr<ModelAPI_Feature>& theFeature,
- const Events_ID& theEvent) : Events_Message(theEvent, 0), myFeature(theFeature)
- {}
+ const Events_ID& theEvent) : Events_MessageGroup(theEvent, 0)
+ {if (theFeature) myFeatures.insert(theFeature);}
/// Returns the feature that has been updated
- boost::shared_ptr<ModelAPI_Feature> feature() const {return myFeature;}
+ std::set<boost::shared_ptr<ModelAPI_Feature> > features() const {return myFeatures;}
+
+ //! Creates a new empty group (to store it in the loop before flush)
+ virtual Events_MessageGroup* newEmpty() {
+ boost::shared_ptr<ModelAPI_Feature> anEmptyFeature;
+ return new Model_FeatureUpdatedMessage(anEmptyFeature, eventID());
+ }
+
+ //! Allows to join the given message with the current one
+ virtual void Join(Events_MessageGroup& theJoined) {
+ Model_FeatureUpdatedMessage* aJoined = dynamic_cast<Model_FeatureUpdatedMessage*>(&theJoined);
+ std::set<boost::shared_ptr<ModelAPI_Feature> >::iterator aFIter = aJoined->myFeatures.begin();
+ for(; aFIter != aJoined->myFeatures.end(); aFIter++) {
+ myFeatures.insert(*aFIter);
+ }
+ }
};
/// Message that feature was deleted (used for Object Browser update)
-class Model_FeatureDeletedMessage : public Events_Message {
+class Model_FeatureDeletedMessage : public Events_MessageGroup {
boost::shared_ptr<ModelAPI_Document> myDoc; ///< document owner of the feature
- std::string myGroup; ///< group identifier that contained the deleted feature
+ std::set<std::string> myGroups; ///< group identifiers that contained the deleted feature
public:
/// creates a message by initialization of fields
Model_FeatureDeletedMessage(const boost::shared_ptr<ModelAPI_Document>& theDoc,
boost::shared_ptr<ModelAPI_Document> document() const {return myDoc;}
/// Returns the group where the feature was deleted
- const std::string& group() const {return myGroup;}
-};
-
-/// Message that features were moved (used for the feature preview update)
-class Model_FeaturesMovedMessage : public Events_Message {
- std::list<boost::shared_ptr<ModelAPI_Feature> > myFeatures; ///< which features are moved
-public:
- /// creates a message by initialization of fields
- MODEL_EXPORT Model_FeaturesMovedMessage();
-
- /// Returns the ID of this message (EVENT_FEATURES_MOVED)
- static const Events_ID messageId();
+ const std::set<std::string >& groups() const {return myGroups;}
- /// Sets a list of features
- MODEL_EXPORT void setFeatures(const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures);
+ //! Creates a new empty group (to store it in the loop before flush)
+ virtual Events_MessageGroup* newEmpty();
- /// Returns a list of features
- MODEL_EXPORT const std::list<boost::shared_ptr<ModelAPI_Feature> >& features() const;
+ //! Allows to join the given message with the current one
+ virtual void Join(Events_MessageGroup& theJoined);
};
#endif
#include "Model_Object.h"
#include <TCollection_AsciiString.hxx>
+#include "Model_Events.h"
+#include <Events_Loop.h>
boost::shared_ptr<ModelAPI_Feature> Model_Object::featureRef()
{
void Model_Object::setName(std::string theName)
{
- myName->Set(theName.c_str());
+ if (myName->Get() != theName.c_str()) {
+ myName->Set(theName.c_str());
+ static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
+ Model_FeatureUpdatedMessage aMsg(boost::shared_ptr<ModelAPI_Object>(this), anEvent);
+ Events_Loop::loop()->send(aMsg, false);
+ }
}
Model_Object::Model_Object(boost::shared_ptr<ModelAPI_Feature> theRef,
#include <Model_Data.h>
#include <Model_Document.h>
#include <Model_Application.h>
+#include <Model_Events.h>
#include <Events_Loop.h>
#include <Events_Error.h>
#include <Config_FeatureMessage.h>
Model_PluginManager::Model_PluginManager()
{
myPluginsInfoLoaded = false;
- //TODO(sbh): Implement static method to extract event id [SEID]
- static Events_ID aFeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
-
+ myCheckTransactions = true;
ModelAPI_PluginManager::SetPluginManager(boost::shared_ptr<ModelAPI_PluginManager>(this));
// register the configuration reading listener
Events_Loop* aLoop = Events_Loop::loop();
- aLoop->registerListener(this, aFeatureEvent);
+ static Events_ID FeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
+ aLoop->registerListener(this, FeatureEvent);
+ aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+ aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+ aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
}
void Model_PluginManager::processEvent(const Events_Message* theMessage)
{
- const Config_FeatureMessage* aMsg =
- dynamic_cast<const Config_FeatureMessage*>(theMessage);
- if (aMsg) {
- // proccess the plugin info, load plugin
- if (myPlugins.find(aMsg->id()) == myPlugins.end()) {
- myPlugins[aMsg->id()] = aMsg->pluginLibrary();
+ static Events_ID FeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
+ if (theMessage->eventID() == FeatureEvent) {
+ const Config_FeatureMessage* aMsg =
+ dynamic_cast<const Config_FeatureMessage*>(theMessage);
+ if (aMsg) {
+ // proccess the plugin info, load plugin
+ if (myPlugins.find(aMsg->id()) == myPlugins.end()) {
+ myPlugins[aMsg->id()] = aMsg->pluginLibrary();
+ }
}
+ // plugins information was started to load, so, it will be loaded
+ myPluginsInfoLoaded = true;
+ } else { // create/update/delete
+ if (myCheckTransactions && !rootDocument()->isOperation())
+ Events_Error::send("Modification of data structure outside of the transaction");
}
- // plugins information was started to load, so, it will be loaded
- myPluginsInfoLoaded = true;
}
void Model_PluginManager::LoadPluginsInfo()
std::map<std::string, ModelAPI_Plugin*> myPluginObjs; ///< instances of the already plugins
std::string myCurrentPluginName; ///< name of the plugin that must be loaded currently
boost::shared_ptr<ModelAPI_Document> myCurrentDoc; ///< current working document
+ bool myCheckTransactions; ///< if true, generates error if document is updated outside of transaction
public:
/// Returns the root document of the application (that may contains sub-documents)
MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> rootDocument();
MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> copy(
boost::shared_ptr<ModelAPI_Document> theSource, std::string theID);
+ void setCheckTransactions(const bool theCheck) {myCheckTransactions = theCheck;}
+
/// Is called only once, on startup of the application
Model_PluginManager();
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
)
#include <ModelAPI_Feature.h>
#include <ModelAPI_Data.h>
#include <ModelAPI_Document.h>
+#include <Model_Events.h>
+
+#include <Events_Loop.h>
#ifdef _DEBUG
#include <QDebug>
boost::shared_ptr<ModelAPI_Data> aData = myFeature->data();
boost::shared_ptr<ModelAPI_AttributeDouble> aReal = aData->real(anId.toStdString());
aReal->setValue(theValue);
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
}
void ModuleBase_Operation::storeCustomValue()
if (myFeature) myFeature->execute();
}
-boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::createFeature()
+void ModuleBase_Operation::flushUpdated()
+{
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+}
+
+void ModuleBase_Operation::flushCreated()
+{
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+}
+
+boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::createFeature(const bool theFlushMessage)
{
boost::shared_ptr<ModelAPI_Document> aDoc = document();
boost::shared_ptr<ModelAPI_Feature> aFeature = aDoc->addFeature(
getDescription()->operationId().toStdString());
if (aFeature) // TODO: generate an error if feature was not created
aFeature->execute();
+
+ if (theFlushMessage)
+ flushCreated();
return aFeature;
}
/// Virtual method called when operation committed (see commit() method for more description)
virtual void commitOperation();
+ /// Send update message by loop
+ void flushUpdated();
+ /// Send created message by loop
+ void flushCreated();
+
/// Creates an operation new feature
+ /// \param theFlushMessage the flag whether the create message should be flushed
/// \returns the created feature
- virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+ virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
/// Returns the operation feature
/// \return the feature
#include <Config_Keywords.h>
+#include <Events_Loop.h>
+#include <Model_Events.h>
+
#include <ModelAPI_Feature.h>
#include <ModelAPI_Data.h>
#include <GeomDataAPI_Point2D.h>
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;
}
if (aType == EVENT_FEATURE_UPDATED ||
aType == EVENT_FEATURE_CREATED)
{
- const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
- boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
- if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
- aType == EVENT_FEATURE_CREATED) {
- myModule->visualizePreview(aFeature, true, false);
- myModule->activateFeature(aFeature, true);
- myModule->workshop()->displayer()->UpdateViewer();
+ const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>
+ (theMessage);
+ std::set<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aUpdMsg->features();
+ std::set<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
+ aLast = aFeatures.end();
+ for (; anIt != aLast; anIt++) {
+ boost::shared_ptr<ModelAPI_Feature> aFeature = *anIt;
+ if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
+ aType == EVENT_FEATURE_CREATED) {
+ myModule->visualizePreview(aFeature, true, false);
+ myModule->activateFeature(aFeature, true);
+ }
}
+ myModule->workshop()->displayer()->UpdateViewer();
}
if (aType == EVENT_FEATURE_DELETED)
{
const Model_FeatureDeletedMessage* aDelMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
boost::shared_ptr<ModelAPI_Document> aDoc = aDelMsg->document();
- std::string aGroup = aDelMsg->group();
- if (aDelMsg->group().compare("Sketch") == 0) { // Update only Sketch group
- myModule->workshop()->displayer()->EraseDeletedFeatures();
- myModule->updateCurrentPreview(aGroup);
+ std::set<std::string> aGroups = aDelMsg->groups();
+ std::set<std::string>::const_iterator anIt = aGroups.begin(), aLast = aGroups.end();
+ for (; anIt != aLast; anIt++) {
+ std::string aGroup = *anIt;
+ if (aGroup.compare("Sketch") == 0) { // Update only Sketch group
+ myModule->workshop()->displayer()->EraseDeletedFeatures();
+ myModule->updateCurrentPreview(aGroup);
+ }
}
}
}
#include <PartSet_OperationSketch.h>
#include <ModuleBase_OperationDescription.h>
+#include <Model_Events.h>
#include <XGUI_ViewerPrs.h>
moveLinePoint(aFeature, aDeltaX, aDeltaY, LINE_ATTR_END);
}
}
+ flushUpdated();
sendFeatures();
myCurPoint.setPoint(aPoint);
myFeatures.clear();
}
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::createFeature(const bool /*theFlushMessage*/)
{
// do nothing in order to do not create a new feature
return boost::shared_ptr<ModelAPI_Feature>();
void PartSet_OperationEditLine::sendFeatures()
{
+ static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_MOVED);
+
std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures;
std::list<XGUI_ViewerPrs>::const_iterator anIt = myFeatures.begin(), aLast = myFeatures.end();
for (; anIt != aLast; anIt++) {
boost::shared_ptr<ModelAPI_Feature> aFeature = (*anIt).feature();
- if (!aFeature || aFeature == feature())
+ if (!aFeature)
continue;
- }
- static Events_ID aModuleEvent = Events_Loop::eventByName("PartSetEditEvent");
- Model_FeaturesMovedMessage aMessage;
- aMessage.setFeatures(aFeatures);
- Events_Loop::loop()->send(aMessage);
+ Model_FeatureUpdatedMessage aMessage(aFeature, anEvent);
+ Events_Loop::loop()->send(aMessage);
+ }
+ Events_Loop::loop()->flush(anEvent);
}
/// Creates an operation new feature
/// Returns NULL feature. This is an operation of edition, not creation.
+ /// \param theFlushMessage the flag whether the create message should be flushed
/// \returns the created feature
- virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+ virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
protected:
/// \brief Save the point to the line.
boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRY));
aDirY->setValue(aC, anA, aB);
boost::shared_ptr<GeomAPI_Dir> aDir = aPlane->direction();
+
+ flushUpdated();
+
emit featureConstructed(feature(), FM_Hide);
emit closeLocalContext();
emit planeSelected(aDir->x(), aDir->y(), aDir->z());
aModes.push_back(TopAbs_EDGE);
return aModes;
}
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature(const bool theFlushMessage)
{
- boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature();
+ boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature(theFlushMessage);
if (aFeature)
emit featureConstructed(aFeature, FM_Activation);
return aFeature;
/// Creates an operation new feature
/// In addition to the default realization it appends the created line feature to
/// the sketch feature
+ /// \param theFlushMessage the flag whether the create message should be flushed
/// \returns the created feature
- virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+ virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
};
#endif
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;
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:
emit multiSelectionEnabled(true);
}
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature(const bool theFlushMessage)
{
- boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature();
+ boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature(false);
if (sketch()) {
boost::shared_ptr<SketchPlugin_Feature> aFeature =
boost::dynamic_pointer_cast<SketchPlugin_Feature>(sketch());
}
emit featureConstructed(aNewFeature, FM_Activation);
+ if (theFlushMessage)
+ flushCreated();
return aNewFeature;
}
/// Creates an operation new feature
/// In addition to the default realization it appends the created line feature to
/// the sketch feature
+ /// \param theFlushMessage the flag whether the create message should be flushed
/// \returns the created feature
- virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+ virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
/// Creates a constraint on two points
/// \param thePoint1 the first point
#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_Data.h>
#include <Model_Events.h>
+
#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_Line.h>
#include <math.h>
#include <assert.h>
+#include <set>
+
/// Tolerance for value of parameters
const double tolerance = 1.e-10;
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()
void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
{
if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED) ||
- theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+ theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED) ||
+ theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED))
{
- const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+ const Model_FeatureUpdatedMessage* anUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+ std::set< boost::shared_ptr<ModelAPI_Feature> > aFeatures = anUpdateMsg->features();
- // Only sketches and constraints can be added by Create event
- const std::string& aFeatureKind = aUpdateMsg->feature()->getKind();
- if (aFeatureKind.compare("Sketch") == 0)
- {
- boost::shared_ptr<SketchPlugin_Feature> aSketch =
- boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
- if (aSketch)
- changeWorkplane(aSketch);
- return ;
- }
- boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
- boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
- if (aConstraint)
- changeConstraint(aConstraint);
- else
+ bool isModifiedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED);
+ if (!isModifiedEvt)
{
- // Sketch plugin features can be only updated
- boost::shared_ptr<SketchPlugin_Feature> aFeature =
- boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
- if (aFeature)
- updateEntity(aFeature);
+ std::set< boost::shared_ptr<ModelAPI_Feature> >::iterator aFeatIter;
+ for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
+ {
+ // Only sketches and constraints can be added by Create event
+ const std::string& aFeatureKind = (*aFeatIter)->getKind();
+ if (aFeatureKind.compare("Sketch") == 0)
+ {
+ boost::shared_ptr<SketchPlugin_Feature> aSketch =
+ boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+ if (aSketch)
+ changeWorkplane(aSketch);
+ return ;
+ }
+ boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+ boost::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFeatIter);
+ if (aConstraint)
+ changeConstraint(aConstraint);
+ else
+ {
+ // Sketch plugin features can be only updated
+ boost::shared_ptr<SketchPlugin_Feature> aFeature =
+ boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+ if (aFeature)
+ updateEntity(aFeature);
+ }
+ }
}
+
+ // Solve the set of constraints
+ resolveConstraints();
}
else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
{
const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
-
- if (aDeleteMsg->group().compare("Sketch") == 0)
+ const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
+
+ // Find "Sketch" in groups. The constraint groups should be updated when an object removed from Sketch
+ std::set<std::string>::const_iterator aFGrIter;
+ for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+ if (aFGrIter->compare("Sketch") == 0)
+ break;
+
+ if (aFGrIter != aFeatureGroups.end())
{
std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
while (aGroupIter != myGroups.end())
}
}
}
- else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURES_MOVED))
- {
- // Solve the set of constraints
- resolveConstraints();
- }
}
bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
{
+ // Already verified workplanes
+ std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
+
std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
{
boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
+ if (aVerified.find(aWP) != aVerified.end())
+ continue;
+
boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
if (*anIter == theConstraint)
return aWP; // workplane is found
+ aVerified.insert(aWP);
}
return boost::shared_ptr<SketchPlugin_Feature>();
std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
(*aGroupIter)->resolveConstraints();
+
+ // Features may be updated => send events
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
}
if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty())
return true;
- /// \todo Should be implemented
+ // Go through constraint entities and verify if some of them already in the group
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
+ {
+ boost::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i])
+ );
+ if (!aCAttrRef) continue;
+ if (myEntityMap.find(aCAttrRef->attr()) != myEntityMap.end())
+ return true;
+ }
+
+ // Entities did not found
return false;
}
// Created object event *******************
if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
- FeaturePtr aFeature = aUpdMsg->feature();
- DocumentPtr aDoc = aFeature->document();
-
- if (aDoc == myDocument) { // If root objects
- if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
- // Add a new part
- int aStart = myPartModels.size() + 1;
- XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
- aModel->setPartId(myPartModels.count());
- myPartModels.append(aModel);
- insertRow(aStart, partFolderNode());
- } else { // Update top groups (other except parts
- QModelIndex aIndex = myModel->findParent(aFeature);
- int aStart = myModel->rowCount(aIndex) - 1;
- aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
- insertRow(aStart, aIndex);
- }
- } else { // if sub-objects of first level nodes
- XGUI_PartModel* aPartModel = 0;
- QList<XGUI_PartModel*>::const_iterator aIt;
- for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
- if ((*aIt)->hasDocument(aDoc)) {
- aPartModel = (*aIt);
- break;
+ std::set<FeaturePtr> aFeatures = aUpdMsg->features();
+
+ std::set<FeaturePtr>::const_iterator aIt;
+ for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+ FeaturePtr aFeature = (*aIt);
+ DocumentPtr aDoc = aFeature->document();
+ if (aDoc == myDocument) { // If root objects
+ if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
+ // Add a new part
+ int aStart = myPartModels.size() + 1;
+ XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
+ aModel->setPartId(myPartModels.count());
+ myPartModels.append(aModel);
+ insertRow(aStart, partFolderNode());
+ } else { // Update top groups (other except parts
+ QModelIndex aIndex = myModel->findParent(aFeature);
+ int aStart = myModel->rowCount(aIndex) - 1;
+ aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+ insertRow(aStart, aIndex);
+ }
+ } else { // if sub-objects of first level nodes
+ XGUI_PartModel* aPartModel = 0;
+ QList<XGUI_PartModel*>::const_iterator aIt;
+ for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
+ if ((*aIt)->hasDocument(aDoc)) {
+ aPartModel = (*aIt);
+ break;
+ }
+ }
+ if (aPartModel) {
+ QModelIndex aIndex = aPartModel->findParent(aFeature);
+ int aStart = aPartModel->rowCount(aIndex) - 1;
+ aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+ insertRow(aStart, aIndex);
}
- }
- if (aPartModel) {
- QModelIndex aIndex = aPartModel->findParent(aFeature);
- int aStart = aPartModel->rowCount(aIndex) - 1;
- aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
- insertRow(aStart, aIndex);
}
}
-
// Deleted object event ***********************
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED)) {
const Model_FeatureDeletedMessage* aUpdMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
DocumentPtr aDoc = aUpdMsg->document();
-
- if (aDoc == myDocument) { // If root objects
- if (aUpdMsg->group().compare(PARTS_GROUP) == 0) { // Updsate only Parts group
- int aStart = myPartModels.size() - 1;
- removeSubModel(aStart);
- removeRow(aStart, partFolderNode());
- } else { // Update top groups (other except parts
- QModelIndex aIndex = myModel->findGroup(aUpdMsg->group());
- int aStart = myModel->rowCount(aIndex);
- aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
- removeRow(aStart, aIndex);
- }
- } else {
- XGUI_PartModel* aPartModel = 0;
- QList<XGUI_PartModel*>::const_iterator aIt;
- for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
- if ((*aIt)->hasDocument(aDoc)) {
- aPartModel = (*aIt);
- break;
+ std::set<std::string> aGroups = aUpdMsg->groups();
+
+ std::set<std::string>::const_iterator aIt;
+ for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
+ std::string aGroup = (*aIt);
+ if (aDoc == myDocument) { // If root objects
+ if (aGroup.compare(PARTS_GROUP) == 0) { // Updsate only Parts group
+ int aStart = myPartModels.size() - 1;
+ removeSubModel(aStart);
+ removeRow(aStart, partFolderNode());
+ } else { // Update top groups (other except parts
+ QModelIndex aIndex = myModel->findGroup(aGroup);
+ int aStart = myModel->rowCount(aIndex);
+ aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+ removeRow(aStart, aIndex);
+ }
+ } else {
+ XGUI_PartModel* aPartModel = 0;
+ QList<XGUI_PartModel*>::const_iterator aIt;
+ for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
+ if ((*aIt)->hasDocument(aDoc)) {
+ aPartModel = (*aIt);
+ break;
+ }
+ }
+ if (aPartModel) {
+ QModelIndex aIndex = aPartModel->findGroup(aGroup);
+ int aStart = aPartModel->rowCount(aIndex);
+ aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+ removeRow(aStart, aIndex);
}
- }
- if (aPartModel) {
- QModelIndex aIndex = aPartModel->findGroup(aUpdMsg->group());
- int aStart = aPartModel->rowCount(aIndex);
- aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
- removeRow(aStart, aIndex);
}
}
-
// Deleted object event ***********************
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED)) {
//const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
// Process creation of Part
if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
- FeaturePtr aFeature = aUpdMsg->feature();
- if (aFeature->getKind() == "Part") {
+ std::set<FeaturePtr> aFeatures = aUpdMsg->features();
+
+ std::set<FeaturePtr>::const_iterator aIt;
+ bool aHasPart = false;
+ for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+ FeaturePtr aFeature = (*aIt);
+ if (aFeature->getKind() == "Part") {
+ aHasPart = true;
+ break;
+ }
+ }
+ if (aHasPart) {
//The created part will be created in Object Browser later and we have to activate it
// only when it is created everywere
QTimer::singleShot(50, this, SLOT(activateLastPart()));
{
const Model_FeatureUpdatedMessage* anUpdateMsg =
dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
- FeaturePtr aNewFeature = anUpdateMsg->feature();
+ std::set<FeaturePtr> aFeatures = anUpdateMsg->features();
+
FeaturePtr aCurrentFeature = myOperationMgr->currentOperation()->feature();
- if(aNewFeature == aCurrentFeature) {
- myPropertyPanel->updateContentWidget(aCurrentFeature);
+ std::set<FeaturePtr>::const_iterator aIt;
+ for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+ FeaturePtr aNewFeature = (*aIt);
+ if(aNewFeature == aCurrentFeature) {
+ myPropertyPanel->updateContentWidget(aCurrentFeature);
+ break;
+ }
}
}
//An operation passed by message. Start it, process and commit.