refdes_renum: warn of possible number clash with non-conforming values
[geda-gaf/whiteaudio.git] / gschem / src / x_compselect.c
blobc94813272ca11fbf4e04935af87aea24b545a59a
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
27 #endif
28 #include <sys/stat.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
36 #include "gschem.h"
37 #include <gdk/gdkkeysyms.h>
39 #ifdef HAVE_LIBDMALLOC
40 #include <dmalloc.h>
41 #endif
43 #include "../include/gschem_dialog.h"
44 #include "../include/x_preview.h"
45 #include "../include/x_compselect.h"
47 /*! \def COMPSELECT_FILTER_INTERVAL
48 * \brief The time interval between request and actual filtering
50 * This constant is the time-lag between user modifications in the
51 * filter entry and the actual evaluation of the filter which
52 * ultimately update the display. It helps reduce the frequency of
53 * evaluation of the filter as user types.
55 * Unit is milliseconds.
57 #define COMPSELECT_FILTER_INTERVAL 200
60 enum compselect_view {
61 VIEW_INUSE=0,
62 VIEW_CLIB
66 /*! \brief Return currently active component-selector view
68 * \par Function Description
69 * This function returns which one of the possible views is active
70 * in the component selector: VIEW_INUSE for the in-use view, or
71 * VIEW_CLIB for the component library view.
73 * \todo FIXME: This function assumes the GtkNotebook pages displaying the
74 * views are in a specific order.
76 * \param [in] compselect The component selection dialog.
77 * \returns The currently active view (from the compselect_view enum).
79 static enum compselect_view
80 compselect_get_view (Compselect *compselect)
82 switch (gtk_notebook_get_current_page (compselect->viewtabs)) {
83 case 0: return VIEW_INUSE; /* In use page */
84 case 1: return VIEW_CLIB; /* Component library page */
85 default:
86 g_critical ("compselect_get_view: Unknown tab position\n");
87 return 0;
92 /*! \brief Process the response returned by the component selection dialog.
93 * \par Function Description
94 * This function handles the response <B>arg1</B> of the component
95 * selection dialog <B>dialog</B>.
97 * Parameter <B>user_data</B> is a pointer on the relevant toplevel
98 * structure.
100 * \param [in] dialog The component selection dialog.
101 * \param [in] arg1 The response ID.
102 * \param [in] user_data A pointer on the GSCHEM_TOPLEVEL environment.
104 static void
105 x_compselect_callback_response (GtkDialog *dialog,
106 gint arg1,
107 gpointer user_data)
109 Compselect *compselect = (Compselect*)dialog;
110 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *)user_data;
111 TOPLEVEL *toplevel = w_current->toplevel;
113 switch (arg1) {
114 case COMPSELECT_RESPONSE_PLACE: {
115 CLibSymbol *symbol = NULL;
116 CompselectBehavior behavior;
118 g_object_get (compselect,
119 "symbol", &symbol,
120 "behavior", &behavior,
121 NULL);
123 w_current->include_complex = w_current->embed_complex = 0;
124 switch (behavior) {
125 case COMPSELECT_BEHAVIOR_REFERENCE:
126 break;
127 case COMPSELECT_BEHAVIOR_EMBED:
128 w_current->embed_complex = 1;
129 break;
130 case COMPSELECT_BEHAVIOR_INCLUDE:
131 w_current->include_complex = 1;
132 break;
133 default:
134 g_assert_not_reached ();
137 if (w_current->event_state == ENDCOMP) {
138 /* Delete the component which was being placed */
139 if (w_current->rubber_visible)
140 o_place_invalidate_rubber (w_current, FALSE);
141 w_current->rubber_visible = 0;
142 s_delete_object_glist (toplevel,
143 toplevel->page_current->place_list);
144 toplevel->page_current->place_list = NULL;
145 } else {
146 /* Cancel whatever other action is currently in progress */
147 o_redraw_cleanstates (w_current);
150 if (symbol == NULL) {
151 /* If there is no symbol selected, switch to SELECT mode */
152 w_current->event_state = SELECT;
153 } else {
154 /* Otherwise set the new symbol to place */
155 o_complex_prepare_place (w_current, symbol);
157 break;
160 case COMPSELECT_RESPONSE_HIDE:
161 /* Response when clicking on the "hide" button */
163 /* If there is no component in the complex place list, set the current one */
164 if (toplevel->page_current->place_list == NULL) {
165 gtk_dialog_response (GTK_DIALOG (compselect),
166 COMPSELECT_RESPONSE_PLACE);
169 /* Hide the component selector */
170 g_object_set (G_OBJECT (compselect), "hidden", TRUE, NULL);
171 break;
173 case GTK_RESPONSE_CLOSE:
174 case GTK_RESPONSE_DELETE_EVENT:
175 g_assert (GTK_WIDGET (dialog) == w_current->cswindow);
176 gtk_widget_destroy (GTK_WIDGET (dialog));
177 w_current->cswindow = NULL;
179 if (w_current->event_state == ENDCOMP) {
181 /* Cancel the place operation currently in progress */
182 o_redraw_cleanstates (w_current);
184 /* return to the default state */
185 i_set_state (w_current, SELECT);
186 i_update_toolbar (w_current);
188 break;
190 default:
191 /* Do nothing, in case there's another handler function which
192 can handle the response ID received. */
193 break;
198 /*! \brief Opens a component selection dialog.
199 * \par Function Description
200 * This function opens the component chooser dialog for
201 * <B>toplevel</B> if it is not already. In this last case, it only
202 * raises the dialog.
204 * \param [in] w_current The GSCHEM_TOPLEVEL environment.
206 void
207 x_compselect_open (GSCHEM_TOPLEVEL *w_current)
209 GtkWidget *current_tab, *entry_filter;
210 GtkNotebook *compselect_notebook;
212 if (w_current->cswindow == NULL) {
213 w_current->cswindow = GTK_WIDGET (
214 g_object_new (TYPE_COMPSELECT,
215 /* GschemDialog */
216 "settings-name", "compselect",
217 "gschem-toplevel", w_current,
218 NULL));
220 g_signal_connect (w_current->cswindow,
221 "response",
222 G_CALLBACK (x_compselect_callback_response),
223 w_current);
225 gtk_window_set_transient_for (GTK_WINDOW (w_current->cswindow),
226 GTK_WINDOW (w_current->main_window));
228 gtk_widget_show (w_current->cswindow);
230 } else {
231 gtk_window_present (GTK_WINDOW (w_current->cswindow));
233 gtk_editable_select_region (GTK_EDITABLE (COMPSELECT (w_current->cswindow)->entry_filter), 0, -1);
235 /* Set the focus to the filter entry only if it is in the current
236 displayed tab */
237 compselect_notebook = GTK_NOTEBOOK (COMPSELECT (w_current->cswindow)->viewtabs);
238 current_tab = gtk_notebook_get_nth_page (compselect_notebook,
239 gtk_notebook_get_current_page (compselect_notebook));
240 entry_filter = GTK_WIDGET (COMPSELECT (w_current->cswindow)->entry_filter);
241 if (gtk_widget_is_ancestor (entry_filter, current_tab)) {
242 gtk_widget_grab_focus (entry_filter);
246 /*! \brief Closes the component selection dialog.
247 * \par Function Description
248 * This function closes the component chooser dialog associated with
249 * <B>toplevel</B>.
251 * \param [in] w_current The GSCHEM_TOPLEVEL environment.
253 void
254 x_compselect_close (GSCHEM_TOPLEVEL *w_current)
256 if (w_current->cswindow) {
257 g_assert (IS_COMPSELECT (w_current->cswindow));
258 gtk_widget_destroy (w_current->cswindow);
259 w_current->cswindow = NULL;
264 void
265 x_compselect_deselect (GSCHEM_TOPLEVEL *w_current)
267 Compselect *compselect = COMPSELECT (w_current->cswindow);
269 if (compselect == NULL)
270 return;
272 switch (compselect_get_view (compselect)) {
273 case VIEW_INUSE:
274 gtk_tree_selection_unselect_all (
275 gtk_tree_view_get_selection (compselect->inusetreeview));
276 break;
277 case VIEW_CLIB:
278 gtk_tree_selection_unselect_all (
279 gtk_tree_view_get_selection (compselect->libtreeview));
280 break;
281 default:
282 g_assert_not_reached ();
287 enum {
288 PROP_SYMBOL=1,
289 PROP_BEHAVIOR,
290 PROP_HIDDEN
293 static GObjectClass *compselect_parent_class = NULL;
296 static void compselect_class_init (CompselectClass *class);
297 static GObject *compselect_constructor (GType type,
298 guint n_construct_properties,
299 GObjectConstructParam *construct_params);
300 static void compselect_finalize (GObject *object);
301 static void compselect_set_property (GObject *object,
302 guint property_id,
303 const GValue *value,
304 GParamSpec *pspec);
305 static void compselect_get_property (GObject *object,
306 guint property_id,
307 GValue *value,
308 GParamSpec *pspec);
312 /*! \brief Sets data for a particular cell of the in use treeview.
313 * \par Function Description
314 * This function determines what data is to be displayed in the
315 * "in use" symbol selection view.
317 * The model is a list of symbols. s_clib_symbol_get_name() is called
318 * to get the text to display.
320 static void
321 inuse_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
322 GtkCellRenderer *cell,
323 GtkTreeModel *tree_model,
324 GtkTreeIter *iter,
325 gpointer data)
327 CLibSymbol *symbol;
329 gtk_tree_model_get (tree_model, iter, 0, &symbol, -1);
330 g_object_set ((GObject*)cell, "text", s_clib_symbol_get_name (symbol), NULL);
333 /*! \brief Sets data for a particular cell of the library treeview.
334 * \par Function Description
335 * This function determines what data is to be displayed in the
336 * selection selection view.
338 * The top level of the model contains sources, and the next symbols.
339 * s_clib_source_get_name() or s_clib_symbol_get_name() as
340 * appropriate is called to get the text to display.
342 static void
343 lib_treeview_set_cell_data (GtkTreeViewColumn *tree_column,
344 GtkCellRenderer *cell,
345 GtkTreeModel *tree_model,
346 GtkTreeIter *iter,
347 gpointer data)
349 GtkTreeIter parent;
350 CLibSource *source;
351 CLibSymbol *symbol;
352 const char *text;
354 if (!gtk_tree_model_iter_parent (tree_model, &parent, iter)) {
355 /* If top level, must be a source. */
356 gtk_tree_model_get (tree_model, iter, 0, &source, -1);
357 text = s_clib_source_get_name (source);
358 } else {
359 /* Otherwise, must be a symbol */
360 gtk_tree_model_get (tree_model, iter, 0, &symbol, -1);
361 text = s_clib_symbol_get_name (symbol);
363 g_object_set ((GObject*)cell, "text", text, NULL);
366 /*! \brief Determines visibility of items of the library treeview.
367 * \par Function Description
368 * This is the function used to filter entries of the component
369 * selection tree.
371 * \param [in] model The current selection in the treeview.
372 * \param [in] iter An iterator on a component or folder in the tree.
373 * \param [in] data The component selection dialog.
374 * \returns TRUE if item should be visible, FALSE otherwise.
376 static gboolean
377 lib_model_filter_visible_func (GtkTreeModel *model,
378 GtkTreeIter *iter,
379 gpointer data)
381 Compselect *compselect = (Compselect*)data;
382 CLibSymbol *sym;
383 const gchar *compname;
384 gchar *compname_upper, *text_upper, *pattern;
385 const gchar *text;
386 gboolean ret;
388 g_assert (IS_COMPSELECT (data));
390 text = gtk_entry_get_text (compselect->entry_filter);
391 if (g_ascii_strcasecmp (text, "") == 0) {
392 return TRUE;
395 /* If this is a source, only display it if it has children that
396 * match */
397 if (gtk_tree_model_iter_has_child (model, iter)) {
398 GtkTreeIter iter2;
400 gtk_tree_model_iter_children (model, &iter2, iter);
401 ret = FALSE;
402 do {
403 if (lib_model_filter_visible_func (model, &iter2, data)) {
404 ret = TRUE;
405 break;
407 } while (gtk_tree_model_iter_next (model, &iter2));
408 } else {
409 gtk_tree_model_get (model, iter,
410 0, &sym,
411 -1);
412 compname = s_clib_symbol_get_name (sym);
413 /* Do a case insensitive comparison, converting the strings
414 to uppercase */
415 compname_upper = g_ascii_strup (compname, -1);
416 text_upper = g_ascii_strup (text, -1);
417 pattern = g_strconcat ("*", text_upper, "*", NULL);
418 ret = g_pattern_match_simple (pattern, compname_upper);
419 g_free (compname_upper);
420 g_free (text_upper);
421 g_free (pattern);
424 return ret;
428 /*! \brief Handles activation (e.g. double-clicking) of a component row
429 * \par Function Description
430 * Component row activated handler:
431 * As a convenince to the user, expand / contract any node with children.
433 * \param [in] tree_view The component treeview.
434 * \param [in] path The GtkTreePath to the activated row.
435 * \param [in] column The GtkTreeViewColumn in which the activation occurred.
436 * \param [in] user_data The component selection dialog.
438 static void
439 tree_row_activated (GtkTreeView *tree_view,
440 GtkTreePath *path,
441 GtkTreeViewColumn *column,
442 gpointer user_data)
444 GtkTreeModel *model;
445 GtkTreeIter iter;
446 Compselect *compselect = (Compselect*)user_data;
448 model = gtk_tree_view_get_model (tree_view);
449 gtk_tree_model_get_iter (model, &iter, path);
451 if (!gtk_tree_model_iter_has_child (model, &iter)) {
452 gtk_dialog_response (GTK_DIALOG (compselect),
453 COMPSELECT_RESPONSE_HIDE);
454 return;
457 if (gtk_tree_view_row_expanded (tree_view, path))
458 gtk_tree_view_collapse_row (tree_view, path);
459 else
460 gtk_tree_view_expand_row (tree_view, path, FALSE);
463 /*! \brief GCompareFunc to sort an text object list by the object strings
465 static gint
466 sort_object_text (OBJECT *a, OBJECT *b)
468 return strcmp (a->text->string, b->text->string);
471 enum {
472 ATTRIBUTE_COLUMN_NAME = 0,
473 ATTRIBUTE_COLUMN_VALUE,
474 NUM_ATTRIBUTE_COLUMNS
477 /*! \brief Update the model of the attributes treeview
478 * \par Function Description
479 * This function takes the toplevel attributes from the preview widget and
480 * puts them into the model of the <b>attrtreeview</b> widget.
481 * \param [in] compselect The dialog compselect
482 * \param [in] preview_toplevel The toplevel of the preview widget
484 void
485 update_attributes_model (Compselect *compselect, TOPLEVEL *preview_toplevel)
487 GtkListStore *model;
488 GtkTreeIter iter;
489 GtkTreeViewColumn *column;
490 GList *listiter, *o_iter, *o_attrlist, *filter_list;
491 gchar *name, *value;
492 OBJECT *o_current;
494 model = (GtkListStore*) gtk_tree_view_get_model (compselect->attrtreeview);
495 gtk_list_store_clear (model);
497 /* Invalidate the column width for the attribute value column, so
498 * the column is re-sized based on the new data being shown. Symbols
499 * with long values are common, and we don't want having viewed those
500 * forcing a h-scroll-bar on symbols with short valued attributes.
502 * We might also consider invalidating the attribute name columns,
503 * however that gives an inconsistent column division when swithing
504 * between symbols, which doesn't look nice. For now, assume that
505 * the name column can keep the max width gained whilst previewing.
507 column = gtk_tree_view_get_column (compselect->attrtreeview,
508 ATTRIBUTE_COLUMN_VALUE);
509 gtk_tree_view_column_queue_resize (column);
511 if (preview_toplevel->page_current == NULL) {
512 return;
515 o_attrlist = o_attrib_find_floating_attribs (
516 s_page_objects (preview_toplevel->page_current));
518 filter_list = GSCHEM_DIALOG (compselect)->w_current->component_select_attrlist;
520 if (filter_list != NULL
521 && strcmp (filter_list->data, "*") == 0) {
522 /* display all attributes in alphabetical order */
523 o_attrlist = g_list_sort (o_attrlist, (GCompareFunc) sort_object_text);
524 for (o_iter = o_attrlist; o_iter != NULL; o_iter = g_list_next (o_iter)) {
525 o_current = o_iter->data;
526 o_attrib_get_name_value (o_current, &name, &value);
527 gtk_list_store_append (model, &iter);
528 gtk_list_store_set (model, &iter, 0, name, 1, value, -1);
529 g_free (name);
530 g_free (value);
532 } else {
533 /* display only attribute that are in the filter list */
534 for (listiter = filter_list;
535 listiter != NULL;
536 listiter = g_list_next (listiter)) {
537 for (o_iter = o_attrlist; o_iter != NULL; o_iter = g_list_next (o_iter)) {
538 o_current = o_iter->data;
539 if (o_attrib_get_name_value (o_current, &name, &value)) {
540 if (strcmp (name, listiter->data) == 0) {
541 gtk_list_store_append (model, &iter);
542 gtk_list_store_set (model, &iter, 0, name, 1, value, -1);
544 g_free (name);
545 g_free (value);
550 g_list_free (o_attrlist);
553 /*! \brief Handles changes in the treeview selection.
554 * \par Function Description
555 * This is the callback function that is called every time the user
556 * select a row in either component treeview of the dialog.
558 * If the selection is not a selection of a component (a directory
559 * name), it does nothing. Otherwise it retrieves the #CLibSymbol
560 * from the model.
562 * It then emits the dialog's <B>apply</B> signal to let its parent
563 * know that a component has been selected.
565 * \param [in] selection The current selection in the treeview.
566 * \param [in] user_data The component selection dialog.
568 static void
569 compselect_callback_tree_selection_changed (GtkTreeSelection *selection,
570 gpointer user_data)
572 GtkTreeView *view;
573 GtkTreeModel *model;
574 GtkTreeIter iter, parent;
575 Compselect *compselect = (Compselect*)user_data;
576 const CLibSymbol *sym = NULL;
577 gchar *buffer = NULL;
579 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
581 view = gtk_tree_selection_get_tree_view (selection);
582 if (view == compselect->inusetreeview ||
583 /* No special handling required */
584 (view == compselect->libtreeview &&
585 gtk_tree_model_iter_parent (model, &parent, &iter))) {
586 /* Tree view needs to check that we're at a leaf node */
588 gtk_tree_model_get (model, &iter, 0, &sym, -1);
589 buffer = s_clib_symbol_get_data (sym);
593 /* update the preview with new symbol data */
594 g_object_set (compselect->preview,
595 "buffer", buffer,
596 "active", (buffer != NULL),
597 NULL);
599 /* update the attributes with the toplevel of the preview widget*/
600 if (compselect->attrtreeview != NULL)
601 update_attributes_model (compselect,
602 compselect->preview->preview_w_current->toplevel);
604 /* signal a component has been selected to parent of dialog */
605 g_signal_emit_by_name (compselect,
606 "response",
607 COMPSELECT_RESPONSE_PLACE,
608 NULL);
610 g_free (buffer);
613 /*! \brief Requests re-evaluation of the filter.
614 * \par Function Description
615 * This is the timeout function for the filtering of component in the
616 * tree of the dialog.
618 * The timeout this callback is attached to is removed after the
619 * function.
621 * \param [in] data The component selection dialog.
622 * \returns FALSE to remove the timeout.
624 static gboolean
625 compselect_filter_timeout (gpointer data)
627 Compselect *compselect = COMPSELECT (data);
628 GtkTreeModel *model;
630 /* resets the source id in compselect */
631 compselect->filter_timeout = 0;
633 model = gtk_tree_view_get_model (compselect->libtreeview);
635 if (model != NULL) {
636 const gchar *text = gtk_entry_get_text (compselect->entry_filter);
637 gtk_tree_model_filter_refilter ((GtkTreeModelFilter*)model);
638 if (strcmp (text, "") != 0) {
639 /* filter text not-empty */
640 gtk_tree_view_expand_all (compselect->libtreeview);
641 } else {
642 /* filter text is empty, collapse expanded tree */
643 gtk_tree_view_collapse_all (compselect->libtreeview);
647 /* return FALSE to remove the source */
648 return FALSE;
651 /*! \brief Callback function for the changed signal of the filter entry.
652 * \par Function Description
653 * This function monitors changes in the entry filter of the dialog.
655 * It specifically manages the sensitivity of the clear button of the
656 * entry depending on its contents. It also requests an update of the
657 * component list by re-evaluating filter at every changes.
659 * \param [in] editable The filter text entry.
660 * \param [in] user_data The component selection dialog.
662 static void
663 compselect_callback_filter_entry_changed (GtkEditable *editable,
664 gpointer user_data)
666 Compselect *compselect = COMPSELECT (user_data);
667 GtkWidget *button;
668 gboolean sensitive;
670 /* turns button off if filter entry is empty */
671 /* turns it on otherwise */
672 button = GTK_WIDGET (compselect->button_clear);
673 sensitive =
674 (g_ascii_strcasecmp (gtk_entry_get_text (compselect->entry_filter),
675 "") != 0);
676 if (GTK_WIDGET_IS_SENSITIVE (button) != sensitive) {
677 gtk_widget_set_sensitive (button, sensitive);
680 /* Cancel any pending update of the component list filter */
681 if (compselect->filter_timeout != 0)
682 g_source_remove (compselect->filter_timeout);
684 /* Schedule an update of the component list filter in
685 * COMPSELECT_FILTER_INTERVAL milliseconds */
686 compselect->filter_timeout = g_timeout_add (COMPSELECT_FILTER_INTERVAL,
687 compselect_filter_timeout,
688 compselect);
692 /*! \brief Handles a click on the clear button.
693 * \par Function Description
694 * This is the callback function called every time the user press the
695 * clear button associated with the filter.
697 * It resets the filter entry, indirectly causing re-evaluation
698 * of the filter on the list of symbols to update the display.
700 * \param [in] button The clear button
701 * \param [in] user_data The component selection dialog.
703 static void
704 compselect_callback_filter_button_clicked (GtkButton *button,
705 gpointer user_data)
707 Compselect *compselect = COMPSELECT (user_data);
709 /* clears text in text entry for filter */
710 gtk_entry_set_text (compselect->entry_filter, "");
714 /*! \brief Handles changes of behavior.
715 * \par Function Description
716 * This function is called every time the value of the option menu
717 * for behaviors is modified.
719 * It emits the dialog's <B>apply</B> signal to let the parent know
720 * that the requested behavior for the next adding of a component has
721 * been changed.
723 * \param [in] optionmenu The behavior option menu.
724 * \param [in] user_data The component selection dialog.
726 static void
727 compselect_callback_behavior_changed (GtkOptionMenu *optionmenu,
728 gpointer user_data)
730 Compselect *compselect = (Compselect*)user_data;
732 g_signal_emit_by_name (compselect,
733 "response",
734 COMPSELECT_RESPONSE_PLACE,
735 NULL);
738 /* \brief Create the tree model for the "In Use" view.
739 * \par Function Description
740 * Creates a straightforward list of symbols which are currently in
741 * use, using s_toplevel_get_symbols().
743 static GtkTreeModel*
744 create_inuse_tree_model (Compselect *compselect)
746 GtkListStore *store;
747 GList *symhead, *symlist;
748 GtkTreeIter iter;
750 store = (GtkListStore *) gtk_list_store_new (1, G_TYPE_POINTER);
752 symhead = s_toplevel_get_symbols (GSCHEM_DIALOG (compselect)->w_current->toplevel);
754 for (symlist = symhead;
755 symlist != NULL;
756 symlist = g_list_next (symlist)) {
758 gtk_list_store_append (store, &iter);
760 gtk_list_store_set (store, &iter,
761 0, symlist->data,
762 -1);
765 g_list_free (symhead);
767 return (GtkTreeModel*)store;
770 /* \brief Create the tree model for the "Library" view.
771 * \par Function Description
772 * Creates a tree where the branches are the available component
773 * sources and the leaves are the symbols.
775 static GtkTreeModel*
776 create_lib_tree_model (Compselect *compselect)
778 GtkTreeStore *store;
779 GList *srchead, *srclist;
780 GList *symhead, *symlist;
782 store = (GtkTreeStore*)gtk_tree_store_new (1, G_TYPE_POINTER);
784 /* populate component store */
785 srchead = s_clib_get_sources (GSCHEM_DIALOG (compselect)->w_current->sort_component_library != 0);
786 for (srclist = srchead;
787 srclist != NULL;
788 srclist = g_list_next (srclist)) {
790 GtkTreeIter iter, iter2;
792 gtk_tree_store_append (store, &iter, NULL);
793 gtk_tree_store_set (store, &iter,
794 0, srclist->data,
795 -1);
797 symhead = s_clib_source_get_symbols ((CLibSource *)srclist->data);
798 for (symlist = symhead;
799 symlist != NULL;
800 symlist = g_list_next (symlist)) {
802 gtk_tree_store_append (store, &iter2, &iter);
803 gtk_tree_store_set (store, &iter2,
804 0, symlist->data,
805 -1);
808 g_list_free (symhead);
810 g_list_free (srchead);
812 return (GtkTreeModel*)store;
815 /* \brief On-demand refresh of the component library.
816 * \par Function Description
817 * Requests a rescan of the component library in order to pick up any
818 * new signals, and then updates the component selector.
820 static void
821 compselect_callback_refresh_library (GtkButton *button, gpointer user_data)
823 Compselect *compselect = COMPSELECT (user_data);
824 GtkTreeModel *model;
825 GtkTreeSelection *selection;
827 /* Rescan the libraries for symbols */
828 s_clib_refresh ();
830 /* Refresh the "Library" view */
831 model = (GtkTreeModel *)
832 g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
833 "child-model", create_lib_tree_model (compselect),
834 "virtual-root", NULL,
835 NULL);
837 gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter*)model,
838 lib_model_filter_visible_func,
839 compselect,
840 NULL);
842 /* Block handling selection updated for duration of model changes */
843 selection = gtk_tree_view_get_selection (compselect->libtreeview);
844 g_signal_handlers_block_by_func (selection,
845 compselect_callback_tree_selection_changed,
846 compselect);
848 /* Update the view model with signals blocked */
849 gtk_tree_view_set_model (compselect->libtreeview, model);
851 /* Refresh the "In Use" view */
852 model = create_inuse_tree_model (compselect);
854 /* Here we can update the model without blocking signals
855 * as this is the second (final) tree view we are updating */
856 gtk_tree_view_set_model (compselect->inusetreeview, model);
858 /* Unblock & fire handler for libtreeview selection */
859 g_signal_handlers_unblock_by_func (selection,
860 compselect_callback_tree_selection_changed,
861 compselect);
864 /*! \brief Creates the treeview for the "In Use" view. */
865 static GtkWidget*
866 create_inuse_treeview (Compselect *compselect)
868 GtkWidget *scrolled_win, *treeview, *vbox, *hbox, *button;
869 GtkTreeModel *model;
870 GtkTreeSelection *selection;
871 GtkCellRenderer *renderer;
872 GtkTreeViewColumn *column;
874 model = create_inuse_tree_model (compselect);
876 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
877 /* GtkContainer */
878 "border-width", 5,
879 /* GtkBox */
880 "homogeneous", FALSE,
881 "spacing", 5,
882 NULL));
884 /* Create a scrolled window to accomodate the treeview */
885 scrolled_win = GTK_WIDGET (
886 g_object_new (GTK_TYPE_SCROLLED_WINDOW,
887 /* GtkContainer */
888 "border-width", 5,
889 /* GtkScrolledWindow */
890 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
891 "vscrollbar-policy", GTK_POLICY_ALWAYS,
892 "shadow-type", GTK_SHADOW_ETCHED_IN,
893 NULL));
895 /* Create the treeview */
896 treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
897 /* GtkTreeView */
898 "model", model,
899 "rules-hint", TRUE,
900 "headers-visible", FALSE,
901 NULL));
903 /* Connect callback to selection */
904 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
905 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
906 g_signal_connect (selection,
907 "changed",
908 G_CALLBACK (compselect_callback_tree_selection_changed),
909 compselect);
911 /* Insert a column for symbol name */
912 renderer = GTK_CELL_RENDERER (
913 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
914 /* GtkCellRendererText */
915 "editable", FALSE,
916 NULL));
917 column = GTK_TREE_VIEW_COLUMN (
918 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
919 /* GtkTreeViewColumn */
920 "title", _("Components"),
921 NULL));
922 gtk_tree_view_column_pack_start (column, renderer, TRUE);
923 gtk_tree_view_column_set_cell_data_func (column, renderer,
924 inuse_treeview_set_cell_data,
925 NULL, NULL);
926 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
928 /* Add the treeview to the scrolled window */
929 gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
930 /* set the inuse treeview of compselect */
931 compselect->inusetreeview = GTK_TREE_VIEW (treeview);
933 /* add the scrolled window for directories to the vertical box */
934 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win,
935 TRUE, TRUE, 0);
937 /* -- refresh button area -- */
938 hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
939 /* GtkBox */
940 "homogeneous", FALSE,
941 "spacing", 3,
942 NULL));
943 /* create the refresh button */
944 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
945 /* GtkWidget */
946 "sensitive", TRUE,
947 /* GtkButton */
948 "relief", GTK_RELIEF_NONE,
949 NULL));
950 gtk_container_add (GTK_CONTAINER (button),
951 gtk_image_new_from_stock (GTK_STOCK_REFRESH,
952 GTK_ICON_SIZE_SMALL_TOOLBAR));
953 /* add the refresh button to the horizontal box at the end */
954 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
955 g_signal_connect (button,
956 "clicked",
957 G_CALLBACK (compselect_callback_refresh_library),
958 compselect);
960 /* add the refresh button area to the vertical box */
961 gtk_box_pack_start (GTK_BOX (vbox), hbox,
962 FALSE, FALSE, 0);
964 return vbox;
967 /*! \brief Creates the treeview for the "Library" view */
968 static GtkWidget *
969 create_lib_treeview (Compselect *compselect)
971 GtkWidget *libtreeview, *vbox, *scrolled_win, *label,
972 *hbox, *entry, *button;
973 GtkTreeModel *child_model, *model;
974 GtkTreeSelection *selection;
975 GtkCellRenderer *renderer;
976 GtkTreeViewColumn *column;
978 /* -- library selection view -- */
980 /* vertical box for component selection and search entry */
981 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
982 /* GtkContainer */
983 "border-width", 5,
984 /* GtkBox */
985 "homogeneous", FALSE,
986 "spacing", 5,
987 NULL));
989 child_model = create_lib_tree_model (compselect);
990 model = (GtkTreeModel*)g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
991 "child-model", child_model,
992 "virtual-root", NULL,
993 NULL);
995 scrolled_win = GTK_WIDGET (
996 g_object_new (GTK_TYPE_SCROLLED_WINDOW,
997 /* GtkContainer */
998 "border-width", 5,
999 /* GtkScrolledWindow */
1000 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
1001 "vscrollbar-policy", GTK_POLICY_ALWAYS,
1002 "shadow-type", GTK_SHADOW_ETCHED_IN,
1003 NULL));
1004 /* create the treeview */
1005 libtreeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
1006 /* GtkTreeView */
1007 "model", model,
1008 "rules-hint", TRUE,
1009 "headers-visible", FALSE,
1010 NULL));
1012 g_signal_connect (libtreeview,
1013 "row-activated",
1014 G_CALLBACK (tree_row_activated),
1015 compselect);
1017 /* connect callback to selection */
1018 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (libtreeview));
1019 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1020 g_signal_connect (selection,
1021 "changed",
1022 G_CALLBACK (compselect_callback_tree_selection_changed),
1023 compselect);
1025 /* insert a column to treeview for library/symbol name */
1026 renderer = GTK_CELL_RENDERER (
1027 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
1028 /* GtkCellRendererText */
1029 "editable", FALSE,
1030 NULL));
1031 column = GTK_TREE_VIEW_COLUMN (
1032 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1033 /* GtkTreeViewColumn */
1034 "title", _("Components"),
1035 NULL));
1036 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1037 gtk_tree_view_column_set_cell_data_func (column, renderer,
1038 lib_treeview_set_cell_data,
1039 NULL, NULL);
1040 gtk_tree_view_append_column (GTK_TREE_VIEW (libtreeview), column);
1042 /* add the treeview to the scrolled window */
1043 gtk_container_add (GTK_CONTAINER (scrolled_win), libtreeview);
1044 /* set directory/component treeview of compselect */
1045 compselect->libtreeview = GTK_TREE_VIEW (libtreeview);
1047 /* add the scrolled window for directories to the vertical box */
1048 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win,
1049 TRUE, TRUE, 0);
1052 /* -- filter area -- */
1053 hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
1054 /* GtkBox */
1055 "homogeneous", FALSE,
1056 "spacing", 3,
1057 NULL));
1059 /* create the entry label */
1060 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
1061 /* GtkMisc */
1062 "xalign", 0.0,
1063 /* GtkLabel */
1064 "label", _("Filter:"),
1065 NULL));
1066 /* add the search label to the filter area */
1067 gtk_box_pack_start (GTK_BOX (hbox), label,
1068 FALSE, FALSE, 0);
1070 /* create the text entry for filter in components */
1071 entry = GTK_WIDGET (g_object_new (GTK_TYPE_ENTRY,
1072 /* GtkEntry */
1073 "text", "",
1074 NULL));
1075 g_signal_connect (entry,
1076 "changed",
1077 G_CALLBACK (compselect_callback_filter_entry_changed),
1078 compselect);
1080 /* now that that we have an entry, set the filter func of model */
1081 gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter*)model,
1082 lib_model_filter_visible_func,
1083 compselect,
1084 NULL);
1086 /* add the filter entry to the filter area */
1087 gtk_box_pack_start (GTK_BOX (hbox), entry,
1088 TRUE, TRUE, 0);
1089 /* set filter entry of compselect */
1090 compselect->entry_filter = GTK_ENTRY (entry);
1091 /* and init the event source for component filter */
1092 compselect->filter_timeout = 0;
1094 /* create the erase button for filter entry */
1095 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
1096 /* GtkWidget */
1097 "sensitive", FALSE,
1098 /* GtkButton */
1099 "relief", GTK_RELIEF_NONE,
1100 NULL));
1102 gtk_container_add (GTK_CONTAINER (button),
1103 gtk_image_new_from_stock (GTK_STOCK_CLEAR,
1104 GTK_ICON_SIZE_SMALL_TOOLBAR));
1105 g_signal_connect (button,
1106 "clicked",
1107 G_CALLBACK (compselect_callback_filter_button_clicked),
1108 compselect);
1109 /* add the clear button to the filter area */
1110 gtk_box_pack_start (GTK_BOX (hbox), button,
1111 FALSE, FALSE, 0);
1112 /* set clear button of compselect */
1113 compselect->button_clear = GTK_BUTTON (button);
1115 /* create the refresh button */
1116 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
1117 /* GtkWidget */
1118 "sensitive", TRUE,
1119 /* GtkButton */
1120 "relief", GTK_RELIEF_NONE,
1121 NULL));
1122 gtk_container_add (GTK_CONTAINER (button),
1123 gtk_image_new_from_stock (GTK_STOCK_REFRESH,
1124 GTK_ICON_SIZE_SMALL_TOOLBAR));
1125 /* add the refresh button to the filter area */
1126 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1127 g_signal_connect (button,
1128 "clicked",
1129 G_CALLBACK (compselect_callback_refresh_library),
1130 compselect);
1132 /* add the filter area to the vertical box */
1133 gtk_box_pack_start (GTK_BOX (vbox), hbox,
1134 FALSE, FALSE, 0);
1136 compselect->libtreeview = GTK_TREE_VIEW (libtreeview);
1138 return vbox;
1141 /*! \brief Creates the treeview widget for the attributes
1143 static GtkWidget*
1144 create_attributes_treeview (Compselect *compselect)
1146 GtkWidget *attrtreeview, *scrolled_win;
1147 GtkListStore *model;
1148 GtkCellRenderer *renderer;
1149 GtkTreeViewColumn *column;
1151 model = gtk_list_store_new (NUM_ATTRIBUTE_COLUMNS,
1152 G_TYPE_STRING, G_TYPE_STRING);
1154 attrtreeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
1155 /* GtkTreeView */
1156 "model", model,
1157 "headers-visible", FALSE,
1158 "rules-hint", TRUE,
1159 NULL));
1161 /* two columns for name and value of the attributes */
1162 renderer = GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
1163 "editable", FALSE,
1164 NULL));
1166 column = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1167 "title", _("Name"),
1168 "resizable", TRUE,
1169 NULL));
1170 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1171 gtk_tree_view_column_add_attribute (column, renderer, "text",
1172 ATTRIBUTE_COLUMN_NAME);
1173 gtk_tree_view_append_column (GTK_TREE_VIEW (attrtreeview), column);
1175 column = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
1176 "title", _("Value"),
1177 "resizable", TRUE,
1178 NULL));
1179 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1180 gtk_tree_view_column_add_attribute (column, renderer, "text",
1181 ATTRIBUTE_COLUMN_VALUE);
1182 gtk_tree_view_append_column (GTK_TREE_VIEW (attrtreeview), column);
1184 scrolled_win = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
1185 /* GtkContainer */
1186 "border-width", 5,
1187 /* GtkScrolledWindow */
1188 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
1189 "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
1190 "shadow-type", GTK_SHADOW_ETCHED_IN,
1191 NULL));
1193 gtk_container_add (GTK_CONTAINER (scrolled_win), attrtreeview);
1195 compselect->attrtreeview = GTK_TREE_VIEW (attrtreeview);
1197 return scrolled_win;
1200 /*! \brief Create the combo box for behaviors.
1201 * \par Function Description
1202 * This function creates and returns a <B>GtkComboBox</B> for
1203 * selecting the behavior when a component is added to the sheet.
1205 static GtkWidget*
1206 create_behaviors_combo_box (void)
1208 GtkWidget *combobox;
1210 combobox = gtk_combo_box_new_text ();
1212 /* Note: order of items in menu is important */
1213 /* COMPSEL_BEHAVIOR_REFERENCE */
1214 gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
1215 _("Default behavior - reference component"));
1216 /* COMPSEL_BEHAVIOR_EMBED */
1217 gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
1218 _("Embed component in schematic"));
1219 /* COMPSEL_BEHAVIOR_INCLUDE */
1220 gtk_combo_box_append_text (GTK_COMBO_BOX (combobox),
1221 _("Include component as individual objects"));
1223 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
1225 return combobox;
1228 GType
1229 compselect_get_type ()
1231 static GType compselect_type = 0;
1233 if (!compselect_type) {
1234 static const GTypeInfo compselect_info = {
1235 sizeof (CompselectClass),
1236 NULL, /* base_init */
1237 NULL, /* base_finalize */
1238 (GClassInitFunc) compselect_class_init,
1239 NULL, /* class_finalize */
1240 NULL, /* class_data */
1241 sizeof (Compselect),
1242 0, /* n_preallocs */
1243 NULL /* instance_init */
1246 compselect_type = g_type_register_static (GSCHEM_TYPE_DIALOG,
1247 "Compselect",
1248 &compselect_info, 0);
1251 return compselect_type;
1255 /*! \brief GschemDialog "geometry_save" class method handler
1257 * \par Function Description
1258 * Chain up to our parent's method to save the dialog's size and
1259 * position, then save the dialog's current internal geometry.
1261 * \param [in] dialog The GschemDialog to save the geometry of.
1262 * \param [in] key_file The GKeyFile to save the geometry data to.
1263 * \param [in] group_name The group name in the key file to store the data under.
1265 static void
1266 compselect_geometry_save (GschemDialog *dialog, GKeyFile *key_file, gchar *group_name)
1268 int position;
1270 /* Call the parent's geometry_save method */
1271 GSCHEM_DIALOG_CLASS (compselect_parent_class)->
1272 geometry_save (dialog, key_file, group_name);
1274 position = gtk_paned_get_position (GTK_PANED (COMPSELECT (dialog)->hpaned));
1275 g_key_file_set_integer (key_file, group_name, "hpaned", position);
1277 position = gtk_paned_get_position (GTK_PANED (COMPSELECT (dialog)->vpaned));
1278 g_key_file_set_integer (key_file, group_name, "vpaned", position);
1280 position = gtk_notebook_get_current_page (COMPSELECT (dialog)->viewtabs);
1281 g_key_file_set_integer (key_file, group_name, "source-tab", position);
1285 /*! \brief GschemDialog "geometry_restore" class method handler
1287 * \par Function Description
1288 * Chain up to our parent's method to restore the dialog's size and
1289 * position, then restore the dialog's current internal geometry.
1291 * \param [in] dialog The GschemDialog to restore the geometry of.
1292 * \param [in] key_file The GKeyFile to save the geometry data to.
1293 * \param [in] group_name The group name in the key file to store the data under.
1295 static void
1296 compselect_geometry_restore (GschemDialog *dialog, GKeyFile *key_file, gchar *group_name)
1298 int position;
1300 /* Call the parent's geometry_restore method */
1301 GSCHEM_DIALOG_CLASS (compselect_parent_class)->
1302 geometry_restore (dialog, key_file, group_name);
1304 position = g_key_file_get_integer (key_file, group_name, "hpaned", NULL);
1305 if (position != 0)
1306 gtk_paned_set_position (GTK_PANED (COMPSELECT (dialog)->hpaned), position);
1308 position = g_key_file_get_integer (key_file, group_name, "vpaned", NULL);
1309 if (position != 0)
1310 gtk_paned_set_position (GTK_PANED (COMPSELECT (dialog)->vpaned), position);
1312 position = g_key_file_get_integer (key_file, group_name, "source-tab", NULL);
1313 gtk_notebook_set_current_page (COMPSELECT (dialog)->viewtabs, position);
1317 static void
1318 compselect_class_init (CompselectClass *klass)
1320 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1321 GschemDialogClass *gschem_dialog_class = GSCHEM_DIALOG_CLASS (klass);
1323 gschem_dialog_class->geometry_save = compselect_geometry_save;
1324 gschem_dialog_class->geometry_restore = compselect_geometry_restore;
1326 gobject_class->constructor = compselect_constructor;
1327 gobject_class->finalize = compselect_finalize;
1328 gobject_class->set_property = compselect_set_property;
1329 gobject_class->get_property = compselect_get_property;
1331 compselect_parent_class = g_type_class_peek_parent (klass);
1333 g_object_class_install_property (
1334 gobject_class, PROP_SYMBOL,
1335 g_param_spec_pointer ("symbol",
1338 G_PARAM_READABLE));
1339 g_object_class_install_property (
1340 gobject_class, PROP_BEHAVIOR,
1341 g_param_spec_enum ("behavior",
1344 COMPSELECT_TYPE_BEHAVIOR,
1345 COMPSELECT_BEHAVIOR_REFERENCE,
1346 G_PARAM_READWRITE));
1347 g_object_class_install_property (
1348 gobject_class, PROP_HIDDEN,
1349 g_param_spec_boolean ("hidden",
1352 FALSE,
1353 G_PARAM_READWRITE));
1357 static GObject*
1358 compselect_constructor (GType type,
1359 guint n_construct_properties,
1360 GObjectConstructParam *construct_params)
1362 GObject *object;
1363 Compselect *compselect;
1365 GtkWidget *hpaned, *vpaned, *notebook, *attributes;
1366 GtkWidget *libview, *inuseview;
1367 GtkWidget *preview, *combobox;
1368 GtkWidget *alignment, *frame;
1370 /* chain up to constructor of parent class */
1371 object = G_OBJECT_CLASS (compselect_parent_class)->
1372 constructor (type, n_construct_properties, construct_params);
1373 compselect = COMPSELECT (object);
1375 /* dialog initialization */
1376 g_object_set (object,
1377 /* GtkWindow */
1378 "title", _("Select Component..."),
1379 "default-height", 300,
1380 "default-width", 400,
1381 NULL);
1383 /* vertical pane containing preview and attributes */
1384 vpaned = GTK_WIDGET (g_object_new (GTK_TYPE_VPANED, NULL));
1385 compselect->vpaned = vpaned;
1387 /* horizontal pane containing selection and preview */
1388 hpaned = GTK_WIDGET (g_object_new (GTK_TYPE_HPANED,
1389 /* GtkContainer */
1390 "border-width", 5,
1391 NULL));
1392 compselect->hpaned = hpaned;
1394 /* notebook for library and inuse views */
1395 notebook = GTK_WIDGET (g_object_new (GTK_TYPE_NOTEBOOK,
1396 NULL));
1397 compselect->viewtabs = GTK_NOTEBOOK (notebook);
1399 inuseview = create_inuse_treeview (compselect);
1400 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), inuseview,
1401 gtk_label_new (_("In Use")));
1403 libview = create_lib_treeview (compselect);
1404 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), libview,
1405 gtk_label_new (_("Libraries")));
1407 /* include the vertical box in horizontal box */
1408 gtk_paned_pack1 (GTK_PANED (hpaned), notebook, TRUE, FALSE);
1411 /* -- preview area -- */
1412 frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
1413 /* GtkFrame */
1414 "label", _("Preview"),
1415 NULL));
1416 alignment = GTK_WIDGET (g_object_new (GTK_TYPE_ALIGNMENT,
1417 /* GtkAlignment */
1418 "border-width", 5,
1419 "xscale", 1.0,
1420 "yscale", 1.0,
1421 "xalign", 0.5,
1422 "yalign", 0.5,
1423 NULL));
1424 preview = GTK_WIDGET (g_object_new (TYPE_PREVIEW,
1425 /* Preview */
1426 "active", FALSE,
1427 NULL));
1428 gtk_container_add (GTK_CONTAINER (alignment), preview);
1429 gtk_container_add (GTK_CONTAINER (frame), alignment);
1430 /* set preview of compselect */
1431 compselect->preview = PREVIEW (preview);
1433 gtk_paned_pack1 (GTK_PANED (vpaned), frame, FALSE, FALSE);
1435 /* only create the attribute treeview if there are elements in the
1436 component_select_attrlist */
1437 if (GSCHEM_DIALOG (compselect)->w_current->component_select_attrlist == NULL) {
1438 compselect->attrtreeview = NULL;
1439 } else {
1440 frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
1441 /* GtkFrame */
1442 "label", _("Attributes"),
1443 NULL));
1444 attributes = create_attributes_treeview (compselect);
1445 gtk_paned_pack2 (GTK_PANED (vpaned), frame, FALSE, FALSE);
1446 gtk_container_add (GTK_CONTAINER (frame), attributes);
1449 gtk_paned_pack2 (GTK_PANED (hpaned), vpaned, FALSE, FALSE);
1451 /* add the hpaned to the dialog vbox */
1452 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (compselect)->vbox), hpaned,
1453 TRUE, TRUE, 0);
1454 gtk_widget_show_all (hpaned);
1457 /* -- behavior combo box -- */
1458 combobox = create_behaviors_combo_box ();
1459 g_signal_connect (combobox,
1460 "changed",
1461 G_CALLBACK (compselect_callback_behavior_changed),
1462 compselect);
1463 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (compselect)->vbox), combobox,
1464 FALSE, FALSE, 10);
1465 gtk_widget_show_all (combobox);
1466 /* set behavior combo box of compselect */
1467 compselect->combobox_behaviors = GTK_COMBO_BOX (combobox);
1469 /* now add buttons in the action area */
1470 gtk_dialog_add_buttons (GTK_DIALOG (compselect),
1471 /* - close button */
1472 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
1473 GTK_STOCK_OK, COMPSELECT_RESPONSE_HIDE,
1474 NULL);
1476 /* Set the alternative button order (ok, cancel, help) for other systems */
1477 gtk_dialog_set_alternative_button_order (GTK_DIALOG (compselect),
1478 COMPSELECT_RESPONSE_HIDE,
1479 GTK_RESPONSE_CLOSE,
1480 -1);
1482 /* Initialize the hidden property */
1483 compselect->hidden = FALSE;
1485 return object;
1488 static void
1489 compselect_finalize (GObject *object)
1491 Compselect *compselect = COMPSELECT (object);
1493 if (compselect->filter_timeout != 0) {
1494 g_source_remove (compselect->filter_timeout);
1495 compselect->filter_timeout = 0;
1498 G_OBJECT_CLASS (compselect_parent_class)->finalize (object);
1501 static void
1502 compselect_set_property (GObject *object,
1503 guint property_id,
1504 const GValue *value,
1505 GParamSpec *pspec)
1507 Compselect *compselect = COMPSELECT (object);
1509 switch (property_id) {
1510 case PROP_BEHAVIOR:
1511 gtk_combo_box_set_active (compselect->combobox_behaviors,
1512 g_value_get_enum (value));
1513 break;
1514 case PROP_HIDDEN:
1515 compselect->hidden = g_value_get_boolean (value);
1516 if (compselect->hidden)
1517 gtk_widget_hide (GTK_WIDGET (compselect));
1518 else
1519 gtk_window_present (GTK_WINDOW (compselect));
1520 break;
1521 default:
1522 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1527 static void
1528 compselect_get_property (GObject *object,
1529 guint property_id,
1530 GValue *value,
1531 GParamSpec *pspec)
1533 Compselect *compselect = COMPSELECT (object);
1535 switch (property_id) {
1536 case PROP_SYMBOL:
1538 GtkTreeModel *model;
1539 GtkTreeIter iter, parent;
1540 CLibSymbol *symbol = NULL;
1542 switch (compselect_get_view (compselect)) {
1543 case VIEW_INUSE:
1544 if (gtk_tree_selection_get_selected (
1545 gtk_tree_view_get_selection (compselect->inusetreeview),
1546 &model,
1547 &iter)) {
1548 gtk_tree_model_get (model, &iter, 0, &symbol, -1);
1550 break;
1551 case VIEW_CLIB:
1552 if (gtk_tree_selection_get_selected (
1553 gtk_tree_view_get_selection (compselect->libtreeview),
1554 &model,
1555 &iter)
1556 && gtk_tree_model_iter_parent (model, &parent, &iter)) {
1557 gtk_tree_model_get (model, &iter, 0, &symbol, -1);
1559 break;
1560 default:
1561 g_assert_not_reached ();
1564 g_value_set_pointer (value, symbol);
1565 break;
1567 case PROP_BEHAVIOR:
1568 g_value_set_enum (value,
1569 gtk_combo_box_get_active (
1570 compselect->combobox_behaviors));
1571 break;
1572 case PROP_HIDDEN:
1573 g_value_set_boolean (value, compselect->hidden);
1574 break;
1575 default:
1576 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1583 GType
1584 compselect_behavior_get_type (void)
1586 static GType etype = 0;
1588 if (etype == 0) {
1589 static const GEnumValue values[] = {
1590 { COMPSELECT_BEHAVIOR_REFERENCE, "COMPSELECT_BEHAVIOR_REFERENCE", "reference" },
1591 { COMPSELECT_BEHAVIOR_EMBED, "COMPSELECT_BEHAVIOR_EMBED", "embed" },
1592 { COMPSELECT_BEHAVIOR_INCLUDE, "COMPSELECT_BEHAVIOR_INCLUDE", "include" },
1593 { 0, NULL, NULL }
1596 etype = g_enum_register_static ("CompselectBehavior", values);
1599 return etype;