/* === 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 <glibmm/main.h>
#include <synfig/general.h>
#include "trees/childrentreestore.h"
#include "iconcontroller.h"
#include <gtkmm/button.h>
#include <synfig/paramdesc.h>
#include <ETL/clock>
#include <gui/localization.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_pixbuf(Gtk::StockID("synfig-type_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());
}
}