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
25 #include <libgeda/libgeda.h>
27 #include "glade_compat.h"
28 #include "gschem_struct.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: */
38 SLOT_EDITOR_SIGNAL_HANDLER
,
39 /* Total number of columns: */
43 enum slot_editor_properties
{
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
,
57 static void slot_editor_get_property(GObject
*object
,
62 /* Signal handlers. */
63 void slot_editor_row_activated(GtkTreeView
*treeview
,
65 GtkTreeViewColumn
*column
,
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
),
78 NULL
, /* base_finalize */
79 (GClassInitFunc
) slot_editor_class_init
,
80 NULL
, /* class_finalize */
81 NULL
, /* class_data */
84 (GInstanceInitFunc
) slot_editor_init
,
87 slot_editor_type
= g_type_register_static(G_TYPE_OBJECT
,
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", "", "",
111 gboolean
slot_editor_delete(GtkWidget
*widget
, GdkEvent
*event
,
116 g_object_get(widget
, "user-data", &se
, NULL
);
118 /* The dialog window "owns" the SlotEditor: drop the reference. */
121 /* Let the default handler destroy the window (?). */
125 static gboolean
slot_editor_dispose_row(GtkTreeModel
*model
,
133 gtk_tree_model_get(model
, iter
,
134 SLOT_EDITOR_OBJECT
, &o
,
135 SLOT_EDITOR_SIGNAL_HANDLER
, &handler_id
,
138 g_signal_handler_disconnect(o
, handler_id
);
143 void slot_editor_delete_row(GtkButton
*button
, gpointer user_data
)
145 GtkTreeSelection
*sel
;
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
;
157 gtk_tree_model_get(model
, &row
,
158 SLOT_EDITOR_OBJECT
, &o
,
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
)
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
)
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. */
196 static gboolean
slot_editor_update_name(GtkTreeModel
*model
,
201 OBJECT
*subject
= data
;
204 gtk_tree_model_get(model
, iter
,
205 SLOT_EDITOR_OBJECT
, &o
,
208 gtk_tree_store_set(GTK_TREE_STORE(model
), iter
,
209 SLOT_EDITOR_FRIENDLY_NAME
, g_strdup(subject
->slot
->name
),
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
)
227 GtkTreeViewColumn
*column
;
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
,
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
,
262 GtkTreeViewColumn
*column
,
265 GSCHEM_TOPLEVEL
*w_current
;
267 GtkTreeSelection
*sel
;
270 SELECTION
*selection
;
272 sel
= gtk_tree_view_get_selection(treeview
);
273 if (gtk_tree_selection_get_selected(sel
, &model
, &row
)) {
276 gtk_tree_model_get(model
, &row
,
277 SLOT_EDITOR_OBJECT
, &o
,
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
,
297 SlotEditor
*se
= SLOT_EDITOR(user_data
);
300 OBJECT
*o
, *slotname_object
;
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
,
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
,
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
));
322 g_free(o_attrib_search_name_single_force(toplevel
, o
, "slotname",
327 se
->page
->CHANGED
= 1;
330 static void slot_editor_visitor(OBJECT
*o
, void *context
)
332 SlotEditor
*se
= SLOT_EDITOR(context
);
336 if (o
->type
!= OBJ_SLOT
) {
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
,
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
)
356 SlotEditor
*se
= SLOT_EDITOR(instance
);
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
),
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
),
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
);
389 /* Let the dialog window "own" the SlotEditor. */
390 g_object_set(sewindow
, "user-data", se
, NULL
);
393 treestore
= gtk_tree_store_new(SLOT_EDITOR_N_COLUMNS
,
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
,
407 SLOT_EDITOR_FRIENDLY_NAME
,
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
,
423 SlotEditor
*se
= SLOT_EDITOR(object
);
425 switch (property_id
) {
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
,
439 static void slot_editor_get_property(GObject
*object
,
446 static void slot_editor_dispose(GObject
*object
)
448 SlotEditor
*se
= SLOT_EDITOR(object
);
450 if (se
->dispose_has_run
) {
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
)
482 se
= SLOT_EDITOR(g_object_new(TYPE_SLOT_EDITOR
,
483 "w_current", w_current
,
486 slot_editor_present(se
);