]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktreeview.c
Draw a compass and bearing while using the ruler
[andy/viking.git] / src / viktreeview.c
index b8935a6f6b45e5a35caa12df4d51eec3b3973653..3611e8f18edf1a0e26eab16dae8bf576f565603c 100644 (file)
@@ -23,7 +23,6 @@
 #include <string.h>
 
 #include "viking.h"
 #include <string.h>
 
 #include "viking.h"
-
 #include "config.h"
 
 #define TREEVIEW_GET(model,iter,what,dest) gtk_tree_model_get(GTK_TREE_MODEL(model),(iter),(what),(dest),-1)
 #include "config.h"
 
 #define TREEVIEW_GET(model,iter,what,dest) gtk_tree_model_get(GTK_TREE_MODEL(model),(iter),(what),(dest),-1)
@@ -68,6 +67,9 @@ static void treeview_init ( VikTreeview *vt );
 static void treeview_finalize ( GObject *gob );
 static void treeview_add_columns ( VikTreeview *vt );
 
 static void treeview_finalize ( GObject *gob );
 static void treeview_add_columns ( VikTreeview *vt );
 
+static gboolean treeview_drag_data_received ( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data );
+static gboolean treeview_drag_data_delete ( GtkTreeDragSource *drag_source, GtkTreePath *path );
+
 GType vik_treeview_get_type (void)
 {
   static GType vt_type = 0;
 GType vik_treeview_get_type (void)
 {
   static GType vt_type = 0;
@@ -104,11 +106,11 @@ static void treeview_class_init ( VikTreeviewClass *klass )
   parent_class = g_type_class_peek_parent (klass);
 
   treeview_signals[VT_ITEM_EDITED_SIGNAL] = g_signal_new ( "item_edited", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikTreeviewClass, item_edited), NULL, NULL, 
   parent_class = g_type_class_peek_parent (klass);
 
   treeview_signals[VT_ITEM_EDITED_SIGNAL] = g_signal_new ( "item_edited", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikTreeviewClass, item_edited), NULL, NULL, 
-    g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, GTK_TYPE_TREE_ITER, G_TYPE_STRING);
+    gtk_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, GTK_TYPE_POINTER, G_TYPE_POINTER);
   /* VOID__UINT_POINTER: kinda hack-ish, but it works. */
 
   treeview_signals[VT_ITEM_TOGGLED_SIGNAL] = g_signal_new ( "item_toggled", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikTreeviewClass, item_toggled), NULL, NULL,
   /* VOID__UINT_POINTER: kinda hack-ish, but it works. */
 
   treeview_signals[VT_ITEM_TOGGLED_SIGNAL] = g_signal_new ( "item_toggled", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikTreeviewClass, item_toggled), NULL, NULL,
-    g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER );
+    g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, GTK_TYPE_POINTER );
 }
 
 static void treeview_edited_cb (GtkCellRendererText *cell, gchar *path_str, const gchar *new_name, VikTreeview *vt)
 }
 
 static void treeview_edited_cb (GtkCellRendererText *cell, gchar *path_str, const gchar *new_name, VikTreeview *vt)
@@ -118,7 +120,7 @@ static void treeview_edited_cb (GtkCellRendererText *cell, gchar *path_str, cons
   /* get type and data */
   vik_treeview_get_iter_from_path_str ( vt, &iter, path_str );
 
   /* get type and data */
   vik_treeview_get_iter_from_path_str ( vt, &iter, path_str );
 
-  g_signal_emit ( G_OBJECT(vt), treeview_signals[VT_ITEM_EDITED_SIGNAL], 0, &iter, new_name, 0 );
+  g_signal_emit ( G_OBJECT(vt), treeview_signals[VT_ITEM_EDITED_SIGNAL], 0, &iter, new_name );
 }
 
 static void treeview_toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, VikTreeview *vt)
 }
 
 static void treeview_toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, VikTreeview *vt)
@@ -170,9 +172,9 @@ gpointer vik_treeview_item_get_parent ( VikTreeview *vt, GtkTreeIter *iter )
   return rv;
 }
 
   return rv;
 }
 
