1 /*
2 * Author:
3 * Gustav Broberg <broberg@kth.se>
4 *
5 * Copyright (c) 2006 Authors
6 *
7 * Released under GNU GPL, read the file 'COPYING' for more information
8 */
10 #include <glibmm/i18n.h>
12 #include "desktop.h"
13 #include "event-log.h"
14 #include "inkscape.h"
15 #include "util/ucompose.hpp"
17 namespace Inkscape {
19 EventLog::EventLog() :
20 UndoStackObserver(),
21 _connected (false),
22 _document (NULL),
23 _event_list_store (Gtk::TreeStore::create(_columns)),
24 _event_list_selection (NULL),
25 _event_list_view (NULL),
26 _curr_event_parent (NULL),
27 _notifications_blocked (false),
28 _callback_connections (NULL)
29 {
30 // add initial pseudo event
31 Gtk::TreeRow curr_row = *(_event_list_store->append());
32 _curr_event = _last_event = curr_row;
34 curr_row[_columns.description] = _("[Unchanged]");
35 curr_row[_columns.type] = SP_VERB_FILE_NEW;
36 }
38 EventLog::~EventLog() { }
40 void
41 EventLog::notifyUndoEvent(Event* log)
42 {
43 if ( !_notifications_blocked ) {
45 // if we're on the first child event...
46 if ( _curr_event->parent() &&
47 _curr_event == _curr_event->parent()->children().begin() )
48 {
49 // ...back up to the parent
50 _curr_event = _curr_event->parent();
51 _curr_event_parent = (iterator)NULL;
53 } else {
55 // if we're about to leave a branch, collapse it
56 if ( !_curr_event->children().empty() && _connected ) {
57 (*_callback_connections)[CALLB_COLLAPSE].block();
58 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event));
59 (*_callback_connections)[CALLB_COLLAPSE].block(false);
60 }
62 --_curr_event;
64 // if we're entering a branch, move to the end of it
65 if (!_curr_event->children().empty()) {
66 _curr_event_parent = _curr_event;
67 _curr_event = _curr_event->children().end();
68 --_curr_event;
69 }
70 }
72 // update the view
73 if (_connected) {
74 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
75 (*_callback_connections)[CALLB_EXPAND].block();
77 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
78 _event_list_view->expand_to_path(curr_path);
79 _event_list_selection->select(curr_path);
80 _event_list_view->scroll_to_row(curr_path);
82 (*_callback_connections)[CALLB_EXPAND].block(false);
83 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
84 }
86 updateUndoVerbs();
87 }
89 }
91 void
92 EventLog::notifyRedoEvent(Event* log)
93 {
94 if ( !_notifications_blocked ) {
96 // if we're on a parent event...
97 if ( !_curr_event->children().empty() ) {
99 // ...move to its first child
100 _curr_event_parent = _curr_event;
101 _curr_event = _curr_event->children().begin();
103 } else {
105 ++_curr_event;
107 // if we are about to leave a branch...
108 if ( _curr_event->parent() &&
109 _curr_event == _curr_event->parent()->children().end() )
110 {
112 // ...collapse it
113 if (_connected) {
114 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
115 (*_callback_connections)[CALLB_COLLAPSE].block();
116 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event->parent()));
117 (*_callback_connections)[CALLB_COLLAPSE].block(false);
118 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
119 }
121 // ...and move to the next event at parent level
122 _curr_event = _curr_event->parent();
123 _curr_event_parent = (iterator)NULL;
125 ++_curr_event;
126 }
127 }
129 // update the view
130 if (_connected) {
131 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
133 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
134 (*_callback_connections)[CALLB_EXPAND].block();
136 _event_list_view->expand_to_path(curr_path);
137 _event_list_selection->select(curr_path);
138 _event_list_view->scroll_to_row(curr_path);
140 (*_callback_connections)[CALLB_EXPAND].block(false);
141 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
142 }
144 updateUndoVerbs();
145 }
147 }
149 void
150 EventLog::notifyUndoCommitEvent(Event* log)
151 {
152 // If we're not at the last event in list then erase the previously undone events
153 if ( _last_event != _curr_event ) {
155 _last_event = _curr_event;
157 if ( !_last_event->children().empty() ) {
158 _last_event = _last_event->children().begin();
159 } else {
160 ++_last_event;
161 }
163 while ( _last_event != _event_list_store->children().end() ) {
165 if (_last_event->parent()) {
166 while ( _last_event != _last_event->parent()->children().end() ) {
167 _last_event = _event_list_store->erase(_last_event);
168 }
169 _last_event = _last_event->parent();
171 (*_last_event)[_columns.child_count] = _last_event->children().size() + 1;
173 ++_last_event;
174 } else {
175 _last_event = _event_list_store->erase(_last_event);
176 }
178 }
179 }
181 const unsigned int event_type = log->type;
183 Gtk::TreeRow curr_row;
185 // if the new event is of the same type as the previous then create a new branch
186 if ( event_type == (*_curr_event)[_columns.type] ) {
187 if ( !_curr_event_parent ) {
188 _curr_event_parent = _curr_event;
189 }
190 curr_row = *(_event_list_store->append(_curr_event_parent->children()));
191 (*_curr_event_parent)[_columns.child_count] = _curr_event_parent->children().size() + 1;
192 } else {
193 curr_row = *(_event_list_store->append());
194 curr_row[_columns.child_count] = 1;
196 _curr_event = _last_event = curr_row;
198 // collapse if we're leaving a branch
199 if (_curr_event_parent && _connected) {
200 (*_callback_connections)[CALLB_COLLAPSE].block();
201 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event_parent));
202 (*_callback_connections)[CALLB_COLLAPSE].block(false);
203 }
205 _curr_event_parent = (iterator)(NULL);
206 }
208 _curr_event = _last_event = curr_row;
210 curr_row[_columns.type] = event_type;
211 curr_row[_columns.description] = log->description;
213 // update the view
214 if (_connected) {
215 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
217 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
218 (*_callback_connections)[CALLB_EXPAND].block();
220 _event_list_view->expand_to_path(curr_path);
221 _event_list_selection->select(curr_path);
222 _event_list_view->scroll_to_row(curr_path);
224 (*_callback_connections)[CALLB_EXPAND].block(false);
225 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
226 }
228 updateUndoVerbs();
229 }
232 void
233 EventLog::setDocument(SPDocument *document)
234 {
235 _document = document;
236 updateUndoVerbs();
237 }
240 void
241 EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
242 {
243 _event_list_view = event_list_view;
244 _event_list_selection = event_list_view->get_selection();
245 _event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
247 _callback_connections = callback_connections;
249 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
250 (*_callback_connections)[CALLB_EXPAND].block();
252 _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event));
253 _event_list_selection->select(_curr_event);
255 (*_callback_connections)[CALLB_EXPAND].block(false);
256 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
258 _connected = true;
259 }
261 void
262 EventLog::updateUndoVerbs()
263 {
264 if(_document) {
266 if(_getUndoEvent()) {
267 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, true);
269 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, String::ucompose("%1 %2",
270 Glib::ustring(_("_Undo")),
271 Glib::ustring((*_getUndoEvent())[_columns.description])));
272 } else {
273 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, _("_Undo"));
274 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, false);
275 }
277 if(_getRedoEvent()) {
278 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, true);
279 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, String::ucompose("%1 %2",
280 Glib::ustring(_("_Redo")),
281 Glib::ustring((*_getRedoEvent())[_columns.description])));
283 } else {
284 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, _("_Redo"));
285 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, false);
286 }
288 }
290 }
293 EventLog::const_iterator
294 EventLog::_getUndoEvent() const
295 {
296 const_iterator undo_event = (const_iterator)NULL;
297 if( _curr_event != _event_list_store->children().begin() )
298 undo_event = _curr_event;
299 return undo_event;
300 }
302 EventLog::const_iterator
303 EventLog::_getRedoEvent() const
304 {
305 const_iterator redo_event = (const_iterator)NULL;
307 if ( _curr_event != _last_event ) {
309 if ( !_curr_event->children().empty() )
310 redo_event = _curr_event->children().begin();
311 else {
312 redo_event = _curr_event;
313 ++redo_event;
315 if ( redo_event->parent() &&
316 redo_event == redo_event->parent()->children().end() ) {
318 redo_event = redo_event->parent();
319 ++redo_event;
321 }
322 }
324 }
326 return redo_event;
327 }
329 }
331 /*
332 Local Variables:
333 mode:c++
334 c-file-style:"stroustrup"
335 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
336 indent-tabs-mode:nil
337 fill-column:99
338 End:
339 */
340 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :