X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Fsrc%2Fgtkmm%2Flayergrouptreestore.cpp;fp=synfig-studio%2Fsrc%2Fgtkmm%2Flayergrouptreestore.cpp;h=6334c0924ae218c9d7df52fdcb07e9f3be609d91;hb=a095981e18cc37a8ecc7cd237cc22b9c10329264;hp=0000000000000000000000000000000000000000;hpb=9459638ad6797b8139f1e9f0715c96076dbf0890;p=synfig.git diff --git a/synfig-studio/src/gtkmm/layergrouptreestore.cpp b/synfig-studio/src/gtkmm/layergrouptreestore.cpp new file mode 100644 index 0000000..6334c09 --- /dev/null +++ b/synfig-studio/src/gtkmm/layergrouptreestore.cpp @@ -0,0 +1,1030 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layergrouptreestore.cpp +** \brief Template File +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2008 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 +#endif + +#include "layergrouptreestore.h" +#include "iconcontroller.h" +#include +#include +#include +#include +#include "app.h" +#include "instance.h" +#include +#include "dockmanager.h" +#include "dockable.h" + +#include +#include +#include "general.h" + +#endif + +/* === U S I N G =========================================================== */ + +using namespace std; +using namespace etl; +using namespace synfig; +using namespace studio; + +/* === M A C R O S ========================================================= */ + +#define GROUP_NEST_CHAR '.' + +/* === 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 LayerGroupTreeStore::Model& ModelHack() +{ + static LayerGroupTreeStore::Model* model(0); + if(!model)model=new LayerGroupTreeStore::Model; + return *model; +} + +LayerGroupTreeStore::LayerGroupTreeStore(etl::loose_handle canvas_interface_): + Gtk::TreeStore (ModelHack()), + canvas_interface_ (canvas_interface_) +{ + layer_icon=Gtk::Button().render_icon(Gtk::StockID("synfig-layer"),Gtk::ICON_SIZE_SMALL_TOOLBAR); + group_icon=Gtk::Button().render_icon(Gtk::StockID("synfig-group"),Gtk::ICON_SIZE_SMALL_TOOLBAR); + + // Connect Signals to Terminals + canvas_interface()->signal_layer_status_changed().connect(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_layer_status_changed)); + canvas_interface()->signal_layer_new_description().connect(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_layer_new_description)); + + canvas_interface()->get_canvas()->signal_group_added().connect(sigc::hide_return(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_group_added))); + canvas_interface()->get_canvas()->signal_group_removed().connect(sigc::hide_return(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_group_removed))); + canvas_interface()->get_canvas()->signal_group_changed().connect(sigc::hide_return(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_group_changed))); + + canvas_interface()->get_canvas()->signal_group_pair_added().connect(sigc::hide_return(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_group_pair_added))); + canvas_interface()->get_canvas()->signal_group_pair_removed().connect(sigc::hide_return(sigc::mem_fun(*this,&studio::LayerGroupTreeStore::on_group_pair_removed))); + + rebuild(); +} + +LayerGroupTreeStore::~LayerGroupTreeStore() +{ + //clear(); + + if (getenv("SYNFIG_DEBUG_DESTRUCTORS")) + synfig::info("LayerGroupTreeStore::~LayerGroupTreeStore(): Deleted"); +} + +bool +LayerGroupTreeStore::search_func(const Glib::RefPtr&,int,const Glib::ustring& x,const TreeModel::iterator& iter) +{ + const Model model; + + Glib::ustring substr(x.uppercase()); + Glib::ustring label((*iter)[model.label]); + label=label.uppercase(); + + return label.find(substr)==Glib::ustring::npos; +} + + +Glib::RefPtr +LayerGroupTreeStore::create(etl::loose_handle canvas_interface_) +{ + return Glib::RefPtr(new LayerGroupTreeStore(canvas_interface_)); +} + +void +LayerGroupTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& iter, int column, Glib::ValueBase& value)const +{ + if(column==model.child_layers.index()) + { + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + if((bool)(*iter)[model.is_group]) + { + set layer_set(canvas_interface()->get_canvas()->get_layers_in_group((Glib::ustring)(*iter)[model.group_name])); + + x.set(LayerList(layer_set.begin(),layer_set.end())); + } + else if((bool)(*iter)[model.is_layer]) + { + LayerList layer_list; + layer_list.push_back((Layer::Handle)(*iter)[model.layer]); + x.set(layer_list); + } + + g_value_init(value.gobj(),x.value_type()); + value=x; + } + else if(column==model.all_layers.index()) + { + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + if((bool)(*iter)[model.is_group]) + { + LayerList layer_list; + Gtk::TreeModel::iterator child_iter(iter->children().begin()); + for(;child_iter;++child_iter) + { + LayerList layer_list2((LayerList)(*child_iter)[model.all_layers]); + for(;layer_list2.size();layer_list2.pop_front()) + layer_list.push_back(layer_list2.front()); + } + x.set(layer_list); + } + else if((bool)(*iter)[model.is_layer]) + { + LayerList layer_list; + layer_list.push_back((Layer::Handle)(*iter)[model.layer]); + x.set(layer_list); + } + + g_value_init(value.gobj(),x.value_type()); + value=x; + } + else if(column==model.group_name.index()) + { + if((bool)(*iter)[model.is_group]) + return Gtk::TreeStore::get_value_vfunc(iter,column,value); + return get_value_vfunc(iter->parent(),column,value); + } + else if(column==model.parent_group_name.index()) + { + if(iter->parent()) + return get_value_vfunc(iter->parent(),model.group_name.index(),value); + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + x.set(Glib::ustring()); + g_value_init(value.gobj(),x.value_type()); + value=x; + } + else if(column==model.label.index()) + { + if((bool)(*iter)[model.is_group]) + { + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + Glib::ustring group_name((*iter)[model.group_name]); + + // Get rid of any parent group crap + while(group_name.find(GROUP_NEST_CHAR)!=Glib::ustring::npos) + group_name=Glib::ustring(group_name,group_name.find(GROUP_NEST_CHAR)+1,Glib::ustring::npos); + + x.set(group_name); + + g_value_init(value.gobj(),x.value_type()); + + value=x; + } + else if((bool)(*iter)[model.is_layer]) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + + if(!layer)return; + + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + x.set(layer->get_non_empty_description()); + + g_value_init(value.gobj(),x.value_type()); + //g_value_copy(x.gobj(),value.gobj()); + value=x; + } + } + else + if(column==model.tooltip.index()) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + + if(!layer)return; + + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + + x.set(layer->get_local_name()); + + g_value_init(value.gobj(),x.value_type()); + //g_value_copy(x.gobj(),value.gobj()); + value=x; + } + else + if(column==model.canvas.index()) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + + if(!layer)return; + + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + + x.set(layer->get_canvas()); + + g_value_init(value.gobj(),x.value_type()); + //g_value_copy(x.gobj(),value.gobj()); + value=x; + } + else + if(column==model.active.index()) + { + Glib::Value x; + g_value_init(x.gobj(),x.value_type()); + + if((bool)(*iter)[model.is_layer]) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + x.set(layer->active()); + } + else if((bool)(*iter)[model.is_group]) + { + int activecount(0),total(0); + Gtk::TreeModel::iterator child_iter(iter->children().begin()); + for(;child_iter;++child_iter) + { + total++; + if((*child_iter)[model.active]) + activecount++; + } + x.set(activecount>total/2); + } + else + x.set(false); + + g_value_init(value.gobj(),x.value_type()); + g_value_copy(x.gobj(),value.gobj()); + } + else + if(column==model.icon.index()) + { + Glib::Value > x; + g_value_init(x.gobj(),x.value_type()); + + if((bool)(*iter)[model.is_layer]) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + if(!layer)return; + //x.set(layer_icon); + x.set(get_tree_pixbuf_layer(layer->get_name())); + } + if((bool)(*iter)[model.is_group]) + x.set(group_icon); + + g_value_init(value.gobj(),x.value_type()); + g_value_copy(x.gobj(),value.gobj()); + } + else + Gtk::TreeStore::get_value_vfunc(iter,column,value); +} + +void +LayerGroupTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value) +{ + //if(!iterator_sane(row)) + // return; + + if(column>=get_n_columns_vfunc()) + { + g_warning("LayerGroupTreeStore::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("LayerGroupTreeStore::set_value_impl: Bad value type"); + return; + } + + try + { + if(column==model.label.index()) + { + Glib::Value x; + g_value_init(x.gobj(),model.label.type()); + g_value_copy(value.gobj(),x.gobj()); + + if((bool)(*iter)[model.is_layer]) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + if(!layer) + return; + synfig::String new_desc(x.get()); + + if(new_desc==layer->get_local_name()) + new_desc=synfig::String(); + + if(new_desc==layer->get_description()) + return; + + synfigapp::Action::Handle action(synfigapp::Action::create("LayerSetDesc")); + + if(!action) + return; + + action->set_param("canvas",canvas_interface()->get_canvas()); + action->set_param("canvas_interface",canvas_interface()); + action->set_param("layer",layer); + action->set_param("new_description",synfig::String(x.get())); + + canvas_interface()->get_instance()->perform_action(action); + return; + } + else if((bool)(*iter)[model.is_group]) + { + synfig::String group((Glib::ustring)(*iter)[model.label]); + synfig::String new_group(x.get()); + + if(x.get()==group) + return; + + Glib::ustring group_name((*iter)[model.group_name]); + group=group_name; + new_group.clear(); + + // Get rid of any parent group crap + while(group_name.find(GROUP_NEST_CHAR)!=Glib::ustring::npos) + { + new_group+=Glib::ustring(group_name,0,group_name.find(GROUP_NEST_CHAR)+1); + group_name=Glib::ustring(group_name,group_name.find(GROUP_NEST_CHAR)+1,Glib::ustring::npos); + } + new_group+=x.get(); + + synfig::info("Renaming group \"%s\" to \"%s\"...",group.c_str(),new_group.c_str()); + + // Check to see if this group is real or not. + // If it isn't real, then renaming it is a cinch. + // We know it isn't real if it doesn't have any + // children yet. + if(iter->children().empty()) + { + (*iter)[model.group_name]=new_group; + } + else + { + synfigapp::Action::Handle action(synfigapp::Action::create("GroupRename")); + + if(!action) + return; + + action->set_param("canvas",canvas_interface()->get_canvas()); + action->set_param("canvas_interface",canvas_interface()); + action->set_param("group",group); + action->set_param("new_group",new_group); + + canvas_interface()->get_instance()->perform_action(action); + } + return; + } + return; + } + else + if(column==model.active.index()) + { + Glib::Value x; + g_value_init(x.gobj(),model.active.type()); + g_value_copy(value.gobj(),x.gobj()); + + if((bool)(*iter)[model.is_layer]) + { + synfig::Layer::Handle layer((*iter)[model.layer]); + if(!layer)return; + + synfigapp::Action::Handle action(synfigapp::Action::create("LayerActivate")); + + if(!action) + return; + + action->set_param("canvas",canvas_interface()->get_canvas()); + action->set_param("canvas_interface",canvas_interface()); + action->set_param("layer",layer); + action->set_param("new_status",bool(x.get())); + + + canvas_interface()->get_instance()->perform_action(action); + return; + } + else if(!iter->children().empty()) + { + synfigapp::Action::PassiveGrouper group( + get_canvas_interface()->get_instance().get(), + String( + x.get()?_("Activate "):_("Deactivate ") + )+(Glib::ustring)(*iter)[model.label] + ); + + Gtk::TreeModel::iterator child_iter(iter->children().begin()); + + for(;child_iter;++child_iter) + (*child_iter)[model.active]=x.get(); + + Gtk::TreeStore::set_value_impl(iter,column, value); + } + } + else + Gtk::TreeStore::set_value_impl(iter,column, value); + + } + catch(std::exception x) + { + g_warning("%s", x.what()); + } +} + + + + +bool +LayerGroupTreeStore::row_draggable_vfunc (const TreeModel::Path& /*path*/)const +{ + //if(!get_iter(path)) return false; +// Gtk::TreeModel::Row row(*get_iter(path)); + + return true; +// return (bool)true; +} + +bool +LayerGroupTreeStore::drag_data_get_vfunc (const TreeModel::Path& path, Gtk::SelectionData& selection_data)const +{ + if(!const_cast(this)->get_iter(path)) return false; + //synfig::info("Dragged data of type \"%s\"",selection_data.get_data_type()); + //synfig::info("Dragged data of target \"%s\"",gdk_atom_name(selection_data->target)); + //synfig::info("Dragged selection=\"%s\"",gdk_atom_name(selection_data->selection)); + + Gtk::TreeModel::Row row(*const_cast(this)->get_iter(path)); + + if((bool)row[model.is_layer]) + { + Layer* layer(((Layer::Handle)row[model.layer]).get()); + assert(layer); + + std::vector layers; + + layers.push_back(layer); + + selection_data.set("LAYER", 8, reinterpret_cast(&layers.front()), sizeof(void*)*layers.size()); + + return true; + } + else if((bool)row[model.is_group]) + { + synfig::String group((Glib::ustring)row[model.group_name]); + if(group.empty()) + return false; + + selection_data.set("GROUP", 8, reinterpret_cast(&*group.begin()), sizeof(void*)*group.size()); + + return true; + } + + return false; +} + +bool +LayerGroupTreeStore::drag_data_delete_vfunc (const TreeModel::Path& /*path*/) +{ + return true; +} + +bool +LayerGroupTreeStore::row_drop_possible_vfunc (const TreeModel::Path& dest, const Gtk::SelectionData& selection_data)const +{ + Gtk::TreeIter iter(const_cast(this)->get_iter(dest)); + if(!iter) return false; + + if(synfig::String(selection_data.get_data_type())=="LAYER") + return true; + + if(synfig::String(selection_data.get_data_type())=="GROUP") + { + synfig::String dest_group((Glib::ustring)(*iter)[model.group_name]); + synfig::String src_group(reinterpret_cast(selection_data.get_data())); + //synfig::String src_group(const_cast(selection_data.get_data())); + + // Avoid putting a group inside of itself + if(dest_group.size()>src_group.size() && src_group==String(dest_group,0,src_group.size())) + return false; + return true; + } + + return false; + //synfig::info("possible_drop -- data of type \"%s\"",selection_data.get_data_type()); + //synfig::info("possible_drop -- data of target \"%s\"",gdk_atom_name(selection_data->target)); + //synfig::info("possible_drop -- selection=\"%s\"",gdk_atom_name(selection_data->selection)); + + //Gtk::TreeModel::Row row(*get_iter(dest)); + +/* if(synfig::String(selection_data.get_data_type())=="LAYER" && (bool)true) + return true; +*/ + return false; +} + +bool +LayerGroupTreeStore::drag_data_received_vfunc (const TreeModel::Path& dest, const Gtk::SelectionData& selection_data) +{ + if(!get_iter(dest)) return false; +// bool ret=false; + //int i(0); + + Gtk::TreeModel::Row row(*get_iter(dest)); + + //synfig::info("Dropped data of type \"%s\"",selection_data.get_data_type()); + //synfig::info("Dropped data of target \"%s\"",gdk_atom_name(selection_data->target)); + //synfig::info("Dropped selection=\"%s\"",gdk_atom_name(selection_data->selection)); + synfigapp::Action::PassiveGrouper passive_grouper(canvas_interface()->get_instance().get(),_("Regroup")); + + if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8)) + { + synfig::String dest_group; + + dest_group=(Glib::ustring)row[model.group_name]; + + if(dest_group.empty()) + return false; + + if(synfig::String(selection_data.get_data_type())=="LAYER") + { + synfigapp::Action::Handle action(synfigapp::Action::create("GroupAddLayers")); + + if(!action) + return false; + + action->set_param("canvas",canvas_interface()->get_canvas()); + action->set_param("canvas_interface",canvas_interface()); + action->set_param("group",dest_group); + + for(unsigned int i=0;i(const_cast(selection_data.get_data()))[i]); + assert(layer); + + action->set_param("layer",layer); + } + if(!canvas_interface()->get_instance()->perform_action(action)) + { + passive_grouper.cancel(); + return false; + } + return true; + } + if(synfig::String(selection_data.get_data_type())=="GROUP") + { + synfig::String src_group(reinterpret_cast(selection_data.get_data())); + synfig::String group(src_group); + + // Get rid of any parent group crap + while(group.find(GROUP_NEST_CHAR)!=Glib::ustring::npos) + group=Glib::ustring(group,group.find(GROUP_NEST_CHAR)+1,Glib::ustring::npos); + + group=dest_group+GROUP_NEST_CHAR+group; + + synfigapp::Action::Handle action(synfigapp::Action::create("GroupRename")); + + if(!action) + return false; + + action->set_param("canvas",canvas_interface()->get_canvas()); + action->set_param("canvas_interface",canvas_interface()); + action->set_param("group",src_group); + action->set_param("new_group",group); + + if(!canvas_interface()->get_instance()->perform_action(action)) + { + passive_grouper.cancel(); + return false; + } + return true; + } + } +/* // Save the selection data + synfigapp::SelectionManager::LayerList selected_layer_list=canvas_interface()->get_selection_manager()->get_selected_layers(); + + if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8)) + { + Canvas::Handle dest_canvas; + Layer::Handle dest_layer; + + dest_canvas=(Canvas::Handle)(row[model.canvas]); + dest_layer=(Layer::Handle)(row[model.layer]); + assert(dest_canvas); + + if(!dest_layer) + return false; + + int dest_layer_depth=dest_layer->get_depth(); + + if(synfig::String(selection_data.get_data_type())=="LAYER")for(i=0;i(const_cast(selection_data.get_data()))[i]); + assert(src); + if(dest_layer==src) + continue; + + // In this case, we are just moving. +// if(dest_canvas==src->get_canvas()) + { + if(dest_canvas==src->get_canvas() && dest_layer_depth && dest_layer_depth>src->get_depth()) + dest_layer_depth--; + if(dest_canvas==src->get_canvas() && dest_layer_depth==src->get_depth()) + continue; + + synfigapp::Action::Handle action(synfigapp::Action::create("LayerMove")); + action->set_param("canvas",dest_canvas); + action->set_param("canvas_interface",canvas_interface()); + action->set_param("layer",src); + action->set_param("new_index",dest_layer_depth); + action->set_param("dest_canvas",dest_canvas); + if(canvas_interface()->get_instance()->perform_action(action)) + { + ret=true; + } + else + { + passive_grouper.cancel(); + return false; + } + continue; + } + } + } + synfig::info("I supposedly moved %d layers",i); + + // Reselect the previously selected layers + canvas_interface()->get_selection_manager()->set_selected_layers(selected_layer_list); + + return ret; + */ + return false; +} + + + + + + + +void +LayerGroupTreeStore::rebuild() +{ + rebuilding=true; + // etl::clock timer;timer.reset(); + try { + + // Clear out the current list + clear(); + Canvas::Handle canvas(canvas_interface()->get_canvas()); + std::set groups(canvas->get_groups()); + for(;groups.size();groups.erase(groups.begin())) + { + String group(*groups.begin()); + Gtk::TreeRow row(on_group_added(group)); + std::set layers(canvas->get_layers_in_group(group)); + + for(;layers.size();layers.erase(layers.begin())) + { + Gtk::TreeRow layer_row(*(prepend(row.children()))); + Layer::Handle layer(*layers.begin()); + set_row_layer(layer_row,layer); + } + } + + // Go ahead and add all the layers + /*std::for_each( + canvas_interface()->get_canvas()->rbegin(), canvas_interface()->get_canvas()->rend(), + sigc::mem_fun(*this, &studio::LayerGroupTreeStore::on_layer_added) + );*/ + } + catch(...) + { + rebuilding=false; + throw; + } + rebuilding=false; + // synfig::info("LayerGroupTreeStore::rebuild() took %f seconds",float(timer())); +} + +void +LayerGroupTreeStore::refresh() +{ + rebuild(); +} + +void +LayerGroupTreeStore::refresh_row(Gtk::TreeModel::Row &row) +{ + if((bool)row[model.is_layer]) + { + Layer::Handle layer=row[model.layer]; + + + //if(layer->dynamic_param_list().count("z_depth")) + // row[model.z_depth]=Time::begin(); + } + + Gtk::TreeModel::Children children = row.children(); + Gtk::TreeModel::Children::iterator iter; + + if(!children.empty()) + for(iter = children.begin(); iter && iter != children.end(); ++iter) + { + Gtk::TreeRow row=*iter; + refresh_row(row); + } +} + + +void +LayerGroupTreeStore::set_row_layer(Gtk::TreeRow &row,synfig::Layer::Handle &handle) +{ + row[model.is_layer] = true; + row[model.is_group] = false; + row[model.layer] = handle; +} + +Gtk::TreeRow +LayerGroupTreeStore::on_group_added(synfig::String group) +{ + // Check to see if this group perhaps already + // exists + { + Gtk::TreeModel::Children::iterator iter; + if(find_group_row(group, iter)) + return *iter; + } + + if(group.find(GROUP_NEST_CHAR)!=String::npos) + { + Gtk::TreeModel::Children::iterator iter; + String parent_name; + do + { + if(parent_name.size()) + parent_name+=GROUP_NEST_CHAR; + parent_name+=string(group,0,group.find(GROUP_NEST_CHAR)); + + if(!find_group_row(parent_name, iter)) + iter=on_group_added(parent_name); + + group=String(group,group.find(GROUP_NEST_CHAR)+1,String::npos); + }while(group.find(GROUP_NEST_CHAR)!=String::npos); + + if(parent_name.size()) + parent_name+=GROUP_NEST_CHAR; + parent_name+=group; + + if(iter) + { + Gtk::TreeRow row(*(prepend(iter->children()))); + row[model.group_name]=parent_name; + row[model.is_layer]=false; + row[model.is_group]=true; + on_activity(); + return row; + } + } + + Gtk::TreeRow row(*(append())); + row[model.group_name]=group; + row[model.is_layer]=false; + row[model.is_group]=true; + on_activity(); + return row; +} + +bool +LayerGroupTreeStore::on_group_removed(synfig::String group) +{ + Gtk::TreeModel::Children::iterator iter; + if(find_group_row(group,iter) && iter->children().size()==0) + erase(iter); + else + return false; + + return true; +} + +bool +LayerGroupTreeStore::on_group_changed(synfig::String /*group*/) +{ + return true; +} + +void +LayerGroupTreeStore::on_group_pair_added(synfig::String group, etl::handle layer) +{ + if(!layer->get_canvas()) + return; + Gtk::TreeModel::Children::iterator iter; + if(!find_group_row(group, iter)) + iter=on_group_added(group); + + Gtk::TreeRow layer_row(*(append(iter->children()))); + set_row_layer(layer_row,layer); + on_activity(); +} + +void +LayerGroupTreeStore::on_group_pair_removed(synfig::String group, etl::handle layer) +{ + if(!layer->get_canvas()) + return; + Gtk::TreeModel::Children::iterator iter; + if(!find_group_row(group, iter)) + return; + + Gtk::TreeModel::Children::iterator prev,layer_iter; + + if(!find_layer_row_(layer, layer->get_canvas(), iter->children(), layer_iter, prev)) + return; + + erase(layer_iter); + + on_activity(); +} + +void +LayerGroupTreeStore::on_activity() +{ + // If we aren't rebuilding and the last action + // had something to do with groups, then go + // a head and present the groups dialog. + if(!rebuilding && canvas_interface()->get_instance()->get_most_recent_action() && canvas_interface()->get_instance()->get_most_recent_action()->get_name().find("Group")!=String::npos) + try + { + App::dock_manager->find_dockable("groups").present(); + } + catch(...) { } +} + +void +LayerGroupTreeStore::on_layer_status_changed(synfig::Layer::Handle handle,bool /*x*/) +{ + Gtk::TreeModel::Children::iterator iter; + if(find_layer_row(handle,iter)) + (*iter)[model.layer]=handle; + else + { + synfig::warning("Couldn't find layer to be activated in layer list. Rebuilding index..."); + rebuild(); + } +} + + +void +LayerGroupTreeStore::on_layer_new_description(synfig::Layer::Handle handle,synfig::String desc) +{ + Gtk::TreeModel::Children::iterator iter; + if(find_layer_row(handle,iter)) + { + Gtk::TreeRow row(*iter); + + Layer::Handle layer(row[model.layer]); + + if(desc.empty()) + { + //row[model.label]=layer->get_local_name(); + row[model.tooltip]=Glib::ustring(_("Layer")); + } + else + //row[model.label]=layer->get_description(); + row[model.tooltip]=layer->get_local_name(); + } + else + { + rebuild(); + } +} + +bool +LayerGroupTreeStore::find_layer_row_(const synfig::Layer::Handle &layer, synfig::Canvas::Handle canvas, Gtk::TreeModel::Children layers, Gtk::TreeModel::Children::iterator &iter, Gtk::TreeModel::Children::iterator &prev) +{ + assert(layer); + + //if(layer->get_canvas()==canvas) + { + for(iter=prev=layers.begin(); iter && iter != layers.end(); prev=iter++) + { + Gtk::TreeModel::Row row = *iter; + if((bool)row[model.is_layer] && layer==(synfig::Layer::Handle)row[model.layer]) + return true; + } + + iter=children().end(); + //return false; + } + + Gtk::TreeModel::Children::iterator iter2; + + for(iter2 = layers.begin(); iter2 && iter2 != layers.end(); ++iter2) + { + Gtk::TreeModel::Row row = *iter2; + assert((bool)true); + + if(row.children().empty()) + continue; + + /*Canvas::Handle canvas((*row.children().begin())[model.canvas]); + if(!canvas) + continue; + */ + + if(find_layer_row_(layer,canvas,iter2->children(),iter,prev)) + return true; + } + + iter=children().end(); + return false; +} + +bool +LayerGroupTreeStore::find_layer_row(const synfig::Layer::Handle &layer, Gtk::TreeModel::Children::iterator &iter) +{ + Gtk::TreeModel::Children::iterator prev; + return find_layer_row_(layer,canvas_interface()->get_canvas(),children(),iter,prev); +} + +bool +LayerGroupTreeStore::find_group_row(const synfig::String &group, Gtk::TreeModel::Children::iterator &iter) +{ + Gtk::TreeModel::Children::iterator prev; + return find_group_row_(group,children(),iter,prev); +} + +bool +LayerGroupTreeStore::find_group_row_(const synfig::String &group, Gtk::TreeModel::Children layers, Gtk::TreeModel::Children::iterator &iter, Gtk::TreeModel::Children::iterator &prev) +{ + //if(layer->get_canvas()==canvas) + { + for(iter=prev=layers.begin(); iter && iter != layers.end(); prev=iter++) + { + Gtk::TreeModel::Row row = *iter; + if((bool)row[model.is_group] && group==(Glib::ustring)row[model.group_name]) + return true; + } + + iter=children().end(); + //return false; + } + + Gtk::TreeModel::Children::iterator iter2; + + for(iter2 = layers.begin(); iter2 && iter2 != layers.end(); ++iter2) + { + Gtk::TreeModel::Row row = *iter2; + assert((bool)true); + + if(row.children().empty()) + continue; + + if(find_group_row_(group,iter2->children(),iter,prev)) + return true; + } + + iter=children().end(); + return false; +} + +bool +LayerGroupTreeStore::find_prev_layer_row(const synfig::Layer::Handle &layer, Gtk::TreeModel::Children::iterator &prev) +{ + Gtk::TreeModel::Children::iterator iter; + if(!find_layer_row_(layer,canvas_interface()->get_canvas(),children(),iter,prev)) + return false; + if(iter==children().begin()) + return false; + return true; +}