d6bc99bea8a34e195cb2c0331413bc0136d5c355
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 // 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 // If we're not at the last event in list then erase the previously undone events
159 if ( _last_event != _curr_event ) {
161 _last_event = _curr_event;
163 if ( !_last_event->children().empty() ) {
164 _last_event = _last_event->children().begin();
165 } else {
166 ++_last_event;
167 }
169 while ( _last_event != _event_list_store->children().end() ) {
171 if (_last_event->parent()) {
172 while ( _last_event != _last_event->parent()->children().end() ) {
173 _last_event = _event_list_store->erase(_last_event);
174 }
175 _last_event = _last_event->parent();
177 (*_last_event)[_columns.child_count] = _last_event->children().size() + 1;
179 ++_last_event;
180 } else {
181 _last_event = _event_list_store->erase(_last_event);
182 }
184 }
185 }
187 const unsigned int event_type = log->type;
189 Gtk::TreeRow curr_row;
191 // if the new event is of the same type as the previous then create a new branch
192 if ( event_type == (*_curr_event)[_columns.type] ) {
193 if ( !_curr_event_parent ) {
194 _curr_event_parent = _curr_event;
195 }
196 curr_row = *(_event_list_store->append(_curr_event_parent->children()));
197 (*_curr_event_parent)[_columns.child_count] = _curr_event_parent->children().size() + 1;
198 } else {
199 curr_row = *(_event_list_store->append());
200 curr_row[_columns.child_count] = 1;
202 _curr_event = _last_event = curr_row;
204 // collapse if we're leaving a branch
205 if (_curr_event_parent && _connected) {
206 (*_callback_connections)[CALLB_COLLAPSE].block();
207 _event_list_view->collapse_row(_event_list_store->get_path(_curr_event_parent));
208 (*_callback_connections)[CALLB_COLLAPSE].block(false);
209 }
211 _curr_event_parent = (iterator)(NULL);
212 }
214 _curr_event = _last_event = curr_row;
216 curr_row[_columns.event] = log;
217 curr_row[_columns.type] = event_type;
218 curr_row[_columns.description] = log->description;
220 // update the view
221 if (_connected) {
222 Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
224 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
225 (*_callback_connections)[CALLB_EXPAND].block();
227 _event_list_view->expand_to_path(curr_path);
228 _event_list_selection->select(curr_path);
229 _event_list_view->scroll_to_row(curr_path);
231 (*_callback_connections)[CALLB_EXPAND].block(false);
232 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
233 }
235 updateUndoVerbs();
236 }
238 void
239 EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
240 {
241 _event_list_view = event_list_view;
242 _event_list_selection = event_list_view->get_selection();
243 _event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
245 _callback_connections = callback_connections;
247 (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
248 (*_callback_connections)[CALLB_EXPAND].block();
250 _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event));
251 _event_list_selection->select(_curr_event);
253 (*_callback_connections)[CALLB_EXPAND].block(false);
254 (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
256 _connected = true;
257 }
259 void
260 EventLog::updateUndoVerbs()
261 {
262 if(_document) {
264 if(_getUndoEvent()) {
265 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, true);
267 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, String::ucompose("%1: %2",
268 Glib::ustring(_("_Undo")),
269 Glib::ustring((*_getUndoEvent())[_columns.description])));
270 } else {
271 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, _("_Undo"));
272 Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, false);
273 }
275 if(_getRedoEvent()) {
276 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, true);
277 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, String::ucompose("%1: %2",
278 Glib::ustring(_("_Redo")),
279 Glib::ustring((*_getRedoEvent())[_columns.description])));
281 } else {
282 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, _("_Redo"));
283 Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, false);
284 }
286 }
288 }
291 EventLog::const_iterator
292 EventLog::_getUndoEvent() const
293 {
294 const_iterator undo_event = (const_iterator)NULL;
295 if( _curr_event != _event_list_store->children().begin() )
296 undo_event = _curr_event;
297 return undo_event;
298 }
300 EventLog::const_iterator
301 EventLog::_getRedoEvent() const
302 {
303 const_iterator redo_event = (const_iterator)NULL;
305 if ( _curr_event != _last_event ) {
307 if ( !_curr_event->children().empty() )
308 redo_event = _curr_event->children().begin();
309 else {
310 redo_event = _curr_event;
311 ++redo_event;
313 if ( redo_event->parent() &&
314 redo_event == redo_event->parent()->children().end() ) {
316 redo_event = redo_event->parent();
317 ++redo_event;
319 }
320 }
322 }
324 return redo_event;
325 }
327 }
329 /*
330 Local Variables:
331 mode:c++
332 c-file-style:"stroustrup"
333 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
334 indent-tabs-mode:nil
335 fill-column:99
336 End:
337 */
338 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :