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
30 #include <libgeda/libgeda.h>
32 #include "../include/i_vars.h"
33 #include "../include/globals.h"
34 #include "../include/prototype.h"
36 #ifdef HAVE_LIBDMALLOC
40 #include <gdk/gdkkeysyms.h>
41 #include "../include/gschem_dialog.h"
42 #include "../include/x_multiattrib.h"
44 /*! \brief Process the response returned by the multi-attribte dialog.
45 * \par Function Description
46 * This function handles the response <B>arg1</B> of the multi-attribute
47 * editor dialog <B>dialog</B>.
49 * \param [in] dialog The multi-attribute editor dialog.
50 * \param [in] arg1 The response ID.
51 * \param [in] user_data A pointer on the toplevel environment.
54 multiattrib_callback_response (GtkDialog
*dialog
,
58 TOPLEVEL
*toplevel
= (TOPLEVEL
*)user_data
;
61 case GTK_RESPONSE_CLOSE
:
62 case GTK_RESPONSE_DELETE_EVENT
:
63 gtk_widget_destroy (GTK_WIDGET (dialog
));
64 toplevel
->mawindow
= NULL
;
69 /*! \brief Open multiple attribute editor dialog.
70 * \par Function Description
71 * Opens the multiple attribute editor dialog for objects in this <B>toplevel</B>.
73 * \param [in] toplevel The TOPLEVEL object.
75 void x_multiattrib_open (TOPLEVEL
*toplevel
)
77 if ( toplevel
->mawindow
== NULL
) {
78 toplevel
->mawindow
= GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB
,
79 "selection", toplevel
->page_current
->selection_list
,
81 "settings-name", "multiattrib",
85 g_signal_connect (toplevel
->mawindow
,
87 G_CALLBACK (multiattrib_callback_response
),
90 gtk_window_set_transient_for (GTK_WINDOW(toplevel
->mawindow
),
91 GTK_WINDOW(toplevel
->main_window
));
93 gtk_widget_show (toplevel
->mawindow
);
95 gtk_window_present (GTK_WINDOW(toplevel
->mawindow
));
100 /*! \brief Close the multiattrib dialog.
102 * \par Function Description
104 * Closes the multiattrib dialog associated with <B>toplevel</B>.
106 * \param [in] toplevel The TOPLEVEL object.
108 void x_multiattrib_close (TOPLEVEL
*toplevel
)
110 if (toplevel
->mawindow
!= NULL
) {
111 gtk_widget_destroy (toplevel
->mawindow
);
112 toplevel
->mawindow
= NULL
;
117 /*! \brief Update the multiattrib editor dialog for a TOPLEVEL.
119 * \par Function Description
121 * If the TOPLEVEL has an open multiattrib dialog, switch to
122 * watching the current page's SELECTION object for changes.
124 * \param [in] toplevel The TOPLEVEL object.
126 void x_multiattrib_update( TOPLEVEL
*toplevel
)
128 if (toplevel
->mawindow
!= NULL
) {
129 g_object_set (G_OBJECT (toplevel
->mawindow
), "selection",
130 toplevel
->page_current
->selection_list
, NULL
);
135 /*! \section celltextview-widget Cell TextView Widget Code.
136 * This widget makes a 'GtkTextView' widget implements the 'GtkCellEditable'
137 * interface. It can then be used to renderer multi-line texts inside
138 * tree views ('GtkTreeView').
140 static void celltextview_class_init (CellTextViewClass
*klass
);
141 static void celltextview_init (CellTextView
*self
);
142 static void celltextview_cell_editable_init (GtkCellEditableIface
*iface
);
144 /*! \todo Finish function documentation
146 * \par Function Description
149 static gboolean
celltextview_key_press_event (GtkWidget
*widget
,
150 GdkEventKey
*key_event
,
153 CellTextView
*celltextview
= (CellTextView
*)widget
;
155 /* If the Escape key is pressed, we flag the edit as canceled */
156 if (key_event
->keyval
== GDK_Escape
)
157 celltextview
->editing_canceled
= TRUE
;
159 /* ends editing of cell if one of these keys are pressed or editing is canceled */
160 if (celltextview
->editing_canceled
== TRUE
||
161 /* the Enter key without the Control modifier */
162 (!(key_event
->state
& GDK_CONTROL_MASK
) &&
163 (key_event
->keyval
== GDK_Return
||
164 key_event
->keyval
== GDK_KP_Enter
))) {
165 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (celltextview
));
166 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (celltextview
));
173 /*! \todo Finish function documentation
175 * \par Function Description
178 static void celltextview_start_editing (GtkCellEditable
*cell_editable
,
181 g_signal_connect (cell_editable
,
183 G_CALLBACK (celltextview_key_press_event
),
188 /*! \todo Finish function documentation
190 * \par Function Description
193 GType
celltextview_get_type()
195 static GType celltextview_type
= 0;
197 if (!celltextview_type
) {
198 static const GTypeInfo celltextview_info
= {
199 sizeof(CellTextViewClass
),
200 NULL
, /* base_init */
201 NULL
, /* base_finalize */
202 (GClassInitFunc
) celltextview_class_init
,
203 NULL
, /* class_finalize */
204 NULL
, /* class_data */
205 sizeof(CellTextView
),
207 (GInstanceInitFunc
) celltextview_init
,
210 static const GInterfaceInfo cell_editable_info
= {
211 (GInterfaceInitFunc
) celltextview_cell_editable_init
,
212 NULL
, /* interface_finalize */
213 NULL
/* interface_data */
216 celltextview_type
= g_type_register_static(GTK_TYPE_TEXT_VIEW
,
218 &celltextview_info
, 0);
219 g_type_add_interface_static(celltextview_type
,
220 GTK_TYPE_CELL_EDITABLE
,
221 &cell_editable_info
);
224 return celltextview_type
;
227 /*! \todo Finish function documentation
229 * \par Function Description
232 static void celltextview_class_init(CellTextViewClass
*klass
)
234 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
237 /*! \todo Finish function documentation
239 * \par Function Description
242 static void celltextview_init(CellTextView
*celltextview
)
244 celltextview
->editing_canceled
= FALSE
;
247 /*! \todo Finish function documentation
249 * \par Function Description
252 static void celltextview_cell_editable_init(GtkCellEditableIface
*iface
)
254 iface
->start_editing
= celltextview_start_editing
;
257 /*! \section multi-line-text-cell-renderer Multi-line Text Cell Renderer
258 * GTK has no multi-line text cell renderer. This code adds one to be used
259 * in gschem code. It is inspired by the 'GtkCellRendererCombo' renderer
262 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
);
263 static void cellrenderermultilinetext_init (CellRendererMultiLineText
*self
);
265 static void cellrenderermultilinetext_editing_done (GtkCellEditable
*cell_editable
,
267 static gboolean
cellrenderermultilinetext_focus_out_event (GtkWidget
*widget
,
272 #define CELL_RENDERER_MULTI_LINE_TEXT_PATH "cell-renderer-multi-line-text-path"
275 /*! \todo Finish function documentation
277 * \par Function Description
280 static GtkCellEditable
* cellrenderermultilinetext_start_editing(GtkCellRenderer
*cell
,
284 GdkRectangle
*background_area
,
285 GdkRectangle
*cell_area
,
286 GtkCellRendererState flags
)
288 GtkCellRendererText
*cell_text
;
289 CellRendererMultiLineText
*cell_mlt
;
291 GtkTextBuffer
*textbuffer
;
293 cell_text
= GTK_CELL_RENDERER_TEXT (cell
);
294 if (cell_text
->editable
== FALSE
) {
298 cell_mlt
= CELL_RENDERER_MULTI_LINE_TEXT (cell
);
300 textbuffer
= GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER
,
302 gtk_text_buffer_set_text (textbuffer
,
304 strlen (cell_text
->text
));
306 textview
= GTK_WIDGET (g_object_new (TYPE_CELL_TEXT_VIEW
,
308 "buffer", textbuffer
,
311 "height-request", cell_area
->height
,
313 g_object_set_data_full (G_OBJECT (textview
),
314 CELL_RENDERER_MULTI_LINE_TEXT_PATH
,
315 g_strdup (path
), g_free
);
317 gtk_widget_show (textview
);
319 g_signal_connect (GTK_CELL_EDITABLE (textview
),
321 G_CALLBACK (cellrenderermultilinetext_editing_done
),
323 cell_mlt
->focus_out_id
=
324 g_signal_connect (textview
,
326 G_CALLBACK (cellrenderermultilinetext_focus_out_event
),
329 return GTK_CELL_EDITABLE (textview
);
332 /*! \todo Finish function documentation
334 * \par Function Description
337 static void cellrenderermultilinetext_editing_done(GtkCellEditable
*cell_editable
,
340 CellRendererMultiLineText
*cell
= CELL_RENDERER_MULTI_LINE_TEXT (user_data
);
341 GtkTextBuffer
*buffer
;
342 GtkTextIter start
, end
;
346 if (cell
->focus_out_id
> 0) {
347 g_signal_handler_disconnect (cell_editable
,
349 cell
->focus_out_id
= 0;
352 gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (cell
),
353 CELL_TEXT_VIEW (cell_editable
)->editing_canceled
);
354 if (CELL_TEXT_VIEW (cell_editable
)->editing_canceled
)
357 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (cell_editable
));
358 gtk_text_buffer_get_start_iter (buffer
, &start
);
359 gtk_text_buffer_get_end_iter (buffer
, &end
);
360 new_text
= gtk_text_buffer_get_text (buffer
, &start
, &end
, TRUE
);
362 path
= g_object_get_data (G_OBJECT (cell_editable
),
363 CELL_RENDERER_MULTI_LINE_TEXT_PATH
);
364 g_signal_emit_by_name (cell
, "edited", path
, new_text
);
370 /*! \todo Finish function documentation
372 * \par Function Description
375 static gboolean
cellrenderermultilinetext_focus_out_event(GtkWidget
*widget
,
379 cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget
),
385 /*! \todo Finish function documentation
387 * \par Function Description
390 GType
cellrenderermultilinetext_get_type()
392 static GType cellrenderermultilinetext_type
= 0;
394 if (!cellrenderermultilinetext_type
) {
395 static const GTypeInfo cellrenderermultilinetext_info
= {
396 sizeof(CellRendererMultiLineTextClass
),
397 NULL
, /* base_init */
398 NULL
, /* base_finalize */
399 (GClassInitFunc
) cellrenderermultilinetext_class_init
,
400 NULL
, /* class_finalize */
401 NULL
, /* class_data */
402 sizeof(CellRendererMultiLineText
),
404 (GInstanceInitFunc
) cellrenderermultilinetext_init
,
407 cellrenderermultilinetext_type
= g_type_register_static (
408 GTK_TYPE_CELL_RENDERER_TEXT
,
409 "CellRendererMultiLineText",
410 &cellrenderermultilinetext_info
, 0);
413 return cellrenderermultilinetext_type
;
416 /*! \todo Finish function documentation
418 * \par Function Description
421 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
)
423 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
424 GtkCellRendererClass
*cell_class
= GTK_CELL_RENDERER_CLASS (klass
);
426 cell_class
->start_editing
= cellrenderermultilinetext_start_editing
;
430 /*! \todo Finish function documentation
432 * \par Function Description
435 static void cellrenderermultilinetext_init(CellRendererMultiLineText
*self
)
449 static GObjectClass
*multiattrib_parent_class
= NULL
;
451 static void multiattrib_class_init (MultiattribClass
*class);
452 static void multiattrib_init (Multiattrib
*multiattrib
);
453 static void multiattrib_set_property (GObject
*object
,
457 static void multiattrib_get_property (GObject
*object
,
462 static void multiattrib_popup_menu (Multiattrib
*multiattrib
,
463 GdkEventButton
*event
);
466 /*! \todo Finish function documentation
468 * \par Function Description
471 static void multiattrib_action_add_attribute(TOPLEVEL
*toplevel
,
473 Multiattrib
*multiattrib
,
477 gint show_name_value
)
482 newtext
= g_strdup_printf ("%s=%s", name
, value
);
484 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
489 /* create a new attribute and link it */
490 o_attrib
= o_attrib_add_attrib (toplevel
, newtext
,
491 visible
, show_name_value
, object
);
493 toplevel
->page_current
->CHANGED
= 1;
494 o_undo_savestate (toplevel
, UNDO_ALL
);
500 /*! \todo Finish function documentation
502 * \par Function Description
505 static void multiattrib_action_duplicate_attribute(TOPLEVEL
*toplevel
,
511 o_new
= o_attrib_add_attrib (toplevel
,
512 o_attrib
->text
->string
,
513 o_attrib
->visibility
,
514 o_attrib
->show_name_value
,
516 toplevel
->page_current
->CHANGED
= 1;
517 o_undo_savestate (toplevel
, UNDO_ALL
);
521 /*! \todo Finish function documentation
523 * \par Function Description
526 static void multiattrib_action_delete_attribute(TOPLEVEL
*toplevel
,
529 /* actually deletes the attribute */
530 o_selection_remove ( toplevel
->page_current
->selection_list
, o_attrib
);
531 o_delete_text (toplevel
, o_attrib
);
532 toplevel
->page_current
->CHANGED
=1;
533 o_undo_savestate (toplevel
, UNDO_ALL
);
537 /*! \todo Finish function documentation
539 * \par Function Description
542 static void multiattrib_column_set_data_name(GtkTreeViewColumn
*tree_column
,
543 GtkCellRenderer
*cell
,
544 GtkTreeModel
*tree_model
,
551 gtk_tree_model_get (tree_model
, iter
,
552 COLUMN_ATTRIBUTE
, &o_attrib
,
554 g_assert (o_attrib
->type
== OBJ_TEXT
);
556 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
565 /*! \todo Finish function documentation
567 * \par Function Description
570 static void multiattrib_column_set_data_value(GtkTreeViewColumn
*tree_column
,
571 GtkCellRenderer
*cell
,
572 GtkTreeModel
*tree_model
,
579 gtk_tree_model_get (tree_model
, iter
,
580 COLUMN_ATTRIBUTE
, &o_attrib
,
582 g_assert (o_attrib
->type
== OBJ_TEXT
);
584 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
593 /*! \todo Finish function documentation
595 * \par Function Description
598 static void multiattrib_column_set_data_visible(GtkTreeViewColumn
*tree_column
,
599 GtkCellRenderer
*cell
,
600 GtkTreeModel
*tree_model
,
606 gtk_tree_model_get (tree_model
, iter
,
607 COLUMN_ATTRIBUTE
, &o_attrib
,
609 g_assert (o_attrib
->type
== OBJ_TEXT
);
612 "active", (o_attrib
->visibility
== VISIBLE
),
617 /*! \todo Finish function documentation
619 * \par Function Description
622 static void multiattrib_column_set_data_show_name(GtkTreeViewColumn
*tree_column
,
623 GtkCellRenderer
*cell
,
624 GtkTreeModel
*tree_model
,
630 gtk_tree_model_get (tree_model
, iter
,
631 COLUMN_ATTRIBUTE
, &o_attrib
,
633 g_assert (o_attrib
->type
== OBJ_TEXT
);
636 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
637 o_attrib
->show_name_value
== SHOW_NAME
),
642 /*! \todo Finish function documentation
644 * \par Function Description
647 static void multiattrib_column_set_data_show_value(GtkTreeViewColumn
*tree_column
,
648 GtkCellRenderer
*cell
,
649 GtkTreeModel
*tree_model
,
655 gtk_tree_model_get (tree_model
, iter
,
656 COLUMN_ATTRIBUTE
, &o_attrib
,
658 g_assert (o_attrib
->type
== OBJ_TEXT
);
661 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
662 o_attrib
->show_name_value
== SHOW_VALUE
),
667 /*! \brief Requests an update of the display of a row.
668 * \par Function Description
669 * This is an helper function to update the display of a row when
670 * data for this row have been modified in the model.
672 * It emits the 'row_changed' signal on the pointed row.
674 * \param [in] model A GtkTreeModel.
675 * \param [in] iter A valid GtkTreeIter pointing to the changed row.
678 update_row_display (GtkTreeModel
*model
, GtkTreeIter
*iter
)
682 path
= gtk_tree_model_get_path (model
, iter
);
683 gtk_tree_model_row_changed (model
, path
, iter
);
684 gtk_tree_path_free (path
);
688 /*! \todo Finish function documentation
690 * \par Function Description
693 static void multiattrib_callback_edited_name(GtkCellRendererText
*cellrenderertext
,
698 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
703 gchar
*name
, *value
, *newtext
;
705 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
706 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
708 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
712 if (g_ascii_strcasecmp (arg2
, "") == 0) {
713 GtkWidget
*dialog
= gtk_message_dialog_new (
714 GTK_WINDOW (multiattrib
),
718 _("Attributes with empty name are not allowed. Please set a name."));
720 gtk_dialog_run (GTK_DIALOG (dialog
));
721 gtk_widget_destroy (dialog
);
725 gtk_tree_model_get (model
, &iter
,
726 COLUMN_ATTRIBUTE
, &o_attrib
,
728 g_assert (o_attrib
->type
== OBJ_TEXT
);
730 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
731 newtext
= g_strdup_printf ("%s=%s", arg2
, value
);
733 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
734 if (name
) g_free (name
);
735 if (value
) g_free (value
);
741 /* actually modifies the attribute */
742 o_text_change (toplevel
, o_attrib
,
743 newtext
, o_attrib
->visibility
, o_attrib
->show_name_value
);
751 /*! \todo Finish function documentation
753 * \par Function Description
756 static void multiattrib_callback_edited_value(GtkCellRendererText
*cell_renderer
,
761 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
766 gchar
*name
, *value
, *newtext
;
768 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
769 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
771 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
775 gtk_tree_model_get (model
, &iter
,
776 COLUMN_ATTRIBUTE
, &o_attrib
,
778 g_assert (o_attrib
->type
== OBJ_TEXT
);
780 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
781 newtext
= g_strdup_printf ("%s=%s", name
, arg2
);
783 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib
), newtext
)) {
784 if (name
) g_free (name
);
785 if (value
) g_free (value
);
790 /* actually modifies the attribute */
791 o_text_change (toplevel
, o_attrib
,
792 newtext
, o_attrib
->visibility
, o_attrib
->show_name_value
);
794 /* request an update of display for this row */
795 update_row_display (model
, &iter
);
803 /*! \todo Finish function documentation
805 * \par Function Description
808 static void multiattrib_callback_toggled_visible(GtkCellRendererToggle
*cell_renderer
,
812 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
819 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
820 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
822 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
826 gtk_tree_model_get (model
, &iter
,
827 COLUMN_ATTRIBUTE
, &o_attrib
,
829 g_assert (o_attrib
->type
== OBJ_TEXT
);
830 o_text_erase (toplevel
, o_attrib
);
832 visibility
= o_attrib
->visibility
== VISIBLE
? INVISIBLE
: VISIBLE
;
834 /* actually modifies the attribute */
835 o_attrib
->visibility
= visibility
;
836 o_text_recreate (toplevel
, o_attrib
);
837 o_text_draw (toplevel
, o_attrib
);
838 o_undo_savestate (toplevel
, UNDO_ALL
);
840 /* request an update of display for this row */
841 update_row_display (model
, &iter
);
845 /*! \todo Finish function documentation
847 * \par Function Description
850 static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle
*cell_renderer
,
854 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
861 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
862 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
864 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
868 gtk_tree_model_get (model
, &iter
,
869 COLUMN_ATTRIBUTE
, &o_attrib
,
871 g_assert (o_attrib
->type
== OBJ_TEXT
);
872 o_text_erase (toplevel
, o_attrib
);
874 switch (o_attrib
->show_name_value
) {
875 case SHOW_NAME_VALUE
: new_snv
= SHOW_VALUE
; break;
876 case SHOW_NAME
: new_snv
= SHOW_VALUE
; break;
877 case SHOW_VALUE
: new_snv
= SHOW_NAME_VALUE
; break;
879 g_assert_not_reached ();
880 new_snv
= SHOW_NAME_VALUE
;
883 /* actually modifies the attribute */
884 o_attrib
->show_name_value
= new_snv
;
885 o_text_recreate (toplevel
, o_attrib
);
886 o_text_draw (toplevel
, o_attrib
);
887 o_undo_savestate (toplevel
, UNDO_ALL
);
889 /* request an update of display for this row */
890 update_row_display (model
, &iter
);
894 /*! \todo Finish function documentation
896 * \par Function Description
899 static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle
*cell_renderer
,
903 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
910 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
911 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
913 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
917 gtk_tree_model_get (model
, &iter
,
918 COLUMN_ATTRIBUTE
, &o_attrib
,
920 g_assert (o_attrib
->type
== OBJ_TEXT
);
921 o_text_erase (toplevel
, o_attrib
);
923 switch (o_attrib
->show_name_value
) {
924 case SHOW_NAME_VALUE
: new_snv
= SHOW_NAME
; break;
925 case SHOW_NAME
: new_snv
= SHOW_NAME_VALUE
; break;
926 case SHOW_VALUE
: new_snv
= SHOW_NAME
; break;
928 g_assert_not_reached ();
929 new_snv
= SHOW_NAME_VALUE
;
932 /* actually modifies the attribute */
933 o_attrib
->show_name_value
= new_snv
;
934 o_text_recreate (toplevel
, o_attrib
);
935 o_text_draw (toplevel
, o_attrib
);
936 o_undo_savestate (toplevel
, UNDO_ALL
);
938 /* request an update of display for this row */
939 update_row_display (model
, &iter
);
943 /*! \todo Finish function documentation
945 * \par Function Description
948 static gboolean
multiattrib_callback_key_pressed(GtkWidget
*widget
,
952 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
954 if (event
->state
== 0 &&
955 (event
->keyval
== GDK_Delete
|| event
->keyval
== GDK_KP_Delete
)) {
959 /* delete the currently selected attribute */
961 if (!gtk_tree_selection_get_selected (
962 gtk_tree_view_get_selection (multiattrib
->treeview
),
964 /* nothing selected, nothing to do */
968 gtk_tree_model_get (model
, &iter
,
969 COLUMN_ATTRIBUTE
, &o_attrib
,
971 g_assert (o_attrib
->type
== OBJ_TEXT
);
973 multiattrib_action_delete_attribute (GSCHEM_DIALOG (multiattrib
)->toplevel
,
976 /* update the treeview contents */
977 multiattrib_update (multiattrib
);
983 /*! \todo Finish function documentation
985 * \par Function Description
988 static gboolean
multiattrib_callback_button_pressed(GtkWidget
*widget
,
989 GdkEventButton
*event
,
992 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
993 gboolean ret
= FALSE
;
995 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3) {
996 multiattrib_popup_menu (multiattrib
, event
);
1003 /*! \todo Finish function documentation
1005 * \par Function Description
1008 static gboolean
multiattrib_callback_popup_menu(GtkWidget
*widget
,
1011 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1013 multiattrib_popup_menu (multiattrib
, NULL
);
1018 /*! \todo Finish function documentation
1020 * \par Function Description
1023 static void multiattrib_callback_popup_duplicate(GtkMenuItem
*menuitem
,
1026 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1027 GtkTreeModel
*model
;
1030 OBJECT
*object
, *o_attrib
;
1032 if (!gtk_tree_selection_get_selected (
1033 gtk_tree_view_get_selection (multiattrib
->treeview
),
1035 /* nothing selected, nothing to do */
1039 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
1040 object
= multiattrib
->object
;
1042 gtk_tree_model_get (model
, &iter
,
1043 COLUMN_ATTRIBUTE
, &o_attrib
,
1045 g_assert (o_attrib
->type
== OBJ_TEXT
);
1047 multiattrib_action_duplicate_attribute (toplevel
, object
, o_attrib
);
1049 /* update the treeview contents */
1050 multiattrib_update (multiattrib
);
1054 /*! \todo Finish function documentation
1056 * \par Function Description
1059 static void multiattrib_callback_popup_delete(GtkMenuItem
*menuitem
,
1062 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1063 GtkTreeModel
*model
;
1068 if (!gtk_tree_selection_get_selected (
1069 gtk_tree_view_get_selection (multiattrib
->treeview
),
1071 /* nothing selected, nothing to do */
1075 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
1077 gtk_tree_model_get (model
, &iter
,
1078 COLUMN_ATTRIBUTE
, &o_attrib
,
1080 g_assert (o_attrib
->type
== OBJ_TEXT
);
1082 multiattrib_action_delete_attribute (toplevel
, o_attrib
);
1084 /* update the treeview contents */
1085 multiattrib_update (multiattrib
);
1089 /*! \todo Finish function documentation
1091 * \par Function Description
1094 static gboolean
multiattrib_callback_value_key_pressed(GtkWidget
*widget
,
1098 Multiattrib
*multiattrib
= (Multiattrib
*)widget
;
1099 gboolean retval
= FALSE
;
1101 /* ends editing of cell if one of these keys are pressed: */
1102 /* - the Return key without the Control modifier */
1103 /* - the Tab key without the Control modifier */
1104 if ((event
->keyval
== GDK_Return
|| event
->keyval
== GDK_KP_Enter
) ||
1105 (event
->keyval
== GDK_Tab
|| event
->keyval
== GDK_KP_Tab
)) {
1106 /* Control modifier activated? */
1107 if (event
->state
& GDK_CONTROL_MASK
) {
1108 /* yes the modifier in event structure and let event propagate */
1109 event
->state
^= GDK_CONTROL_MASK
;
1112 /* change focus and stop propagation */
1113 g_signal_emit_by_name (multiattrib
,
1115 (event
->state
& GDK_SHIFT_MASK
) ?
1116 GTK_DIR_TAB_BACKWARD
: GTK_DIR_TAB_FORWARD
);
1125 /*! \brief GtkWidget "grab-focus" signal handler
1127 * \par Function Description
1128 * Select the text in the GtkTextView so it may be over-typed quickly
1130 static void multiattrib_callback_value_grab_focus (GtkWidget
*widget
,
1133 GtkTextView
*textview
= GTK_TEXT_VIEW (widget
);
1134 GtkTextBuffer
*textbuffer
;
1135 GtkTextIter startiter
, enditer
;
1137 textbuffer
= gtk_text_view_get_buffer (textview
);
1138 gtk_text_buffer_get_iter_at_offset (textbuffer
, &startiter
, 0);
1139 gtk_text_buffer_get_iter_at_offset (textbuffer
, &enditer
, -1);
1140 gtk_text_buffer_select_range (textbuffer
, &enditer
, &startiter
);
1144 /*! \todo Finish function documentation
1146 * \par Function Description
1149 static void multiattrib_callback_button_add(GtkButton
*button
,
1152 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1153 GtkTextBuffer
*buffer
;
1154 GtkTextIter start
, end
;
1162 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
1163 object
= multiattrib
->object
;
1164 buffer
= gtk_text_view_get_buffer (multiattrib
->textview_value
);
1166 /* retrieve information from the Add/Edit frame */
1167 /* - attribute's name */
1168 name
= gtk_entry_get_text (
1169 GTK_ENTRY (GTK_COMBO (multiattrib
->combo_name
)->entry
));
1170 /* - attribute's value */
1171 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
1172 value
= gtk_text_buffer_get_text (buffer
, &start
, &end
, FALSE
);
1173 /* - attribute's visibility status */
1174 visible
= gtk_toggle_button_get_active (
1175 (GtkToggleButton
*)multiattrib
->button_visible
);
1176 /* - visibility type */
1177 shownv
= (gint
)gtk_option_menu_get_history (multiattrib
->optionmenu_shownv
);
1179 if (name
[0] == '\0' || name
[0] == ' ') {
1180 /* name not allowed for an attribute */
1185 multiattrib_action_add_attribute (toplevel
, object
, multiattrib
,
1190 multiattrib_update (multiattrib
);
1193 /*! \todo Finish function documentation
1195 * \par Function Description
1198 static void multiattrib_init_attrib_names(GtkCombo
*combo
)
1200 GList
*items
= NULL
;
1201 const gchar
*string
;
1204 for (i
= 0, string
= s_attrib_get (i
);
1206 i
++, string
= s_attrib_get (i
)) {
1207 items
= g_list_append (items
, (gpointer
)string
);
1210 gtk_combo_set_popdown_strings (GTK_COMBO (combo
), items
);
1212 g_list_free (items
);
1216 /*! \todo Finish function documentation
1218 * \par Function Description
1221 static void multiattrib_init_visible_types(GtkOptionMenu
*optionmenu
)
1223 GtkWidget
*menu
, *item
;
1225 menu
= gtk_menu_new ();
1226 item
= gtk_menu_item_new_with_label (_("Show Name & Value"));
1227 gtk_menu_append (menu
, item
);
1228 item
= gtk_menu_item_new_with_label (_("Show Value only"));
1229 gtk_menu_append (menu
, item
);
1230 item
= gtk_menu_item_new_with_label (_("Show Name only"));
1231 gtk_menu_append (menu
, item
);
1233 gtk_option_menu_set_menu (optionmenu
, menu
);
1238 /*! \brief Popup a context-sensitive menu.
1239 * \par Function Description
1240 * Pops up a context-sensitive menu.
1241 * <B>event</B> can be NULL if the popup is triggered by a key binding
1242 * instead of a mouse click.
1244 * \param [in] multiattrib The Multiattrib object.
1245 * \param [in] event Mouse event.
1247 static void multiattrib_popup_menu(Multiattrib
*multiattrib
,
1248 GdkEventButton
*event
)
1256 struct menuitem_t menuitems
[] = {
1257 { N_("Duplicate"), G_CALLBACK (multiattrib_callback_popup_duplicate
) },
1258 { N_("Delete"), G_CALLBACK (multiattrib_callback_popup_delete
) },
1260 struct menuitem_t
*tmp
;
1262 if (event
!= NULL
&&
1263 gtk_tree_view_get_path_at_pos (multiattrib
->treeview
,
1266 &path
, NULL
, NULL
, NULL
)) {
1267 GtkTreeSelection
*selection
;
1268 selection
= gtk_tree_view_get_selection (multiattrib
->treeview
);
1269 gtk_tree_selection_unselect_all (selection
);
1270 gtk_tree_selection_select_path (selection
, path
);
1271 gtk_tree_path_free (path
);
1274 /* create the context menu */
1275 menu
= gtk_menu_new();
1276 for (tmp
= menuitems
; tmp
->label
!= NULL
; tmp
++) {
1277 GtkWidget
*menuitem
;
1278 if (g_strcasecmp (tmp
->label
, "-") == 0) {
1279 menuitem
= gtk_separator_menu_item_new ();
1281 menuitem
= gtk_menu_item_new_with_label (_(tmp
->label
));
1282 g_signal_connect (menuitem
,
1287 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1289 gtk_widget_show_all (menu
);
1290 /* make menu a popup menu */
1291 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
1292 (event
!= NULL
) ? event
->button
: 0,
1293 gdk_event_get_time ((GdkEvent
*)event
));
1298 /*! \brief Function to retrieve Multiattrib's GType identifier.
1300 * \par Function Description
1302 * Function to retrieve Multiattrib's GType identifier.
1303 * Upon first call, this registers Multiattrib in the GType system.
1304 * Subsequently it returns the saved value from its first execution.
1306 * \return the GType identifier associated with Multiattrib.
1308 GType
multiattrib_get_type()
1310 static GType multiattrib_type
= 0;
1312 if (!multiattrib_type
) {
1313 static const GTypeInfo multiattrib_info
= {
1314 sizeof(MultiattribClass
),
1315 NULL
, /* base_init */
1316 NULL
, /* base_finalize */
1317 (GClassInitFunc
) multiattrib_class_init
,
1318 NULL
, /* class_finalize */
1319 NULL
, /* class_data */
1320 sizeof(Multiattrib
),
1321 0, /* n_preallocs */
1322 (GInstanceInitFunc
) multiattrib_init
,
1325 multiattrib_type
= g_type_register_static (GSCHEM_TYPE_DIALOG
,
1327 &multiattrib_info
, 0);
1330 return multiattrib_type
;
1334 /*! \brief Update the multiattrib editor dialog when the page's selection changes.
1336 * \par Function Description
1338 * When the page's selection changes this function identifies how many objects
1339 * which can have attributes are currently selected. If this number is 1, the
1340 * dialog is set to edit its attributes.
1342 * \todo The dialog doesn't currently support editing multiple objects at once
1344 * \param [in] selection The SELECTION object of page being edited.
1345 * \param [in] multiattrib The multi-attribute editor dialog.
1347 static void selection_changed_cb (SELECTION
*selection
, Multiattrib
*multiattrib
)
1349 int object_count
= 0;
1350 GList
*selection_glist
;
1354 selection_glist
= geda_list_get_glist (selection
);
1356 for ( iter
= selection_glist
;
1358 iter
= g_list_next (iter
) ) {
1359 object
= (OBJECT
*)iter
->data
;
1360 g_assert( object
!= NULL
);
1362 if (object
->type
== OBJ_COMPLEX
||
1363 object
->type
== OBJ_PLACEHOLDER
||
1364 object
->type
== OBJ_NET
||
1365 object
->type
== OBJ_BUS
||
1366 object
->type
== OBJ_PIN
) {
1371 if (object_count
== 0) {
1372 /* TODO: If the user selects a single attribute which is
1373 * not floating, should we find its parent object and
1374 * display the multi-attribute editor for that?
1375 * Bonus marks for making it jump to the correct attrib.
1377 multiattrib
->object
= NULL
;
1378 } else if (object_count
== 1) {
1379 multiattrib
->object
= (OBJECT
*)selection_glist
->data
;
1381 /* TODO: Something clever with multiple objects selected */
1382 multiattrib
->object
= NULL
;
1385 multiattrib_update (multiattrib
);
1389 /*! \brief Update the dialog when the current page's SELECTION object is destroyed
1391 * \par Function Description
1393 * This handler is called when the g_object_weak_ref() on the SELECTION object
1394 * we're watching expires. We reset our multiattrib->selection pointer to NULL
1395 * to avoid attempting to access the destroyed object. NB: Our signal handlers
1396 * were automatically disconnected during the destruction process.
1398 * \param [in] data Pointer to the multi-attrib dialog
1399 * \param [in] where_the_object_was Pointer to where the object was just destroyed
1401 static void selection_weak_ref_cb (gpointer data
, GObject
*where_the_object_was
)
1403 Multiattrib
*multiattrib
= (Multiattrib
*)data
;
1405 multiattrib
->selection
= NULL
;
1406 multiattrib_update (multiattrib
);
1410 /*! \brief Connect signal handler and weak_ref on the SELECTION object
1412 * \par Function Description
1414 * Connect the "changed" signal and add a weak reference
1415 * on the SELECTION object we are going to watch.
1417 * \param [in] multiattrib The Multiattrib dialog.
1418 * \param [in] selection The SELECTION object to watch.
1420 static void connect_selection( Multiattrib
*multiattrib
, SELECTION
*selection
)
1422 multiattrib
->selection
= selection
;
1423 if (multiattrib
->selection
!= NULL
) {
1424 g_object_weak_ref (G_OBJECT (multiattrib
->selection
),
1425 selection_weak_ref_cb
,
1427 multiattrib
->selection_changed_id
=
1428 g_signal_connect (G_OBJECT (multiattrib
->selection
),
1430 G_CALLBACK (selection_changed_cb
),
1432 /* Synthesise a selection changed update to refresh the view */
1433 selection_changed_cb (multiattrib
->selection
, multiattrib
);
1435 /* Call an update to set the sensitivities */
1436 multiattrib_update (multiattrib
);
1441 /*! \brief Disconnect signal handler and weak_ref on the SELECTION object
1443 * \par Function Description
1445 * If the dialog is watching a SELECTION object, disconnect the
1446 * "changed" signal and remove our weak reference on the object.
1448 * \param [in] multiattrib The Multiattrib dialog.
1450 static void disconnect_selection( Multiattrib
*multiattrib
)
1452 if (multiattrib
->selection
!= NULL
) {
1453 g_signal_handler_disconnect (multiattrib
->selection
,
1454 multiattrib
->selection_changed_id
);
1455 g_object_weak_unref(G_OBJECT( multiattrib
->selection
),
1456 selection_weak_ref_cb
,
1462 /*! \brief GObject finalise handler
1464 * \par Function Description
1466 * Just before the Multiattrib GObject is finalized, disconnect from
1467 * the SELECTION object being watched and then chain up to the parent
1468 * class's finalize handler.
1470 * \param [in] object The GObject being finalized.
1472 static void multiattrib_finalize (GObject
*object
)
1474 Multiattrib
*multiattrib
= MULTIATTRIB(object
);
1476 disconnect_selection( multiattrib
);
1477 G_OBJECT_CLASS (multiattrib_parent_class
)->finalize (object
);
1481 /*! \brief GType class initialiser for Multiattrib
1483 * \par Function Description
1485 * GType class initialiser for Multiattrib. We override our parent
1486 * virtual class methods as needed and register our GObject properties.
1488 * \param [in] klass The MultiattribClass we are initialising
1490 static void multiattrib_class_init(MultiattribClass
*klass
)
1492 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1494 multiattrib_parent_class
= g_type_class_peek_parent (klass
);
1496 gobject_class
->set_property
= multiattrib_set_property
;
1497 gobject_class
->get_property
= multiattrib_get_property
;
1498 gobject_class
->finalize
= multiattrib_finalize
;
1500 g_object_class_install_property (
1501 gobject_class
, PROP_SELECTION
,
1502 g_param_spec_pointer ("selection",
1505 G_PARAM_READWRITE
));
1509 /*! \brief GType instance initialiser for Multiattrib
1511 * \par Function Description
1513 * GType instance initialiser for Multiattrib. Create
1514 * and setup the widgets which make up the dialog.
1516 * \param [in] dialog The Multiattrib we are initialising
1518 static void multiattrib_init(Multiattrib
*multiattrib
)
1520 GtkWidget
*frame
, *label
, *scrolled_win
, *treeview
;
1521 GtkWidget
*table
, *textview
, *combo
, *optionm
, *button
;
1522 GtkTreeModel
*store
;
1523 GtkCellRenderer
*renderer
;
1524 GtkTreeViewColumn
*column
;
1525 GtkTreeSelection
*selection
;
1528 /* dialog initialization */
1529 g_object_set (G_OBJECT (multiattrib
),
1533 "type", GTK_WINDOW_TOPLEVEL
,
1534 "title", _("Edit Attributes"),
1535 "default-width", 320,
1536 "default-height", 350,
1537 "window-position", GTK_WIN_POS_MOUSE
,
1539 "allow-shrink", FALSE
,
1541 "has-separator", TRUE
,
1544 multiattrib
->object
= NULL
;
1546 /* create the attribute list frame */
1547 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1549 "label", _("Attributes"),
1551 multiattrib
->frame_add
= frame
;
1552 /* - create the model for the treeview */
1553 store
= (GtkTreeModel
*)gtk_list_store_new (NUM_COLUMNS
,
1554 G_TYPE_POINTER
); /* attribute */
1555 /* - create a scrolled window for the treeview */
1556 scrolled_win
= GTK_WIDGET (
1557 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1560 /* GtkScrolledWindow */
1561 "hscrollbar-policy",
1562 GTK_POLICY_AUTOMATIC
,
1563 "vscrollbar-policy",
1564 GTK_POLICY_AUTOMATIC
,
1566 GTK_SHADOW_ETCHED_IN
,
1568 /* - create the treeview */
1569 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
1574 g_signal_connect (treeview
,
1576 G_CALLBACK (multiattrib_callback_key_pressed
),
1578 g_signal_connect (treeview
,
1579 "button-press-event",
1580 G_CALLBACK (multiattrib_callback_button_pressed
),
1582 g_signal_connect (treeview
,
1584 G_CALLBACK (multiattrib_callback_popup_menu
),
1586 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
1587 gtk_tree_selection_set_mode (selection
,
1588 GTK_SELECTION_SINGLE
);
1590 /* - and now the columns of the treeview */
1591 /* - column 1: attribute name */
1592 renderer
= GTK_CELL_RENDERER (
1593 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT
,
1594 /* GtkCellRendererText */
1596 /* unknown in GTK 2.4 */
1598 * PANGO_ELLIPSIZE_END, */
1600 g_signal_connect (renderer
,
1602 G_CALLBACK (multiattrib_callback_edited_name
),
1604 column
= GTK_TREE_VIEW_COLUMN (
1605 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1606 /* GtkTreeViewColumn */
1611 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1612 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1613 multiattrib_column_set_data_name
,
1615 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1616 /* - column 2: attribute value */
1617 renderer
= GTK_CELL_RENDERER (
1618 g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT
,
1619 /* GtkCellRendererText */
1621 /* unknown in GTK 2.4 */
1623 PANGO_ELLIPSIZE_END, */
1625 g_signal_connect (renderer
,
1627 G_CALLBACK (multiattrib_callback_edited_value
),
1629 column
= GTK_TREE_VIEW_COLUMN (
1630 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1631 /* GtkTreeViewColumn */
1632 "title", _("Value"),
1636 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1637 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1638 multiattrib_column_set_data_value
,
1640 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1641 /* - column 3: visibility */
1642 renderer
= GTK_CELL_RENDERER (
1643 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1644 /* GtkCellRendererToggle */
1645 "activatable", TRUE
,
1647 g_signal_connect (renderer
,
1649 G_CALLBACK (multiattrib_callback_toggled_visible
),
1651 column
= GTK_TREE_VIEW_COLUMN (
1652 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1653 /* GtkTreeViewColumn */
1656 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1657 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1658 multiattrib_column_set_data_visible
,
1660 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1661 /* - column 4: show name */
1662 renderer
= GTK_CELL_RENDERER (
1663 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1664 /* GtkCellRendererToggle */
1665 "activatable", TRUE
,
1667 g_signal_connect (renderer
,
1669 G_CALLBACK (multiattrib_callback_toggled_show_name
),
1671 column
= GTK_TREE_VIEW_COLUMN (
1672 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1673 /* GtkTreeViewColumn */
1676 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1677 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1678 multiattrib_column_set_data_show_name
,
1680 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1681 /* - column 5: show value */
1682 renderer
= GTK_CELL_RENDERER (
1683 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1684 /* GtkCellRendererToggle */
1685 "activatable", TRUE
,
1687 g_signal_connect (renderer
,
1689 G_CALLBACK (multiattrib_callback_toggled_show_value
),
1691 column
= GTK_TREE_VIEW_COLUMN (
1692 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1693 /* GtkTreeViewColumn */
1696 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1697 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1698 multiattrib_column_set_data_show_value
,
1700 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1702 /* add the treeview to the scrolled window */
1703 gtk_container_add (GTK_CONTAINER (scrolled_win
), treeview
);
1704 /* set treeview of multiattrib */
1705 multiattrib
->treeview
= GTK_TREE_VIEW (treeview
);
1706 /* add the scrolled window to frame */
1707 gtk_container_add (GTK_CONTAINER (frame
), scrolled_win
);
1708 /* pack the frame */
1709 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1711 gtk_widget_show_all (frame
);
1713 /* create the add/edit frame */
1714 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1715 "label", _("Add Attribute"),
1717 multiattrib
->frame_attributes
= frame
;
1718 table
= GTK_WIDGET (g_object_new (GTK_TYPE_TABLE
,
1722 "homogeneous", FALSE
,
1725 /* - the name entry: a GtkComboBoxEntry */
1726 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1731 "label", _("Name:"),
1733 combo
= GTK_WIDGET (g_object_new (GTK_TYPE_COMBO
,
1735 "value-in-list", FALSE
,
1737 multiattrib_init_attrib_names (GTK_COMBO (combo
));
1738 multiattrib
->combo_name
= GTK_COMBO (combo
);
1739 gtk_table_attach (GTK_TABLE (table
), label
,
1740 0, 1, 0, 1, 0, 0, 0, 0);
1741 gtk_table_attach (GTK_TABLE (table
), combo
,
1742 1, 2, 0, 1, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1744 /* - the value entry: a GtkEntry */
1745 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1750 "label", _("Value:"),
1752 scrolled_win
= GTK_WIDGET (
1753 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1754 /* GtkScrolledWindow */
1755 "hscrollbar-policy",
1757 "vscrollbar-policy",
1758 GTK_POLICY_AUTOMATIC
,
1762 textview
= GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW
,
1764 g_signal_connect (textview
,
1766 G_CALLBACK (multiattrib_callback_value_key_pressed
),
1768 g_signal_connect (textview
,
1770 G_CALLBACK (multiattrib_callback_value_grab_focus
),
1772 /* Save the GTK_STATE_NORMAL color so we can work around GtkTextView's
1773 * stubborn refusal to draw with GTK_STATE_INSENSITIVE later on */
1774 style
= gtk_widget_get_style (textview
);
1775 multiattrib
->value_normal_text_color
= style
->text
[ GTK_STATE_NORMAL
];
1777 gtk_container_add (GTK_CONTAINER (scrolled_win
), textview
);
1778 multiattrib
->textview_value
= GTK_TEXT_VIEW (textview
);
1779 gtk_table_attach (GTK_TABLE (table
), label
,
1780 0, 1, 1, 2, 0, 0, 0, 0);
1781 gtk_table_attach (GTK_TABLE (table
), scrolled_win
,
1782 1, 2, 1, 2, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1784 /* - the visible status */
1785 button
= GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON
,
1787 "label", _("Visible"),
1790 multiattrib
->button_visible
= GTK_CHECK_BUTTON (button
);
1791 gtk_table_attach (GTK_TABLE (table
), button
,
1792 0, 1, 2, 3, GTK_FILL
, 0, 3, 0);
1794 /* - the visibility type */
1795 optionm
= GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU
,
1797 multiattrib_init_visible_types (GTK_OPTION_MENU (optionm
));
1798 multiattrib
->optionmenu_shownv
= GTK_OPTION_MENU (optionm
);
1799 gtk_table_attach (GTK_TABLE (table
), optionm
,
1800 1, 2, 2, 3, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1801 gtk_widget_show_all (table
);
1803 /* create the add button */
1804 button
= gtk_button_new_from_stock (GTK_STOCK_ADD
);
1805 g_signal_connect (button
,
1807 G_CALLBACK (multiattrib_callback_button_add
),
1809 gtk_table_attach (GTK_TABLE (table
), button
,
1810 2, 3, 0, 3, 0, 0, 6, 3);
1812 /* add the table to the frame */
1813 gtk_container_add (GTK_CONTAINER (frame
), table
);
1814 /* pack the frame in the dialog */
1815 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1817 gtk_widget_show_all (frame
);
1820 /* now add the close button to the action area */
1821 gtk_dialog_add_button (GTK_DIALOG (multiattrib
),
1822 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
);
1827 /*! \brief GObject property setter function
1829 * \par Function Description
1830 * Setter function for Multiattrib's GObject property, "selection".
1832 * \param [in] object The GObject whose properties we are setting
1833 * \param [in] property_id The numeric id. under which the property was
1834 * registered with g_object_class_install_property()
1835 * \param [in] value The GValue the property is being set from
1836 * \param [in] pspec A GParamSpec describing the property being set
1839 static void multiattrib_set_property (GObject
*object
,
1841 const GValue
*value
,
1844 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
1846 switch(property_id
) {
1847 case PROP_SELECTION
:
1848 disconnect_selection (multiattrib
);
1849 connect_selection (multiattrib
, g_value_get_pointer (value
));
1852 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1857 /*! \brief GObject property getter function
1859 * \par Function Description
1860 * Getter function for Multiattrib's GObject property, "selection".
1862 * \param [in] object The GObject whose properties we are getting
1863 * \param [in] property_id The numeric id. under which the property was
1864 * registered with g_object_class_install_property()
1865 * \param [out] value The GValue in which to return the value of the property
1866 * \param [in] pspec A GParamSpec describing the property being got
1868 static void multiattrib_get_property (GObject
*object
,
1873 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
1875 switch(property_id
) {
1876 case PROP_SELECTION
:
1877 g_value_set_pointer (value
, (gpointer
)multiattrib
->selection
);
1880 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1886 /*! \brief Update the multiattrib editor dialog's interface
1888 * \par Function Description
1890 * Update the dialog to reflect the attributes of the currently selected
1891 * object. If no (or multiple) objects are selected, the dialog's controls
1892 * are set insensitive.
1894 * \todo The dialog doesn't currently support editing multiple objects at once
1896 * \param [in] multiattrib The multi-attribute editor dialog.
1898 void multiattrib_update (Multiattrib
*multiattrib
)
1900 GtkListStore
*liststore
;
1902 OBJECT
**object_attribs
, *o_current
;
1907 g_assert (GSCHEM_DIALOG (multiattrib
)->toplevel
!= NULL
);
1909 /* clear the list of attributes */
1910 liststore
= (GtkListStore
*)gtk_tree_view_get_model (multiattrib
->treeview
);
1911 gtk_list_store_clear (liststore
);
1913 /* Update sensitivities */
1914 sensitive
= (multiattrib
->selection
!= NULL
&& multiattrib
->object
!= NULL
);
1915 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib
->frame_attributes
), sensitive
);
1916 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib
->frame_add
), sensitive
);
1918 /* Work around GtkTextView's stubborn indifference
1919 * to GTK_STATE_INSENSITIVE when rendering its text. */
1920 style
= gtk_widget_get_style (GTK_WIDGET (multiattrib
->textview_value
));
1921 gtk_widget_modify_text (GTK_WIDGET (multiattrib
->textview_value
),
1923 sensitive
? &multiattrib
->value_normal_text_color
1924 : &style
->text
[GTK_STATE_INSENSITIVE
]);
1926 /* If we aren't sensitive, there is nothing more to do */
1930 /* get list of attributes */
1931 object_attribs
= o_attrib_return_attribs (
1932 GSCHEM_DIALOG (multiattrib
)->toplevel
->page_current
->object_head
,
1933 multiattrib
->object
);
1934 /* populate the store with attributes */
1935 if (object_attribs
) {
1936 for (i
= 0, o_current
= object_attribs
[i
];
1938 i
++, o_current
= object_attribs
[i
]) {
1939 gtk_list_store_append (liststore
, &iter
);
1940 gtk_list_store_set (liststore
, &iter
,
1941 COLUMN_ATTRIBUTE
, o_current
,
1945 /* delete the list of attribute objects */
1946 o_attrib_free_returned (object_attribs
);