#include <fstream>
#include <ostream>
+#ifdef WIN32
+#pragma warning(disable : 4996) // for sprintf
+#endif
+
/**
* \class Config_TSReader
* \ingroup Config
#include "Events_InfoMessage.h"
+#ifdef WIN32
+#pragma warning(disable : 4996) // for sprintf
+#endif
void Events_InfoMessage::addParameter(double theParam)
{
// Author: Mikhail PONIKAROV
#include <Events_Listener.h>
+#include <Events_MessageGroup.h>
+#include <Events_Loop.h>
+
+void Events_Listener::groupWhileFlush(const std::shared_ptr<Events_Message>& theMessage) {
+ std::shared_ptr<Events_MessageGroup> aGroup =
+ std::dynamic_pointer_cast<Events_MessageGroup>(theMessage);
+ if (aGroup) {
+ std::map<char*, std::shared_ptr<Events_Message> >::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());
+ }
+ std::shared_ptr<Events_MessageGroup> aStored =
+ std::dynamic_pointer_cast<Events_MessageGroup>(aMyGroup->second);
+ aStored->Join(aGroup);
+ //std::cout<<"Add to group "<<theMessage->eventID().eventText()<<std::endl;
+ return;
+ }
+}
+
+void Events_Listener::flushGrouped(const Events_ID& theID) {
+ std::map<char*, std::shared_ptr<Events_Message> >::iterator aMyGroup =
+ myGroups.find(theID.eventText());
+ if (aMyGroup != myGroups.end()) {
+ std::shared_ptr<Events_Message> aMessage = aMyGroup->second;
+ myGroups.erase(aMyGroup);
+ processEvent(aMessage);
+ }
+}
#include <Events.h>
#include <memory>
+#include <map>
class Events_Message;
+class Events_ID;
/**\class Events_Listener
* \ingroup EventsLoop
* If some object wants to listen some events it must inherit
* this class and register in the Loop.
*/
-class EVENTS_EXPORT Events_Listener
-{
+class Events_Listener {
+ /// map from event ID to groupped messages (for flush for groupMessages=true listeners)
+ std::map<char*, std::shared_ptr<Events_Message> > myGroups;
public:
//! This method is called by loop when the event is started to process.
- virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage) = 0;
+ EVENTS_EXPORT virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage) = 0;
+
+ //! Listener that needs mostly grouped messages received returns true in this method.
+ //! In this case during the message is flushed, all the new messages are grouped, not sended
+ //! immideately and then sent in the end of flush.
+ EVENTS_EXPORT virtual bool groupMessages() {return false;}
+
+protected:
+ //! Allows to group messages while they are flushed (for flush for groupMessages=true listeners)
+ void groupWhileFlush(const std::shared_ptr<Events_Message>& theMessage);
+ //! Sends myGroups on flush finish
+ EVENTS_EXPORT void flushGrouped(const Events_ID& theID);
+
+ friend class Events_Loop;
};
#endif
return Events_ID(aResult);
}
+void Events_Loop::sendProcessEvent(const std::shared_ptr<Events_Message>& theMessage,
+ std::list<Events_Listener*>& theListeners, const bool theFlushedNow)
+{
+ for (list<Events_Listener*>::iterator aL = theListeners.begin(); aL != theListeners.end(); aL++) {
+ if (theFlushedNow && (*aL)->groupMessages()) {
+ (*aL)->groupWhileFlush(theMessage);
+ } else {
+ (*aL)->processEvent(theMessage);
+ }
+ }
+}
+
void Events_Loop::send(const std::shared_ptr<Events_Message>& theMessage, bool isGroup)
{
if (myImmediateListeners.find(theMessage->eventID().eventText()) != myImmediateListeners.end()) {
myImmediateListeners[theMessage->eventID().eventText()]->processEvent(theMessage);
}
// if it is grouped message, just accumulate it
- if (isGroup && myFlushed.find(theMessage->eventID().myID) == myFlushed.end()) {
+ bool isFlushedNow = myFlushed.find(theMessage->eventID().myID) != myFlushed.end();
+ if (isGroup && !isFlushedNow) {
std::shared_ptr<Events_MessageGroup> aGroup =
std::dynamic_pointer_cast<Events_MessageGroup>(theMessage);
if (aGroup) {
return;
}
}
-
+ // send
map<char*, map<void*, list<Events_Listener*> > >::iterator aFindID = myListeners.find(
theMessage->eventID().eventText());
if (aFindID != myListeners.end()) {
map<void*, list<Events_Listener*> >::iterator aFindSender = aFindID->second.find(
theMessage->sender());
if (aFindSender != aFindID->second.end()) {
- list<Events_Listener*>& aListeners = aFindSender->second;
- for (list<Events_Listener*>::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++)
- (*aL)->processEvent(theMessage);
+ sendProcessEvent(theMessage, aFindSender->second, isFlushedNow && isGroup);
}
if (theMessage->sender()) { // also call for NULL senders registered
aFindSender = aFindID->second.find(NULL);
if (aFindSender != aFindID->second.end()) {
- list<Events_Listener*>& aListeners = aFindSender->second;
- for (list<Events_Listener*>::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++)
- (*aL)->processEvent(theMessage);
+ sendProcessEvent(theMessage, aFindSender->second, isFlushedNow && isGroup);
}
}
}
myGroups.erase(aMyGroup);
send(aGroup, false);
- if (!aWasFlushed)
+ if (!aWasFlushed) {
// TODO: Stabilization fix. Check later.
if(myFlushed.find(theID.myID) != myFlushed.end()) {
myFlushed.erase(myFlushed.find(theID.myID));
+ } else {
+ bool aProblem = true;
+ }
+ }
+ // send accumulated messages to "groupListeners"
+ map<char*, map<void*, list<Events_Listener*> > >::iterator aFindID = myListeners.find(
+ theID.eventText());
+ if (aFindID != myListeners.end()) {
+ map<void*, list<Events_Listener*> >::iterator aFindSender = aFindID->second.begin();
+ for(; aFindSender != aFindID->second.end(); aFindSender++) {
+ list<Events_Listener*>::iterator aListener = aFindSender->second.begin();
+ for(; aListener != aFindSender->second.end(); aListener++) {
+ if ((*aListener)->groupMessages()) {
+ (*aListener)->flushGrouped(theID);
+ }
+ }
}
+ }
}
}
/// map from event ID to listeners which must process message without waiting for flush
std::map<char*, Events_Listener*> myImmediateListeners;
- /// map from event ID to groupped messages (accumulated on flush)
+ /// map from event ID to groupped messages (accumulated for flush)
std::map<char*, std::shared_ptr<Events_Message> > myGroups;
///< set of messages that are flushed right now, so they are not grouped
EVENTS_EXPORT bool isFlushed(const Events_ID& theID);
//! Sets the flag that the event is flished right now
EVENTS_EXPORT void setFlushed(const Events_ID& theID, const bool theValue);
+
+private:
+ //! Calls "processEvent" for the given listeners.
+ //! If theFlushedNow for grouped listeners is stores message in listeners.
+ void sendProcessEvent(const std::shared_ptr<Events_Message>& theMessage,
+ std::list<Events_Listener*>& theListeners, const bool theFlushedNow);
+
};
#endif
std::list<std::shared_ptr<ModelAPI_Result> > aResults;\r
ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);\r
\r
- int aConcealedResults = aResults.size();\r
+ size_t aConcealedResults = aResults.size();\r
if (!aConcealedResults && !theArguments.empty()) {\r
// find if these results are touched by the feature in another attribute\r
std::list<std::string>::const_iterator anIt = theArguments.begin();\r
* It's aim is to fulfill the newly created documents with the "origin"
* construction point (0,0,0) and base planes (x0y, z0y, x0z)
*/
-class INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_Plugin : public Events_Listener
+class InitializationPlugin_Plugin : public Events_Listener
{
public:
/// Creates plug-in and registers it in the Event Loop
- InitializationPlugin_Plugin();
+ INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_Plugin();
/// Destructs the plugin
- virtual ~InitializationPlugin_Plugin() {}
+ INITIALIZATIONPLUGIN_EXPORT virtual ~InitializationPlugin_Plugin() {}
/// Process the ModelAPI_DocumentCreatedMessage to fulfill a document
/// from the message with origin and planes
- virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+ INITIALIZATIONPLUGIN_EXPORT virtual void processEvent(
+ const std::shared_ptr<Events_Message>& theMessage);
protected:
/// Creates a plane by given parameters A, B, C
if (aContext->groupName() == ModelAPI_ResultBody::group()) {
// body: just a named shape, use selection mechanism from OCCT
TNaming_Selector aSelector(aSelLab);
+ TopoDS_Shape anOldShape = aSelector.NamedShape()->Get();
bool aResult = aSelector.Solve(scope()) == Standard_True;
aResult = setInvalidIfFalse(aSelLab, aResult); // must be before sending of updated attribute (1556)
- owner()->data()->sendAttributeUpdated(this);
+ if (!anOldShape.IsEqual(aSelector.NamedShape()->Get())) // send updated if shape is changed
+ owner()->data()->sendAttributeUpdated(this);
return aResult;
} else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
// construction: identification by the results indexes, recompute faces and
friend class Model_AttributeReference;
friend class Model_AttributeRefAttr;
friend class Model_AttributeRefList;
- friend class Model_AttributeRefList;
friend class Model_SelectionNaming;
};
if (myModified.find(theFeature) != myModified.end()) {
if (theReason.get()) {
#ifdef DEB_UPDATE
- std::cout<<"*** Add already modified "<<theFeature->name()<<" reason "<<theReason->name()<<std::endl;
+ //std::cout<<"*** Add already modified "<<theFeature->name()<<" reason "<<theReason->name()<<std::endl;
#endif
myModified[theFeature].insert(theReason);
}
}
myModified[theFeature] = aNewSet;
#ifdef DEB_UPDATE
- if (theReason.get())
- std::cout<<"*** Add modified "<<theFeature->name()<<" reason "<<theReason->name()<<std::endl;
- else
- std::cout<<"*** Add modified "<<theFeature->name()<<std::endl;
+ if (theReason.get()) {
+ //std::cout<<"*** Add modified "<<theFeature->name()<<" reason "<<theReason->name()<<std::endl;
+ } else {
+ //std::cout<<"*** Add modified "<<theFeature->name()<<std::endl;
+ }
#endif
} else { // will be updated during the finish of the operation, or when it becomes enabled
if (theFeature->data()->execState() == ModelAPI_StateDone)
else
return true; // do not need iteration deeply if it is already marked as modified or so
#ifdef DEB_UPDATE
- std::cout<<"*** Set modified state "<<theFeature->name()<<std::endl;
+ //std::cout<<"*** Set modified state "<<theFeature->name()<<std::endl;
#endif
}
// clear processed and fill modified recursively
}
}
updateArguments(theFeature);
+ // send event that sketch is prepared to be recomputed
+ static Events_ID& anID = Events_Loop::eventByName("SketchPrepared");
+ std::shared_ptr<Events_Message> aMsg(new Events_Message(anID, this));
+ Events_Loop::loop()->send(aMsg);
}
if (!aIsModified) { // no modification is needed
/// Event ID that informs that some object has changed the stability
static const char * EVENT_STABILITY_CHANGED = "StabilityChanged";
+/// Event ID that the sketch is prepared and all grouped messages for the solver may be flushed
+static const char * EVENT_SKETCH_PREPARED = "SketchPrepared";
+
/// Message that feature was changed (used for Object Browser update): moved, updated and deleted
class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup
{
#include <GeomAPI_Lin.h>
#include <GeomAPI_Circ.h>
+#ifdef WIN32
+#pragma warning(disable : 4996) // for sprintf
+#endif
+
namespace ModelGeomAlgo_Point2D {
std::shared_ptr<GeomDataAPI_Point2D> getPointOfRefAttr(ModelAPI_Feature* theFeature,
const std::string& theAttribute,
* \ingroup Plugins
* \brief The main class for management the part set operations as plugin.
*/
-class PARTSETPLUGIN_EXPORT PartSetPlugin_Plugin : public ModelAPI_Plugin,
+class PartSetPlugin_Plugin : public ModelAPI_Plugin,
public Events_Listener
{
public:
/// Creates the feature object of this plugin by the feature string ID
- virtual FeaturePtr createFeature(std::string theFeatureID);
+ PARTSETPLUGIN_EXPORT virtual FeaturePtr createFeature(std::string theFeatureID);
/// Is needed for python wrapping by swig
- PartSetPlugin_Plugin();
+ PARTSETPLUGIN_EXPORT PartSetPlugin_Plugin();
//! Redefinition of Events_Listener method
- virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+ PARTSETPLUGIN_EXPORT virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
//! Performs the chenges of enabled/disabled state in the toolbar
//! due to the current state of the application.
- std::shared_ptr<ModelAPI_FeatureStateMessage> getFeaturesState();
+ PARTSETPLUGIN_EXPORT std::shared_ptr<ModelAPI_FeatureStateMessage> getFeaturesState();
};
#endif
* \ingroup Plugins
* \brief Interface common for any plugin: allows to use plugin by the plugins manager.
*/
-class SKETCHPLUGIN_EXPORT SketchPlugin_Plugin : public ModelAPI_Plugin, public Events_Listener
+class SketchPlugin_Plugin : public ModelAPI_Plugin, public Events_Listener
{
public:
/// Creates the feature object of this plugin by the feature string ID
- virtual FeaturePtr createFeature(std::string theFeatureID);
+ SKETCHPLUGIN_EXPORT virtual FeaturePtr createFeature(std::string theFeatureID);
+
+ /// Constructor that registers features and other plugin elements.
+ SKETCHPLUGIN_EXPORT SketchPlugin_Plugin();
- public:
- SketchPlugin_Plugin();
//! Redefinition of Events_Listener method
- virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+ SKETCHPLUGIN_EXPORT virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
protected:
//! Returns the state of the feature in the WorkBench: enabled or disabled for the moment.
std::shared_ptr<ModelAPI_FeatureStateMessage> getFeaturesState(
// Register in event loop
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ Events_Loop::loop()->registerListener(this, anUpdateEvent);
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED));
}
SketchSolver_Manager::~SketchSolver_Manager()
return myBuilder;
}
+bool SketchSolver_Manager::groupMessages()
+{
+ return true;
+}
+
// ============================================================================
// Function: processEvent
// Purpose: listen the event loop and process the message
void SketchSolver_Manager::processEvent(
const std::shared_ptr<Events_Message>& theMessage)
{
+ static const Events_ID aSketchPreparedEvent = Events_Loop::eventByName(EVENT_SKETCH_PREPARED);
+ // sketch is prepared for resolve: all the needed events are collected and must be processed by the solver
+ if (theMessage->eventID() == aSketchPreparedEvent) {
+ flushGrouped(anUpdateEvent);
+ return;
+ }
+
checkConflictingConstraints(theMessage);
+
if (myIsComputed)
return;
myIsComputed = true;
bool hasProperFeature = false;
if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
- || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
+ || theMessage->eventID() == anUpdateEvent
|| theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
// Features may be updated => now send events, but for all changed at once
if (isUpdateFlushed)
allowSendUpdate();
+
+ myIsComputed = false;
+
// send update for movement in any case
if (needToUpdate || isMovedEvt)
Events_Loop::loop()->flush(anUpdateEvent);
if (!aGroupsToResolve.empty())
resolveConstraints(aGroupsToResolve);
}
+ myIsComputed = false;
}
if (hasProperFeature)
degreesOfFreedom();
- myIsComputed = false;
}
void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptr<Events_Message>& theMessage)
*/
virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+ /**
+ * The solver needs all the updated objects are transfered in one group, not one by one.
+ * This iscreases performance and avoids problems in resolve of only part of the made updates.
+ */
+ virtual bool groupMessages();
+
/// \brief Initialize builder for solver's data structure entities
/// \param theBuilder [in] solver's specific builder
SKETCHSOLVER_EXPORT void setBuilder(BuilderPtr theBuilder);
* Gets the number of the steps.
* @return the number of steps.
*/
- const int countSteps() const { return m_steps.size(); }
+ const int countSteps() const { return int(m_steps.size()); }
/**
* Gets the name of a component.
*/
const int count() const
{
- return m_elements.size();
+ return int(m_elements.size());
}
/**