1 /*
2 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
3 * Copyright (C) 2011 Vivien Malerba <malerba@gnome-db.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include <glib/gi18n-lib.h>
21 #include <string.h>
22 #include "classes-view.h"
23 #include "../dnd.h"
24 #include "../support.h"
25 #include "../gdaui-bar.h"
26 #include "../browser-stock-icons.h"
27 #include <virtual/gda-ldap-connection.h>
28 #include "mgr-ldap-classes.h"
29 #include <libgda-ui/gdaui-tree-store.h>
30 #include <libgda/gda-debug-macros.h>
31
32 struct _ClassesViewPrivate {
33 BrowserConnection *bcnc;
34
35 GdaTree *classes_tree;
36 GdauiTreeStore *classes_store;
37
38 gchar *current_class;
39 };
40
41 static void classes_view_class_init (ClassesViewClass *klass);
42 static void classes_view_init (ClassesView *eview, ClassesViewClass *klass);
43 static void classes_view_dispose (GObject *object);
44
45 static GObjectClass *parent_class = NULL;
46
47
48 /*
49 * ClassesView class implementation
50 */
51
52 static void
classes_view_class_init(ClassesViewClass * klass)53 classes_view_class_init (ClassesViewClass *klass)
54 {
55 GObjectClass *object_class = G_OBJECT_CLASS (klass);
56
57 parent_class = g_type_class_peek_parent (klass);
58
59 object_class->dispose = classes_view_dispose;
60 }
61
62 static void
classes_view_init(ClassesView * eview,G_GNUC_UNUSED ClassesViewClass * klass)63 classes_view_init (ClassesView *eview, G_GNUC_UNUSED ClassesViewClass *klass)
64 {
65 eview->priv = g_new0 (ClassesViewPrivate, 1);
66 eview->priv->current_class = NULL;
67 }
68
69 static void
classes_view_dispose(GObject * object)70 classes_view_dispose (GObject *object)
71 {
72 ClassesView *eview = (ClassesView *) object;
73
74 /* free memory */
75 if (eview->priv) {
76 if (eview->priv->bcnc)
77 g_object_unref (eview->priv->bcnc);
78 if (eview->priv->classes_tree)
79 g_object_unref (eview->priv->classes_tree);
80
81 g_free (eview->priv);
82 eview->priv = NULL;
83 }
84
85 parent_class->dispose (object);
86 }
87
88 GType
classes_view_get_type(void)89 classes_view_get_type (void)
90 {
91 static GType type = 0;
92
93 if (G_UNLIKELY (type == 0)) {
94 static const GTypeInfo info = {
95 sizeof (ClassesViewClass),
96 (GBaseInitFunc) NULL,
97 (GBaseFinalizeFunc) NULL,
98 (GClassInitFunc) classes_view_class_init,
99 NULL,
100 NULL,
101 sizeof (ClassesView),
102 0,
103 (GInstanceInitFunc) classes_view_init,
104 0
105 };
106
107 type = g_type_register_static (GTK_TYPE_TREE_VIEW, "ClassesView", &info, 0);
108 }
109 return type;
110 }
111
112 static gchar *
classes_view_to_selection(G_GNUC_UNUSED ClassesView * eview)113 classes_view_to_selection (G_GNUC_UNUSED ClassesView *eview)
114 {
115 /*
116 GString *string;
117 gchar *tmp;
118 string = g_string_new ("OBJ_TYPE=classes");
119 tmp = gda_rfc1738_encode (eview->priv->schema);
120 g_string_append_printf (string, ";OBJ_SCHEMA=%s", tmp);
121 g_free (tmp);
122 tmp = gda_rfc1738_encode (eview->priv->classes_name);
123 g_string_append_printf (string, ";OBJ_NAME=%s", tmp);
124 g_free (tmp);
125 tmp = gda_rfc1738_encode (eview->priv->classes_short_name);
126 g_string_append_printf (string, ";OBJ_SHORT_NAME=%s", tmp);
127 g_free (tmp);
128 return g_string_free (string, FALSE);
129 */
130 if (eview->priv->current_class)
131 return g_strdup (eview->priv->current_class);
132 else
133 return NULL;
134 }
135
136 static void
source_drag_data_get_cb(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkDragContext * context,GtkSelectionData * selection_data,guint view,G_GNUC_UNUSED guint time,ClassesView * eview)137 source_drag_data_get_cb (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkDragContext *context,
138 GtkSelectionData *selection_data,
139 guint view, G_GNUC_UNUSED guint time, ClassesView *eview)
140 {
141 switch (view) {
142 case TARGET_KEY_VALUE: {
143 gchar *str;
144 str = classes_view_to_selection (eview);
145 gtk_selection_data_set (selection_data,
146 gtk_selection_data_get_target (selection_data), 8, (guchar*) str,
147 strlen (str));
148 g_free (str);
149 break;
150 }
151 default:
152 case TARGET_PLAIN: {
153 gtk_selection_data_set_text (selection_data, classes_view_get_current_class (eview), -1);
154 break;
155 }
156 case TARGET_ROOTWIN:
157 TO_IMPLEMENT; /* dropping on the Root Window => create a file */
158 break;
159 }
160 }
161
162 static void selection_changed_cb (GtkTreeSelection *sel, ClassesView *eview);
163
164 enum {
165 COLUMN_CLASS,
166 COLUMN_ICON,
167 COLUMN_NAME,
168 NUM_COLUMNS
169 };
170
171 static void
text_cell_data_func(G_GNUC_UNUSED GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,G_GNUC_UNUSED gpointer data)172 text_cell_data_func (G_GNUC_UNUSED GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
173 GtkTreeModel *tree_model, GtkTreeIter *iter, G_GNUC_UNUSED gpointer data)
174 {
175 gchar *tmp;
176 gtk_tree_model_get (tree_model, iter,
177 COLUMN_CLASS, &tmp, -1);
178 if (tmp) {
179 g_object_set ((GObject*) cell, "text", tmp,
180 "weight-set", FALSE,
181 "background-set", FALSE,
182 NULL);
183 g_free (tmp);
184 }
185 else {
186 gtk_tree_model_get (tree_model, iter,
187 COLUMN_NAME, &tmp, -1);
188 g_object_set ((GObject*) cell, "text", tmp,
189 "weight", PANGO_WEIGHT_BOLD,
190 "background", "grey", NULL);
191 g_free (tmp);
192 }
193 }
194
195 /**
196 * classes_view_new
197 *
198 * Returns: a new #GtkWidget
199 */
200 GtkWidget *
classes_view_new(BrowserConnection * bcnc,const gchar * classname)201 classes_view_new (BrowserConnection *bcnc, const gchar *classname)
202 {
203 ClassesView *eview;
204
205 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
206
207 eview = CLASSES_VIEW (g_object_new (CLASSES_VIEW_TYPE, NULL));
208 eview->priv->bcnc = g_object_ref ((GObject*) bcnc);
209 g_signal_connect (eview, "drag-data-get",
210 G_CALLBACK (source_drag_data_get_cb), eview);
211
212 GdaTreeManager *mgr;
213 GtkTreeModel *store;
214 GtkCellRenderer *renderer;
215 GtkTreeViewColumn *column;
216 eview->priv->classes_tree = gda_tree_new ();
217 mgr = mgr_ldap_classes_new (eview->priv->bcnc, FALSE, NULL);
218 gda_tree_add_manager (eview->priv->classes_tree, mgr);
219 gda_tree_manager_add_manager (mgr, mgr);
220 gda_tree_update_all (eview->priv->classes_tree, NULL);
221 g_object_unref (mgr);
222
223 store = gdaui_tree_store_new (eview->priv->classes_tree, NUM_COLUMNS,
224 G_TYPE_STRING, "class",
225 G_TYPE_OBJECT, "icon",
226 G_TYPE_STRING, GDA_ATTRIBUTE_NAME);
227 gtk_tree_view_set_model (GTK_TREE_VIEW (eview), GTK_TREE_MODEL (store));
228
229 eview->priv->classes_store = GDAUI_TREE_STORE (store);
230 g_object_unref (G_OBJECT (store));
231
232 column = gtk_tree_view_column_new ();
233
234 renderer = gtk_cell_renderer_pixbuf_new ();
235 gtk_tree_view_column_pack_start (column, renderer, FALSE);
236 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", COLUMN_ICON);
237 g_object_set ((GObject*) renderer, "yalign", 0., NULL);
238
239 renderer = gtk_cell_renderer_text_new ();
240 gtk_tree_view_column_pack_start (column, renderer, TRUE);
241 gtk_tree_view_column_set_cell_data_func (column, renderer,
242 (GtkTreeCellDataFunc) text_cell_data_func,
243 NULL, NULL);
244
245 gtk_tree_view_append_column (GTK_TREE_VIEW (eview), column);
246 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (eview), column);
247 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (eview), FALSE);
248
249 /* tree selection */
250 GtkTreeSelection *sel;
251 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (eview));
252 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
253 g_signal_connect (sel, "changed",
254 G_CALLBACK (selection_changed_cb), eview);
255
256 if (classname)
257 classes_view_set_current_class (eview, classname);
258
259 return (GtkWidget*) eview;
260 }
261
262 static void
selection_changed_cb(GtkTreeSelection * sel,ClassesView * eview)263 selection_changed_cb (GtkTreeSelection *sel, ClassesView *eview)
264 {
265 GtkTreeIter iter;
266 GtkTreeModel *model;
267 if (gtk_tree_selection_get_selected (sel, &model, &iter)) {
268 GdaTreeNode *node;
269 const GValue *cvalue;
270 node = gdaui_tree_store_get_node (GDAUI_TREE_STORE (model), &iter);
271 g_assert (node);
272 cvalue = gda_tree_node_get_node_attribute (node, "class");
273 g_free (eview->priv->current_class);
274 if (cvalue)
275 eview->priv->current_class = g_value_dup_string (cvalue);
276 else
277 eview->priv->current_class = NULL;
278 }
279 }
280
281 /**
282 * classes_view_get_current_class:
283 */
284 const gchar *
classes_view_get_current_class(ClassesView * eview)285 classes_view_get_current_class (ClassesView *eview)
286 {
287 g_return_val_if_fail (IS_CLASSES_VIEW (eview), NULL);
288 return eview->priv->current_class;
289 }
290
291 static GtkTreePath *
search_for_class(GtkTreeModel * model,const gchar * classname,GtkTreeIter * iter)292 search_for_class (GtkTreeModel *model, const gchar *classname, GtkTreeIter *iter)
293 {
294 #ifdef GDA_DEBUG_NO
295 GtkTreePath *debug;
296 if (iter) {
297 debug = gtk_tree_model_get_path (model, iter);
298 g_print ("%s (%s)\n", __FUNCTION__, gtk_tree_path_to_string (debug));
299 gtk_tree_path_free (debug);
300 }
301 else
302 g_print ("%s (TOP)\n", __FUNCTION__);
303 #endif
304
305 if (iter) {
306 /* look in the node itself */
307 gchar *cln = NULL;
308 gtk_tree_model_get (model, iter, COLUMN_CLASS, &cln, -1);
309 if (cln && !strcmp (cln, classname)) {
310 g_free (cln);
311 return gtk_tree_model_get_path (model, iter);
312 }
313 g_free (cln);
314 }
315
316 /* look at the children */
317 GtkTreeIter chiter;
318 if (gtk_tree_model_iter_children (model, &chiter, iter)) {
319 GtkTreePath *path;
320 path = search_for_class (model, classname, &chiter);
321 if (path)
322 return path;
323
324 for (; gtk_tree_model_iter_next (model, &chiter); ) {
325 GtkTreePath *path;
326 path = search_for_class (model, classname, &chiter);
327 if (path)
328 return path;
329 }
330 }
331
332 return NULL;
333 }
334
335 /**
336 * classes_view_set_current_class:
337 */
338 void
classes_view_set_current_class(ClassesView * eview,const gchar * classname)339 classes_view_set_current_class (ClassesView *eview, const gchar *classname)
340 {
341 GtkTreePath *path = NULL;
342 g_return_if_fail (IS_CLASSES_VIEW (eview));
343 g_return_if_fail (classname && *classname);
344
345 path = search_for_class (GTK_TREE_MODEL (eview->priv->classes_store), classname, NULL);
346 if (path) {
347 GtkTreeSelection *sel;
348
349 #ifdef GDA_DEBUG_NO
350 g_print ("Found class [%s] at %s\n", classname, gtk_tree_path_to_string (path));
351 #endif
352 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (eview), path);
353 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (eview), path, NULL, TRUE, .5, 0.);
354
355 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (eview));
356 gtk_tree_selection_select_path (sel, path);
357 gtk_tree_path_free (path);
358 }
359 }
360