- Use a NotifyLock instead of (History|Simulation)::set_notify_enabled() method, which is more elegant and also exception-safe
- Delete set_notify_enabled() method from ConcreteHistory; it was both wrong and useless, and caused impredictable behaviour! - Don't make some methods of History and Simulation virtual if we don't want the user to override them - Loading from file and jumping to an instant of the simulation should be much quickier now git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@1170 3ecf2c5c-341e-0410-92b4-d18e462d057c
This commit is contained in:
parent
737324f250
commit
83b655496f
|
@ -70,7 +70,7 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his
|
||||||
// DEBUG - remove me when finished
|
// DEBUG - remove me when finished
|
||||||
|
|
||||||
// disable notifications over history until the end of this method
|
// disable notifications over history until the end of this method
|
||||||
bool was_enabled = hist.set_notify_enabled(false);
|
History::LockNotify h_lock(hist);
|
||||||
|
|
||||||
#ifdef LIBXML_SAX1_ENABLED
|
#ifdef LIBXML_SAX1_ENABLED
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
|
@ -107,8 +107,6 @@ void XMLSerializer::restore_snapshot(const Glib::ustring& filename, History& his
|
||||||
#error Compilation of LIBXML with SAX1 support must be enabled
|
#error Compilation of LIBXML with SAX1 support must be enabled
|
||||||
#endif /* LIBXML_SAX1_ENABLED */
|
#endif /* LIBXML_SAX1_ENABLED */
|
||||||
|
|
||||||
// Re-enable notifications over history observers
|
|
||||||
hist.set_notify_enabled(was_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ AddRequestDialog::run_edit(Request& request)
|
||||||
{
|
{
|
||||||
assert(_list_model->children());
|
assert(_list_model->children());
|
||||||
|
|
||||||
bool was_enabled = history.set_notify_enabled(false);
|
History::LockNotify h_lock(history);
|
||||||
|
|
||||||
// I know it's a bit hack-ish, but do you know an elegant alternative way?
|
// I know it's a bit hack-ish, but do you know an elegant alternative way?
|
||||||
for(Iseq<vector<SubRequest*>::iterator> it = iseq(subrequests); it; ++it)
|
for(Iseq<vector<SubRequest*>::iterator> it = iseq(subrequests); it; ++it)
|
||||||
|
@ -178,8 +178,6 @@ AddRequestDialog::run_edit(Request& request)
|
||||||
|
|
||||||
for(Iseq<TreeIter> it = iseq(sreq_container); it; ++it)
|
for(Iseq<TreeIter> it = iseq(sreq_container); it; ++it)
|
||||||
history.add_subrequest(request, (*it)[_list_key_column], (*it)[_list_duration_column]);
|
history.add_subrequest(request, (*it)[_list_key_column], (*it)[_list_duration_column]);
|
||||||
|
|
||||||
history.set_notify_enabled(was_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hide();
|
hide();
|
||||||
|
|
|
@ -523,14 +523,6 @@ ConcreteHistory::reset(bool notify)
|
||||||
notify_change();
|
notify_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ConcreteHistory::notify_change()
|
|
||||||
{
|
|
||||||
History::RegisteredObservers::iterator it;
|
|
||||||
for (it = _observers.begin(); it != _observers.end(); it++)
|
|
||||||
(*it)->update(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ConcreteHistory::is_sealed() const
|
ConcreteHistory::is_sealed() const
|
||||||
|
|
|
@ -124,8 +124,6 @@ namespace sgpem
|
||||||
typedef std::vector<ConcreteEnvironment*> Snapshots;
|
typedef std::vector<ConcreteEnvironment*> Snapshots;
|
||||||
Snapshots _snapshots;
|
Snapshots _snapshots;
|
||||||
|
|
||||||
virtual void notify_change();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Disable assignment, implement it only if needed
|
// Disable assignment, implement it only if needed
|
||||||
ConcreteHistory& operator=(const ConcreteHistory& op2);
|
ConcreteHistory& operator=(const ConcreteHistory& op2);
|
||||||
|
|
|
@ -73,39 +73,21 @@ ConcreteSimulation::jump_to(History::position p) throw(UserInterruptException, N
|
||||||
|
|
||||||
// Disable momentarily updates for registered observers on
|
// Disable momentarily updates for registered observers on
|
||||||
// sgpem::Simulation and sgpem::History.
|
// sgpem::Simulation and sgpem::History.
|
||||||
bool his_enabled = _history.set_notify_enabled(false);
|
History::LockNotify h_lock(_history);
|
||||||
bool sim_enabled = set_notify_enabled(false);
|
Simulation::LockNotify s_lock(*this);
|
||||||
|
|
||||||
pause();
|
pause();
|
||||||
|
|
||||||
bool yet_to_finish = true;
|
bool yet_to_finish = true;
|
||||||
History::position increment = 0;
|
History::position increment = 0;
|
||||||
while (yet_to_finish && p > _history.get_front() + increment)
|
while (yet_to_finish && p > _history.get_front() + increment)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
yet_to_finish = step();
|
yet_to_finish = step();
|
||||||
increment++;
|
increment++;
|
||||||
}
|
}
|
||||||
catch(const CPUPolicyException&)
|
|
||||||
{
|
|
||||||
// Lookout that notifications have to be re-enabled.
|
|
||||||
_history.set_notify_enabled(his_enabled);
|
|
||||||
set_notify_enabled(sim_enabled);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get_history().set_front(std::min(p, _history.get_size()));
|
get_history().set_front(std::min(p, _history.get_size()));
|
||||||
if (!yet_to_finish)
|
if (!yet_to_finish)
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
// Reenables updates to registered observers.
|
|
||||||
// Calls _history.notify_change() on reactivation.
|
|
||||||
_history.set_notify_enabled(his_enabled);
|
|
||||||
|
|
||||||
// Do the same for notifications on the state
|
|
||||||
// of Simulation
|
|
||||||
set_notify_enabled(sim_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,5 @@ namespace sgpem
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,15 @@ History::set_notify_enabled(bool enabled)
|
||||||
return old_value;
|
return old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
History::is_notify_enabled() const
|
// --------- History::LockNotify ---------------
|
||||||
|
|
||||||
|
History::LockNotify::LockNotify(History& history)
|
||||||
|
: _h(history), _was_enabled(_h.set_notify_enabled(false))
|
||||||
{
|
{
|
||||||
return _notify;
|
}
|
||||||
|
|
||||||
|
History::LockNotify::~LockNotify()
|
||||||
|
{
|
||||||
|
_h.set_notify_enabled(_was_enabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,10 @@ namespace sgpem
|
||||||
class SG_DLLEXPORT History
|
class SG_DLLEXPORT History
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Forward declaration
|
||||||
|
class LockNotify;
|
||||||
|
friend class History::LockNotify;
|
||||||
|
|
||||||
typedef unsigned int size_t;
|
typedef unsigned int size_t;
|
||||||
typedef unsigned int time_t;
|
typedef unsigned int time_t;
|
||||||
typedef unsigned int position;
|
typedef unsigned int position;
|
||||||
|
@ -134,6 +138,14 @@ namespace sgpem
|
||||||
virtual void attach(HistoryObserver& observer);
|
virtual void attach(HistoryObserver& observer);
|
||||||
virtual void detach(const HistoryObserver& observer);
|
virtual void detach(const HistoryObserver& observer);
|
||||||
|
|
||||||
|
virtual void reset() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef std::vector<HistoryObserver*> RegisteredObservers;
|
||||||
|
RegisteredObservers _observers;
|
||||||
|
|
||||||
|
void notify_change();
|
||||||
|
|
||||||
/** \brief Enable/disable notifications to registered observers
|
/** \brief Enable/disable notifications to registered observers
|
||||||
*
|
*
|
||||||
* This is quite useful to disable momentarily notification while you
|
* This is quite useful to disable momentarily notification while you
|
||||||
|
@ -142,26 +154,36 @@ namespace sgpem
|
||||||
*
|
*
|
||||||
* \return The old value
|
* \return The old value
|
||||||
*/
|
*/
|
||||||
virtual bool set_notify_enabled(bool enabled = true);
|
bool set_notify_enabled(bool enabled = true);
|
||||||
bool is_notify_enabled() const;
|
|
||||||
|
|
||||||
virtual void reset() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::vector<HistoryObserver*> RegisteredObservers;
|
|
||||||
RegisteredObservers _observers;
|
|
||||||
|
|
||||||
virtual void notify_change();
|
|
||||||
|
|
||||||
position _front;
|
position _front;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
bool _notify;
|
bool _notify;
|
||||||
|
|
||||||
}
|
}; //~ class History
|
||||||
; //~ class History
|
|
||||||
|
/** \brief Disables notifications to History during the life of this object
|
||||||
|
*
|
||||||
|
* This class is useful if you've to do a lot of sequential operations on
|
||||||
|
* History that would reset it / notify its observers. For example, when loading
|
||||||
|
* from a file. In this case, create an object of this type on the stack.
|
||||||
|
* The destructor will take care of re-enabling notifications.
|
||||||
|
*/
|
||||||
|
class SG_DLLEXPORT History::LockNotify
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LockNotify(History& history);
|
||||||
|
~LockNotify();
|
||||||
|
|
||||||
|
private:
|
||||||
|
History& _h;
|
||||||
|
bool _was_enabled;
|
||||||
|
|
||||||
|
LockNotify(const LockNotify&);
|
||||||
|
LockNotify& operator=(const LockNotify&);
|
||||||
|
}; //~ class History::LockNotify
|
||||||
|
|
||||||
|
|
||||||
}//~ namespace sgpem
|
}//~ namespace sgpem
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,9 @@ namespace sgpem
|
||||||
class SG_DLLEXPORT Simulation : public Singleton<ConcreteSimulation>
|
class SG_DLLEXPORT Simulation : public Singleton<ConcreteSimulation>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
class LockNotify;
|
||||||
|
friend class Simulation::LockNotify;
|
||||||
|
|
||||||
enum state
|
enum state
|
||||||
{
|
{
|
||||||
state_running = 0xdeafd0d0,
|
state_running = 0xdeafd0d0,
|
||||||
|
@ -170,6 +173,10 @@ namespace sgpem
|
||||||
virtual void attach(SimulationObserver& observer);
|
virtual void attach(SimulationObserver& observer);
|
||||||
virtual void detach(const SimulationObserver& observer);
|
virtual void detach(const SimulationObserver& observer);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef std::vector<SimulationObserver*> RegisteredObservers;
|
||||||
|
RegisteredObservers _observers;
|
||||||
|
|
||||||
/** \brief Enable/disable notifications to registered observers
|
/** \brief Enable/disable notifications to registered observers
|
||||||
*
|
*
|
||||||
* This is quite useful to disable momentarily notification while you
|
* This is quite useful to disable momentarily notification while you
|
||||||
|
@ -178,20 +185,36 @@ namespace sgpem
|
||||||
*
|
*
|
||||||
* \return The old value
|
* \return The old value
|
||||||
*/
|
*/
|
||||||
virtual bool set_notify_enabled(bool enabled = true);
|
bool set_notify_enabled(bool enabled = true);
|
||||||
bool is_notify_enabled() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::vector<SimulationObserver*> RegisteredObservers;
|
|
||||||
RegisteredObservers _observers;
|
|
||||||
|
|
||||||
Simulation(); // Constructor
|
Simulation(); // Constructor
|
||||||
|
|
||||||
virtual void notify_change();
|
void notify_change();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _notify;
|
bool _notify;
|
||||||
};
|
}; //~ class Simulation
|
||||||
|
|
||||||
|
/** \brief Disables notifications to Simulation during the life of this object
|
||||||
|
*
|
||||||
|
* This class is useful if you've to do a lot of sequential operations on
|
||||||
|
* Simulation that would reset it / notify its observers. For example, when loading
|
||||||
|
* from a file. In this case, create an object of this type on the stack.
|
||||||
|
* The destructor will take care of re-enabling notifications.
|
||||||
|
*/
|
||||||
|
class SG_DLLEXPORT Simulation::LockNotify
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LockNotify(Simulation& simulation);
|
||||||
|
~LockNotify();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Simulation& _s;
|
||||||
|
bool _was_enabled;
|
||||||
|
|
||||||
|
LockNotify(const LockNotify&);
|
||||||
|
LockNotify& operator=(const LockNotify&);
|
||||||
|
}; //~ class Simulation::LockNotify
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,14 @@ Simulation::set_notify_enabled(bool enabled)
|
||||||
return old_value;
|
return old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
// --------- Simulation::LockNotify ---------------
|
||||||
Simulation::is_notify_enabled() const
|
|
||||||
|
Simulation::LockNotify::LockNotify(Simulation& simulation)
|
||||||
|
: _s(simulation), _was_enabled(_s.set_notify_enabled(false))
|
||||||
{
|
{
|
||||||
return _notify;
|
}
|
||||||
|
|
||||||
|
Simulation::LockNotify::~LockNotify()
|
||||||
|
{
|
||||||
|
_s.set_notify_enabled(_was_enabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,9 +84,6 @@ JumpToDialog::start()
|
||||||
// start listening to simulation updates
|
// start listening to simulation updates
|
||||||
sim.attach(*this);
|
sim.attach(*this);
|
||||||
|
|
||||||
// remember state of notifications for History
|
|
||||||
bool reenable = h.is_notify_enabled();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(_target_instant < h.get_size() - 1)
|
if(_target_instant < h.get_size() - 1)
|
||||||
|
@ -94,9 +91,9 @@ JumpToDialog::start()
|
||||||
else
|
else
|
||||||
sim.jump_to(h.get_size() - 1);
|
sim.jump_to(h.get_size() - 1);
|
||||||
|
|
||||||
// disable notifications since we could call
|
// disable notifications on History since we could call
|
||||||
// run() a lot of times
|
// run() a lot of times
|
||||||
h.set_notify_enabled(false);
|
History::LockNotify h_lock(h);
|
||||||
while(h.get_front() <= _target_instant)
|
while(h.get_front() <= _target_instant)
|
||||||
{
|
{
|
||||||
sim.run();
|
sim.run();
|
||||||
|
@ -149,7 +146,6 @@ JumpToDialog::start()
|
||||||
// Ending successfully: detach me, reenable notifications,
|
// Ending successfully: detach me, reenable notifications,
|
||||||
// and emit response ``okay''
|
// and emit response ``okay''
|
||||||
sim.detach(*this);
|
sim.detach(*this);
|
||||||
h.set_notify_enabled(reenable);
|
|
||||||
response(Gtk::RESPONSE_OK);
|
response(Gtk::RESPONSE_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue