event-log.cpp revision a4030d5ca449e7e384bc699cd249ee704faaeab0
1568N/A/*
830N/A * Author:
830N/A * Gustav Broberg <broberg@kth.se>
919N/A *
919N/A * Copyright (c) 2006, 2007 Authors
919N/A *
919N/A * Released under GNU GPL, read the file 'COPYING' for more information
919N/A */
830N/A
919N/A#include <glibmm/i18n.h>
919N/A
919N/A#include "desktop.h"
830N/A#include "event-log.h"
919N/A#include "inkscape.h"
919N/A#include "util/ucompose.hpp"
919N/A#include "document.h"
919N/A#include "xml/repr.h"
919N/A#include "sp-object.h"
919N/A
919N/Anamespace Inkscape {
830N/A
830N/AEventLog::EventLog(SPDocument* document) :
830N/A UndoStackObserver(),
830N/A _connected (false),
830N/A _document (document),
830N/A _event_list_store (Gtk::TreeStore::create(_columns)),
830N/A _event_list_selection (NULL),
830N/A _event_list_view (NULL),
830N/A _curr_event_parent (NULL),
830N/A _notifications_blocked (false),
830N/A _callback_connections (NULL)
830N/A{
830N/A // add initial pseudo event
830N/A Gtk::TreeRow curr_row = *(_event_list_store->append());
830N/A _curr_event = _last_saved = _last_event = curr_row;
830N/A
830N/A curr_row[_columns.description] = _("[Unchanged]");
830N/A curr_row[_columns.type] = SP_VERB_FILE_NEW;
830N/A}
830N/A
830N/AEventLog::~EventLog() { }
830N/A
830N/Avoid
830N/AEventLog::notifyUndoEvent(Event* log)
830N/A{
830N/A if ( !_notifications_blocked ) {
830N/A
830N/A // make sure the supplied event matches the next undoable event
830N/A g_return_if_fail ( _getUndoEvent() && (*(_getUndoEvent()))[_columns.event] == log );
830N/A
830N/A // if we're on the first child event...
830N/A if ( _curr_event->parent() &&
830N/A _curr_event == _curr_event->parent()->children().begin() )
830N/A {
830N/A // ...back up to the parent
830N/A _curr_event = _curr_event->parent();
830N/A _curr_event_parent = (iterator)NULL;
830N/A
830N/A } else {
830N/A
830N/A // if we're about to leave a branch, collapse it
830N/A if ( !_curr_event->children().empty() && _connected ) {
830N/A (*_callback_connections)[CALLB_COLLAPSE].block();
830N/A _event_list_view->collapse_row(_event_list_store->get_path(_curr_event));
830N/A (*_callback_connections)[CALLB_COLLAPSE].block(false);
830N/A }
830N/A
830N/A --_curr_event;
830N/A
830N/A // if we're entering a branch, move to the end of it
830N/A if (!_curr_event->children().empty()) {
830N/A _curr_event_parent = _curr_event;
830N/A _curr_event = _curr_event->children().end();
830N/A --_curr_event;
830N/A }
830N/A }
830N/A
830N/A checkForVirginity();
830N/A
830N/A // update the view
830N/A if (_connected) {
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
830N/A (*_callback_connections)[CALLB_EXPAND].block();
830N/A
830N/A Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
830N/A _event_list_view->expand_to_path(curr_path);
830N/A _event_list_selection->select(curr_path);
830N/A _event_list_view->scroll_to_row(curr_path);
830N/A
830N/A (*_callback_connections)[CALLB_EXPAND].block(false);
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
830N/A }
830N/A
830N/A updateUndoVerbs();
830N/A }
830N/A
830N/A}
830N/A
830N/Avoid
830N/AEventLog::notifyRedoEvent(Event* log)
830N/A{
830N/A if ( !_notifications_blocked ) {
830N/A
830N/A // make sure the supplied event matches the next redoable event
830N/A g_return_if_fail ( _getRedoEvent() && (*(_getRedoEvent()))[_columns.event] == log );
830N/A
830N/A // if we're on a parent event...
830N/A if ( !_curr_event->children().empty() ) {
830N/A
830N/A // ...move to its first child
830N/A _curr_event_parent = _curr_event;
830N/A _curr_event = _curr_event->children().begin();
830N/A
830N/A } else {
830N/A
830N/A ++_curr_event;
830N/A
830N/A // if we are about to leave a branch...
830N/A if ( _curr_event->parent() &&
830N/A _curr_event == _curr_event->parent()->children().end() )
830N/A {
830N/A
830N/A // ...collapse it
830N/A if (_connected) {
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
830N/A (*_callback_connections)[CALLB_COLLAPSE].block();
830N/A _event_list_view->collapse_row(_event_list_store->get_path(_curr_event->parent()));
830N/A (*_callback_connections)[CALLB_COLLAPSE].block(false);
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
830N/A }
830N/A
830N/A // ...and move to the next event at parent level
830N/A _curr_event = _curr_event->parent();
830N/A _curr_event_parent = (iterator)NULL;
830N/A
830N/A ++_curr_event;
830N/A }
830N/A }
830N/A
830N/A checkForVirginity();
830N/A
830N/A // update the view
830N/A if (_connected) {
830N/A Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
830N/A
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
830N/A (*_callback_connections)[CALLB_EXPAND].block();
830N/A
830N/A _event_list_view->expand_to_path(curr_path);
830N/A _event_list_selection->select(curr_path);
830N/A _event_list_view->scroll_to_row(curr_path);
830N/A
830N/A (*_callback_connections)[CALLB_EXPAND].block(false);
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
830N/A }
830N/A
830N/A updateUndoVerbs();
830N/A }
830N/A
830N/A}
830N/A
830N/Avoid
830N/AEventLog::notifyUndoCommitEvent(Event* log)
830N/A{
830N/A _clearRedo();
830N/A
830N/A const unsigned int event_type = log->type;
830N/A
830N/A Gtk::TreeRow curr_row;
830N/A
830N/A // if the new event is of the same type as the previous then create a new branch
830N/A if ( event_type == (*_curr_event)[_columns.type] ) {
830N/A if ( !_curr_event_parent ) {
830N/A _curr_event_parent = _curr_event;
830N/A }
830N/A curr_row = *(_event_list_store->append(_curr_event_parent->children()));
830N/A (*_curr_event_parent)[_columns.child_count] = _curr_event_parent->children().size() + 1;
830N/A } else {
830N/A curr_row = *(_event_list_store->append());
830N/A curr_row[_columns.child_count] = 1;
830N/A
830N/A _curr_event = _last_event = curr_row;
830N/A
830N/A // collapse if we're leaving a branch
830N/A if (_curr_event_parent && _connected) {
830N/A (*_callback_connections)[CALLB_COLLAPSE].block();
830N/A _event_list_view->collapse_row(_event_list_store->get_path(_curr_event_parent));
830N/A (*_callback_connections)[CALLB_COLLAPSE].block(false);
830N/A }
830N/A
830N/A _curr_event_parent = (iterator)(NULL);
830N/A }
830N/A
830N/A _curr_event = _last_event = curr_row;
830N/A
830N/A curr_row[_columns.event] = log;
830N/A curr_row[_columns.type] = event_type;
830N/A curr_row[_columns.description] = log->description;
830N/A
830N/A checkForVirginity();
830N/A
830N/A // update the view
830N/A if (_connected) {
830N/A Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event);
830N/A
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
830N/A (*_callback_connections)[CALLB_EXPAND].block();
830N/A
830N/A _event_list_view->expand_to_path(curr_path);
830N/A _event_list_selection->select(curr_path);
830N/A _event_list_view->scroll_to_row(curr_path);
830N/A
830N/A (*_callback_connections)[CALLB_EXPAND].block(false);
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
830N/A }
830N/A
830N/A updateUndoVerbs();
830N/A}
830N/A
830N/Avoid
830N/AEventLog::notifyClearUndoEvent()
830N/A{
830N/A _clearUndo();
830N/A updateUndoVerbs();
830N/A}
830N/A
830N/Avoid
830N/AEventLog::notifyClearRedoEvent()
830N/A{
830N/A _clearRedo();
830N/A updateUndoVerbs();
830N/A}
830N/A
830N/Avoid
830N/AEventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
830N/A{
830N/A _event_list_view = event_list_view;
830N/A _event_list_selection = event_list_view->get_selection();
830N/A _event_list_selection->set_mode(Gtk::SELECTION_SINGLE);
830N/A
830N/A _callback_connections = callback_connections;
830N/A
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block();
830N/A (*_callback_connections)[CALLB_EXPAND].block();
830N/A
830N/A _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event));
830N/A _event_list_selection->select(_curr_event);
830N/A
830N/A (*_callback_connections)[CALLB_EXPAND].block(false);
830N/A (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false);
830N/A
830N/A _connected = true;
830N/A}
830N/A
830N/Avoid
830N/AEventLog::updateUndoVerbs()
830N/A{
830N/A if(_document) {
830N/A
830N/A if(_getUndoEvent()) {
830N/A Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, true);
830N/A
830N/A Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, String::ucompose("%1: %2",
830N/A Glib::ustring(_("_Undo")),
830N/A Glib::ustring((*_getUndoEvent())[_columns.description])));
830N/A } else {
830N/A Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->name(_document, _("_Undo"));
830N/A Inkscape::Verb::get(SP_VERB_EDIT_UNDO)->sensitive(_document, false);
830N/A }
830N/A
830N/A if(_getRedoEvent()) {
830N/A Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, true);
830N/A Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, String::ucompose("%1: %2",
830N/A Glib::ustring(_("_Redo")),
830N/A Glib::ustring((*_getRedoEvent())[_columns.description])));
830N/A
830N/A } else {
830N/A Inkscape::Verb::get(SP_VERB_EDIT_REDO)->name(_document, _("_Redo"));
830N/A Inkscape::Verb::get(SP_VERB_EDIT_REDO)->sensitive(_document, false);
830N/A }
830N/A
830N/A }
830N/A
830N/A}
830N/A
830N/A
830N/AEventLog::const_iterator
830N/AEventLog::_getUndoEvent() const
830N/A{
830N/A const_iterator undo_event = (const_iterator)NULL;
830N/A if( _curr_event != _event_list_store->children().begin() )
830N/A undo_event = _curr_event;
830N/A return undo_event;
830N/A}
830N/A
830N/AEventLog::const_iterator
830N/AEventLog::_getRedoEvent() const
830N/A{
830N/A const_iterator redo_event = (const_iterator)NULL;
830N/A
830N/A if ( _curr_event != _last_event ) {
830N/A
830N/A if ( !_curr_event->children().empty() )
830N/A redo_event = _curr_event->children().begin();
830N/A else {
830N/A redo_event = _curr_event;
830N/A ++redo_event;
830N/A
830N/A if ( redo_event->parent() &&
830N/A redo_event == redo_event->parent()->children().end() ) {
830N/A
830N/A redo_event = redo_event->parent();
830N/A ++redo_event;
830N/A
830N/A }
830N/A }
830N/A
830N/A }
830N/A
830N/A return redo_event;
830N/A}
830N/A
830N/Avoid
830N/AEventLog::_clearUndo()
830N/A{
830N/A // TODO: Implement when needed
830N/A}
830N/A
830N/Avoid
830N/AEventLog::_clearRedo()
830N/A{
830N/A if ( _last_event != _curr_event ) {
830N/A
830N/A _last_event = _curr_event;
830N/A
830N/A if ( !_last_event->children().empty() ) {
830N/A _last_event = _last_event->children().begin();
830N/A } else {
830N/A ++_last_event;
830N/A }
830N/A
830N/A while ( _last_event != _event_list_store->children().end() ) {
830N/A
830N/A if (_last_event->parent()) {
830N/A while ( _last_event != _last_event->parent()->children().end() ) {
830N/A _last_event = _event_list_store->erase(_last_event);
830N/A }
830N/A _last_event = _last_event->parent();
830N/A
830N/A (*_last_event)[_columns.child_count] = _last_event->children().size() + 1;
830N/A
830N/A ++_last_event;
830N/A } else {
830N/A _last_event = _event_list_store->erase(_last_event);
830N/A }
830N/A
830N/A }
830N/A
830N/A }
830N/A}
830N/A
830N/A/* mark document as untouched if we reach a state where the document was previously saved */
830N/Avoid
830N/AEventLog::checkForVirginity() {
830N/A g_return_if_fail (_document);
830N/A if (_curr_event == _last_saved) {
830N/A _document->setModifiedSinceSave(false);
830N/A }
830N/A}
830N/A
830N/A} // namespace Inkscape
830N/A
830N/A
830N/A/*
830N/A Local Variables:
830N/A mode:c++
830N/A c-file-style:"stroustrup"
830N/A c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
830N/A indent-tabs-mode:nil
830N/A fill-column:99
830N/A End:
830N/A*/
830N/A// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
830N/A