Hunt down some unused variables.
[geda-gaf/berndj.git] / gschem / src / x_multiattrib.c
blob0a115c5e40e8143eff97a1237cb71a3a28d185ea
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
20 #include <config.h>
22 #include <stdio.h>
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
30 #include "gschem.h"
31 #include <gdk/gdkkeysyms.h>
33 #ifdef HAVE_LIBDMALLOC
34 #include <dmalloc.h>
35 #endif
38 /*! \brief Update the multiattrib editor dialog when the page's
39 * selection changes.
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,
50 gpointer user_data)
52 Multiattrib *multiattrib = MULTIATTRIB (user_data);
53 GList *iter;
54 OBJECT *object;
55 gint object_count = 0;
57 for (iter = geda_list_get_glist (selection);
58 iter != NULL;
59 iter = g_list_next (iter)) {
60 object = iter->data;
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) {
69 object_count++;
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.
79 object = NULL;
80 } else if (object_count == 1) {
81 object = (geda_list_get_glist (selection))->data;
82 } else {
83 /* TODO: Something clever with multiple objects selected */
84 object = NULL;
87 g_object_set (multiattrib,
88 "object", object,
89 NULL);
92 #define DIALOG_DATA_SELECTION "current-selection"
94 /*! \brief Update the dialog when the current page's SELECTION object
95 * is destroyed
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.
102 * \note
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
108 * just destroyed
110 static void callback_selection_finalized (gpointer data,
111 GObject *where_the_object_was)
113 Multiattrib *multiattrib = MULTIATTRIB (data);
114 g_object_set (multiattrib,
115 "object", NULL,
116 NULL);
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,
137 multiattrib);
138 g_signal_connect (selection,
139 "changed",
140 (GCallback)callback_selection_changed,
141 multiattrib);
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
150 * added on it.
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 */
162 return;
165 g_signal_handlers_disconnect_matched (selection,
166 G_SIGNAL_MATCH_FUNC |
167 G_SIGNAL_MATCH_DATA,
168 0, 0, NULL,
169 callback_selection_changed,
170 multiattrib);
171 g_object_weak_unref (G_OBJECT (selection),
172 callback_selection_finalized,
173 multiattrib);
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.
188 static void
189 multiattrib_callback_response (GtkDialog *dialog,
190 gint arg1,
191 gpointer user_data)
193 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL*)user_data;
195 switch (arg1) {
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;
202 break;
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,
217 "object", NULL,
218 /* GschemDialog */
219 "settings-name", "multiattrib",
220 "gschem-toplevel", w_current,
221 /* GtkDialog */
222 "type", GTK_WINDOW_TOPLEVEL,
223 NULL));
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,
229 "response",
230 G_CALLBACK (multiattrib_callback_response),
231 w_current);
233 /* attach dialog to selection of current page */
234 x_multiattrib_update (w_current, selection);
236 gtk_widget_show (w_current->mawindow);
237 } else {
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)) {
273 return;
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
293 * \brief
294 * \par Function Description
297 static gboolean celltextview_key_press_event (GtkWidget *widget,
298 GdkEventKey *key_event,
299 gpointer data)
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));
315 return TRUE;
318 return FALSE;
321 /*! \todo Finish function documentation
322 * \brief
323 * \par Function Description
326 static void celltextview_start_editing (GtkCellEditable *cell_editable,
327 GdkEvent *event)
329 g_signal_connect (cell_editable,
330 "key_press_event",
331 G_CALLBACK (celltextview_key_press_event),
332 NULL);
336 /*! \todo Finish function documentation
337 * \brief
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),
354 0, /* n_preallocs */
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,
365 "CellTextView",
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
376 * \brief
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
386 * \brief
387 * \par Function Description
390 static void celltextview_init(CellTextView *celltextview)
392 celltextview->editing_canceled = FALSE;
395 /*! \todo Finish function documentation
396 * \brief
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
408 * of GTK 2.4 (LGPL).
410 static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass *klass);
411 static void cellrenderermultilinetext_editing_done (GtkCellEditable *cell_editable,
412 gpointer user_data);
413 static gboolean cellrenderermultilinetext_focus_out_event (GtkWidget *widget,
414 GdkEvent *event,
415 gpointer user_data);
418 #define CELL_RENDERER_MULTI_LINE_TEXT_PATH "cell-renderer-multi-line-text-path"
421 /*! \todo Finish function documentation
422 * \brief
423 * \par Function Description
426 static GtkCellEditable* cellrenderermultilinetext_start_editing(GtkCellRenderer *cell,
427 GdkEvent *event,
428 GtkWidget *widget,
429 const gchar *path,
430 GdkRectangle *background_area,
431 GdkRectangle *cell_area,
432 GtkCellRendererState flags)
434 GtkCellRendererText *cell_text;
435 CellRendererMultiLineText *cell_mlt;
436 GtkWidget *textview;
437 GtkTextBuffer *textbuffer;
439 cell_text = GTK_CELL_RENDERER_TEXT (cell);
440 if (cell_text->editable == FALSE) {
441 return NULL;
444 cell_mlt = CELL_RENDERER_MULTI_LINE_TEXT (cell);
446 textbuffer = GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER,
447 NULL));
448 gtk_text_buffer_set_text (textbuffer,
449 cell_text->text,
450 strlen (cell_text->text));
452 textview = GTK_WIDGET (g_object_new (TYPE_CELL_TEXT_VIEW,
453 /* GtkTextView */
454 "buffer", textbuffer,
455 "editable", TRUE,
456 /* GtkWidget */
457 "height-request", cell_area->height,
458 NULL));
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),
466 "editing_done",
467 G_CALLBACK (cellrenderermultilinetext_editing_done),
468 cell_mlt);
469 cell_mlt->focus_out_id =
470 g_signal_connect (textview,
471 "focus_out_event",
472 G_CALLBACK (cellrenderermultilinetext_focus_out_event),
473 cell_mlt);
475 return GTK_CELL_EDITABLE (textview);
478 /*! \todo Finish function documentation
479 * \brief
480 * \par Function Description
483 static void cellrenderermultilinetext_editing_done(GtkCellEditable *cell_editable,
484 gpointer user_data)
486 CellRendererMultiLineText *cell = CELL_RENDERER_MULTI_LINE_TEXT (user_data);
487 GtkTextBuffer *buffer;
488 GtkTextIter start, end;
489 gchar *new_text;
490 const gchar *path;
492 if (cell->focus_out_id > 0) {
493 g_signal_handler_disconnect (cell_editable,
494 cell->focus_out_id);
495 cell->focus_out_id = 0;
498 if (CELL_TEXT_VIEW (cell_editable)->editing_canceled) {
499 g_signal_emit_by_name (cell, "editing-canceled");
500 return;
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);
512 g_free (new_text);
516 /*! \todo Finish function documentation
517 * \brief
518 * \par Function Description
521 static gboolean cellrenderermultilinetext_focus_out_event(GtkWidget *widget,
522 GdkEvent *event,
523 gpointer user_data)
525 cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget),
526 user_data);
528 return FALSE;
531 /*! \todo Finish function documentation
532 * \brief
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),
549 0, /* n_preallocs */
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
563 * \brief
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;
577 enum {
578 PROP_OBJECT = 1
581 enum {
582 COLUMN_ATTRIBUTE,
583 NUM_COLUMNS
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,
591 guint property_id,
592 const GValue *value,
593 GParamSpec *pspec);
594 static void multiattrib_get_property (GObject *object,
595 guint property_id,
596 GValue *value,
597 GParamSpec *pspec);
599 static void multiattrib_popup_menu (Multiattrib *multiattrib,
600 GdkEventButton *event);
603 /*! \todo Finish function documentation
604 * \brief
605 * \par Function Description
608 static void multiattrib_action_add_attribute(GSCHEM_TOPLEVEL *w_current,
609 OBJECT *object,
610 Multiattrib *multiattrib,
611 const gchar *name,
612 const gchar *value,
613 gint button_visible,
614 gint show_name_value)
616 gchar *newtext;
618 newtext = g_strdup_printf ("%s=%s", name, value);
620 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib), newtext)) {
621 g_free(newtext);
622 return;
625 /* create a new attribute and link it */
626 o_attrib_add_attrib(w_current, newtext, button_visible, show_name_value,
627 object);
629 w_current->toplevel->page_current->CHANGED = 1;
630 o_undo_savestate (w_current, UNDO_ALL);
632 g_free (newtext);
635 /*! \todo Finish function documentation
636 * \brief
637 * \par Function Description
640 static void multiattrib_action_duplicate_attribute(GSCHEM_TOPLEVEL *w_current,
641 OBJECT *object,
642 OBJECT *o_attrib)
644 o_attrib_add_attrib(w_current, o_text_get_string(o_attrib),
645 o_attrib->visibility, o_attrib->show_name_value,
646 object);
647 w_current->toplevel->page_current->CHANGED = 1;
648 o_undo_savestate (w_current, UNDO_ALL);
652 /*! \todo Finish function documentation
653 * \brief
654 * \par Function Description
657 static void multiattrib_action_delete_attribute(GSCHEM_TOPLEVEL *w_current,
658 OBJECT *o_attrib)
660 SELECTION *selection;
662 g_object_get(w_current->mawindow, DIALOG_DATA_SELECTION, &selection, NULL);
664 /* actually deletes the attribute */
665 o_selection_remove (selection, o_attrib);
666 o_delete (w_current, o_attrib);
667 w_current->toplevel->page_current->CHANGED=1;
668 o_undo_savestate (w_current, UNDO_ALL);
671 /*! \todo Finish function documentation
672 * \brief
673 * \par Function Description
676 static void multiattrib_column_set_data_name(GtkTreeViewColumn *tree_column,
677 GtkCellRenderer *cell,
678 GtkTreeModel *tree_model,
679 GtkTreeIter *iter,
680 gpointer data)
682 OBJECT *o_attrib;
683 gchar *name;
684 const gchar *str = NULL;
686 gtk_tree_model_get (tree_model, iter,
687 COLUMN_ATTRIBUTE, &o_attrib,
688 -1);
689 g_assert (o_attrib->type == OBJ_TEXT);
691 str = o_text_get_string(o_attrib);
693 o_attrib_get_name_value (str, &name, NULL);
694 g_object_set (cell,
695 "text", name,
696 NULL);
697 g_free (name);
701 /*! \todo Finish function documentation
702 * \brief
703 * \par Function Description
706 static void multiattrib_column_set_data_value(GtkTreeViewColumn *tree_column,
707 GtkCellRenderer *cell,
708 GtkTreeModel *tree_model,
709 GtkTreeIter *iter,
710 gpointer data)
712 OBJECT *o_attrib;
713 gchar *value;
714 const gchar *str = NULL;
716 gtk_tree_model_get (tree_model, iter,
717 COLUMN_ATTRIBUTE, &o_attrib,
718 -1);
719 g_assert (o_attrib->type == OBJ_TEXT);
721 str = o_text_get_string(o_attrib);
723 o_attrib_get_name_value (str, NULL, &value);
724 g_object_set (cell,
725 "text", value,
726 NULL);
727 g_free (value);
731 /*! \todo Finish function documentation
732 * \brief
733 * \par Function Description
736 static void multiattrib_column_set_data_visible(GtkTreeViewColumn *tree_column,
737 GtkCellRenderer *cell,
738 GtkTreeModel *tree_model,
739 GtkTreeIter *iter,
740 gpointer data)
742 OBJECT *o_attrib;
744 gtk_tree_model_get (tree_model, iter,
745 COLUMN_ATTRIBUTE, &o_attrib,
746 -1);
747 g_assert (o_attrib->type == OBJ_TEXT);
749 g_object_set (cell,
750 "active", (o_attrib->visibility == VISIBLE),
751 NULL);
755 /*! \todo Finish function documentation
756 * \brief
757 * \par Function Description
760 static void multiattrib_column_set_data_show_name(GtkTreeViewColumn *tree_column,
761 GtkCellRenderer *cell,
762 GtkTreeModel *tree_model,
763 GtkTreeIter *iter,
764 gpointer data)
766 OBJECT *o_attrib;
768 gtk_tree_model_get (tree_model, iter,
769 COLUMN_ATTRIBUTE, &o_attrib,
770 -1);
771 g_assert (o_attrib->type == OBJ_TEXT);
773 g_object_set (cell,
774 "active", (o_attrib->show_name_value == SHOW_NAME_VALUE ||
775 o_attrib->show_name_value == SHOW_NAME),
776 NULL);
780 /*! \todo Finish function documentation
781 * \brief
782 * \par Function Description
785 static void multiattrib_column_set_data_show_value(GtkTreeViewColumn *tree_column,
786 GtkCellRenderer *cell,
787 GtkTreeModel *tree_model,
788 GtkTreeIter *iter,
789 gpointer data)
791 OBJECT *o_attrib;
793 gtk_tree_model_get (tree_model, iter,
794 COLUMN_ATTRIBUTE, &o_attrib,
795 -1);
796 g_assert (o_attrib->type == OBJ_TEXT);
798 g_object_set (cell,
799 "active", (o_attrib->show_name_value == SHOW_NAME_VALUE ||
800 o_attrib->show_name_value == SHOW_VALUE),
801 NULL);
805 /*! \brief Requests an update of the display of a row.
806 * \par Function Description
807 * This is an helper function to update the display of a row when
808 * data for this row have been modified in the model.
810 * It emits the 'row_changed' signal on the pointed row.
812 * \param [in] model A GtkTreeModel.
813 * \param [in] iter A valid GtkTreeIter pointing to the changed row.
815 static void
816 update_row_display (GtkTreeModel *model, GtkTreeIter *iter)
818 GtkTreePath *path;
820 path = gtk_tree_model_get_path (model, iter);
821 gtk_tree_model_row_changed (model, path, iter);
822 gtk_tree_path_free (path);
826 /*! \todo Finish function documentation
827 * \brief
828 * \par Function Description
831 static void multiattrib_callback_edited_name(GtkCellRendererText *cellrenderertext,
832 gchar *arg1,
833 gchar *arg2,
834 gpointer user_data)
836 Multiattrib *multiattrib = (Multiattrib*)user_data;
837 GtkTreeModel *model;
838 GtkTreeIter iter;
839 OBJECT *o_attrib;
840 gchar *value, *newtext;
842 model = gtk_tree_view_get_model (multiattrib->treeview);
844 if (!gtk_tree_model_get_iter_from_string (model, &iter, arg1)) {
845 return;
848 if (g_ascii_strcasecmp (arg2, "") == 0) {
849 GtkWidget *dialog = gtk_message_dialog_new (
850 GTK_WINDOW (multiattrib),
851 GTK_DIALOG_MODAL,
852 GTK_MESSAGE_ERROR,
853 GTK_BUTTONS_OK,
854 _("Attributes with empty name are not allowed. Please set a name."));
856 gtk_dialog_run (GTK_DIALOG (dialog));
857 gtk_widget_destroy (dialog);
858 return;
861 gtk_tree_model_get (model, &iter,
862 COLUMN_ATTRIBUTE, &o_attrib,
863 -1);
864 g_assert (o_attrib->type == OBJ_TEXT);
866 o_attrib_get_name_value(o_text_get_string(o_attrib), NULL, &value);
867 newtext = g_strdup_printf ("%s=%s", arg2, value);
869 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib), newtext)) {
870 g_free (value);
871 g_free(newtext);
872 return;
876 /* actually modifies the attribute */
877 o_text_change(o_attrib, newtext,
878 o_attrib->visibility, o_attrib->show_name_value);
880 g_free (value);
881 g_free (newtext);
885 /*! \todo Finish function documentation
886 * \brief
887 * \par Function Description
890 static void multiattrib_callback_edited_value(GtkCellRendererText *cell_renderer,
891 gchar *arg1,
892 gchar *arg2,
893 gpointer user_data)
895 Multiattrib *multiattrib = (Multiattrib*)user_data;
896 GtkTreeModel *model;
897 GtkTreeIter iter;
898 OBJECT *o_attrib;
899 gchar *name, *newtext;
901 model = gtk_tree_view_get_model (multiattrib->treeview);
903 if (!gtk_tree_model_get_iter_from_string (model, &iter, arg1)) {
904 return;
907 gtk_tree_model_get (model, &iter,
908 COLUMN_ATTRIBUTE, &o_attrib,
909 -1);
910 g_assert (o_attrib->type == OBJ_TEXT);
912 o_attrib_get_name_value(o_text_get_string(o_attrib), &name, NULL);
913 newtext = g_strdup_printf ("%s=%s", name, arg2);
915 if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib), newtext)) {
916 g_free (name);
917 g_free(newtext);
918 return;
921 /* actually modifies the attribute */
922 o_text_change(o_attrib, newtext,
923 o_attrib->visibility, o_attrib->show_name_value);
925 /* request an update of display for this row */
926 update_row_display (model, &iter);
928 g_free (name);
929 g_free (newtext);
933 /*! \todo Finish function documentation
934 * \brief
935 * \par Function Description
938 static void multiattrib_callback_toggled_visible(GtkCellRendererToggle *cell_renderer,
939 gchar *path,
940 gpointer user_data)
942 Multiattrib *multiattrib = (Multiattrib*)user_data;
943 GtkTreeModel *model;
944 GtkTreeIter iter;
945 OBJECT *o_attrib;
946 GSCHEM_TOPLEVEL *w_current;
947 gint visibility;
949 model = gtk_tree_view_get_model (multiattrib->treeview);
950 w_current = GSCHEM_DIALOG (multiattrib)->w_current;
952 if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
953 return;
956 gtk_tree_model_get (model, &iter,
957 COLUMN_ATTRIBUTE, &o_attrib,
958 -1);
959 g_assert (o_attrib->type == OBJ_TEXT);
960 o_erase_single (w_current, o_attrib);
962 visibility = o_attrib->visibility == VISIBLE ? INVISIBLE : VISIBLE;
964 /* actually modifies the attribute */
965 o_attrib->visibility = visibility;
966 o_text_recreate(o_attrib);
967 o_text_draw (w_current, o_attrib);
968 o_undo_savestate (w_current, UNDO_ALL);
970 /* request an update of display for this row */
971 update_row_display (model, &iter);
975 /*! \todo Finish function documentation
976 * \brief
977 * \par Function Description
980 static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle *cell_renderer,
981 gchar *path,
982 gpointer user_data)
984 Multiattrib *multiattrib = (Multiattrib*)user_data;
985 GtkTreeModel *model;
986 GtkTreeIter iter;
987 OBJECT *o_attrib;
988 GSCHEM_TOPLEVEL *w_current;
989 gint new_snv;
991 model = gtk_tree_view_get_model (multiattrib->treeview);
992 w_current = GSCHEM_DIALOG (multiattrib)->w_current;
994 if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
995 return;
998 gtk_tree_model_get (model, &iter,
999 COLUMN_ATTRIBUTE, &o_attrib,
1000 -1);
1001 g_assert (o_attrib->type == OBJ_TEXT);
1002 o_erase_single (w_current, o_attrib);
1004 switch (o_attrib->show_name_value) {
1005 case SHOW_NAME_VALUE: new_snv = SHOW_VALUE; break;
1006 case SHOW_NAME: new_snv = SHOW_VALUE; break;
1007 case SHOW_VALUE: new_snv = SHOW_NAME_VALUE; break;
1008 default:
1009 g_assert_not_reached ();
1010 new_snv = SHOW_NAME_VALUE;
1013 /* actually modifies the attribute */
1014 o_attrib->show_name_value = new_snv;
1015 o_text_recreate(o_attrib);
1016 o_text_draw (w_current, o_attrib);
1017 o_undo_savestate (w_current, UNDO_ALL);
1019 /* request an update of display for this row */
1020 update_row_display (model, &iter);
1024 /*! \todo Finish function documentation
1025 * \brief
1026 * \par Function Description
1029 static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle *cell_renderer,
1030 gchar *path,
1031 gpointer user_data)
1033 Multiattrib *multiattrib = (Multiattrib*)user_data;
1034 GtkTreeModel *model;
1035 GtkTreeIter iter;
1036 OBJECT *o_attrib;
1037 GSCHEM_TOPLEVEL *w_current;
1038 gint new_snv;
1040 model = gtk_tree_view_get_model (multiattrib->treeview);
1041 w_current = GSCHEM_DIALOG (multiattrib)->w_current;
1043 if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
1044 return;
1047 gtk_tree_model_get (model, &iter,
1048 COLUMN_ATTRIBUTE, &o_attrib,
1049 -1);
1050 g_assert (o_attrib->type == OBJ_TEXT);
1051 o_erase_single (w_current, o_attrib);
1053 switch (o_attrib->show_name_value) {
1054 case SHOW_NAME_VALUE: new_snv = SHOW_NAME; break;
1055 case SHOW_NAME: new_snv = SHOW_NAME_VALUE; break;
1056 case SHOW_VALUE: new_snv = SHOW_NAME; break;
1057 default:
1058 g_assert_not_reached ();
1059 new_snv = SHOW_NAME_VALUE;
1062 /* actually modifies the attribute */
1063 o_attrib->show_name_value = new_snv;
1064 o_text_recreate(o_attrib);
1065 o_text_draw (w_current, o_attrib);
1066 o_undo_savestate (w_current, UNDO_ALL);
1068 /* request an update of display for this row */
1069 update_row_display (model, &iter);
1073 /*! \todo Finish function documentation
1074 * \brief
1075 * \par Function Description
1078 static gboolean multiattrib_callback_key_pressed(GtkWidget *widget,
1079 GdkEventKey *event,
1080 gpointer user_data)
1082 Multiattrib *multiattrib = (Multiattrib*)user_data;
1084 if (event->state == 0 &&
1085 (event->keyval == GDK_Delete || event->keyval == GDK_KP_Delete)) {
1086 GtkTreeModel *model;
1087 GtkTreeIter iter;
1088 OBJECT *o_attrib;
1089 /* delete the currently selected attribute */
1091 if (!gtk_tree_selection_get_selected (
1092 gtk_tree_view_get_selection (multiattrib->treeview),
1093 &model, &iter)) {
1094 /* nothing selected, nothing to do */
1095 return FALSE;
1098 gtk_tree_model_get (model, &iter,
1099 COLUMN_ATTRIBUTE, &o_attrib,
1100 -1);
1101 g_assert (o_attrib->type == OBJ_TEXT);
1103 multiattrib_action_delete_attribute (GSCHEM_DIALOG (multiattrib)->w_current,
1104 o_attrib);
1106 /* update the treeview contents */
1107 multiattrib_update (multiattrib);
1110 return FALSE;
1113 /*! \todo Finish function documentation
1114 * \brief
1115 * \par Function Description
1118 static gboolean multiattrib_callback_button_pressed(GtkWidget *widget,
1119 GdkEventButton *event,
1120 gpointer user_data)
1122 Multiattrib *multiattrib = (Multiattrib*)user_data;
1123 gboolean ret = FALSE;
1125 if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
1126 multiattrib_popup_menu (multiattrib, event);
1127 ret = TRUE;
1130 return ret;
1133 /*! \todo Finish function documentation
1134 * \brief
1135 * \par Function Description
1138 static gboolean multiattrib_callback_popup_menu(GtkWidget *widget,
1139 gpointer user_data)
1141 Multiattrib *multiattrib = (Multiattrib*)user_data;
1143 multiattrib_popup_menu (multiattrib, NULL);
1145 return TRUE;
1148 /*! \todo Finish function documentation
1149 * \brief
1150 * \par Function Description
1153 static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
1154 gpointer user_data)
1156 Multiattrib *multiattrib = (Multiattrib*)user_data;
1157 GtkTreeModel *model;
1158 GtkTreeIter iter;
1159 GSCHEM_TOPLEVEL *w_current;
1160 OBJECT *object, *o_attrib;
1162 if (!gtk_tree_selection_get_selected (
1163 gtk_tree_view_get_selection (multiattrib->treeview),
1164 &model, &iter)) {
1165 /* nothing selected, nothing to do */
1166 return;
1169 w_current = GSCHEM_DIALOG (multiattrib)->w_current;
1170 object = multiattrib->object;
1172 gtk_tree_model_get (model, &iter,
1173 COLUMN_ATTRIBUTE, &o_attrib,
1174 -1);
1175 g_assert (o_attrib->type == OBJ_TEXT);
1177 multiattrib_action_duplicate_attribute (w_current, object, o_attrib);
1179 /* update the treeview contents */
1180 multiattrib_update (multiattrib);
1184 /*! \todo Finish function documentation
1185 * \brief
1186 * \par Function Description
1189 static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
1190 gpointer user_data)
1192 Multiattrib *multiattrib = (Multiattrib*)user_data;
1193 GtkTreeModel *model;
1194 GtkTreeIter iter;
1195 GSCHEM_TOPLEVEL *w_current;
1196 OBJECT *o_attrib;
1198 if (!gtk_tree_selection_get_selected (
1199 gtk_tree_view_get_selection (multiattrib->treeview),
1200 &model, &iter)) {
1201 /* nothing selected, nothing to do */
1202 return;
1205 w_current = GSCHEM_DIALOG (multiattrib)->w_current;
1207 gtk_tree_model_get (model, &iter,
1208 COLUMN_ATTRIBUTE, &o_attrib,
1209 -1);
1210 g_assert (o_attrib->type == OBJ_TEXT);
1212 multiattrib_action_delete_attribute (w_current, o_attrib);
1214 /* update the treeview contents */
1215 multiattrib_update (multiattrib);
1219 /*! \todo Finish function documentation
1220 * \brief
1221 * \par Function Description
1224 static gboolean multiattrib_callback_value_key_pressed(GtkWidget *widget,
1225 GdkEventKey *event,
1226 gpointer user_data)
1228 Multiattrib *multiattrib = (Multiattrib*)widget;
1229 gboolean retval = FALSE;
1231 /* ends editing of cell if one of these keys are pressed: */
1232 /* - the Return key without the Control modifier */
1233 /* - the Tab key without the Control modifier */
1234 if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) ||
1235 (event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab)) {
1236 /* Control modifier activated? */
1237 if (event->state & GDK_CONTROL_MASK) {
1238 /* yes the modifier in event structure and let event propagate */
1239 event->state ^= GDK_CONTROL_MASK;
1240 retval = FALSE;
1241 } else {
1242 /* change focus and stop propagation */
1243 g_signal_emit_by_name (multiattrib,
1244 "move_focus",
1245 (event->state & GDK_SHIFT_MASK) ?
1246 GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
1247 retval = TRUE;
1251 return retval;
1255 /*! \brief GtkWidget "grab-focus" signal handler
1257 * \par Function Description
1258 * Select the text in the GtkTextView so it may be over-typed quickly
1260 static void multiattrib_callback_value_grab_focus (GtkWidget *widget,
1261 gpointer user_data)
1263 GtkTextView *textview = GTK_TEXT_VIEW (widget);
1264 GtkTextBuffer *textbuffer;
1265 GtkTextIter startiter, enditer;
1267 textbuffer = gtk_text_view_get_buffer (textview);
1268 gtk_text_buffer_get_iter_at_offset (textbuffer, &startiter, 0);
1269 gtk_text_buffer_get_iter_at_offset (textbuffer, &enditer, -1);
1270 gtk_text_buffer_select_range (textbuffer, &enditer, &startiter);
1274 /*! \todo Finish function documentation
1275 * \brief
1276 * \par Function Description
1279 static void multiattrib_callback_button_add(GtkButton *button,
1280 gpointer user_data)
1282 Multiattrib *multiattrib = (Multiattrib*)user_data;
1283 GtkTextBuffer *buffer;
1284 GtkTextIter start, end;
1285 const gchar *name;
1286 gchar *value;
1287 GSCHEM_TOPLEVEL *w_current;
1288 OBJECT *object;
1289 gboolean button_visible;
1290 gint shownv;
1292 w_current = GSCHEM_DIALOG (multiattrib)->w_current;
1293 object = multiattrib->object;
1294 buffer = gtk_text_view_get_buffer (multiattrib->textview_value);
1296 /* retrieve information from the Add/Edit frame */
1297 /* - attribute's name */
1298 name = gtk_entry_get_text (
1299 GTK_ENTRY (GTK_COMBO (multiattrib->combo_name)->entry));
1300 /* - attribute's value */
1301 gtk_text_buffer_get_bounds (buffer, &start, &end);
1302 value = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1303 /* - attribute's visibility status */
1304 button_visible = gtk_toggle_button_get_active(
1305 (GtkToggleButton*)multiattrib->button_visible);
1306 /* - visibility type */
1307 shownv = (gint)gtk_option_menu_get_history (multiattrib->optionmenu_shownv);
1309 if (name[0] == '\0' || name[0] == ' ') {
1310 /* name not allowed for an attribute */
1311 g_free (value);
1312 return;
1315 multiattrib_action_add_attribute (w_current, object, multiattrib,
1316 name, value,
1317 button_visible, shownv);
1318 g_free (value);
1320 multiattrib_update (multiattrib);
1323 /*! \todo Finish function documentation
1324 * \brief
1325 * \par Function Description
1328 static void multiattrib_init_attrib_names(GtkCombo *combo)
1330 GList *items = NULL;
1331 const gchar *string;
1332 gint i;
1334 for (i = 0, string = s_attrib_get (i);
1335 string != NULL;
1336 i++, string = s_attrib_get (i)) {
1337 items = g_list_append (items, (gpointer)string);
1340 gtk_combo_set_popdown_strings (GTK_COMBO (combo), items);
1342 g_list_free (items);
1346 /*! \todo Finish function documentation
1347 * \brief
1348 * \par Function Description
1351 static void multiattrib_init_visible_types(GtkOptionMenu *optionmenu)
1353 GtkWidget *menu, *item;
1355 menu = gtk_menu_new ();
1356 item = gtk_menu_item_new_with_label (_("Show Name & Value"));
1357 gtk_menu_append (menu, item);
1358 item = gtk_menu_item_new_with_label (_("Show Value only"));
1359 gtk_menu_append (menu, item);
1360 item = gtk_menu_item_new_with_label (_("Show Name only"));
1361 gtk_menu_append (menu, item);
1363 gtk_option_menu_set_menu (optionmenu, menu);
1368 /*! \brief Popup a context-sensitive menu.
1369 * \par Function Description
1370 * Pops up a context-sensitive menu.
1371 * <B>event</B> can be NULL if the popup is triggered by a key binding
1372 * instead of a mouse click.
1374 * \param [in] multiattrib The Multiattrib object.
1375 * \param [in] event Mouse event.
1377 static void multiattrib_popup_menu(Multiattrib *multiattrib,
1378 GdkEventButton *event)
1380 GtkTreePath *path;
1381 GtkWidget *menu;
1382 struct menuitem_t {
1383 gchar *label;
1384 GCallback callback;
1386 struct menuitem_t menuitems[] = {
1387 { N_("Duplicate"), G_CALLBACK (multiattrib_callback_popup_duplicate) },
1388 { N_("Delete"), G_CALLBACK (multiattrib_callback_popup_delete) },
1389 { NULL, NULL } };
1390 struct menuitem_t *tmp;
1392 if (event != NULL &&
1393 gtk_tree_view_get_path_at_pos (multiattrib->treeview,
1394 (gint)event->x,
1395 (gint)event->y,
1396 &path, NULL, NULL, NULL)) {
1397 GtkTreeSelection *selection;
1398 selection = gtk_tree_view_get_selection (multiattrib->treeview);
1399 gtk_tree_selection_unselect_all (selection);
1400 gtk_tree_selection_select_path (selection, path);
1401 gtk_tree_path_free (path);
1404 /* create the context menu */
1405 menu = gtk_menu_new();
1406 for (tmp = menuitems; tmp->label != NULL; tmp++) {
1407 GtkWidget *menuitem;
1408 if (g_strcasecmp (tmp->label, "-") == 0) {
1409 menuitem = gtk_separator_menu_item_new ();
1410 } else {
1411 menuitem = gtk_menu_item_new_with_label (_(tmp->label));
1412 g_signal_connect (menuitem,
1413 "activate",
1414 tmp->callback,
1415 multiattrib);
1417 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1419 gtk_widget_show_all (menu);
1420 /* make menu a popup menu */
1421 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
1422 (event != NULL) ? event->button : 0,
1423 gdk_event_get_time ((GdkEvent*)event));
1428 /*! \brief Function to retrieve Multiattrib's GType identifier.
1430 * \par Function Description
1432 * Function to retrieve Multiattrib's GType identifier.
1433 * Upon first call, this registers Multiattrib in the GType system.
1434 * Subsequently it returns the saved value from its first execution.
1436 * \return the GType identifier associated with Multiattrib.
1438 GType multiattrib_get_type()
1440 static GType multiattrib_type = 0;
1442 if (!multiattrib_type) {
1443 static const GTypeInfo multiattrib_info = {
1444 sizeof(MultiattribClass),
1445 NULL, /* base_init */
1446 NULL, /* base_finalize */
1447 (GClassInitFunc) multiattrib_class_init,
1448 NULL, /* class_finalize */
1449 NULL, /* class_data */
1450 sizeof(Multiattrib),
1451 0, /* n_preallocs */
1452 (GInstanceInitFunc) multiattrib_init,
1455 multiattrib_type = g_type_register_static (GSCHEM_TYPE_DIALOG,
1456 "Multiattrib",
1457 &multiattrib_info, 0);
1460 return multiattrib_type;
1463 /*! \brief GType class initialiser for Multiattrib
1465 * \par Function Description
1467 * GType class initialiser for Multiattrib. We override our parent
1468 * virtual class methods as needed and register our GObject properties.
1470 * \param [in] klass The MultiattribClass we are initialising
1472 static void multiattrib_class_init(MultiattribClass *klass)
1474 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1476 multiattrib_parent_class = g_type_class_peek_parent (klass);
1478 gobject_class->set_property = multiattrib_set_property;
1479 gobject_class->get_property = multiattrib_get_property;
1481 g_object_class_install_property (
1482 gobject_class, PROP_OBJECT,
1483 g_param_spec_pointer ("object",
1486 G_PARAM_READWRITE));
1490 /*! \brief GType instance initialiser for Multiattrib
1492 * \par Function Description
1494 * GType instance initialiser for Multiattrib. Create
1495 * and setup the widgets which make up the dialog.
1497 * \param [in] dialog The Multiattrib we are initialising
1499 static void multiattrib_init(Multiattrib *multiattrib)
1501 GtkWidget *frame, *label, *scrolled_win, *treeview;
1502 GtkWidget *table, *textview, *combo, *optionm, *button;
1503 GtkTreeModel *store;
1504 GtkCellRenderer *renderer;
1505 GtkTreeViewColumn *column;
1506 GtkTreeSelection *selection;
1507 GtkStyle *style;
1509 /* dialog initialization */
1510 g_object_set (G_OBJECT (multiattrib),
1511 /* GtkContainer */
1512 "border-width", 0,
1513 /* GtkWindow */
1514 "title", _("Edit Attributes"),
1515 "default-width", 320,
1516 "default-height", 350,
1517 "window-position", GTK_WIN_POS_MOUSE,
1518 "allow-grow", TRUE,
1519 "allow-shrink", FALSE,
1520 /* GtkDialog */
1521 "has-separator", TRUE,
1522 NULL);
1524 multiattrib->object = NULL;
1526 /* create the attribute list frame */
1527 frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
1528 /* GtkFrame */
1529 "label", _("Attributes"),
1530 NULL));
1531 multiattrib->frame_add = frame;
1532 /* - create the model for the treeview */
1533 store = (GtkTreeModel*)gtk_list_store_new (NUM_COLUMNS,
1534 G_TYPE_POINTER); /* attribute */
1535 /* - create a scrolled window for the treeview */
1536 scrolled_win = GTK_WIDGET (
1537 g_object_new (GTK_TYPE_SCROLLED_WINDOW,
1538 /* GtkContainer */
1539 "border-width", 3,
1540 /* GtkScrolledWindow */
1541 "hscrollbar-policy",
1542 GTK_POLICY_AUTOMATIC,
1543 "vscrollbar-policy",
1544 GTK_POLICY_AUTOMATIC,
1545 "shadow-type",
1546 GTK_SHADOW_ETCHED_IN,
1547 NULL));
1548 /* - create the treeview */
1549 treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
1550 /* GtkTreeView */
1551 "model", store,
1552 "rules-hint", TRUE,
1553 NULL));
1554 g_signal_connect (treeview,
1555 "key-press-event",
1556 G_CALLBACK (multiattrib_callback_key_pressed),
1557 multiattrib);
1558 g_signal_connect (treeview,
1559 "button-press-event",
1560 G_CALLBACK (multiattrib_callback_button_pressed),
1561 multiattrib);
1562 g_signal_connect (treeview,
1563 "popup-menu",
1564 G_CALLBACK (multiattrib_callback_popup_menu),
1565 multiattrib);
1566 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1567 gtk_tree_selection_set_mode (selection,
1568 GTK_SELECTION_SINGLE);
1570 /* - and now the columns of the treeview */
1571 /* - column 1: attribute name */
1572 renderer = GTK_CELL_RENDERER (
1573 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
1574 /* GtkCellRendererText */
1575 "editable", TRUE,
1576 /* unknown in GTK 2.4 */
1577 /* "ellipsize",
1578 * PANGO_ELLIPSIZE_END, */
1579 NULL));
1580 g_signal_connect (renderer,
1581 "edited",
1582 G_CALLBACK (multiattrib_callback_edited_name),
1583 multiattrib);
1584 column = GTK_TREE_VIEW_COLUMN (
1585 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1586 /* GtkTreeViewColumn */
1587 "title", _("Name"),
1588 "min-width", 100,
1589 "resizable", TRUE,
1590 NULL));
1591 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1592 gtk_tree_view_column_set_cell_data_func (column, renderer,
1593 multiattrib_column_set_data_name,
1594 NULL, NULL);
1595 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1596 /* - column 2: attribute value */
1597 renderer = GTK_CELL_RENDERER (
1598 g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT,
1599 /* GtkCellRendererText */
1600 "editable", TRUE,
1601 /* unknown in GTK 2.4 */
1602 /* "ellipsize",
1603 PANGO_ELLIPSIZE_END, */
1604 NULL));
1605 g_signal_connect (renderer,
1606 "edited",
1607 G_CALLBACK (multiattrib_callback_edited_value),
1608 multiattrib);
1609 column = GTK_TREE_VIEW_COLUMN (
1610 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1611 /* GtkTreeViewColumn */
1612 "title", _("Value"),
1613 "min-width", 140,
1614 "resizable", TRUE,
1615 NULL));
1616 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1617 gtk_tree_view_column_set_cell_data_func (column, renderer,
1618 multiattrib_column_set_data_value,
1619 NULL, NULL);
1620 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1621 /* - column 3: visibility */
1622 renderer = GTK_CELL_RENDERER (
1623 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
1624 /* GtkCellRendererToggle */
1625 "activatable", TRUE,
1626 NULL));
1627 g_signal_connect (renderer,
1628 "toggled",
1629 G_CALLBACK (multiattrib_callback_toggled_visible),
1630 multiattrib);
1631 column = GTK_TREE_VIEW_COLUMN (
1632 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1633 /* GtkTreeViewColumn */
1634 "title", _("Vis?"),
1635 NULL));
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_visible,
1639 NULL, NULL);
1640 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1641 /* - column 4: show name */
1642 renderer = GTK_CELL_RENDERER (
1643 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
1644 /* GtkCellRendererToggle */
1645 "activatable", TRUE,
1646 NULL));
1647 g_signal_connect (renderer,
1648 "toggled",
1649 G_CALLBACK (multiattrib_callback_toggled_show_name),
1650 multiattrib);
1651 column = GTK_TREE_VIEW_COLUMN (
1652 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1653 /* GtkTreeViewColumn */
1654 "title", _("N"),
1655 NULL));
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_show_name,
1659 NULL, NULL);
1660 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1661 /* - column 5: show value */
1662 renderer = GTK_CELL_RENDERER (
1663 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
1664 /* GtkCellRendererToggle */
1665 "activatable", TRUE,
1666 NULL));
1667 g_signal_connect (renderer,
1668 "toggled",
1669 G_CALLBACK (multiattrib_callback_toggled_show_value),
1670 multiattrib);
1671 column = GTK_TREE_VIEW_COLUMN (
1672 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1673 /* GtkTreeViewColumn */
1674 "title", _("V"),
1675 NULL));
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_value,
1679 NULL, NULL);
1680 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1682 /* add the treeview to the scrolled window */
1683 gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
1684 /* set treeview of multiattrib */
1685 multiattrib->treeview = GTK_TREE_VIEW (treeview);
1686 /* add the scrolled window to frame */
1687 gtk_container_add (GTK_CONTAINER (frame), scrolled_win);
1688 /* pack the frame */
1689 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), frame,
1690 TRUE, TRUE, 1);
1691 gtk_widget_show_all (frame);
1693 /* create the add/edit frame */
1694 frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
1695 "label", _("Add Attribute"),
1696 NULL));
1697 multiattrib->frame_attributes = frame;
1698 table = GTK_WIDGET (g_object_new (GTK_TYPE_TABLE,
1699 /* GtkTable */
1700 "n-rows", 4,
1701 "n-columns", 2,
1702 "homogeneous", FALSE,
1703 NULL));
1705 /* - the name entry: a GtkComboBoxEntry */
1706 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
1707 /* GtkMisc */
1708 "xalign", 0.0,
1709 "yalign", 0.5,
1710 /* GtkLabel */
1711 "label", _("Name:"),
1712 NULL));
1713 combo = GTK_WIDGET (g_object_new (GTK_TYPE_COMBO,
1714 /* GtkCombo */
1715 "value-in-list", FALSE,
1716 NULL));
1717 multiattrib_init_attrib_names (GTK_COMBO (combo));
1718 multiattrib->combo_name = GTK_COMBO (combo);
1719 gtk_table_attach (GTK_TABLE (table), label,
1720 0, 1, 0, 1, 0, 0, 0, 0);
1721 gtk_table_attach (GTK_TABLE (table), combo,
1722 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 6, 3);
1724 /* - the value entry: a GtkEntry */
1725 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
1726 /* GtkMisc */
1727 "xalign", 0.0,
1728 "yalign", 0.5,
1729 /* GtkLabel */
1730 "label", _("Value:"),
1731 NULL));
1732 scrolled_win = GTK_WIDGET (
1733 g_object_new (GTK_TYPE_SCROLLED_WINDOW,
1734 /* GtkScrolledWindow */
1735 "hscrollbar-policy",
1736 GTK_POLICY_NEVER,
1737 "vscrollbar-policy",
1738 GTK_POLICY_AUTOMATIC,
1739 "shadow-type",
1740 GTK_SHADOW_IN,
1741 NULL));
1742 textview = GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW,
1743 NULL));
1744 g_signal_connect (textview,
1745 "key_press_event",
1746 G_CALLBACK (multiattrib_callback_value_key_pressed),
1747 multiattrib);
1748 g_signal_connect (textview,
1749 "grab-focus",
1750 G_CALLBACK (multiattrib_callback_value_grab_focus),
1751 multiattrib);
1752 /* Save the GTK_STATE_NORMAL color so we can work around GtkTextView's
1753 * stubborn refusal to draw with GTK_STATE_INSENSITIVE later on */
1754 style = gtk_widget_get_style (textview);
1755 multiattrib->value_normal_text_color = style->text[ GTK_STATE_NORMAL ];
1757 gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
1758 multiattrib->textview_value = GTK_TEXT_VIEW (textview);
1759 gtk_table_attach (GTK_TABLE (table), label,
1760 0, 1, 1, 2, 0, 0, 0, 0);
1761 gtk_table_attach (GTK_TABLE (table), scrolled_win,
1762 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 6, 3);
1764 /* - the visible status */
1765 button = GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON,
1766 /* GtkButton */
1767 "label", _("Visible"),
1768 "active", TRUE,
1769 NULL));
1770 multiattrib->button_visible = GTK_CHECK_BUTTON (button);
1771 gtk_table_attach (GTK_TABLE (table), button,
1772 0, 1, 2, 3, GTK_FILL, 0, 3, 0);
1774 /* - the visibility type */
1775 optionm = GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU,
1776 NULL));
1777 multiattrib_init_visible_types (GTK_OPTION_MENU (optionm));
1778 multiattrib->optionmenu_shownv = GTK_OPTION_MENU (optionm);
1779 gtk_table_attach (GTK_TABLE (table), optionm,
1780 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 6, 3);
1781 gtk_widget_show_all (table);
1783 /* create the add button */
1784 button = gtk_button_new_from_stock (GTK_STOCK_ADD);
1785 g_signal_connect (button,
1786 "clicked",
1787 G_CALLBACK (multiattrib_callback_button_add),
1788 multiattrib);
1789 gtk_table_attach (GTK_TABLE (table), button,
1790 2, 3, 0, 3, 0, 0, 6, 3);
1792 /* add the table to the frame */
1793 gtk_container_add (GTK_CONTAINER (frame), table);
1794 /* pack the frame in the dialog */
1795 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), frame,
1796 FALSE, TRUE, 4);
1797 gtk_widget_show_all (frame);
1800 /* now add the close button to the action area */
1801 gtk_dialog_add_button (GTK_DIALOG (multiattrib),
1802 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1807 /*! \brief GObject property setter function
1809 * \par Function Description
1810 * Setter function for Multiattrib's GObject property, "object".
1812 * \param [in] object The GObject whose properties we are setting
1813 * \param [in] property_id The numeric id. under which the property was
1814 * registered with g_object_class_install_property()
1815 * \param [in] value The GValue the property is being set from
1816 * \param [in] pspec A GParamSpec describing the property being set
1819 static void multiattrib_set_property (GObject *object,
1820 guint property_id,
1821 const GValue *value,
1822 GParamSpec *pspec)
1824 Multiattrib *multiattrib = MULTIATTRIB (object);
1826 switch(property_id) {
1827 case PROP_OBJECT:
1828 multiattrib->object = (OBJECT*)g_value_get_pointer (value);
1829 multiattrib_update (multiattrib);
1830 break;
1831 default:
1832 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1837 /*! \brief GObject property getter function
1839 * \par Function Description
1840 * Getter function for Multiattrib's GObject property, "object".
1842 * \param [in] object The GObject whose properties we are getting
1843 * \param [in] property_id The numeric id. under which the property was
1844 * registered with g_object_class_install_property()
1845 * \param [out] value The GValue in which to return the value of the property
1846 * \param [in] pspec A GParamSpec describing the property being got
1848 static void multiattrib_get_property (GObject *object,
1849 guint property_id,
1850 GValue *value,
1851 GParamSpec *pspec)
1853 Multiattrib *multiattrib = MULTIATTRIB (object);
1855 switch(property_id) {
1856 case PROP_OBJECT:
1857 g_value_set_pointer (value, (gpointer)multiattrib->object);
1858 break;
1859 default:
1860 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1866 /*! \brief Update the multiattrib editor dialog's interface
1868 * \par Function Description
1870 * Update the dialog to reflect the attributes of the object. If
1871 * there is no object set, the dialog's controls are set insensitive.
1873 * \param [in] multiattrib The multi-attribute editor dialog.
1875 void multiattrib_update (Multiattrib *multiattrib)
1877 GtkListStore *liststore;
1878 GtkTreeIter iter;
1879 OBJECT **object_attribs, *o_current;
1880 gint i;
1881 gboolean sensitive;
1882 GtkStyle *style;
1884 /* clear the list of attributes */
1885 liststore = (GtkListStore*)gtk_tree_view_get_model (multiattrib->treeview);
1886 gtk_list_store_clear (liststore);
1888 /* Update sensitivities */
1889 sensitive = (multiattrib->object != NULL);
1890 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_attributes), sensitive);
1891 gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_add), sensitive);
1893 /* Work around GtkTextView's stubborn indifference
1894 * to GTK_STATE_INSENSITIVE when rendering its text. */
1895 style = gtk_widget_get_style (GTK_WIDGET (multiattrib->textview_value));
1896 gtk_widget_modify_text (GTK_WIDGET (multiattrib->textview_value),
1897 GTK_STATE_NORMAL,
1898 sensitive ? &multiattrib->value_normal_text_color
1899 : &style->text[GTK_STATE_INSENSITIVE]);
1901 /* If we aren't sensitive, there is nothing more to do */
1902 if (!sensitive)
1903 return;
1905 /* get list of attributes */
1906 object_attribs = o_attrib_return_attribs (multiattrib->object);
1907 /* populate the store with attributes */
1908 if (object_attribs) {
1909 for (i = 0, o_current = object_attribs[i];
1910 o_current != NULL;
1911 i++, o_current = object_attribs[i]) {
1913 /* Don't add invalid attributes to the list */
1914 if (!o_attrib_get_name_value(o_text_get_string(o_current), NULL, NULL))
1915 continue;
1917 gtk_list_store_append (liststore, &iter);
1918 gtk_list_store_set (liststore, &iter,
1919 COLUMN_ATTRIBUTE, o_current,
1920 -1);
1923 /* delete the list of attribute objects */
1924 o_attrib_free_returned (object_attribs);