Remove ancient trunk folder from svn repository
[synfig.git] / synfig-studio / src / gtkmm / childrentreestore.cpp
diff --git a/synfig-studio/src/gtkmm/childrentreestore.cpp b/synfig-studio/src/gtkmm/childrentreestore.cpp
new file mode 100644 (file)
index 0000000..cf8798f
--- /dev/null
@@ -0,0 +1,389 @@
+/* === S Y N F I G ========================================================= */
+/*!    \file childrentreestore.cpp
+**     \brief Template File
+**
+**     $Id$
+**
+**     \legal
+**     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007 Chris Moore
+**
+**     This package is free software; you can redistribute it and/or
+**     modify it under the terms of the GNU General Public License as
+**     published by the Free Software Foundation; either version 2 of
+**     the License, or (at your option) any later version.
+**
+**     This package is distributed in the hope that it will be useful,
+**     but WITHOUT ANY WARRANTY; without even the implied warranty of
+**     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+**     General Public License for more details.
+**     \endlegal
+*/
+/* ========================================================================= */
+
+/* === H E A D E R S ======================================================= */
+
+#ifdef USING_PCH
+#      include "pch.h"
+#else
+#ifdef HAVE_CONFIG_H
+#      include <config.h>
+#endif
+
+#include "childrentreestore.h"
+#include "iconcontroller.h"
+#include <gtkmm/button.h>
+#include <synfig/paramdesc.h>
+#include <ETL/clock>
+
+#include "general.h"
+
+class Profiler : private etl::clock
+{
+       const std::string name;
+public:
+       Profiler(const std::string& name):name(name) { reset(); }
+       ~Profiler() { float time(operator()()); synfig::info("%s: took %f msec",name.c_str(),time*1000); }
+};
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+using namespace etl;
+using namespace synfig;
+using namespace studio;
+
+/* === M A C R O S ========================================================= */
+
+/* === G L O B A L S ======================================================= */
+
+/* === P R O C E D U R E S ================================================= */
+
+/* === M E T H O D S ======================================================= */
+
+static ChildrenTreeStore::Model& ModelHack()
+{
+       static ChildrenTreeStore::Model* model(0);
+       if(!model)model=new ChildrenTreeStore::Model;
+       return *model;
+}
+
+ChildrenTreeStore::ChildrenTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
+       Gtk::TreeStore                  (ModelHack()),
+       CanvasTreeStore                 (canvas_interface_)
+{
+       canvas_row=*append();
+       canvas_row[model.label]=_("Canvases");
+       canvas_row[model.is_canvas] = false;
+       canvas_row[model.is_value_node] = false;
+
+       value_node_row=*append();
+       value_node_row[model.label]=_("ValueBase Nodes");
+       value_node_row[model.is_canvas] = false;
+       value_node_row[model.is_value_node] = false;
+
+       // Connect all the signals
+       canvas_interface()->signal_value_node_changed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_changed));
+       canvas_interface()->signal_value_node_renamed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_renamed));
+       canvas_interface()->signal_value_node_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_added));
+       canvas_interface()->signal_value_node_deleted().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_deleted));
+       canvas_interface()->signal_value_node_replaced().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_replaced));
+       canvas_interface()->signal_canvas_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_added));
+       canvas_interface()->signal_canvas_removed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_removed));
+
+       rebuild();
+}
+
+ChildrenTreeStore::~ChildrenTreeStore()
+{
+}
+
+Glib::RefPtr<ChildrenTreeStore>
+ChildrenTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
+{
+       return Glib::RefPtr<ChildrenTreeStore>(new ChildrenTreeStore(canvas_interface_));
+}
+
+void
+ChildrenTreeStore::rebuild()
+{
+       // Profiler profiler("ChildrenTreeStore::rebuild()");
+       rebuild_value_nodes();
+       rebuild_canvases();
+}
+
+void
+ChildrenTreeStore::refresh()
+{
+       // Profiler profiler("ChildrenTreeStore::refresh()");
+       refresh_value_nodes();
+       refresh_canvases();
+}
+
+void
+ChildrenTreeStore::rebuild_value_nodes()
+{
+       Gtk::TreeModel::Children children(value_node_row.children());
+
+       while(!children.empty())erase(children.begin());
+
+       clear_changed_queue();
+
+       std::for_each(
+               canvas_interface()->get_canvas()->value_node_list().rbegin(), canvas_interface()->get_canvas()->value_node_list().rend(),
+               sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_value_node_added)
+       );
+}
+
+void
+ChildrenTreeStore::refresh_value_nodes()
+{
+       Gtk::TreeModel::Children children(value_node_row.children());
+
+       Gtk::TreeModel::Children::iterator iter;
+
+       if(!children.empty())
+               for(iter = children.begin(); iter != children.end(); ++iter)
+               {
+                       Gtk::TreeRow row=*iter;
+                       refresh_row(row);
+               }
+}
+
+void
+ChildrenTreeStore::rebuild_canvases()
+{
+       Gtk::TreeModel::Children children(canvas_row.children());
+
+       while(!children.empty())erase(children.begin());
+
+       std::for_each(
+               canvas_interface()->get_canvas()->children().rbegin(), canvas_interface()->get_canvas()->children().rend(),
+               sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_canvas_added)
+       );
+}
+
+void
+ChildrenTreeStore::refresh_canvases()
+{
+       rebuild_canvases();
+}
+
+void
+ChildrenTreeStore::refresh_row(Gtk::TreeModel::Row &row, bool /*do_children*/)
+{
+       CanvasTreeStore::refresh_row(row,false);
+
+       if((bool)row[model.is_value_node])
+       {
+               changed_set_.erase(row[model.value_node]);
+       }
+
+}
+
+void
+ChildrenTreeStore::on_canvas_added(synfig::Canvas::Handle canvas)
+{
+       Gtk::TreeRow row = *(prepend(canvas_row.children()));
+
+       row[model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
+       row[model.id] = canvas->get_id();
+       row[model.name] = canvas->get_name();
+
+       if(!canvas->get_id().empty())
+               row[model.label] = canvas->get_id();
+       else
+       if(!canvas->get_name().empty())
+               row[model.label] = canvas->get_name();
+       else
+               row[model.label] = _("[Unnamed]");
+
+       row[model.canvas] = canvas;
+       row[model.type] = _("Canvas");
+       //row[model.is_canvas] = true;
+       //row[model.is_value_node] = false;
+}
+
+void
+ChildrenTreeStore::on_canvas_removed(synfig::Canvas::Handle /*canvas*/)
+{
+       rebuild_canvases();
+}
+
+void
+ChildrenTreeStore::on_value_node_added(synfig::ValueNode::Handle value_node)
+{
+//     if(value_node->get_id().find("Unnamed")!=String::npos)
+//             return;
+
+       Gtk::TreeRow row = *prepend(value_node_row.children());
+
+       set_row(row,synfigapp::ValueDesc(canvas_interface()->get_canvas(),value_node->get_id()),false);
+}
+
+void
+ChildrenTreeStore::on_value_node_deleted(synfig::ValueNode::Handle value_node)
+{
+       Gtk::TreeIter iter;
+       //int i(0);
+
+       if(find_first_value_node(value_node,iter))
+       {
+               erase(iter);
+       }
+       //rebuild_value_nodes();
+}
+
+bool
+ChildrenTreeStore::execute_changed_value_nodes()
+{
+       // Profiler profiler("ChildrenTreeStore::execute_changed_value_nodes()");
+       if(!replaced_set_.empty())
+               rebuild_value_nodes();
+
+       etl::clock timer;
+       timer.reset();
+
+       while(!changed_set_.empty())
+       {
+               ValueNode::Handle value_node(*changed_set_.begin());
+               changed_set_.erase(value_node);
+
+               Gtk::TreeIter iter;
+
+               try
+               {
+                       Gtk::TreeIter iter;
+                       int i(0);
+
+                       if(!value_node->is_exported() && find_first_value_node(value_node,iter))
+                       {
+                               rebuild_value_nodes();
+                               continue;
+                       }
+
+                       if(value_node->is_exported() && find_first_value_node(value_node,iter)) do
+                       {
+                               Gtk::TreeRow row(*iter);
+                               i++;
+                               refresh_row(row);
+                       }while(find_next_value_node(value_node,iter));
+
+                       if(!i)
+                       {
+                               refresh_value_nodes();
+                               return false;
+                       }
+
+               }
+               catch(...)
+               {
+                       rebuild_value_nodes();
+                       return false;
+               }
+
+               // If we are taking too long...
+               if(timer()>4)
+               {
+                       refresh_value_nodes();
+                       return false;
+               }
+       }
+
+       return false;
+}
+
+void
+ChildrenTreeStore::on_value_node_changed(synfig::ValueNode::Handle value_node)
+{
+
+       if(!value_node->is_exported())
+               return;
+       changed_connection.disconnect();
+//     if(!execute_changed_queued())
+//             changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
+       changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
+
+       changed_set_.insert(value_node);
+       /*
+       try
+       {
+               Gtk::TreeIter iter;
+               int i(0);
+               while(find_next_value_node(value_node,iter))
+               {
+                       Gtk::TreeRow row(*iter);
+                       i++;
+                       refresh_row(row);
+               }
+               if(!i)
+               {
+                       refresh_value_nodes();
+               }
+       }
+       catch(...)
+       {
+               rebuild_value_nodes();
+       }
+       */
+}
+
+void
+ChildrenTreeStore::on_value_node_renamed(synfig::ValueNode::Handle value_node __attribute__ ((unused)))
+{
+       rebuild_value_nodes();
+}
+
+void
+ChildrenTreeStore::on_value_node_replaced(synfig::ValueNode::Handle replaced_value_node,synfig::ValueNode::Handle /*new_value_node*/)
+{
+       changed_connection.disconnect();
+       //if(!execute_changed_queued())
+//             changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
+               changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
+
+       replaced_set_.insert(replaced_value_node);
+}
+
+void
+ChildrenTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
+{
+       if(column>=get_n_columns_vfunc())
+       {
+               g_warning("LayerTreeStore::set_value_impl: Bad column (%d)",column);
+               return;
+       }
+
+       if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
+       {
+               g_warning("LayerTreeStore::set_value_impl: Bad value type");
+               return;
+       }
+
+       try
+       {
+               if(column==model.value.index())
+               {
+                       Glib::Value<synfig::ValueBase> x;
+                       g_value_init(x.gobj(),model.value.type());
+                       g_value_copy(value.gobj(),x.gobj());
+
+                       synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
+                       if(value_desc)
+                       {
+                               canvas_interface()->change_value(value_desc,x.get());
+                               row_changed(get_path(*iter),*iter);
+                       }
+
+                       return;
+               }
+               else
+                       CanvasTreeStore::set_value_impl(iter,column, value);
+       }
+       catch(std::exception x)
+       {
+               g_warning("%s", x.what());
+       }
+}