Added copyright lines for files I've edited this year.
[synfig.git] / synfig-studio / trunk / src / gtkmm / app.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file app.cpp
3 **      \brief writeme
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include <fstream>
34 #include <iostream>
35 #include <locale>
36 #include <cstring>
37
38 #ifdef HAVE_SYS_ERRNO_H
39 #include <sys/errno.h>
40 #endif
41 #include <gtkmm/fileselection.h>
42 #include <gtkmm/dialog.h>
43 #include <gtkmm/messagedialog.h>
44 #include <gtkmm/label.h>
45 #include <gtkmm/stock.h>
46 #include <gtkmm/stockitem.h>
47 #include <gtkmm/iconsource.h>
48 #include <gtkmm/inputdialog.h>
49 #include <gtkmm/accelmap.h>
50 #include <gtkmm/uimanager.h>
51
52 #include <gtk/gtk.h>
53
54 #include <synfig/loadcanvas.h>
55 #include <synfig/savecanvas.h>
56
57 #include "app.h"
58 #include "about.h"
59 #include "splash.h"
60 #include "instance.h"
61 #include "canvasview.h"
62 #include "dialog_setup.h"
63 #include "dialog_gradient.h"
64 #include "dialog_color.h"
65 #include "toolbox.h"
66 #include "compview.h"
67 #include "onemoment.h"
68
69 #include "dockmanager.h"
70
71 #include "state_eyedrop.h"
72 #include "state_normal.h"
73 #include "state_draw.h"
74 #include "state_fill.h"
75 #include "state_bline.h"
76 #include "state_polygon.h"
77 #include "state_sketch.h"
78 #include "state_gradient.h"
79 #include "state_circle.h"
80 #include "state_rectangle.h"
81 #include "state_smoothmove.h"
82 #include "state_scale.h"
83 #include "state_width.h"
84 #include "state_rotate.h"
85 #include "state_zoom.h"
86
87 #include "devicetracker.h"
88 #include "dialog_tooloptions.h"
89 #include "widget_enum.h"
90
91 #include "autorecover.h"
92
93 #include <synfigapp/settings.h>
94 #include "dock_history.h"
95 #include "dock_canvases.h"
96 #include "dock_keyframes.h"
97 #include "dock_layers.h"
98 #include "dock_params.h"
99 #include "dock_metadata.h"
100 #include "dock_children.h"
101 #include "dock_info.h"
102 #include "dock_navigator.h"
103 #include "dock_layergroups.h"
104 #include "dock_timetrack.h"
105 #include "dock_curves.h"
106
107 #include "mod_palette/mod_palette.h"
108 #include "mod_mirror/mod_mirror.h"
109
110 #include <sys/stat.h>
111
112 #include "ipc.h"
113
114 #include "module.h"
115
116 #include "statemanager.h"
117
118 #ifdef WITH_FMOD
119 #include <fmod.h>
120 #endif
121
122 #ifdef WIN32
123 #define _WIN32_WINNT 0x0500
124 #include <windows.h>
125 #endif
126 #include <gtkmm/accelmap.h>
127 #include <gtkmm/filechooser.h>
128 #include <gtkmm/filechooserdialog.h>
129
130 #include "general.h"
131
132 #endif
133
134 /* === U S I N G =========================================================== */
135
136 using namespace std;
137 using namespace etl;
138 using namespace synfig;
139 using namespace studio;
140
141 /* === M A C R O S ========================================================= */
142
143 #ifndef SYNFIG_USER_APP_DIR
144 #ifdef __APPLE__
145 #define SYNFIG_USER_APP_DIR     "Library/Synfig"
146 #elif defined(_WIN32)
147 #define SYNFIG_USER_APP_DIR     "Synfig"
148 #else
149 #define SYNFIG_USER_APP_DIR     ".synfig"
150 #endif
151 #endif
152
153 #ifndef DPM2DPI
154 #define DPM2DPI(x)      (float(x)/39.3700787402f)
155 #define DPI2DPM(x)      (float(x)*39.3700787402f)
156 #endif
157
158 #ifdef WIN32
159 #       ifdef IMAGE_DIR
160 #               undef IMAGE_DIR
161 #               define IMAGE_DIR "share\\pixmaps"
162 #       endif
163 #endif
164
165 #ifndef IMAGE_DIR
166 #       define IMAGE_DIR "/usr/local/share/pixmaps"
167 #endif
168
169 #ifndef IMAGE_EXT
170 #       define IMAGE_EXT        "tif"
171 #endif
172
173 #include <synfigapp/main.h>
174
175 /* === S I G N A L S ======================================================= */
176
177 static sigc::signal<void> signal_present_all_;
178 sigc::signal<void>&
179 App::signal_present_all() { return signal_present_all_; }
180
181 static sigc::signal<void> signal_recent_files_changed_;
182 sigc::signal<void>&
183 App::signal_recent_files_changed() { return signal_recent_files_changed_; }
184
185 static sigc::signal<void,etl::loose_handle<CanvasView> > signal_canvas_view_focus_;
186 sigc::signal<void,etl::loose_handle<CanvasView> >&
187 App::signal_canvas_view_focus() { return signal_canvas_view_focus_; }
188
189 static sigc::signal<void,etl::handle<Instance> > signal_instance_selected_;
190 sigc::signal<void,etl::handle<Instance> >&
191 App::signal_instance_selected() { return signal_instance_selected_; }
192
193 static sigc::signal<void,etl::handle<Instance> > signal_instance_created_;
194 sigc::signal<void,etl::handle<Instance> >&
195 App::signal_instance_created() { return signal_instance_created_; }
196
197 static sigc::signal<void,etl::handle<Instance> > signal_instance_deleted_;
198 sigc::signal<void,etl::handle<Instance> >&
199 App::signal_instance_deleted() { return signal_instance_deleted_; }
200
201 /* === G L O B A L S ======================================================= */
202
203 static std::list<std::string> recent_files;
204 const std::list<std::string>& App::get_recent_files() { return recent_files; }
205
206 int     App::Busy::count;
207 bool App::shutdown_in_progress;
208
209 synfig::Gamma App::gamma;
210
211 Glib::RefPtr<studio::UIManager> App::ui_manager_;
212
213 synfig::Distance::System App::distance_system;
214
215 studio::Dialog_Setup* App::dialog_setup;
216
217 etl::handle< studio::ModPalette > mod_palette_;
218 //studio::Dialog_Palette* App::dialog_palette;
219
220 std::list<etl::handle<Instance> > App::instance_list;
221
222 static etl::handle<synfigapp::UIInterface> ui_interface_;
223 const etl::handle<synfigapp::UIInterface>& App::get_ui_interface() { return ui_interface_; }
224
225 etl::handle<Instance> App::selected_instance;
226 etl::handle<CanvasView> App::selected_canvas_view;
227
228 studio::About *studio::App::about=NULL;
229
230 studio::Toolbox *studio::App::toolbox=NULL;
231
232 studio::AutoRecover *studio::App::auto_recover=NULL;
233
234 studio::IPC *ipc=NULL;
235
236 studio::DockManager* studio::App::dock_manager=0;
237
238 studio::DeviceTracker* studio::App::device_tracker=0;
239
240 studio::Dialog_Gradient* studio::App::dialog_gradient;
241
242 studio::Dialog_Color* studio::App::dialog_color;
243
244 Gtk::InputDialog* studio::App::dialog_input;
245
246 studio::Dialog_ToolOptions* studio::App::dialog_tool_options;
247
248 studio::Dock_History* dock_history;
249 studio::Dock_Canvases* dock_canvases;
250 studio::Dock_Keyframes* dock_keyframes;
251 studio::Dock_Layers* dock_layers;
252 studio::Dock_Params* dock_params;
253 studio::Dock_MetaData* dock_meta_data;
254 studio::Dock_Children* dock_children;
255 studio::Dock_Info* dock_info;
256 studio::Dock_LayerGroups* dock_layer_groups;
257 studio::Dock_Navigator* dock_navigator;
258 studio::Dock_Timetrack* dock_timetrack;
259 studio::Dock_Curves* dock_curves;
260
261 std::list< etl::handle< studio::Module > > module_list_;
262
263 bool studio::App::use_colorspace_gamma=true;
264 bool studio::App::single_threaded=false;
265 bool studio::App::restrict_radius_ducks=false;
266
267 static int max_recent_files_=25;
268 int studio::App::get_max_recent_files() { return max_recent_files_; }
269 void studio::App::set_max_recent_files(int x) { max_recent_files_=x; }
270
271 static synfig::String app_base_path_;
272
273 namespace studio {
274
275 bool
276 really_delete_widget(Gtk::Widget *widget)
277 {
278         // synfig::info("really delete %p", (void*)widget);
279         delete widget;
280         return false;
281 }
282
283 // nasty workaround - when we've finished with a popup menu, we want to delete it
284 // attaching to the signal_hide() signal gets us here before the action on the menu has run,
285 // so schedule the real delete to happen in 50ms, giving the action a chance to run
286 void
287 delete_widget(Gtk::Widget *widget)
288 {
289         // synfig::info("delete %p", (void*)widget);
290         Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&really_delete_widget), widget), 50);
291 }
292
293 }; // END of namespace studio
294 studio::StateManager* state_manager;
295
296
297
298
299 class GlobalUIInterface : public synfigapp::UIInterface
300 {
301 public:
302
303         virtual Response yes_no(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
304         {
305                 Gtk::Dialog dialog(
306                         title,          // Title
307                         true,           // Modal
308                         true            // use_separator
309                 );
310                 Gtk::Label label(message);
311                 label.show();
312
313                 dialog.get_vbox()->pack_start(label);
314                 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
315                 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
316
317                 dialog.set_default_response(dflt);
318                 dialog.show();
319                 return (Response)dialog.run();
320         }
321         virtual Response yes_no_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_YES)
322         {
323                 Gtk::Dialog dialog(
324                         title,          // Title
325                         true,           // Modal
326                         true            // use_separator
327                 );
328                 Gtk::Label label(message);
329                 label.show();
330
331                 dialog.get_vbox()->pack_start(label);
332                 dialog.add_button(Gtk::StockID("gtk-yes"),RESPONSE_YES);
333                 dialog.add_button(Gtk::StockID("gtk-no"),RESPONSE_NO);
334                 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
335
336                 dialog.set_default_response(dflt);
337                 dialog.show();
338                 return (Response)dialog.run();
339         }
340         virtual Response ok_cancel(const std::string &title, const std::string &message,Response dflt=RESPONSE_OK)
341         {
342                 Gtk::Dialog dialog(
343                         title,          // Title
344                         true,           // Modal
345                         true            // use_separator
346                 );
347                 Gtk::Label label(message);
348                 label.show();
349
350                 dialog.get_vbox()->pack_start(label);
351                 dialog.add_button(Gtk::StockID("gtk-ok"),RESPONSE_OK);
352                 dialog.add_button(Gtk::StockID("gtk-cancel"),RESPONSE_CANCEL);
353
354                 dialog.set_default_response(dflt);
355                 dialog.show();
356                 return (Response)dialog.run();
357         }
358
359         virtual bool
360         task(const std::string &task)
361         {
362                 std::cerr<<task<<std::endl;
363                 while(studio::App::events_pending())studio::App::iteration(false);
364                 return true;
365         }
366
367         virtual bool
368         error(const std::string &err)
369         {
370                 Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
371                 dialog.show();
372                 dialog.run();
373                 return true;
374         }
375
376         virtual bool
377         warning(const std::string &err)
378         {
379                 std::cerr<<"warning: "<<err<<std::endl;
380                 while(studio::App::events_pending())studio::App::iteration(false);
381                 return true;
382         }
383
384         virtual bool
385         amount_complete(int /*current*/, int /*total*/)
386         {
387                 while(studio::App::events_pending())studio::App::iteration(false);
388                 return true;
389         }
390 };
391
392 /* === P R O C E D U R E S ================================================= */
393
394 /*
395 void
396 studio::UIManager::insert_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group, int pos)
397 {
398         action_group_list.push_back(action_group);
399         Gtk::UIManager::insert_action_group(action_group, pos);
400 }
401
402 void
403 studio::UIManager::remove_action_group (const Glib::RefPtr<Gtk::ActionGroup>& action_group)
404 {
405         std::list<Glib::RefPtr<Gtk::ActionGroup> >::iterator iter;
406         for(iter=action_group_list.begin();iter!=action_group_list.end();++iter)
407                 if(*iter==action_group)
408                 {
409                         action_group_list.erase(iter);
410                         Gtk::UIManager::remove_action_group(action_group);
411                         return;
412                 }
413         synfig::error("Unable to find action group");
414 }
415
416 void
417 studio::add_action_group_to_top(Glib::RefPtr<studio::UIManager> ui_manager, Glib::RefPtr<Gtk::ActionGroup> group)
418 {
419         ui_manager->insert_action_group(group,0);
420         return;
421         std::list<Glib::RefPtr<Gtk::ActionGroup> > prev_groups(ui_manager->get_action_groups());
422         std::list<Glib::RefPtr<Gtk::ActionGroup> >::reverse_iterator iter;
423
424         for(iter=prev_groups.rbegin();iter!=prev_groups.rend();++iter)
425         {
426                 if(*iter && (*iter)->get_name()!="menus")
427                 {
428                         synfig::info("Removing action group "+(*iter)->get_name());
429                         ui_manager->remove_action_group(*iter);
430                 }
431         }
432         ui_manager->insert_action_group(group,0);
433
434         for(;!prev_groups.empty();prev_groups.pop_front())
435         {
436                 if(prev_groups.front() && prev_groups.front()!=group && prev_groups.front()->get_name()!="menus")
437                         ui_manager->insert_action_group(prev_groups.front(),1);
438         }
439 }
440 */
441 class Preferences : public synfigapp::Settings
442 {
443 public:
444         virtual bool get_value(const synfig::String& key, synfig::String& value)const
445         {
446                 if(key=="gamma")
447                 {
448                         value=strprintf("%f %f %f %f",
449                                 App::gamma.get_gamma_r(),
450                                 App::gamma.get_gamma_g(),
451                                 App::gamma.get_gamma_b(),
452                                 App::gamma.get_black_level()
453                         );
454                         return true;
455                 }
456                 if(key=="time_format")
457                 {
458                         value=strprintf("%i",App::get_time_format());
459                         return true;
460                 }
461                 if(key=="file_history.size")
462                 {
463                         value=strprintf("%i",App::get_max_recent_files());
464                         return true;
465                 }
466                 if(key=="use_colorspace_gamma")
467                 {
468                         value=strprintf("%i",(int)App::use_colorspace_gamma);
469                         return true;
470                 }
471                 if(key=="distance_system")
472                 {
473                         value=strprintf("%s",Distance::system_name(App::distance_system).c_str());
474                         return true;
475                 }
476                 if(key=="single_threaded")
477                 {
478                         value=strprintf("%i",(int)App::single_threaded);
479                         return true;
480                 }
481                 if(key=="auto_recover_backup_interval")
482                 {
483                         value=strprintf("%i",App::auto_recover->get_timeout());
484                         return true;
485                 }
486                 if(key=="restrict_radius_ducks")
487                 {
488                         value=strprintf("%i",(int)App::restrict_radius_ducks);
489                         return true;
490                 }
491
492                 return synfigapp::Settings::get_value(key,value);
493         }
494
495         virtual bool set_value(const synfig::String& key,const synfig::String& value)
496         {
497                 if(key=="gamma")
498                 {
499                         float r,g,b,blk;
500
501                         strscanf(value,"%f %f %f %f",
502                                 &r,
503                                 &g,
504                                 &b,
505                                 &blk
506                         );
507
508                         App::gamma.set_all(r,g,b,blk);
509
510                         return true;
511                 }
512                 if(key=="time_format")
513                 {
514                         int i(atoi(value.c_str()));
515                         App::set_time_format(static_cast<synfig::Time::Format>(i));
516                         return true;
517                 }
518                 if(key=="auto_recover_backup_interval")
519                 {
520                         int i(atoi(value.c_str()));
521                         App::auto_recover->set_timeout(i);
522                         return true;
523                 }
524                 if(key=="file_history.size")
525                 {
526                         int i(atoi(value.c_str()));
527                         App::set_max_recent_files(i);
528                         return true;
529                 }
530                 if(key=="use_colorspace_gamma")
531                 {
532                         int i(atoi(value.c_str()));
533                         App::use_colorspace_gamma=i;
534                         return true;
535                 }
536                 if(key=="distance_system")
537                 {
538                         App::distance_system=Distance::ident_system(value);;
539                         return true;
540                 }
541                 if(key=="single_threaded")
542                 {
543                         int i(atoi(value.c_str()));
544                         App::single_threaded=i;
545                         return true;
546                 }
547                 if(key=="restrict_radius_ducks")
548                 {
549                         int i(atoi(value.c_str()));
550                         App::restrict_radius_ducks=i;
551                         return true;
552                 }
553
554                 return synfigapp::Settings::set_value(key,value);
555         }
556
557         virtual KeyList get_key_list()const
558         {
559                 KeyList ret(synfigapp::Settings::get_key_list());
560                 ret.push_back("gamma");
561                 ret.push_back("time_format");
562                 ret.push_back("distance_system");
563                 ret.push_back("file_history.size");
564                 ret.push_back("use_colorspace_gamma");
565                 ret.push_back("single_threaded");
566                 ret.push_back("auto_recover_backup_interval");
567                 ret.push_back("restrict_radius_ducks");
568                 return ret;
569         }
570 };
571
572 static ::Preferences _preferences;
573
574 void
575 init_ui_manager()
576 {
577         Glib::RefPtr<Gtk::ActionGroup> menus_action_group = Gtk::ActionGroup::create("menus");
578
579         Glib::RefPtr<Gtk::ActionGroup> toolbox_action_group = Gtk::ActionGroup::create("toolbox");
580
581         Glib::RefPtr<Gtk::ActionGroup> actions_action_group = Gtk::ActionGroup::create();
582
583         menus_action_group->add( Gtk::Action::create("menu-file", _("_File")) );
584         menus_action_group->add( Gtk::Action::create("menu-edit", _("_Edit")) );
585         menus_action_group->add( Gtk::Action::create("menu-view", _("_View")) );
586         menus_action_group->add( Gtk::Action::create("menu-canvas", _("_Canvas")) );
587         menus_action_group->add( Gtk::Action::create("menu-layer", _("_Layer")) );
588         menus_action_group->add( Gtk::Action::create("menu-duck-mask", _("Show/Hide Ducks")) );
589         menus_action_group->add( Gtk::Action::create("menu-preview-quality", _("Preview Quality")) );
590         menus_action_group->add( Gtk::Action::create("menu-lowres-pixel", _("Low-Res Pixel Size")) );
591         menus_action_group->add( Gtk::Action::create("menu-layer-new", _("New Layer")) );
592         menus_action_group->add( Gtk::Action::create("menu-keyframe", _("Keyframe")) );
593         menus_action_group->add( Gtk::Action::create("menu-group", _("Group")) );
594         menus_action_group->add( Gtk::Action::create("menu-state", _("State")) );
595         menus_action_group->add( Gtk::Action::create("menu-toolbox", _("Toolbox")) );
596
597         // Add the synfigapp actions...
598         synfigapp::Action::Book::iterator iter;
599         for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
600         {
601                 actions_action_group->add(Gtk::Action::create(
602                         "action-"+iter->second.name,
603                         get_action_stock_id(iter->second),
604                         iter->second.local_name,iter->second.local_name
605                 ));
606         }
607
608 #define DEFINE_ACTION(x,stock) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
609 #define DEFINE_ACTION2(x,stock,label) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock,label,label) ); /*action->set_sensitive(false);*/ actions_action_group->add(action); }
610 #define DEFINE_ACTION_SIG(group,x,stock,sig) { Glib::RefPtr<Gtk::Action> action( Gtk::Action::create(x, stock) ); /*action->set_sensitive(false);*/ group->add(action,sig); }
611
612         DEFINE_ACTION2("keyframe-properties", Gtk::StockID("gtk-properties"), _("Keyframe Properties"));
613         DEFINE_ACTION("about", Gtk::StockID("synfig-about"));
614         DEFINE_ACTION("new", Gtk::Stock::NEW);
615         DEFINE_ACTION("open", Gtk::Stock::OPEN);
616         DEFINE_ACTION("save", Gtk::Stock::SAVE);
617         DEFINE_ACTION("save-as", Gtk::Stock::SAVE_AS);
618         DEFINE_ACTION("revert", Gtk::Stock::REVERT_TO_SAVED);
619         DEFINE_ACTION("cvs-add", Gtk::StockID("synfig-cvs_add"));
620         DEFINE_ACTION("cvs-update", Gtk::StockID("synfig-cvs_update"));
621         DEFINE_ACTION("cvs-commit", Gtk::StockID("synfig-cvs_commit"));
622         DEFINE_ACTION("cvs-revert", Gtk::StockID("synfig-cvs_revert"));
623         DEFINE_ACTION("import", _("Import"));
624         DEFINE_ACTION("render", _("Render"));
625         DEFINE_ACTION("preview", _("Preview"));
626         DEFINE_ACTION("dialog-flipbook", _("Preview Dialog"));
627         DEFINE_ACTION("sound", _("Sound File"));
628         DEFINE_ACTION("options", _("Options"));
629         DEFINE_ACTION("close", _("Close View"));
630         DEFINE_ACTION("close-document", _("Close Document"));
631         DEFINE_ACTION("quit", Gtk::Stock::QUIT);
632
633
634         DEFINE_ACTION("undo", Gtk::StockID("gtk-undo"));
635         DEFINE_ACTION("redo", Gtk::StockID("gtk-redo"));
636         DEFINE_ACTION("cut", Gtk::StockID("gtk-cut"));
637         DEFINE_ACTION("copy", Gtk::StockID("gtk-copy"));
638         DEFINE_ACTION("paste", Gtk::StockID("gtk-paste"));
639         DEFINE_ACTION("select-all-ducks", _("Select All Ducks"));
640         DEFINE_ACTION("unselect-all-layers", _("Unselect All Layers"));
641         DEFINE_ACTION("properties", _("Properties"));
642
643         DEFINE_ACTION("mask-position-ducks", _("Show Position Ducks"));
644         DEFINE_ACTION("mask-vertex-ducks", _("Show Vertex Ducks"));
645         DEFINE_ACTION("mask-tangent-ducks", _("Show Tangent Ducks"));
646         DEFINE_ACTION("mask-radius-ducks", _("Show Radius Ducks"));
647         DEFINE_ACTION("mask-width-ducks", _("Show Width Ducks"));
648         DEFINE_ACTION("mask-angle-ducks", _("Show Angle Ducks"));
649         DEFINE_ACTION("quality-00", _("Use Parametric Renderer"));
650         DEFINE_ACTION("quality-01", _("Use Quality Level 1"));
651         DEFINE_ACTION("quality-02", _("Use Quality Level 2"));
652         DEFINE_ACTION("quality-03", _("Use Quality Level 3"));
653         DEFINE_ACTION("quality-04", _("Use Quality Level 4"));
654         DEFINE_ACTION("quality-05", _("Use Quality Level 5"));
655         DEFINE_ACTION("quality-06", _("Use Quality Level 6"));
656         DEFINE_ACTION("quality-07", _("Use Quality Level 7"));
657         DEFINE_ACTION("quality-08", _("Use Quality Level 8"));
658         DEFINE_ACTION("quality-09", _("Use Quality Level 9"));
659         DEFINE_ACTION("quality-10", _("Use Quality Level 10"));
660         for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
661                 DEFINE_ACTION(strprintf("lowres-pixel-%d", *iter), strprintf(_("Set Low-Res pixel size to %d"), *iter));
662         DEFINE_ACTION("play", _("Play"));
663         // DEFINE_ACTION("pause", _("Pause"));
664         DEFINE_ACTION("stop", _("Stop"));
665         DEFINE_ACTION("toggle-grid-show", _("Toggle Grid Show"));
666         DEFINE_ACTION("toggle-grid-snap", _("Toggle Grid Snap"));
667         DEFINE_ACTION("toggle-guide-show", _("Toggle Guide Show"));
668         DEFINE_ACTION("toggle-low-res", _("Toggle Low-Res"));
669         DEFINE_ACTION("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
670         DEFINE_ACTION("increase-low-res-pixel-size", _("Increase Low-Res Pixel Size"));
671         DEFINE_ACTION("toggle-onion-skin", _("Toggle Onion Skin"));
672         DEFINE_ACTION("canvas-zoom-in", Gtk::StockID("gtk-zoom-in"));
673         DEFINE_ACTION("canvas-zoom-out", Gtk::StockID("gtk-zoom-out"));
674         DEFINE_ACTION("canvas-zoom-fit", Gtk::StockID("gtk-zoom-fit"));
675         DEFINE_ACTION("canvas-zoom-100", Gtk::StockID("gtk-zoom-100"));
676         DEFINE_ACTION("time-zoom-in", Gtk::StockID("gtk-zoom-in"));
677         DEFINE_ACTION("time-zoom-out", Gtk::StockID("gtk-zoom-out"));
678         DEFINE_ACTION("jump-next-keyframe", _("Jump to Next Keyframe"));
679         DEFINE_ACTION("jump-prev-keyframe", _("Jump to Prev Keyframe"));
680         DEFINE_ACTION("seek-next-frame", _("Next Frame"));
681         DEFINE_ACTION("seek-prev-frame", _("Prev Frame"));
682         DEFINE_ACTION("seek-next-second", _("Seek Forward"));
683         DEFINE_ACTION("seek-prev-second", _("Seek Backward"));
684         DEFINE_ACTION("seek-begin", _("Seek to Begin"));
685         DEFINE_ACTION("seek-end", _("Seek to End"));
686
687         DEFINE_ACTION("action-group_add", _("Add group"));
688
689         DEFINE_ACTION("canvas-new", _("New Canvas"));
690
691         DEFINE_ACTION("amount-inc", _("Increase Amount"));
692         DEFINE_ACTION("amount-dec", _("Decrease Amount"));
693
694 #undef DEFINE_ACTION
695
696
697 // Set up synfigapp actions
698         /*{
699                 synfigapp::Action::Book::iterator iter;
700
701                 for(iter=synfigapp::Action::book().begin();iter!=synfigapp::Action::book().end();++iter)
702                 {
703                         Gtk::StockID stock_id;
704
705                         if(!(iter->second.category&synfigapp::Action::CATEGORY_HIDDEN))
706                         {
707                                 //Gtk::Image* image(manage(new Gtk::Image()));
708                                 if(iter->second.task=="raise")                  stock_id=Gtk::Stock::GO_UP;
709                                 else if(iter->second.task=="lower")             stock_id=Gtk::Stock::GO_DOWN;
710                                 else if(iter->second.task=="move_top")  stock_id=Gtk::Stock::GOTO_TOP;
711                                 else if(iter->second.task=="move_bottom")       stock_id=Gtk::Stock::GOTO_BOTTOM;
712                                 else if(iter->second.task=="remove")    stock_id=Gtk::Stock::DELETE;
713                                 else if(iter->second.task=="set_on")    stock_id=Gtk::Stock::YES;
714                                 else if(iter->second.task=="set_off")   stock_id=Gtk::Stock::NO;
715                                 //else if(iter->second.task=="duplicate")       stock_id=Gtk::Stock::COPY;
716                                 else if(iter->second.task=="remove")    stock_id=Gtk::Stock::DELETE;
717                                 else                                                                    stock_id=Gtk::StockID("synfig-"+iter->second.task);
718
719                                 actions_action_group->add(Gtk::Action::create(
720                                         "action-"+iter->second.name,
721                                         stock_id,
722                                         iter->second.local_name,iter->second.local_name
723                                 ));
724                         }
725                 }
726         }
727 */
728
729
730     Glib::ustring ui_info =
731 "<ui>"
732 "       <popup name='menu-toolbox' action='menu-toolbox'>"
733 "       <menu action='menu-file'>"
734 "       </menu>"
735 "       </popup>"
736 "       <popup name='menu-main' action='menu-main'>"
737 "       <menu action='menu-file'>"
738 "               <menuitem action='new' />"
739 "               <menuitem action='open' />"
740 "               <menuitem action='save' />"
741 "               <menuitem action='save-as' />"
742 "               <menuitem action='revert' />"
743 "               <separator name='bleh01'/>"
744 "               <menuitem action='cvs-add' />"
745 "               <menuitem action='cvs-update' />"
746 "               <menuitem action='cvs-commit' />"
747 "               <menuitem action='cvs-revert' />"
748 "               <separator name='bleh02'/>"
749 "               <menuitem action='import' />"
750 "               <separator name='bleh03'/>"
751 "               <menuitem action='render' />"
752 "               <menuitem action='preview' />"
753 "               <menuitem action='sound' />"
754 "               <separator name='bleh04'/>"
755 "               <menuitem action='options' />"
756 "               <menuitem action='close' />"
757 "               <menuitem action='close-document' />"
758 "               <menuitem action='quit' />"
759 "       </menu>"
760 "       <menu action='menu-edit'>"
761 "               <menuitem action='undo'/>"
762 "               <menuitem action='redo'/>"
763 "               <separator name='bleh05'/>"
764 "               <menuitem action='cut'/>"
765 "               <menuitem action='copy'/>"
766 "               <menuitem action='paste'/>"
767 "               <separator name='bleh06'/>"
768 "               <menuitem action='select-all-ducks'/>"
769 "               <menuitem action='unselect-all-layers'/>"
770 "               <separator name='bleh07'/>"
771 "               <menuitem action='properties'/>"
772 "       </menu>"
773 "       <menu action='menu-view'>"
774 "               <menu action='menu-duck-mask'>"
775 "                       <menuitem action='mask-position-ducks' />"
776 "                       <menuitem action='mask-vertex-ducks' />"
777 "                       <menuitem action='mask-tangent-ducks' />"
778 "                       <menuitem action='mask-radius-ducks' />"
779 "                       <menuitem action='mask-width-ducks' />"
780 "                       <menuitem action='mask-angle-ducks' />"
781 "               </menu>"
782 "               <menu action='menu-preview-quality'>"
783 "                       <menuitem action='quality-00' />"
784 "                       <menuitem action='quality-01' />"
785 "                       <menuitem action='quality-02' />"
786 "                       <menuitem action='quality-03' />"
787 "                       <menuitem action='quality-04' />"
788 "                       <menuitem action='quality-05' />"
789 "                       <menuitem action='quality-06' />"
790 "                       <menuitem action='quality-07' />"
791 "                       <menuitem action='quality-08' />"
792 "                       <menuitem action='quality-09' />"
793 "                       <menuitem action='quality-10' />"
794 "               </menu>"
795 "               <menu action='menu-lowres-pixel'>"
796 "               <menuitem action='decrease-low-res-pixel-size'/>"
797 "               <menuitem action='increase-low-res-pixel-size'/>"
798 "               <separator name='pixel-size-separator'/>"
799 ;
800
801         for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
802                 ui_info += strprintf("                  <menuitem action='lowres-pixel-%d' />", *iter);
803
804         ui_info +=
805 "               </menu>"
806 "               <separator name='bleh08'/>"
807 "               <menuitem action='play'/>"
808 //"             <menuitem action='pause'/>"
809 "               <menuitem action='stop'/>"
810 "               <menuitem action='dialog-flipbook'/>"
811 "               <separator name='bleh09'/>"
812 "               <menuitem action='toggle-grid-show'/>"
813 "               <menuitem action='toggle-grid-snap'/>"
814 "               <menuitem action='toggle-guide-show'/>"
815 "               <menuitem action='toggle-low-res'/>"
816 "               <menuitem action='toggle-onion-skin'/>"
817 "               <separator name='bleh10'/>"
818 "               <menuitem action='canvas-zoom-in'/>"
819 "               <menuitem action='canvas-zoom-out'/>"
820 "               <menuitem action='canvas-zoom-fit'/>"
821 "               <menuitem action='canvas-zoom-100'/>"
822 "               <separator name='bleh11'/>"
823 "               <menuitem action='time-zoom-in'/>"
824 "               <menuitem action='time-zoom-out'/>"
825 "               <separator name='bleh12'/>"
826 "               <menuitem action='jump-next-keyframe'/>"
827 "               <menuitem action='jump-prev-keyframe'/>"
828 "               <menuitem action='seek-next-frame'/>"
829 "               <menuitem action='seek-prev-frame'/>"
830 "               <menuitem action='seek-next-second'/>"
831 "               <menuitem action='seek-prev-second'/>"
832 "               <menuitem action='seek-begin'/>"
833 "               <menuitem action='seek-end'/>"
834 "       </menu>"
835 "       <menu action='menu-canvas'>"
836 "               <menuitem action='canvas-new'/>"
837 "       </menu>"
838 "       <menu name='menu-state' action='menu-state'>"
839 "       </menu>"
840 "       <menu action='menu-group'>"
841 "               <menuitem action='action-group_add'/>"
842 "       </menu>"
843 "       <menu action='menu-layer'>"
844 //"             <menuitem action='cut'/>"
845 //"             <menuitem action='copy'/>"
846 //"             <menuitem action='paste'/>"
847 //"             <separator name='bleh06'/>"
848 "               <menu action='menu-layer-new'></menu>"
849 "               <menuitem action='amount-inc'/>"
850 "               <menuitem action='amount-dec'/>"
851 "       </menu>"
852 "       <menu action='menu-keyframe'>"
853 "               <menuitem action='keyframe-properties'/>"
854 "       </menu>"
855 "       </popup>"
856
857 "</ui>"
858 ;
859 /*              "<ui>"
860         "  <menubar name='MenuBar'>"
861         "    <menu action='MenuFile'>"
862         "      <menuitem action='New'/>"
863         "      <menuitem action='Open'/>"
864         "      <separator/>"
865         "      <menuitem action='Quit'/>"
866         "    </menu>"
867         "    <menu action='MenuEdit'>"
868         "      <menuitem action='Cut'/>"
869         "      <menuitem action='Copy'/>"
870         "      <menuitem action='Paste'/>"
871         "    </menu>"
872         "  </menubar>"
873         "  <toolbar  name='ToolBar'>"
874         "    <toolitem action='Open'/>"
875         "    <toolitem action='Quit'/>"
876         "  </toolbar>"
877         "</ui>";
878 */
879         try
880         {
881                 actions_action_group->set_sensitive(false);
882                 App::ui_manager()->set_add_tearoffs(true);
883                 App::ui_manager()->insert_action_group(menus_action_group,1);
884                 App::ui_manager()->insert_action_group(actions_action_group,1);
885                 App::ui_manager()->add_ui_from_string(ui_info);
886
887                 //App::ui_manager()->get_accel_group()->unlock();
888         }
889         catch(const Glib::Error& ex)
890         {
891                 synfig::error("building menus and toolbars failed: " + ex.what());
892         }
893
894         // Add default keyboard accelerators
895 #define ACCEL(path,accel)                                               \
896         {                                                                                       \
897                 Gtk::AccelKey accel_key(accel,path);    \
898                 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
899         }
900
901 #define ACCEL2(accel)                                                   \
902         {                                                                                       \
903                 Gtk::AccelKey accel_key(accel);                 \
904                 Gtk::AccelMap::add_entry(accel_key.get_path(), accel_key.get_key(), accel_key.get_mod());       \
905         }
906
907         ACCEL("<Actions>//select-all-ducks","<Control>a");
908         ACCEL("<Actions>//unselect-all-layers","<Control>d");
909         ACCEL("<Actions>//render","F9");
910         ACCEL("<Actions>//preview","F11");
911         ACCEL("<Actions>//properties","F8");
912         ACCEL("<Actions>//options","F12");
913         ACCEL("<Actions>//import","<control>i");
914         ACCEL2(Gtk::AccelKey(GDK_Escape,static_cast<Gdk::ModifierType>(0),"<Actions>//stop"));
915         ACCEL("<Actions>//toggle-grid-show","<Control>g");
916         ACCEL("<Actions>//toggle-grid-snap","<Control>l");
917         ACCEL2(Gtk::AccelKey('`',Gdk::CONTROL_MASK,"<Actions>//toggle-low-res"));
918         ACCEL("<Actions>//mask-position-ducks", "<Mod1>1");
919         ACCEL("<Actions>//mask-vertex-ducks", "<Mod1>2");
920         ACCEL("<Actions>//mask-tangent-ducks", "<Mod1>3");
921         ACCEL("<Actions>//mask-radius-ducks", "<Mod1>4");
922         ACCEL("<Actions>//mask-width-ducks", "<Mod1>5");
923         ACCEL("<Actions>//mask-angle-ducks", "<Mod1>6");
924
925         ACCEL2(Gtk::AccelKey(GDK_Page_Up,Gdk::SHIFT_MASK,"<Actions>//action-layer_raise"));
926         ACCEL2(Gtk::AccelKey(GDK_Page_Down,Gdk::SHIFT_MASK,"<Actions>//action-layer_lower"));
927
928         ACCEL("<Actions>//quality-01","<Control>1");
929         ACCEL("<Actions>//quality-02","<Control>2");
930         ACCEL("<Actions>//quality-03","<Control>3");
931         ACCEL("<Actions>//quality-04","<Control>4");
932         ACCEL("<Actions>//quality-05","<Control>5");
933         ACCEL("<Actions>//quality-06","<Control>6");
934         ACCEL("<Actions>//quality-07","<Control>7");
935         ACCEL("<Actions>//quality-08","<Control>8");
936         ACCEL("<Actions>//quality-09","<Control>9");
937         ACCEL("<Actions>//quality-10","<Control>0");
938         ACCEL("<Actions>//undo","<Control>z");
939         ACCEL("<Actions>//redo","<Control>r");
940         ACCEL("<Actions>//action-layer_remove","Delete");
941
942 /*      ACCEL2(Gtk::AccelKey(']',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-next-keyframe"));
943         ACCEL2(Gtk::AccelKey('[',static_cast<Gdk::ModifierType>(0),"<Actions>//jump-prev-keyframe"));
944         ACCEL2(Gtk::AccelKey('=',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-in"));
945         ACCEL2(Gtk::AccelKey('-',static_cast<Gdk::ModifierType>(0),"<Actions>//canvas-zoom-out"));
946         ACCEL("<Actions>//time-zoom-in","+");
947         ACCEL("<Actions>//time-zoom-out","_");
948 */
949         ACCEL2(Gtk::AccelKey('(',Gdk::CONTROL_MASK,"<Actions>//decrease-low-res-pixel-size"));
950         ACCEL2(Gtk::AccelKey(')',Gdk::CONTROL_MASK,"<Actions>//increase-low-res-pixel-size"));
951
952         ACCEL2(Gtk::AccelKey('(',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-dec"));
953         ACCEL2(Gtk::AccelKey(')',Gdk::MOD1_MASK|Gdk::CONTROL_MASK,"<Actions>//amount-inc"));
954
955         ACCEL2(Gtk::AccelKey(']',Gdk::CONTROL_MASK,"<Actions>//jump-next-keyframe"));
956         ACCEL2(Gtk::AccelKey('[',Gdk::CONTROL_MASK,"<Actions>//jump-prev-keyframe"));
957         ACCEL2(Gtk::AccelKey('=',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-in"));
958         ACCEL2(Gtk::AccelKey('-',Gdk::CONTROL_MASK,"<Actions>//canvas-zoom-out"));
959         ACCEL2(Gtk::AccelKey('+',Gdk::CONTROL_MASK,"<Actions>//time-zoom-in"));
960         ACCEL2(Gtk::AccelKey('_',Gdk::CONTROL_MASK,"<Actions>//time-zoom-out"));
961         ACCEL2(Gtk::AccelKey('.',Gdk::CONTROL_MASK,"<Actions>//seek-next-frame"));
962         ACCEL2(Gtk::AccelKey(',',Gdk::CONTROL_MASK,"<Actions>//seek-prev-frame"));
963         ACCEL2(Gtk::AccelKey('>',Gdk::CONTROL_MASK,"<Actions>//seek-next-second"));
964         ACCEL2(Gtk::AccelKey('<',Gdk::CONTROL_MASK,"<Actions>//seek-prev-second"));
965         ACCEL2(Gtk::AccelKey('o',Gdk::MOD1_MASK,"<Actions>//toggle-onion-skin"));
966         ACCEL("<Actions>//play",              "<Control>p");
967         ACCEL("<Actions>//seek-begin","Home");
968         ACCEL("<Actions>//seek-end","End");
969
970         ACCEL("<Actions>//state-normal",      "<Mod1>a");
971         ACCEL("<Actions>//state-smooth_move", "<Mod1>v");
972         ACCEL("<Actions>//state-scale",       "<Mod1>d");
973         ACCEL("<Actions>//state-rotate",      "<Mod1>s");
974
975         ACCEL("<Actions>//state-bline",       "<Mod1>b");
976         ACCEL("<Actions>//state-circle",      "<Mod1>c");
977         ACCEL("<Actions>//state-rectangle",   "<Mod1>r");
978         ACCEL("<Actions>//state-gradient",    "<Mod1>g");
979
980         ACCEL("<Actions>//state-eyedrop",     "<Mod1>e");
981         ACCEL("<Actions>//state-fill",        "<Mod1>f");
982         ACCEL("<Actions>//state-zoom",        "<Mod1>z");
983         ACCEL("<Actions>//state-polygon",     "<Mod1>p");
984
985         ACCEL("<Actions>//state-draw",        "<Mod1>w");
986         ACCEL("<Actions>//state-sketch",      "<Mod1>k");
987         ACCEL("<Actions>//state-width",       "<Mod1>t");
988         ACCEL("<Actions>//state-mirror",      "<Mod1>m");
989
990         ACCEL("<Actions>//canvas-zoom-fit","<Control><Shift>z");
991
992 #undef ACCEL
993 }
994
995 #ifdef _WIN32
996 #define mkdir(x,y) mkdir(x)
997 #endif
998
999 /* === M E T H O D S ======================================================= */
1000
1001 App::App(int *argc, char ***argv):
1002         Gtk::Main(argc,argv),
1003         IconController(etl::dirname((*argv)[0]))
1004 {
1005         app_base_path_=etl::dirname(etl::dirname((*argv)[0]));
1006
1007
1008         ui_interface_=new GlobalUIInterface();
1009
1010         gdk_rgb_init();
1011
1012         // don't call thread_init() if threads are already initialized
1013         // on some machines bonobo_init() initialized threads before we get here
1014         if (!g_thread_supported())
1015                 Glib::thread_init();
1016
1017         distance_system=Distance::SYSTEM_UNITS;
1018
1019         if(mkdir(get_user_app_directory().c_str(),ACCESSPERMS)<0)
1020         {
1021                 if(errno!=EEXIST)
1022                         synfig::error("UNABLE TO CREATE \"%s\"",get_user_app_directory().c_str());
1023         }
1024         else
1025         {
1026                 synfig::info("Created directory \"%s\"",get_user_app_directory().c_str());
1027         }
1028
1029
1030         ipc=new IPC();
1031
1032         if(!SYNFIG_CHECK_VERSION())
1033         {
1034                 cerr<<"FATAL: Synfig Version Mismatch"<<endl;
1035                 dialog_error_blocking("Synfig Studio",
1036                         "This copy of Synfig Studio was compiled against a\n"
1037                         "different version of libsynfig than what is currently\n"
1038                         "installed. Synfig Studio will now abort. Try downloading\n"
1039                         "the latest version from the Synfig website at\n"
1040                         "http://synfig.org/Download"
1041                 );
1042                 throw 40;
1043         }
1044         Glib::set_application_name(_("Synfig Studio"));
1045
1046         Splash splash_screen;
1047         splash_screen.set_can_self_destruct(false);
1048         splash_screen.show();
1049
1050         shutdown_in_progress=false;
1051         SuperCallback synfig_init_cb(splash_screen.get_callback(),0,9000,10000);
1052         SuperCallback studio_init_cb(splash_screen.get_callback(),9000,10000,10000);
1053
1054         // Initialize the Synfig library
1055         try { synfigapp_main=etl::smart_ptr<synfigapp::Main>(new synfigapp::Main(etl::dirname((*argv)[0]),&synfig_init_cb)); }
1056         catch(...)
1057         {
1058                 get_ui_interface()->error(_("Failed to initialize synfig!"));
1059                 throw;
1060         }
1061
1062         // add the preferences to the settings
1063         synfigapp::Main::settings().add_domain(&_preferences,"pref");
1064
1065         try
1066         {
1067                 studio_init_cb.task(_("Init UI Manager..."));
1068                 App::ui_manager_=studio::UIManager::create();
1069                 init_ui_manager();
1070
1071                 studio_init_cb.task(_("Init Dock Manager..."));
1072                 dock_manager=new studio::DockManager();
1073
1074                 studio_init_cb.task(_("Init State Manager..."));
1075                 state_manager=new StateManager();
1076
1077                 studio_init_cb.task(_("Init Toolbox..."));
1078                 toolbox=new studio::Toolbox();
1079
1080                 studio_init_cb.task(_("Init About Dialog..."));
1081                 about=new studio::About();
1082
1083                 studio_init_cb.task(_("Init Tool Options..."));
1084                 dialog_tool_options=new studio::Dialog_ToolOptions();
1085                 dock_manager->register_dockable(*dialog_tool_options);
1086
1087                 studio_init_cb.task(_("Init History..."));
1088                 dock_history=new studio::Dock_History();
1089                 dock_manager->register_dockable(*dock_history);
1090
1091                 studio_init_cb.task(_("Init Canvases..."));
1092                 dock_canvases=new studio::Dock_Canvases();
1093                 dock_manager->register_dockable(*dock_canvases);
1094
1095                 studio_init_cb.task(_("Init Keyframes..."));
1096                 dock_keyframes=new studio::Dock_Keyframes();
1097                 dock_manager->register_dockable(*dock_keyframes);
1098
1099                 studio_init_cb.task(_("Init Layers..."));
1100                 dock_layers=new studio::Dock_Layers();
1101                 dock_manager->register_dockable(*dock_layers);
1102
1103                 studio_init_cb.task(_("Init Params..."));
1104                 dock_params=new studio::Dock_Params();
1105                 dock_manager->register_dockable(*dock_params);
1106
1107                 studio_init_cb.task(_("Init MetaData..."));
1108                 dock_meta_data=new studio::Dock_MetaData();
1109                 dock_manager->register_dockable(*dock_meta_data);
1110
1111                 studio_init_cb.task(_("Init Children..."));
1112                 dock_children=new studio::Dock_Children();
1113                 dock_manager->register_dockable(*dock_children);
1114
1115                 studio_init_cb.task(_("Init Info..."));
1116                 dock_info = new studio::Dock_Info();
1117                 dock_manager->register_dockable(*dock_info);
1118
1119                 studio_init_cb.task(_("Init Navigator..."));
1120                 dock_navigator = new studio::Dock_Navigator();
1121                 dock_manager->register_dockable(*dock_navigator);
1122
1123                 studio_init_cb.task(_("Init Timetrack..."));
1124                 dock_timetrack = new studio::Dock_Timetrack();
1125                 dock_manager->register_dockable(*dock_timetrack);
1126
1127                 studio_init_cb.task(_("Init Curve Editor..."));
1128                 dock_curves = new studio::Dock_Curves();
1129                 dock_manager->register_dockable(*dock_curves);
1130
1131                 studio_init_cb.task(_("Init Layer Groups..."));
1132                 dock_layer_groups = new studio::Dock_LayerGroups();
1133                 dock_manager->register_dockable(*dock_layer_groups);
1134
1135
1136                 studio_init_cb.task(_("Init Color Dialog..."));
1137                 dialog_color=new studio::Dialog_Color();
1138
1139                 studio_init_cb.task(_("Init Gradient Dialog..."));
1140                 dialog_gradient=new studio::Dialog_Gradient();
1141
1142                 studio_init_cb.task(_("Init DeviceTracker..."));
1143                 device_tracker=new studio::DeviceTracker();
1144
1145                 studio_init_cb.task(_("Init Tools..."));
1146
1147                 /* row 1 */
1148                 state_manager->add_state(&state_normal);
1149                 state_manager->add_state(&state_smooth_move);
1150                 state_manager->add_state(&state_scale);
1151                 state_manager->add_state(&state_rotate);
1152                 studio_init_cb.task(_("Init ModMirror...")); module_list_.push_back(new ModMirror()); module_list_.back()->start();
1153
1154                 /* row 2 */
1155                 state_manager->add_state(&state_bline);
1156                 state_manager->add_state(&state_circle);
1157                 state_manager->add_state(&state_rectangle);
1158                 state_manager->add_state(&state_gradient);
1159                 if(!getenv("SYNFIG_DISABLE_POLYGON")) state_manager->add_state(&state_polygon); // Enabled - for working without ducks
1160
1161                 /* row 3 */
1162                 if(!getenv("SYNFIG_DISABLE_DRAW"   )) state_manager->add_state(&state_draw); // Enabled for now.  Let's see whether they're good enough yet.
1163                 if(!getenv("SYNFIG_DISABLE_SKETCH" )) state_manager->add_state(&state_sketch);
1164                 state_manager->add_state(&state_fill);
1165                 state_manager->add_state(&state_eyedrop);
1166                 state_manager->add_state(&state_zoom);
1167
1168                 // Disabled by default - it doesn't work properly?
1169                 if(getenv("SYNFIG_ENABLE_WIDTH"    )) state_manager->add_state(&state_width);
1170
1171                 studio_init_cb.task(_("Init ModPalette..."));
1172                 module_list_.push_back(new ModPalette()); module_list_.back()->start();
1173
1174                 studio_init_cb.task(_("Init Setup Dialog..."));
1175                 dialog_setup=new studio::Dialog_Setup();
1176
1177                 studio_init_cb.task(_("Init Input Dialog..."));
1178                 dialog_input=new Gtk::InputDialog();
1179                 dialog_input->get_close_button()->signal_clicked().connect( sigc::mem_fun( *dialog_input, &Gtk::InputDialog::hide ) );
1180                 dialog_input->get_save_button()->signal_clicked().connect( sigc::ptr_fun(studio::App::dialog_not_implemented) );
1181
1182                 studio_init_cb.task(_("Init auto recovery..."));
1183                 auto_recover=new AutoRecover();
1184
1185                 studio_init_cb.amount_complete(9250,10000);
1186                 studio_init_cb.task(_("Loading Settings..."));
1187                 load_settings();
1188                 studio_init_cb.task(_("Checking auto-recover..."));
1189
1190                 studio_init_cb.amount_complete(9900,10000);
1191
1192                 bool opened_any = false;
1193                 if(auto_recover->recovery_needed())
1194                 {
1195                         splash_screen.hide();
1196                         if (get_ui_interface()->yes_no(_("Auto Recovery"),
1197                                                                                    _("Synfig Studio seems to have crashed\n"
1198                                                                                          "before you could save all your files.\n"
1199                                                                                          "Would you like to re-open those files\n"
1200                                                                                          "and recover your unsaved changes?")) ==
1201                                 synfigapp::UIInterface::RESPONSE_YES)
1202                         {
1203                                 int number_recovered;
1204                                 if(!auto_recover->recover(number_recovered))
1205                                         if (number_recovered)
1206                                                 get_ui_interface()->error(_("Unable to fully recover from previous crash"));
1207                                         else
1208                                                 get_ui_interface()->error(_("Unable to recover from previous crash"));
1209                                 else
1210                                         get_ui_interface()->error(
1211                                                 _("Synfig Studio has attempted to recover\n"
1212                                                   "from a previous crash. The files that it has\n"
1213                                                   "recovered are NOT YET SAVED. It would be a good\n"
1214                                                   "idea to review them and save them now."));
1215
1216                                 if (number_recovered)
1217                                         opened_any = true;
1218                         }
1219                         splash_screen.show();
1220                 }
1221
1222                 // Look for any files given on the command line,
1223                 // and load them if found.
1224                 for(;*argc>=1;(*argc)--)
1225                         if((*argv)[*argc] && (*argv)[*argc][0]!='-')
1226                         {
1227                                 studio_init_cb.task(_("Loading files..."));
1228                                 splash_screen.hide();
1229                                 open((*argv)[*argc]);
1230                                 opened_any = true;
1231                                 splash_screen.show();
1232                         }
1233
1234                 // if no file was specified to be opened, create a new document to help new users get started more easily
1235                 if (!opened_any && !getenv("SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION"))
1236                         new_instance();
1237
1238                 studio_init_cb.task(_("Done."));
1239                 studio_init_cb.amount_complete(10000,10000);
1240
1241                 toolbox->present();
1242         }
1243         catch(String x)
1244         {
1245                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable.") + String("\n\n") + x);
1246         }
1247         catch(...)
1248         {
1249                 get_ui_interface()->error(_("Unknown exception caught when constructing App.\nThis software may be unstable."));
1250         }
1251 }
1252
1253 StateManager* App::get_state_manager() { return state_manager; }
1254
1255 App::~App()
1256 {
1257         shutdown_in_progress=true;
1258
1259         save_settings();
1260
1261         synfigapp::Main::settings().remove_domain("pref");
1262
1263         selected_instance=0;
1264
1265         // Unload all of the modules
1266         for(;!module_list_.empty();module_list_.pop_back())
1267                 ;
1268
1269         delete state_manager;
1270
1271         delete ipc;
1272
1273         delete auto_recover;
1274
1275         delete about;
1276         
1277         toolbox->hide();
1278
1279 //      studio::App::iteration(false);
1280
1281         delete toolbox;
1282
1283 //      studio::App::iteration(false);
1284
1285 //      studio::App::iteration(false);
1286
1287         delete dialog_setup;
1288
1289         delete dialog_gradient;
1290
1291         delete dialog_color;
1292
1293         delete dialog_input;
1294
1295         delete dock_manager;
1296
1297         instance_list.clear();
1298
1299 //      studio::App::iteration(false);
1300 }
1301
1302 String
1303 App::get_user_app_directory()
1304 {
1305         return Glib::build_filename(Glib::get_home_dir(),SYNFIG_USER_APP_DIR);
1306 }
1307
1308 synfig::String
1309 App::get_config_file(const synfig::String& file)
1310 {
1311         return Glib::build_filename(get_user_app_directory(),file);
1312 }
1313
1314 void
1315 App::add_recent_file(const std::string &file_name)
1316 {
1317         std::string filename(file_name);
1318
1319         assert(!filename.empty());
1320
1321         if(filename.empty())
1322                 return;
1323
1324         // Toss out any "hidden" files
1325         if(basename(filename)[0]=='.')
1326                 return;
1327
1328         // If we aren't an absolute path, turn ourselves into one
1329         if(!is_absolute_path(filename))
1330                 filename=absolute_path(filename);
1331
1332         list<string>::iterator iter;
1333         // Check to see if the file is already on the list.
1334         // If it is, then remove it from the list
1335         for(iter=recent_files.begin();iter!=recent_files.end();iter++)
1336                 if(*iter==filename)
1337                 {
1338                         recent_files.erase(iter);
1339                         break;
1340                 }
1341
1342
1343         // Push the filename to the front of the list
1344         recent_files.push_front(filename);
1345
1346         // Clean out the files at the end of the list.
1347         while(recent_files.size()>(unsigned)get_max_recent_files())
1348                 recent_files.pop_back();
1349
1350         signal_recent_files_changed_();
1351
1352         return;
1353 }
1354
1355 static Time::Format _App_time_format(Time::FORMAT_NORMAL);
1356
1357 Time::Format
1358 App::get_time_format()
1359 {
1360         return _App_time_format;
1361 }
1362
1363 void
1364 App::set_time_format(synfig::Time::Format x)
1365 {
1366         _App_time_format=x;
1367 }
1368
1369
1370 void
1371 App::save_settings()
1372 {
1373         char * old_locale;
1374         try
1375         {
1376         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1377         setlocale(LC_NUMERIC, "C");
1378                 {
1379                         std::string filename=get_config_file("accelrc");
1380                         Gtk::AccelMap::save(filename);
1381                 }
1382                 do{
1383                         std::string filename=get_config_file("recentfiles");
1384
1385                         std::ofstream file(filename.c_str());
1386
1387                         if(!file)
1388                         {
1389                                 synfig::warning("Unable to save %s",filename.c_str());
1390                                 break;
1391                         }
1392
1393                         list<string>::reverse_iterator iter;
1394
1395                         for(iter=recent_files.rbegin();iter!=recent_files.rend();iter++)
1396                                 file<<*iter<<endl;
1397                 }while(0);
1398
1399                 std::string filename=get_config_file("settings");
1400                 synfigapp::Main::settings().save_to_file(filename);
1401         setlocale(LC_NUMERIC,old_locale);
1402         }
1403         catch(...)
1404         {
1405                 synfig::warning("Caught exception when attempting to save settings.");
1406         }
1407 }
1408
1409 void
1410 App::load_settings()
1411 {
1412         char  * old_locale;
1413         try
1414         {
1415         old_locale=strdup(setlocale(LC_NUMERIC, NULL));
1416         setlocale(LC_NUMERIC, "C");
1417                 {
1418                         std::string filename=get_config_file("accelrc");
1419                         Gtk::AccelMap::load(filename);
1420                 }
1421                 {
1422                         std::string filename=get_config_file("recentfiles");
1423
1424                         std::ifstream file(filename.c_str());
1425
1426                         while(file)
1427                         {
1428                                 std::string recent_file;
1429                                 getline(file,recent_file);
1430                                 if(!recent_file.empty())
1431                                         add_recent_file(recent_file);
1432                         }
1433                 }
1434                 std::string filename=get_config_file("settings");
1435                 if(!synfigapp::Main::settings().load_from_file(filename))
1436                 {
1437                         //std::string filename=Glib::build_filename(Glib::get_home_dir(),".synfigrc");
1438                         //if(!synfigapp::Main::settings().load_from_file(filename))
1439                         {
1440                                 gamma.set_gamma(1.0/2.2);
1441                                 reset_initial_window_configuration();
1442                         }
1443                 }
1444         setlocale(LC_NUMERIC,old_locale);
1445         }
1446         catch(...)
1447         {
1448                 synfig::warning("Caught exception when attempting to load settings.");
1449         }
1450 }
1451
1452 void
1453 App::reset_initial_window_configuration()
1454 {
1455         synfigapp::Main::settings().set_value("dock.dialog.1.comp_selector","1");
1456         synfigapp::Main::settings().set_value("dock.dialog.1.contents","navigator - info pal_edit pal_browse - tool_options history canvases - layers groups");
1457         synfigapp::Main::settings().set_value("dock.dialog.1.contents_size","225 167 207");
1458         synfigapp::Main::settings().set_value("dock.dialog.1.pos","1057 32");
1459         synfigapp::Main::settings().set_value("dock.dialog.1.size","208 1174");
1460         synfigapp::Main::settings().set_value("dock.dialog.2.comp_selector","0");
1461         synfigapp::Main::settings().set_value("dock.dialog.2.contents","params children keyframes | timetrack curves meta_data");
1462         synfigapp::Main::settings().set_value("dock.dialog.2.contents_size","263");
1463         synfigapp::Main::settings().set_value("dock.dialog.2.pos","0 973");
1464         synfigapp::Main::settings().set_value("dock.dialog.2.size","1045 235");
1465         synfigapp::Main::settings().set_value("pref.distance_system","pt");
1466         synfigapp::Main::settings().set_value("pref.use_colorspace_gamma","1");
1467         synfigapp::Main::settings().set_value("pref.single_threaded","0");
1468         synfigapp::Main::settings().set_value("pref.restrict_radius_ducks","0");
1469         synfigapp::Main::settings().set_value("window.toolbox.pos","4 4");
1470 }
1471
1472 bool
1473 App::shutdown_request(GdkEventAny*)
1474 {
1475         quit();
1476         return true;
1477         //return !shutdown_in_progress;
1478 }
1479
1480 void
1481 App::quit()
1482 {
1483         if(shutdown_in_progress)return;
1484
1485
1486         get_ui_interface()->task(_("Quit Request"));
1487         if(Busy::count)
1488         {
1489                 dialog_error_blocking(_("Cannot quit!"),_("Tasks are currently running.\nPlease cancel the current tasks and try again"));
1490                 return;
1491         }
1492
1493         std::list<etl::handle<Instance> >::iterator iter;
1494         for(iter=instance_list.begin();!instance_list.empty();iter=instance_list.begin())
1495         {
1496                 if(!(*iter)->safe_close())
1497                         return;
1498
1499 /*
1500                 if((*iter)->synfigapp::Instance::get_action_count())
1501                 {
1502                         handle<synfigapp::UIInterface> uim;
1503                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1504                         assert(uim);
1505                         string str=strprintf(_("Would you like to save your changes to %s?"),(*iter)->get_file_name().c_str() );
1506                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1507                         {
1508                                 case synfigapp::UIInterface::RESPONSE_NO:
1509                                         break;
1510                                 case synfigapp::UIInterface::RESPONSE_YES:
1511                                         (*iter)->save();
1512                                         break;
1513                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1514                                         return;
1515                                 default:
1516                                         assert(0);
1517                                         return;
1518                         }
1519                 }
1520
1521
1522                 if((*iter)->synfigapp::Instance::is_modified())
1523                 {
1524                         handle<synfigapp::UIInterface> uim;
1525                         uim=(*iter)->find_canvas_view((*iter)->get_canvas())->get_ui_interface();
1526                         assert(uim);
1527                         string str=strprintf(_("%s has changes not yet on the CVS repository.\nWould you like to commit these changes?"),(*iter)->get_file_name().c_str() );
1528                         switch(uim->yes_no_cancel((*iter)->get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES))
1529                         {
1530                                 case synfigapp::UIInterface::RESPONSE_NO:
1531                                         break;
1532                                 case synfigapp::UIInterface::RESPONSE_YES:
1533                                         (*iter)->dialog_cvs_commit();
1534                                         break;
1535                                 case synfigapp::UIInterface::RESPONSE_CANCEL:
1536                                         return;
1537                                 default:
1538                                         assert(0);
1539                                         return;
1540                         }
1541                 }
1542 */
1543
1544                 // This next line causes things to crash for some reason
1545                 //(*iter)->close();
1546         }
1547
1548         shutdown_in_progress=true;
1549
1550         instance_list.clear();
1551
1552         while(studio::App::events_pending())studio::App::iteration(false);
1553
1554         Gtk::Main::quit();
1555         auto_recover->normal_shutdown();
1556
1557         get_ui_interface()->task(_("Quit Request sent"));
1558 }
1559
1560 void
1561 App::show_setup()
1562 {
1563         dialog_setup->refresh();
1564         dialog_setup->show();
1565 }
1566
1567 gint Signal_Open_Ok(GtkWidget */*widget*/, int *val){*val=1;return 0;}
1568 gint Signal_Open_Cancel(GtkWidget */*widget*/, int *val){*val=2;return 0;}
1569
1570 //#ifdef WIN32
1571 //#define USE_WIN32_FILE_DIALOGS 1
1572 //#endif
1573
1574 #ifdef USE_WIN32_FILE_DIALOGS
1575 static OPENFILENAME ofn={};
1576 #endif
1577
1578 #ifdef WIN32
1579 #include <gdk/gdkwin32.h>
1580 #endif
1581
1582 bool
1583 App::dialog_open_file(const std::string &title, std::string &filename, std::string preference)
1584 {
1585         info("App::dialog_open_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1586
1587 #ifdef USE_WIN32_FILE_DIALOGS
1588         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1589
1590         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1591         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1592         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1593
1594         ofn.lStructSize=sizeof(OPENFILENAME);
1595         ofn.hwndOwner = hWnd;
1596         ofn.hInstance = hInstance;
1597         ofn.lpstrFilter = szFilter;
1598 //      ofn.lpstrCustomFilter=NULL;
1599 //      ofn.nMaxCustFilter=0;
1600 //      ofn.nFilterIndex=0;
1601 //      ofn.lpstrFile=NULL;
1602         ofn.nMaxFile=MAX_PATH;
1603 //      ofn.lpstrFileTitle=NULL;
1604 //      ofn.lpstrInitialDir=NULL;
1605 //      ofn.lpstrTitle=NULL;
1606         ofn.Flags=OFN_HIDEREADONLY;
1607 //      ofn.nFileOffset=0;
1608 //      ofn.nFileExtension=0;
1609         ofn.lpstrDefExt=TEXT("sif");
1610 //      ofn.lCustData = 0l;
1611         ofn.lpfnHook=NULL;
1612 //      ofn.lpTemplateName=NULL;
1613
1614         CHAR szFilename[MAX_PATH];
1615         CHAR szTitle[500];
1616         strcpy(szFilename,filename.c_str());
1617         strcpy(szTitle,title.c_str());
1618
1619         ofn.lpstrFile=szFilename;
1620         ofn.lpstrFileTitle=szTitle;
1621
1622         if(GetOpenFileName(&ofn))
1623         {
1624                 filename=szFilename;
1625                 return true;
1626         }
1627         return false;
1628
1629 #else
1630         synfig::String prev_path;
1631
1632         if(!_preferences.get_value(preference, prev_path))
1633                 prev_path = ".";
1634
1635         prev_path = absolute_path(prev_path);
1636
1637     Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_OPEN);
1638
1639     dialog->set_current_folder(prev_path);
1640     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1641     dialog->add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_ACCEPT);
1642
1643     if (filename.empty())
1644                 dialog->set_filename(prev_path);
1645         else if (is_absolute_path(filename))
1646                 dialog->set_filename(filename);
1647         else
1648                 dialog->set_filename(prev_path + ETL_DIRECTORY_SEPARATOR + filename);
1649
1650     if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1651         filename = dialog->get_filename();
1652                 info("Saving preference %s = '%s' in App::dialog_open_file()", preference.c_str(), dirname(filename).c_str());
1653                 _preferences.set_value(preference, dirname(filename));
1654         delete dialog;
1655         return true;
1656     }
1657
1658     delete dialog;
1659     return false;
1660
1661     /*
1662
1663         GtkWidget *ok;
1664         GtkWidget *cancel;
1665         int val=0;
1666
1667         GtkWidget *fileselection;
1668         fileselection = gtk_file_selection_new(title.c_str());
1669
1670
1671         if(basename(filename)==filename)
1672         {
1673                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),(prev_path+ETL_DIRECTORY_SEPARATOR).c_str());
1674         }
1675         else
1676                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection),dirname(filename).c_str());
1677
1678         gtk_file_selection_complete(GTK_FILE_SELECTION(fileselection),basename(filename).c_str());
1679
1680         ok=GTK_FILE_SELECTION(fileselection)->ok_button;
1681         cancel=GTK_FILE_SELECTION(fileselection)->cancel_button;
1682
1683         gtk_signal_connect(GTK_OBJECT(ok),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Ok),&val);
1684         gtk_signal_connect(GTK_OBJECT(cancel),"clicked",GTK_SIGNAL_FUNC(Signal_Open_Cancel),&val);
1685
1686         gtk_widget_show(fileselection);
1687
1688         while(!val)
1689                 iteration();
1690
1691
1692         if(val==1)
1693         {
1694                 filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection));
1695                 _preferences.set_value(preference,dirname(filename));
1696         }
1697         else
1698         {
1699                 gtk_widget_destroy(fileselection);
1700                 return false;
1701         }
1702         gtk_widget_destroy(fileselection);
1703         return true;
1704     */
1705 #endif
1706 }
1707
1708 bool
1709 App::dialog_save_file(const std::string &title, std::string &filename, std::string preference)
1710 {
1711         info("App::dialog_save_file('%s', '%s', '%s')", title.c_str(), filename.c_str(), preference.c_str());
1712
1713 #if USE_WIN32_FILE_DIALOGS
1714         static TCHAR szFilter[] = TEXT ("All Files (*.*)\0*.*\0\0") ;
1715
1716         GdkWindow *gdkWinPtr=toolbox->get_window()->gobj();
1717         HINSTANCE hInstance=static_cast<HINSTANCE>(GetModuleHandle(NULL));
1718         HWND hWnd=static_cast<HWND>(GDK_WINDOW_HWND(gdkWinPtr));
1719
1720         ofn.lStructSize=sizeof(OPENFILENAME);
1721         ofn.hwndOwner = hWnd;
1722         ofn.hInstance = hInstance;
1723         ofn.lpstrFilter = szFilter;
1724 //      ofn.lpstrCustomFilter=NULL;
1725 //      ofn.nMaxCustFilter=0;
1726 //      ofn.nFilterIndex=0;
1727 //      ofn.lpstrFile=NULL;
1728         ofn.nMaxFile=MAX_PATH;
1729 //      ofn.lpstrFileTitle=NULL;
1730 //      ofn.lpstrInitialDir=NULL;
1731 //      ofn.lpstrTitle=NULL;
1732         ofn.Flags=OFN_OVERWRITEPROMPT;
1733 //      ofn.nFileOffset=0;
1734 //      ofn.nFileExtension=0;
1735         ofn.lpstrDefExt=TEXT("sif");
1736 //      ofn.lCustData = 0l;
1737         ofn.lpfnHook=NULL;
1738 //      ofn.lpTemplateName=NULL;
1739
1740         CHAR szFilename[MAX_PATH];
1741         CHAR szTitle[500];
1742         strcpy(szFilename,filename.c_str());
1743         strcpy(szTitle,title.c_str());
1744
1745         ofn.lpstrFile=szFilename;
1746         ofn.lpstrFileTitle=szTitle;
1747
1748         if(GetSaveFileName(&ofn))
1749         {
1750                 filename=szFilename;
1751                 _preferences.set_value(preference,dirname(filename));
1752                 return true;
1753         }
1754         return false;
1755 #else
1756         synfig::String prev_path;
1757
1758         if(!_preferences.get_value(preference, prev_path))
1759                 prev_path=".";
1760
1761         prev_path = absolute_path(prev_path);
1762
1763     Gtk::FileChooserDialog *dialog = new Gtk::FileChooserDialog(title, Gtk::FILE_CHOOSER_ACTION_SAVE);
1764
1765     dialog->set_current_folder(prev_path);
1766     dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1767     dialog->add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_ACCEPT);
1768
1769         Widget_Enum *file_type_enum = 0;
1770         if (preference == ANIMATION_DIR_PREFERENCE)
1771         {
1772                 file_type_enum = manage(new Widget_Enum());
1773                 file_type_enum->set_param_desc(ParamDesc().set_hint("enum")
1774                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_08, "0.61.08", strprintf("0.61.08 (%s)", _("current")))
1775                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_07, "0.61.07", "0.61.07")
1776                                                                            .add_enum_value(synfig::RELEASE_VERSION_0_61_06, "0.61.06", strprintf("0.61.06 %s", _("and older"))));
1777                 file_type_enum->set_value(RELEASE_VERSION_END-1); // default to the most recent version
1778
1779                 Gtk::HBox *hbox = manage(new Gtk::HBox);
1780                 hbox->pack_start(*manage(new Gtk::Label(_("File Format Version: "))),Gtk::PACK_SHRINK,0);
1781                 hbox->pack_start(*file_type_enum,Gtk::PACK_EXPAND_WIDGET,0);
1782                 hbox->show_all();
1783
1784                 dialog->set_extra_widget(*hbox);
1785         }
1786
1787     if (filename.empty())
1788                 dialog->set_filename(prev_path);
1789     else
1790         {
1791                 std::string full_path;
1792                 if (is_absolute_path(filename))
1793                         full_path = filename;
1794                 else
1795                         full_path = prev_path + ETL_DIRECTORY_SEPARATOR + filename;
1796
1797                 // select the file if it exists
1798                 dialog->set_filename(full_path);
1799
1800                 // if the file doesn't exist, put its name into the filename box
1801                 struct stat s;
1802                 if(stat(full_path.c_str(),&s) == -1 && errno == ENOENT)
1803                         dialog->set_current_name(basename(filename));
1804         }
1805
1806     if(dialog->run() == GTK_RESPONSE_ACCEPT) {
1807                 if (preference == ANIMATION_DIR_PREFERENCE)
1808                         set_file_version(synfig::ReleaseVersion(file_type_enum->get_value()));
1809         filename = dialog->get_filename();
1810                 info("Saving preference %s = '%s' in App::dialog_save_file()", preference.c_str(), dirname(filename).c_str());
1811                 _preferences.set_value(preference, dirname(filename));
1812         delete dialog;
1813         return true;
1814     }
1815
1816     delete dialog;
1817     return false;
1818 #endif
1819 }
1820
1821 void
1822 App::dialog_error_blocking(const std::string &title, const std::string &message)
1823 {
1824         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1825         dialog.set_title(title);
1826         dialog.show();
1827         dialog.run();
1828 }
1829
1830 void
1831 App::dialog_warning_blocking(const std::string &title, const std::string &message)
1832 {
1833         Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
1834         dialog.set_title(title);
1835         dialog.show();
1836         dialog.run();
1837 }
1838
1839 bool
1840 App::dialog_yes_no(const std::string &title, const std::string &message)
1841 {
1842         Gtk::Dialog dialog(
1843                 title,          // Title
1844                 true,           // Modal
1845                 true            // use_separator
1846         );
1847         Gtk::Label label(message);
1848         label.show();
1849
1850         dialog.get_vbox()->pack_start(label);
1851         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1852         dialog.add_button(Gtk::StockID("gtk-no"),0);
1853         dialog.show();
1854         return dialog.run();
1855 }
1856
1857 int
1858 App::dialog_yes_no_cancel(const std::string &title, const std::string &message)
1859 {
1860         Gtk::Dialog dialog(
1861                 title,          // Title
1862                 true,           // Modal
1863                 true            // use_separator
1864         );
1865         Gtk::Label label(message);
1866         label.show();
1867
1868         dialog.get_vbox()->pack_start(label);
1869         dialog.add_button(Gtk::StockID("gtk-yes"),1);
1870         dialog.add_button(Gtk::StockID("gtk-no"),0);
1871         dialog.add_button(Gtk::StockID("gtk-cancel"),2);
1872         dialog.show();
1873         return dialog.run();
1874 }
1875
1876 void
1877 App::dialog_not_implemented()
1878 {
1879         Gtk::MessageDialog dialog(_("Feature not available"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
1880         dialog.set_secondary_text(_("Sorry, this feature has not yet been implemented."));
1881         dialog.run();
1882 }
1883
1884 bool
1885 App::dialog_entry(const std::string &title, const std::string &message,std::string &text)
1886 {
1887         Gtk::Dialog dialog(
1888                 title,          // Title
1889                 true,           // Modal
1890                 true            // use_separator
1891         );
1892         Gtk::Label label(message);
1893         label.show();
1894         dialog.get_vbox()->pack_start(label);
1895
1896         Gtk::Entry entry;
1897         entry.set_text(text);
1898         entry.show();
1899         entry.set_activates_default(true);
1900         dialog.get_vbox()->pack_start(entry);
1901
1902         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
1903         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
1904         dialog.set_default_response(Gtk::RESPONSE_OK);
1905         entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
1906         dialog.show();
1907
1908         if(dialog.run()!=Gtk::RESPONSE_OK)
1909                 return false;
1910
1911         text=entry.get_text();
1912
1913         return true;
1914 }
1915
1916
1917
1918
1919 bool
1920 App::open(std::string filename)
1921 {
1922         return open_as(filename,filename);
1923 }
1924
1925 // this is called from autorecover.cpp:
1926 //   App::open_as(get_shadow_file_name(filename),filename)
1927 // other than that, 'filename' and 'as' are the same
1928 bool
1929 App::open_as(std::string filename,std::string as)
1930 {
1931 #ifdef WIN32
1932     char long_name[1024];
1933     if(GetLongPathName(as.c_str(),long_name,sizeof(long_name)));
1934     as=long_name;
1935 #endif
1936
1937         try
1938         {
1939                 OneMoment one_moment;
1940
1941                 etl::handle<synfig::Canvas> canvas(open_canvas_as(filename,as));
1942                 if(canvas && get_instance(canvas))
1943                 {
1944                         get_instance(canvas)->find_canvas_view(canvas)->present();
1945                         info("%s is already open", filename.c_str());
1946                         // throw (String)strprintf(_("\"%s\" appears to already be open!"),filename.c_str());
1947                 }
1948                 else
1949                 {
1950                         if(!canvas)
1951                                 throw (String)strprintf(_("Unable to open file \"%s\""),filename.c_str());
1952
1953                         add_recent_file(as);
1954
1955                         handle<Instance> instance(Instance::create(canvas));
1956
1957                         if(!instance)
1958                                 throw (String)strprintf(_("Unable to create instance for \"%s\""),filename.c_str());
1959
1960                         one_moment.hide();
1961
1962                         if(instance->is_updated() && App::dialog_yes_no(_("CVS Update"), _("There appears to be a newer version of this file available on the CVS repository.\nWould you like to update now? (It would probably be a good idea)")))
1963                                 instance->dialog_cvs_update();
1964                 }
1965         }
1966         catch(String x)
1967         {
1968                 dialog_error_blocking(_("Error"), x);
1969                 return false;
1970         }
1971         catch(...)
1972         {
1973                 dialog_error_blocking(_("Error"), _("Uncaught error on file open (BUG)"));
1974                 return false;
1975         }
1976
1977         return true;
1978 }
1979
1980
1981 void
1982 App::new_instance()
1983 {
1984         handle<synfig::Canvas> canvas=synfig::Canvas::create();
1985         canvas->set_name(strprintf("%s%d", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1986
1987         String file_name(strprintf("%s%d.sifz", DEFAULT_FILENAME_PREFIX, Instance::get_count()+1));
1988
1989         canvas->rend_desc().set_frame_rate(24.0);
1990         canvas->rend_desc().set_time_start(0.0);
1991         canvas->rend_desc().set_time_end(5.0);
1992         canvas->rend_desc().set_x_res(DPI2DPM(72.0f));
1993         canvas->rend_desc().set_y_res(DPI2DPM(72.0f));
1994         canvas->rend_desc().set_tl(Vector(-4,2.25));
1995         canvas->rend_desc().set_br(Vector(4,-2.25));
1996         canvas->rend_desc().set_w(480);
1997         canvas->rend_desc().set_h(270);
1998         canvas->rend_desc().set_antialias(1);
1999         canvas->rend_desc().set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN);
2000         canvas->set_file_name(file_name);
2001
2002         handle<Instance> instance = Instance::create(canvas);
2003
2004         if (getenv("SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES"))
2005                 instance->find_canvas_view(canvas)->canvas_properties.present();
2006 }
2007
2008 void
2009 App::dialog_open()
2010 {
2011         string filename="*.sif";
2012
2013         while(dialog_open_file("Open", filename, ANIMATION_DIR_PREFERENCE))
2014         {
2015                 // If the filename still has wildcards, then we should
2016                 // continue looking for the file we want
2017                 if(find(filename.begin(),filename.end(),'*')!=filename.end())
2018                         continue;
2019
2020                 if(open(filename))
2021                         break;
2022
2023                 get_ui_interface()->error(_("Unable to open file"));
2024         }
2025 }
2026
2027 void
2028 App::set_selected_instance(etl::loose_handle<Instance> instance)
2029 {
2030 /*      if(get_selected_instance()==instance)
2031         {
2032                 selected_instance=instance;
2033                 signal_instance_selected()(instance);
2034                 return;
2035         }
2036         else
2037         {
2038 */
2039                 selected_instance=instance;
2040                 if(get_selected_canvas_view() && get_selected_canvas_view()->get_instance()!=instance)
2041                 {
2042                         if(instance)
2043                         {
2044                                 instance->focus(instance->get_canvas());
2045                         }
2046                         else
2047                                 set_selected_canvas_view(0);
2048                 }
2049                 signal_instance_selected()(instance);
2050 }
2051
2052 void
2053 App::set_selected_canvas_view(etl::loose_handle<CanvasView> canvas_view)
2054 {
2055         selected_canvas_view=canvas_view;
2056         signal_canvas_view_focus()(selected_canvas_view);
2057         if(canvas_view)
2058         {
2059                 selected_instance=canvas_view->get_instance();
2060                 signal_instance_selected()(canvas_view->get_instance());
2061         }
2062 /*
2063         if(get_selected_canvas_view()==canvas_view)
2064         {
2065                 signal_canvas_view_focus()(selected_canvas_view);
2066                 signal_instance_selected()(canvas_view->get_instance());
2067                 return;
2068         }
2069         selected_canvas_view=canvas_view;
2070         if(canvas_view && canvas_view->get_instance() != get_selected_instance())
2071                 set_selected_instance(canvas_view->get_instance());
2072         signal_canvas_view_focus()(selected_canvas_view);
2073 */
2074 }
2075
2076 etl::loose_handle<Instance>
2077 App::get_instance(etl::handle<synfig::Canvas> canvas)
2078 {
2079         if(!canvas) return 0;
2080         canvas=canvas->get_root();
2081
2082         std::list<etl::handle<Instance> >::iterator iter;
2083         for(iter=instance_list.begin();iter!=instance_list.end();++iter)
2084         {
2085                 if((*iter)->get_canvas()==canvas)
2086                         return *iter;
2087         }
2088         return 0;
2089 }
2090
2091 void
2092 App::dialog_about()
2093 {
2094         if(about)
2095                 about->show();
2096 }
2097
2098 void
2099 studio::App::undo()
2100 {
2101         if(selected_instance)
2102                 selected_instance->undo();
2103 }
2104
2105 void
2106 studio::App::redo()
2107 {
2108         if(selected_instance)
2109                 selected_instance->redo();
2110 }
2111
2112 synfig::String
2113 studio::App::get_base_path()
2114 {
2115         return app_base_path_;
2116 }