1 /* === S Y N F I G ========================================================= */
2 /*!	\file keyframetreestore.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 **	Copyright (c) 2012-2013 Konstantin Dmitriev
11 **
12 **	This package is free software; you can redistribute it and/or
13 **	modify it under the terms of the GNU General Public License as
14 **	published by the Free Software Foundation; either version 2 of
15 **	the License, or (at your option) any later version.
16 **
17 **	This package is distributed in the hope that it will be useful,
18 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 **	General Public License for more details.
21 **	\endlegal
22 */
23 /* ========================================================================= */
24 
25 /* === H E A D E R S ======================================================= */
26 
27 #ifdef USING_PCH
28 #	include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #	include <config.h>
32 #endif
33 
34 #include <synfig/general.h>
35 
36 #include "trees/keyframetreestore.h"
37 #include <synfig/valuenode.h>
38 #include "iconcontroller.h"
39 #include <synfig/valuenodes/valuenode_timedswap.h>
40 #include <gtkmm/button.h>
41 #include <gtkmm/treerowreference.h>
42 #include <synfig/canvas.h>
43 #include <synfig/keyframe.h>
44 #include <time.h>
45 #include <cstdlib>
46 #include <ETL/smart_ptr>
47 #include <synfigapp/action.h>
48 #include <synfigapp/instance.h>
49 #include "onemoment.h"
50 #include <synfig/exception.h>
51 
52 #include <gui/localization.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 /* === G L O B A L S ======================================================= */
66 
67 // KeyframeTreeStore_Class KeyframeTreeStore::keyframe_tree_store_class_;
68 
69 /* === C L A S S E S & S T R U C T S ======================================= */
70 
71 struct _keyframe_iterator
72 {
73 	synfig::KeyframeList::iterator iter;
74 	int ref_count;
75 	int index;
76 };
77 
78 /*
79 Gtk::TreeModel::iterator keyframe_iter_2_model_iter(synfig::KeyframeList::iterator iter,int index)
80 {
81 	Gtk::TreeModel::iterator ret;
82 
83 	_keyframe_iterator*& data(static_cast<_keyframe_iterator*&>(ret->gobj()->user_data));
84 	data=new _keyframe_iterator();
85 	data->ref_count=1;
86 	data->iter=iter;
87 	data->index=index;
88 
89 	return ret;
90 }
91 */
92 
model_iter_2_keyframe_iter(Gtk::TreeModel::iterator iter)93 synfig::KeyframeList::iterator model_iter_2_keyframe_iter(Gtk::TreeModel::iterator iter)
94 {
95 	_keyframe_iterator* data(static_cast<_keyframe_iterator*>(iter->gobj()->user_data));
96 	if(!data)
97 		throw std::runtime_error("bad data");
98 	return data->iter;
99 }
100 
get_index_from_model_iter(Gtk::TreeModel::iterator iter)101 int get_index_from_model_iter(Gtk::TreeModel::iterator iter)
102 {
103 	_keyframe_iterator* data(static_cast<_keyframe_iterator*>(iter->gobj()->user_data));
104 	if(!data)
105 		throw std::runtime_error("bad data");
106 	return data->index;
107 }
108 
109 
110 /*
111 #ifndef TreeRowReferenceHack
112 class TreeRowReferenceHack
113 {
114 	GtkTreeRowReference *gobject_;
115 public:
116 	TreeRowReferenceHack():
117 		gobject_(0)
118 	{
119 	}
120 
121 	TreeRowReferenceHack(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path):
122 		gobject_ ( gtk_tree_row_reference_new(model->gobj(), const_cast<GtkTreePath*>(path.gobj())) )
123 	{
124 	}
125 
126 	TreeRowReferenceHack(const TreeRowReferenceHack &x):
127 		gobject_ ( x.gobject_?gtk_tree_row_reference_copy(x.gobject_):0 )
128 	{
129 
130 	}
131 
132 	void swap(TreeRowReferenceHack & other)
133 	{
134 		GtkTreeRowReference *const temp = gobject_;
135 		gobject_ = other.gobject_;
136 		other.gobject_ = temp;
137 	}
138 
139 	const TreeRowReferenceHack &
140 	operator=(const TreeRowReferenceHack &rhs)
141 	{
142 		TreeRowReferenceHack temp (rhs);
143   		swap(temp);
144 		return *this;
145 	}
146 
147 	~TreeRowReferenceHack()
148 	{
149 		if(gobject_)
150 			gtk_tree_row_reference_free(gobject_);
151 	}
152 
153 	Gtk::TreeModel::Path get_path() { return Gtk::TreeModel::Path(gtk_tree_row_reference_get_path(gobject_),false); }
154 	GtkTreeRowReference *gobj() { return gobject_; }
155 };
156 #endif
157 */
158 
159 /* === P R O C E D U R E S ================================================= */
160 
clear_iterator(GtkTreeIter * iter)161 void clear_iterator(GtkTreeIter* iter)
162 {
163 	iter->stamp=0;
164 	iter->user_data=iter->user_data2=iter->user_data3=0;
165 }
166 
167 /* === M E T H O D S ======================================================= */
168 
169 
KeyframeTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)170 KeyframeTreeStore::KeyframeTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
171 	Glib::ObjectBase	("KeyframeTreeStore"),
172 	//! \todo what is going on here?  why the need for this KeyframeTreeStore_Class at all?
173 	// Glib::Object		(Glib::ConstructParams(keyframe_tree_store_class_.init(), (char*) 0, (char*) 0)),
174 	canvas_interface_	(canvas_interface_)
175 {
176 	reset_stamp();
177 	//reset_path_table();
178 
179 	//connect some events
180 	canvas_interface()->signal_keyframe_added().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::add_keyframe));
181 	canvas_interface()->signal_keyframe_removed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::remove_keyframe));
182 	canvas_interface()->signal_keyframe_changed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::change_keyframe));
183 	//canvas_interface()->signal_keyframe_selected().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::select_keyframe));
184 }
185 
~KeyframeTreeStore()186 KeyframeTreeStore::~KeyframeTreeStore()
187 {
188 	if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
189 		synfig::info("KeyframeTreeStore::~KeyframeTreeStore(): Deleted");
190 }
191 
192 Glib::RefPtr<KeyframeTreeStore>
create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)193 KeyframeTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
194 {
195 	KeyframeTreeStore *store(new KeyframeTreeStore(canvas_interface_));
196 	Glib::RefPtr<KeyframeTreeStore> ret(store);
197 	assert(ret);
198 	return ret;
199 }
200 
201 void
reset_stamp()202 KeyframeTreeStore::reset_stamp()
203 {
204 	stamp_=time(0)+reinterpret_cast<intptr_t>(this);
205 }
206 
207 /*
208 void
209 KeyframeTreeStore::reset_path_table()
210 {
211 	Gtk::TreeModel::Children::iterator iter;
212 	const Gtk::TreeModel::Children children(children());
213 	path_table_.clear();
214 	for(iter = children.begin(); iter != children.end(); ++iter)
215 	{
216 		Gtk::TreeModel::Row row(*iter);
217 		path_table_[(Keyframe)row[model.keyframe]]=TreeRowReferenceHack(Glib::RefPtr<KeyframeTreeStore>(this),Gtk::TreePath(row));
218 	}
219 }
220 */
221 
222 
223 inline bool
iterator_sane(const GtkTreeIter * iter) const224 KeyframeTreeStore::iterator_sane(const GtkTreeIter* iter)const
225 {
226 	if(iter && iter->stamp==stamp_)
227 		return true;
228 	g_warning("KeyframeTreeStore::iterator_sane(): Bad iterator stamp");
229 	return false;
230 }
231 
232 inline bool
iterator_sane(const Gtk::TreeModel::iterator & iter) const233 KeyframeTreeStore::iterator_sane(const Gtk::TreeModel::iterator& iter)const
234 {
235 	return iterator_sane(iter->gobj());
236 }
237 
238 inline void
dump_iterator(const GtkTreeIter *,const Glib::ustring &) const239 KeyframeTreeStore::dump_iterator(const GtkTreeIter* /*gtk_iter*/, const Glib::ustring &/*name*/)const
240 {
241 #if 0
242 	if(!gtk_iter)
243 	{
244 		g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is NULL (Root?)",name.c_str());
245 		return;
246 	}
247 
248 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
249 
250 	if(gtk_iter->stamp!=stamp_ || !iter)
251 	{
252 		g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is INVALID",name.c_str());
253 		return;
254 	}
255 
256 	if((unsigned)iter->index>=canvas_interface()->get_canvas()->keyframe_list().size())
257 		g_warning("KeyframeTreeStore::dump_iterator: \"%s\"(%p) has bad index(index:%d)",name.c_str(),gtk_iter,iter->index);
258 
259 	g_warning("KeyframeTreeStore::dump_iterator: \"%s\"(%p) ref:%d, index:%d, time:%s",name.c_str(),gtk_iter,iter->ref_count,iter->index,iter->iter->get_time().get_string().c_str());
260 #endif
261 }
262 
263 inline void
dump_iterator(const Gtk::TreeModel::iterator & iter,const Glib::ustring & name) const264 KeyframeTreeStore::dump_iterator(const Gtk::TreeModel::iterator& iter, const Glib::ustring &name)const
265 {
266 	dump_iterator(iter->gobj(),name);
267 }
268 
269 int
time_sorter(const Gtk::TreeModel::iterator & rhs,const Gtk::TreeModel::iterator & lhs)270 KeyframeTreeStore::time_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
271 {
272 	const Model model;
273 
274 	_keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
275 	_keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
276 
277 	Time diff(rhs_iter->iter->get_time()-lhs_iter->iter->get_time());
278 	if(diff<0)
279 		return -1;
280 	if(diff>0)
281 		return 1;
282 	return 0;
283 }
284 
285 int
description_sorter(const Gtk::TreeModel::iterator & rhs,const Gtk::TreeModel::iterator & lhs)286 KeyframeTreeStore::description_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
287 {
288 	const Model model;
289 
290 	_keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
291 	_keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
292 
293 	int comp = rhs_iter->iter->get_description().compare(lhs_iter->iter->get_description());
294 	if (comp > 0) return 1;
295 	if (comp < 0) return -1;
296 	return 0;
297 }
298 
299 void
set_value_impl(const Gtk::TreeModel::iterator & row,int column,const Glib::ValueBase & value)300 KeyframeTreeStore::set_value_impl(const Gtk::TreeModel::iterator& row, int column, const Glib::ValueBase& value)
301 {
302 	if(!iterator_sane(row))
303 		return;
304 
305 	if(column>=get_n_columns_vfunc())
306 	{
307 		g_warning("KeyframeTreeStore::set_value_impl: Bad column (%d)",column);
308 		return;
309 	}
310 
311 	if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
312 	{
313 		g_warning("KeyframeTreeStore::set_value_impl: Bad value type");
314 		return;
315 	}
316 
317 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(row.gobj()->user_data));
318 
319 	try
320 	{
321 		if(column==model.time_delta.index())
322 		{
323 			Glib::Value<synfig::Time> x;
324 			g_value_init(x.gobj(),model.time.type());
325 			g_value_copy(value.gobj(),x.gobj());
326 
327 			Time new_delta(x.get());
328 			if(new_delta<=Time::zero()+Time::epsilon())
329 			{
330 				// Bad value
331 				return;
332 			}
333 
334 			Time old_delta((*row)[model.time_delta]);
335 			if(old_delta<=Time::zero()+Time::epsilon())
336 			{
337 				// Bad old delta
338 				return;
339 			}
340 			// row(row) on the next line is bad - don't use it, because it leaves 'row' uninitialized
341 			//Gtk::TreeModel::iterator row(row);
342 			//row++;
343 			//if(!row)return;
344 
345 			Time change_delta(new_delta-old_delta);
346 
347 			if(change_delta<=Time::zero()+Time::epsilon() &&change_delta>=Time::zero()-Time::epsilon())
348 			{
349 				// Not an error, just no change
350 				return;
351 			}
352 
353 			{
354 				Keyframe keyframe((*row)[model.keyframe]);
355 				synfigapp::Action::Handle action(synfigapp::Action::create("KeyframeSetDelta"));
356 
357 				if(!action)return;
358 
359 				action->set_param("canvas",canvas_interface()->get_canvas());
360 				action->set_param("canvas_interface",canvas_interface());
361 				action->set_param("keyframe",keyframe);
362 				action->set_param("delta",change_delta);
363 
364 				canvas_interface()->get_instance()->perform_action(action);
365 			}
366 
367 			return;
368 		}
369 		else
370 		if(column==model.time.index())
371 		{
372 			OneMoment one_moment;
373 
374 			Glib::Value<synfig::Time> x;
375 			g_value_init(x.gobj(),model.time.type());
376 			g_value_copy(value.gobj(),x.gobj());
377 			synfig::Keyframe keyframe(*iter->iter);
378 
379 			synfig::info("KeyframeTreeStore::set_value_impl():old_time=%s",keyframe.get_time().get_string().c_str());
380 			keyframe.set_time(x.get());
381 			synfig::info("KeyframeTreeStore::set_value_impl():new_time=%s",keyframe.get_time().get_string().c_str());
382 
383 			synfigapp::Action::Handle action(synfigapp::Action::create("KeyframeSet"));
384 
385 			if(!action)
386 				return;
387 
388 			action->set_param("canvas",canvas_interface()->get_canvas());
389 			action->set_param("canvas_interface",canvas_interface());
390 			action->set_param("keyframe",keyframe);
391 
392 			canvas_interface()->get_instance()->perform_action(action);
393 		}
394 		else if(column==model.description.index())
395 		{
396 			Glib::Value<Glib::ustring> x;
397 			g_value_init(x.gobj(),model.description.type());
398 			g_value_copy(value.gobj(),x.gobj());
399 			synfig::Keyframe keyframe(*iter->iter);
400 			keyframe.set_description(x.get());
401 
402 			synfigapp::Action::Handle action(synfigapp::Action::create("KeyframeSet"));
403 
404 			if(!action)
405 				return;
406 
407 			action->set_param("canvas",canvas_interface()->get_canvas());
408 			action->set_param("canvas_interface",canvas_interface());
409 			action->set_param("keyframe",keyframe);
410 
411 			canvas_interface()->get_instance()->perform_action(action);
412 		}
413 		else if(column==model.active.index())
414 		{
415 
416 			synfig::Keyframe keyframe((*row)[model.keyframe]);
417 
418 			Glib::Value<bool> x;
419 			g_value_init(x.gobj(),model.active.type());
420 			g_value_copy(value.gobj(),x.gobj());
421 
422 			synfigapp::Action::Handle action(synfigapp::Action::create("KeyframeToggl"));
423 
424 			if(!action)
425 				return;
426 			action->set_param("canvas",canvas_interface()->get_canvas());
427 			action->set_param("canvas_interface",canvas_interface());
428 			action->set_param("keyframe",keyframe);
429 			action->set_param("new_status",bool(x.get()));
430 
431 			canvas_interface()->get_instance()->perform_action(action);
432 		}
433 		else if(column==model.keyframe.index())
434 		{
435 			g_warning("KeyframeTreeStore::set_value_impl: This column is read-only");
436 		}
437 		else
438 		{
439 			assert(0);
440 		}
441 	}
442 	catch(std::exception x)
443 	{
444 		g_warning("%s", x.what());
445 	}
446 }
447 
448 Gtk::TreeModelFlags
get_flags_vfunc()449 KeyframeTreeStore::get_flags_vfunc ()
450 {
451 	return Gtk::TREE_MODEL_LIST_ONLY;
452 }
453 
454 int
get_n_columns_vfunc()455 KeyframeTreeStore::get_n_columns_vfunc ()
456 {
457 	return model.size();
458 }
459 
460 GType
get_column_type_vfunc(int index)461 KeyframeTreeStore::get_column_type_vfunc (int index)
462 {
463 	return model.types()[index];
464 }
465 
466 bool
iter_next_vfunc(const iterator & xiter,iterator & iter_next) const467 KeyframeTreeStore::iter_next_vfunc (const iterator& xiter, iterator& iter_next) const
468 {
469 	if(!iterator_sane(xiter)) return false;
470 
471 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(xiter.gobj()->user_data));
472 
473 	if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
474 		return false;
475 
476 	_keyframe_iterator *next(new _keyframe_iterator());
477 	iter_next.gobj()->user_data=static_cast<gpointer>(next);
478 	next->ref_count=1;
479 	next->index=iter->index+1;
480 	next->iter=iter->iter;
481 	++next->iter;
482 
483 	if(next->iter==canvas_interface()->get_canvas()->keyframe_list().end())
484 		return false;
485 
486 	iter_next.gobj()->stamp=stamp_;
487 
488 	return true;
489 }
490 
491 /*
492 bool
493 KeyframeTreeStore::iter_next_vfunc (GtkTreeIter* gtk_iter)
494 {
495 	if(!iterator_sane(gtk_iter)) return false;
496 
497 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
498 
499 	// If we are already at the end, then we are very invalid
500 	if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
501 		return false;
502 
503 	++(iter->iter);
504 
505 	if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
506 	{
507 		--(iter->iter);
508 		return false;
509 	}
510 	(iter->index)++;
511 	return true;
512 }
513 
514 bool
515 KeyframeTreeStore::iter_children_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent)
516 {
517 	dump_iterator(gtk_iter,"gtk_iter");
518 	dump_iterator(parent,"parent");
519 
520 	if(!parent || !iterator_sane(parent))
521 	{
522 		clear_iterator(gtk_iter);
523 		return false;
524 	}
525 
526 	_keyframe_iterator *iter(new _keyframe_iterator());
527 	iter->ref_count=1;
528 	iter->index=0;
529 	iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
530 
531 	gtk_iter->user_data=static_cast<gpointer>(iter);
532 	gtk_iter->stamp=stamp_;
533 
534 	return true;
535 }
536 
537 bool
538 KeyframeTreeStore::iter_has_child_vfunc (const GtkTreeIter*parent)
539 {
540 	dump_iterator(parent,"parent");
541 
542 	if(parent)
543 		return false;
544 
545 	return true;
546 }
547 
548 int
549 KeyframeTreeStore::iter_n_children_vfunc (const GtkTreeIter* parent)
550 {
551 	dump_iterator(parent,"parent");
552 
553 	if(parent)
554 		return 0;
555 
556 	return canvas_interface()->get_canvas()->keyframe_list().size();
557 }
558 */
559 
560 int
iter_n_root_children_vfunc() const561 KeyframeTreeStore::iter_n_root_children_vfunc () const
562 {
563 	return canvas_interface()->get_canvas()->keyframe_list().size();
564 }
565 
566 bool
iter_nth_root_child_vfunc(int n,iterator & xiter) const567 KeyframeTreeStore::iter_nth_root_child_vfunc (int n, iterator& xiter)const
568 {
569 	if(canvas_interface()->get_canvas()->keyframe_list().size()==0)
570 	{
571 		return false;
572 	}
573 
574 	if(n<0)
575 	{
576 		g_warning("KeyframeTreeStore::iter_nth_root_child_vfunc: Out of range (negative index)");
577 		return false;
578 	}
579 	if(n && (unsigned)n>=canvas_interface()->get_canvas()->keyframe_list().size())
580 	{
581 		g_warning("KeyframeTreeStore::iter_nth_child_vfunc: Out of range (large index)");
582 		return false;
583 	}
584 
585 	_keyframe_iterator *iter(new _keyframe_iterator());
586 	iter->ref_count=1;
587 	iter->index=n;
588 	iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
589 	while(n--)
590 	{
591 		if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
592 		{
593 			g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
594 			delete iter;
595 			return false;
596 		}
597 		++iter->iter;
598 	}
599 	xiter.gobj()->user_data=static_cast<gpointer>(iter);
600 	xiter.gobj()->stamp=stamp_;
601 	return true;
602 }
603 
604 /*
605 bool
606 KeyframeTreeStore::iter_nth_child_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent, int n)
607 {
608 	dump_iterator(parent,"parent");
609 
610 	if(parent)
611 	{
612 		g_warning("KeyframeTreeStore::iter_nth_child_vfunc: I am a list");
613 		clear_iterator(gtk_iter);
614 		return false;
615 	}
616 
617 
618 
619 	_keyframe_iterator *iter(new _keyframe_iterator());
620 	iter->ref_count=1;
621 	iter->index=n;
622 	iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
623 	while(n--)
624 	{
625 		if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
626 		{
627 			g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
628 			delete iter;
629 			clear_iterator(gtk_iter);
630 			return false;
631 		}
632 		++iter->iter;
633 	}
634 
635 	gtk_iter->user_data=static_cast<gpointer>(iter);
636 	gtk_iter->stamp=stamp_;
637 	return true;
638 }
639 
640 bool
641 KeyframeTreeStore::iter_parent_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* child)
642 {
643 	dump_iterator(child,"child");
644 	iterator_sane(child);
645 	clear_iterator(gtk_iter);
646 	return false;
647 }
648 */
649 
650 void
ref_node_vfunc(iterator & xiter) const651 KeyframeTreeStore::ref_node_vfunc (iterator& xiter)const
652 {
653 	GtkTreeIter* gtk_iter(xiter.gobj());
654 	if(!gtk_iter || !iterator_sane(gtk_iter)) return;
655 
656 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
657 	iter->ref_count++;
658 }
659 
660 void
unref_node_vfunc(iterator & xiter) const661 KeyframeTreeStore::unref_node_vfunc (iterator& xiter)const
662 {
663 	GtkTreeIter* gtk_iter(xiter.gobj());
664 	if(!gtk_iter || !iterator_sane(gtk_iter)) return;
665 
666 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
667 	iter->ref_count--;
668 	if(!iter->ref_count)
669 	{
670 		delete iter;
671 
672 		// Make this iterator invalid
673 		gtk_iter->stamp=0;
674 	}
675 }
676 
677 Gtk::TreeModel::Path
get_path_vfunc(const iterator & gtk_iter) const678 KeyframeTreeStore::get_path_vfunc (const iterator& gtk_iter)const
679 {
680 	Gtk::TreeModel::Path path;
681 
682 	// If this is the root node, then return
683 	// a root path
684 	if(!iterator_sane(gtk_iter))
685 		return path;
686 
687 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
688 
689 	path.push_back(iter->index);
690 
691 	return path;
692 }
693 
694 bool
get_iter_vfunc(const Gtk::TreeModel::Path & path,iterator & iter) const695 KeyframeTreeStore::get_iter_vfunc (const Gtk::TreeModel::Path& path, iterator& iter)const
696 {
697 	if(path.size()>=1)
698 		return iter_nth_root_child_vfunc(path.front(),iter);
699 
700 	// Error case
701 	g_warning("KeyframeTreeStore::get_iter_vfunc(): Bad path \"%s\"",path.to_string().c_str());
702 	//clear_iterator(iter);
703 	return false;
704 }
705 
706 bool
iter_is_valid(const iterator & iter) const707 KeyframeTreeStore::iter_is_valid (const iterator& iter) const
708 {
709 	return iterator_sane(iter);
710 }
711 
712 void
get_value_vfunc(const Gtk::TreeModel::iterator & gtk_iter,int column,Glib::ValueBase & value) const713 KeyframeTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& gtk_iter, int column, Glib::ValueBase& value)const
714 {
715 	dump_iterator(gtk_iter,"gtk_iter");
716 	if(!iterator_sane(gtk_iter))
717 		return;
718 
719 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
720 
721 	switch(column)
722 	{
723 	case 0:		// Time
724 	{
725 		Glib::Value<synfig::Time> x;
726 		g_value_init(x.gobj(),x.value_type());
727 		x.set(iter->iter->get_time());
728 		g_value_init(value.gobj(),x.value_type());
729 		g_value_copy(x.gobj(),value.gobj());
730 		return;
731 	}
732 	case 3:		// Time Delta
733 	{
734 		Glib::Value<synfig::Time> x;
735 		g_value_init(x.gobj(),x.value_type());
736 
737 		synfig::Keyframe prev_keyframe(*iter->iter);
738 		synfig::Keyframe keyframe;
739 		{
740 			KeyframeList::iterator tmp(iter->iter);
741 			tmp++;
742 			if(tmp==get_canvas()->keyframe_list().end())
743 			{
744 				x.set(Time(0));
745 				g_value_init(value.gobj(),x.value_type());
746 				g_value_copy(x.gobj(),value.gobj());
747 				return;
748 			}
749 			keyframe=*tmp;
750 		}
751 
752 		Time delta(0);
753 		try {
754 			delta=keyframe.get_time()-prev_keyframe.get_time();
755 		}catch(...) { }
756 		x.set(delta);
757 		g_value_init(value.gobj(),x.value_type());
758 		g_value_copy(x.gobj(),value.gobj());
759 		return;
760 	}
761 	case 1:		// Description
762 	{
763 		g_value_init(value.gobj(),G_TYPE_STRING);
764 		g_value_set_string(value.gobj(),iter->iter->get_description().c_str());
765 		return;
766 	}
767 	case 2:		// Keyframe
768 	{
769 		Glib::Value<synfig::Keyframe> x;
770 		g_value_init(x.gobj(),x.value_type());
771 		x.set(*iter->iter);
772 		g_value_init(value.gobj(),x.value_type());
773 		g_value_copy(x.gobj(),value.gobj());
774 		return;
775 	}
776 	case 4:		// Active
777 	{
778 		Glib::Value<bool> x;
779 		g_value_init(x.gobj(),x.value_type());
780 
781 		x.set(iter->iter->active());
782 
783 		g_value_init(value.gobj(),x.value_type());
784 		g_value_copy(x.gobj(),value.gobj());
785 	}
786 	default:
787 		break;
788 	}
789 }
790 
791 Gtk::TreeModel::Row
find_row(const synfig::Keyframe & keyframe)792 KeyframeTreeStore::find_row(const synfig::Keyframe &keyframe)
793 {
794 	Gtk::TreeModel::Row row(*(children().begin()));
795 	dump_iterator(row,"find_row,begin");
796 	const GtkTreeIter *gtk_iter(row.gobj());
797 	if(!iterator_sane(gtk_iter))
798 		throw std::runtime_error(_("Unable to find Keyframe in table"));
799 
800 	_keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
801 
802 	synfig::KeyframeList &keyframe_list(canvas_interface()->get_canvas()->keyframe_list());
803 	if(keyframe_list.empty())
804 		throw std::runtime_error(_("There are no keyframes in this canvas"));
805 
806 	iter->index=0;
807 
808 	for(iter->iter=keyframe_list.begin();iter->iter!=keyframe_list.end() && *iter->iter!=keyframe;++iter->iter)
809 	{
810 		iter->index++;
811 	}
812 	if(iter->iter==keyframe_list.end())
813 		throw std::runtime_error(_("Unable to find Keyframe in table"));
814 	return row;
815 }
816 
817 bool
find_keyframe_path(const synfig::Keyframe & keyframe,Gtk::TreeModel::Path & path)818 KeyframeTreeStore::find_keyframe_path(const synfig::Keyframe &keyframe, Gtk::TreeModel::Path &path)
819 {
820 	assert(keyframe);
821 	Gtk::TreeRow row(find_row(keyframe));
822 	path = get_path(row);
823 
824 	return true;
825 }
826 
827 void
add_keyframe(synfig::Keyframe keyframe)828 KeyframeTreeStore::add_keyframe(synfig::Keyframe keyframe)
829 {
830 	try
831 	{
832 		Gtk::TreeRow row(find_row(keyframe));
833 		dump_iterator(row.gobj(),"add_keyframe,row");
834 		Gtk::TreePath path(get_path(row));
835 
836 		row_inserted(path,row);
837 
838 		old_keyframe_list=get_canvas()->keyframe_list();
839 		//old_keyframe_list.add(keyframe);
840 		//old_keyframe_list.sort();
841 	}
842 	catch(std::exception x)
843 	{
844 		g_warning("%s", x.what());
845 	}
846 
847 	// inform that something change around time to update the canvasview time widget color
848 	canvas_interface()->signal_time_changed()();
849 }
850 
851 void
remove_keyframe(synfig::Keyframe keyframe)852 KeyframeTreeStore::remove_keyframe(synfig::Keyframe keyframe)
853 {
854 	try
855 	{
856 		if(1)
857 		{
858 			// Hack: (begin) the keyframe should exist in keyframe_list,
859 			//     otherwise find_row() function will fail.
860 			//     Example: try removing keyframe from composition with only 1 kf
861 			// Note: To avoid the hack the KeyframeTreeStore probably should be re-implemented as ListStore --KD
862 			canvas_interface()->get_canvas()->keyframe_list().add(keyframe);
863 
864 			Gtk::TreeRow row(find_row(keyframe));
865 			dump_iterator(row,"remove_keyframe,row");
866 			Gtk::TreePath path(get_path(row));
867 			row_deleted(path);
868 
869 			// Hack: (end) remove added keyframe
870 			canvas_interface()->get_canvas()->keyframe_list().erase(keyframe);
871 
872 			old_keyframe_list.erase(keyframe);
873 		}
874 		else
875 		{
876 			g_warning("KeyframeTreeStore::remove_keyframe: Keyframe not in table");
877 		}
878 	}
879 	catch(std::exception x)
880 	{
881 		g_warning("%s", x.what());
882 	}
883 
884 	// inform that something change around time to update the canvasview time widget color
885 	canvas_interface()->signal_time_changed()();
886 }
887 
888 void
change_keyframe(synfig::Keyframe keyframe)889 KeyframeTreeStore::change_keyframe(synfig::Keyframe keyframe)
890 {
891 	try
892 	{
893 		Gtk::TreeRow row(find_row(keyframe));
894 
895 		unsigned int new_index(get_index_from_model_iter(row));
896 		unsigned int old_index(0);
897 		synfig::KeyframeList::iterator iter;
898 		for(old_index=0,iter=old_keyframe_list.begin();iter!=old_keyframe_list.end() && (UniqueID)*iter!=(UniqueID)keyframe;++iter,old_index++)
899 			;
900 
901 		if(iter!=old_keyframe_list.end() && new_index!=old_index)
902 		{
903 			std::vector<int> new_order;
904 			for(unsigned int i=0;i<old_keyframe_list.size();i++)
905 			{
906 				new_order.push_back(i);
907 			}
908 			if(new_order.size()>new_index)
909 			{
910 				new_order.erase(new_order.begin()+new_index);
911 				new_order.insert(new_order.begin()+old_index,new_index);
912 
913 				//new_order[old_index]=
914 
915 				rows_reordered (Path(), iterator(), &new_order[0]);
916 			}
917 
918 		}
919 
920 		old_keyframe_list=get_canvas()->keyframe_list();
921 
922 		row=find_row(keyframe);
923 
924 		dump_iterator(row,"change_keyframe,row");
925 		row_changed(get_path(row),row);
926 
927 		// If exist, previous row should be updated too (length value)
928 		try
929 		{
930 			if (new_index != 0)
931 			{
932 				synfig::Keyframe keyframe_prev = *(get_canvas()->keyframe_list().find_prev(keyframe.get_time(),false));
933 				Gtk::TreeRow row_prev(find_row(keyframe_prev));
934 				dump_iterator(row_prev,"change_keyframe,row_prev");
935 				row_changed(get_path(row_prev),row_prev);
936 			}
937 		}
938 
939 		catch(Exception::NotFound x)
940 		{
941 			g_warning("%s", x.what());
942 		}
943 	}
944 	catch(std::exception x)
945 	{
946 		g_warning("%s", x.what());
947 	}
948 
949 	// inform that something change around time to update the canvasview time widget color
950 	canvas_interface()->signal_time_changed()();
951 }
952