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(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 // 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 }
231 void
232 EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
233 {
234 _event_list_view = event_list_view;
235 _event_list_selection = event_list_view->get_selection();
236 _event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
238 _callback_connections = callback_connections;
240 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
241 (*_callback_connections)[CALLB_EXPAND].block();
243 _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event));
244 _event_list_selection->select(_curr_event);
246 (*_callback_connections)[CALLB_EXPAND].block(false);
247 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
249 _connected = true;
250 }
252 void
253 EventLog::updateUndoVerbs()
254 {
255 if(_document) {
257 if(_getUndoEvent()) {
258 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, true);
260 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, String::ucompose("%1: %2",
261 Glib::ustring(_("_Undo")),
262 Glib::ustring((*_getUndoEvent())[_columns.description])));
263 } else {
264 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, _("_Undo"));
265 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, false);
266 }
268 if(_getRedoEvent()) {
269 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, true);
270 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, String::ucompose("%1: %2",
271 Glib::ustring(_("_Redo")),
272 Glib::ustring((*_getRedoEvent())[_columns.description])));
274 } else {
275 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, _("_Redo"));
276 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, false);
277 }
279 }
281 }
284 EventLog::const_iterator
285 EventLog::_getUndoEvent() const
286 {
287 const_iterator undo_event = (const_iterator)NULL;
288 if( _curr_event != _event_list_store->children().begin() )
289 undo_event = _curr_event;
290 return undo_event;
291 }
293 EventLog::const_iterator
294 EventLog::_getRedoEvent() const
295 {
296 const_iterator redo_event = (const_iterator)NULL;
298 if ( _curr_event != _last_event ) {
300 if ( !_curr_event->children().empty() )
301 redo_event = _curr_event->children().begin();
302 else {
303 redo_event = _curr_event;
304 ++redo_event;
306 if ( redo_event->parent() &&
307 redo_event == redo_event->parent()->children().end() ) {
309 redo_event = redo_event->parent();
310 ++redo_event;
312 }
313 }
315 }
317 return redo_event;
318 }
320 }
322 /*
323 Local Variables:
324 mode:c++
325 c-file-style:"stroustrup"
326 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
327 indent-tabs-mode:nil
328 fill-column:99
329 End:
330 */
331 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :