Code

Moved EventLog from SPDocument to SPDesktop to prevent it from being
[inkscape.git] / src / event-log.cpp
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;
33     
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 ) {
44     
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 {
104         
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     }
149 void 
150 EventLog::notifyUndoCommitEvent(Event* log)
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();
231 void 
232 EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
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;
252 void
253 EventLog::updateUndoVerbs()
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     }
284 EventLog::const_iterator
285 EventLog::_getUndoEvent() const
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;
293 EventLog::const_iterator
294 EventLog::_getRedoEvent() const
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;
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 :