2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "treemodel.h"
23 #include "globaldefs.h"
25 #include "debugging/debugging.h"
29 #include <uilib/uilib.h>
31 #include "iscenegraph.h"
34 #include "generic/callback.h"
36 #include "string/string.h"
37 #include "generic/reference.h"
39 inline Nameable* Node_getNameable( scene::Node& node ){
40 return NodeTypeCast<Nameable>::cast( node );
45 #include "gtkutil/gtktreestore.h"
47 template<typename value_type>
48 inline void gtk_tree_model_get_pointer( ui::TreeModel model, GtkTreeIter* iter, gint column, value_type** pointer ){
49 GValue value = GValue_default();
50 gtk_tree_model_get_value( model, iter, column, &value );
51 *pointer = (value_type*)g_value_get_pointer( &value );
55 typedef GtkTreeStore GraphTreeModel;
57 ui::TreeStore graph_tree_model_new( graph_type* graph ){
58 return gtk_tree_store_new( 2, G_TYPE_POINTER, G_TYPE_POINTER );
61 void graph_tree_model_delete( GraphTreeModel* model ){
62 g_object_unref( G_OBJECT( model ) );
66 bool graph_tree_model_subtree_find_node( GraphTreeModel* model, GtkTreeIter* parent, const scene::Node& node, GtkTreeIter* iter ){
67 for ( gboolean success = gtk_tree_model_iter_children( model, iter, parent );
69 success = gtk_tree_model_iter_next( model, iter ) )
72 gtk_tree_model_get_pointer( model, iter, 0, ¤t );
73 if ( current == node ) {
80 typedef GtkTreeIter DoubleGtkTreeIter[2];
82 bool graph_tree_model_find_top( GraphTreeModel* model, const scene::Path& path, GtkTreeIter& iter ){
84 GtkTreeIter* parent_pointer = NULL;
86 for ( scene::Path::const_iterator i = path.begin(); i != path.end(); ++i )
88 if ( !graph_tree_model_subtree_find_node( model, parent_pointer, *i, &iter ) ) {
92 parent_pointer = &parent;
97 bool graph_tree_model_find_parent( GraphTreeModel* model, const scene::Path& path, GtkTreeIter& iter ){
99 GtkTreeIter* parent_pointer = NULL;
100 ASSERT_MESSAGE( path.size() > 1, "path too short" );
101 for ( scene::Path::const_iterator i = path.begin(); i != path.end() - 1; ++i )
104 if ( !graph_tree_model_subtree_find_node( model, parent_pointer, *i, &child ) ) {
108 parent_pointer = &iter;
113 void node_attach_name_changed_callback( scene::Node& node, const Callback<void()>& callback ){
115 Nameable* nameable = Node_getNameable( node );
116 if ( nameable != 0 ) {
117 nameable->attach( callback );
121 void node_detach_name_changed_callback( scene::Node& node, const Callback<void()>& callback ){
123 Nameable* nameable = Node_getNameable( node );
124 if ( nameable != 0 ) {
125 nameable->detach( callback );
130 GraphTreeModel* scene_graph_get_tree_model(); // temp hack
132 void graph_tree_model_row_changed( const scene::Instance& instance ){
133 GraphTreeModel* model = scene_graph_get_tree_model();
136 ASSERT_MESSAGE( graph_tree_model_find_top( model, instance.path(), child ), "RUNTIME ERROR" );
138 gtk_tree_store_set( GTK_TREE_STORE( model ), &child, 0, instance.path().top(), -1 );
141 void graph_tree_model_row_inserted( GraphTreeModel* model, const scene::Instance& instance ){
143 GtkTreeIter* parent_pointer = NULL;
144 if ( instance.path().size() != 1 ) {
145 ASSERT_MESSAGE( graph_tree_model_find_parent( model, instance.path(), parent ), "RUNTIME ERROR" );
146 parent_pointer = &parent;
149 gpointer node = instance.path().top();
150 gconstpointer selectable = Instance_getSelectable( instance );
153 gtk_tree_store_append( GTK_TREE_STORE( model ), &child, parent_pointer );
154 gtk_tree_store_set( GTK_TREE_STORE( model ), &child, 0, node, 1, selectable, -1 );
156 node_attach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(), graph_tree_model_row_changed>( instance ) );
159 void graph_tree_model_row_deleted( GraphTreeModel* model, const scene::Instance& instance ){
161 ASSERT_MESSAGE( graph_tree_model_find_top( model, instance.path(), child ), "RUNTIME ERROR" );
163 node_detach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(), graph_tree_model_row_changed>( instance ) );
165 gtk_tree_store_remove( GTK_TREE_STORE( model ), &child );
170 const char* node_get_name( scene::Node& node );
172 typedef scene::Node* NodePointer;
177 bool operator()( const NodePointer& self, const NodePointer& other ) const {
184 int result = string_compare( node_get_name( self ), node_get_name( other ) );
195 bool operator()( const PathConstReference& self, const PathConstReference& other ) const {
196 return std::lexicographical_compare( self.get().begin(), self.get().end(), other.get().begin(), other.get().end(), NodeNameLess() );
200 typedef std::map<PathConstReference, scene::Instance*, PathNameLess> graph_type;
202 struct GraphTreeModel
209 struct GraphTreeModelClass
211 GObjectClass parent_class;
214 #define GRAPH_TREE_MODEL( p ) ( reinterpret_cast<GraphTreeModel*>( p ) )
216 static GtkTreeModelFlags graph_tree_model_get_flags( GtkTreeModel* tree_model ){
217 return GTK_TREE_MODEL_ITERS_PERSIST;
220 static gint graph_tree_model_get_n_columns( ui::TreeModel tree_model ){
221 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
222 GraphTreeModel* graph_tree_model = (GraphTreeModel*) tree_model;
227 static const gint c_stamp = 0xabcdef;
229 inline graph_type::iterator graph_iterator_read_tree_iter( GtkTreeIter* iter ){
230 ASSERT_MESSAGE( iter != 0, "tree model error" );
231 ASSERT_MESSAGE( iter->user_data != 0, "tree model error" );
232 ASSERT_MESSAGE( iter->stamp == c_stamp, "tree model error" );
233 return *reinterpret_cast<graph_type::iterator*>( &iter->user_data );
236 inline void graph_iterator_write_tree_iter( graph_type::iterator i, GtkTreeIter* iter ){
237 ASSERT_MESSAGE( iter != 0, "tree model error" );
238 iter->stamp = c_stamp;
239 *reinterpret_cast<graph_type::iterator*>( &iter->user_data ) = i;
240 ASSERT_MESSAGE( iter->user_data != 0, "tree model error" );
243 static GType graph_tree_model_get_column_type( ui::TreeModel tree_model, gint index ){
244 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
245 GraphTreeModel *graph_tree_model = (GraphTreeModel *) tree_model;
247 return G_TYPE_POINTER;
250 static gboolean graph_tree_model_get_iter( ui::TreeModel tree_model, GtkTreeIter* iter, ui::TreePath path ){
251 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
252 gint* indices = gtk_tree_path_get_indices( path );
253 gint depth = gtk_tree_path_get_depth( path );
255 g_return_val_if_fail( depth > 0, FALSE );
257 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
259 if ( graph.empty() ) {
264 GtkTreeIter* parent = 0;
266 for ( gint i = 0; i < depth; i++ )
268 if ( !gtk_tree_model_iter_nth_child( tree_model, iter, parent, indices[i] ) ) {
278 static ui::TreePath graph_tree_model_get_path( ui::TreeModel tree_model, GtkTreeIter* iter ){
279 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
280 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
281 graph_type::iterator i = graph_iterator_read_tree_iter( iter );
283 auto path = ui::TreePath();
285 for ( std::size_t depth = ( *i ).first.get().size(); depth != 0; --depth )
287 std::size_t index = 0;
289 while ( i != graph.begin() && ( *i ).first.get().size() >= depth )
292 if ( ( *i ).first.get().size() == depth ) {
297 gtk_tree_path_prepend_index( path, index );
304 static void graph_tree_model_get_value( ui::TreeModel tree_model, GtkTreeIter *iter, gint column, GValue *value ){
305 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
306 ASSERT_MESSAGE( column == 0 || column == 1, "tree model error" );
308 graph_type::iterator i = graph_iterator_read_tree_iter( iter );
310 g_value_init( value, G_TYPE_POINTER );
313 g_value_set_pointer( value, reinterpret_cast<gpointer>( ( *i ).first.get().top() ) );
316 g_value_set_pointer( value, reinterpret_cast<gpointer>( Instance_getSelectable( *( *i ).second ) ) );
320 static gboolean graph_tree_model_iter_next( ui::TreeModel tree_model, GtkTreeIter *iter ){
321 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
322 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
323 graph_type::iterator i = graph_iterator_read_tree_iter( iter );
324 std::size_t depth = ( *i ).first.get().size();
328 while ( i != graph.end() && ( *i ).first.get().size() > depth )
333 if ( i == graph.end() || ( *i ).first.get().size() != depth ) {
337 graph_iterator_write_tree_iter( i, iter );
342 static gboolean graph_tree_model_iter_children( ui::TreeModel tree_model, GtkTreeIter *iter, GtkTreeIter *parent ){
343 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
344 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
345 graph_type::iterator i = ( parent == 0 ) ? graph.begin() : graph_iterator_read_tree_iter( parent );
346 std::size_t depth = ( parent == 0 ) ? 1 : ( *i ).first.get().size() + 1;
352 if ( i != graph.end() && ( *i ).first.get().size() == depth ) {
353 graph_iterator_write_tree_iter( i, iter );
360 static gboolean graph_tree_model_iter_has_child( ui::TreeModel tree_model, GtkTreeIter *iter ){
361 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
362 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
363 graph_type::iterator i = graph_iterator_read_tree_iter( iter );
364 std::size_t depth = ( *i ).first.get().size() + 1;
366 return ++i != graph.end() && ( *i ).first.get().size() == depth;
369 static gint graph_tree_model_iter_n_children( ui::TreeModel tree_model, GtkTreeIter *parent ){
370 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
371 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
372 graph_type::iterator i = ( parent == 0 ) ? graph.begin() : graph_iterator_read_tree_iter( parent );
373 std::size_t depth = ( parent == 0 ) ? 1 : ( *i ).first.get().size() + 1;
380 while ( i != graph.end() && ( *i ).first.get().size() >= depth )
389 static gboolean graph_tree_model_iter_nth_child( ui::TreeModel tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n ){
390 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
391 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
392 graph_type::iterator i = ( parent == 0 ) ? graph.begin() : graph_iterator_read_tree_iter( parent );
393 std::size_t depth = ( parent == 0 ) ? 1 : ( *i ).first.get().size() + 1;
399 while ( i != graph.end() && ( *i ).first.get().size() >= depth )
401 if ( ( *i ).first.get().size() == depth && n-- == 0 ) {
402 graph_iterator_write_tree_iter( i, iter );
411 static gboolean graph_tree_model_iter_parent( ui::TreeModel tree_model, GtkTreeIter *iter, GtkTreeIter *child ){
412 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
413 graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
414 graph_type::iterator i = graph_iterator_read_tree_iter( child );
415 std::size_t depth = ( *i ).first.get().size();
425 while ( ( *i ).first.get().size() >= depth );
426 graph_iterator_write_tree_iter( i, iter );
431 static GObjectClass *g_parent_class = 0;
433 static void graph_tree_model_init( GraphTreeModel *graph_tree_model ){
434 graph_tree_model->graph = 0;
437 static void graph_tree_model_finalize( GObject* object ){
438 GraphTreeModel* graph_tree_model = GRAPH_TREE_MODEL( object );
441 ( *g_parent_class->finalize )( object );
444 static void graph_tree_model_class_init( GraphTreeModelClass *class_ ){
445 GObjectClass *object_class;
447 g_parent_class = (GObjectClass*)g_type_class_peek_parent( class_ );
448 object_class = (GObjectClass *) class_;
450 object_class->finalize = graph_tree_model_finalize;
453 static void graph_tree_model_tree_model_init( GtkTreeModelIface *iface ){
454 iface->get_flags = graph_tree_model_get_flags;
455 iface->get_n_columns = graph_tree_model_get_n_columns;
456 iface->get_column_type = graph_tree_model_get_column_type;
457 iface->get_iter = graph_tree_model_get_iter;
458 iface->get_path = graph_tree_model_get_path;
459 iface->get_value = graph_tree_model_get_value;
460 iface->iter_next = graph_tree_model_iter_next;
461 iface->iter_children = graph_tree_model_iter_children;
462 iface->iter_has_child = graph_tree_model_iter_has_child;
463 iface->iter_n_children = graph_tree_model_iter_n_children;
464 iface->iter_nth_child = graph_tree_model_iter_nth_child;
465 iface->iter_parent = graph_tree_model_iter_parent;
468 static gboolean graph_tree_model_row_draggable( GtkTreeDragSource *drag_source, ui::TreePath path ){
470 gint depth = gtk_tree_path_get_depth( path );
472 return gtk_tree_path_get_depth( path ) > 1;
475 static gboolean graph_tree_model_drag_data_delete( GtkTreeDragSource *drag_source, ui::TreePath path ){
478 if ( gtk_tree_model_get_iter( drag_source, &iter, path ) ) {
479 graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
480 Path_deleteTop( ( *i ).first );
489 static gboolean graph_tree_model_drag_data_get( GtkTreeDragSource *drag_source, ui::TreePath path, GtkSelectionData *selection_data ){
490 if ( gtk_tree_set_row_drag_data( selection_data, drag_source, path ) ) {
495 /* FIXME handle text targets at least. */
501 static void graph_tree_model_drag_source_init( GtkTreeDragSourceIface *iface ){
502 iface->row_draggable = graph_tree_model_row_draggable;
503 iface->drag_data_delete = graph_tree_model_drag_data_delete;
504 iface->drag_data_get = graph_tree_model_drag_data_get;
507 static gboolean graph_tree_model_drag_data_received( GtkTreeDragDest *drag_dest, ui::TreePath dest, GtkSelectionData *selection_data ){
508 auto tree_model = drag_dest;
510 GtkTreeModel *src_model = 0;
511 GtkTreePath *src_path = 0;
512 if ( gtk_tree_get_row_drag_data( selection_data, &src_model, &src_path )
513 && src_model == tree_model ) {
514 /* Copy the given row to a new position */
517 if ( gtk_tree_model_get_iter( src_model, &iter, src_path ) ) {
523 /* FIXME maybe add some data targets eventually, or handle text
524 * targets in the simple case.
531 static gboolean graph_tree_model_row_drop_possible( GtkTreeDragDest *drag_dest, ui::TreePath dest_path, GtkSelectionData *selection_data ){
532 gboolean retval = FALSE;
534 GtkTreeModel *src_model = 0;
535 GtkTreePath *src_path = 0;
536 if ( gtk_tree_get_row_drag_data( selection_data, &src_model, &src_path ) != FALSE ) {
537 /* can only drag to ourselves */
538 if ( src_model == drag_dest ) {
539 /* Can't drop into ourself. */
540 if ( !gtk_tree_path_is_ancestor( src_path, dest_path ) ) {
541 /* Can't drop if dest_path's parent doesn't exist */
542 if ( gtk_tree_path_get_depth( dest_path ) > 1 ) {
543 auto tmp = gtk_tree_path_copy( dest_path );
544 gtk_tree_path_up( tmp );
547 retval = gtk_tree_model_get_iter( drag_dest, &iter, tmp );
549 gtk_tree_path_free( tmp );
554 gtk_tree_path_free( src_path );
560 static void graph_tree_model_drag_dest_init( GtkTreeDragDestIface *iface ){
561 iface->drag_data_received = graph_tree_model_drag_data_received;
562 iface->row_drop_possible = graph_tree_model_row_drop_possible;
565 GType graph_tree_model_get_type( void ){
566 static GType graph_tree_model_type = 0;
568 if ( !graph_tree_model_type ) {
569 static const GTypeInfo graph_tree_model_info =
571 sizeof( GraphTreeModelClass ),
573 0, /* base_finalize */
574 (GClassInitFunc) graph_tree_model_class_init,
575 0, /* class_finalize */
577 sizeof( GraphTreeModel ),
579 (GInstanceInitFunc) graph_tree_model_init
582 static const GInterfaceInfo tree_model_info =
584 (GInterfaceInitFunc) graph_tree_model_tree_model_init,
589 static const GInterfaceInfo drag_source_info =
591 (GInterfaceInitFunc) graph_tree_model_drag_source_init,
596 static const GInterfaceInfo drag_dest_info =
598 (GInterfaceInitFunc) graph_tree_model_drag_dest_init,
603 graph_tree_model_type = g_type_register_static( G_TYPE_OBJECT, "GraphTreeModel",
604 &graph_tree_model_info, (GTypeFlags)0 );
606 g_type_add_interface_static( graph_tree_model_type,
609 g_type_add_interface_static( graph_tree_model_type,
610 GTK_TYPE_TREE_DRAG_SOURCE,
612 g_type_add_interface_static( graph_tree_model_type,
613 GTK_TYPE_TREE_DRAG_DEST,
617 return graph_tree_model_type;
620 GraphTreeModel* graph_tree_model_new(){
621 GraphTreeModel* graph_tree_model = GRAPH_TREE_MODEL( g_object_new( graph_tree_model_get_type(), 0 ) );
623 graph_tree_model->graph = new graph_type;
625 return graph_tree_model;
628 void graph_tree_model_delete( GraphTreeModel* model ){
630 g_object_unref( G_OBJECT( model ) );
634 class TempNameable : public Nameable
638 TempNameable( const char* name ) : m_name( name ){
640 const char* name() const {
643 void attach( const NameCallback& callback ){
645 void detach( const NameCallback& callback ){
649 void node_attach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
650 // Reference cannot be bound to dereferenced null pointer in well-defined
651 // C++ code, and Clang will assume that comparison below always evaluates
652 // to true, resulting in a segmentation fault. Use a dirty hack to force
653 // Clang to check those "bad" references for null nonetheless.
654 volatile intptr_t n = (intptr_t)&node;
657 Nameable* nameable = Node_getNameable( node );
658 if ( nameable != 0 ) {
659 nameable->attach( callback );
663 void node_detach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
664 volatile intptr_t n = (intptr_t)&node; // see the comment on line 650
667 Nameable* nameable = Node_getNameable( node );
668 if ( nameable != 0 ) {
669 nameable->detach( callback );
674 GraphTreeModel* scene_graph_get_tree_model(); // temp hack
676 void graph_tree_model_row_inserted( GraphTreeModel* model, graph_type::iterator i ){
678 graph_iterator_write_tree_iter( i, &iter );
680 auto tree_path = graph_tree_model_get_path( model, &iter );
682 gint depth = gtk_tree_path_get_depth( tree_path );
683 gint* indices = gtk_tree_path_get_indices( tree_path );
685 gtk_tree_model_row_inserted( model, tree_path, &iter );
687 gtk_tree_path_free( tree_path );
690 void graph_tree_model_row_deleted( GraphTreeModel* model, graph_type::iterator i ){
692 graph_iterator_write_tree_iter( i, &iter );
694 auto tree_path = graph_tree_model_get_path( model, &iter );
696 gtk_tree_model_row_deleted( model, tree_path );
698 gtk_tree_path_free( tree_path );
701 #include "generic/referencecounted.h"
703 void graph_tree_model_set_name( const scene::Instance& instance, const char* name ){
704 GraphTreeModel* model = scene_graph_get_tree_model();
706 if ( string_empty( name ) ) { // hack!
707 graph_type::iterator i = model->graph->find( PathConstReference( instance.path() ) );
708 ASSERT_MESSAGE( i != model->graph->end(), "ERROR" );
710 graph_tree_model_row_deleted( model, i );
712 model->graph->erase( i );
716 graph_type::iterator i = model->graph->insert( graph_type::value_type( PathConstReference( instance.path() ), &const_cast<scene::Instance&>( instance ) ) ).first;
718 graph_tree_model_row_inserted( model, i );
722 void graph_tree_model_insert( GraphTreeModel* model, const scene::Instance& instance ){
723 graph_type::iterator i = model->graph->insert( graph_type::value_type( PathConstReference( instance.path() ), &const_cast<scene::Instance&>( instance ) ) ).first;
725 graph_tree_model_row_inserted( model, i );
727 node_attach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );
730 void graph_tree_model_erase( GraphTreeModel* model, const scene::Instance& instance ){
731 node_detach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );
733 graph_type::iterator i = model->graph->find( PathConstReference( instance.path() ) );
734 ASSERT_MESSAGE( i != model->graph->end(), "ERROR" );
736 graph_tree_model_row_deleted( model, i );
738 model->graph->erase( i );
744 void graph_tree_model_row_changed( GraphTreeNode& node );
748 typedef std::map<std::pair<CopiedString, scene::Node*>, GraphTreeNode*> ChildNodes;
749 ChildNodes m_childnodes;
751 Reference<scene::Instance> m_instance;
752 GraphTreeNode* m_parent;
754 typedef ChildNodes::iterator iterator;
755 typedef ChildNodes::key_type key_type;
756 typedef ChildNodes::value_type value_type;
757 typedef ChildNodes::size_type size_type;
759 GraphTreeNode( scene::Instance& instance ) : m_instance( instance ), m_parent( 0 ){
760 m_instance.get().setChildSelectedChangedCallback( RowChangedCaller( *this ) );
763 m_instance.get().setChildSelectedChangedCallback( Callback<void()>() );
764 ASSERT_MESSAGE( empty(), "GraphTreeNode::~GraphTreeNode: memory leak" );
768 return m_childnodes.begin();
771 return m_childnodes.end();
774 size_type size() const {
775 return m_childnodes.size();
778 return m_childnodes.empty();
781 iterator insert( const value_type& value ){
782 iterator i = m_childnodes.insert( value ).first;
783 ( *i ).second->m_parent = this;
786 void erase( iterator i ){
787 m_childnodes.erase( i );
789 iterator find( const key_type& key ){
790 return m_childnodes.find( key );
793 void swap( GraphTreeNode& other ){
794 std::swap( m_parent, other.m_parent );
795 std::swap( m_childnodes, other.m_childnodes );
796 std::swap( m_instance, other.m_instance );
800 graph_tree_model_row_changed( *this );
802 typedef MemberCaller<GraphTreeNode, void(), &GraphTreeNode::rowChanged> RowChangedCaller;
805 struct GraphTreeModel
809 GraphTreeNode* m_graph;
812 struct GraphTreeModelClass
814 GObjectClass parent_class;
817 static GtkTreeModelFlags graph_tree_model_get_flags( ui::TreeModel tree_model ){
818 return GTK_TREE_MODEL_ITERS_PERSIST;
821 static gint graph_tree_model_get_n_columns( ui::TreeModel tree_model ){
822 ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
823 //GraphTreeModel* graph_tree_model = (GraphTreeModel*) tree_model;
828 static const gint c_stamp = 0xabcdef;
830 inline GraphTreeNode::iterator graph_iterator_read_tree_iter( GtkTreeIter* iter ){
831 ASSERT_MESSAGE( iter != 0, "tree model error" );
832 ASSERT_MESSAGE( iter->user_data != 0, "tree model error" );
833 ASSERT_MESSAGE( iter->stamp == c_stamp, "tree model error" );
834 return *reinterpret_cast<GraphTreeNode::iterator*>( &iter->user_data );
837 inline void graph_iterator_write_tree_iter( GraphTreeNode::iterator i, GtkTreeIter* iter ){
838 ASSERT_MESSAGE( iter != 0, "tree model error" );
839 iter->stamp = c_stamp;
840 *reinterpret_cast<GraphTreeNode::iterator*>( &iter->user_data ) = i;
841 ASSERT_MESSAGE( iter->user_data != 0, "tree model error" );
844 static GType graph_tree_model_get_column_type( ui::TreeModel tree_model, gint index ){
845 ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
846 //GraphTreeModel *graph_tree_model = (GraphTreeModel *) tree_model;
848 return G_TYPE_POINTER;
851 static gboolean graph_tree_model_get_iter( GraphTreeModel* tree_model, GtkTreeIter* iter, ui::TreePath path ){
852 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
853 gint* indices = gtk_tree_path_get_indices( path );
854 gint depth = gtk_tree_path_get_depth( path );
856 g_return_val_if_fail( depth > 0, FALSE );
858 GraphTreeNode *graph = tree_model->m_graph;
860 if ( graph->empty() ) {
865 GtkTreeIter* parent = 0;
867 for ( gint i = 0; i < depth; i++ )
869 if ( !gtk_tree_model_iter_nth_child( GTK_TREE_MODEL(tree_model), iter, parent, indices[i] ) ) {
879 static ui::TreePath graph_tree_model_get_path( GraphTreeModel *tree_model, GtkTreeIter* iter ){
880 ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
881 GraphTreeNode* graph = tree_model->m_graph;
883 auto path = ui::TreePath(ui::New);
885 for ( GraphTreeNode* node = ( *graph_iterator_read_tree_iter( iter ) ).second; node != graph; node = node->m_parent )
887 std::size_t index = 0;
888 for ( GraphTreeNode::iterator i = node->m_parent->begin(); i != node->m_parent->end(); ++i, ++index )
890 if ( ( *i ).second == node ) {
891 gtk_tree_path_prepend_index( path, gint( index ) );
895 ASSERT_MESSAGE( index != node->m_parent->size(), "error resolving tree path" );
902 static void graph_tree_model_get_value( ui::TreeModel tree_model, GtkTreeIter *iter, gint column, GValue *value ){
903 ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
904 ASSERT_MESSAGE( column == 0 || column == 1, "tree model error" );
906 GraphTreeNode::iterator i = graph_iterator_read_tree_iter( iter );
908 g_value_init( value, G_TYPE_POINTER );
911 g_value_set_pointer( value, reinterpret_cast<gpointer>( ( *i ).first.second ) );
915 g_value_set_pointer( value, reinterpret_cast<gpointer>( &( *i ).second->m_instance.get() ) );
919 static gboolean graph_tree_model_iter_next( ui::TreeModel tree_model, GtkTreeIter *iter ){
920 ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
921 GraphTreeNode::iterator i = graph_iterator_read_tree_iter( iter );
922 GraphTreeNode& parent = *( *i ).second->m_parent;
924 ASSERT_MESSAGE( i != parent.end(), "RUNTIME ERROR" );
926 if ( ++i == parent.end() ) {
930 graph_iterator_write_tree_iter( i, iter );
935 static gboolean graph_tree_model_iter_children( GraphTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent ){
936 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
937 GraphTreeNode& node = ( parent == 0 ) ? *tree_model->m_graph : *( *graph_iterator_read_tree_iter( parent ) ).second;
938 if ( !node.empty() ) {
939 graph_iterator_write_tree_iter( node.begin(), iter );
946 static gboolean graph_tree_model_iter_has_child( ui::TreeModel tree_model, GtkTreeIter *iter ){
947 ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
948 GraphTreeNode& node = *( *graph_iterator_read_tree_iter( iter ) ).second;
949 return !node.empty();
952 static gint graph_tree_model_iter_n_children( GraphTreeModel *tree_model, GtkTreeIter *parent ){
953 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
954 GraphTreeNode& node = ( parent == 0 ) ? *tree_model->m_graph : *( *graph_iterator_read_tree_iter( parent ) ).second;
955 return static_cast<gint>( node.size() );
958 static gboolean graph_tree_model_iter_nth_child( GraphTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n ){
959 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
960 GraphTreeNode& node = ( parent == 0 ) ? *tree_model->m_graph : *( *graph_iterator_read_tree_iter( parent ) ).second;
961 if ( static_cast<std::size_t>( n ) < node.size() ) {
962 GraphTreeNode::iterator i = node.begin();
963 std::advance( i, n );
964 graph_iterator_write_tree_iter( i, iter );
971 static gboolean graph_tree_model_iter_parent( GraphTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child ){
972 ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
973 GraphTreeNode& node = *( *graph_iterator_read_tree_iter( child ) ).second;
974 if ( node.m_parent != tree_model->m_graph ) {
975 GraphTreeNode& parentParent = *node.m_parent->m_parent;
976 for ( GraphTreeNode::iterator i = parentParent.begin(); i != parentParent.end(); ++i )
978 if ( ( *i ).second == node.m_parent ) {
979 graph_iterator_write_tree_iter( i, iter );
987 static GObjectClass *g_parent_class = 0;
991 scene::Node* g_null_node = 0;
994 class NullInstance : public scene::Instance
997 NullInstance() : scene::Instance( scene::Path( makeReference( *g_null_node ) ), 0, 0, Static<InstanceTypeCastTable>::instance() ){
1003 NullInstance g_null_instance;
1006 static void graph_tree_model_init( GraphTreeModel *graph_tree_model ){
1007 graph_tree_model->m_graph = new GraphTreeNode( g_null_instance );
1010 static void graph_tree_model_finalize( GObject* object ){
1011 auto graph_tree_model = reinterpret_cast<GraphTreeModel*>(object);
1013 delete graph_tree_model->m_graph;
1016 ( *g_parent_class->finalize )( object );
1019 static void graph_tree_model_class_init( GraphTreeModelClass *class_ ){
1020 GObjectClass *object_class;
1022 g_parent_class = (GObjectClass*)g_type_class_peek_parent( class_ );
1023 object_class = (GObjectClass *) class_;
1025 object_class->finalize = graph_tree_model_finalize;
1028 static void graph_tree_model_tree_model_init( GtkTreeModelIface *iface ){
1029 iface->get_flags = reinterpret_cast<GtkTreeModelFlags (*)(GtkTreeModel *)>(graph_tree_model_get_flags);
1030 iface->get_n_columns = reinterpret_cast<gint (*)(GtkTreeModel *)>(graph_tree_model_get_n_columns);
1031 iface->get_column_type = reinterpret_cast<GType (*)(GtkTreeModel *, gint)>(graph_tree_model_get_column_type);
1032 iface->get_iter = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreePath *)>(graph_tree_model_get_iter);
1033 iface->get_path = reinterpret_cast<GtkTreePath *(*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_get_path);
1034 iface->get_value = reinterpret_cast<void (*)(GtkTreeModel *, GtkTreeIter *, gint, GValue *)>(graph_tree_model_get_value);
1035 iface->iter_next = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_iter_next);
1036 iface->iter_children = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *)>(graph_tree_model_iter_children);
1037 iface->iter_has_child = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_iter_has_child);
1038 iface->iter_n_children = reinterpret_cast<gint (*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_iter_n_children);
1039 iface->iter_nth_child = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gint)>(graph_tree_model_iter_nth_child);
1040 iface->iter_parent = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *)>(graph_tree_model_iter_parent);
1043 GType graph_tree_model_get_type( void ){
1044 static GType graph_tree_model_type = 0;
1046 if ( !graph_tree_model_type ) {
1047 static const GTypeInfo graph_tree_model_info =
1049 sizeof( GraphTreeModelClass ),
1051 0, /* base_finalize */
1052 (GClassInitFunc) graph_tree_model_class_init,
1053 0, /* class_finalize */
1055 sizeof( GraphTreeModel ),
1056 0, /* n_preallocs */
1057 (GInstanceInitFunc) graph_tree_model_init,
1061 static const GInterfaceInfo tree_model_info =
1063 (GInterfaceInitFunc) graph_tree_model_tree_model_init,
1068 graph_tree_model_type = g_type_register_static( G_TYPE_OBJECT, "GraphTreeModel",
1069 &graph_tree_model_info, (GTypeFlags)0 );
1071 g_type_add_interface_static( graph_tree_model_type,
1072 GTK_TYPE_TREE_MODEL,
1076 return graph_tree_model_type;
1079 GraphTreeModel* graph_tree_model_new(){
1080 auto graph_tree_model = reinterpret_cast<GraphTreeModel*>(g_object_new( graph_tree_model_get_type(), 0 ));
1082 return graph_tree_model;
1085 void graph_tree_model_delete( GraphTreeModel* model ){
1086 g_object_unref( G_OBJECT( model ) );
1089 void graph_tree_model_row_changed( GraphTreeModel* model, GraphTreeNode::iterator i ){
1091 graph_iterator_write_tree_iter( i, &iter );
1093 auto tree_path = graph_tree_model_get_path(model, &iter );
1095 gtk_tree_model_row_changed( GTK_TREE_MODEL( model ), tree_path, &iter );
1097 gtk_tree_path_free( tree_path );
1100 void graph_tree_model_row_inserted( GraphTreeModel* model, GraphTreeNode::iterator i ){
1102 graph_iterator_write_tree_iter( i, &iter );
1104 auto tree_path = graph_tree_model_get_path(model, &iter );
1106 gtk_tree_model_row_inserted( GTK_TREE_MODEL( model ), tree_path, &iter );
1108 gtk_tree_path_free( tree_path );
1111 void graph_tree_model_row_deleted( GraphTreeModel* model, GraphTreeNode::iterator i ){
1113 graph_iterator_write_tree_iter( i, &iter );
1115 auto tree_path = graph_tree_model_get_path(model, &iter );
1117 gtk_tree_model_row_deleted( GTK_TREE_MODEL( model ), tree_path );
1119 gtk_tree_path_free( tree_path );
1122 void graph_tree_model_row_inserted( GraphTreeModel& model, GraphTreeNode::iterator i ){
1123 graph_tree_model_row_inserted( &model, i );
1126 void graph_tree_model_row_deleted( GraphTreeModel& model, GraphTreeNode::iterator i ){
1127 graph_tree_model_row_deleted( &model, i );
1130 const char* node_get_name( scene::Node& node );
1132 const char* node_get_name_safe( scene::Node& node ){
1133 volatile intptr_t n = (intptr_t)&node; // see the comment on line 650
1137 return node_get_name( node );
1140 GraphTreeNode* graph_tree_model_find_parent( GraphTreeModel* model, const scene::Path& path ){
1141 GraphTreeNode* parent = model->m_graph;
1142 for ( scene::Path::const_iterator i = path.begin(); i != path.end() - 1; ++i )
1144 GraphTreeNode::iterator child = parent->find( GraphTreeNode::key_type( node_get_name_safe( ( *i ).get() ), ( *i ).get_pointer() ) );
1145 ASSERT_MESSAGE( child != parent->end(), "ERROR" );
1146 parent = ( *child ).second;
1151 void node_attach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
1152 volatile intptr_t n = (intptr_t)&node; // see the comment on line 650
1154 Nameable* nameable = Node_getNameable( node );
1155 if ( nameable != 0 ) {
1156 nameable->attach( callback );
1160 void node_detach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
1161 volatile intptr_t n = (intptr_t)&node; // see the comment on line 650
1163 Nameable* nameable = Node_getNameable( node );
1164 if ( nameable != 0 ) {
1165 nameable->detach( callback );
1170 GraphTreeModel* scene_graph_get_tree_model(); // temp hack
1172 void graph_tree_node_foreach_pre( GraphTreeNode::iterator root, const Callback<void(GraphTreeNode::iterator)>& callback ){
1174 for ( GraphTreeNode::iterator i = ( *root ).second->begin(); i != ( *root ).second->end(); ++i )
1176 graph_tree_node_foreach_pre( i, callback );
1180 void graph_tree_node_foreach_post( GraphTreeNode::iterator root, const Callback<void(GraphTreeNode::iterator)>& callback ){
1181 for ( GraphTreeNode::iterator i = ( *root ).second->begin(); i != ( *root ).second->end(); ++i )
1183 graph_tree_node_foreach_post( i, callback );
1188 void graph_tree_model_row_changed( GraphTreeNode& node ){
1189 GraphTreeModel* model = scene_graph_get_tree_model();
1190 const scene::Instance& instance = node.m_instance.get();
1192 GraphTreeNode::iterator i = node.m_parent->find( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ) );
1194 graph_tree_model_row_changed( model, i );
1197 void graph_tree_model_set_name( const scene::Instance& instance, const char* name ){
1198 GraphTreeModel* model = scene_graph_get_tree_model();
1199 GraphTreeNode* parent = graph_tree_model_find_parent( model, instance.path() );
1201 GraphTreeNode::iterator oldNode = parent->find( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ) );
1202 graph_tree_node_foreach_post( oldNode, ReferenceCaller<GraphTreeModel, void(GraphTreeNode::iterator), graph_tree_model_row_deleted>( *model ) );
1203 GraphTreeNode* node( ( *oldNode ).second );
1204 parent->erase( oldNode );
1206 GraphTreeNode::iterator newNode = parent->insert( GraphTreeNode::value_type( GraphTreeNode::key_type( name, &instance.path().top().get() ), node ) );
1207 graph_tree_node_foreach_pre( newNode, ReferenceCaller<GraphTreeModel, void(GraphTreeNode::iterator), graph_tree_model_row_inserted>( *model ) );
1210 void graph_tree_model_insert( GraphTreeModel* model, const scene::Instance& instance ){
1211 GraphTreeNode* parent = graph_tree_model_find_parent( model, instance.path() );
1213 GraphTreeNode::iterator i = parent->insert( GraphTreeNode::value_type( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ), new GraphTreeNode( const_cast<scene::Instance&>( instance ) ) ) );
1215 graph_tree_model_row_inserted( model, i );
1217 node_attach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );
1220 void graph_tree_model_erase( GraphTreeModel* model, const scene::Instance& instance ){
1221 node_detach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );
1223 GraphTreeNode* parent = graph_tree_model_find_parent( model, instance.path() );
1225 GraphTreeNode::iterator i = parent->find( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ) );
1227 graph_tree_model_row_deleted( model, i );
1229 GraphTreeNode* node( ( *i ).second );
1242 class TestGraphTreeModel
1245 TestGraphTreeModel(){
1250 scene::Node* root = *(scene::Node*)0xa0000000;
1251 scene::Node* node1 = (scene::Node*)0xa0000001;
1252 scene::Node* node2 = (scene::Node*)0xa0000002;
1253 scene::Node* node3 = (scene::Node*)0xa0000003;
1254 scene::Node* node4 = (scene::Node*)0xa0000004;
1255 scene::Instance* instance = (scene::Instance*)0xaaaaaaaa;
1257 scene::Path rootpath( root );
1259 graph.insert( graph_type::value_type( rootpath, instance ) );
1261 rootpath.push( node1 );
1262 graph.insert( graph_type::value_type( rootpath, instance ) );
1265 rootpath.push( node2 );
1266 graph.insert( graph_type::value_type( rootpath, instance ) );
1267 rootpath.push( node3 );
1268 graph.insert( graph_type::value_type( rootpath, instance ) );
1270 rootpath.push( node4 );
1271 graph.insert( graph_type::value_type( rootpath, instance ) );
1275 auto model = graph_tree_model_new( &graph );
1278 gint n_columns = gtk_tree_model_get_n_columns( model );
1279 ASSERT_MESSAGE( n_columns == 2, "test failed!" );
1283 GType type = gtk_tree_model_get_column_type( model, 0 );
1284 ASSERT_MESSAGE( type == G_TYPE_POINTER, "test failed!" );
1288 GType type = gtk_tree_model_get_column_type( model, 1 );
1289 ASSERT_MESSAGE( type == G_TYPE_POINTER, "test failed!" );
1295 gtk_tree_model_get_iter_first( model, &iter );
1297 graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
1298 ASSERT_MESSAGE( ( *i ).first.get().size() == 2 && ( *i ).first.get().top() == node1, "test failed!" );
1303 gtk_tree_model_get_iter_first( model, &iter );
1305 ASSERT_MESSAGE( gtk_tree_model_iter_has_child( model, &iter ) == FALSE, "test failed!" );
1307 ASSERT_MESSAGE( gtk_tree_model_iter_n_children( model, &iter ) == 0, "test failed!" );
1309 gtk_tree_model_iter_next( model, &iter );
1311 ASSERT_MESSAGE( gtk_tree_model_iter_has_child( model, &iter ) != FALSE, "test failed!" );
1313 ASSERT_MESSAGE( gtk_tree_model_iter_n_children( model, &iter ) == 2, "test failed!" );
1317 gtk_tree_model_iter_nth_child( model, &child, &iter, 0 );
1320 gtk_tree_model_get_value( model, &child, 0, (GValue*)&test );
1321 ASSERT_MESSAGE( test == node3, "test failed!" );
1325 gtk_tree_model_iter_parent( model, &parent, &child );
1328 gtk_tree_model_get_value( model, &parent, 0, (GValue*)&test );
1329 ASSERT_MESSAGE( test == node2, "test failed!" );
1335 gtk_tree_model_iter_nth_child( model, &child, &iter, 1 );
1338 gtk_tree_model_get_value( model, &child, 0, (GValue*)&test );
1339 ASSERT_MESSAGE( test == node4, "test failed!" );
1345 std::size_t count = 0;
1346 for ( gboolean good = gtk_tree_model_get_iter_first( model, &iter ); good; good = gtk_tree_model_iter_next( model, &iter ) )
1349 gtk_tree_model_get_value( model, &iter, 0, (GValue*)&test );
1351 ASSERT_MESSAGE( ( count == 0 && test == node1 ) || ( count == 1 && test == node2 ), "test failed!" );
1355 ASSERT_MESSAGE( count == 2, "test failed!" );
1361 gtk_tree_model_get_iter_first( model, &iter );
1364 gtk_tree_model_get_value( model, &iter, 0, (GValue*)&test );
1365 ASSERT_MESSAGE( test == node1, "test failed!" );
1370 auto path = ui::TreePath( "0" );
1371 gtk_tree_model_get_iter( model, &iter, path );
1372 gtk_tree_path_free( path );
1374 graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
1375 ASSERT_MESSAGE( ( *i ).first.get().size() == 2 && ( *i ).first.get().top() == node1, "test failed!" );
1380 auto path = ui::TreePath( "1" );
1381 gtk_tree_model_get_iter( model, &iter, path );
1382 gtk_tree_path_free( path );
1384 graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
1385 ASSERT_MESSAGE( ( *i ).first.get().size() == 2 && ( *i ).first.get().top() == node2, "test failed!" );
1390 graph_type::iterator i = graph.begin();
1392 graph_iterator_write_tree_iter( i, &iter );
1394 auto path = gtk_tree_model_get_path( model, &iter );
1396 gint depth = gtk_tree_path_get_depth( path );
1397 gint* indices = gtk_tree_path_get_indices( path );
1399 ASSERT_MESSAGE( depth == 1 && indices[0] == 0, "test failed!" );
1401 gtk_tree_path_free( path );
1406 graph_type::iterator i = graph.begin();
1409 graph_iterator_write_tree_iter( i, &iter );
1411 auto path = gtk_tree_model_get_path( model, &iter );
1413 gint depth = gtk_tree_path_get_depth( path );
1414 gint* indices = gtk_tree_path_get_indices( path );
1416 ASSERT_MESSAGE( depth == 1 && indices[0] == 1, "test failed!" );
1418 gtk_tree_path_free( path );
1424 TestGraphTreeModel g_TestGraphTreeModel;