summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJon A. Cruz <jon@joncruz.org>2014-03-08 03:14:20 +0000
committerJon A. Cruz <jon@joncruz.org>2014-03-08 03:14:20 +0000
commit19d4e1aa3f982b4b841c76eed22491a3a63084cb (patch)
treeb0070039eec1eee49f69b4a733ec67063db83e83 /src
parentSymbols. Adding missing include. (diff)
downloadinkscape-19d4e1aa3f982b4b841c76eed22491a3a63084cb.tar.gz
inkscape-19d4e1aa3f982b4b841c76eed22491a3a63084cb.zip
Reconnect correctly as documents are replaced.
Removed hardcoding to only a single panel. (bzr r13127)
Diffstat (limited to 'src')
-rw-r--r--src/event-log.cpp254
-rw-r--r--src/event-log.h24
-rw-r--r--src/ui/dialog/undo-history.cpp130
-rw-r--r--src/ui/dialog/undo-history.h11
-rw-r--r--src/util/signal-blocker.h70
5 files changed, 362 insertions, 127 deletions
diff --git a/src/event-log.cpp b/src/event-log.cpp
index d0342fbe9..db680d6d2 100644
--- a/src/event-log.cpp
+++ b/src/event-log.cpp
@@ -1,34 +1,182 @@
/*
* Author:
* Gustav Broberg <broberg@kth.se>
+ * Jon A. Cruz <jon@joncruz.org>
*
- * Copyright (c) 2006, 2007 Authors
+ * Copyright (c) 2014 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include "util/signal-blocker.h"
+
#include "event-log.h"
#include <glibmm/i18n.h>
+#include <gtkmm/treemodel.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
#include "desktop.h"
#include "inkscape.h"
+#include "util/signal-blocker.h"
#include "util/ucompose.hpp"
#include "document.h"
#include "xml/repr.h"
#include "sp-object.h"
+namespace
+{
+
+class DialogConnection
+{
+public:
+ DialogConnection(Gtk::TreeView *event_list_view, Inkscape::EventLog::CallbackMap *callback_connections) :
+ _event_list_view(event_list_view),
+ _callback_connections(callback_connections),
+ _event_list_selection(_event_list_view->get_selection())
+ {
+ }
+
+ Gtk::TreeView *_event_list_view;
+
+ // Map of connections used to temporary block/unblock callbacks in a TreeView
+ Inkscape::EventLog::CallbackMap *_callback_connections;
+
+ Glib::RefPtr<Gtk::TreeSelection> _event_list_selection; /// @todo remove this and use _event_list_view's call
+};
+
+class ConnectionMatcher
+{
+public:
+ ConnectionMatcher(Gtk::TreeView *view,
+ Inkscape::EventLog::CallbackMap *callbacks) :
+ _view(view),
+ _callbacks(callbacks)
+ {
+ }
+
+ bool operator() (DialogConnection const &dlg)
+ {
+ return (_view == dlg._event_list_view) && (_callbacks == dlg._callback_connections);
+ }
+
+ Gtk::TreeView *_view;
+ Inkscape::EventLog::CallbackMap *_callbacks;
+};
+
+void addBlocker(std::vector<boost::shared_ptr<SignalBlocker> > &blockers, sigc::connection *connection)
+{
+ blockers.push_back(boost::make_shared<SignalBlocker>(connection));
+}
+
+
+} // namespace
+
namespace Inkscape {
+class EventLogPrivate
+{
+public:
+ EventLogPrivate() :
+ _connections()
+ {
+ }
+
+ bool isConnected() const
+ {
+ return !_connections.empty();
+ }
+
+ void addDialogConnection(Gtk::TreeView *event_list_view,
+ Inkscape::EventLog::CallbackMap *callback_connections,
+ Glib::RefPtr<Gtk::TreeStore> event_list_store,
+ Inkscape::EventLog::iterator &curr_event)
+ {
+ if (std::find_if(_connections.begin(), _connections.end(), ConnectionMatcher(event_list_view, callback_connections)) != _connections.end()) {
+ // skipping
+ }
+ else
+ {
+ DialogConnection dlg(event_list_view, callback_connections);
+
+ dlg._event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
+
+ {
+ std::vector<boost::shared_ptr<SignalBlocker> > blockers;
+ addBlocker(blockers, &(*dlg._callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]);
+ addBlocker(blockers, &(*dlg._callback_connections)[Inkscape::EventLog::CALLB_EXPAND]);
+
+ dlg._event_list_view->expand_to_path(event_list_store->get_path(curr_event));
+ dlg._event_list_selection->select(curr_event);
+ }
+ _connections.push_back(dlg);
+ }
+ }
+
+ void removeDialogConnection(Gtk::TreeView *event_list_view, Inkscape::EventLog::CallbackMap *callback_connections)
+ {
+ std::vector<DialogConnection>::iterator it = std::find_if(_connections.begin(), _connections.end(), ConnectionMatcher(event_list_view, callback_connections));
+ if (it != _connections.end()) {
+ _connections.erase(it);
+ }
+ }
+
+ void collapseRow(Gtk::TreeModel::Path const &path)
+ {
+ std::vector<boost::shared_ptr<SignalBlocker> > blockers;
+ for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it)
+ {
+ addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]);
+ addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_COLLAPSE]);
+ }
+
+ for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it)
+ {
+ it->_event_list_view->collapse_row(path);
+ }
+ }
+
+ void selectRow(Gtk::TreeModel::Path const &path)
+ {
+ std::vector<boost::shared_ptr<SignalBlocker> > blockers;
+ for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it)
+ {
+ addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]);
+ addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_EXPAND]);
+ }
+
+ for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it)
+ {
+ it->_event_list_view->expand_to_path(path);
+ it->_event_list_selection->select(path);
+ it->_event_list_view->scroll_to_row(path);
+ }
+ }
+
+ void clearEventList(Glib::RefPtr<Gtk::TreeStore> eventListStore)
+ {
+ if (eventListStore) {
+ std::vector<boost::shared_ptr<SignalBlocker> > blockers;
+ for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it)
+ {
+ addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]);
+ addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_EXPAND]);
+ }
+
+ eventListStore->clear();
+ }
+ }
+
+ std::vector<DialogConnection> _connections;
+};
+
EventLog::EventLog(SPDocument* document) :
UndoStackObserver(),
- _connected (false),
+ _priv(new EventLogPrivate()),
_document (document),
_event_list_store (Gtk::TreeStore::create(_columns)),
- _event_list_selection (NULL),
- _event_list_view (NULL),
_curr_event_parent (NULL),
- _notifications_blocked (false),
- _callback_connections (NULL)
+ _notifications_blocked (false)
{
// add initial pseudo event
Gtk::TreeRow curr_row = *(_event_list_store->append());
@@ -39,16 +187,11 @@ EventLog::EventLog(SPDocument* document) :
}
EventLog::~EventLog() {
- // avoid crash by clearing entries here (see bug #1071082)
- if (_connected) {
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
- (*_callback_connections)[CALLB_EXPAND].block();
+ // avoid crash by clearing entries here (see bug #1071082)
+ _priv->clearEventList(_event_list_store);
- _event_list_store->clear();
-
- (*_callback_connections)[CALLB_EXPAND].block(false);
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
- }
+ delete _priv;
+ _priv = 0;
}
void
@@ -70,10 +213,8 @@ EventLog::notifyUndoEvent(Event* log)
} else {
// if we're about to leave a branch, collapse it
- if ( !_curr_event->children().empty() && _connected ) {
- (*_callback_connections)[CALLB_COLLAPSE].block();
- _event_list_view->collapse_row(_event_list_store->get_path(_curr_event));
- (*_callback_connections)[CALLB_COLLAPSE].block(false);
+ if ( !_curr_event->children().empty() ) {
+ _priv->collapseRow(_event_list_store->get_path(_curr_event));
}
--_curr_event;
@@ -89,17 +230,9 @@ EventLog::notifyUndoEvent(Event* log)
checkForVirginity();
// update the view
- if (_connected) {
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
- (*_callback_connections)[CALLB_EXPAND].block();
-
+ if (_priv->isConnected()) {
Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
- _event_list_view->expand_to_path(curr_path);
- _event_list_selection->select(curr_path);
- _event_list_view->scroll_to_row(curr_path);
-
- (*_callback_connections)[CALLB_EXPAND].block(false);
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
+ _priv->selectRow(curr_path);
}
updateUndoVerbs();
@@ -132,13 +265,7 @@ EventLog::notifyRedoEvent(Event* log)
{
// ...collapse it
- if (_connected) {
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
- (*_callback_connections)[CALLB_COLLAPSE].block();
- _event_list_view->collapse_row(_event_list_store->get_path(_curr_event->parent()));
- (*_callback_connections)[CALLB_COLLAPSE].block(false);
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
- }
+ _priv->collapseRow(_event_list_store->get_path(_curr_event->parent()));
// ...and move to the next event at parent level
_curr_event = _curr_event->parent();
@@ -151,18 +278,9 @@ EventLog::notifyRedoEvent(Event* log)
checkForVirginity();
// update the view
- if (_connected) {
+ if (_priv->isConnected()) {
Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
-
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
- (*_callback_connections)[CALLB_EXPAND].block();
-
- _event_list_view->expand_to_path(curr_path);
- _event_list_selection->select(curr_path);
- _event_list_view->scroll_to_row(curr_path);
-
- (*_callback_connections)[CALLB_EXPAND].block(false);
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
+ _priv->selectRow(curr_path);
}
updateUndoVerbs();
@@ -193,10 +311,8 @@ EventLog::notifyUndoCommitEvent(Event* log)
_curr_event = _last_event = curr_row;
// collapse if we're leaving a branch
- if (_curr_event_parent && _connected) {
- (*_callback_connections)[CALLB_COLLAPSE].block();
- _event_list_view->collapse_row(_event_list_store->get_path(_curr_event_parent));
- (*_callback_connections)[CALLB_COLLAPSE].block(false);
+ if (_curr_event_parent) {
+ _priv->collapseRow(_event_list_store->get_path(_curr_event_parent));
}
_curr_event_parent = (iterator)(NULL);
@@ -211,18 +327,9 @@ EventLog::notifyUndoCommitEvent(Event* log)
checkForVirginity();
// update the view
- if (_connected) {
+ if (_priv->isConnected()) {
Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
-
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
- (*_callback_connections)[CALLB_EXPAND].block();
-
- _event_list_view->expand_to_path(curr_path);
- _event_list_selection->select(curr_path);
- _event_list_view->scroll_to_row(curr_path);
-
- (*_callback_connections)[CALLB_EXPAND].block(false);
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
+ _priv->selectRow(curr_path);
}
updateUndoVerbs();
@@ -242,25 +349,14 @@ EventLog::notifyClearRedoEvent()
updateUndoVerbs();
}
-void
-EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
+void EventLog::addDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
{
- _event_list_view = event_list_view;
- _event_list_selection = event_list_view->get_selection();
- _event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
-
- _callback_connections = callback_connections;
-
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
- (*_callback_connections)[CALLB_EXPAND].block();
-
- _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event));
- _event_list_selection->select(_curr_event);
-
- (*_callback_connections)[CALLB_EXPAND].block(false);
- (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
+ _priv->addDialogConnection(event_list_view, callback_connections, _event_list_store, _curr_event);
+}
- _connected = true;
+void EventLog::removeDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
+{
+ _priv->removeDialogConnection(event_list_view, callback_connections);
}
void
diff --git a/src/event-log.h b/src/event-log.h
index 78f0ae5d1..7e3ba6817 100644
--- a/src/event-log.h
+++ b/src/event-log.h
@@ -1,8 +1,9 @@
/*
* Author:
* Gustav Broberg <broberg@kth.se>
+ * Jon A. Cruz <jon@joncruz.org>
*
- * Copyright (c) 2006, 2007 Authors
+ * Copyright (c) 2014 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -22,12 +23,15 @@
#include <glibmm/refptr.h>
#include <gtkmm/treeselection.h>
#include <gtkmm/treeview.h>
+#include <sigc++/trackable.h>
#include "undo-stack-observer.h"
#include "event.h"
namespace Inkscape {
+class EventLogPrivate;
+
/**
* A simple log for maintaining a history of commited, undone and redone events along with their
* type. It implements the UndoStackObserver and should be registered with a
@@ -41,7 +45,7 @@ namespace Inkscape {
* expanded/collapsed state will be updated as events are commited, undone and redone. Whenever
* this happens, the event log will block the TreeView's callbacks to prevent circular updates.
*/
-class EventLog : public UndoStackObserver
+class EventLog : public UndoStackObserver, public sigc::trackable
{
public:
@@ -104,7 +108,12 @@ public:
/**
* Connect with a TreeView.
*/
- void connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections);
+ void addDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections);
+
+ /**
+ * Disconnect from a TreeView.
+ */
+ void removeDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections);
/*
* Updates the sensitivity and names of SP_VERB_EDIT_UNDO and SP_VERB_EDIT_REDO to reflect the
@@ -113,14 +122,13 @@ public:
void updateUndoVerbs();
private:
- bool _connected; //< connected with dialog
+ EventLogPrivate *_priv;
+
SPDocument *_document; //< document that is logged
const EventModelColumns _columns;
Glib::RefPtr<Gtk::TreeStore> _event_list_store;
- Glib::RefPtr<Gtk::TreeSelection> _event_list_selection;
- Gtk::TreeView *_event_list_view;
iterator _curr_event; //< current event in _event_list_store
iterator _last_event; //< end position in _event_list_store
@@ -130,9 +138,6 @@ private:
bool _notifications_blocked; //< if notifications should be handled
- // Map of connections used to temporary block/unblock callbacks in a TreeView
- CallbackMap *_callback_connections;
-
// Helper functions
const_iterator _getUndoEvent() const; //< returns the current undoable event or NULL if none
@@ -146,7 +151,6 @@ private:
// noncopyable, nonassignable
EventLog(EventLog const &other);
EventLog& operator=(EventLog const &other);
-
};
} // namespace Inkscape
diff --git a/src/ui/dialog/undo-history.cpp b/src/ui/dialog/undo-history.cpp
index a487eb930..2412c3ec9 100644
--- a/src/ui/dialog/undo-history.cpp
+++ b/src/ui/dialog/undo-history.cpp
@@ -5,8 +5,9 @@
/* Author:
* Gustav Broberg <broberg@kth.se>
* Abhishek Sharma
+ * Jon A. Cruz <jon@joncruz.org>
*
- * Copyright (C) 2006 Authors
+ * Copyright (C) 2014 Authors
* Released under GNU GPL. Read the file 'COPYING' for more information.
*/
@@ -24,6 +25,7 @@
#include "inkscape.h"
#include "verbs.h"
#include "desktop-handles.h"
+#include "util/signal-blocker.h"
#include "desktop.h"
#include <gtkmm/invisible.h>
@@ -131,39 +133,19 @@ UndoHistory& UndoHistory::getInstance()
return *new UndoHistory();
}
-void
-UndoHistory::setDesktop(SPDesktop* desktop)
-{
- Panel::setDesktop(desktop);
-
- if (!desktop) return;
-
- _document = sp_desktop_document(desktop);
-
- _event_log = desktop->event_log;
-
- _callback_connections[EventLog::CALLB_SELECTION_CHANGE].block();
-
- _event_list_store = _event_log->getEventListStore();
- _event_list_view.set_model(_event_list_store);
- _event_list_selection = _event_list_view.get_selection();
-
- _event_log->connectWithDialog(&_event_list_view, &_callback_connections);
- _event_list_view.scroll_to_row(_event_list_store->get_path(_event_list_selection->get_selected()));
-
- _callback_connections[EventLog::CALLB_SELECTION_CHANGE].block(false);
-}
-
UndoHistory::UndoHistory()
: UI::Widget::Panel ("", "/dialogs/undo-history", SP_VERB_DIALOG_UNDO_HISTORY),
- _document (sp_desktop_document(getDesktop())),
- _event_log (getDesktop() ? getDesktop()->event_log : NULL),
- _columns (_event_log ? &_event_log->getColumns() : NULL),
- _event_list_selection (_event_list_view.get_selection()),
- _desktop(NULL),
+ _document_replaced_connection(),
+ _desktop(getDesktop()),
+ _document(_desktop ? _desktop->doc() : NULL),
+ _event_log(_desktop ? _desktop->event_log : NULL),
+ _columns(_event_log ? &_event_log->getColumns() : NULL),
+ _scrolled_window(),
+ _event_list_store(),
+ _event_list_selection(_event_list_view.get_selection()),
_deskTrack(),
- _desktopChangeConn()
-
+ _desktopChangeConn(),
+ _callback_connections()
{
if ( !_document || !_event_log || !_columns ) return;
@@ -172,9 +154,9 @@ UndoHistory::UndoHistory()
_getContents()->pack_start(_scrolled_window);
_scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
- _event_list_store = _event_log->getEventListStore();
+ // connect with the EventLog
+ _connectEventLog();
- _event_list_view.set_model(_event_list_store);
_event_list_view.set_rules_hint(false);
_event_list_view.set_enable_search(false);
_event_list_view.set_headers_visible(false);
@@ -221,12 +203,12 @@ UndoHistory::UndoHistory()
_callback_connections[EventLog::CALLB_COLLAPSE] =
_event_list_view.signal_row_collapsed().connect(sigc::mem_fun(*this, &Inkscape::UI::Dialog::UndoHistory::_onCollapseEvent));
- // connect with the EventLog
- _event_log->connectWithDialog(&_event_list_view, &_callback_connections);
-
_desktopChangeConn = _deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &UndoHistory::setDesktop) );
_deskTrack.connect(GTK_WIDGET(gobj()));
+ // connect to be informed of document changes
+ signalDocumentReplaced().connect(sigc::mem_fun(*this, &UndoHistory::_handleDocumentReplaced));
+
show_all_children();
// scroll to the selected row
@@ -239,6 +221,82 @@ UndoHistory::~UndoHistory()
}
+void UndoHistory::setDesktop(SPDesktop* desktop)
+{
+ Panel::setDesktop(desktop);
+
+ EventLog *newEventLog = desktop ? desktop->event_log : NULL;
+ if ((_desktop == desktop) && (_event_log == newEventLog)) {
+ // same desktop set
+ }
+ else
+ {
+ _connectDocument(desktop, desktop ? desktop->doc() : NULL);
+ }
+}
+
+void UndoHistory::_connectDocument(SPDesktop* desktop, SPDocument *document)
+{
+ // disconnect from prior
+ if (_event_log) {
+ _event_log->removeDialogConnection(&_event_list_view, &_callback_connections);
+ }
+
+ SignalBlocker blocker(&_callback_connections[EventLog::CALLB_SELECTION_CHANGE]);
+
+ _event_list_view.unset_model();
+
+ // connect to new EventLog/Desktop
+ _desktop = desktop;
+ _event_log = desktop ? desktop->event_log : NULL;
+ _document = desktop ? desktop->doc() : NULL;
+ _connectEventLog();
+}
+
+void UndoHistory::_connectEventLog()
+{
+ if (_event_log) {
+ _event_log->add_destroy_notify_callback(this, &_handleEventLogDestroyCB);
+ _event_list_store = _event_log->getEventListStore();
+
+ _event_list_view.set_model(_event_list_store);
+
+ _event_log->addDialogConnection(&_event_list_view, &_callback_connections);
+ _event_list_view.scroll_to_row(_event_list_store->get_path(_event_list_selection->get_selected()));
+ }
+}
+
+void UndoHistory::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *document)
+{
+ if ((desktop != _desktop) || (document != _document)) {
+ _connectDocument(desktop, document);
+ }
+}
+
+void *UndoHistory::_handleEventLogDestroyCB(void *data)
+{
+ void *result = NULL;
+ if (data) {
+ UndoHistory *self = reinterpret_cast<UndoHistory*>(data);
+ result = self->_handleEventLogDestroy();
+ }
+ return result;
+}
+
+// called *after* _event_log has been destroyed.
+void *UndoHistory::_handleEventLogDestroy()
+{
+ if (_event_log) {
+ SignalBlocker blocker(&_callback_connections[EventLog::CALLB_SELECTION_CHANGE]);
+
+ _event_list_view.unset_model();
+ _event_list_store.reset();
+ _event_log = NULL;
+ }
+
+ return NULL;
+}
+
void
UndoHistory::_onListSelectionChange()
{
diff --git a/src/ui/dialog/undo-history.h b/src/ui/dialog/undo-history.h
index adf4f1936..b0cc283cf 100644
--- a/src/ui/dialog/undo-history.h
+++ b/src/ui/dialog/undo-history.h
@@ -3,8 +3,9 @@
*/
/* Author:
* Gustav Broberg <broberg@kth.se>
+ * Jon A. Cruz <jon@joncruz.org>
*
- * Copyright (C) 2006 Authors
+ * Copyright (C) 2014 Authors
* Released under GNU GPL. Read the file 'COPYING' for more information.
*/
@@ -134,6 +135,7 @@ public:
protected:
+ SPDesktop *_desktop;
SPDocument *_document;
EventLog *_event_log;
@@ -146,12 +148,17 @@ protected:
Gtk::TreeView _event_list_view;
Glib::RefPtr<Gtk::TreeSelection> _event_list_selection;
- SPDesktop *_desktop;
DesktopTracker _deskTrack;
sigc::connection _desktopChangeConn;
EventLog::CallbackMap _callback_connections;
+ static void *_handleEventLogDestroyCB(void *data);
+
+ void _connectDocument(SPDesktop* desktop, SPDocument *document);
+ void _connectEventLog();
+ void _handleDocumentReplaced(SPDesktop* desktop, SPDocument *document);
+ void *_handleEventLogDestroy();
void _onListSelectionChange();
void _onExpandEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path);
void _onCollapseEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path);
diff --git a/src/util/signal-blocker.h b/src/util/signal-blocker.h
new file mode 100644
index 000000000..06d9736f2
--- /dev/null
+++ b/src/util/signal-blocker.h
@@ -0,0 +1,70 @@
+/*
+ * Base RAII blocker for sgic++ signals.
+ *
+ * Authors:
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2014 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_UTIL_SIGNAL_BLOCKER_H
+#define SEEN_INKSCAPE_UTIL_SIGNAL_BLOCKER_H
+
+#include <string>
+#include <sigc++/connection.h>
+
+/**
+ * Base RAII blocker for sgic++ signals.
+ */
+class SignalBlocker
+{
+public:
+ /**
+ * Creates a new instance that if the signal is currently unblocked will block
+ * it until this instance is destructed and then will unblock it.
+ */
+ SignalBlocker( sigc::connection *connection ) :
+ _connection(connection),
+ _wasBlocked(_connection->blocked())
+ {
+ if (!_wasBlocked)
+ {
+ _connection->block();
+ }
+ }
+
+ /**
+ * Destructor that will unblock the signal if it was blocked initially by this
+ * instance.
+ */
+ ~SignalBlocker()
+ {
+ if (!_wasBlocked)
+ {
+ _connection->block(false);
+ }
+ }
+
+private:
+ // noncopyable, nonassignable
+ SignalBlocker(SignalBlocker const &other);
+ SignalBlocker& operator=(SignalBlocker const &other);
+
+ sigc::connection *_connection;
+ bool _wasBlocked;
+};
+
+#endif // SEEN_INKSCAPE_UTIL_SIGNAL_BLOCKER_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :