1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 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
)) {
61 g_assert (object
!= NULL
);
63 if (object
->type
== OBJ_COMPLEX
||
64 object
->type
== OBJ_PLACEHOLDER
||
65 object
->type
== OBJ_SLOT
||
66 object
->type
== OBJ_NET
||
67 object
->type
== OBJ_BUS
||
68 object
->type
== OBJ_PIN
) {
73 if (object_count
== 0) {
74 /* TODO: If the user selects a single attribute which is
75 * not floating, should we find its parent object and
76 * display the multi-attribute editor for that?
77 * Bonus marks for making it jump to the correct attrib.
80 } else if (object_count
== 1) {
81 object
= (geda_list_get_glist (selection
))->data
;
83 /* TODO: Something clever with multiple objects selected */
87 g_object_set (multiattrib
,
92 #define DIALOG_DATA_SELECTION "current-selection"
94 /*! \brief Update the dialog when the current page's SELECTION object
96 * \par Function Description
97 * This handler is called when the g_object_weak_ref() on the
98 * SELECTION object we're watching expires. We reset our
99 * multiattrib->selection pointer to NULL to avoid attempting to
100 * access the destroyed object.
103 * Our signal handlers were automatically disconnected during the
104 * destruction process.
106 * \param [in] data Pointer to the multi-attrib dialog
107 * \param [in] where_the_object_was Pointer to where the object was
110 static void callback_selection_finalized (gpointer data
,
111 GObject
*where_the_object_was
)
113 Multiattrib
*multiattrib
= MULTIATTRIB (data
);
114 g_object_set (multiattrib
,
117 g_object_set_data (G_OBJECT (multiattrib
), DIALOG_DATA_SELECTION
, NULL
);
120 /*! \brief Add link between multiattrib dialog and current selection.
121 * \par Function Description
122 * This function connects a handler to the "changed" signal of
123 * current selection to let the dialog watch it. It also adds a weak
124 * reference on the selection.
126 * \param [in] multiattrib The Multiattrib dialog.
127 * \param [in] selection The selection to watch.
129 static void connect_selection (Multiattrib
*multiattrib
,
130 SELECTION
*selection
)
132 g_assert (g_object_get_data (G_OBJECT (multiattrib
),
133 DIALOG_DATA_SELECTION
) == NULL
);
134 g_object_set_data (G_OBJECT (multiattrib
), DIALOG_DATA_SELECTION
, selection
);
135 g_object_weak_ref (G_OBJECT (selection
),
136 callback_selection_finalized
,
138 g_signal_connect (selection
,
140 (GCallback
)callback_selection_changed
,
142 /* Synthesise a selection changed update to refresh the view */
143 callback_selection_changed (selection
, multiattrib
);
146 /*! \brief Remove the link between multiattrib dialog and selection.
147 * \par Function Description
148 * If the dialog is watching a selection, this function disconnects
149 * the "changed" signal and removes the weak reference it previously
152 * \param [in] multiattrib The Multiattrib dialog.
154 static void disconnect_selection (Multiattrib
*multiattrib
) {
155 SELECTION
*selection
;
157 /* get selection watched from dialog data */
158 selection
= (SELECTION
*)g_object_get_data (G_OBJECT (multiattrib
),
159 DIALOG_DATA_SELECTION
);
160 if (selection
== NULL
) {
161 /* no selection watched */
165 g_signal_handlers_disconnect_matched (selection
,
166 G_SIGNAL_MATCH_FUNC
|
169 callback_selection_changed
,
171 g_object_weak_unref (G_OBJECT (selection
),
172 callback_selection_finalized
,
175 /* reset dialog data */
176 g_object_set_data (G_OBJECT (multiattrib
), DIALOG_DATA_SELECTION
, NULL
);
179 /*! \brief Process the response returned by the multi-attribute dialog.
180 * \par Function Description
181 * This function handles the response <B>arg1</B> of the multi-attribute
182 * editor dialog <B>dialog</B>.
184 * \param [in] dialog The multi-attribute editor dialog.
185 * \param [in] arg1 The response ID.
186 * \param [in] user_data A pointer on the GSCHEM_TOPLEVEL environment.
189 multiattrib_callback_response (GtkDialog
*dialog
,
193 GSCHEM_TOPLEVEL
*w_current
= (GSCHEM_TOPLEVEL
*)user_data
;
196 case GTK_RESPONSE_CLOSE
:
197 case GTK_RESPONSE_DELETE_EVENT
:
198 /* cut link from dialog to selection */
199 disconnect_selection (MULTIATTRIB (w_current
->mawindow
));
200 gtk_widget_destroy (GTK_WIDGET (dialog
));
201 w_current
->mawindow
= NULL
;
206 /*! \brief Open multiple attribute editor dialog.
207 * \par Function Description
208 * Opens the multiple attribute editor dialog for objects in this <B>toplevel</B>.
210 * \param [in] w_current The GSCHEM_TOPLEVEL object.
212 void x_multiattrib_open(GSCHEM_TOPLEVEL
*w_current
, SELECTION
*selection
)
214 if ( w_current
->mawindow
== NULL
) {
215 w_current
->mawindow
=
216 GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB
,
219 "settings-name", "multiattrib",
220 "gschem-toplevel", w_current
,
222 "type", GTK_WINDOW_TOPLEVEL
,
225 gtk_window_set_transient_for (GTK_WINDOW(w_current
->mawindow
),
226 GTK_WINDOW(w_current
->main_window
));
228 g_signal_connect (w_current
->mawindow
,
230 G_CALLBACK (multiattrib_callback_response
),
233 /* attach dialog to selection of current page */
234 x_multiattrib_update (w_current
, selection
);
236 gtk_widget_show (w_current
->mawindow
);
238 gtk_window_present (GTK_WINDOW(w_current
->mawindow
));
243 /*! \brief Close the multiattrib dialog.
245 * \par Function Description
247 * Closes the multiattrib dialog associated with <B>w_current</B>.
249 * \param [in] w_current The GSCHEM_TOPLEVEL object.
251 void x_multiattrib_close (GSCHEM_TOPLEVEL
*w_current
)
253 if (w_current
->mawindow
!= NULL
) {
254 /* cut link from dialog to selection */
255 disconnect_selection (MULTIATTRIB (w_current
->mawindow
));
256 gtk_widget_destroy (w_current
->mawindow
);
257 w_current
->mawindow
= NULL
;
261 /*! \brief Update the multiattrib editor dialog for a GSCHEM_TOPLEVEL.
263 * \par Function Description
265 * If the GSCHEM_TOPLEVEL has an open multiattrib dialog, switch to
266 * watching the current page's SELECTION object for changes.
268 * \param [in] w_current The GSCHEM_TOPLEVEL object.
270 void x_multiattrib_update(GSCHEM_TOPLEVEL
*w_current
, SELECTION
*selection
)
272 if (!IS_MULTIATTRIB (w_current
->mawindow
)) {
276 /* disconnect dialog from previous selection */
277 disconnect_selection (MULTIATTRIB (w_current
->mawindow
));
278 /* connect the dialog to the selection of the current page */
279 connect_selection (MULTIATTRIB (w_current
->mawindow
), selection
);
283 /*! \section celltextview-widget Cell TextView Widget Code.
284 * This widget makes a 'GtkTextView' widget implements the 'GtkCellEditable'
285 * interface. It can then be used to renderer multi-line texts inside
286 * tree views ('GtkTreeView').
288 static void celltextview_class_init (CellTextViewClass
*klass
);
289 static void celltextview_init (CellTextView
*self
);
290 static void celltextview_cell_editable_init (GtkCellEditableIface
*iface
);
292 /*! \todo Finish function documentation
294 * \par Function Description
297 static gboolean
celltextview_key_press_event (GtkWidget
*widget
,
298 GdkEventKey
*key_event
,
301 CellTextView
*celltextview
= (CellTextView
*)widget
;
303 /* If the Escape key is pressed, we flag the edit as canceled */
304 if (key_event
->keyval
== GDK_Escape
)
305 celltextview
->editing_canceled
= TRUE
;
307 /* ends editing of cell if one of these keys are pressed or editing is canceled */
308 if (celltextview
->editing_canceled
== TRUE
||
309 /* the Enter key without the Control modifier */
310 (!(key_event
->state
& GDK_CONTROL_MASK
) &&
311 (key_event
->keyval
== GDK_Return
||
312 key_event
->keyval
== GDK_KP_Enter
))) {
313 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (celltextview
));
314 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (celltextview
));
321 /*! \todo Finish function documentation
323 * \par Function Description
326 static void celltextview_start_editing (GtkCellEditable
*cell_editable
,
329 g_signal_connect (cell_editable
,
331 G_CALLBACK (celltextview_key_press_event
),
336 /*! \todo Finish function documentation
338 * \par Function Description
341 GType
celltextview_get_type()
343 static GType celltextview_type
= 0;
345 if (!celltextview_type
) {
346 static const GTypeInfo celltextview_info
= {
347 sizeof(CellTextViewClass
),
348 NULL
, /* base_init */
349 NULL
, /* base_finalize */
350 (GClassInitFunc
) celltextview_class_init
,
351 NULL
, /* class_finalize */
352 NULL
, /* class_data */
353 sizeof(CellTextView
),
355 (GInstanceInitFunc
) celltextview_init
,
358 static const GInterfaceInfo cell_editable_info
= {
359 (GInterfaceInitFunc
) celltextview_cell_editable_init
,
360 NULL
, /* interface_finalize */
361 NULL
/* interface_data */
364 celltextview_type
= g_type_register_static(GTK_TYPE_TEXT_VIEW
,
366 &celltextview_info
, 0);
367 g_type_add_interface_static(celltextview_type
,
368 GTK_TYPE_CELL_EDITABLE
,
369 &cell_editable_info
);
372 return celltextview_type
;
375 /*! \todo Finish function documentation
377 * \par Function Description
380 static void celltextview_class_init(CellTextViewClass
*klass
)
382 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
385 /*! \todo Finish function documentation
387 * \par Function Description
390 static void celltextview_init(CellTextView
*celltextview
)
392 celltextview
->editing_canceled
= FALSE
;
395 /*! \todo Finish function documentation
397 * \par Function Description
400 static void celltextview_cell_editable_init(GtkCellEditableIface
*iface
)
402 iface
->start_editing
= celltextview_start_editing
;
405 /*! \section multi-line-text-cell-renderer Multi-line Text Cell Renderer
406 * GTK has no multi-line text cell renderer. This code adds one to be used
407 * in gschem code. It is inspired by the 'GtkCellRendererCombo' renderer
410 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
);
411 static void cellrenderermultilinetext_editing_done (GtkCellEditable
*cell_editable
,
413 static gboolean
cellrenderermultilinetext_focus_out_event (GtkWidget
*widget
,
418 #define CELL_RENDERER_MULTI_LINE_TEXT_PATH "cell-renderer-multi-line-text-path"
421 /*! \todo Finish function documentation
423 * \par Function Description
426 static GtkCellEditable
* cellrenderermultilinetext_start_editing(GtkCellRenderer
*cell
,
430 GdkRectangle
*background_area
,
431 GdkRectangle
*cell_area
,
432 GtkCellRendererState flags
)
434 GtkCellRendererText
*cell_text
;
435 CellRendererMultiLineText
*cell_mlt
;
437 GtkTextBuffer
*textbuffer
;
439 cell_text
= GTK_CELL_RENDERER_TEXT (cell
);
440 if (cell_text
->editable
== FALSE
) {
444 cell_mlt
= CELL_RENDERER_MULTI_LINE_TEXT (cell
);
446 textbuffer
= GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER
,
448 gtk_text_buffer_set_text (textbuffer
,
450 strlen (cell_text
->text
));
452 textview
= GTK_WIDGET (g_object_new (TYPE_CELL_TEXT_VIEW
,
454 "buffer", textbuffer
,
457 "height-request", cell_area
->height
,
459 g_object_set_data_full (G_OBJECT (textview
),
460 CELL_RENDERER_MULTI_LINE_TEXT_PATH
,
461 g_strdup (path
), g_free
);
463 gtk_widget_show (textview
);
465 g_signal_connect (GTK_CELL_EDITABLE (textview
),
467 G_CALLBACK (cellrenderermultilinetext_editing_done
),
469 cell_mlt
->focus_out_id
=
470 g_signal_connect (textview
,
472 G_CALLBACK (cellrenderermultilinetext_focus_out_event
),
475 return GTK_CELL_EDITABLE (textview
);
478 /*! \todo Finish function documentation
480 * \par Function Description
483 static void cellrenderermultilinetext_editing_done(GtkCellEditable
*cell_editable
,
486 CellRendererMultiLineText
*cell
= CELL_RENDERER_MULTI_LINE_TEXT (user_data
);
487 GtkTextBuffer
*buffer
;
488 GtkTextIter start
, end
;
492 if (cell
->focus_out_id
> 0) {
493 g_signal_handler_disconnect (cell_editable
,
495 cell
->focus_out_id
= 0;
498 if (CELL_TEXT_VIEW (cell_editable
)->editing_canceled
) {
499 g_signal_emit_by_name (cell
, "editing-canceled");
503 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (cell_editable
));
504 gtk_text_buffer_get_start_iter (buffer
, &start
);
505 gtk_text_buffer_get_end_iter (buffer
, &end
);
506 new_text
= gtk_text_buffer_get_text (buffer
, &start
, &end
, TRUE
);
508 path
= g_object_get_data (G_OBJECT (cell_editable
),
509 CELL_RENDERER_MULTI_LINE_TEXT_PATH
);
510 g_signal_emit_by_name (cell
, "edited", path
, new_text
);
516 /*! \todo Finish function documentation
518 * \par Function Description
521 static gboolean
cellrenderermultilinetext_focus_out_event(GtkWidget
*widget
,
525 cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget
),
531 /*! \todo Finish function documentation
533 * \par Function Description
536 GType
cellrenderermultilinetext_get_type()
538 static GType cellrenderermultilinetext_type
= 0;
540 if (!cellrenderermultilinetext_type
) {
541 static const GTypeInfo cellrenderermultilinetext_info
= {
542 sizeof(CellRendererMultiLineTextClass
),
543 NULL
, /* base_init */
544 NULL
, /* base_finalize */
545 (GClassInitFunc
) cellrenderermultilinetext_class_init
,
546 NULL
, /* class_finalize */
547 NULL
, /* class_data */
548 sizeof(CellRendererMultiLineText
),
550 NULL
, /* instance_init */
553 cellrenderermultilinetext_type
= g_type_register_static (
554 GTK_TYPE_CELL_RENDERER_TEXT
,
555 "CellRendererMultiLineText",
556 &cellrenderermultilinetext_info
, 0);
559 return cellrenderermultilinetext_type
;
562 /*! \todo Finish function documentation
564 * \par Function Description
567 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
)
569 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
570 GtkCellRendererClass
*cell_class
= GTK_CELL_RENDERER_CLASS (klass
);
572 cell_class
->start_editing
= cellrenderermultilinetext_start_editing
;
586 static GObjectClass
*multiattrib_parent_class
= NULL
;
588 static void multiattrib_class_init (MultiattribClass
*class);
589 static void multiattrib_init (Multiattrib
*multiattrib
);
590 static void multiattrib_set_property (GObject
*object
,
594 static void multiattrib_get_property (GObject
*object
,
599 static void multiattrib_popup_menu (Multiattrib
*multiattrib
,
600 GdkEventButton
*event
);
603 /*! \todo Finish function documentation
605 * \par Function Description
608 static void multiattrib_action_add_attribute(GSCHEM_TOPLEVEL
*w_current
,
610 Multiattrib
*multiattrib
,
614 gint show_name_value
)
618 newtext
= g_strdup_printf ("%s=%s", name
, value
);
620 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
625 /* create a new attribute and link it */
626 o_attrib_add_attrib(w_current
, newtext
, button_visible
, show_name_value
,
629 w_current
->toplevel
->page_current
->CHANGED
= 1;
630 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
,
644 g_return_if_fail(o_attrib
->type
== OBJ_TEXT
);
646 o_attrib_add_attrib(w_current
, o_text_get_string(o_attrib
),
647 o_attrib
->visibility
, o_attrib
->show_name_value
,
649 w_current
->toplevel
->page_current
->CHANGED
= 1;
650 o_undo_savestate (w_current
, UNDO_ALL
);
653 /*! \todo Finish function documentation
655 * \par Function Description
658 static void multiattrib_action_delete_attribute(GSCHEM_TOPLEVEL
*w_current
,
661 SELECTION
*selection
;
663 g_object_get(w_current
->mawindow
, DIALOG_DATA_SELECTION
, &selection
, NULL
);
665 /* actually deletes the attribute */
666 o_selection_remove (selection
, o_attrib
);
667 o_delete (w_current
, o_attrib
);
668 w_current
->toplevel
->page_current
->CHANGED
=1;
669 o_undo_savestate (w_current
, UNDO_ALL
);
672 /*! \todo Finish function documentation
674 * \par Function Description
677 static void multiattrib_column_set_data_name(GtkTreeViewColumn
*tree_column
,
678 GtkCellRenderer
*cell
,
679 GtkTreeModel
*tree_model
,
685 const gchar
*str
= NULL
;
687 gtk_tree_model_get (tree_model
, iter
,
688 COLUMN_ATTRIBUTE
, &o_attrib
,
690 g_assert (o_attrib
->type
== OBJ_TEXT
);
692 str
= o_text_get_string(o_attrib
);
694 o_attrib_get_name_value (str
, &name
, NULL
);
702 /*! \todo Finish function documentation
704 * \par Function Description
707 static void multiattrib_column_set_data_value(GtkTreeViewColumn
*tree_column
,
708 GtkCellRenderer
*cell
,
709 GtkTreeModel
*tree_model
,
715 const gchar
*str
= NULL
;
717 gtk_tree_model_get (tree_model
, iter
,
718 COLUMN_ATTRIBUTE
, &o_attrib
,
720 g_assert (o_attrib
->type
== OBJ_TEXT
);
722 str
= o_text_get_string(o_attrib
);
724 o_attrib_get_name_value (str
, NULL
, &value
);
732 /*! \todo Finish function documentation
734 * \par Function Description
737 static void multiattrib_column_set_data_visible(GtkTreeViewColumn
*tree_column
,
738 GtkCellRenderer
*cell
,
739 GtkTreeModel
*tree_model
,
745 gtk_tree_model_get (tree_model
, iter
,
746 COLUMN_ATTRIBUTE
, &o_attrib
,
748 g_assert (o_attrib
->type
== OBJ_TEXT
);
751 "active", (o_attrib
->visibility
== VISIBLE
),
756 /*! \todo Finish function documentation
758 * \par Function Description
761 static void multiattrib_column_set_data_show_name(GtkTreeViewColumn
*tree_column
,
762 GtkCellRenderer
*cell
,
763 GtkTreeModel
*tree_model
,
769 gtk_tree_model_get (tree_model
, iter
,
770 COLUMN_ATTRIBUTE
, &o_attrib
,
772 g_assert (o_attrib
->type
== OBJ_TEXT
);
775 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
776 o_attrib
->show_name_value
== SHOW_NAME
),
781 /*! \todo Finish function documentation
783 * \par Function Description
786 static void multiattrib_column_set_data_show_value(GtkTreeViewColumn
*tree_column
,
787 GtkCellRenderer
*cell
,
788 GtkTreeModel
*tree_model
,
794 gtk_tree_model_get (tree_model
, iter
,
795 COLUMN_ATTRIBUTE
, &o_attrib
,
797 g_assert (o_attrib
->type
== OBJ_TEXT
);
800 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
801 o_attrib
->show_name_value
== SHOW_VALUE
),
806 /*! \brief Requests an update of the display of a row.
807 * \par Function Description
808 * This is an helper function to update the display of a row when
809 * data for this row have been modified in the model.
811 * It emits the 'row_changed' signal on the pointed row.
813 * \param [in] model A GtkTreeModel.
814 * \param [in] iter A valid GtkTreeIter pointing to the changed row.
817 update_row_display (GtkTreeModel
*model
, GtkTreeIter
*iter
)
821 path
= gtk_tree_model_get_path (model
, iter
);
822 gtk_tree_model_row_changed (model
, path
, iter
);
823 gtk_tree_path_free (path
);
827 /*! \todo Finish function documentation
829 * \par Function Description
832 static void multiattrib_callback_edited_name(GtkCellRendererText
*cellrenderertext
,
837 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
841 gchar
*value
, *newtext
;
843 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
845 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
849 if (g_ascii_strcasecmp (arg2
, "") == 0) {
850 GtkWidget
*dialog
= gtk_message_dialog_new (
851 GTK_WINDOW (multiattrib
),
855 _("Attributes with empty name are not allowed. Please set a name."));
857 gtk_dialog_run (GTK_DIALOG (dialog
));
858 gtk_widget_destroy (dialog
);
862 gtk_tree_model_get (model
, &iter
,
863 COLUMN_ATTRIBUTE
, &o_attrib
,
865 g_assert (o_attrib
->type
== OBJ_TEXT
);
867 o_attrib_get_name_value(o_text_get_string(o_attrib
), NULL
, &value
);
868 newtext
= g_strdup_printf ("%s=%s", arg2
, value
);
870 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
876 /* actually modifies the attribute */
877 o_text_take_string(o_attrib
, newtext
);
882 /*! \todo Finish function documentation
884 * \par Function Description
887 static void multiattrib_callback_edited_value(GtkCellRendererText
*cell_renderer
,
892 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
896 gchar
*name
, *newtext
;
898 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
900 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
904 gtk_tree_model_get (model
, &iter
,
905 COLUMN_ATTRIBUTE
, &o_attrib
,
907 g_assert (o_attrib
->type
== OBJ_TEXT
);
909 o_attrib_get_name_value(o_text_get_string(o_attrib
), &name
, NULL
);
910 newtext
= g_strdup_printf ("%s=%s", name
, arg2
);
912 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
918 /* actually modifies the attribute */
919 o_text_take_string(o_attrib
, newtext
);
921 /* request an update of display for this row */
922 update_row_display (model
, &iter
);
927 /*! \todo Finish function documentation
929 * \par Function Description
932 static void multiattrib_callback_toggled_visible(GtkCellRendererToggle
*cell_renderer
,
936 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
940 GSCHEM_TOPLEVEL
*w_current
;
943 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
944 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
946 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
950 gtk_tree_model_get (model
, &iter
,
951 COLUMN_ATTRIBUTE
, &o_attrib
,
953 g_assert (o_attrib
->type
== OBJ_TEXT
);
954 o_erase_single (w_current
, o_attrib
);
956 visibility
= o_attrib
->visibility
== VISIBLE
? INVISIBLE
: VISIBLE
;
958 /* actually modifies the attribute */
959 o_text_change(o_attrib
, NULL
, visibility
, LEAVE_NAME_VALUE_ALONE
);
960 o_text_recreate(o_attrib
);
961 o_text_draw (w_current
, o_attrib
);
962 o_undo_savestate (w_current
, UNDO_ALL
);
964 /* request an update of display for this row */
965 update_row_display (model
, &iter
);
968 /*! \todo Finish function documentation
970 * \par Function Description
973 static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle
*cell_renderer
,
977 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
981 GSCHEM_TOPLEVEL
*w_current
;
984 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
985 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
987 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
991 gtk_tree_model_get (model
, &iter
,
992 COLUMN_ATTRIBUTE
, &o_attrib
,
994 g_assert (o_attrib
->type
== OBJ_TEXT
);
995 o_erase_single (w_current
, o_attrib
);
997 switch (o_attrib
->show_name_value
) {
998 case SHOW_NAME_VALUE
: new_snv
= SHOW_VALUE
; break;
999 case SHOW_NAME
: new_snv
= SHOW_VALUE
; break;
1000 case SHOW_VALUE
: new_snv
= SHOW_NAME_VALUE
; break;
1002 g_assert_not_reached ();
1003 new_snv
= SHOW_NAME_VALUE
;
1006 /* actually modifies the attribute */
1007 o_text_change(o_attrib
, NULL
, LEAVE_VISIBILITY_ALONE
, new_snv
);
1008 o_text_recreate(o_attrib
);
1009 o_text_draw (w_current
, o_attrib
);
1010 o_undo_savestate (w_current
, UNDO_ALL
);
1012 /* request an update of display for this row */
1013 update_row_display (model
, &iter
);
1016 /*! \todo Finish function documentation
1018 * \par Function Description
1021 static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle
*cell_renderer
,
1025 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1026 GtkTreeModel
*model
;
1029 GSCHEM_TOPLEVEL
*w_current
;
1032 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
1033 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1035 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
1039 gtk_tree_model_get (model
, &iter
,
1040 COLUMN_ATTRIBUTE
, &o_attrib
,
1042 g_assert (o_attrib
->type
== OBJ_TEXT
);
1043 o_erase_single (w_current
, o_attrib
);
1045 switch (o_attrib
->show_name_value
) {
1046 case SHOW_NAME_VALUE
: new_snv
= SHOW_NAME
; break;
1047 case SHOW_NAME
: new_snv
= SHOW_NAME_VALUE
; break;
1048 case SHOW_VALUE
: new_snv
= SHOW_NAME
; break;
1050 g_assert_not_reached ();
1051 new_snv
= SHOW_NAME_VALUE
;
1054 /* actually modifies the attribute */
1055 o_text_change(o_attrib
, NULL
, LEAVE_VISIBILITY_ALONE
, new_snv
);
1056 o_text_recreate(o_attrib
);
1057 o_text_draw (w_current
, o_attrib
);
1058 o_undo_savestate (w_current
, UNDO_ALL
);
1060 /* request an update of display for this row */
1061 update_row_display (model
, &iter
);
1065 /*! \todo Finish function documentation
1067 * \par Function Description
1070 static gboolean
multiattrib_callback_key_pressed(GtkWidget
*widget
,
1074 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1076 if (event
->state
== 0 &&
1077 (event
->keyval
== GDK_Delete
|| event
->keyval
== GDK_KP_Delete
)) {
1078 GtkTreeModel
*model
;
1081 /* delete the currently selected attribute */
1083 if (!gtk_tree_selection_get_selected (
1084 gtk_tree_view_get_selection (multiattrib
->treeview
),
1086 /* nothing selected, nothing to do */
1090 gtk_tree_model_get (model
, &iter
,
1091 COLUMN_ATTRIBUTE
, &o_attrib
,
1093 g_assert (o_attrib
->type
== OBJ_TEXT
);
1095 multiattrib_action_delete_attribute (GSCHEM_DIALOG (multiattrib
)->w_current
,
1098 /* update the treeview contents */
1099 multiattrib_update (multiattrib
);
1105 /*! \todo Finish function documentation
1107 * \par Function Description
1110 static gboolean
multiattrib_callback_button_pressed(GtkWidget
*widget
,
1111 GdkEventButton
*event
,
1114 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1115 gboolean ret
= FALSE
;
1117 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3) {
1118 multiattrib_popup_menu (multiattrib
, event
);
1125 /*! \todo Finish function documentation
1127 * \par Function Description
1130 static gboolean
multiattrib_callback_popup_menu(GtkWidget
*widget
,
1133 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1135 multiattrib_popup_menu (multiattrib
, NULL
);
1140 /*! \todo Finish function documentation
1142 * \par Function Description
1145 static void multiattrib_callback_popup_duplicate(GtkMenuItem
*menuitem
,
1148 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1149 GtkTreeModel
*model
;
1151 GSCHEM_TOPLEVEL
*w_current
;
1152 OBJECT
*object
, *o_attrib
;
1154 if (!gtk_tree_selection_get_selected (
1155 gtk_tree_view_get_selection (multiattrib
->treeview
),
1157 /* nothing selected, nothing to do */
1161 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1162 object
= multiattrib
->object
;
1164 gtk_tree_model_get (model
, &iter
,
1165 COLUMN_ATTRIBUTE
, &o_attrib
,
1167 g_assert (o_attrib
->type
== OBJ_TEXT
);
1169 multiattrib_action_duplicate_attribute (w_current
, object
, o_attrib
);
1171 /* update the treeview contents */
1172 multiattrib_update (multiattrib
);
1175 /*! \todo Finish function documentation
1177 * \par Function Description
1180 static void multiattrib_callback_popup_delete(GtkMenuItem
*menuitem
,
1183 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1184 GtkTreeModel
*model
;
1186 GSCHEM_TOPLEVEL
*w_current
;
1189 if (!gtk_tree_selection_get_selected (
1190 gtk_tree_view_get_selection (multiattrib
->treeview
),
1192 /* nothing selected, nothing to do */
1196 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1198 gtk_tree_model_get (model
, &iter
,
1199 COLUMN_ATTRIBUTE
, &o_attrib
,
1201 g_assert (o_attrib
->type
== OBJ_TEXT
);
1203 multiattrib_action_delete_attribute (w_current
, o_attrib
);
1205 /* update the treeview contents */
1206 multiattrib_update (multiattrib
);
1210 /*! \todo Finish function documentation
1212 * \par Function Description
1215 static gboolean
multiattrib_callback_value_key_pressed(GtkWidget
*widget
,
1219 Multiattrib
*multiattrib
= (Multiattrib
*)widget
;
1220 gboolean retval
= FALSE
;
1222 /* ends editing of cell if one of these keys are pressed: */
1223 /* - the Return key without the Control modifier */
1224 /* - the Tab key without the Control modifier */
1225 if ((event
->keyval
== GDK_Return
|| event
->keyval
== GDK_KP_Enter
) ||
1226 (event
->keyval
== GDK_Tab
|| event
->keyval
== GDK_KP_Tab
)) {
1227 /* Control modifier activated? */
1228 if (event
->state
& GDK_CONTROL_MASK
) {
1229 /* yes the modifier in event structure and let event propagate */
1230 event
->state
^= GDK_CONTROL_MASK
;
1233 /* change focus and stop propagation */
1234 g_signal_emit_by_name (multiattrib
,
1236 (event
->state
& GDK_SHIFT_MASK
) ?
1237 GTK_DIR_TAB_BACKWARD
: GTK_DIR_TAB_FORWARD
);
1246 /*! \brief GtkWidget "grab-focus" signal handler
1248 * \par Function Description
1249 * Select the text in the GtkTextView so it may be over-typed quickly
1251 static void multiattrib_callback_value_grab_focus (GtkWidget
*widget
,
1254 GtkTextView
*textview
= GTK_TEXT_VIEW (widget
);
1255 GtkTextBuffer
*textbuffer
;
1256 GtkTextIter startiter
, enditer
;
1258 textbuffer
= gtk_text_view_get_buffer (textview
);
1259 gtk_text_buffer_get_iter_at_offset (textbuffer
, &startiter
, 0);
1260 gtk_text_buffer_get_iter_at_offset (textbuffer
, &enditer
, -1);
1261 gtk_text_buffer_select_range (textbuffer
, &enditer
, &startiter
);
1265 /*! \todo Finish function documentation
1267 * \par Function Description
1270 static void multiattrib_callback_button_add(GtkButton
*button
,
1273 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1274 GtkTextBuffer
*buffer
;
1275 GtkTextIter start
, end
;
1278 GSCHEM_TOPLEVEL
*w_current
;
1280 gboolean button_visible
;
1283 w_current
= GSCHEM_DIALOG (multiattrib
)->w_current
;
1284 object
= multiattrib
->object
;
1285 buffer
= gtk_text_view_get_buffer (multiattrib
->textview_value
);
1287 /* retrieve information from the Add/Edit frame */
1288 /* - attribute's name */
1289 name
= gtk_entry_get_text (
1290 GTK_ENTRY (GTK_COMBO (multiattrib
->combo_name
)->entry
));
1291 /* - attribute's value */
1292 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
1293 value
= gtk_text_buffer_get_text (buffer
, &start
, &end
, FALSE
);
1294 /* - attribute's visibility status */
1295 button_visible
= gtk_toggle_button_get_active(
1296 (GtkToggleButton
*)multiattrib
->button_visible
);
1297 /* - visibility type */
1298 shownv
= (gint
)gtk_option_menu_get_history (multiattrib
->optionmenu_shownv
);
1300 if (name
[0] == '\0' || name
[0] == ' ') {
1301 /* name not allowed for an attribute */
1306 multiattrib_action_add_attribute (w_current
, object
, multiattrib
,
1308 button_visible
, shownv
);
1311 multiattrib_update (multiattrib
);
1314 /*! \todo Finish function documentation
1316 * \par Function Description
1319 static void multiattrib_init_attrib_names(GtkCombo
*combo
)
1321 GList
*items
= NULL
;
1322 const gchar
*string
;
1325 for (i
= 0, string
= s_attrib_get (i
);
1327 i
++, string
= s_attrib_get (i
)) {
1328 items
= g_list_append (items
, (gpointer
)string
);
1331 gtk_combo_set_popdown_strings (GTK_COMBO (combo
), items
);
1333 g_list_free (items
);
1337 /*! \todo Finish function documentation
1339 * \par Function Description
1342 static void multiattrib_init_visible_types(GtkOptionMenu
*optionmenu
)
1344 GtkWidget
*menu
, *item
;
1346 menu
= gtk_menu_new ();
1347 item
= gtk_menu_item_new_with_label (_("Show Name & Value"));
1348 gtk_menu_append (menu
, item
);
1349 item
= gtk_menu_item_new_with_label (_("Show Value only"));
1350 gtk_menu_append (menu
, item
);
1351 item
= gtk_menu_item_new_with_label (_("Show Name only"));
1352 gtk_menu_append (menu
, item
);
1354 gtk_option_menu_set_menu (optionmenu
, menu
);
1359 /*! \brief Popup a context-sensitive menu.
1360 * \par Function Description
1361 * Pops up a context-sensitive menu.
1362 * <B>event</B> can be NULL if the popup is triggered by a key binding
1363 * instead of a mouse click.
1365 * \param [in] multiattrib The Multiattrib object.
1366 * \param [in] event Mouse event.
1368 static void multiattrib_popup_menu(Multiattrib
*multiattrib
,
1369 GdkEventButton
*event
)
1377 struct menuitem_t menuitems
[] = {
1378 { N_("Duplicate"), G_CALLBACK (multiattrib_callback_popup_duplicate
) },
1379 { N_("Delete"), G_CALLBACK (multiattrib_callback_popup_delete
) },
1381 struct menuitem_t
*tmp
;
1383 if (event
!= NULL
&&
1384 gtk_tree_view_get_path_at_pos (multiattrib
->treeview
,
1387 &path
, NULL
, NULL
, NULL
)) {
1388 GtkTreeSelection
*selection
;
1389 selection
= gtk_tree_view_get_selection (multiattrib
->treeview
);
1390 gtk_tree_selection_unselect_all (selection
);
1391 gtk_tree_selection_select_path (selection
, path
);
1392 gtk_tree_path_free (path
);
1395 /* create the context menu */
1396 menu
= gtk_menu_new();
1397 for (tmp
= menuitems
; tmp
->label
!= NULL
; tmp
++) {
1398 GtkWidget
*menuitem
;
1399 if (strcmp(tmp
->label
, "-") == 0) {
1400 menuitem
= gtk_separator_menu_item_new ();
1402 menuitem
= gtk_menu_item_new_with_label (_(tmp
->label
));
1403 g_signal_connect (menuitem
,
1408 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1410 gtk_widget_show_all (menu
);
1411 /* make menu a popup menu */
1412 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
1413 (event
!= NULL
) ? event
->button
: 0,
1414 gdk_event_get_time ((GdkEvent
*)event
));
1419 /*! \brief Function to retrieve Multiattrib's GType identifier.
1421 * \par Function Description
1423 * Function to retrieve Multiattrib's GType identifier.
1424 * Upon first call, this registers Multiattrib in the GType system.
1425 * Subsequently it returns the saved value from its first execution.
1427 * \return the GType identifier associated with Multiattrib.
1429 GType
multiattrib_get_type()
1431 static GType multiattrib_type
= 0;
1433 if (!multiattrib_type
) {
1434 static const GTypeInfo multiattrib_info
= {
1435 sizeof(MultiattribClass
),
1436 NULL
, /* base_init */
1437 NULL
, /* base_finalize */
1438 (GClassInitFunc
) multiattrib_class_init
,
1439 NULL
, /* class_finalize */
1440 NULL
, /* class_data */
1441 sizeof(Multiattrib
),
1442 0, /* n_preallocs */
1443 (GInstanceInitFunc
) multiattrib_init
,
1446 multiattrib_type
= g_type_register_static (GSCHEM_TYPE_DIALOG
,
1448 &multiattrib_info
, 0);
1451 return multiattrib_type
;
1454 /*! \brief GType class initialiser for Multiattrib
1456 * \par Function Description
1458 * GType class initialiser for Multiattrib. We override our parent
1459 * virtual class methods as needed and register our GObject properties.
1461 * \param [in] klass The MultiattribClass we are initialising
1463 static void multiattrib_class_init(MultiattribClass
*klass
)
1465 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1467 multiattrib_parent_class
= g_type_class_peek_parent (klass
);
1469 gobject_class
->set_property
= multiattrib_set_property
;
1470 gobject_class
->get_property
= multiattrib_get_property
;
1472 g_object_class_install_property (
1473 gobject_class
, PROP_OBJECT
,
1474 g_param_spec_pointer ("object",
1477 G_PARAM_READWRITE
));
1481 /*! \brief GType instance initialiser for Multiattrib
1483 * \par Function Description
1485 * GType instance initialiser for Multiattrib. Create
1486 * and setup the widgets which make up the dialog.
1488 * \param [in] dialog The Multiattrib we are initialising
1490 static void multiattrib_init(Multiattrib
*multiattrib
)
1492 GtkWidget
*frame
, *label
, *scrolled_win
, *treeview
;
1493 GtkWidget
*table
, *textview
, *combo
, *optionm
, *button
;
1494 GtkTreeModel
*store
;
1495 GtkCellRenderer
*renderer
;
1496 GtkTreeViewColumn
*column
;
1497 GtkTreeSelection
*selection
;
1500 /* dialog initialization */
1501 g_object_set (G_OBJECT (multiattrib
),
1505 "title", _("Edit Attributes"),
1506 "default-width", 320,
1507 "default-height", 350,
1508 "window-position", GTK_WIN_POS_MOUSE
,
1510 "allow-shrink", FALSE
,
1512 "has-separator", TRUE
,
1515 multiattrib
->object
= NULL
;
1517 /* create the attribute list frame */
1518 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1520 "label", _("Attributes"),
1522 multiattrib
->frame_add
= frame
;
1523 /* - create the model for the treeview */
1524 store
= (GtkTreeModel
*)gtk_list_store_new (NUM_COLUMNS
,
1525 G_TYPE_POINTER
); /* attribute */
1526 /* - create a scrolled window for the treeview */
1527 scrolled_win
= GTK_WIDGET (
1528 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1531 /* GtkScrolledWindow */
1532 "hscrollbar-policy",
1533 GTK_POLICY_AUTOMATIC
,
1534 "vscrollbar-policy",
1535 GTK_POLICY_AUTOMATIC
,
1537 GTK_SHADOW_ETCHED_IN
,
1539 /* - create the treeview */
1540 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
1545 g_signal_connect (treeview
,
1547 G_CALLBACK (multiattrib_callback_key_pressed
),
1549 g_signal_connect (treeview
,
1550 "button-press-event",
1551 G_CALLBACK (multiattrib_callback_button_pressed
),
1553 g_signal_connect (treeview
,
1555 G_CALLBACK (multiattrib_callback_popup_menu
),
1557 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
1558 gtk_tree_selection_set_mode (selection
,
1559 GTK_SELECTION_SINGLE
);
1561 /* - and now the columns of the treeview */
1562 /* - column 1: attribute name */
1563 renderer
= GTK_CELL_RENDERER (
1564 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT
,
1565 /* GtkCellRendererText */
1567 /* unknown in GTK 2.4 */
1569 * PANGO_ELLIPSIZE_END, */
1571 g_signal_connect (renderer
,
1573 G_CALLBACK (multiattrib_callback_edited_name
),
1575 column
= GTK_TREE_VIEW_COLUMN (
1576 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1577 /* GtkTreeViewColumn */
1582 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1583 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1584 multiattrib_column_set_data_name
,
1586 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1587 /* - column 2: attribute value */
1588 renderer
= GTK_CELL_RENDERER (
1589 g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT
,
1590 /* GtkCellRendererText */
1592 /* unknown in GTK 2.4 */
1594 PANGO_ELLIPSIZE_END, */
1596 g_signal_connect (renderer
,
1598 G_CALLBACK (multiattrib_callback_edited_value
),
1600 column
= GTK_TREE_VIEW_COLUMN (
1601 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1602 /* GtkTreeViewColumn */
1603 "title", _("Value"),
1607 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1608 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1609 multiattrib_column_set_data_value
,
1611 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1612 /* - column 3: visibility */
1613 renderer
= GTK_CELL_RENDERER (
1614 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1615 /* GtkCellRendererToggle */
1616 "activatable", TRUE
,
1618 g_signal_connect (renderer
,
1620 G_CALLBACK (multiattrib_callback_toggled_visible
),
1622 column
= GTK_TREE_VIEW_COLUMN (
1623 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1624 /* GtkTreeViewColumn */
1627 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1628 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1629 multiattrib_column_set_data_visible
,
1631 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1632 /* - column 4: show name */
1633 renderer
= GTK_CELL_RENDERER (
1634 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1635 /* GtkCellRendererToggle */
1636 "activatable", TRUE
,
1638 g_signal_connect (renderer
,
1640 G_CALLBACK (multiattrib_callback_toggled_show_name
),
1642 column
= GTK_TREE_VIEW_COLUMN (
1643 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1644 /* GtkTreeViewColumn */
1647 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1648 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1649 multiattrib_column_set_data_show_name
,
1651 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1652 /* - column 5: show value */
1653 renderer
= GTK_CELL_RENDERER (
1654 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1655 /* GtkCellRendererToggle */
1656 "activatable", TRUE
,
1658 g_signal_connect (renderer
,
1660 G_CALLBACK (multiattrib_callback_toggled_show_value
),
1662 column
= GTK_TREE_VIEW_COLUMN (
1663 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1664 /* GtkTreeViewColumn */
1667 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1668 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1669 multiattrib_column_set_data_show_value
,
1671 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1673 /* add the treeview to the scrolled window */
1674 gtk_container_add (GTK_CONTAINER (scrolled_win
), treeview
);
1675 /* set treeview of multiattrib */
1676 multiattrib
->treeview
= GTK_TREE_VIEW (treeview
);
1677 /* add the scrolled window to frame */
1678 gtk_container_add (GTK_CONTAINER (frame
), scrolled_win
);
1679 /* pack the frame */
1680 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1682 gtk_widget_show_all (frame
);
1684 /* create the add/edit frame */
1685 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1686 "label", _("Add Attribute"),
1688 multiattrib
->frame_attributes
= frame
;
1689 table
= GTK_WIDGET (g_object_new (GTK_TYPE_TABLE
,
1693 "homogeneous", FALSE
,
1696 /* - the name entry: a GtkComboBoxEntry */
1697 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1702 "label", _("Name:"),
1704 combo
= GTK_WIDGET (g_object_new (GTK_TYPE_COMBO
,
1706 "value-in-list", FALSE
,
1708 multiattrib_init_attrib_names (GTK_COMBO (combo
));
1709 multiattrib
->combo_name
= GTK_COMBO (combo
);
1710 gtk_table_attach (GTK_TABLE (table
), label
,
1711 0, 1, 0, 1, 0, 0, 0, 0);
1712 gtk_table_attach (GTK_TABLE (table
), combo
,
1713 1, 2, 0, 1, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1715 /* - the value entry: a GtkEntry */
1716 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1721 "label", _("Value:"),
1723 scrolled_win
= GTK_WIDGET (
1724 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1725 /* GtkScrolledWindow */
1726 "hscrollbar-policy",
1728 "vscrollbar-policy",
1729 GTK_POLICY_AUTOMATIC
,
1733 textview
= GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW
,
1735 g_signal_connect (textview
,
1737 G_CALLBACK (multiattrib_callback_value_key_pressed
),
1739 g_signal_connect (textview
,
1741 G_CALLBACK (multiattrib_callback_value_grab_focus
),
1743 /* Save the GTK_STATE_NORMAL color so we can work around GtkTextView's
1744 * stubborn refusal to draw with GTK_STATE_INSENSITIVE later on */
1745 style
= gtk_widget_get_style (textview
);
1746 multiattrib
->value_normal_text_color
= style
->text
[ GTK_STATE_NORMAL
];
1748 gtk_container_add (GTK_CONTAINER (scrolled_win
), textview
);
1749 multiattrib
->textview_value
= GTK_TEXT_VIEW (textview
);
1750 gtk_table_attach (GTK_TABLE (table
), label
,
1751 0, 1, 1, 2, 0, 0, 0, 0);
1752 gtk_table_attach (GTK_TABLE (table
), scrolled_win
,
1753 1, 2, 1, 2, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1755 /* - the visible status */
1756 button
= GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON
,
1758 "label", _("Visible"),
1761 multiattrib
->button_visible
= GTK_CHECK_BUTTON (button
);
1762 gtk_table_attach (GTK_TABLE (table
), button
,
1763 0, 1, 2, 3, GTK_FILL
, 0, 3, 0);
1765 /* - the visibility type */
1766 optionm
= GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU
,
1768 multiattrib_init_visible_types (GTK_OPTION_MENU (optionm
));
1769 multiattrib
->optionmenu_shownv
= GTK_OPTION_MENU (optionm
);
1770 gtk_table_attach (GTK_TABLE (table
), optionm
,
1771 1, 2, 2, 3, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1772 gtk_widget_show_all (table
);
1774 /* create the add button */
1775 button
= gtk_button_new_from_stock (GTK_STOCK_ADD
);
1776 g_signal_connect (button
,
1778 G_CALLBACK (multiattrib_callback_button_add
),
1780 gtk_table_attach (GTK_TABLE (table
), button
,
1781 2, 3, 0, 3, 0, 0, 6, 3);
1783 /* add the table to the frame */
1784 gtk_container_add (GTK_CONTAINER (frame
), table
);
1785 /* pack the frame in the dialog */
1786 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1788 gtk_widget_show_all (frame
);
1791 /* now add the close button to the action area */
1792 gtk_dialog_add_button (GTK_DIALOG (multiattrib
),
1793 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
);
1798 /*! \brief GObject property setter function
1800 * \par Function Description
1801 * Setter function for Multiattrib's GObject property, "object".
1803 * \param [in] object The GObject whose properties we are setting
1804 * \param [in] property_id The numeric id. under which the property was
1805 * registered with g_object_class_install_property()
1806 * \param [in] value The GValue the property is being set from
1807 * \param [in] pspec A GParamSpec describing the property being set
1810 static void multiattrib_set_property (GObject
*object
,
1812 const GValue
*value
,
1815 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
1817 switch(property_id
) {
1819 multiattrib
->object
= (OBJECT
*)g_value_get_pointer (value
);
1820 multiattrib_update (multiattrib
);
1823 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1828 /*! \brief GObject property getter function
1830 * \par Function Description
1831 * Getter function for Multiattrib's GObject property, "object".
1833 * \param [in] object The GObject whose properties we are getting
1834 * \param [in] property_id The numeric id. under which the property was
1835 * registered with g_object_class_install_property()
1836 * \param [out] value The GValue in which to return the value of the property
1837 * \param [in] pspec A GParamSpec describing the property being got
1839 static void multiattrib_get_property (GObject
*object
,
1844 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
1846 switch(property_id
) {
1848 g_value_set_pointer (value
, (gpointer
)multiattrib
->object
);
1851 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1857 /*! \brief Update the multiattrib editor dialog's interface
1859 * \par Function Description
1861 * Update the dialog to reflect the attributes of the object. If
1862 * there is no object set, the dialog's controls are set insensitive.
1864 * \param [in] multiattrib The multi-attribute editor dialog.
1866 void multiattrib_update (Multiattrib
*multiattrib
)
1868 GtkListStore
*liststore
;
1870 OBJECT
**object_attribs
, *o_current
;
1875 /* clear the list of attributes */
1876 liststore
= (GtkListStore
*)gtk_tree_view_get_model (multiattrib
->treeview
);
1877 gtk_list_store_clear (liststore
);
1879 /* Update sensitivities */
1880 sensitive
= (multiattrib
->object
!= NULL
);
1881 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib
->frame_attributes
), sensitive
);
1882 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib
->frame_add
), sensitive
);
1884 /* Work around GtkTextView's stubborn indifference
1885 * to GTK_STATE_INSENSITIVE when rendering its text. */
1886 style
= gtk_widget_get_style (GTK_WIDGET (multiattrib
->textview_value
));
1887 gtk_widget_modify_text (GTK_WIDGET (multiattrib
->textview_value
),
1889 sensitive
? &multiattrib
->value_normal_text_color
1890 : &style
->text
[GTK_STATE_INSENSITIVE
]);
1892 /* If we aren't sensitive, there is nothing more to do */
1896 /* get list of attributes */
1897 object_attribs
= o_attrib_return_attribs (multiattrib
->object
);
1898 /* populate the store with attributes */
1899 if (object_attribs
) {
1900 for (i
= 0, o_current
= object_attribs
[i
];
1902 i
++, o_current
= object_attribs
[i
]) {
1904 /* Don't add invalid attributes to the list */
1905 if (!o_attrib_get_name_value(o_text_get_string(o_current
), NULL
, NULL
))
1908 gtk_list_store_append (liststore
, &iter
);
1909 gtk_list_store_set (liststore
, &iter
,
1910 COLUMN_ATTRIBUTE
, o_current
,
1914 /* delete the list of attribute objects */
1915 o_attrib_free_returned (object_attribs
);