1 /*
2 * Author:
3 * Gustav Broberg <broberg@kth.se>
4 *
5 * Copyright (c) 2006, 2007 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(SPDocument* document) :
20 UndoStackObserver(),
21 _connected (false),
22 _document (document),
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 // make sure the supplied event matches the next undoable event
46 g_return_if_fail ( _getUndoEvent() && (*(_getUndoEvent()))[_columns.event] == log );
48 // if we're on the first child event...
49 if ( _curr_event->parent() &&
50 _curr_event == _curr_event->parent()->children().begin() )
51 {
52 // ...back up to the parent
53 _curr_event = _curr_event->parent();
54 _curr_event_parent = (iterator)NULL;
56 } else {
58 // if we're about to leave a branch, collapse it
59 if ( !_curr_event->children().empty() && _connected ) {
60 (*_callback_connections)[CALLB_COLLAPSE].block();
61 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event));
62 (*_callback_connections)[CALLB_COLLAPSE].block(false);
63 }
65 --_curr_event;
67 // if we're entering a branch, move to the end of it
68 if (!_curr_event->children().empty()) {
69 _curr_event_parent = _curr_event;
70 _curr_event = _curr_event->children().end();
71 --_curr_event;
72 }
73 }
75 // update the view
76 if (_connected) {
77 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
78 (*_callback_connections)[CALLB_EXPAND].block();
80 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
81 _event_list_view->expand_to_path(curr_path);
82 _event_list_selection->select(curr_path);
83 _event_list_view->scroll_to_row(curr_path);
85 (*_callback_connections)[CALLB_EXPAND].block(false);
86 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
87 }
89 updateUndoVerbs();
90 }
92 }
94 void
95 EventLog::notifyRedoEvent(Event* log)
96 {
97 if ( !_notifications_blocked ) {
99 // make sure the supplied event matches the next redoable event
100 g_return_if_fail ( _getRedoEvent() && (*(_getRedoEvent()))[_columns.event] == log );
102 // if we're on a parent event...
103 if ( !_curr_event->children().empty() ) {
105 // ...move to its first child
106 _curr_event_parent = _curr_event;
107 _curr_event = _curr_event->children().begin();
109 } else {
111 ++_curr_event;
113 // if we are about to leave a branch...
114 if ( _curr_event->parent() &&
115 _curr_event == _curr_event->parent()->children().end() )
116 {
118 // ...collapse it
119 if (_connected) {
120 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
121 (*_callback_connections)[CALLB_COLLAPSE].block();
122 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event->parent()));
123 (*_callback_connections)[CALLB_COLLAPSE].block(false);
124 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
125 }
127 // ...and move to the next event at parent level
128 _curr_event = _curr_event->parent();
129 _curr_event_parent = (iterator)NULL;
131 ++_curr_event;
132 }
133 }
135 // update the view
136 if (_connected) {
137 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
139 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
140 (*_callback_connections)[CALLB_EXPAND].block();
142 _event_list_view->expand_to_path(curr_path);
143 _event_list_selection->select(curr_path);
144 _event_list_view->scroll_to_row(curr_path);
146 (*_callback_connections)[CALLB_EXPAND].block(false);
147 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
148 }
150 updateUndoVerbs();
151 }
153 }
155 void
156 EventLog::notifyUndoCommitEvent(Event* log)
157 {
158 _clearRedo();
160 const unsigned int event_type = log->type;
162 Gtk::TreeRow curr_row;
164 // if the new event is of the same type as the previous then create a new branch
165 if ( event_type == (*_curr_event)[_columns.type] ) {
166 if ( !_curr_event_parent ) {
167 _curr_event_parent = _curr_event;
168 }
169 curr_row = *(_event_list_store->append(_curr_event_parent->children()));
170 (*_curr_event_parent)[_columns.child_count] = _curr_event_parent->children().size() + 1;
171 } else {
172 curr_row = *(_event_list_store->append());
173 curr_row[_columns.child_count] = 1;
175 _curr_event = _last_event = curr_row;
177 // collapse if we're leaving a branch
178 if (_curr_event_parent && _connected) {
179 (*_callback_connections)[CALLB_COLLAPSE].block();
180 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event_parent));
181 (*_callback_connections)[CALLB_COLLAPSE].block(false);
182 }
184 _curr_event_parent = (iterator)(NULL);
185 }
187 _curr_event = _last_event = curr_row;
189 curr_row[_columns.event] = log;
190 curr_row[_columns.type] = event_type;
191 curr_row[_columns.description] = log->description;
193 // update the view
194 if (_connected) {
195 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
197 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
198 (*_callback_connections)[CALLB_EXPAND].block();
200 _event_list_view->expand_to_path(curr_path);
201 _event_list_selection->select(curr_path);
202 _event_list_view->scroll_to_row(curr_path);
204 (*_callback_connections)[CALLB_EXPAND].block(false);
205 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
206 }
208 updateUndoVerbs();
209 }
211 void
212 EventLog::notifyClearUndoEvent()
213 {
214 _clearUndo();
215 updateUndoVerbs();
216 }
218 void
219 EventLog::notifyClearRedoEvent()
220 {
221 _clearRedo();
222 updateUndoVerbs();
223 }
225 void
226 EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
227 {
228 _event_list_view = event_list_view;
229 _event_list_selection = event_list_view->get_selection();
230 _event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
232 _callback_connections = callback_connections;
234 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
235 (*_callback_connections)[CALLB_EXPAND].block();
237 _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event));
238 _event_list_selection->select(_curr_event);
240 (*_callback_connections)[CALLB_EXPAND].block(false);
241 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
243 _connected = true;
244 }
246 void
247 EventLog::updateUndoVerbs()
248 {
249 if(_document) {
251 if(_getUndoEvent()) {
252 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, true);
254 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, String::ucompose("%1: %2",
255 Glib::ustring(_("_Undo")),
256 Glib::ustring((*_getUndoEvent())[_columns.description])));
257 } else {
258 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, _("_Undo"));
259 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, false);
260 }
262 if(_getRedoEvent()) {
263 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, true);
264 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, String::ucompose("%1: %2",
265 Glib::ustring(_("_Redo")),
266 Glib::ustring((*_getRedoEvent())[_columns.description])));
268 } else {
269 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, _("_Redo"));
270 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, false);
271 }
273 }
275 }
278 EventLog::const_iterator
279 EventLog::_getUndoEvent() const
280 {
281 const_iterator undo_event = (const_iterator)NULL;
282 if( _curr_event != _event_list_store->children().begin() )
283 undo_event = _curr_event;
284 return undo_event;
285 }
287 EventLog::const_iterator
288 EventLog::_getRedoEvent() const
289 {
290 const_iterator redo_event = (const_iterator)NULL;
292 if ( _curr_event != _last_event ) {
294 if ( !_curr_event->children().empty() )
295 redo_event = _curr_event->children().begin();
296 else {
297 redo_event = _curr_event;
298 ++redo_event;
300 if ( redo_event->parent() &&
301 redo_event == redo_event->parent()->children().end() ) {
303 redo_event = redo_event->parent();
304 ++redo_event;
306 }
307 }
309 }
311 return redo_event;
312 }
314 void
315 EventLog::_clearUndo()
316 {
317 // TODO: Implement when needed
318 }
320 void
321 EventLog::_clearRedo()
322 {
323 if ( _last_event != _curr_event ) {
325 _last_event = _curr_event;
327 if ( !_last_event->children().empty() ) {
328 _last_event = _last_event->children().begin();
329 } else {
330 ++_last_event;
331 }
333 while ( _last_event != _event_list_store->children().end() ) {
335 if (_last_event->parent()) {
336 while ( _last_event != _last_event->parent()->children().end() ) {
337 _last_event = _event_list_store->erase(_last_event);
338 }
339 _last_event = _last_event->parent();
341 (*_last_event)[_columns.child_count] = _last_event->children().size() + 1;
343 ++_last_event;
344 } else {
345 _last_event = _event_list_store->erase(_last_event);
346 }
348 }
350 }
351 }
353 } // namespace Inkscape
356 /*
357 Local Variables:
358 mode:c++
359 c-file-style:"stroustrup"
360 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
361 indent-tabs-mode:nil
362 fill-column:99
363 End:
364 */
365 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :