my log
[synfig.git] / synfig-studio / trunk / src / gtkmm / dock_history.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file dialog_history.cpp
3 **      \brief Template File
4 **
5 **      $Id: dock_history.cpp,v 1.1.1.1 2005/01/07 03:34:36 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "dock_history.h"
32 #include "app.h"
33
34
35
36 #include <gtkmm/scrolledwindow.h>
37 #include <cassert>
38 #include "instance.h"
39 #include <sigc++/signal.h>
40 #include <sigc++/hide.h>
41 #include <sigc++/slot.h>
42 #include <synfigapp/action.h>
43 #include "historytreestore.h"
44
45 #endif
46
47 /* === U S I N G =========================================================== */
48
49 using namespace std;
50 using namespace etl;
51 using namespace synfig;
52 using namespace studio;
53
54 /* === M A C R O S ========================================================= */
55 #define COLUMNID_JUMP           (787584)
56 #define ColumnID        int
57
58 /* === G L O B A L S ======================================================= */
59
60 /* === P R O C E D U R E S ================================================= */
61
62 /* === M E T H O D S ======================================================= */
63
64 Dock_History::Dock_History():
65         Dock_CanvasSpecific("history",_("History"),Gtk::StockID("gtk-undo")),
66         action_group(Gtk::ActionGroup::create())
67 {
68         App::signal_instance_deleted().connect(sigc::mem_fun(*this,&studio::Dock_History::delete_instance));
69         App::signal_instance_selected().connect(sigc::mem_fun(*this,&studio::Dock_History::set_selected_instance_signal));
70         
71         action_group->add(Gtk::Action::create(
72                 "clear-undo",
73                 Gtk::StockID("synfig-clear_undo"),
74                 _("Clear the UNDO Stack"),
75                 _("Clear the UNDO Stack")
76         ),
77                 sigc::mem_fun(
78                         *this,
79                         &Dock_History::clear_undo
80                 )
81         );
82         action_group->add(Gtk::Action::create(
83                 "clear-redo",
84                 Gtk::StockID("synfig-clear_redo"),
85                 _("Clear the REDO Stack"),
86                 _("Clear the REDO Stack")
87         ),
88                 sigc::mem_fun(
89                         *this,
90                         &Dock_History::clear_redo
91                 )
92         );
93         action_group->add(Gtk::Action::create(
94                 "undo",
95                 Gtk::StockID("gtk-undo"),
96                 _("Undo previous action"),
97                 _("Undo previous action")
98         ),
99                 sigc::ptr_fun(studio::App::undo)        
100         );
101         action_group->add(Gtk::Action::create(
102                 "redo",
103                 Gtk::StockID("gtk-redo"),
104                 _("Redo previous action"),
105                 _("Redo previous action")
106         ),
107                 sigc::ptr_fun(studio::App::redo)        
108         );
109
110         action_group->add( Gtk::Action::create("toolbar-history", "History") );
111         App::ui_manager()->insert_action_group(action_group);
112
113         Glib::ustring ui_info =
114         "<ui>"
115         "       <toolbar action='toolbar-history'>"
116         "       <toolitem action='undo' />"
117         "       <toolitem action='clear-undo' />"
118         "       <toolitem action='clear-redo' />"
119         "       <toolitem action='redo' />"
120         "       </toolbar>"
121         "</ui>"
122         ;
123
124         App::ui_manager()->add_ui_from_string(ui_info);
125
126         action_group->set_sensitive(false);
127
128         set_toolbar(*dynamic_cast<Gtk::Toolbar*>(App::ui_manager()->get_widget("/toolbar-history")));   
129         add(*create_action_tree());
130         
131         /*
132         add_button(
133                 Gtk::StockID("synfig-clear_undo"),
134                 _("Clear the UNDO Stack")
135         )->signal_clicked().connect(
136                 sigc::mem_fun(
137                         *this,
138                         &Dock_History::clear_undo
139                 )
140         );
141         add_button(
142                 Gtk::StockID("synfig-clear_redo"),
143                 _("Clear the REDO Stack")
144         )->signal_clicked().connect(
145                 sigc::mem_fun(
146                         *this,
147                         &Dock_History::clear_redo
148                 )
149         );
150         */
151 }
152
153 Dock_History::~Dock_History()
154 {
155 }
156
157 void
158 Dock_History::init_instance_vfunc(etl::loose_handle<Instance> instance)
159 {
160         instance->signal_undo_redo_status_changed().connect(
161                 sigc::mem_fun(*this,&Dock_History::update_undo_redo)
162         );
163 }
164
165 Gtk::Widget*
166 Dock_History::create_action_tree()
167 {
168         studio::HistoryTreeStore::Model history_tree_model;
169         action_tree=manage(new class Gtk::TreeView());
170         {
171                 Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column("") );
172
173                 Gtk::CellRendererToggle* toggle_cr = Gtk::manage( new Gtk::CellRendererToggle() );
174                 toggle_cr->signal_toggled().connect(sigc::mem_fun(*this, &studio::Dock_History::on_action_toggle) );
175                 
176                 column->pack_start(*toggle_cr); //false = don't expand.
177                 column->add_attribute(toggle_cr->property_active(),history_tree_model.is_active);
178                 column->set_resizable();
179                 column->set_clickable();
180                                 
181                 action_tree->append_column(*column);
182         }
183         /*{
184                 Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column("Canvas") );
185                 Gtk::CellRendererText *text_cr=Gtk::manage(new Gtk::CellRendererText());
186                 text_cr->property_foreground()=Glib::ustring("#7f7f7f");
187                 
188                 column->pack_start(*text_cr);
189                 column->add_attribute(text_cr->property_text(),history_tree_model.canvas_id);
190                 column->add_attribute(text_cr->property_foreground_set(),history_tree_model.is_redo);
191                                 
192                 action_tree->append_column(*column);
193         }*/
194         {
195                 Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_("Jump")) );
196
197                 Gtk::CellRendererText* cell_renderer_jump=Gtk::manage(new Gtk::CellRendererText());
198                 column->pack_start(*cell_renderer_jump,true);
199                 
200                 cell_renderer_jump->property_text()="(JMP)";
201                 cell_renderer_jump->property_foreground()="#003a7f";
202                 
203                 column->set_resizable();
204                 column->set_clickable();
205                 
206                 column->set_sort_column_id(COLUMNID_JUMP);
207
208                 action_tree->append_column(*column);
209                 //column->clicked();
210         }
211         {
212                 Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column("Action") );
213
214                 Gtk::CellRendererText *text_cr=Gtk::manage(new Gtk::CellRendererText());
215                 text_cr->property_foreground()=Glib::ustring("#7f7f7f");
216
217                 
218
219                 //column->pack_start(history_tree_model.icon, false); //false = don't expand.
220                 column->pack_start(*text_cr);
221                 column->add_attribute(text_cr->property_text(),history_tree_model.name);
222                 column->add_attribute(text_cr->property_foreground_set(),history_tree_model.is_redo);
223                                 
224                 action_tree->append_column(*column);
225         }
226
227         
228         action_tree->set_rules_hint();
229 //      action_tree->signal_row_activated().connect(sigc::mem_fun(*this,&Dock_History::on_row_activate));
230         action_tree->signal_event().connect(sigc::mem_fun(*this,&Dock_History::on_action_event));
231 //      action_tree->add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
232 //      action_tree->add_events(Gdk::BUTTON1_MOTION_MASK);
233         action_tree->show();
234
235         Gtk::ScrolledWindow *scrolledwindow = manage(new class Gtk::ScrolledWindow());
236         scrolledwindow->set_flags(Gtk::CAN_FOCUS);
237         scrolledwindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
238         scrolledwindow->add(*action_tree);
239         scrolledwindow->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
240         scrolledwindow->show_all();
241
242 /*      {
243                 Gtk::Widget& widget(*action_tree);
244                 Pango::FontDescription font(widget.get_modifier_style()->get_font());
245                 font.set_size(Pango::SCALE*5);
246                 widget.get_modifier_style()->set_font(font);
247                 widget.modify_font(font);
248         }
249 */
250         return scrolledwindow;
251 }
252
253 void
254 Dock_History::clear_undo()
255 {
256         if(selected_instance && App::dialog_yes_no(_("Clear History"), _("You will not be able to undo any changes that you have made!\nAre you sure you want to clear the undo stack?")))
257         {               
258                 selected_instance->clear_undo_stack();
259         }
260 }
261
262 void
263 Dock_History::clear_redo()
264 {
265         if(selected_instance && App::dialog_yes_no(_("Clear History"), _("You will not be able to redo any changes that you have made!\nAre you sure you want to clear the redo stack?")))
266         {               
267                 selected_instance->clear_redo_stack();
268         }
269 }
270
271 void
272 Dock_History::update_undo_redo()
273 {
274         etl::handle<Instance> instance=App::get_selected_instance();
275         if(instance)
276         {
277                 action_group->get_action("undo")->set_sensitive(instance->get_undo_status());
278                 action_group->get_action("clear-undo")->set_sensitive(instance->get_undo_status());
279                 action_group->get_action("redo")->set_sensitive(instance->get_redo_status());
280                 action_group->get_action("clear-redo")->set_sensitive(instance->get_redo_status());
281         }
282 }
283
284 void
285 Dock_History::set_selected_instance_(etl::handle<studio::Instance> instance)
286 {
287         if(studio::App::shutdown_in_progress)
288                 return;
289
290         selected_instance=instance;
291         if(instance)
292         {
293                 action_tree->set_model(instance->history_tree_store());
294                 action_tree->show();
295                 update_undo_redo();
296                 action_group->set_sensitive(true);
297         }
298         else
299         {
300                 action_tree->set_model(Glib::RefPtr< Gtk::TreeModel >());
301                 action_tree->hide();
302                 action_group->set_sensitive(false);
303         }
304 }
305
306 void
307 Dock_History::set_selected_instance_signal(etl::handle<studio::Instance> x)
308 {
309         set_selected_instance(x);
310 }
311
312 void
313 Dock_History::set_selected_instance(etl::loose_handle<studio::Instance> x)
314 {
315         if(studio::App::shutdown_in_progress)
316                 return;
317
318         // if it's already selected, don't select it again
319         if (x==selected_instance)
320                 return;
321
322         std::list<etl::handle<studio::Instance> >::iterator iter;
323
324         set_selected_instance_(x);      
325 }
326
327 void
328 Dock_History::delete_instance(etl::handle<studio::Instance> instance)
329 {
330         if(studio::App::shutdown_in_progress)
331                 return;
332
333         if(selected_instance==instance)
334         {
335                 set_selected_instance(0);
336         }
337 }
338
339 bool
340 Dock_History::on_action_event(GdkEvent *event)
341 {
342         studio::HistoryTreeStore::Model model;
343     switch(event->type)
344     {
345         case GDK_BUTTON_PRESS:
346         case GDK_2BUTTON_PRESS:
347                 {
348                         Gtk::TreeModel::Path path;
349                         Gtk::TreeViewColumn *column;
350                         int cell_x, cell_y;
351                         if(!action_tree->get_path_at_pos(
352                                 int(event->button.x),int(event->button.y),      // x, y
353                                 path, // TreeModel::Path&
354                                 column, //TreeViewColumn*&
355                                 cell_x,cell_y //int&cell_x,int&cell_y
356                                 )
357                         ) break;
358                         const Gtk::TreeRow row = *(action_tree->get_model()->get_iter(path));
359                         
360                         //signal_user_click()(event->button.button,row,(ColumnID)column->get_sort_column_id());
361                         if((ColumnID)column->get_sort_column_id()==COLUMNID_JUMP)
362                         {
363                                 etl::handle<synfigapp::Action::Undoable> action(row[model.action]);
364                                 try{
365                                 if((bool)row[model.is_undo])
366                                 {
367                                         while(get_selected_instance()->undo_action_stack().size() && get_selected_instance()->undo_action_stack().front()!=action)
368                                                 if(get_selected_instance()->undo()==false)
369                                                         throw int();
370                                 }
371                                 else if((bool)row[model.is_redo])
372                                 {
373                                         while(get_selected_instance()->redo_action_stack().size() && get_selected_instance()->undo_action_stack().front()!=action)
374                                                 if(get_selected_instance()->redo()==false)
375                                                         throw int();
376                                 }
377                                 }
378                                 catch(int)
379                                 {
380                                         return true;
381                                 }
382                         }
383                 }
384                 
385         case GDK_BUTTON_RELEASE:
386                 break;
387         default:
388                 break;
389         }
390         return false;
391 }
392
393 void
394 Dock_History::on_action_toggle(const Glib::ustring& path_string)
395 {
396         studio::HistoryTreeStore::Model history_tree_model;
397
398         Gtk::TreePath path(path_string);
399         
400         const Gtk::TreeRow row = *(selected_instance->history_tree_store()->get_iter(path));
401
402         handle<synfigapp::Action::Undoable> action=row[history_tree_model.action];
403         
404         selected_instance->synfigapp::Instance::set_action_status(action,!action->is_active());
405 }