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