1 /* === S Y N F I G ========================================================= */
2 /*!	\file dockmanager.cpp
3 **	\brief Template File
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 <synfig/general.h>
34 
35 #include "docks/dockmanager.h"
36 #include <stdexcept>
37 #include "docks/dockable.h"
38 #include "docks/dockbook.h"
39 #include "docks/dockdialog.h"
40 #include <synfigapp/settings.h>
41 #include <synfigapp/main.h>
42 #include <gdkmm/general.h>
43 
44 #include <gui/localization.h>
45 
46 #include <gtkmm/paned.h>
47 #include <gtkmm/box.h>
48 #include <gtkmm/window.h>
49 
50 #include "app.h"
51 #include "mainwindow.h"
52 #include "canvasview.h"
53 
54 #endif
55 
56 /* === U S I N G =========================================================== */
57 
58 using namespace std;
59 using namespace etl;
60 using namespace synfig;
61 using namespace studio;
62 
63 /* === M A C R O S ========================================================= */
64 
65 /* === P R O C E D U R E S ================================================= */
66 
67 std::map<Gtk::Container*, bool> DockManager::containers_to_remove_;
68 
69 namespace studio {
70 	class DockLinkPoint {
71 	public:
72 		Gtk::Bin *bin;
73 		Gtk::Paned *paned;
74 		Gtk::Window *window;
75 		bool is_first;
76 
DockLinkPoint()77 		DockLinkPoint(): bin(NULL), paned(NULL), window(NULL), is_first(false) { }
DockLinkPoint(Gtk::Bin * bin)78 		explicit DockLinkPoint(Gtk::Bin *bin): bin(bin), paned(NULL), window(NULL), is_first(false) { }
DockLinkPoint(Gtk::Paned * paned,bool is_first)79 		explicit DockLinkPoint(Gtk::Paned *paned, bool is_first): bin(NULL), paned(paned), window(NULL), is_first(is_first) { }
DockLinkPoint(Gtk::Window * window)80 		explicit DockLinkPoint(Gtk::Window *window): bin(NULL), paned(NULL), window(window), is_first(false) { }
DockLinkPoint(Gtk::Widget & widget)81 		explicit DockLinkPoint(Gtk::Widget &widget) {
82 			Gtk::Container *container = widget.get_parent();
83 			bin = dynamic_cast<Gtk::Bin*>(container);
84 			paned = dynamic_cast<Gtk::Paned*>(container);
85 			window = dynamic_cast<Gtk::Window*>(container);
86 			is_first = paned != NULL && paned->get_child1() == &widget;
87 		}
88 
is_valid()89 		bool is_valid() { return bin || paned || window; }
90 
unlink()91 		void unlink() {
92 			if (paned && is_first && paned->get_child1())
93 				paned->remove(*paned->get_child1());
94 			else
95 			if (paned && !is_first && paned->get_child2())
96 				paned->remove(*paned->get_child2());
97 			else
98 			if (window)
99 				window->remove();
100 			if (bin)
101 				bin->remove();
102 		}
103 
link(Gtk::Widget & widget)104 		void link(Gtk::Widget &widget)
105 		{
106 			if (paned && is_first)
107 				paned->pack1(widget, true, false);
108 			else
109 			if (paned && !is_first)
110 				paned->pack2(widget, true, false);
111 			else
112 			if (window)
113 				window->add(widget);
114 			else
115 			if (bin)
116 				bin->add(widget);
117 		}
118 	};
119 }
120 
121 class studio::DockSettings : public synfigapp::Settings
122 {
123 	DockManager* dock_manager;
124 
125 public:
DockSettings(DockManager * dock_manager)126 	DockSettings(DockManager* dock_manager):dock_manager(dock_manager)
127 	{
128 		synfigapp::Main::settings().add_domain(this,"dock");
129 	}
130 
~DockSettings()131 	virtual ~DockSettings()
132 	{
133 		synfigapp::Main::settings().remove_domain("dock");
134 	}
135 
get_value(const synfig::String & key_,synfig::String & value) const136 	virtual bool get_value(const synfig::String& key_, synfig::String& value)const
137 	{
138 		try
139 		{
140 			if (key_ == "layout")
141 			{
142 				value = dock_manager->save_layout_to_string();
143 				return true;
144 			}
145 		}catch (...) { return false; }
146 		return synfigapp::Settings::get_value(key_,value);
147 	}
148 
set_value(const synfig::String & key_,const synfig::String & value)149 	virtual bool set_value(const synfig::String& key_,const synfig::String& value)
150 	{
151 		try
152 		{
153 			if (key_ == "layout")
154 			{
155 				dock_manager->load_layout_from_string(value);
156 				return true;
157 			}
158 		}catch (...) { return false; }
159 		return synfigapp::Settings::set_value(key_,value);
160 	}
161 
get_key_list() const162 	virtual KeyList get_key_list()const
163 	{
164 		synfigapp::Settings::KeyList ret(synfigapp::Settings::get_key_list());
165 		ret.push_back("layout");
166 		return ret;
167 	}
168 };
169 
170 /* === M E T H O D S ======================================================= */
171 
DockManager()172 DockManager::DockManager():
173 	dock_settings(new DockSettings(this))
174 {
175 }
176 
~DockManager()177 DockManager::~DockManager()
178 {
179 	while(!dock_dialog_list_.empty())
180 	{
181 		dock_dialog_list_.back()->close();
182 	}
183 	while(!dockable_list_.empty())
184 	{
185 		Dockable* dockable(dockable_list_.back());
186 		// synfig::info("DockManager::~DockManager(): Deleting dockable \"%s\"",dockable->get_name().c_str());
187 		dockable_list_.pop_back();
188 		delete dockable;
189 	}
190 }
191 
192 void
register_dockable(Dockable & x)193 DockManager::register_dockable(Dockable& x)
194 {
195 	dockable_list_.push_back(&x);
196 	// synfig::info("DockManager::register_dockable(): Registered dockable \"%s\"",dockable_list_.back()->get_name().c_str());
197 	signal_dockable_registered()(&x);
198 }
199 
200 bool
unregister_dockable(Dockable & x)201 DockManager::unregister_dockable(Dockable& x)
202 {
203 	std::list<Dockable*>::iterator iter;
204 	for(iter=dockable_list_.begin();iter!=dockable_list_.end();++iter)
205 	{
206 		if(&x==*iter)
207 		{
208 			remove_widget_recursive(x);
209 			dockable_list_.erase(iter);
210 			signal_dockable_unregistered()(&x);
211 			synfig::info("DockManager::unregister_dockable(): \"%s\" has been Unregistered",x.get_name().c_str());
212 			update_window_titles();
213 			return true;
214 		}
215 	}
216 	return false;
217 }
218 
219 Dockable&
find_dockable(const synfig::String & x)220 DockManager::find_dockable(const synfig::String& x)
221 {
222 	std::list<Dockable*>::iterator iter;
223 	for(iter=dockable_list_.begin();iter!=dockable_list_.end();++iter)
224 		if((*iter)->get_name()==x)
225 			return **iter;
226 
227 	throw std::runtime_error("DockManager::find_dockable(): not found");
228 }
229 
230 void
present(synfig::String x)231 DockManager::present(synfig::String x)
232 {
233 	try
234 	{
235 		find_dockable(x).present();
236 	}
237 	catch(...)
238 	{
239 	}
240 }
241 
242 DockDialog&
find_dock_dialog(int id)243 DockManager::find_dock_dialog(int id)
244 {
245 	std::list<DockDialog*>::iterator iter;
246 	for(iter=dock_dialog_list_.begin();iter!=dock_dialog_list_.end();++iter)
247 		if((*iter)->get_id()==id)
248 			return **iter;
249 
250 	DockDialog* dock_dialog(new DockDialog());
251 	dock_dialog->set_id(id);
252 	return *dock_dialog;
253 }
254 
255 const DockDialog&
find_dock_dialog(int id) const256 DockManager::find_dock_dialog(int id)const
257 {
258 	std::list<DockDialog*>::const_iterator iter;
259 	for(iter=dock_dialog_list_.begin();iter!=dock_dialog_list_.end();++iter)
260 		if((*iter)->get_id()==id)
261 			return **iter;
262 
263 	throw std::runtime_error("DockManager::find_dock_dialog(int id)const: not found");
264 }
265 
266 void
show_all_dock_dialogs()267 DockManager::show_all_dock_dialogs()
268 {
269 	std::list<DockDialog*>::iterator iter;
270 	for(iter=dock_dialog_list_.begin();iter!=dock_dialog_list_.end();++iter)
271 		(*iter)->present();
272 }
273 
274 bool
swap_widgets(Gtk::Widget & widget1,Gtk::Widget & widget2)275 DockManager::swap_widgets(Gtk::Widget &widget1, Gtk::Widget &widget2)
276 {
277 	DockLinkPoint point1(widget1);
278 	DockLinkPoint point2(widget2);
279 	if (point1.is_valid() && point2.is_valid())
280 	{
281 		point1.unlink();
282 		point2.unlink();
283 		point1.link(widget2);
284 		point2.link(widget1);
285 		return true;
286 	}
287 	return false;
288 }
289 
290 void
remove_empty_container_recursive(Gtk::Container & container)291 DockManager::remove_empty_container_recursive(Gtk::Container &container)
292 {
293 	containers_to_remove_.erase(&container);
294 	Gtk::Paned *paned = dynamic_cast<Gtk::Paned*>(&container);
295 	Gtk::Window *window = dynamic_cast<Gtk::Window*>(&container);
296 	DockBook *book = dynamic_cast<DockBook*>(&container);
297 
298 	if (paned)
299 	{
300 		if (paned->get_child1() && paned->get_child2()) return;
301 		Gtk::Widget *child = paned->get_child1() ? paned->get_child1() : paned->get_child2();
302 		if (child)
303 		{
304 			DockLinkPoint link(*paned);
305 			if (link.is_valid())
306 			{
307 				paned->remove(*child);
308 				link.unlink();
309 				link.link(*child);
310 				delete paned;
311 			}
312 		}
313 		else
314 		{
315 			remove_widget_recursive(*paned);
316 			delete paned;
317 			return;
318 		}
319 	}
320 	else
321 	if (window)
322 	{
323 		if (!window->get_child())
324 			window->hide();
325 	}
326 	else
327 	if (book)
328 	{
329 		if (!book->allow_empty && book->get_n_pages() == 0)
330 		{
331 			remove_widget_recursive(*book);
332 			delete book;
333 		}
334 	}
335 }
336 
337 void
remove_widget_recursive(Gtk::Widget & widget)338 DockManager::remove_widget_recursive(Gtk::Widget &widget)
339 {
340 	Gtk::Container *container = widget.get_parent();
341 	if (container)
342 	{
343 		container->remove(widget);
344 		remove_empty_container_recursive(*container);
345 	}
346 }
347 
348 bool
add_widget(Gtk::Widget & dest_widget,Gtk::Widget & src_widget,bool vertical,bool first)349 DockManager::add_widget(Gtk::Widget &dest_widget, Gtk::Widget &src_widget, bool vertical, bool first)
350 {
351 	if (&src_widget == &dest_widget) return false;
352 
353 	// check for src widget is parent for dest_widget
354 	for(Gtk::Widget *parent = src_widget.get_parent(); parent != NULL; parent = parent->get_parent())
355 		if (parent == &dest_widget)
356 			return swap_widgets(src_widget, dest_widget);
357 
358 	// unlink dest_widget
359 	DockLinkPoint dest_link(dest_widget);
360 	if (!dest_link.is_valid()) return false;
361 	dest_link.unlink();
362 
363 	// unlink src_widget
364 	remove_widget_recursive(src_widget);
365 
366 	// create new paned and link all
367 	Gtk::Paned *paned = manage(vertical ? (Gtk::Paned*)new Gtk::VPaned() : (Gtk::Paned*)new Gtk::HPaned());
368 	paned->show();
369 	DockLinkPoint(paned, first).link(src_widget);
370 	DockLinkPoint(paned, !first).link(dest_widget);
371 	dest_link.link(*paned);
372 	return true;
373 }
374 
375 bool
add_dockable(Gtk::Widget & dest_widget,Dockable & dockable,bool vertical,bool first)376 DockManager::add_dockable(Gtk::Widget &dest_widget, Dockable &dockable, bool vertical, bool first)
377 {
378 	DockBook *book = manage(new DockBook());
379 	book->show();
380 	if (add_widget(dest_widget, *book, vertical, first))
381 	{
382 		book->add(dockable);
383 		return true;
384 	}
385 	delete book;
386 	return false;
387 }
388 
read_separator(std::string & x)389 bool DockManager::read_separator(std::string &x)
390 {
391 	size_t pos = x.find_first_of("|]");
392 	if (pos == std::string::npos) { x.clear(); return false; }
393 	if (x[pos] == '|') { x = x.substr(pos+1); return true; }
394 	if (x[pos] == ']') x = x.substr(pos+1);
395 	return false;
396 }
397 
read_string(std::string & x)398 std::string DockManager::read_string(std::string &x)
399 {
400 	size_t pos = x.find_first_of("|]");
401 	std::string res = x.substr(0, pos);
402 	if (pos == std::string::npos) x.clear(); else x = x.substr(pos);
403 	return res;
404 }
405 
read_int(std::string & x)406 int DockManager::read_int(std::string &x)
407 {
408 	return strtol(read_string(x).c_str(), NULL, 10);
409 }
410 
read_bool(std::string & x)411 bool DockManager::read_bool(std::string &x)
412 {
413 	return read_string(x) == "true";
414 }
415 
read_widget(std::string & x)416 Gtk::Widget* DockManager::read_widget(std::string &x)
417 {
418 	bool hor = x.substr(0, 5) == "[hor|";
419 	bool vert = x.substr(0, 6) == "[vert|";
420 
421 	// paned
422 	if (hor || vert)
423 	{
424 		// skip "[hor|" or "[vert|"
425 		x = x.substr(1);
426 		if (!read_separator(x)) return NULL;
427 
428 		int size = read_int(x);
429 		if (!read_separator(x)) return NULL;
430 
431 		Gtk::Widget *first = NULL;
432 		Gtk::Widget *second = NULL;
433 
434 		first = read_widget(x);
435 		if (!read_separator(x)) return first;
436 		second = read_widget(x);
437 		read_separator(x);
438 
439 		if (!first && !second) return NULL;
440 		if (first && !second) return first;
441 		if (!first && second) return second;
442 
443 		// create paned
444 		Gtk::Paned *paned = manage(hor ? (Gtk::Paned*)new Gtk::HPaned() : (Gtk::Paned*)new Gtk::VPaned());
445 		paned->pack1(*first,  true, false);
446 		paned->pack2(*second, true, false);
447 		paned->set_position(size);
448 		paned->show();
449 		return paned;
450 	}
451 	else
452 	if (x.substr(0, 6) == "[book|")
453 	{
454 		// skip "[book|"
455 		x = x.substr(1);
456 		if (!read_separator(x)) return NULL;
457 
458 		DockBook *book = NULL;
459 		do
460 		{
461 			std::string name = read_string(x);
462 			if (!name.empty())
463 			{
464 				Dockable *dockable = &find_dockable(name);
465 				if (dockable != NULL)
466 				{
467 					Gtk::Container *container = dockable->get_parent();
468 					if (container)
469 					{
470 						container->remove(*dockable);
471 						containers_to_remove_[container] = true;
472 					}
473 					if (book == NULL) { book = manage(new DockBook()); book->show(); }
474 					book->add(*dockable);
475 				}
476 			}
477 		} while (read_separator(x));
478 
479 		return book;
480 	}
481 	else
482 	if (x.substr(0, 8) == "[dialog|")
483 	{
484 		// skip "[dialog|"
485 		x = x.substr(1);
486 		if (!read_separator(x)) return NULL;
487 
488 		int left = read_int(x);
489 		if (!read_separator(x)) return NULL;
490 		int top = read_int(x);
491 		if (!read_separator(x)) return NULL;
492 		int width = read_int(x);
493 		if (!read_separator(x)) return NULL;
494 		int height = read_int(x);
495 		if (!read_separator(x)) return NULL;
496 
497 		Gtk::Widget *widget = read_widget(x);
498 		read_separator(x);
499 
500 		if (!widget) return NULL;
501 
502 		DockDialog *dialog = new DockDialog();
503 		dialog->add(*widget);
504 		dialog->move(left, top);
505 		dialog->set_default_size(width, height);
506 		dialog->resize(width, height);
507 		dialog->present();
508 
509 		return NULL;
510 	}
511 	else
512 	if (x.substr(0, 12) == "[mainwindow|")
513 	{
514 		// skip "[dialog|"
515 		x = x.substr(1);
516 		if (!read_separator(x)) return NULL;
517 
518 		int left = read_int(x);
519 		if (!read_separator(x)) return NULL;
520 		int top = read_int(x);
521 		if (!read_separator(x)) return NULL;
522 		int width = read_int(x);
523 		if (!read_separator(x)) return NULL;
524 		int height = read_int(x);
525 		if (!read_separator(x)) return NULL;
526 
527 		Gtk::Widget *widget = read_widget(x);
528 		read_separator(x);
529 
530 		if (!widget) return NULL;
531 
532 		Gtk::Widget *child = App::main_window->root().get_child();
533 		App::main_window->root().remove();
534 		if (child && child != &App::main_window->main_dock_book())
535 			delete child;
536 		App::main_window->root().add(*widget);
537 
538 		App::main_window->move(left, top);
539 		App::main_window->set_default_size(width, height);
540 		App::main_window->resize(width, height);
541 		App::main_window->present();
542 
543 		return NULL;
544 	}
545 	else
546 	if (x.substr(0, 14) == "[mainnotebook]")
547 	{
548 		x = x.substr(14);
549 		if (App::main_window->main_dock_book().get_parent())
550 			App::main_window->main_dock_book().get_parent()->remove(App::main_window->main_dock_book());
551 		return &App::main_window->main_dock_book();
552 	}
553 
554 	return NULL;
555 }
556 
write_string(std::string & x,const std::string & str)557 void DockManager::write_string(std::string &x, const std::string &str)
558 	{ x += str; }
write_separator(std::string & x,bool continue_)559 void DockManager::write_separator(std::string &x, bool continue_)
560 	{ write_string(x, continue_ ? "|" : "]"); }
write_int(std::string & x,int i)561 void DockManager::write_int(std::string &x, int i)
562 	{ write_string(x, strprintf("%d", i)); }
write_bool(std::string & x,bool b)563 void DockManager::write_bool(std::string &x, bool b)
564 	{ write_string(x, b ? "true" : "false"); }
565 
write_widget(std::string & x,Gtk::Widget * widget)566 void DockManager::write_widget(std::string &x, Gtk::Widget* widget)
567 {
568 	Gtk::Paned *paned = dynamic_cast<Gtk::Paned*>(widget);
569 	Gtk::HPaned *hpaned = dynamic_cast<Gtk::HPaned*>(widget);
570 	DockBook *book = dynamic_cast<DockBook*>(widget);
571 	DockDialog *dialog = dynamic_cast<DockDialog*>(widget);
572 
573 	if (widget == NULL)
574 	{
575 		return;
576 	}
577 	else
578 	if (widget == App::main_window)
579 	{
580 		write_string(x, "[mainwindow|");
581 		int left = 0, top = 0, width = 0, height = 0;
582 		App::main_window->get_position(left, top);
583 		App::main_window->get_size(width, height);
584 		write_int(x, left);
585 		write_separator(x);
586 		write_int(x, top);
587 		write_separator(x);
588 		write_int(x, width);
589 		write_separator(x);
590 		write_int(x, height);
591 		write_separator(x);
592 
593 		write_widget(x, App::main_window->root().get_child());
594 		write_separator(x, false);
595 	}
596 	else
597 	if (widget == &App::main_window->main_dock_book())
598 	{
599 		write_string(x, "[mainnotebook]");
600 	}
601 	else
602 	if (dialog)
603 	{
604 		write_string(x, "[dialog|");
605 		int left = 0, top = 0, width = 0, height = 0;
606 		dialog->get_position(left, top);
607 		dialog->get_size(width, height);
608 		write_int(x, left);
609 		write_separator(x);
610 		write_int(x, top);
611 		write_separator(x);
612 		write_int(x, width);
613 		write_separator(x);
614 		write_int(x, height);
615 		write_separator(x);
616 
617 		write_widget(x, dialog->get_child());
618 		write_separator(x, false);
619 	}
620 	else
621 	if (paned)
622 	{
623 		write_string(x, hpaned ? "[hor|" : "[vert|");
624 		write_int(x, paned->get_position());
625 		write_separator(x);
626 		write_widget(x, paned->get_child1());
627 		write_separator(x);
628 		write_widget(x, paned->get_child2());
629 		write_separator(x, false);
630 	}
631 	else
632 	if (book)
633 	{
634 		write_string(x, "[book");
635 		for(int i = 0; i < book->get_n_pages(); ++i)
636 		{
637 			Dockable *dockable = dynamic_cast<Dockable*>(book->get_nth_page(i));
638 			if (dockable)
639 			{
640 				write_separator(x);
641 				write_string(x, dockable->get_name());
642 			}
643 		}
644 		write_separator(x, false);
645 	}
646 }
647 
save_widget_to_string(Gtk::Widget * widget)648 std::string DockManager::save_widget_to_string(Gtk::Widget *widget)
649 {
650 	std::string res;
651 	write_widget(res, widget);
652 	return res;
653 }
654 
load_widget_from_string(const std::string & x)655 Gtk::Widget* DockManager::load_widget_from_string(const std::string &x)
656 {
657 	std::string copy(x);
658 	Gtk::Widget *widget = read_widget(copy);
659 	while (!containers_to_remove_.empty())
660 		remove_empty_container_recursive(*containers_to_remove_.begin()->first);
661 	return widget;
662 }
663 
save_layout_to_string()664 std::string DockManager::save_layout_to_string()
665 {
666 	std::string res;
667 	for(std::list<DockDialog*>::iterator i = dock_dialog_list_.begin(); i != dock_dialog_list_.end(); i++)
668 	{
669 		write_widget(res, *i);
670 		write_separator(res);
671 	}
672 	write_widget(res, App::main_window);
673 	return res;
674 }
675 
load_layout_from_string(const std::string & x)676 void DockManager::load_layout_from_string(const std::string &x)
677 {
678 	std::string copy(x);
679 	do
680 	{
681 		read_widget(copy);
682 	} while (read_separator(copy));
683 	while (!containers_to_remove_.empty())
684 		remove_empty_container_recursive(*containers_to_remove_.begin()->first);
685 }
686 
layout_from_template(const std::string & tpl,float dx,float dy,float sx,float sy)687 std::string DockManager::layout_from_template(const std::string &tpl, float dx, float dy, float sx, float sy)
688 {
689 	std::string res;
690 	size_t pos_begin;
691 	size_t pos_end = 0;
692 	while(true)
693 	{
694 		pos_begin = tpl.find_first_of("%", pos_end);
695 		if (pos_begin == std::string::npos)
696 			{ res+=tpl.substr(pos_end); break; }
697 		res+=tpl.substr(pos_end, pos_begin-pos_end);
698 		pos_end = tpl.find_first_of("xyXY", pos_begin);
699 		if (pos_end == std::string::npos) break;
700 		float f = (float)strtol(tpl.c_str()+pos_begin+1, NULL, 10);
701 		if (tpl[pos_end] == 'X') res += strprintf("%d", (int)roundf(dx+f*sx/100.f));
702 		if (tpl[pos_end] == 'Y') res += strprintf("%d", (int)roundf(dy+f*sy/100.f));
703 		if (tpl[pos_end] == 'x') res += strprintf("%d", (int)roundf(f*sx/100.f));
704 		if (tpl[pos_end] == 'y') res += strprintf("%d", (int)roundf(f*sy/100.f));
705 		pos_end++;
706 	}
707 	return res;
708 }
709 
710 
711 void
update_window_titles()712 DockManager::update_window_titles()
713 {
714 	// build maps
715 	typedef std::map< CanvasView::ActivationIndex, CanvasView* > CanvasViewMap;
716 	typedef std::map< Glib::RefPtr<Gdk::Window>, std::string > TitleMap;
717 	CanvasViewMap canvas_view_map;
718 	TitleMap title_map;
719 	for(std::list<Dockable*>::iterator i = dockable_list_.begin(); i != dockable_list_.end(); i++)
720 	{
721 		if ((*i)->get_parent_window())
722 		{
723 			title_map[(*i)->get_parent_window()] = (*i)->get_parent_window() == App::main_window->get_window()
724 			                                     ? _("Synfig Studio") : _("Dock Panel");
725 			CanvasView *canvas_view = dynamic_cast<CanvasView*>(*i);
726 			if (canvas_view)
727 				canvas_view_map[canvas_view->get_activation_index()] = canvas_view;
728 		}
729 	}
730 
731 	// prepare titles
732 	for(CanvasViewMap::iterator i = canvas_view_map.begin(); i != canvas_view_map.end(); i++)
733 		title_map[ i->second->get_parent_window() ] =
734 			i->second->get_local_name() + " - " + _("Synfig Studio");
735 
736 	// set titles
737 	for(TitleMap::iterator i = title_map.begin(); i != title_map.end(); i++)
738 		i->first->set_title(i->second);
739 }
740