Log name of expander function.
[geda-gaf/berndj.git] / gschem / src / x_sloteditor.c
bloba8de43944a75229562992109671ad4b03ec12fdc
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * x_sloteditor.c - A dialog to edit slots in a schematic.
4 * Copyright (C) 2008 Bernd Jendrissek <bernd.jendrissek@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdarg.h>
23 #include <gtk/gtk.h>
25 #include <libgeda/libgeda.h>
27 #include "glade_compat.h"
28 #include "gschem_struct.h"
29 #include "globals.h"
30 #include "prototype.h"
31 #include "x_sloteditor.h"
33 enum slot_editor_columns {
34 /* Visible columns: */
35 SLOT_EDITOR_FRIENDLY_NAME,
36 /* Invisible columns: */
37 SLOT_EDITOR_OBJECT,
38 SLOT_EDITOR_SIGNAL_HANDLER,
39 /* Total number of columns: */
40 SLOT_EDITOR_N_COLUMNS
43 enum slot_editor_properties {
44 PROP_ZERO,
45 PROP_W_CURRENT,
48 /* Class and instance methods. */
49 static void slot_editor_class_init(gpointer g_class, gpointer class_data);
50 static void slot_editor_init(GTypeInstance *instance, gpointer g_class);
51 static void slot_editor_dispose(GObject *object);
52 static void slot_editor_finalize(GObject *object);
53 static void slot_editor_set_property(GObject *object,
54 guint property_id,
55 GValue const *value,
56 GParamSpec *pspec);
57 static void slot_editor_get_property(GObject *object,
58 guint property_id,
59 GValue *value,
60 GParamSpec *pspec);
62 /* Signal handlers. */
63 void slot_editor_row_activated(GtkTreeView *treeview,
64 GtkTreePath *path,
65 GtkTreeViewColumn *column,
66 gpointer user_data);
68 static GObjectClass *slot_editor_parent_class = NULL;
70 GType slot_editor_get_type(void)
72 static GType slot_editor_type = 0;
74 if (!slot_editor_type) {
75 static const GTypeInfo slot_editor_info = {
76 sizeof(SlotEditorClass),
77 NULL, /* base_init */
78 NULL, /* base_finalize */
79 (GClassInitFunc) slot_editor_class_init,
80 NULL, /* class_finalize */
81 NULL, /* class_data */
82 sizeof (SlotEditor),
83 0, /* n_preallocs */
84 (GInstanceInitFunc) slot_editor_init,
87 slot_editor_type = g_type_register_static(G_TYPE_OBJECT,
88 "Sloteditor",
89 &slot_editor_info, 0);
92 return slot_editor_type;
95 static void slot_editor_class_init(gpointer g_class, gpointer class_data)
97 GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
99 slot_editor_parent_class = g_type_class_peek_parent(gobject_class);
101 gobject_class->set_property = &slot_editor_set_property;
102 gobject_class->get_property = &slot_editor_get_property;
103 gobject_class->dispose = &slot_editor_dispose;
104 gobject_class->finalize = &slot_editor_finalize;
106 g_object_class_install_property(gobject_class, PROP_W_CURRENT,
107 g_param_spec_pointer("w_current", "", "",
108 G_PARAM_WRITABLE));
111 gboolean slot_editor_delete(GtkWidget *widget, GdkEvent *event,
112 gpointer user_data)
114 SlotEditor *se;
116 g_object_get(widget, "user-data", &se, NULL);
118 /* The dialog window "owns" the SlotEditor: drop the reference. */
119 g_object_unref(se);
121 /* Let the default handler destroy the window (?). */
122 return FALSE;
125 static gboolean slot_editor_dispose_row(GtkTreeModel *model,
126 GtkTreePath *path,
127 GtkTreeIter *iter,
128 gpointer data)
130 OBJECT *o;
131 gulong handler_id;
133 gtk_tree_model_get(model, iter,
134 SLOT_EDITOR_OBJECT, &o,
135 SLOT_EDITOR_SIGNAL_HANDLER, &handler_id,
136 -1);
138 g_signal_handler_disconnect(o, handler_id);
140 return FALSE;
143 void slot_editor_delete_row(GtkButton *button, gpointer user_data)
145 GtkTreeSelection *sel;
146 GtkTreeModel *model;
147 GtkTreeIter row;
148 SlotEditor *se;
150 g_object_get(button, "user-data", &se, NULL);
152 sel = gtk_tree_view_get_selection(se->treeview);
153 if (gtk_tree_selection_get_selected(sel, &model, &row)) {
154 OBJECT *o, **attribs;
155 int i;
157 gtk_tree_model_get(model, &row,
158 SLOT_EDITOR_OBJECT, &o,
159 -1);
161 gtk_tree_store_remove(se->treestore, &row);
163 /* First, free all the attributes attached to the slot. */
164 attribs = o_attrib_return_attribs(o);
165 for (i = 0; attribs && attribs[i]; i++) {
166 s_delete(se->w_current->toplevel, attribs[i]);
168 o_attrib_free_returned(attribs);
170 /* s_delete() will implicitly destroy the OBJECT_EVENT_CHANGED observer. */
171 s_delete(se->w_current->toplevel, o);
175 void slot_editor_edit(GtkButton *button, gpointer user_data)
177 SlotEditor *se;
179 g_object_get(button, "user-data", &se, NULL);
181 slot_editor_row_activated(se->treeview, NULL, NULL, NULL);
184 void slot_editor_finish(GtkButton *button, gpointer user_data)
186 SlotEditor *se;
188 g_object_get(button, "user-data", &se, NULL);
190 gtk_widget_destroy(GTK_WIDGET(se->sewindow));
192 /* The dialog window "owns" the SlotEditor: drop the reference. */
193 g_object_unref(se);
196 static gboolean slot_editor_update_name(GtkTreeModel *model,
197 GtkTreePath *path,
198 GtkTreeIter *iter,
199 gpointer data)
201 OBJECT *subject = data;
202 OBJECT *o;
204 gtk_tree_model_get(model, iter,
205 SLOT_EDITOR_OBJECT, &o,
206 -1);
207 if (o == subject) {
208 gtk_tree_store_set(GTK_TREE_STORE(model), iter,
209 SLOT_EDITOR_FRIENDLY_NAME, g_strdup(subject->slot->name),
210 -1);
213 return FALSE;
216 static void slot_editor_notice_changed(OBJECT *subject, SlotEditor *se)
218 g_message("slot_editor_notice_changed: %p has changed to %s\n",
219 subject, subject->slot->name);
220 gtk_tree_model_foreach(GTK_TREE_MODEL(se->treestore),
221 &slot_editor_update_name, subject);
224 void slot_editor_new_row(GtkButton *button, gpointer user_data)
226 GtkTreeIter newrow;
227 GtkTreeViewColumn *column;
228 GtkTreePath *path;
229 SlotEditor *se;
230 TOPLEVEL *toplevel;
231 OBJECT *slot;
232 gulong handler_id;
234 g_object_get(button, "user-data", &se, NULL);
235 toplevel = se->w_current->toplevel;
237 /* Add a new, empty slot to the current page. */
238 slot = s_slot_read(toplevel, "S");
239 s_page_append(toplevel->page_current, slot);
241 /* Keep an eye on this new slot. */
242 handler_id = g_signal_connect(G_OBJECT(slot), "changed",
243 G_CALLBACK(slot_editor_notice_changed), se);
244 g_assert(handler_id);
246 gtk_tree_store_append(se->treestore, &newrow, NULL);
247 gtk_tree_store_set(se->treestore, &newrow,
248 SLOT_EDITOR_FRIENDLY_NAME, g_strdup(""),
249 SLOT_EDITOR_OBJECT, slot,
250 SLOT_EDITOR_SIGNAL_HANDLER, handler_id,
251 -1);
253 /* Focus the name of the new slot. */
254 column = gtk_tree_view_get_column(se->treeview, SLOT_EDITOR_FRIENDLY_NAME);
255 path = gtk_tree_model_get_path(GTK_TREE_MODEL(se->treestore), &newrow);
256 gtk_tree_view_set_cursor(se->treeview, path, column, TRUE);
257 gtk_widget_grab_focus(GTK_WIDGET(se->treeview));
260 void slot_editor_row_activated(GtkTreeView *treeview,
261 GtkTreePath *path,
262 GtkTreeViewColumn *column,
263 gpointer user_data)
265 GSCHEM_TOPLEVEL *w_current;
266 SlotEditor *se;
267 GtkTreeSelection *sel;
268 GtkTreeModel *model;
269 GtkTreeIter row;
270 SELECTION *selection;
272 sel = gtk_tree_view_get_selection(treeview);
273 if (gtk_tree_selection_get_selected(sel, &model, &row)) {
274 OBJECT *o;
276 gtk_tree_model_get(model, &row,
277 SLOT_EDITOR_OBJECT, &o,
278 -1);
280 g_object_get(treeview, "user-data", &se, NULL);
281 w_current = se->w_current;
283 selection = o_selection_new();
284 o_selection_add(selection, o);
285 o_attrib_add_selected(w_current, selection, o);
286 fprintf(stderr, "selected object %s type = %c\n", o->name, o->type);
287 x_multiattrib_open(w_current, selection);
288 x_multiattrib_update(w_current, selection);
292 static void slot_editor_name_edited(GtkCellRendererText *renderer,
293 gchar *path_string,
294 gchar *new_text,
295 gpointer user_data)
297 SlotEditor *se = SLOT_EDITOR(user_data);
298 GtkTreeIter row;
299 GtkTreePath *path;
300 OBJECT *o, *slotname_object;
301 TOPLEVEL *toplevel;
303 /* Update the tree model with the new slot name. */
304 path = gtk_tree_path_new_from_string(path_string);
305 gtk_tree_model_get_iter(GTK_TREE_MODEL(se->treestore), &row, path);
307 gtk_tree_store_set(se->treestore, &row,
308 SLOT_EDITOR_FRIENDLY_NAME, new_text,
309 -1);
311 /* Force the slotname= attribute with the new value. */
312 gtk_tree_model_get(GTK_TREE_MODEL(se->treestore), &row,
313 SLOT_EDITOR_OBJECT, &o,
314 -1);
315 toplevel = se->w_current->toplevel;
317 /* XXX - should factorize this into s_slot_rename(). */
318 g_free(o_attrib_search_name_single_exact(o, "slotname", &slotname_object));
319 if (slotname_object) {
320 o_text_take_string(slotname_object, g_strconcat("slotname=", new_text, NULL));
321 } else {
322 g_free(o_attrib_search_name_single_force(toplevel, o, "slotname",
323 &g_strdup, new_text,
324 &slotname_object));
327 se->page->CHANGED = 1;
330 static void slot_editor_visitor(OBJECT *o, void *context)
332 SlotEditor *se = SLOT_EDITOR(context);
333 GtkTreeIter newrow;
334 gulong handler_id;
336 if (o->type != OBJ_SLOT) {
337 return;
340 handler_id = g_signal_connect(G_OBJECT(o), "changed",
341 G_CALLBACK(slot_editor_notice_changed), se);
342 g_assert(handler_id);
344 gtk_tree_store_append(se->treestore, &newrow, NULL);
345 gtk_tree_store_set(se->treestore, &newrow,
346 SLOT_EDITOR_FRIENDLY_NAME, g_strdup(o->slot->name),
347 SLOT_EDITOR_OBJECT, o,
348 SLOT_EDITOR_SIGNAL_HANDLER, handler_id,
349 -1);
350 fprintf(stderr, "Found slot %s, handler = %lu\n", o->slot->name, handler_id);
353 static void slot_editor_init(GTypeInstance *instance, gpointer g_class)
355 GladeXML *xml;
356 SlotEditor *se = SLOT_EDITOR(instance);
357 GtkWidget *widget;
358 GtkWindow *sewindow;
359 GtkTreeView *treeview;
360 GtkTreeStore *treestore;
361 GtkCellRenderer *renderer;
362 GtkTreeViewColumn *column;
364 widget = x_glade_get_widget(&xml, "slot_editor",
365 "slot_editor_delete",
366 G_CALLBACK(&slot_editor_delete),
367 "slot_editor_delete_row",
368 G_CALLBACK(&slot_editor_delete_row),
369 "slot_editor_edit",
370 G_CALLBACK(&slot_editor_edit),
371 "slot_editor_finish",
372 G_CALLBACK(&slot_editor_finish),
373 "slot_editor_new_row",
374 G_CALLBACK(&slot_editor_new_row),
375 "slot_editor_row_activated",
376 G_CALLBACK(&slot_editor_row_activated),
377 NULL);
378 sewindow = GTK_WINDOW(widget);
380 treeview = GTK_TREE_VIEW(x_lookup_widget_set(xml, "slot_treeview",
381 "user-data", se, NULL));
382 x_lookup_widget_set(xml, "delete_button", "user-data", se, NULL);
383 x_lookup_widget_set(xml, "edit_button", "user-data", se, NULL);
384 x_lookup_widget_set(xml, "new_button", "user-data", se, NULL);
385 x_lookup_widget_set(xml, "ok_button", "user-data", se, NULL);
387 g_object_unref(xml);
389 /* Let the dialog window "own" the SlotEditor. */
390 g_object_set(sewindow, "user-data", se, NULL);
391 g_object_ref(se);
393 treestore = gtk_tree_store_new(SLOT_EDITOR_N_COLUMNS,
394 G_TYPE_STRING,
395 G_TYPE_POINTER,
396 G_TYPE_ULONG);
397 gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(treestore));
398 gtk_tree_view_set_search_column(treeview, SLOT_EDITOR_FRIENDLY_NAME);
400 renderer = gtk_cell_renderer_text_new();
401 g_object_set(renderer, "editable", TRUE, NULL);
402 g_signal_connect(renderer, "edited",
403 G_CALLBACK(&slot_editor_name_edited), se);
405 column = gtk_tree_view_column_new_with_attributes("name", renderer,
406 "text",
407 SLOT_EDITOR_FRIENDLY_NAME,
408 NULL);
410 gtk_tree_view_append_column(treeview, column);
412 se->sewindow = sewindow;
413 se->treeview = treeview;
414 se->treestore = treestore;
415 se->dispose_has_run = FALSE;
418 static void slot_editor_set_property(GObject *object,
419 guint property_id,
420 GValue const *value,
421 GParamSpec *pspec)
423 SlotEditor *se = SLOT_EDITOR(object);
425 switch (property_id) {
426 case PROP_W_CURRENT:
427 se->w_current = g_value_get_pointer(value);
428 /* Also remember which page was the current one. */
429 se->page = se->w_current->toplevel->page_current;
431 gtk_tree_store_clear(se->treestore);
432 s_visit_page(se->w_current->toplevel->page_current,
433 &slot_editor_visitor, se,
434 VISIT_UNORDERED, 1);
435 break;
439 static void slot_editor_get_property(GObject *object,
440 guint property_id,
441 GValue *value,
442 GParamSpec *pspec)
446 static void slot_editor_dispose(GObject *object)
448 SlotEditor *se = SLOT_EDITOR(object);
450 if (se->dispose_has_run) {
451 return;
453 se->dispose_has_run = TRUE;
455 gtk_tree_model_foreach(GTK_TREE_MODEL(se->treestore),
456 &slot_editor_dispose_row, se);
457 g_object_unref(se->treestore);
459 slot_editor_parent_class->dispose(object);
462 static void slot_editor_finalize(GObject *object)
464 /* The window is already dead if our refcount has dropped to zero. */
466 slot_editor_parent_class->finalize(object);
469 static void slot_editor_present(SlotEditor *se)
471 gtk_window_present(se->sewindow);
474 /*! \brief Create the slot chooser dialog
475 * \par Function Description
476 * This function creates the slot chooser dialog.
478 void x_sloteditor_open(GSCHEM_TOPLEVEL *w_current)
480 SlotEditor *se;
482 se = SLOT_EDITOR(g_object_new(TYPE_SLOT_EDITOR,
483 "w_current", w_current,
484 NULL));
486 slot_editor_present(se);
488 g_object_unref(se);