-void vik_treeview_get_iter_from_path_str ( VikTreeview *vt, GtkTreeIter *iter, const gchar *path_str )
+gboolean vik_treeview_get_iter_from_path_str ( VikTreeview *vt, GtkTreeIter *iter, const gchar *path_str )
 {
 {
-  gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(vt->model), iter, path_str );
+  return gtk_tree_model_get_iter_from_string ( GTK_TREE_MODEL(vt->model), iter, path_str );
 }
 
 static void treeview_add_columns ( VikTreeview *vt )
 }
 
 static void treeview_add_columns ( VikTreeview *vt )
@@ -258,9 +260,26 @@ void treeview_init ( VikTreeview *vt )
   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (vt)),
                                GTK_SELECTION_SINGLE);
 
   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (vt)),
                                GTK_SELECTION_SINGLE);
 
+  /* Override treestore's dnd methods only; this is easier than deriving from GtkTreeStore. 
+   * The downside is that all treestores will have this behavior, so this needs to be
+   * changed if we add more treeviews in the future.  //Alex
+   */
+  if (1) {
+    GtkTreeDragSourceIface *isrc;
+    GtkTreeDragDestIface *idest;
+
+    isrc = g_type_interface_peek (g_type_class_peek(G_OBJECT_TYPE(vt->model)), GTK_TYPE_TREE_DRAG_SOURCE);
+    isrc->drag_data_delete = treeview_drag_data_delete;
+
+    idest = g_type_interface_peek (g_type_class_peek(G_OBJECT_TYPE(vt->model)), GTK_TYPE_TREE_DRAG_DEST);
+    idest->drag_data_received = treeview_drag_data_received;
+  }      
+
   for ( i = 0; i < VIK_LAYER_NUM_TYPES; i++ )
     vt->layer_type_icons[i] = vik_layer_load_icon ( i ); /* if icon can't be loaded, it will be null and simply not be shown. */
 
   for ( i = 0; i < VIK_LAYER_NUM_TYPES; i++ )
     vt->layer_type_icons[i] = vik_layer_load_icon ( i ); /* if icon can't be loaded, it will be null and simply not be shown. */
 
+  gtk_tree_view_set_reorderable (GTK_TREE_VIEW(vt), TRUE);
+
 }
 
 gboolean vik_treeview_item_get_parent_iter ( VikTreeview *vt, GtkTreeIter *iter,  GtkTreeIter *parent )
 }
 
 gboolean vik_treeview_item_get_parent_iter ( VikTreeview *vt, GtkTreeIter *iter,  GtkTreeIter *parent )
