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 Open multiple attribute editor dialog.
45 * \par Function Description
46 * Opens the multiple attribute editor dialog for <B>object</B> in the
47 * context of <B>toplevel</B>.
49 * The dialog is modal and this function does not return until the user
52 * \param [in] toplevel The TOPLEVEL object.
53 * \param [in] object OBJECT to edit attributes on.
55 void x_multiattrib_open (TOPLEVEL
*toplevel
, OBJECT
*object
)
59 dialog
= GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB
,
62 "settings-name", "multiattrib",
66 gtk_window_set_transient_for(GTK_WINDOW(dialog
),
67 GTK_WINDOW(toplevel
->main_window
));
69 multiattrib_update (MULTIATTRIB(dialog
));
70 gtk_widget_show (dialog
);
71 switch (gtk_dialog_run ((GtkDialog
*)dialog
)) {
72 case GTK_RESPONSE_CLOSE
:
73 case GTK_RESPONSE_DELETE_EVENT
:
74 /* reset state and update message in toolbar */
75 i_set_state (toplevel
, SELECT
);
76 i_update_toolbar (toplevel
);
79 g_assert_not_reached ();
81 gtk_widget_destroy (dialog
);
85 /*! \section celltextview-widget Cell TextView Widget Code.
86 * This widget makes a 'GtkTextView' widget implements the 'GtkCellEditable'
87 * interface. It can then be used to renderer multi-line texts inside
88 * tree views ('GtkTreeView').
90 static void celltextview_class_init (CellTextViewClass
*klass
);
91 static void celltextview_init (CellTextView
*self
);
92 static void celltextview_cell_editable_init (GtkCellEditableIface
*iface
);
94 /*! \todo Finish function documentation
96 * \par Function Description
99 static gboolean
celltextview_key_press_event (GtkWidget
*widget
,
103 CellTextView
*celltextview
= (CellTextView
*)widget
;
105 /* ends editing of cell if one of these keys are pressed */
108 event
->keyval
== GDK_Escape
||
109 /* the Enter key without the Control modifier */
110 (!(event
->state
& GDK_CONTROL_MASK
) &&
111 (event
->keyval
== GDK_Return
||
112 event
->keyval
== GDK_KP_Enter
))) {
113 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (celltextview
));
114 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (celltextview
));
121 /*! \todo Finish function documentation
123 * \par Function Description
126 static void celltextview_start_editing (GtkCellEditable
*cell_editable
,
129 g_signal_connect (cell_editable
,
131 G_CALLBACK (celltextview_key_press_event
),
136 /*! \todo Finish function documentation
138 * \par Function Description
141 GType
celltextview_get_type()
143 static GType celltextview_type
= 0;
145 if (!celltextview_type
) {
146 static const GTypeInfo celltextview_info
= {
147 sizeof(CellTextViewClass
),
148 NULL
, /* base_init */
149 NULL
, /* base_finalize */
150 (GClassInitFunc
) celltextview_class_init
,
151 NULL
, /* class_finalize */
152 NULL
, /* class_data */
153 sizeof(CellTextView
),
155 (GInstanceInitFunc
) celltextview_init
,
158 static const GInterfaceInfo cell_editable_info
= {
159 (GInterfaceInitFunc
) celltextview_cell_editable_init
,
160 NULL
, /* interface_finalize */
161 NULL
/* interface_data */
164 celltextview_type
= g_type_register_static(GTK_TYPE_TEXT_VIEW
,
166 &celltextview_info
, 0);
167 g_type_add_interface_static(celltextview_type
,
168 GTK_TYPE_CELL_EDITABLE
,
169 &cell_editable_info
);
172 return celltextview_type
;
175 /*! \todo Finish function documentation
177 * \par Function Description
180 static void celltextview_class_init(CellTextViewClass
*klass
)
182 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
185 /*! \todo Finish function documentation
187 * \par Function Description
190 static void celltextview_init(CellTextView
*self
)
194 /*! \todo Finish function documentation
196 * \par Function Description
199 static void celltextview_cell_editable_init(GtkCellEditableIface
*iface
)
201 iface
->start_editing
= celltextview_start_editing
;
204 /*! \section multi-line-text-cell-renderer Multi-line Text Cell Renderer
205 * GTK has no multi-line text cell renderer. This code adds one to be used
206 * in gschem code. It is inspired by the 'GtkCellRendererCombo' renderer
209 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
);
210 static void cellrenderermultilinetext_init (CellRendererMultiLineText
*self
);
212 static void cellrenderermultilinetext_editing_done (GtkCellEditable
*cell_editable
,
214 static gboolean
cellrenderermultilinetext_focus_out_event (GtkWidget
*widget
,
219 #define CELL_RENDERER_MULTI_LINE_TEXT_PATH "cell-renderer-multi-line-text-path"
222 /*! \todo Finish function documentation
224 * \par Function Description
227 static GtkCellEditable
* cellrenderermultilinetext_start_editing(GtkCellRenderer
*cell
,
231 GdkRectangle
*background_area
,
232 GdkRectangle
*cell_area
,
233 GtkCellRendererState flags
)
235 GtkCellRendererText
*cell_text
;
236 CellRendererMultiLineText
*cell_mlt
;
238 GtkTextBuffer
*textbuffer
;
240 cell_text
= GTK_CELL_RENDERER_TEXT (cell
);
241 if (cell_text
->editable
== FALSE
) {
245 cell_mlt
= CELL_RENDERER_MULTI_LINE_TEXT (cell
);
247 textbuffer
= GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER
,
249 gtk_text_buffer_set_text (textbuffer
,
251 strlen (cell_text
->text
));
253 textview
= GTK_WIDGET (g_object_new (TYPE_CELL_TEXT_VIEW
,
255 /* unknown property in GTK 2.2, use
256 * gtk_text_view_set_buffer() instead */
257 /* "buffer", textbuffer, */
260 "height-request", cell_area
->height
,
262 gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview
), textbuffer
);
263 g_object_set_data_full (G_OBJECT (textview
),
264 CELL_RENDERER_MULTI_LINE_TEXT_PATH
,
265 g_strdup (path
), g_free
);
267 gtk_widget_show (textview
);
269 g_signal_connect (GTK_CELL_EDITABLE (textview
),
271 G_CALLBACK (cellrenderermultilinetext_editing_done
),
273 cell_mlt
->focus_out_id
=
274 g_signal_connect (textview
,
276 G_CALLBACK (cellrenderermultilinetext_focus_out_event
),
279 return GTK_CELL_EDITABLE (textview
);
282 /*! \todo Finish function documentation
284 * \par Function Description
287 static void cellrenderermultilinetext_editing_done(GtkCellEditable
*cell_editable
,
290 CellRendererMultiLineText
*cell
= CELL_RENDERER_MULTI_LINE_TEXT (user_data
);
291 GtkTextBuffer
*buffer
;
292 GtkTextIter start
, end
;
296 if (cell
->focus_out_id
> 0) {
297 g_signal_handler_disconnect (cell_editable
,
299 cell
->focus_out_id
= 0;
302 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (cell_editable
));
303 gtk_text_buffer_get_start_iter (buffer
, &start
);
304 gtk_text_buffer_get_end_iter (buffer
, &end
);
305 new_text
= gtk_text_buffer_get_text (buffer
, &start
, &end
, TRUE
);
307 path
= g_object_get_data (G_OBJECT (cell_editable
),
308 CELL_RENDERER_MULTI_LINE_TEXT_PATH
);
309 g_signal_emit_by_name (cell
, "edited", path
, new_text
);
315 /*! \todo Finish function documentation
317 * \par Function Description
320 static gboolean
cellrenderermultilinetext_focus_out_event(GtkWidget
*widget
,
324 cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget
),
330 /*! \todo Finish function documentation
332 * \par Function Description
335 GType
cellrenderermultilinetext_get_type()
337 static GType cellrenderermultilinetext_type
= 0;
339 if (!cellrenderermultilinetext_type
) {
340 static const GTypeInfo cellrenderermultilinetext_info
= {
341 sizeof(CellRendererMultiLineTextClass
),
342 NULL
, /* base_init */
343 NULL
, /* base_finalize */
344 (GClassInitFunc
) cellrenderermultilinetext_class_init
,
345 NULL
, /* class_finalize */
346 NULL
, /* class_data */
347 sizeof(CellRendererMultiLineText
),
349 (GInstanceInitFunc
) cellrenderermultilinetext_init
,
352 cellrenderermultilinetext_type
= g_type_register_static (
353 GTK_TYPE_CELL_RENDERER_TEXT
,
354 "CellRendererMultiLineText",
355 &cellrenderermultilinetext_info
, 0);
358 return cellrenderermultilinetext_type
;
361 /*! \todo Finish function documentation
363 * \par Function Description
366 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
*klass
)
368 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
369 GtkCellRendererClass
*cell_class
= GTK_CELL_RENDERER_CLASS (klass
);
371 cell_class
->start_editing
= cellrenderermultilinetext_start_editing
;
375 /*! \todo Finish function documentation
377 * \par Function Description
380 static void cellrenderermultilinetext_init(CellRendererMultiLineText
*self
)
395 static void multiattrib_class_init (MultiattribClass
*class);
396 static void multiattrib_init (Multiattrib
*multiattrib
);
397 static void multiattrib_set_property (GObject
*object
,
401 static void multiattrib_get_property (GObject
*object
,
406 static void multiattrib_popup_menu (Multiattrib
*multiattrib
,
407 GdkEventButton
*event
);
410 /*! \todo Finish function documentation
412 * \par Function Description
415 static void multiattrib_action_add_attribute(TOPLEVEL
*toplevel
,
420 gint show_name_value
)
425 newtext
= g_strdup_printf ("%s=%s", name
, value
);
427 /* create a new attribute and link it */
428 o_attrib
= o_attrib_add_attrib (toplevel
, newtext
,
429 visible
, show_name_value
, object
);
431 toplevel
->page_current
->CHANGED
= 1;
432 o_undo_savestate (toplevel
, UNDO_ALL
);
438 /*! \todo Finish function documentation
440 * \par Function Description
443 static void multiattrib_action_duplicate_attribute(TOPLEVEL
*toplevel
,
449 o_new
= o_attrib_add_attrib (toplevel
,
450 o_attrib
->text
->string
,
451 o_attrib
->visibility
,
452 o_attrib
->show_name_value
,
454 toplevel
->page_current
->CHANGED
= 1;
455 o_undo_savestate (toplevel
, UNDO_ALL
);
459 /*! \todo Finish function documentation
461 * \par Function Description
464 static void multiattrib_action_delete_attribute(TOPLEVEL
*toplevel
,
467 /* actually deletes the attribute */
468 o_selection_remove (&(toplevel
->page_current
->selection_list
), o_attrib
);
469 o_delete_text (toplevel
, o_attrib
);
470 toplevel
->page_current
->CHANGED
=1;
471 o_undo_savestate (toplevel
, UNDO_ALL
);
475 /*! \todo Finish function documentation
477 * \par Function Description
480 static void multiattrib_column_set_data_name(GtkTreeViewColumn
*tree_column
,
481 GtkCellRenderer
*cell
,
482 GtkTreeModel
*tree_model
,
489 gtk_tree_model_get (tree_model
, iter
,
490 COLUMN_ATTRIBUTE
, &o_attrib
,
492 g_assert (o_attrib
->type
== OBJ_TEXT
);
494 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
503 /*! \todo Finish function documentation
505 * \par Function Description
508 static void multiattrib_column_set_data_value(GtkTreeViewColumn
*tree_column
,
509 GtkCellRenderer
*cell
,
510 GtkTreeModel
*tree_model
,
517 gtk_tree_model_get (tree_model
, iter
,
518 COLUMN_ATTRIBUTE
, &o_attrib
,
520 g_assert (o_attrib
->type
== OBJ_TEXT
);
522 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
531 /*! \todo Finish function documentation
533 * \par Function Description
536 static void multiattrib_column_set_data_visible(GtkTreeViewColumn
*tree_column
,
537 GtkCellRenderer
*cell
,
538 GtkTreeModel
*tree_model
,
544 gtk_tree_model_get (tree_model
, iter
,
545 COLUMN_ATTRIBUTE
, &o_attrib
,
547 g_assert (o_attrib
->type
== OBJ_TEXT
);
550 "active", (o_attrib
->visibility
== VISIBLE
),
555 /*! \todo Finish function documentation
557 * \par Function Description
560 static void multiattrib_column_set_data_show_name(GtkTreeViewColumn
*tree_column
,
561 GtkCellRenderer
*cell
,
562 GtkTreeModel
*tree_model
,
568 gtk_tree_model_get (tree_model
, iter
,
569 COLUMN_ATTRIBUTE
, &o_attrib
,
571 g_assert (o_attrib
->type
== OBJ_TEXT
);
574 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
575 o_attrib
->show_name_value
== SHOW_NAME
),
580 /*! \todo Finish function documentation
582 * \par Function Description
585 static void multiattrib_column_set_data_show_value(GtkTreeViewColumn
*tree_column
,
586 GtkCellRenderer
*cell
,
587 GtkTreeModel
*tree_model
,
593 gtk_tree_model_get (tree_model
, iter
,
594 COLUMN_ATTRIBUTE
, &o_attrib
,
596 g_assert (o_attrib
->type
== OBJ_TEXT
);
599 "active", (o_attrib
->show_name_value
== SHOW_NAME_VALUE
||
600 o_attrib
->show_name_value
== SHOW_VALUE
),
605 /*! \brief Requests an update of the display of a row.
606 * \par Function Description
607 * This is an helper function to update the display of a row when
608 * data for this row have been modified in the model.
610 * It emits the 'row_changed' signal on the pointed row.
612 * \param [in] model A GtkTreeModel.
613 * \param [in] iter A valid GtkTreeIter pointing to the changed row.
616 update_row_display (GtkTreeModel
*model
, GtkTreeIter
*iter
)
620 path
= gtk_tree_model_get_path (model
, iter
);
621 gtk_tree_model_row_changed (model
, path
, iter
);
622 gtk_tree_path_free (path
);
626 /*! \todo Finish function documentation
628 * \par Function Description
631 static void multiattrib_callback_edited_name(GtkCellRendererText
*cellrenderertext
,
636 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
641 gchar
*name
, *value
, *newtext
;
643 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
644 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
646 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
650 if (g_ascii_strcasecmp (arg2
, "") == 0) {
651 GtkWidget
*dialog
= gtk_message_dialog_new (
652 GTK_WINDOW (multiattrib
),
656 _("Attributes with empty name are not allowed. Please set a name."));
658 gtk_dialog_run (GTK_DIALOG (dialog
));
659 gtk_widget_destroy (dialog
);
663 gtk_tree_model_get (model
, &iter
,
664 COLUMN_ATTRIBUTE
, &o_attrib
,
666 g_assert (o_attrib
->type
== OBJ_TEXT
);
668 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
669 newtext
= g_strdup_printf ("%s=%s", arg2
, value
);
671 /* actually modifies the attribute */
672 o_text_change (toplevel
, o_attrib
,
673 newtext
, o_attrib
->visibility
, o_attrib
->show_name_value
);
681 /*! \todo Finish function documentation
683 * \par Function Description
686 static void multiattrib_callback_edited_value(GtkCellRendererText
*cell_renderer
,
691 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
696 gchar
*name
, *value
, *newtext
;
698 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
699 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
701 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, arg1
)) {
705 gtk_tree_model_get (model
, &iter
,
706 COLUMN_ATTRIBUTE
, &o_attrib
,
708 g_assert (o_attrib
->type
== OBJ_TEXT
);
710 o_attrib_get_name_value (o_attrib
->text
->string
, &name
, &value
);
711 newtext
= g_strdup_printf ("%s=%s", name
, arg2
);
713 /* actually modifies the attribute */
714 o_text_change (toplevel
, o_attrib
,
715 newtext
, o_attrib
->visibility
, o_attrib
->show_name_value
);
717 /* request an update of display for this row */
718 update_row_display (model
, &iter
);
726 /*! \todo Finish function documentation
728 * \par Function Description
731 static void multiattrib_callback_toggled_visible(GtkCellRendererToggle
*cell_renderer
,
735 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
742 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
743 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
745 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
749 gtk_tree_model_get (model
, &iter
,
750 COLUMN_ATTRIBUTE
, &o_attrib
,
752 g_assert (o_attrib
->type
== OBJ_TEXT
);
753 o_text_erase (toplevel
, o_attrib
);
755 visibility
= o_attrib
->visibility
== VISIBLE
? INVISIBLE
: VISIBLE
;
757 /* actually modifies the attribute */
758 o_attrib
->visibility
= visibility
;
759 o_text_recreate (toplevel
, o_attrib
);
760 o_text_draw (toplevel
, o_attrib
);
761 o_undo_savestate (toplevel
, UNDO_ALL
);
763 /* request an update of display for this row */
764 update_row_display (model
, &iter
);
768 /*! \todo Finish function documentation
770 * \par Function Description
773 static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle
*cell_renderer
,
777 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
784 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
785 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
787 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
791 gtk_tree_model_get (model
, &iter
,
792 COLUMN_ATTRIBUTE
, &o_attrib
,
794 g_assert (o_attrib
->type
== OBJ_TEXT
);
795 o_text_erase (toplevel
, o_attrib
);
797 switch (o_attrib
->show_name_value
) {
798 case SHOW_NAME_VALUE
: new_snv
= SHOW_VALUE
; break;
799 case SHOW_NAME
: new_snv
= SHOW_VALUE
; break;
800 case SHOW_VALUE
: new_snv
= SHOW_NAME_VALUE
; break;
802 g_assert_not_reached ();
803 new_snv
= SHOW_NAME_VALUE
;
806 /* actually modifies the attribute */
807 o_attrib
->show_name_value
= new_snv
;
808 o_text_recreate (toplevel
, o_attrib
);
809 o_text_draw (toplevel
, o_attrib
);
810 o_undo_savestate (toplevel
, UNDO_ALL
);
812 /* request an update of display for this row */
813 update_row_display (model
, &iter
);
817 /*! \todo Finish function documentation
819 * \par Function Description
822 static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle
*cell_renderer
,
826 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
833 model
= gtk_tree_view_get_model (multiattrib
->treeview
);
834 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
836 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path
)) {
840 gtk_tree_model_get (model
, &iter
,
841 COLUMN_ATTRIBUTE
, &o_attrib
,
843 g_assert (o_attrib
->type
== OBJ_TEXT
);
844 o_text_erase (toplevel
, o_attrib
);
846 switch (o_attrib
->show_name_value
) {
847 case SHOW_NAME_VALUE
: new_snv
= SHOW_NAME
; break;
848 case SHOW_NAME
: new_snv
= SHOW_NAME_VALUE
; break;
849 case SHOW_VALUE
: new_snv
= SHOW_NAME
; break;
851 g_assert_not_reached ();
852 new_snv
= SHOW_NAME_VALUE
;
855 /* actually modifies the attribute */
856 o_attrib
->show_name_value
= new_snv
;
857 o_text_recreate (toplevel
, o_attrib
);
858 o_text_draw (toplevel
, o_attrib
);
859 o_undo_savestate (toplevel
, UNDO_ALL
);
861 /* request an update of display for this row */
862 update_row_display (model
, &iter
);
866 /*! \todo Finish function documentation
868 * \par Function Description
871 static gboolean
multiattrib_callback_key_pressed(GtkWidget
*widget
,
875 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
877 if (event
->state
== 0 &&
878 (event
->keyval
== GDK_Delete
|| event
->keyval
== GDK_KP_Delete
)) {
882 /* delete the currently selected attribute */
884 if (!gtk_tree_selection_get_selected (
885 gtk_tree_view_get_selection (multiattrib
->treeview
),
887 /* nothing selected, nothing to do */
891 gtk_tree_model_get (model
, &iter
,
892 COLUMN_ATTRIBUTE
, &o_attrib
,
894 g_assert (o_attrib
->type
== OBJ_TEXT
);
896 multiattrib_action_delete_attribute (GSCHEM_DIALOG (multiattrib
)->toplevel
,
899 /* update the treeview contents */
900 multiattrib_update (multiattrib
);
906 /*! \todo Finish function documentation
908 * \par Function Description
911 static gboolean
multiattrib_callback_button_pressed(GtkWidget
*widget
,
912 GdkEventButton
*event
,
915 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
916 gboolean ret
= FALSE
;
918 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3) {
919 multiattrib_popup_menu (multiattrib
, event
);
926 /*! \todo Finish function documentation
928 * \par Function Description
931 static gboolean
multiattrib_callback_popup_menu(GtkWidget
*widget
,
934 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
936 multiattrib_popup_menu (multiattrib
, NULL
);
941 /*! \todo Finish function documentation
943 * \par Function Description
946 static void multiattrib_callback_popup_duplicate(GtkMenuItem
*menuitem
,
949 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
953 OBJECT
*object
, *o_attrib
;
955 if (!gtk_tree_selection_get_selected (
956 gtk_tree_view_get_selection (multiattrib
->treeview
),
958 /* nothing selected, nothing to do */
962 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
963 object
= multiattrib
->object
;
965 gtk_tree_model_get (model
, &iter
,
966 COLUMN_ATTRIBUTE
, &o_attrib
,
968 g_assert (o_attrib
->type
== OBJ_TEXT
);
970 multiattrib_action_duplicate_attribute (toplevel
, object
, o_attrib
);
972 /* update the treeview contents */
973 multiattrib_update (multiattrib
);
977 /*! \todo Finish function documentation
979 * \par Function Description
982 static void multiattrib_callback_popup_delete(GtkMenuItem
*menuitem
,
985 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
991 if (!gtk_tree_selection_get_selected (
992 gtk_tree_view_get_selection (multiattrib
->treeview
),
994 /* nothing selected, nothing to do */
998 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
1000 gtk_tree_model_get (model
, &iter
,
1001 COLUMN_ATTRIBUTE
, &o_attrib
,
1003 g_assert (o_attrib
->type
== OBJ_TEXT
);
1005 multiattrib_action_delete_attribute (toplevel
, o_attrib
);
1007 /* update the treeview contents */
1008 multiattrib_update (multiattrib
);
1012 /*! \todo Finish function documentation
1014 * \par Function Description
1017 static gboolean
multiattrib_callback_value_key_pressed(GtkWidget
*widget
,
1021 Multiattrib
*multiattrib
= (Multiattrib
*)widget
;
1022 gboolean retval
= FALSE
;
1024 /* ends editing of cell if one of these keys are pressed: */
1025 /* - the Return key without the Control modifier */
1026 /* - the Tab key without the Control modifier */
1027 if ((event
->keyval
== GDK_Return
|| event
->keyval
== GDK_KP_Enter
) ||
1028 (event
->keyval
== GDK_Tab
|| event
->keyval
== GDK_KP_Tab
)) {
1029 /* Control modifier activated? */
1030 if (event
->state
& GDK_CONTROL_MASK
) {
1031 /* yes the modifier in event structure and let event propagate */
1032 event
->state
^= GDK_CONTROL_MASK
;
1035 /* change focus and stop propagation */
1036 g_signal_emit_by_name (multiattrib
,
1038 (event
->state
& GDK_SHIFT_MASK
) ?
1039 GTK_DIR_TAB_BACKWARD
: GTK_DIR_TAB_FORWARD
);
1047 /*! \todo Finish function documentation
1049 * \par Function Description
1052 static void multiattrib_callback_button_add(GtkButton
*button
,
1055 Multiattrib
*multiattrib
= (Multiattrib
*)user_data
;
1056 GtkTextBuffer
*buffer
;
1057 GtkTextIter start
, end
;
1065 toplevel
= GSCHEM_DIALOG (multiattrib
)->toplevel
;
1066 object
= multiattrib
->object
;
1067 buffer
= gtk_text_view_get_buffer (multiattrib
->textview_value
);
1069 /* retrieve information from the Add/Edit frame */
1070 /* - attribute's name */
1071 name
= gtk_entry_get_text (
1072 GTK_ENTRY (GTK_COMBO (multiattrib
->combo_name
)->entry
));
1073 /* - attribute's value */
1074 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
1075 value
= gtk_text_buffer_get_text (buffer
, &start
, &end
, FALSE
);
1076 /* - attribute's visibility status */
1077 visible
= gtk_toggle_button_get_active (
1078 (GtkToggleButton
*)multiattrib
->button_visible
);
1079 /* - visibility type */
1080 shownv
= (gint
)gtk_option_menu_get_history (multiattrib
->optionmenu_shownv
);
1082 if (name
[0] == '\0' || name
[0] == ' ') {
1083 /* name not allowed for an attribute */
1088 multiattrib_action_add_attribute (toplevel
, object
,
1093 /* clear fields of lower frame */
1094 /* - resets entry for name */
1095 gtk_list_select_item (GTK_LIST (multiattrib
->combo_name
->list
), 0);
1096 /* - resets entry for value */
1097 gtk_text_buffer_set_text (buffer
, "", 0);
1098 /* - resets entry for visibility */
1099 g_object_set (multiattrib
->button_visible
,
1102 /* - resets entry for show name/value */
1103 gtk_option_menu_set_history (multiattrib
->optionmenu_shownv
,
1106 multiattrib_update (multiattrib
);
1110 /*! \todo Finish function documentation
1112 * \par Function Description
1115 static void multiattrib_init_attrib_names(GtkCombo
*combo
)
1117 GList
*items
= NULL
;
1118 const gchar
*string
;
1121 for (i
= 0, string
= s_attrib_get (i
);
1123 i
++, string
= s_attrib_get (i
)) {
1124 items
= g_list_append (items
, (gpointer
)string
);
1127 gtk_combo_set_popdown_strings (GTK_COMBO (combo
), items
);
1129 g_list_free (items
);
1133 /*! \todo Finish function documentation
1135 * \par Function Description
1138 static void multiattrib_init_visible_types(GtkOptionMenu
*optionmenu
)
1140 GtkWidget
*menu
, *item
;
1142 menu
= gtk_menu_new ();
1143 item
= gtk_menu_item_new_with_label (_("Show Name & Value"));
1144 gtk_menu_append (menu
, item
);
1145 item
= gtk_menu_item_new_with_label (_("Show Value only"));
1146 gtk_menu_append (menu
, item
);
1147 item
= gtk_menu_item_new_with_label (_("Show Name only"));
1148 gtk_menu_append (menu
, item
);
1150 gtk_option_menu_set_menu (optionmenu
, menu
);
1154 /*! \brief Popup a context-sensitive menu.
1155 * \par Function Description
1156 * Pops up a context-sensitive menu.
1157 * <B>event</B> can be NULL if the popup is triggered by a key binding
1158 * instead of a mouse click.
1160 * \param [in] multiattrib The Multiattrib object.
1161 * \param [in] event Mouse event.
1163 static void multiattrib_popup_menu(Multiattrib
*multiattrib
,
1164 GdkEventButton
*event
)
1172 struct menuitem_t menuitems
[] = {
1173 { N_("Duplicate"), G_CALLBACK (multiattrib_callback_popup_duplicate
) },
1174 { N_("Delete"), G_CALLBACK (multiattrib_callback_popup_delete
) },
1176 struct menuitem_t
*tmp
;
1178 if (event
!= NULL
&&
1179 gtk_tree_view_get_path_at_pos (multiattrib
->treeview
,
1182 &path
, NULL
, NULL
, NULL
)) {
1183 GtkTreeSelection
*selection
;
1184 selection
= gtk_tree_view_get_selection (multiattrib
->treeview
);
1185 gtk_tree_selection_unselect_all (selection
);
1186 gtk_tree_selection_select_path (selection
, path
);
1187 gtk_tree_path_free (path
);
1190 /* create the context menu */
1191 menu
= gtk_menu_new();
1192 for (tmp
= menuitems
; tmp
->label
!= NULL
; tmp
++) {
1193 GtkWidget
*menuitem
;
1194 if (g_strcasecmp (tmp
->label
, "-") == 0) {
1195 menuitem
= gtk_separator_menu_item_new ();
1197 menuitem
= gtk_menu_item_new_with_label (_(tmp
->label
));
1198 g_signal_connect (menuitem
,
1203 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1205 gtk_widget_show_all (menu
);
1206 /* make menu a popup menu */
1207 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
1208 (event
!= NULL
) ? event
->button
: 0,
1209 gdk_event_get_time ((GdkEvent
*)event
));
1213 /*! \todo Finish function documentation
1215 * \par Function Description
1218 GType
multiattrib_get_type()
1220 static GType multiattrib_type
= 0;
1222 if (!multiattrib_type
) {
1223 static const GTypeInfo multiattrib_info
= {
1224 sizeof(MultiattribClass
),
1225 NULL
, /* base_init */
1226 NULL
, /* base_finalize */
1227 (GClassInitFunc
) multiattrib_class_init
,
1228 NULL
, /* class_finalize */
1229 NULL
, /* class_data */
1230 sizeof(Multiattrib
),
1231 0, /* n_preallocs */
1232 (GInstanceInitFunc
) multiattrib_init
,
1235 multiattrib_type
= g_type_register_static (GSCHEM_TYPE_DIALOG
,
1237 &multiattrib_info
, 0);
1240 return multiattrib_type
;
1243 /*! \todo Finish function documentation
1245 * \par Function Description
1248 static void multiattrib_class_init(MultiattribClass
*klass
)
1250 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1252 gobject_class
->set_property
= multiattrib_set_property
;
1253 gobject_class
->get_property
= multiattrib_get_property
;
1255 g_object_class_install_property (
1256 gobject_class
, PROP_OBJECT
,
1257 g_param_spec_pointer ("object",
1260 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1264 /*! \todo Finish function documentation
1266 * \par Function Description
1269 static void multiattrib_init(Multiattrib
*multiattrib
)
1271 GtkWidget
*frame
, *label
, *scrolled_win
, *treeview
;
1272 GtkWidget
*table
, *textview
, *combo
, *optionm
, *button
;
1273 GtkTreeModel
*store
;
1274 GtkCellRenderer
*renderer
;
1275 GtkTreeViewColumn
*column
;
1276 GtkTreeSelection
*selection
;
1278 /* dialog initialization */
1279 g_object_set (G_OBJECT (multiattrib
),
1283 "type", GTK_WINDOW_TOPLEVEL
,
1284 "title", _("Edit Attributes"),
1285 "default-width", 320,
1286 "default-height", 350,
1288 "window-position", GTK_WIN_POS_MOUSE
,
1290 "allow-shrink", FALSE
,
1292 "has-separator", TRUE
,
1295 multiattrib
->object
= NULL
;
1297 /* create the attribute list frame */
1298 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1300 "label", _("Attributes"),
1302 /* - create the model for the treeview */
1303 store
= (GtkTreeModel
*)gtk_list_store_new (NUM_COLUMNS
,
1304 G_TYPE_POINTER
); /* attribute */
1305 /* - create a scrolled window for the treeview */
1306 scrolled_win
= GTK_WIDGET (
1307 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1310 /* GtkScrolledWindow */
1311 "hscrollbar-policy",
1312 GTK_POLICY_AUTOMATIC
,
1313 "vscrollbar-policy",
1314 GTK_POLICY_AUTOMATIC
,
1316 GTK_SHADOW_ETCHED_IN
,
1318 /* - create the treeview */
1319 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
1324 g_signal_connect (treeview
,
1326 G_CALLBACK (multiattrib_callback_key_pressed
),
1328 g_signal_connect (treeview
,
1329 "button-press-event",
1330 G_CALLBACK (multiattrib_callback_button_pressed
),
1332 g_signal_connect (treeview
,
1334 G_CALLBACK (multiattrib_callback_popup_menu
),
1336 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
1337 gtk_tree_selection_set_mode (selection
,
1338 GTK_SELECTION_SINGLE
);
1340 /* - and now the columns of the treeview */
1341 /* - column 1: attribute name */
1342 renderer
= GTK_CELL_RENDERER (
1343 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT
,
1344 /* GtkCellRendererText */
1346 /* unknown in GTK 2.4 */
1348 * PANGO_ELLIPSIZE_END, */
1350 g_signal_connect (renderer
,
1352 G_CALLBACK (multiattrib_callback_edited_name
),
1354 column
= GTK_TREE_VIEW_COLUMN (
1355 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1356 /* GtkTreeViewColumn */
1361 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1362 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1363 multiattrib_column_set_data_name
,
1365 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1366 /* - column 2: attribute value */
1367 renderer
= GTK_CELL_RENDERER (
1368 g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT
,
1369 /* GtkCellRendererText */
1371 /* unknown in GTK 2.4 */
1373 PANGO_ELLIPSIZE_END, */
1375 g_signal_connect (renderer
,
1377 G_CALLBACK (multiattrib_callback_edited_value
),
1379 column
= GTK_TREE_VIEW_COLUMN (
1380 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1381 /* GtkTreeViewColumn */
1382 "title", _("Value"),
1386 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1387 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1388 multiattrib_column_set_data_value
,
1390 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1391 /* - column 3: visibility */
1392 renderer
= GTK_CELL_RENDERER (
1393 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1394 /* GtkCellRendererToggle */
1395 "activatable", TRUE
,
1397 g_signal_connect (renderer
,
1399 G_CALLBACK (multiattrib_callback_toggled_visible
),
1401 column
= GTK_TREE_VIEW_COLUMN (
1402 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1403 /* GtkTreeViewColumn */
1406 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1407 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1408 multiattrib_column_set_data_visible
,
1410 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1411 /* - column 4: show name */
1412 renderer
= GTK_CELL_RENDERER (
1413 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1414 /* GtkCellRendererToggle */
1415 "activatable", TRUE
,
1417 g_signal_connect (renderer
,
1419 G_CALLBACK (multiattrib_callback_toggled_show_name
),
1421 column
= GTK_TREE_VIEW_COLUMN (
1422 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1423 /* GtkTreeViewColumn */
1426 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1427 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1428 multiattrib_column_set_data_show_name
,
1430 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1431 /* - column 5: show value */
1432 renderer
= GTK_CELL_RENDERER (
1433 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
1434 /* GtkCellRendererToggle */
1435 "activatable", TRUE
,
1437 g_signal_connect (renderer
,
1439 G_CALLBACK (multiattrib_callback_toggled_show_value
),
1441 column
= GTK_TREE_VIEW_COLUMN (
1442 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
1443 /* GtkTreeViewColumn */
1446 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1447 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1448 multiattrib_column_set_data_show_value
,
1450 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
1452 /* add the treeview to the scrolled window */
1453 gtk_container_add (GTK_CONTAINER (scrolled_win
), treeview
);
1454 /* set treeview of multiattrib */
1455 multiattrib
->treeview
= GTK_TREE_VIEW (treeview
);
1456 /* add the scrolled window to frame */
1457 gtk_container_add (GTK_CONTAINER (frame
), scrolled_win
);
1458 /* pack the frame */
1459 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1461 gtk_widget_show_all (frame
);
1463 /* create the add/edit frame */
1464 frame
= GTK_WIDGET (g_object_new (GTK_TYPE_FRAME
,
1465 "label", _("Add Attribute"),
1467 table
= GTK_WIDGET (g_object_new (GTK_TYPE_TABLE
,
1471 "homogeneous", FALSE
,
1474 /* - the name entry: a GtkComboBoxEntry */
1475 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1480 "label", _("Name:"),
1482 combo
= GTK_WIDGET (g_object_new (GTK_TYPE_COMBO
,
1484 "value-in-list", FALSE
,
1486 multiattrib_init_attrib_names (GTK_COMBO (combo
));
1487 multiattrib
->combo_name
= GTK_COMBO (combo
);
1488 gtk_table_attach (GTK_TABLE (table
), label
,
1489 0, 1, 0, 1, 0, 0, 0, 0);
1490 gtk_table_attach (GTK_TABLE (table
), combo
,
1491 1, 2, 0, 1, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1493 /* - the value entry: a GtkEntry */
1494 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
1499 "label", _("Value:"),
1501 scrolled_win
= GTK_WIDGET (
1502 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
1503 /* GtkScrolledWindow */
1504 "hscrollbar-policy",
1506 "vscrollbar-policy",
1507 GTK_POLICY_AUTOMATIC
,
1511 textview
= GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW
,
1513 g_signal_connect (textview
,
1515 G_CALLBACK (multiattrib_callback_value_key_pressed
),
1517 gtk_container_add (GTK_CONTAINER (scrolled_win
), textview
);
1518 multiattrib
->textview_value
= GTK_TEXT_VIEW (textview
);
1519 gtk_table_attach (GTK_TABLE (table
), label
,
1520 0, 1, 1, 2, 0, 0, 0, 0);
1521 gtk_table_attach (GTK_TABLE (table
), scrolled_win
,
1522 1, 2, 1, 2, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1524 /* - the visible status */
1525 button
= GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON
,
1527 "label", _("Visible"),
1530 multiattrib
->button_visible
= GTK_CHECK_BUTTON (button
);
1531 gtk_table_attach (GTK_TABLE (table
), button
,
1532 0, 1, 2, 3, GTK_FILL
, 0, 3, 0);
1534 /* - the visibility type */
1535 optionm
= GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU
,
1537 multiattrib_init_visible_types (GTK_OPTION_MENU (optionm
));
1538 multiattrib
->optionmenu_shownv
= GTK_OPTION_MENU (optionm
);
1539 gtk_table_attach (GTK_TABLE (table
), optionm
,
1540 1, 2, 2, 3, GTK_EXPAND
| GTK_FILL
, 0, 6, 3);
1541 gtk_widget_show_all (table
);
1543 /* create the add button */
1544 button
= gtk_button_new_from_stock (GTK_STOCK_ADD
);
1545 g_signal_connect (button
,
1547 G_CALLBACK (multiattrib_callback_button_add
),
1549 gtk_table_attach (GTK_TABLE (table
), button
,
1550 2, 3, 0, 3, 0, 0, 6, 3);
1552 /* add the table to the frame */
1553 gtk_container_add (GTK_CONTAINER (frame
), table
);
1554 /* pack the frame in the dialog */
1555 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib
)->vbox
), frame
,
1557 gtk_widget_show_all (frame
);
1560 /* now add the close button to the action area */
1561 gtk_dialog_add_button (GTK_DIALOG (multiattrib
),
1562 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
);
1566 /*! \todo Finish function documentation
1568 * \par Function Description
1571 static void multiattrib_set_property (GObject
*object
,
1573 const GValue
*value
,
1576 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
1578 switch(property_id
) {
1580 multiattrib
->object
= (OBJECT
*)g_value_get_pointer (value
);
1581 multiattrib_update (multiattrib
);
1584 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1589 /*! \todo Finish function documentation
1591 * \par Function Description
1594 static void multiattrib_get_property (GObject
*object
,
1599 Multiattrib
*multiattrib
= MULTIATTRIB (object
);
1601 switch(property_id
) {
1603 g_value_set_pointer (value
, (gpointer
)multiattrib
->object
);
1606 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1611 /*! \todo Finish function documentation
1613 * \par Function Description
1616 void multiattrib_update (Multiattrib
*multiattrib
)
1618 GtkListStore
*liststore
;
1620 OBJECT
**object_attribs
, *o_current
;
1623 if (GSCHEM_DIALOG (multiattrib
)->toplevel
== NULL
||
1624 multiattrib
->object
== NULL
) {
1625 /* we can not do anything until both toplevel and object are set */
1629 liststore
= (GtkListStore
*)gtk_tree_view_get_model (multiattrib
->treeview
);
1631 /* clear the list of attributes */
1632 gtk_list_store_clear (liststore
);
1634 /* get list of attributes */
1635 object_attribs
= o_attrib_return_attribs (
1636 GSCHEM_DIALOG (multiattrib
)->toplevel
->page_current
->object_head
,
1637 multiattrib
->object
);
1638 /* populate the store with attributes */
1639 if (object_attribs
) {
1640 for (i
= 0, o_current
= object_attribs
[i
];
1642 i
++, o_current
= object_attribs
[i
]) {
1643 gtk_list_store_append (liststore
, &iter
);
1644 gtk_list_store_set (liststore
, &iter
,
1645 COLUMN_ATTRIBUTE
, o_current
,
1649 /* delete the list of attribute objects */
1650 o_attrib_free_returned (object_attribs
);