[dia] Reimplementation of the Diagram Tree with GtkTree(Model|View)
- From: Hans Breuer <hans src gnome org>
- To: svn-commits-list gnome org
- Subject: [dia] Reimplementation of the Diagram Tree with GtkTree(Model|View)
- Date: Sun, 31 May 2009 05:46:36 -0400 (EDT)
commit 131eea01ceb400268ef0b6662cfce4c53a4b936c
Author: Hans Breuer <hans breuer org>
Date: Fri Apr 24 19:58:00 2009 +0200
Reimplementation of the Diagram Tree with GtkTree(Model|View)
It already has a bunch of fancy new features:
- nicer look
- can search for object name by simply typing it
- multiple selection (works across layers!)
- allows to transfer the selection to the diagram
- tooltips for additional information
Currently missing:
- reaction to the diagram changes (i.e. auto update)
- filtering by object type (or anything else)
- sorting by name or type (or size?)
- serializing it's position
- looking into groups
- in-place editing (e.g. moving objects between layers)
- enough functionality to also replace the layer dialog
- move layer up or down
- add/remove layer
- hide/show layer
- rename layer
- maybe hide toe objects for layer editing (or just view defaults)
---
app/Makefile.am | 6 +
app/diagram_tree_model.c | 377 +++++++++++++++++++++++++++++++++
app/diagram_tree_model.h | 28 +++
app/diagram_tree_view.c | 514 ++++++++++++++++++++++++++++++++++++++++++++++
app/makefile.msc | 5 +-
app/menus.c | 4 +-
6 files changed, 932 insertions(+), 2 deletions(-)
diff --git a/app/Makefile.am b/app/Makefile.am
index 0e84710..6f18451 100644
--- a/app/Makefile.am
+++ b/app/Makefile.am
@@ -181,12 +181,18 @@ dia_core_files = \
recent_files.c \
diagram_tree.h \
diagram_tree.c \
+ \
diagram_tree_window.h \
diagram_tree_window.c \
diagram_tree_menu.h \
diagram_tree_menu.c \
diagram_tree_menu_callbacks.h \
diagram_tree_menu_callbacks.c \
+ \
+ diagram_tree_model.c \
+ diagram_tree_model.h \
+ diagram_tree_view.c \
+ \
sheets.c \
sheets.h \
sheets_dialog.c \
diff --git a/app/diagram_tree_model.c b/app/diagram_tree_model.c
new file mode 100644
index 0000000..e8af9a0
--- /dev/null
+++ b/app/diagram_tree_model.c
@@ -0,0 +1,377 @@
+/* Dia -- a diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * diagram_tree.c : a tree showing open diagrams
+ * Copyright (C) 2001 Jose A Ortega Ruiz
+ *
+ * complete rewrite to get rid of deprecated widgets
+ * Copyright (C) 2009 Hans Breuer
+ *
+ * This program 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 program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include "diagram.h"
+#include "object.h"
+
+#include "diagram_tree_model.h"
+
+/* accessing iter fileds by name by */
+#define NODE_DIAGRAM(it) ((DiagramData*)(it->user_data))
+#define NODE_LAYER(it) ((Layer*)(it->user_data2))
+#define NODE_OBJECT(it) ((DiaObject*)(it->user_data3))
+typedef struct _DiagramTreeModelClass
+{
+ GObjectClass parent_class;
+} DiagramTreeModelClass;
+typedef struct _DiagramTreeModel
+{
+ GObject parent;
+ /* no need to store anything */
+} DiagramTreeModel;
+static void
+_dtm_class_init (DiagramTreeModelClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+}
+static void
+_dtm_init (DiagramTreeModel *dtm)
+{
+}
+
+#define DIAGRAM_TREE_MODEL (_dtm_get_type ())
+
+static void _dtm_iface_init (GtkTreeModelIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (DiagramTreeModel, _dtm, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ _dtm_iface_init))
+
+static GtkTreeModelFlags
+_get_flags (GtkTreeModel *tree_model)
+{
+ return GTK_TREE_MODEL_ITERS_PERSIST;
+}
+static gint
+_dtm_get_n_columns (GtkTreeModel *tree_model)
+{
+ return NUM_COLUMNS;
+}
+static GType
+_dtm_get_column_type (GtkTreeModel *tree_model,
+ gint index)
+{
+ g_return_val_if_fail (index >= DIAGRAM_COLUMN || index < NUM_COLUMNS, G_TYPE_NONE);
+
+ switch (index) {
+ case DIAGRAM_COLUMN :
+ return DIA_TYPE_DIAGRAM;
+ case NAME_COLUMN :
+ return G_TYPE_STRING;
+ case LAYER_COLUMN :
+ case OBJECT_COLUMN :
+ /* TODO: these should be ported to GObject ... */
+ return G_TYPE_POINTER;
+ default :
+ g_assert_not_reached ();
+ return G_TYPE_NONE;
+ }
+}
+static gboolean
+_dtm_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ /* copy&paste from Gtk */
+ GtkTreeIter parent;
+ gint *indices;
+ gint depth, i;
+
+ indices = gtk_tree_path_get_indices (path);
+ depth = gtk_tree_path_get_depth (path);
+
+ g_return_val_if_fail (depth > 0, FALSE);
+
+ if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
+ return FALSE;
+
+ for (i = 1; i < depth; i++)
+ {
+ parent = *iter;
+ if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+static GtkTreePath *
+_dtm_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ GtkTreePath *result;
+
+ if (!NODE_DIAGRAM(iter) && !NODE_LAYER(iter) && !NODE_OBJECT(iter)) {
+ /* the root path */
+ return gtk_tree_path_new_first ();
+ }
+
+ result = gtk_tree_path_new ();
+
+ if (NODE_DIAGRAM(iter)) {
+ GList *list = dia_open_diagrams();
+ gtk_tree_path_append_index (result, g_list_index (list, NODE_DIAGRAM(iter)));
+ }
+ if (NODE_LAYER(iter)) {
+ g_return_val_if_fail (NODE_DIAGRAM(iter) == layer_get_parent_diagram (NODE_LAYER(iter)), NULL);
+ gtk_tree_path_append_index (result, data_layer_get_index (NODE_DIAGRAM(iter), NODE_LAYER(iter)));
+ }
+ if (NODE_OBJECT(iter)) {
+ g_return_val_if_fail (NODE_LAYER(iter) == dia_object_get_parent_layer (NODE_OBJECT(iter)), NULL);
+ gtk_tree_path_append_index (result, layer_object_get_index (NODE_LAYER(iter), NODE_OBJECT(iter)));
+ }
+
+ return result;
+}
+
+static gint
+_dtm_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ if (!iter)
+ return g_list_length (dia_open_diagrams());
+
+ if (NODE_OBJECT(iter)) {
+ /* TODO: dive into objects (groups?)? */
+ return 0;
+ } else if (NODE_LAYER(iter)) {
+ if (!NODE_LAYER(iter))
+ return 0;
+ return layer_object_count (NODE_LAYER(iter));
+ } else if (NODE_DIAGRAM(iter)) {
+ if (!NODE_DIAGRAM(iter))
+ return 0;
+ return data_layer_count (NODE_DIAGRAM(iter));
+ }
+ return 0;
+}
+static void
+_dtm_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+
+ switch (column) {
+ case DIAGRAM_COLUMN :
+ g_value_init (value, G_TYPE_OBJECT);
+ g_value_set_object (value, g_object_ref(NODE_DIAGRAM(iter)));
+ break;
+ case LAYER_COLUMN :
+ g_value_init (value, G_TYPE_POINTER);
+ g_value_set_pointer (value, NODE_LAYER(iter));
+ break;
+ case OBJECT_COLUMN :
+ g_value_init (value, G_TYPE_POINTER);
+ g_value_set_pointer (value, NODE_OBJECT(iter));
+ break;
+ case NAME_COLUMN :
+ g_value_init (value, G_TYPE_STRING);
+ /* deduce the requested name from the iter */
+ if (NODE_OBJECT(iter))
+ g_value_set_string (value, object_get_displayname (NODE_OBJECT (iter)));
+ else if (NODE_LAYER(iter))
+ g_value_set_string (value, layer_get_name (NODE_LAYER (iter)));
+ else if (NODE_DIAGRAM(iter))
+ g_value_set_string (value, diagram_get_name (DIA_DIAGRAM(NODE_DIAGRAM(iter))));
+ else /* warn on it? */
+ g_value_set_string (value, NULL);
+ break;
+ default :
+ g_assert_not_reached ();
+ }
+}
+static gboolean
+_dtm_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ int i;
+ if (NODE_OBJECT(iter)) {
+ if (!NODE_LAYER(iter))
+ return FALSE;
+ i = layer_object_get_index (NODE_LAYER(iter), NODE_OBJECT(iter));
+ ++i;
+ NODE_OBJECT(iter) = layer_object_get_nth(NODE_LAYER(iter), i);
+ return NODE_OBJECT(iter) != NULL;
+ } else if (NODE_LAYER(iter)) {
+ if (!NODE_DIAGRAM(iter))
+ return FALSE;
+ i = data_layer_get_index (NODE_DIAGRAM(iter), NODE_LAYER(iter));
+ ++i;
+ NODE_LAYER(iter) = data_layer_get_nth(NODE_DIAGRAM(iter), i);
+ return NODE_LAYER(iter) != NULL;
+ } else if (NODE_DIAGRAM(iter)) {
+ GList *list = dia_open_diagrams();
+ i = g_list_index (list, NODE_DIAGRAM(iter));
+ ++i;
+ list = g_list_nth (list, i);
+ NODE_DIAGRAM(iter) = list ? list->data : NULL;
+ return NODE_DIAGRAM(iter) != NULL;
+ } else {
+ /* empy iter? */
+ GList *list = dia_open_diagrams();
+ NODE_DIAGRAM(iter) = list ? list->data : NULL;
+ return NODE_DIAGRAM(iter) != NULL;
+ }
+ return FALSE;
+}
+static gboolean
+_dtm_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ if (parent) {
+ if (NODE_OBJECT(parent))
+ return FALSE;
+ else if (NODE_LAYER(parent)) {
+ NODE_OBJECT(iter) = layer_object_get_nth(NODE_LAYER(parent), 0);
+ if (NODE_OBJECT(iter)) {
+ NODE_LAYER(iter) = dia_object_get_parent_layer(NODE_OBJECT(iter));
+ NODE_DIAGRAM(iter) = layer_get_parent_diagram (NODE_LAYER(iter));
+ return TRUE;
+ }
+ } else if (NODE_DIAGRAM(parent)) {
+ NODE_LAYER(iter) = data_layer_get_nth(NODE_DIAGRAM(parent), 0);
+ if (NODE_LAYER(iter)) {
+ NODE_DIAGRAM(iter) = layer_get_parent_diagram (NODE_LAYER(iter));
+ NODE_OBJECT(iter) = NULL;
+ return TRUE;
+ }
+ } else {
+ /* deliver root's children */
+ parent = NULL;
+ }
+ }
+ if (!parent) {
+ /* the first diagram */
+ GList *list = dia_open_diagrams();
+ NODE_DIAGRAM(iter) = list ? list->data : NULL;
+ NODE_LAYER(iter) = NULL;
+ NODE_OBJECT(iter) = NULL;
+ return NODE_DIAGRAM(iter) != NULL;
+ }
+}
+static gboolean
+_dtm_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return _dtm_iter_n_children (tree_model, iter) > 0;
+}
+static gboolean
+_dtm_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ if (parent) {
+ *iter = *parent;
+ if (NODE_OBJECT(parent)) {
+ return FALSE;
+ } else if (NODE_LAYER(parent)) {
+ NODE_OBJECT(iter) = layer_object_get_nth(NODE_LAYER(iter), n);
+ return NODE_OBJECT(iter) != NULL;
+ } else if (NODE_DIAGRAM(parent)) {
+ NODE_LAYER(iter) = data_layer_get_nth(NODE_DIAGRAM(iter), n);
+ return NODE_LAYER(iter) != NULL;
+ }
+ }
+ if (!parent || !NODE_DIAGRAM(parent)) {
+ /* the nth diagram */
+ GList *list = dia_open_diagrams();
+ list = g_list_nth(list, n);
+ NODE_DIAGRAM(iter) = list ? list->data : NULL;
+ NODE_LAYER(iter) = NULL;
+ NODE_OBJECT(iter) = NULL;
+ return NODE_DIAGRAM(iter) != NULL;
+ }
+ return FALSE;
+}
+static gboolean
+_dtm_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ *iter = *child;
+ if (!NODE_DIAGRAM(child))
+ return FALSE;
+ if (NODE_OBJECT(child))
+ NODE_OBJECT(iter) = NULL;
+ else if (NODE_LAYER(child))
+ NODE_LAYER(iter) = NULL;
+ else if (NODE_DIAGRAM(child))
+ NODE_DIAGRAM(iter) = NULL;
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+_dtm_ref_node (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ /* fixme: ref-counting? */
+}
+static void
+_dtm_unref_node (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ /* fixme: ref-counting? */
+}
+static void
+_dtm_iface_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = _get_flags;
+ iface->get_n_columns = _dtm_get_n_columns;
+ iface->get_column_type = _dtm_get_column_type;
+ iface->get_iter = _dtm_get_iter;
+ iface->get_path = _dtm_get_path;
+ iface->get_value = _dtm_get_value;
+ iface->iter_next = _dtm_iter_next;
+ iface->iter_children = _dtm_iter_children;
+ iface->iter_has_child = _dtm_iter_has_child;
+ iface->iter_n_children = _dtm_iter_n_children;
+ iface->iter_nth_child = _dtm_iter_nth_child;
+ iface->iter_parent = _dtm_iter_parent;
+
+ iface->ref_node = _dtm_ref_node;
+ iface->unref_node = _dtm_unref_node;
+
+ /*todo?*/
+#if 0
+ row_changed;
+ row_inserted;
+ row_has_child_toggled;
+ row_deleted;
+ rows_reordered;
+#endif
+}
+
+GtkTreeModel *
+diagram_tree_model_new (void)
+{
+ return g_object_new (DIAGRAM_TREE_MODEL, NULL);
+}
diff --git a/app/diagram_tree_model.h b/app/diagram_tree_model.h
new file mode 100644
index 0000000..4e67056
--- /dev/null
+++ b/app/diagram_tree_model.h
@@ -0,0 +1,28 @@
+#ifndef DIAGRAM_TREE_MODEL_H
+#define DIAGRAM_TREE_MODEL_H
+/* Root/
+ * Diagram/
+ * Layer/
+ * Object/ object or group with objects?
+ * (Meta-)Properties/ ?
+ *
+ * But for a tree the concept of column and hierachy are ortogonal,
+ * e.g. we can have a name column (something we can provide a value for)
+ * for all of the objects.
+ * We may also want to build another heirachy by connected? Or maybe
+ * not because they could be circular.
+ *
+ * Another idea: split models, e.g. one for the application list of diagrams,
+ * one for a single diagram and one for meta/properties of an object.
+ */
+typedef enum {
+ DIAGRAM_COLUMN, /*!< conceptionally the Diagram although it is called DiagramData */
+ LAYER_COLUMN, /*!< not a gobject yet, but a pointer */
+ OBJECT_COLUMN, /*!< not a gobject yet, but a pointer */
+ NAME_COLUMN, /*!< the name of the 'row' be it diagram/layer/object */
+ NUM_COLUMNS /*! must be last - total number */
+} DiaNodeType;
+
+GtkTreeModel *diagram_tree_model_new (void);
+
+#endif
\ No newline at end of file
diff --git a/app/diagram_tree_view.c b/app/diagram_tree_view.c
new file mode 100644
index 0000000..139d313
--- /dev/null
+++ b/app/diagram_tree_view.c
@@ -0,0 +1,514 @@
+/* Dia -- a diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * diagram_tree.c : a tree showing open diagrams
+ * Copyright (C) 2001 Jose A Ortega Ruiz
+ *
+ * diagram_tree_view.c : complete rewrite to get rid of deprecated widgets
+ * Copyright (C) 2009 Hans Breuer
+ *
+ * This program 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 program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include <lib/object.h>
+
+#include "diagram_tree_model.h"
+
+#include "dia-app-icons.h" /* for dia_group_icon */
+#include <lib/group.h> /* IS_GROUP */
+#include "display.h"
+#include "properties-dialog.h" /* object_list_properties_show */
+#include "dia-props.h" /* diagram_properties_show */
+
+typedef struct _DiagramTreeView DiagramTreeView;
+struct _DiagramTreeView {
+ GtkTreeView parent_instance;
+
+ GtkUIManager *ui_manager;
+ GtkMenu *popup;
+};
+
+typedef struct _DiagramTreeViewClass DiagramTreeViewClass;
+struct _DiagramTreeViewClass {
+ GtkTreeViewClass parent_class;
+};
+
+#define DIAGRAM_TREE_VIEW_TYPE (_dtv_get_type ())
+#define DIAGRAM_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DIAGRAM_TREE_VIEW_TYPE, DiagramTreeView))
+
+#if 0
+//future
+G_DEFINE_TYPE_WITH_CODE (DiagramTreeView, _dtv, GTK_TYPE_TREE_VIEW,
+ G_IMPLEMENT_INTERFACE (DIAGRAM_TYPE_SEARCHABLE,
+ _dtv_init))
+#else
+G_DEFINE_TYPE (DiagramTreeView, _dtv, GTK_TYPE_TREE_VIEW);
+#endif
+
+static gboolean
+_dtv_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ DiaObject *object;
+ Diagram *diagram;
+
+ if (event->button == 3) {
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+ if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ event->x, event->y,
+ &path, NULL, NULL, NULL)) {
+ return TRUE;
+ }
+
+ if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection (GTK_TREE_VIEW (widget))) < 2) {
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_path (selection, path);
+
+ /* FIXME: for multiple selection we should check all object selected being compatible */
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, OBJECT_COLUMN, &object, -1);
+ gtk_tree_path_free (path);
+ }
+
+ gtk_menu_popup (DIAGRAM_TREE_VIEW(widget)->popup, NULL, NULL, NULL, NULL, event->button, event->time);
+
+ } else {
+ GTK_WIDGET_CLASS (_dtv_parent_class)->button_press_event (widget, event);
+
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ event->x, event->y,
+ &path, NULL, NULL, NULL)) {
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, OBJECT_COLUMN, &object, -1);
+ gtk_tree_model_get (model, &iter, DIAGRAM_COLUMN, &diagram, -1);
+
+ if (object && diagram && ddisplay_active_diagram() == diagram) {
+ if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) /* double-click 'locates' */
+ ddisplay_present_object (ddisplay_active(), object);
+ }
+ if (diagram)
+ g_object_unref(diagram);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_dtv_query_tooltip (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip)
+{
+ int bin_x, bin_y;
+ GtkTreePath *path = NULL;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GdkRectangle cell_area;
+ GString *markup;
+ gboolean had_info = FALSE;
+
+ gtk_tree_view_convert_widget_to_bin_window_coords (
+ GTK_TREE_VIEW (widget), x, y, &bin_x, &bin_y);
+
+ if (gtk_tree_view_get_path_at_pos
+ (GTK_TREE_VIEW (widget), bin_x, bin_y, &path, &column, NULL, NULL)) {
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+ if (gtk_tree_model_get_iter (model, &iter, path)) {
+ /* show some useful information */
+ Diagram *diagram;
+ Layer *layer;
+ DiaObject *object;
+
+
+ gtk_tree_model_get (model, &iter, DIAGRAM_COLUMN, &diagram, -1);
+ gtk_tree_model_get (model, &iter, LAYER_COLUMN, &layer, -1);
+ gtk_tree_model_get (model, &iter, OBJECT_COLUMN, &object, -1);
+
+ markup = g_string_new (NULL);
+
+ if (diagram) {
+ g_string_append_printf (markup, "<b>%s</b>: %s\n", _("Diagram"), diagram->filename);
+ g_object_unref (diagram);
+ }
+ if (layer) {
+ gchar *name = layer_get_name (layer);
+ g_string_append_printf (markup, "<b>%s</b>: %s\n", _("Layer"), name);
+ g_free (name);
+ } else if (diagram) {
+ g_string_append_printf (markup, "%d %s",
+ data_layer_count (DIA_DIAGRAM_DATA(diagram)), _("Layer(s)"));
+ }
+ if (object) {
+ g_string_append_printf (markup, "<b>%s</b>: %s\n", _("Type"), object->type->name);
+ g_string_append_printf (markup, "<b>%s</b>: %g,%g\n", _("Position"),
+ object->position.x, object->position.y);
+ g_string_append_printf (markup, "%d %s",
+ g_list_length (object->children), _("Children"));
+ /* and some dia_object_get_meta ? */
+ } else if (layer) {
+ g_string_append_printf (markup, "%d %s",
+ layer_object_count (layer), _("Object(s)"));
+ }
+
+ if (markup->len > 0) {
+ gtk_tree_view_get_cell_area (GTK_TREE_VIEW (widget), path, column, &cell_area);
+
+ gtk_tree_view_convert_bin_window_to_widget_coords
+ (GTK_TREE_VIEW (widget), cell_area.x, cell_area.y,
+ &cell_area.x, &cell_area.y);
+
+ gtk_tooltip_set_tip_area (tooltip, &cell_area);
+ gtk_tooltip_set_markup (tooltip, markup->str);
+ had_info = TRUE;
+ }
+
+ g_string_free (markup, TRUE);
+ }
+ gtk_tree_path_free (path);
+ if (had_info)
+ return TRUE;
+ }
+
+ return GTK_WIDGET_CLASS (_dtv_parent_class)->query_tooltip
+ (widget, x, y, keyboard_mode, tooltip);
+}
+
+static void
+_dtv_row_activated (GtkTreeView *view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ DiaObject *object;
+
+ model = gtk_tree_view_get_model (view);
+
+ if (gtk_tree_model_get_iter (model, &iter, path)) {
+ gtk_tree_model_get (model, &iter, OBJECT_COLUMN, &object, -1);
+
+ //g_signal_emit (view, signals[REVISION_ACTIVATED], 0, object);
+
+ }
+
+ if (GTK_TREE_VIEW_CLASS (_dtv_parent_class)->row_activated)
+ GTK_TREE_VIEW_CLASS (_dtv_parent_class)->row_activated (view, path, column);
+}
+
+static void
+_dtv_class_init (DiagramTreeViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkTreeViewClass *tree_view_class = GTK_TREE_VIEW_CLASS (klass);
+
+ widget_class->button_press_event = _dtv_button_press;
+ widget_class->query_tooltip = _dtv_query_tooltip;
+
+ tree_view_class->row_activated = _dtv_row_activated;
+}
+
+/* given the model and the path, construct the icon */
+static void
+_dtv_cell_pixbuf_func (GtkCellLayout *layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ DiaObject *object;
+ GdkPixbuf *pixbuf = NULL;
+
+ gtk_tree_model_get (tree_model, iter, OBJECT_COLUMN, &object, -1);
+ if (object) {
+ if (object->type->pixmap != NULL) {
+ if (strncmp((char *)object->type->pixmap, "GdkP", 4) == 0)
+ pixbuf = gdk_pixbuf_new_from_inline(-1, (guint8*)object->type->pixmap, TRUE, NULL);
+ else /* must be an XPM */
+ pixbuf = gdk_pixbuf_new_from_xpm_data(object->type->pixmap);
+ } else if (object->type->pixmap_file != NULL) {
+ GError *error = NULL;
+ pixbuf = gdk_pixbuf_new_from_file (object->type->pixmap_file, &error);
+ if (error) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ } else if (IS_GROUP(object)) {
+ pixbuf = gdk_pixbuf_new_from_inline(-1, dia_group_icon, TRUE, NULL);
+ }
+ } else {
+#if 0 /* these icons are not that useful */
+ Layer *layer;
+ gtk_tree_model_get (tree_model, iter, LAYER_COLUMN, &layer, -1);
+ if (layer)
+ pixbuf = gdk_pixbuf_new_from_inline(-1, dia_layers, TRUE, NULL);
+ else /* must be diagram */
+ pixbuf = gdk_pixbuf_new_from_inline(-1, dia_diagram_icon, TRUE, NULL);
+#endif
+ }
+
+ g_object_set (cell, "pixbuf", pixbuf, NULL);
+ if (pixbuf)
+ g_object_unref (pixbuf);
+}
+
+static void
+_dtv_select_items (GtkAction *action,
+ DiagramTreeView *dtv)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GList *rows, *r;
+ gboolean once = TRUE;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dtv));
+ rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ r = rows;
+ while (r) {
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (model, &iter, r->data)) {
+ Diagram *diagram;
+ Layer *layer;
+ DiaObject *object;
+
+ gtk_tree_model_get (model, &iter, DIAGRAM_COLUMN, &diagram, -1);
+ gtk_tree_model_get (model, &iter, LAYER_COLUMN, &layer, -1);
+ gtk_tree_model_get (model, &iter, OBJECT_COLUMN, &object, -1);
+
+ if (once) { /* destroy previous selection in first iteration */
+ diagram_remove_all_selected(diagram, TRUE);
+ once = FALSE;
+ }
+
+ if (layer) /* fixme: layer dialog update missing */
+ data_set_active_layer (DIA_DIAGRAM_DATA(diagram), layer);
+ if (object)
+ diagram_select (diagram, object);
+ if (diagram) {
+ diagram_add_update_all (diagram);
+ diagram_flush(diagram);
+ g_object_unref (diagram);
+ }
+ }
+ r = g_list_next (r);
+ }
+ g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (rows);
+}
+static void
+_dtv_locate_item (GtkAction *action,
+ DiagramTreeView *dtv)
+{
+ /* FIXME: implement */
+}
+static void
+_dtv_showprops_item (GtkAction *action,
+ DiagramTreeView *dtv)
+{
+ GList *selected = NULL;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GList *rows, *r;
+ Diagram *diagram = NULL;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dtv));
+ rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ r = rows;
+ while (r) {
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (model, &iter, r->data)) {
+ DiaObject *object;
+ Diagram *current_diagram;
+
+ gtk_tree_model_get (model, &iter, DIAGRAM_COLUMN, ¤t_diagram, -1);
+ gtk_tree_model_get (model, &iter, OBJECT_COLUMN, &object, -1);
+ if (object)
+ selected = g_list_append (selected, object);
+ if (!diagram) /* keep the reference */
+ diagram = current_diagram;
+ else if (diagram == current_diagram) /* still the same */
+ g_object_unref (current_diagram);
+ else {
+ g_object_unref (current_diagram);
+ break; /* can only handle one diagram's objects */
+ }
+ }
+ r = g_list_next (r);
+ }
+
+ if (diagram && selected)
+ object_list_properties_show (diagram, selected);
+ else if (diagram)
+ diagram_properties_show(diagram);
+ if (diagram)
+ g_object_unref(diagram);
+
+ g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (rows);
+}
+/* create the popup menu */
+static void
+_dtv_create_popup_menu (DiagramTreeView *dtv)
+{
+ static GtkActionEntry menu_items [] = {
+ { "Select", NULL, N_("Select"), NULL, NULL, G_CALLBACK (_dtv_select_items) },
+ { "Locate", NULL, N_("Locate"), NULL, NULL, G_CALLBACK (_dtv_locate_item) },
+ { "Properties", NULL, N_("Properties"), NULL, NULL, G_CALLBACK(_dtv_showprops_item) }
+ };
+ static const gchar *ui_description =
+ "<ui>"
+ " <popup name='PopupMenu'>"
+ " <menuitem action='Select'/>"
+ " <menuitem action='Locate'/>"
+ " <menuitem action='Properties'/>"
+ " </popup>"
+ "</ui>";
+ GtkActionGroup *action_group;
+
+ g_return_if_fail (dtv->popup == NULL && dtv->ui_manager == NULL);
+
+ action_group = gtk_action_group_new ("PopupActions");
+ gtk_action_group_set_translation_domain (action_group, NULL); /* FIXME? */
+ gtk_action_group_add_actions (action_group, menu_items,
+ G_N_ELEMENTS (menu_items), dtv);
+
+ dtv->ui_manager = gtk_ui_manager_new ();
+ gtk_ui_manager_insert_action_group (dtv->ui_manager, action_group, 0);
+ if (gtk_ui_manager_add_ui_from_string (dtv->ui_manager, ui_description, -1, NULL))
+ dtv->popup = GTK_MENU(gtk_ui_manager_get_widget (dtv->ui_manager, "/ui/PopupMenu"));
+}
+
+static void
+_dtv_init (DiagramTreeView *dtv)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ gint font_size;
+
+ /* connect the model with the view */
+ gtk_tree_view_set_model (GTK_TREE_VIEW (dtv), diagram_tree_model_new ());
+
+ gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (dtv), TRUE);
+ /* the tree requires reading across rows (semantic hint) */
+#if 0 /* stripe style */
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (dtv), TRUE);
+#endif
+
+ font_size = pango_font_description_get_size (GTK_WIDGET (dtv)->style->font_desc);
+ font_size = PANGO_PIXELS (font_size);
+
+ /* first colum: name of diagram/layer/object - here is the tree */
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (cell), 1);
+ g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Name"));
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_min_width (column, font_size * 10);
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
+ gtk_tree_view_column_add_attribute (column, cell, "text", NAME_COLUMN);
+ gtk_tree_view_insert_column (GTK_TREE_VIEW (dtv), column, -1);
+
+ /* this is enough for simple name search (just typing) */
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (dtv), NAME_COLUMN);
+
+ /* type column - show the type icon */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Type"));
+ /* must have fixed size, too */
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ /* without it gets zero size - not very useful! */
+ gtk_tree_view_column_set_min_width (column, font_size * 4);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), cell,
+ _dtv_cell_pixbuf_func, dtv, NULL);
+ gtk_tree_view_insert_column (GTK_TREE_VIEW (dtv), column, -1);
+
+ /* TODO: other fancy stuff */
+
+ {
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dtv));
+
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (dtv), TRUE);
+ }
+ gtk_widget_set_has_tooltip (GTK_WIDGET (dtv), TRUE);
+
+
+ _dtv_create_popup_menu (dtv);
+}
+
+GtkWidget *
+diagram_tree_view_new (void)
+{
+ return g_object_new (DIAGRAM_TREE_VIEW_TYPE, NULL);
+}
+
+/* should go to it's own file, just for testing */
+void
+diagram_tree_show (void)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window) {
+ GtkWidget *sw;
+ GtkWidget *dtv;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), _("Diagram Tree"));
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (window), sw);
+ gtk_window_set_default_size (GTK_WINDOW (window), 300, 600);
+
+ dtv = diagram_tree_view_new ();
+ gtk_container_add (GTK_CONTAINER (sw), dtv);
+ /* expand all rows after the treeview widget has been realized */
+ g_signal_connect (dtv, "realize",
+ G_CALLBACK (gtk_tree_view_expand_all), NULL);
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ }
+ gtk_window_present (GTK_WINDOW(window));
+}
diff --git a/app/makefile.msc b/app/makefile.msc
index ca6b773..1c9fa77 100644
--- a/app/makefile.msc
+++ b/app/makefile.msc
@@ -74,7 +74,10 @@ OBJECTS = \
textedit.obj \
textedit_tool.obj \
tool.obj \
- undo.obj
+ undo.obj \
+ \
+ diagram_tree_model.obj \
+ diagram_tree_view.obj \
ICON_PNG_PAIRS = \
dia_connectable_icon pixmaps\connectable.png \
diff --git a/app/menus.c b/app/menus.c
index d884f80..81bd30b 100644
--- a/app/menus.c
+++ b/app/menus.c
@@ -94,10 +94,12 @@ static const GtkActionEntry toolbox_entries[] =
{ "FilePlugins", NULL, N_("Plugins..."), NULL, NULL, G_CALLBACK (file_plugins_callback) }
};
+extern void diagram_tree_show(void);
/* Toggle-Actions for toolbox menu */
static const GtkToggleActionEntry toolbox_toggle_entries[] =
{
- { "FileTree", NULL, N_("_Diagram tree..."), "F8", NULL, G_CALLBACK (diagtree_show_callback) }
+ { "FileTree", NULL, N_("_Diagram tree..."), "F8", NULL, G_CALLBACK (diagtree_show_callback) },
+ { "DiagramTree", NULL, N_("_Diagram tree"), NULL, NULL, G_CALLBACK (diagram_tree_show) }
};
/* Toggle-Actions for toolbox menu */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]