1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
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
31 #include <gdk/gdkkeysyms.h>
33 #ifdef HAVE_LIBDMALLOC
38 /*! \brief Update the multiattrib editor dialog when the page's
40 * \par Function Description
41 * When the page's selection changes this function identifies how
42 * many objects which can have attributes are currently selected. If
43 * this number is 1, the dialog is set to edit the attributes of the
44 * first selected object..
46 * \param [in] selection The SELECTION object of page being edited.
47 * \param [in] user_data The multi-attribute editor dialog.
49 static void callback_selection_changed (SELECTION
*selection
,
52 Multiattrib
*multiattrib
= MULTIATTRIB (user_data
);
55 gint object_count
= 0;
57 for (iter
= geda_list_get_glist (selection
);
59 iter
= g_list_next (iter
)) {
60 object
= (OBJECT
*)iter
->data
;
61 g_assert (object
!= NULL
);
63 if (object
->type
== OBJ_COMPLEX
||
64 object
->type
== OBJ_PLACEHOLDER
||
65 object
->type
== OBJ_NET
||
66 object
->type
== OBJ_BUS
||
67 object
->type
== OBJ_PIN
) {
72 if (object_count
== 0) {
73 /* TODO: If the user selects a single attribute which is
74 * not floating, should we find its parent object and
75 * display the multi-attribute editor for that?
76 * Bonus marks for making it jump to the correct attrib.
79 } else if (object_count
== 1) {
80 object
= (OBJECT
*)((geda_list_get_glist (selection
))->data
);
82 /* TODO: Something clever with multiple objects selected */
86 g_object_set (multiattrib
,
91 #define DIALOG_DATA_SELECTION "current-selection"
93 /*! \brief Update the dialog when the current page's SELECTION object
95 * \par Function Description
96 * This handler is called when the g_object_weak_ref() on the
97 * SELECTION object we're watching expires. We reset our
98 * multiattrib->selection pointer to NULL to avoid attempting to
99 * access the destroyed object.
102 * Our signal handlers were automatically disconnected during the
103 * destruction process.
105 * \param [in] data Pointer to the multi-attrib dialog
106 * \param [in] where_the_object_was Pointer to where the object was
109 static void callback_selection_finalized (gpointer data
,
110 GObject
*where_the_object_was
)
112 Multiattrib
*multiattrib
= MULTIATTRIB (data
);
113 g_object_set (multiattrib
,
116 g_object_set_data (G_OBJECT (multiattrib
), DIALOG_DATA_SELECTION
, NULL
);
119 /*! \brief Add link between multiattrib dialog and current selection.
120 * \par Function Description
121 * This function connects a handler to the "changed" signal of
122 * current selection to let the dialog watch it. It also adds a weak
123 * reference on the selection.
125 * \param [in] multiattrib The Multiattrib dialog.
126 * \param [in] selection The selection to watch.
128 static void connect_selection (Multiattrib
*multiattrib
,
129 SELECTION
*selection
)
131 g_assert (g_object_get_data (G_OBJECT (multiattrib
),
132 DIALOG_DATA_SELECTION
) == NULL
);
133 g_object_set_data (G_OBJECT (multiattrib
), DIALOG_DATA_SELECTION
, selection
);
134 g_object_weak_ref (G_OBJECT (selection
),
135 callback_selection_finalized
,
137 g_signal_connect (selection
,
139 (GCallback
)callback_selection_changed
,
141 /* Synthesise a selection changed update to refresh the view */
142 callback_selection_changed (selection
, multiattrib
);
145 /*! \brief Remove the link between multiattrib dialog and selection.
146 * \par Function Description
147 * If the dialog is watching a selection, this function disconnects
148 * the "changed" signal and removes the weak reference it previously
151 * \param [in] multiattrib The Multiattrib dialog.
153 static void disconnect_selection (Multiattrib
*multiattrib
) {
154 SELECTION
*selection
;
156 /* get selection watched from dialog data */
157 selection
= (SELECTION
*)g_object_get_data (G_OBJECT (multiattrib
),
158 DIALOG_DATA_SELECTION
);
159 if (selection
== NULL
) {
160 /* no selection watched */
164 g_signal_handlers_disconnect_matched (selection
,
165 G_SIGNAL_MATCH_FUNC
|
168 callback_selection_changed
,
170 g_object_weak_unref (G_OBJECT (selection
),
171 callback_selection_finalized
,
174 /* reset dialog data */
175 g_object_set_data (G_OBJECT (multiattrib
), DIALOG_DATA_SELECTION
, NULL
);
178 /*! \brief Process the response returned by the multi-attribte dialog.
179 * \par Function Description
180 * This function handles the response <B>arg1</B> of the multi-attribute
181 * editor dialog <B>dialog</B>.
183 * \param [in] dialog The multi-attribute editor dialog.
184 * \param [in] arg1 The response ID.
185 * \param [in] user_data A pointer on the GSCHEM_TOPLEVEL environment.
188 multiattrib_callback_response (GtkDialog
*dialog
,
192 GSCHEM_TOPLEVEL
*w_current
= (GSCHEM_TOPLEVEL
*)user_data
;
195 case GTK_RESPONSE_CLOSE
:
196 case GTK_RESPONSE_DELETE_EVENT
:
197 /* cut link from dialog to selection */
198 disconnect_selection (MULTIATTRIB (w_current
->mawindow
));
199 gtk_widget_destroy (GTK_WIDGET (dialog
));
200 w_current
->mawindow
= NULL
;
205 /*! \brief Open multiple attribute editor dialog.
206 * \par Function Description
207 * Opens the multiple attribute editor dialog for objects in this <B>toplevel</B>.
209 * \param [in] w_current The GSCHEM_TOPLEVEL object.
211 void x_multiattrib_open (GSCHEM_TOPLEVEL
*w_current
)
213 if ( w_current
->mawindow
== NULL
) {
214 w_current
->mawindow
=
215 GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB
,
218 "settings-name", "multiattrib",
219 "gschem-toplevel", w_current
,
222 gtk_window_set_transient_for (GTK_WINDOW(w_current
->mawindow
),
223 GTK_WINDOW(w_current
->main_window
));
225 g_signal_connect (w_current
->mawindow
,
227 G_CALLBACK (multiattrib_callback_response
),
230 /* attach dialog to selection of current page */
231 x_multiattrib_update (w_current
);
233 gtk_widget_show (w_current
->mawindow
);
235 gtk_window_present (GTK_WINDOW(w_current
->mawindow
));
240 /*! \brief Close the multiattrib dialog.
242 * \par Function Description
244 * Closes the multiattrib dialog associated with <B>w_current</B>.
246 * \param [in] w_current The GSCHEM_TOPLEVEL object.
248 void x_multiattrib_close (GSCHEM_TOPLEVEL
*w_current
)
250 if (w_current
->mawindow
!= NULL
) {
251 /* cut link from dialog to selection */
252 disconnect_selection (MULTIATTRIB (w_current
->mawindow
));
253 gtk_widget_destroy (w_current
->mawindow
);
254 w_current
->mawindow
= NULL
;
258 /*! \brief Update the multiattrib editor dialog for a GSCHEM_TOPLEVEL.
260 * \par Function Description
262 * If the GSCHEM_TOPLEVEL has an open multiattrib dialog, switch to
263 * watching the current page's SELECTION object for changes.
265 * \param [in] w_current The GSCHEM_TOPLEVEL object.
267 void x_multiattrib_update( GSCHEM_TOPLEVEL
*w_current
)
269 if (!IS_MULTIATTRIB (w_current
->mawindow
)) {
273 /* disconnect dialog from previous selection */
274 disconnect_selection (MULTIATTRIB (w_current
->mawindow
));
275 /* connect the dialog to the selection of the current page */
276 connect_selection (MULTIATTRIB (w_current
->mawindow
),
277 w_current
->toplevel
->page_current
->selection_list
);
281 /*! \section celltextview-widget Cell TextView Widget Code.
282 * This widget makes a 'GtkTextView' widget implements the 'GtkCellEditable'
283 * interface. It can then be used to renderer multi-line texts inside
284 * tree views ('GtkTreeView').
286 static void celltextview_class_init (CellTextViewClass
*klass
);
287 static void celltextview_init (CellTextView
*self
);
288 static void celltextview_cell_editable_init (GtkCellEditableIface
*iface
);
290 /*! \todo Finish function documentation
292 * \par Function Description
295 static gboolean
celltextview_key_press_event (GtkWidget
*widget
,
296 GdkEventKey
*key_event
,
299 CellTextView
*celltextview
= (CellTextView
*)widget
;
301 /* If the Escape key is pressed, we flag the edit as canceled */
302 if (key_event
->keyval
== GDK_Escape
)
303 celltextview
->editing_canceled
= TRUE
;
305 /* ends editing of cell if one of these keys are pressed or editing is canceled */
306 if (celltextview
->editing_canceled
== TRUE
||
307 /* the Enter key without the Control modifier */
308 (!(key_event
->state
& GDK_CONTROL_MASK
) &&
309 (key_event
->keyval
== GDK_Return
||
310 key_event
->keyval
== GDK_KP_Enter
))) {
311 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (celltextview
));
312 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (celltextview
));
319 /*! \todo Finish function documentation
321 * \par Function Description
324 static void celltextview_start_editing (GtkCellEditable
*cell_editable
,
327 g_signal_connect (cell_editable
,
329 G_CALLBACK (celltextview_key_press_event
),
334 /*! \todo Finish function documentation
336 * \par Function Description
339 GType
celltextview_get_type()
341 static GType celltextview_type
= 0;
343 if (!celltextview_type
) {
344 static const GTypeInfo celltextview_info
= {
345 sizeof(CellTextViewClass
),
346 NULL
, /* base_init */
347 NULL
, /* base_finalize */
348 (GClassInitFunc
) celltextview_class_init
,
349 NULL
, /* class_finalize */
350 NULL
, /* class_data */
351 sizeof(CellTextView
),
353 (GInstanceInitFunc
) celltextview_init
,
356 static const GInterfaceInfo cell_editable_info
= {
357 (GInterfaceInitFunc
) celltextview_cell_editable_init
,
358 NULL
, /* interface_finalize */
359 NULL
/* interface_data */
362 celltextview_type
= g_type_register_static(GTK_TYPE_TEXT_VIEW
,
364 &celltextview_info
, 0);
365 g_type_add_interface_static(celltextview_type
,
366 GTK_TYPE_CELL_EDITABLE
,
367 &cell_editable_info
);
370 return celltextview_type
;
373 /*! \todo Finish function documentation
375 * \par Function Description
378 static void celltextview_class_init(CellTextViewClass
*klass
)
380 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
383 /*! \todo Finish function documentation
385 * \par Function Description
388 static void celltextview_init(CellTextView
*celltextview
)
390 celltextview
->editing_canceled
= FALSE
;
393 /*! \todo Finish function documentation
395 * \par Function Description
398 static void celltextview_cell_editable_init(GtkCellEditableIface
*iface
)
400 iface
->start_editing
= celltextview_start_editing
;
403 /*! \section multi-line-text-cell-renderer Multi-line Text Cell Renderer
404 * GTK has no multi-line text cell renderer. This code adds one to be used
405 * in gschem code. It is inspired by the 'GtkCellRendererCombo' renderer
408 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
);
409 static void cellrenderermultilinetext_editing_done (GtkCellEditable
*cell_editable
,
411 static gboolean
cellrenderermultilinetext_focus_out_event (GtkWidget
*widget
,
416 #define CELL_RENDERER_MULTI_LINE_TEXT_PATH "cell-renderer-multi-line-text-path"
419 /*! \todo Finish function documentation
421 * \par Function Description
424 static GtkCellEditable
* cellrenderermultilinetext_start_editing(GtkCellRenderer
*cell
,
428 GdkRectangle
*background_area
,
429 GdkRectangle
*cell_area
,
430 GtkCellRendererState flags
)
432 GtkCellRendererText
*cell_text
;
433 CellRendererMultiLineText
*cell_mlt
;
435 GtkTextBuffer
*textbuffer
;
437 cell_text
= GTK_CELL_RENDERER_TEXT (cell
);
438 if (cell_text
->editable
== FALSE
) {
442 cell_mlt
= CELL_RENDERER_MULTI_LINE_TEXT (cell
);
444 textbuffer
= GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER
,
446 gtk_text_buffer_set_text (textbuffer
,
448 strlen (cell_text
->text
));
450 textview
= GTK_WIDGET (g_object_new (TYPE_CELL_TEXT_VIEW
,
452 "buffer", textbuffer
,
455 "height-request", cell_area
->height
,
457 g_object_set_data_full (G_OBJECT (textview
),
458 CELL_RENDERER_MULTI_LINE_TEXT_PATH
,
459 g_strdup (path
), g_free
);
461 gtk_widget_show (textview
);
463 g_signal_connect (GTK_CELL_EDITABLE (textview
),
465 G_CALLBACK (cellrenderermultilinetext_editing_done
),
467 cell_mlt
->focus_out_id
=
468 g_signal_connect (textview
,
470 G_CALLBACK (cellrenderermultilinetext_focus_out_event
),
473 return GTK_CELL_EDITABLE (textview
);
476 /*! \todo Finish function documentation
478 * \par Function Description
481 static void cellrenderermultilinetext_editing_done(GtkCellEditable
*cell_editable
,
484 CellRendererMultiLineText
*cell
= CELL_RENDERER_MULTI_LINE_TEXT (user_data
);
485 GtkTextBuffer
*buffer
;
486 GtkTextIter start
, end
;
490 if (cell
->focus_out_id
> 0) {
491 g_signal_handler_disconnect (cell_editable
,
493 cell
->focus_out_id
= 0;
496 if (CELL_TEXT_VIEW (cell_editable
)->editing_canceled
) {
497 g_signal_emit_by_name (cell
, "editing-canceled");
501 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (cell_editable
));
502 gtk_text_buffer_get_start_iter (buffer
, &start
);
503 gtk_text_buffer_get_end_iter (buffer
, &end
);
504 new_text
= gtk_text_buffer_get_text (buffer
, &start
, &end
, TRUE
);
506 path
= g_object_get_data (G_OBJECT (cell_editable
),
507 CELL_RENDERER_MULTI_LINE_TEXT_PATH
);
508 g_signal_emit_by_name (cell
, "edited", path
, new_text
);
514 /*! \todo Finish function documentation
516 * \par Function Description
519 static gboolean
cellrenderermultilinetext_focus_out_event(GtkWidget
*widget
,
523 cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget
),
529 /*! \todo Finish function documentation
531 * \par Function Description
534 GType
cellrenderermultilinetext_get_type()
536 static GType cellrenderermultilinetext_type
= 0;
538 if (!cellrenderermultilinetext_type
) {
539 static const GTypeInfo cellrenderermultilinetext_info
= {
540 sizeof(CellRendererMultiLineTextClass
),
541 NULL
, /* base_init */
542 NULL
, /* base_finalize */
543 (GClassInitFunc
) cellrenderermultilinetext_class_init
,
544 NULL
, /* class_finalize */
545 NULL
, /* class_data */
546 sizeof(CellRendererMultiLineText
),
548 NULL
, /* instance_init */
551 cellrenderermultilinetext_type
= g_type_register_static (
552 GTK_TYPE_CELL_RENDERER_TEXT
,
553 "CellRendererMultiLineText",
554 &cellrenderermultilinetext_info
, 0);
557 return cellrenderermultilinetext_type
;
560 /*! \todo Finish function documentation
562 * \par Function Description
565 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
)
567 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
568 GtkCellRendererClass
*cell_class
= GTK_CELL_RENDERER_CLASS (klass
);
570 cell_class
->start_editing
= cellrenderermultilinetext_start_editing
;
584 static GObjectClass
*multiattrib_parent_class
= NULL
;
586 static void multiattrib_class_init (MultiattribClass
*class);
587 static void multiattrib_init (Multiattrib
*multiattrib
);
588 static void multiattrib_set_property (GObject
*object
,
592 static void multiattrib_get_property (GObject
*object
,
597 static void multiattrib_popup_menu (Multiattrib
*multiattrib
,
598 GdkEventButton
*event
);
601 /*! \todo Finish function documentation
603 * \par Function Description
606 static void multiattrib_action_add_attribute(GSCHEM_TOPLEVEL
*w_current
,
608 Multiattrib
*multiattrib
,
612 gint show_name_value
)
617 newtext
= g_strdup_printf ("%s=%s", name
, value
);
619 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
624 /* create a new attribute and link it */
625 o_attrib
= o_attrib_add_attrib (w_current
, newtext
,
626 visible
, show_name_value
, object
);
628 w_current
->toplevel
->page_current
->CHANGED
= 1;
629 o_undo_savestate (w_current
, UNDO_ALL
);
635 /*! \todo Finish function documentation
637 * \par Function Description
640 static void multiattrib_action_duplicate_attribute(GSCHEM_TOPLEVEL
*w_current
,
646 o_new
= o_attrib_add_attrib (w_current
,
647 o_text_get_string (w_current
->toplevel
, o_attrib
),
648 o_attrib
->visibility
,
649 o_attrib
->show_name_value
,
651 w_current
->toplevel
->page_current
->CHANGED
= 1;
652 o_undo_savestate (w_current
, UNDO_ALL
);
656 /*! \todo Finish function documentation
658 * \par Function Description
661 static void multiattrib_action_promote_attribute (GSCHEM_TOPLEVEL
*w_current
,
665 TOPLEVEL
*toplevel
= w_current
->toplevel
;
668 if (o_attrib
->visibility
) {
669 /* If the attribute we're promoting is visible, don't clone its location */
670 o_new
= o_attrib_add_attrib (w_current
,
671 o_text_get_string (w_current
->toplevel
, o_attrib
),
672 o_attrib
->visibility
,
673 o_attrib
->show_name_value
,
676 /* make a copy of the attribute object */
677 o_new
= o_object_copy (toplevel
, o_attrib
, NORMAL_FLAG
);
678 s_page_append (toplevel
, toplevel
->page_current
, o_new
);
679 /* add the attribute its parent */
680 o_attrib_attach (toplevel
, o_new
, object
, TRUE
);
681 /* redraw the attribute object */
682 o_invalidate (w_current
, o_new
);
683 /* note: this object is unselected (not added to selection). */
685 w_current
->toplevel
->page_current
->CHANGED
= 1;
686 o_undo_savestate (w_current
, UNDO_ALL
);
689 /*! \todo Finish function documentation
691 * \par Function Description
694 static void multiattrib_action_delete_attribute(GSCHEM_TOPLEVEL
*w_current
,
697 /* actually deletes the attribute */
698 o_selection_remove (w_current
->toplevel
,
699 w_current
->toplevel
->page_current
->selection_list
,
701 o_delete (w_current
, o_attrib
);
702 w_current
->toplevel
->page_current
->CHANGED
=1;
703 o_undo_savestate (w_current
, UNDO_ALL
);
707 /*! \todo Finish function documentation
709 * \par Function Description
712 static void multiattrib_column_set_data_name(GtkTreeViewColumn
*tree_column
,
713 GtkCellRenderer
*cell
,
714 GtkTreeModel
*tree_model
,
720 Multiattrib
*dialog
= (Multiattrib
*) data
;
723 gtk_tree_model_get (tree_model
, iter
,
724 COLUMN_ATTRIBUTE
, &o_attrib
,
726 g_assert (o_attrib
->type
== OBJ_TEXT
);
728 inherited
= o_attrib_is_inherited (o_attrib
);
730 o_attrib_get_name_value (o_attrib
, &name
, NULL
);
733 "foreground-gdk", inherited
? &dialog
->insensitive_text_color
: NULL
,
734 "editable", !inherited
,
740 /*! \todo Finish function documentation
742 * \par Function Description
745 static void multiattrib_column_set_data_value(GtkTreeViewColumn
*tree_column
,
746 GtkCellRenderer
*cell
,
747 GtkTreeModel
*tree_model
,
753 Multiattrib
*dialog
= (Multiattrib
*) data
;
756 gtk_tree_model_get (tree_model
, iter
,
757 COLUMN_ATTRIBUTE
, &o_attrib
,
759 g_assert (o_attrib
->type
== OBJ_TEXT
);
761 inherited
= o_attrib_is_inherited (o_attrib
);
763 o_attrib_get_name_value (o_attrib
, NULL
, &value
);
766 "foreground-gdk", inherited
? &dialog
->insensitive_text_color
: NULL
,
767 "editable", !inherited
,
773 /*! \todo Finish function documentation
775 * \par Function Description
778 static void multiattrib_column_set_data_visible(GtkTreeViewColumn
*tree_column
,
779 GtkCellRenderer
*cell
,
780 GtkTreeModel
*tree_model
,
787 gtk_tree_model_get (tree_model
, iter
,
788 COLUMN_ATTRIBUTE
, &o_attrib
,
790 g_assert (o_attrib
->type
== OBJ_TEXT
);
792 inherited
= o_attrib_is_inherited (o_attrib
);
795 "active", (o_attrib
->visibility
== VISIBLE
),
796 "sensitive", !inherited
,
797 "activatable", !inherited
,
802 /*! \todo Finish function documentation
804 * \par Function Description
807 static void multiattrib_column_set_data_show_name(GtkTreeViewColumn
*tree_column
,
808 GtkCellRenderer
*cell
,
809 GtkTreeModel
*tree_model
,
816 gtk_tree_model_get (tree_model
, iter
,
817 COLUMN_ATTRIBUTE
, &o_attrib
,
819 g_assert (o_attrib
->type
== OBJ_TEXT
);
821 inherited
= o_attrib_is_inherited (o_attrib
);
824 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
825 o_attrib
->show_name_value
== SHOW_NAME
),
826 "sensitive", !inherited
,
827 "activatable", !inherited
,
832 /*! \todo Finish function documentation
834 * \par Function Description
837 static void multiattrib_column_set_data_show_value(GtkTreeViewColumn
*tree_column
,
838 GtkCellRenderer
*cell
,
839 GtkTreeModel
*tree_model
,
846 gtk_tree_model_get (tree_model
, iter
,
847 COLUMN_ATTRIBUTE
, &o_attrib
,
849 g_assert (o_attrib
->type
== OBJ_TEXT
);
851 inherited
= o_attrib_is_inherited (o_attrib
);
854 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
855 o_attrib
->show_name_value
== SHOW_VALUE
),
856 "sensitive", !inherited
,
857 "activatable", !inherited
,
862 /*! \brief Requests an update of the display of a row.
863 * \par Function Description
864 * This is an helper function to update the display of a row when
865 * data for this row have been modified in the model.
867 * It emits the 'row_changed' signal on the pointed row.
869 * \param [in] model A GtkTreeModel.
870 * \param [in] iter A valid GtkTreeIter pointing to the changed row.
873 update_row_display (GtkTreeModel
*model
, GtkTreeIter
*iter
)
877 path
= gtk_tree_model_get_path (model
, iter
);
878 gtk_tree_model_row_changed (model
, path
, iter
);
879 gtk_tree_path_free (path
);
883 /*! \todo Finish function documentation
885 * \par Function Description
888 static void multiattrib_callback_edited_name(GtkCellRendererText
*cellrenderertext
,
893 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
897 GSCHEM_TOPLEVEL
*w_current
;
898 gchar
*value
, *newtext
;
900 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
901 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
903 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
907 if (g_ascii_strcasecmp (arg2
, "") == 0) {
908 GtkWidget
*dialog
= gtk_message_dialog_new (
909 GTK_WINDOW (multiattrib
),
913 _("Attributes with empty name are not allowed. Please set a name."));
915 gtk_dialog_run (GTK_DIALOG (dialog
));
916 gtk_widget_destroy (dialog
);
920 gtk_tree_model_get (model
, &iter
,
921 COLUMN_ATTRIBUTE
, &o_attrib
,
923 g_assert (o_attrib
->type
== OBJ_TEXT
);
925 o_attrib_get_name_value (o_attrib
, NULL
, &value
);
926 newtext
= g_strdup_printf ("%s=%s", arg2
, value
);
928 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
935 /* actually modifies the attribute */
936 o_text_change (w_current
, o_attrib
,
937 newtext
, o_attrib
->visibility
, o_attrib
->show_name_value
);
944 /*! \todo Finish function documentation
946 * \par Function Description
949 static void multiattrib_callback_edited_value(GtkCellRendererText
*cell_renderer
,
954 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
958 GSCHEM_TOPLEVEL
*w_current
;
959 gchar
*name
, *newtext
;
961 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
962 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
964 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
968 gtk_tree_model_get (model
, &iter
,
969 COLUMN_ATTRIBUTE
, &o_attrib
,
971 g_assert (o_attrib
->type
== OBJ_TEXT
);
973 o_attrib_get_name_value (o_attrib
, &name
, NULL
);
974 newtext
= g_strdup_printf ("%s=%s", name
, arg2
);
976 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
982 /* actually modifies the attribute */
983 o_text_change (w_current
, o_attrib
,
984 newtext
, o_attrib
->visibility
, o_attrib
->show_name_value
);
986 /* request an update of display for this row */
987 update_row_display (model
, &iter
);
994 /*! \todo Finish function documentation
996 * \par Function Description
999 static void multiattrib_callback_toggled_visible(GtkCellRendererToggle
*cell_renderer
,
1003 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1004 GtkTreeModel
*model
;
1007 GSCHEM_TOPLEVEL
*w_current
;
1010 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
1011 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1013 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
1017 gtk_tree_model_get (model
, &iter
,
1018 COLUMN_ATTRIBUTE
, &o_attrib
,
1020 g_assert (o_attrib
->type
== OBJ_TEXT
);
1021 o_invalidate (w_current
, o_attrib
);
1023 visibility
= o_attrib
->visibility
== VISIBLE
? INVISIBLE
: VISIBLE
;
1025 /* actually modifies the attribute */
1026 o_attrib
->visibility
= visibility
;
1027 o_text_recreate (w_current
->toplevel
, o_attrib
);
1028 o_invalidate (w_current
, o_attrib
);
1029 o_undo_savestate (w_current
, UNDO_ALL
);
1031 /* request an update of display for this row */
1032 update_row_display (model
, &iter
);
1036 /*! \todo Finish function documentation
1038 * \par Function Description
1041 static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle
*cell_renderer
,
1045 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1046 GtkTreeModel
*model
;
1049 GSCHEM_TOPLEVEL
*w_current
;
1052 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
1053 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1055 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
1059 gtk_tree_model_get (model
, &iter
,
1060 COLUMN_ATTRIBUTE
, &o_attrib
,
1062 g_assert (o_attrib
->type
== OBJ_TEXT
);
1063 o_invalidate (w_current
, o_attrib
);
1065 switch (o_attrib
->show_name_value
) {
1066 case SHOW_NAME_VALUE
: new_snv
= SHOW_VALUE
; break;
1067 case SHOW_NAME
: new_snv
= SHOW_VALUE
; break;
1068 case SHOW_VALUE
: new_snv
= SHOW_NAME_VALUE
; break;
1070 g_assert_not_reached ();
1071 new_snv
= SHOW_NAME_VALUE
;
1074 /* actually modifies the attribute */
1075 o_attrib
->show_name_value
= new_snv
;
1076 o_text_recreate (w_current
->toplevel
, o_attrib
);
1077 o_invalidate (w_current
, o_attrib
);
1078 o_undo_savestate (w_current
, UNDO_ALL
);
1080 /* request an update of display for this row */
1081 update_row_display (model
, &iter
);
1085 /*! \todo Finish function documentation
1087 * \par Function Description
1090 static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle
*cell_renderer
,
1094 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1095 GtkTreeModel
*model
;
1098 GSCHEM_TOPLEVEL
*w_current
;
1101 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
1102 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1104 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
1108 gtk_tree_model_get (model
, &iter
,
1109 COLUMN_ATTRIBUTE
, &o_attrib
,
1111 g_assert (o_attrib
->type
== OBJ_TEXT
);
1112 o_invalidate (w_current
, o_attrib
);
1114 switch (o_attrib
->show_name_value
) {
1115 case SHOW_NAME_VALUE
: new_snv
= SHOW_NAME
; break;
1116 case SHOW_NAME
: new_snv
= SHOW_NAME_VALUE
; break;
1117 case SHOW_VALUE
: new_snv
= SHOW_NAME
; break;
1119 g_assert_not_reached ();
1120 new_snv
= SHOW_NAME_VALUE
;
1123 /* actually modifies the attribute */
1124 o_attrib
->show_name_value
= new_snv
;
1125 o_text_recreate (w_current
->toplevel
, o_attrib
);
1126 o_invalidate (w_current
, o_attrib
);
1127 o_undo_savestate (w_current
, UNDO_ALL
);
1129 /* request an update of display for this row */
1130 update_row_display (model
, &iter
);
1134 /*! \todo Finish function documentation
1136 * \par Function Description
1139 static gboolean
multiattrib_callback_key_pressed(GtkWidget
*widget
,
1143 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1145 if (event
->state
== 0 &&
1146 (event
->keyval
== GDK_Delete
|| event
->keyval
== GDK_KP_Delete
)) {
1147 GtkTreeModel
*model
;
1151 /* delete the currently selected attribute */
1153 if (!gtk_tree_selection_get_selected (
1154 gtk_tree_view_get_selection (multiattrib
->treeview
),
1156 /* nothing selected, nothing to do */
1160 gtk_tree_model_get (model
, &iter
,
1161 COLUMN_ATTRIBUTE
, &o_attrib
,
1163 g_assert (o_attrib
->type
== OBJ_TEXT
);
1165 inherited
= o_attrib_is_inherited (o_attrib
);
1166 /* We can't delete inherited attribtes */
1170 multiattrib_action_delete_attribute (GSCHEM_DIALOG (multiattrib
)->w_current
,
1173 /* update the treeview contents */
1174 multiattrib_update (multiattrib
);
1180 /*! \todo Finish function documentation
1182 * \par Function Description
1185 static gboolean
multiattrib_callback_button_pressed(GtkWidget
*widget
,
1186 GdkEventButton
*event
,
1189 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1190 gboolean ret
= FALSE
;
1192 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3) {
1193 multiattrib_popup_menu (multiattrib
, event
);
1200 /*! \todo Finish function documentation
1202 * \par Function Description
1205 static gboolean
multiattrib_callback_popup_menu(GtkWidget
*widget
,
1208 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1210 multiattrib_popup_menu (multiattrib
, NULL
);
1215 /*! \todo Finish function documentation
1217 * \par Function Description
1220 static void multiattrib_callback_popup_duplicate(GtkMenuItem
*menuitem
,
1223 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1224 GtkTreeModel
*model
;
1226 GSCHEM_TOPLEVEL
*w_current
;
1227 OBJECT
*object
, *o_attrib
;
1229 if (!gtk_tree_selection_get_selected (
1230 gtk_tree_view_get_selection (multiattrib
->treeview
),
1232 /* nothing selected, nothing to do */
1236 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1237 object
= multiattrib
->object
;
1239 gtk_tree_model_get (model
, &iter
,
1240 COLUMN_ATTRIBUTE
, &o_attrib
,
1242 g_assert (o_attrib
->type
== OBJ_TEXT
);
1244 multiattrib_action_duplicate_attribute (w_current
, object
, o_attrib
);
1246 /* update the treeview contents */
1247 multiattrib_update (multiattrib
);
1252 /*! \todo Finish function documentation
1254 * \par Function Description
1257 static void multiattrib_callback_popup_promote (GtkMenuItem
*menuitem
,
1260 Multiattrib
*multiattrib
= user_data
;
1261 GtkTreeModel
*model
;
1263 GSCHEM_TOPLEVEL
*w_current
;
1264 OBJECT
*object
, *o_attrib
;
1266 if (!gtk_tree_selection_get_selected (
1267 gtk_tree_view_get_selection (multiattrib
->treeview
),
1269 /* nothing selected, nothing to do */
1273 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1274 object
= multiattrib
->object
;
1276 gtk_tree_model_get (model
, &iter
,
1277 COLUMN_ATTRIBUTE
, &o_attrib
,
1279 g_assert (o_attrib
->type
== OBJ_TEXT
);
1281 multiattrib_action_promote_attribute (w_current
, object
, o_attrib
);
1283 /* update the treeview contents */
1284 multiattrib_update (multiattrib
);
1287 /*! \todo Finish function documentation
1289 * \par Function Description
1292 static void multiattrib_callback_popup_delete(GtkMenuItem
*menuitem
,
1295 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1296 GtkTreeModel
*model
;
1298 GSCHEM_TOPLEVEL
*w_current
;
1301 if (!gtk_tree_selection_get_selected (
1302 gtk_tree_view_get_selection (multiattrib
->treeview
),
1304 /* nothing selected, nothing to do */
1308 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1310 gtk_tree_model_get (model
, &iter
,
1311 COLUMN_ATTRIBUTE
, &o_attrib
,
1313 g_assert (o_attrib
->type
== OBJ_TEXT
);
1315 multiattrib_action_delete_attribute (w_current
, o_attrib
);
1317 /* update the treeview contents */
1318 multiattrib_update (multiattrib
);
1322 /*! \todo Finish function documentation
1324 * \par Function Description
1327 static gboolean
multiattrib_callback_value_key_pressed(GtkWidget
*widget
,
1331 Multiattrib
*multiattrib
= (Multiattrib
*)widget
;
1332 gboolean retval
= FALSE
;
1334 /* ends editing of cell if one of these keys are pressed: */
1335 /* - the Return key without the Control modifier */
1336 /* - the Tab key without the Control modifier */
1337 if ((event
->keyval
== GDK_Return
|| event
->keyval
== GDK_KP_Enter
) ||
1338 (event
->keyval
== GDK_Tab
|| event
->keyval
== GDK_KP_Tab
)) {
1339 /* Control modifier activated? */
1340 if (event
->state
& GDK_CONTROL_MASK
) {
1341 /* yes the modifier in event structure and let event propagate */
1342 event
->state
^= GDK_CONTROL_MASK
;
1345 /* change focus and stop propagation */
1346 g_signal_emit_by_name (multiattrib
,
1348 (event
->state
& GDK_SHIFT_MASK
) ?
1349 GTK_DIR_TAB_BACKWARD
: GTK_DIR_TAB_FORWARD
);
1358 /*! \brief GtkWidget "grab-focus" signal handler
1360 * \par Function Description
1361 * Select the text in the GtkTextView so it may be over-typed quickly
1363 static void multiattrib_callback_value_grab_focus (GtkWidget
*widget
,
1366 GtkTextView
*textview
= GTK_TEXT_VIEW (widget
);
1367 GtkTextBuffer
*textbuffer
;
1368 GtkTextIter startiter
, enditer
;
1370 textbuffer
= gtk_text_view_get_buffer (textview
);
1371 gtk_text_buffer_get_iter_at_offset (textbuffer
, &startiter
, 0);
1372 gtk_text_buffer_get_iter_at_offset (textbuffer
, &enditer
, -1);
1373 gtk_text_buffer_select_range (textbuffer
, &enditer
, &startiter
);
1377 /*! \todo Finish function documentation
1379 * \par Function Description
1382 static void multiattrib_callback_button_add(GtkButton
*button
,
1385 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1386 GtkTextBuffer
*buffer
;
1387 GtkTextIter start
, end
;
1390 GSCHEM_TOPLEVEL
*w_current
;
1395 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1396 object
= multiattrib
->object
;
1397 buffer
= gtk_text_view_get_buffer (multiattrib
->textview_value
);
1399 /* retrieve information from the Add/Edit frame */
1400 /* - attribute's name */
1401 name
= gtk_entry_get_text (
1402 GTK_ENTRY (GTK_COMBO (multiattrib
->combo_name
)->entry
));
1403 /* - attribute's value */
1404 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
1405 value
= gtk_text_buffer_get_text (buffer
, &start
, &end
, FALSE
);
1406 /* - attribute's visibility status */
1407 visible
= gtk_toggle_button_get_active (
1408 (GtkToggleButton
*)multiattrib
->button_visible
);
1409 /* - visibility type */
1410 shownv
= (gint
)gtk_option_menu_get_history (multiattrib
->optionmenu_shownv
);
1412 if (name
[0] == '\0' || name
[0] == ' ') {
1413 /* name not allowed for an attribute */
1418 multiattrib_action_add_attribute (w_current
, object
, multiattrib
,
1423 multiattrib_update (multiattrib
);
1426 /*! \todo Finish function documentation
1428 * \par Function Description
1431 static void multiattrib_init_attrib_names(GtkCombo
*combo
)
1433 GList
*items
= NULL
;
1434 const gchar
*string
;
1437 for (i
= 0, string
= s_attrib_get (i
);
1439 i
++, string
= s_attrib_get (i
)) {
1440 items
= g_list_append (items
, (gpointer
)string
);
1443 gtk_combo_set_popdown_strings (GTK_COMBO (combo
), items
);
1445 g_list_free (items
);
1449 /*! \todo Finish function documentation
1451 * \par Function Description
1454 static void multiattrib_init_visible_types(GtkOptionMenu
*optionmenu
)
1456 GtkWidget
*menu
, *item
;
1458 menu
= gtk_menu_new ();
1459 item
= gtk_menu_item_new_with_label (_("Show Name & Value"));
1460 gtk_menu_append (menu
, item
);
1461 item
= gtk_menu_item_new_with_label (_("Show Value only"));
1462 gtk_menu_append (menu
, item
);
1463 item
= gtk_menu_item_new_with_label (_("Show Name only"));
1464 gtk_menu_append (menu
, item
);
1466 gtk_option_menu_set_menu (optionmenu
, menu
);
1471 /*! \brief Popup a context-sensitive menu.
1472 * \par Function Description
1473 * Pops up a context-sensitive menu.
1474 * <B>event</B> can be NULL if the popup is triggered by a key binding
1475 * instead of a mouse click.
1477 * \param [in] multiattrib The Multiattrib object.
1478 * \param [in] event Mouse event.
1480 static void multiattrib_popup_menu(Multiattrib
*multiattrib
,
1481 GdkEventButton
*event
)
1490 struct menuitem_t menuitems_inherited
[] = {
1491 { N_("Promote"), G_CALLBACK (multiattrib_callback_popup_promote
) },
1494 struct menuitem_t menuitems_noninherited
[] = {
1495 { N_("Duplicate"), G_CALLBACK (multiattrib_callback_popup_duplicate
) },
1496 { N_("Delete"), G_CALLBACK (multiattrib_callback_popup_delete
) },
1499 struct menuitem_t
*item_list
;
1500 struct menuitem_t
*tmp
;
1502 GtkTreeModel
*model
;
1504 GtkTreeSelection
*selection
;
1507 selection
= gtk_tree_view_get_selection (multiattrib
->treeview
);
1509 if (event
!= NULL
&&
1510 gtk_tree_view_get_path_at_pos (multiattrib
->treeview
,
1513 &path
, NULL
, NULL
, NULL
)) {
1514 gtk_tree_selection_unselect_all (selection
);
1515 gtk_tree_selection_select_path (selection
, path
);
1516 gtk_tree_path_free (path
);
1519 /* if nothing is selected, nothing to do */
1520 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
1523 gtk_tree_model_get (model
, &iter
,
1524 COLUMN_ATTRIBUTE
, &o_attrib
,
1526 g_assert (o_attrib
->type
== OBJ_TEXT
);
1528 inherited
= o_attrib_is_inherited (o_attrib
);
1529 item_list
= inherited
? menuitems_inherited
: menuitems_noninherited
;
1531 /* create the context menu */
1532 menu
= gtk_menu_new();
1533 for (tmp
= item_list
; tmp
->label
!= NULL
; tmp
++) {
1534 GtkWidget
*menuitem
;
1535 if (g_strcasecmp (tmp
->label
, "-") == 0) {
1536 menuitem
= gtk_separator_menu_item_new ();
1538 menuitem
= gtk_menu_item_new_with_label (_(tmp
->label
));
1539 g_signal_connect (menuitem
,
1544 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1546 gtk_widget_show_all (menu
);
1547 /* make menu a popup menu */
1548 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
1549 (event
!= NULL
) ? event
->button
: 0,
1550 gdk_event_get_time ((GdkEvent
*)event
));
1555 /*! \brief GschemDialog "geometry_save" class method handler
1557 * \par Function Description
1558 * Chain up to our parent's method to save the dialog's size and
1559 * position, then save the dialog's current internal geometry.
1561 * \param [in] dialog The GschemDialog to save the geometry of.
1562 * \param [in] key_file The GKeyFile to save the geometry data to.
1563 * \param [in] group_name The group name in the key file to store the data under.
1566 multiattrib_geometry_save (GschemDialog
*dialog
, GKeyFile
*key_file
, gchar
*group_name
)
1568 gboolean show_inherited
;
1570 /* Call the parent's geometry_save method */
1571 GSCHEM_DIALOG_CLASS (multiattrib_parent_class
)->
1572 geometry_save (dialog
, key_file
, group_name
);
1575 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (MULTIATTRIB (dialog
)->show_inherited
));
1576 g_key_file_set_boolean (key_file
, group_name
, "show_inherited", show_inherited
);
1580 /*! \brief GschemDialog "geometry_restore" class method handler
1582 * \par Function Description
1583 * Chain up to our parent's method to restore the dialog's size and
1584 * position, then restore the dialog's current internal geometry.
1586 * \param [in] dialog The GschemDialog to restore the geometry of.
1587 * \param [in] key_file The GKeyFile to save the geometry data to.
1588 * \param [in] group_name The group name in the key file to store the data under.
1591 multiattrib_geometry_restore (GschemDialog
*dialog
, GKeyFile
*key_file
, gchar
*group_name
)
1593 gboolean show_inherited
;
1594 GError
*error
= NULL
;
1596 /* Call the parent's geometry_restore method */
1597 GSCHEM_DIALOG_CLASS (multiattrib_parent_class
)->
1598 geometry_restore (dialog
, key_file
, group_name
);
1600 show_inherited
= g_key_file_get_boolean (key_file
, group_name
, "show_inherited", &error
);
1601 if (error
!= NULL
) {
1602 show_inherited
= TRUE
;
1603 g_error_free (error
);
1605 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (MULTIATTRIB (dialog
)->show_inherited
), show_inherited
);
1609 /*! \brief Function to retrieve Multiattrib's GType identifier.
1611 * \par Function Description
1613 * Function to retrieve Multiattrib's GType identifier.
1614 * Upon first call, this registers Multiattrib in the GType system.
1615 * Subsequently it returns the saved value from its first execution.
1617 * \return the GType identifier associated with Multiattrib.
1619 GType
multiattrib_get_type()
1621 static GType multiattrib_type
= 0;
1623 if (!multiattrib_type
) {
1624 static const GTypeInfo multiattrib_info
= {
1625 sizeof(MultiattribClass
),
1626 NULL
, /* base_init */
1627 NULL
, /* base_finalize */
1628 (GClassInitFunc
) multiattrib_class_init
,
1629 NULL
, /* class_finalize */
1630 NULL
, /* class_data */
1631 sizeof(Multiattrib
),
1632 0, /* n_preallocs */
1633 (GInstanceInitFunc
) multiattrib_init
,
1636 multiattrib_type
= g_type_register_static (GSCHEM_TYPE_DIALOG
,
1638 &multiattrib_info
, 0);
1641 return multiattrib_type
;
1644 /*! \brief GType class initialiser for Multiattrib
1646 * \par Function Description
1648 * GType class initialiser for Multiattrib. We override our parent
1649 * virtual class methods as needed and register our GObject properties.
1651 * \param [in] klass The MultiattribClass we are initialising
1653 static void multiattrib_class_init(MultiattribClass
*klass
)
1655 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1656 GschemDialogClass
*gschem_dialog_class
= GSCHEM_DIALOG_CLASS (klass
);
1658 gschem_dialog_class
->geometry_save
= multiattrib_geometry_save
;
1659 gschem_dialog_class
->geometry_restore
= multiattrib_geometry_restore
;
1661 gobject_class
->set_property
= multiattrib_set_property
;
1662 gobject_class
->get_property
= multiattrib_get_property
;
1664 multiattrib_parent_class
= g_type_class_peek_parent (klass
);
1666 g_object_class_install_property (
1667 gobject_class
, PROP_OBJECT
,
1668 g_param_spec_pointer ("object",
1671 G_PARAM_READWRITE
));
1674 /*! \brief Regenerate the attribute list when the visibility
1675 * setting for inherited attributes changes
1677 static void multiattrib_show_inherited_toggled (GtkToggleButton
*button
,
1680 Multiattrib
*multiattrib
= user_data
;
1682 /* update the treeview contents */
1683 multiattrib_update (multiattrib
);
1687 /*! \brief GType instance initialiser for Multiattrib
1689 * \par Function Description
1691 * GType instance initialiser for Multiattrib. Create
1692 * and setup the widgets which make up the dialog.
1694 * \param [in] multiattrib The Multiattrib we are initialising
1696 static void multiattrib_init(Multiattrib
*multiattrib
)
1698 GtkWidget
*frame
, *label
, *scrolled_win
, *treeview
;
1699 GtkWidget
*table
, *textview
, *combo
, *optionm
, *button
;
1700 GtkWidget
*attrib_vbox
, *show_inherited
;
1701 GtkTreeModel
*store
;
1702 GtkCellRenderer
*renderer
;
1703 GtkTreeViewColumn
*column
;
1704 GtkTreeSelection
*selection
;
1707 /* dialog initialization */
1708 g_object_set (G_OBJECT (multiattrib
),
1712 "type", GTK_WINDOW_TOPLEVEL
,
1713 "title", _("Edit Attributes"),
1714 "default-width", 320,
1715 "default-height", 350,
1716 "window-position", GTK_WIN_POS_MOUSE
,
1718 "allow-shrink", FALSE
,
1720 "has-separator", TRUE
,
1723 multiattrib
->object
= NULL
;
1725 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), 5);
1727 /* create the attribute list frame */
1728 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1730 "shadow", GTK_SHADOW_NONE
,
1732 multiattrib
->frame_add
= frame
;
1733 /* - create the model for the treeview */
1734 store
= (GtkTreeModel
*)gtk_list_store_new (NUM_COLUMNS
,
1735 G_TYPE_POINTER
); /* attribute */
1736 /* - create a scrolled window for the treeview */
1737 scrolled_win
= GTK_WIDGET (
1738 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1741 /* GtkScrolledWindow */
1742 "hscrollbar-policy",
1743 GTK_POLICY_AUTOMATIC
,
1744 "vscrollbar-policy",
1745 GTK_POLICY_AUTOMATIC
,
1747 GTK_SHADOW_ETCHED_IN
,
1749 /* - create the treeview */
1750 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
1755 g_signal_connect (treeview
,
1757 G_CALLBACK (multiattrib_callback_key_pressed
),
1759 g_signal_connect (treeview
,
1760 "button-press-event",
1761 G_CALLBACK (multiattrib_callback_button_pressed
),
1763 g_signal_connect (treeview
,
1765 G_CALLBACK (multiattrib_callback_popup_menu
),
1767 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
1768 gtk_tree_selection_set_mode (selection
,
1769 GTK_SELECTION_SINGLE
);
1771 /* - and now the columns of the treeview */
1772 /* - column 1: attribute name */
1773 renderer
= GTK_CELL_RENDERER (
1774 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT
,
1775 /* GtkCellRendererText */
1776 /* unknown in GTK 2.4 */
1778 * PANGO_ELLIPSIZE_END, */
1780 g_signal_connect (renderer
,
1782 G_CALLBACK (multiattrib_callback_edited_name
),
1784 column
= GTK_TREE_VIEW_COLUMN (
1785 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1786 /* GtkTreeViewColumn */
1791 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1792 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1793 multiattrib_column_set_data_name
,
1795 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1796 /* - column 2: attribute value */
1797 renderer
= GTK_CELL_RENDERER (
1798 g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT
,
1799 /* GtkCellRendererText */
1800 /* unknown in GTK 2.4 */
1802 PANGO_ELLIPSIZE_END, */
1804 g_signal_connect (renderer
,
1806 G_CALLBACK (multiattrib_callback_edited_value
),
1808 column
= GTK_TREE_VIEW_COLUMN (
1809 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1810 /* GtkTreeViewColumn */
1811 "title", _("Value"),
1815 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1816 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1817 multiattrib_column_set_data_value
,
1819 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1820 /* - column 3: visibility */
1821 renderer
= GTK_CELL_RENDERER (
1822 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1824 g_signal_connect (renderer
,
1826 G_CALLBACK (multiattrib_callback_toggled_visible
),
1828 column
= GTK_TREE_VIEW_COLUMN (
1829 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1830 /* GtkTreeViewColumn */
1833 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1834 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1835 multiattrib_column_set_data_visible
,
1837 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1838 /* - column 4: show name */
1839 renderer
= GTK_CELL_RENDERER (
1840 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1842 g_signal_connect (renderer
,
1844 G_CALLBACK (multiattrib_callback_toggled_show_name
),
1846 column
= GTK_TREE_VIEW_COLUMN (
1847 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1848 /* GtkTreeViewColumn */
1851 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1852 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1853 multiattrib_column_set_data_show_name
,
1855 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1856 /* - column 5: show value */
1857 renderer
= GTK_CELL_RENDERER (
1858 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1860 g_signal_connect (renderer
,
1862 G_CALLBACK (multiattrib_callback_toggled_show_value
),
1864 column
= GTK_TREE_VIEW_COLUMN (
1865 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1866 /* GtkTreeViewColumn */
1869 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1870 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1871 multiattrib_column_set_data_show_value
,
1873 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1875 /* add the treeview to the scrolled window */
1876 gtk_container_add (GTK_CONTAINER (scrolled_win
), treeview
);
1877 /* set treeview of multiattrib */
1878 multiattrib
->treeview
= GTK_TREE_VIEW (treeview
);
1880 attrib_vbox
= gtk_vbox_new (FALSE
, 0);
1882 /* Pack the vbox into the frame */
1883 gtk_container_add (GTK_CONTAINER (frame
), attrib_vbox
);
1885 /* add the scrolled window to box */
1886 gtk_box_pack_start (GTK_BOX (attrib_vbox
), scrolled_win
, TRUE
, TRUE
, 0);
1888 /* create the show inherited button */
1889 show_inherited
= gtk_check_button_new_with_label (_("Show inherited attributes"));
1890 multiattrib
->show_inherited
= show_inherited
;
1891 gtk_box_pack_start (GTK_BOX (attrib_vbox
), show_inherited
, FALSE
, FALSE
, 0);
1893 g_signal_connect (show_inherited
,
1895 G_CALLBACK (multiattrib_show_inherited_toggled
),
1898 /* pack the frame */
1899 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1901 gtk_widget_show_all (frame
);
1903 /* create the add/edit frame */
1904 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1905 "label", _("Add Attribute"),
1907 multiattrib
->frame_attributes
= frame
;
1908 table
= GTK_WIDGET (g_object_new (GTK_TYPE_TABLE
,
1912 "homogeneous", FALSE
,
1915 /* - the name entry: a GtkComboBoxEntry */
1916 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1921 "label", _("Name:"),
1923 combo
= GTK_WIDGET (g_object_new (GTK_TYPE_COMBO
,
1925 "value-in-list", FALSE
,
1927 multiattrib_init_attrib_names (GTK_COMBO (combo
));
1928 multiattrib
->combo_name
= GTK_COMBO (combo
);
1929 gtk_table_attach (GTK_TABLE (table
), label
,
1930 0, 1, 0, 1, 0, 0, 0, 0);
1931 gtk_table_attach (GTK_TABLE (table
), combo
,
1932 1, 2, 0, 1, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1934 /* - the value entry: a GtkEntry */
1935 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1940 "label", _("Value:"),
1942 scrolled_win
= GTK_WIDGET (
1943 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1944 /* GtkScrolledWindow */
1945 "hscrollbar-policy",
1947 "vscrollbar-policy",
1948 GTK_POLICY_AUTOMATIC
,
1952 textview
= GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW
,
1954 g_signal_connect (textview
,
1956 G_CALLBACK (multiattrib_callback_value_key_pressed
),
1958 g_signal_connect (textview
,
1960 G_CALLBACK (multiattrib_callback_value_grab_focus
),
1962 /* Save the GTK_STATE_NORMAL color so we can work around GtkTextView's
1963 * stubborn refusal to draw with GTK_STATE_INSENSITIVE later on */
1964 style
= gtk_widget_get_style (textview
);
1965 multiattrib
->value_normal_text_color
= style
->text
[ GTK_STATE_NORMAL
];
1967 /* Save this one so we can pick it as a sensible colour to show the
1968 * inherited attributes dimmed.
1970 style
= gtk_widget_get_style (treeview
);
1971 multiattrib
->insensitive_text_color
= style
->text
[ GTK_STATE_INSENSITIVE
];
1973 gtk_container_add (GTK_CONTAINER (scrolled_win
), textview
);
1974 multiattrib
->textview_value
= GTK_TEXT_VIEW (textview
);
1975 gtk_table_attach (GTK_TABLE (table
), label
,
1976 0, 1, 1, 2, 0, 0, 0, 0);
1977 gtk_table_attach (GTK_TABLE (table
), scrolled_win
,
1978 1, 2, 1, 2, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1980 /* - the visible status */
1981 button
= GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON
,
1983 "label", _("Visible"),
1986 multiattrib
->button_visible
= GTK_CHECK_BUTTON (button
);
1987 gtk_table_attach (GTK_TABLE (table
), button
,
1988 0, 1, 2, 3, GTK_FILL
, 0, 3, 0);
1990 /* - the visibility type */
1991 optionm
= GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU
,
1993 multiattrib_init_visible_types (GTK_OPTION_MENU (optionm
));
1994 multiattrib
->optionmenu_shownv
= GTK_OPTION_MENU (optionm
);
1995 gtk_table_attach (GTK_TABLE (table
), optionm
,
1996 1, 2, 2, 3, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1997 gtk_widget_show_all (table
);
1999 /* create the add button */
2000 button
= gtk_button_new_from_stock (GTK_STOCK_ADD
);
2001 g_signal_connect (button
,
2003 G_CALLBACK (multiattrib_callback_button_add
),
2005 gtk_table_attach (GTK_TABLE (table
), button
,
2006 2, 3, 0, 3, 0, 0, 6, 3);
2008 /* add the table to the frame */
2009 gtk_container_add (GTK_CONTAINER (frame
), table
);
2010 /* pack the frame in the dialog */
2011 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
2013 gtk_widget_show_all (frame
);
2016 /* now add the close button to the action area */
2017 gtk_dialog_add_button (GTK_DIALOG (multiattrib
),
2018 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
);
2023 /*! \brief GObject property setter function
2025 * \par Function Description
2026 * Setter function for Multiattrib's GObject property, "object".
2028 * \param [in] object The GObject whose properties we are setting
2029 * \param [in] property_id The numeric id. under which the property was
2030 * registered with g_object_class_install_property()
2031 * \param [in] value The GValue the property is being set from
2032 * \param [in] pspec A GParamSpec describing the property being set
2035 static void multiattrib_set_property (GObject
*object
,
2037 const GValue
*value
,
2040 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
2042 switch(property_id
) {
2044 multiattrib
->object
= (OBJECT
*)g_value_get_pointer (value
);
2045 multiattrib_update (multiattrib
);
2048 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
2053 /*! \brief GObject property getter function
2055 * \par Function Description
2056 * Getter function for Multiattrib's GObject property, "object".
2058 * \param [in] object The GObject whose properties we are getting
2059 * \param [in] property_id The numeric id. under which the property was
2060 * registered with g_object_class_install_property()
2061 * \param [out] value The GValue in which to return the value of the property
2062 * \param [in] pspec A GParamSpec describing the property being got
2064 static void multiattrib_get_property (GObject
*object
,
2069 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
2071 switch(property_id
) {
2073 g_value_set_pointer (value
, (gpointer
)multiattrib
->object
);
2076 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
2082 /*! \brief Update the multiattrib editor dialog's interface
2084 * \par Function Description
2086 * Update the dialog to reflect the attributes of the object. If
2087 * there is no object set, the dialog's controls are set insensitive.
2089 * \param [in] multiattrib The multi-attribute editor dialog.
2091 void multiattrib_update (Multiattrib
*multiattrib
)
2094 GtkListStore
*liststore
;
2096 GList
*object_attribs
;
2101 gboolean show_inherited
;
2103 g_assert (GSCHEM_DIALOG (multiattrib
)->w_current
!= NULL
);
2104 toplevel
= GSCHEM_DIALOG (multiattrib
)->w_current
->toplevel
;
2106 /* clear the list of attributes */
2107 liststore
= (GtkListStore
*)gtk_tree_view_get_model (multiattrib
->treeview
);
2108 gtk_list_store_clear (liststore
);
2110 /* Update sensitivities */
2111 sensitive
= (multiattrib
->object
!= NULL
);
2112 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib
->frame_attributes
), sensitive
);
2113 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib
->frame_add
), sensitive
);
2115 /* Work around GtkTextView's stubborn indifference
2116 * to GTK_STATE_INSENSITIVE when rendering its text. */
2117 style
= gtk_widget_get_style (GTK_WIDGET (multiattrib
->textview_value
));
2118 gtk_widget_modify_text (GTK_WIDGET (multiattrib
->textview_value
),
2120 sensitive
? &multiattrib
->value_normal_text_color
2121 : &style
->text
[GTK_STATE_INSENSITIVE
]);
2123 /* If we aren't sensitive, there is nothing more to do */
2128 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiattrib
->show_inherited
));
2130 /* get list of attributes */
2131 object_attribs
= o_attrib_return_attribs (multiattrib
->object
);
2132 /* populate the store with attributes */
2133 for (a_iter
= object_attribs
; a_iter
!= NULL
;
2134 a_iter
= g_list_next (a_iter
)) {
2135 a_current
= a_iter
->data
;
2137 /* Skip over inherited attributes if we don't want to show them */
2138 if (!show_inherited
&& o_attrib_is_inherited (a_current
))
2141 gtk_list_store_append (liststore
, &iter
);
2142 gtk_list_store_set (liststore
, &iter
,
2143 COLUMN_ATTRIBUTE
, a_current
,
2146 /* delete the list of attribute objects */
2147 g_list_free (object_attribs
);