@@ -369,7 +388,12 @@ void vik_treeview_insert_layer ( VikTreeview *vt, GtkTreeIter *parent_iter, GtkT
 {
   g_assert ( iter != NULL );
   g_assert ( icon_type < VIK_LAYER_NUM_TYPES );
 {
   g_assert ( iter != NULL );
   g_assert ( icon_type < VIK_LAYER_NUM_TYPES );
-  gtk_tree_store_insert_before ( GTK_TREE_STORE(vt->model), iter, parent_iter, sibling );
+  if (sibling) {
+    gtk_tree_store_insert_before ( GTK_TREE_STORE(vt->model), iter, parent_iter, sibling );
+  } else {
+    gtk_tree_store_append ( GTK_TREE_STORE(vt->model), iter, parent_iter );
+  }
+    
   gtk_tree_store_set ( GTK_TREE_STORE(vt->model), iter, NAME_COLUMN, name, VISIBLE_COLUMN, TRUE, 
     TYPE_COLUMN, VIK_TREEVIEW_TYPE_LAYER, ITEM_PARENT_COLUMN, parent, ITEM_POINTER_COLUMN, item, 
     ITEM_DATA_COLUMN, data, HAS_VISIBLE_COLUMN, TRUE, EDITABLE_COLUMN, TRUE,
   gtk_tree_store_set ( GTK_TREE_STORE(vt->model), iter, NAME_COLUMN, name, VISIBLE_COLUMN, TRUE, 
     TYPE_COLUMN, VIK_TREEVIEW_TYPE_LAYER, ITEM_PARENT_COLUMN, parent, ITEM_POINTER_COLUMN, item, 
     ITEM_DATA_COLUMN, data, HAS_VISIBLE_COLUMN, TRUE, EDITABLE_COLUMN, TRUE,
@@ -453,3 +477,94 @@ static void treeview_finalize ( GObject *gob )
 
   G_OBJECT_CLASS(parent_class)->finalize(gob);
 }
 
   G_OBJECT_CLASS(parent_class)->finalize(gob);
 }
+
+static gboolean treeview_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data)
+{
+  GtkTreeModel *tree_model;
+  GtkTreeStore *tree_store;
+  GtkTreeModel *src_model = NULL;
+  GtkTreePath *src_path = NULL, *dest_cp = NULL;
+  gboolean retval = FALSE;
+  GtkTreeIter src_iter, root_iter, dest_iter, dest_parent;
+  guint *i_src = NULL;
+  VikTreeview *vt;
+  VikLayer *vl;
+
+  g_return_val_if_fail (GTK_IS_TREE_STORE (drag_dest), FALSE);
+
+  tree_model = GTK_TREE_MODEL (drag_dest);
+  tree_store = GTK_TREE_STORE (drag_dest);
+
+  if (gtk_tree_get_row_drag_data (selection_data, &src_model, &src_path) && src_model == tree_model) {
+    /* 
+     * Copy src_path to dest.  There are two subcases here, depending on what 
+     * is being dragged.
+     * 
+     * 1. src_path is a layer. In this case, interpret the drop 
+     *    as a request to move the layer to a different aggregate layer.
+     *    If the destination is not an aggregate layer, use the first 
+     *    ancestor that is.
+     *
+     * 2. src_path is a sublayer.  In this case, find ancestors of 
+     *    both source and destination nodes who are full layers,
+     *    and call the move method of that layer type. 
+     *
+     */
+    i_src = gtk_tree_path_get_indices (src_path);
+    dest_cp = gtk_tree_path_copy (dest);
+
+    gtk_tree_model_get_iter_first(tree_model, &root_iter);
+    TREEVIEW_GET(tree_model, &root_iter, ITEM_POINTER_COLUMN, &vl);
+    vt = vl->vt;
+
+    if (!gtk_tree_model_get_iter (src_model, &src_iter, src_path)) {
+      goto out;
+    }
+
+    if (gtk_tree_path_get_depth(dest_cp)>1) { /* can't be sibling of top layer */
+      VikLayer *vl_src, *vl_dest;
+
+      /* Find the first ancestor that is a full layer, and store in dest_parent. 
+       * In addition, put in dest_iter where Gtk wants us to insert the dragged object.
+       * (Note that this may end up being an invalid iter). 
+       */
+      do {
+       gtk_tree_path_up(dest_cp);
+       dest_iter = dest_parent;
+       gtk_tree_model_get_iter (src_model, &dest_parent, dest_cp);
+      } while (gtk_tree_path_get_depth(dest_cp)>1 &&
+              vik_treeview_item_get_type(vt, &dest_parent) != VIK_TREEVIEW_TYPE_LAYER);
+
+      
+      g_assert ( vik_treeview_item_get_parent(vt, &src_iter) );
+      vl_src = vik_treeview_item_get_parent(vt, &src_iter);
+      vl_dest = vik_treeview_item_get_pointer(vt, &dest_parent);
+
+      /* TODO: might want to allow different types, and let the clients handle how they want */
+      if (vl_src->type == vl_dest->type && vik_layer_get_interface(vl_dest->type)->drag_drop_request) {
+       g_print("moving an item from layer '%s' into layer '%s'\n", vl_src->name, vl_dest->name);
+       vik_layer_get_interface(vl_dest->type)->drag_drop_request(vl_src, vl_dest, &src_iter, dest);
+      }    
+    }
+  }
+
+ out:
+  if (dest_cp) 
+    gtk_tree_path_free(dest_cp);
+  if (src_path)
+    gtk_tree_path_free (src_path);
+
+  return retval;
+}
+
+/* 
+ * This may not be necessary.
+ */
+static gboolean treeview_drag_data_delete ( GtkTreeDragSource *drag_source, GtkTreePath *path )
+{
+  gchar *s_dest = gtk_tree_path_to_string(path);
+  g_print("delete data from %s\n", s_dest);
+  g_free(s_dest);
+  return FALSE;
+}
+