pcb 4.1.1
An interactive printed circuit board layout editor.

gui-library-window.c

Go to the documentation of this file.
00001 /*
00002  *                            COPYRIGHT
00003  *
00004  *  PCB, interactive printed circuit board design
00005  *  Copyright (C) 1994,1995,1996 Thomas Nau
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License along
00018  *  with this program; if not, write to the Free Software Foundation, Inc.,
00019  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  *
00021  *  Contact addresses for paper mail and Email:
00022  *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
00023  *  Thomas.Nau@rz.uni-ulm.de
00024  *
00025  */
00026 
00027 /* This file originally from the PCB Gtk port by Bill Wilson. It has
00028  * since been combined with modified code from the gEDA project:
00029  *
00030  * gschem/src/ghid_library_window.c, checked out by Peter Clifton
00031  * from gEDA/gaf commit 72581a91da08c9d69593c24756144fc18940992e
00032  * on 3rd Jan, 2008.
00033  *
00034  * gEDA - GPL Electronic Design Automation
00035  * gschem - gEDA Schematic Capture
00036  * Copyright (C) 1998-2007 Ales Hvezda
00037  * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
00038  *
00039  * This program is free software; you can redistribute it and/or modify
00040  * it under the terms of the GNU General Public License as published by
00041  * the Free Software Foundation; either version 2 of the License, or
00042  * (at your option) any later version.
00043  *
00044  * This program is distributed in the hope that it will be useful,
00045  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00046  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00047  * GNU General Public License for more details.
00048  *
00049  * You should have received a copy of the GNU General Public License
00050  * along with this program; if not, write to the Free Software
00051  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
00052  */
00053 
00054 #ifdef HAVE_CONFIG_H
00055 #include "config.h"
00056 #endif
00057 
00058 #include "gui.h"
00059 #include "global.h"
00060 #include "buffer.h"
00061 #include "data.h"
00062 #include "set.h"
00063 
00064 #include <gdk/gdkkeysyms.h>
00065 
00066 #ifdef HAVE_LIBDMALLOC
00067 #include <dmalloc.h>
00068 #endif
00069 
00070 static GtkWidget *library_window;
00071 
00072 #include "gui-pinout-preview.h"
00073 #include "gui-library-window.h"
00074 
00085 #define LIBRARY_FILTER_INTERVAL 200
00086 
00087 
00088 static gint
00089 library_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev,
00090                                    gpointer data)
00091 {
00092   GtkAllocation allocation;
00093 
00094   gtk_widget_get_allocation (widget, &allocation);
00095   ghidgui->library_window_width = allocation.width;
00096   ghidgui->library_window_height = allocation.height;
00097   ghidgui->config_modified = TRUE;
00098   return FALSE;
00099 }
00100 
00101 
00102 enum
00103 {
00104   MENU_TOPPATH_COLUMN,          /* Top path of the library         */
00105   MENU_SUBPATH_COLUMN,          /* Relative path to the top        */
00106   MENU_NAME_COLUMN,             /* Text to display in the tree     */
00107   MENU_LIBRARY_COLUMN,          /* Pointer to the LibraryMenuType  */
00108   MENU_ENTRY_COLUMN,            /* Pointer to the LibraryEntryType */
00109   N_MENU_COLUMNS
00110 };
00111 
00112 
00125 static void
00126 library_window_callback_response (GtkDialog * dialog,
00127                                   gint arg1, gpointer user_data)
00128 {
00129   switch (arg1)
00130     {
00131     case GTK_RESPONSE_CLOSE:
00132     case GTK_RESPONSE_DELETE_EVENT:
00133       gtk_widget_destroy (GTK_WIDGET (library_window));
00134       library_window = NULL;
00135       break;
00136 
00137     default:
00138       /* Do nothing, in case there's another handler function which
00139          can handle the response ID received. */
00140       break;
00141     }
00142 }
00143 
00144 
00151 void
00152 ghid_library_window_create (GHidPort * out)
00153 {
00154   GtkWidget *current_tab, *entry_filter;
00155   GtkNotebook *notebook;
00156 
00157   if (library_window)
00158     return;
00159 
00160   library_window = (GtkWidget *)g_object_new (GHID_TYPE_LIBRARY_WINDOW, NULL);
00161 
00162   g_signal_connect (library_window,
00163                     "response",
00164                     G_CALLBACK (library_window_callback_response), NULL);
00165   g_signal_connect (G_OBJECT (library_window), "configure_event",
00166                     G_CALLBACK (library_window_configure_event_cb), NULL);
00167   gtk_window_resize (GTK_WINDOW (library_window),
00168                      ghidgui->library_window_width,
00169                      ghidgui->library_window_height);
00170 
00171   gtk_window_set_title (GTK_WINDOW (library_window), _("PCB Library"));
00172   gtk_window_set_wmclass (GTK_WINDOW (library_window), "PCB_Library",
00173                           "PCB");
00174 
00175   gtk_widget_realize (library_window);
00176   if (Settings.AutoPlace)
00177     gtk_window_move (GTK_WINDOW (library_window), 10, 10);
00178 
00179   gtk_editable_select_region (GTK_EDITABLE
00180                               (GHID_LIBRARY_WINDOW (library_window)->
00181                                entry_filter), 0, -1);
00182 
00183   /* Set the focus to the filter entry only if it is in the current
00184      displayed tab */
00185   notebook = GTK_NOTEBOOK (GHID_LIBRARY_WINDOW (library_window)->viewtabs);
00186   current_tab = gtk_notebook_get_nth_page (notebook,
00187                                            gtk_notebook_get_current_page
00188                                            (notebook));
00189   entry_filter =
00190     GTK_WIDGET (GHID_LIBRARY_WINDOW (library_window)->entry_filter);
00191   if (gtk_widget_is_ancestor (entry_filter, current_tab))
00192     {
00193       gtk_widget_grab_focus (entry_filter);
00194     }
00195 }
00196 
00203 void
00204 ghid_library_window_show (GHidPort * out, gboolean raise)
00205 {
00206   ghid_library_window_create (out);
00207   gtk_widget_show_all (library_window);
00208   if (raise)
00209     gtk_window_present (GTK_WINDOW(library_window));
00210 }
00211 
00212 static GObjectClass *library_window_parent_class = NULL;
00213 
00214 
00225 static gboolean
00226 lib_model_filter_visible_func (GtkTreeModel * model,
00227                                GtkTreeIter * iter, gpointer data)
00228 {
00229   GhidLibraryWindow *library_window = (GhidLibraryWindow *) data;
00230   const gchar *compname;
00231   gchar *compname_upper, *text_upper, *pattern;
00232   const gchar *text;
00233   gboolean ret;
00234 
00235   g_assert (GHID_IS_LIBRARY_WINDOW (data));
00236 
00237   text = gtk_entry_get_text (library_window->entry_filter);
00238   if (g_ascii_strcasecmp (text, "") == 0)
00239     {
00240       return TRUE;
00241     }
00242 
00243   /* If this is a source, only display it if it has children that
00244    * match */
00245   if (gtk_tree_model_iter_has_child (model, iter))
00246     {
00247       GtkTreeIter iter2;
00248 
00249       gtk_tree_model_iter_children (model, &iter2, iter);
00250       ret = FALSE;
00251       do
00252         {
00253           if (lib_model_filter_visible_func (model, &iter2, data))
00254             {
00255               ret = TRUE;
00256               break;
00257             }
00258         }
00259       while (gtk_tree_model_iter_next (model, &iter2));
00260     }
00261   else
00262     {
00263       gtk_tree_model_get (model, iter, MENU_NAME_COLUMN, &compname, -1);
00264       /* Do a case insensitive comparison, converting the strings
00265          to uppercase */
00266       compname_upper = g_ascii_strup (compname, -1);
00267       text_upper = g_ascii_strup (text, -1);
00268       pattern = g_strconcat ("*", text_upper, "*", NULL);
00269       ret = g_pattern_match_simple (pattern, compname_upper);
00270       g_free (compname_upper);
00271       g_free (text_upper);
00272       g_free (pattern);
00273     }
00274 
00275   return ret;
00276 }
00277 
00278 
00289 static void
00290 tree_row_activated (GtkTreeView       *tree_view,
00291                     GtkTreePath       *path,
00292                     GtkTreeViewColumn *column,
00293                     gpointer           user_data)
00294 {
00295   GtkTreeModel *model;
00296   GtkTreeIter iter;
00297 
00298   model = gtk_tree_view_get_model (tree_view);
00299   gtk_tree_model_get_iter (model, &iter, path);
00300 
00301   if (!gtk_tree_model_iter_has_child (model, &iter))
00302     return;
00303 
00304   if (gtk_tree_view_row_expanded (tree_view, path))
00305     gtk_tree_view_collapse_row (tree_view, path);
00306   else
00307     gtk_tree_view_expand_row (tree_view, path, FALSE);
00308 }
00309 
00320 static gboolean
00321 tree_row_key_pressed (GtkTreeView *tree_view,
00322                       GdkEventKey *event,
00323                       gpointer     user_data)
00324 {
00325   GtkTreeSelection *selection;
00326   GtkTreeModel *model;
00327   GtkTreeIter iter;
00328   GtkClipboard *clipboard;
00329   const gchar *compname;
00330   guint default_mod_mask = gtk_accelerator_get_default_mod_mask();
00331 
00332   /* Handle both lower- and uppercase `c' */
00333   if (((event->state & default_mod_mask) != GDK_CONTROL_MASK)
00334       || ((event->keyval != GDK_c) && (event->keyval != GDK_C)))
00335     return FALSE;
00336 
00337   selection = gtk_tree_view_get_selection (tree_view);
00338   g_return_val_if_fail (selection != NULL, TRUE);
00339 
00340   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
00341     return TRUE;
00342 
00343   gtk_tree_model_get (model, &iter, MENU_NAME_COLUMN, &compname, -1);
00344 
00345   clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
00346   g_return_val_if_fail (clipboard != NULL, TRUE);
00347 
00348   gtk_clipboard_set_text (clipboard, compname, -1);
00349 
00350   return TRUE;
00351 }
00352 
00364 static void
00365 library_window_callback_tree_selection_changed (GtkTreeSelection * selection,
00366                                                 gpointer user_data)
00367 {
00368   GtkTreeModel *model;
00369   GtkTreeIter iter;
00370   GhidLibraryWindow *library_window = (GhidLibraryWindow *) user_data;
00371   LibraryEntryType *entry = NULL;
00372   gchar *m4_args;
00373 
00374   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
00375     return;
00376 
00377   gtk_tree_model_get (model, &iter, MENU_ENTRY_COLUMN, &entry, -1);
00378 
00379   if (entry == NULL)
00380     return;
00381 
00382   /* -1 flags this is an element file part and the file path is in
00383      |  entry->AllocateMemory.
00384    */
00385   if (entry->Template == (char *) -1)
00386     {
00387       if (LoadElementToBuffer (PASTEBUFFER, entry->AllocatedMemory, true))
00388         {
00389           SetMode (PASTEBUFFER_MODE);
00390           goto out;
00391         }
00392       return;
00393     }
00394 
00395   /* Otherwise, it's a m4 element and we need to create a string of
00396      |  macro arguments to be passed to the library command in
00397      |  LoadElementToBuffer()
00398    */
00399   m4_args = g_strdup_printf ("'%s' '%s' '%s'", EMPTY (entry->Template),
00400                              EMPTY (entry->Value), EMPTY (entry->Package));
00401 
00402   if (LoadElementToBuffer (PASTEBUFFER, m4_args, false))
00403     {
00404       SetMode (PASTEBUFFER_MODE);
00405       g_free (m4_args);
00406       goto out;
00407     }
00408 
00409   g_free (m4_args);
00410   return;
00411 
00412 out:
00413 
00414   /* update the preview with new symbol data */
00415   g_object_set (library_window->preview,
00416                 "element-data", PASTEBUFFER->Data->Element->data, NULL);
00417 }
00418 
00421 static void
00422 maybe_expand_toplevel_node (GtkTreeView *tree_view)
00423 {
00424   GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
00425   if (gtk_tree_model_iter_n_children (model, NULL) == 1)
00426     {
00427       GtkTreePath *path = gtk_tree_path_new_first ();
00428       if (path != NULL)
00429         {
00430           gtk_tree_view_expand_row (tree_view, path, FALSE);
00431           gtk_tree_path_free(path);
00432         }
00433     }
00434 }
00435 
00447 static gboolean
00448 library_window_filter_timeout (gpointer data)
00449 {
00450   GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (data);
00451   GtkTreeModel *model;
00452 
00453   /* resets the source id in library_window */
00454   library_window->filter_timeout = 0;
00455 
00456   model = gtk_tree_view_get_model (library_window->libtreeview);
00457 
00458   if (model != NULL)
00459     {
00460       const gchar *text = gtk_entry_get_text (library_window->entry_filter);
00461       gtk_tree_model_filter_refilter ((GtkTreeModelFilter *) model);
00462       if (strcmp (text, "") != 0)
00463         {
00464           /* filter text not-empty */
00465           gtk_tree_view_expand_all (library_window->libtreeview);
00466         } else {
00467           /* filter text is empty, collapse expanded tree */
00468           gtk_tree_view_collapse_all (library_window->libtreeview);
00469           maybe_expand_toplevel_node (library_window->libtreeview);
00470         }
00471     }
00472 
00473   /* return FALSE to remove the source */
00474   return FALSE;
00475 }
00476 
00488 static void
00489 library_window_callback_filter_entry_changed (GtkEditable * editable,
00490                                               gpointer user_data)
00491 {
00492   GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (user_data);
00493   GtkWidget *button;
00494   gboolean sensitive;
00495 
00496   /* turns button off if filter entry is empty */
00497   /* turns it on otherwise */
00498   button = GTK_WIDGET (library_window->button_clear);
00499   sensitive =
00500     (g_ascii_strcasecmp (gtk_entry_get_text (library_window->entry_filter),
00501                          "") != 0);
00502   gtk_widget_set_sensitive (button, sensitive);
00503 
00504   /* Cancel any pending update of the footprint list filter */
00505   if (library_window->filter_timeout != 0)
00506     g_source_remove (library_window->filter_timeout);
00507 
00508   /* Schedule an update of the footprint list filter in
00509    * LIBRARY_FILTER_INTERVAL milliseconds */
00510   library_window->filter_timeout = g_timeout_add (LIBRARY_FILTER_INTERVAL,
00511                                                   library_window_filter_timeout,
00512                                                   library_window);
00513 
00514 }
00515 
00527 static void
00528 library_window_callback_filter_button_clicked (GtkButton * button,
00529                                                gpointer user_data)
00530 {
00531   GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (user_data);
00532 
00533   /* clears text in text entry for filter */
00534   gtk_entry_set_text (library_window->entry_filter, "");
00535 
00536 }
00537 
00538 /* \brief Create the tree model for the "Library" view.
00539  * \par Function Description
00540  * Creates a tree where the branches are the available library
00541  * sources and the leaves are the footprints.
00542  */
00543 static GtkTreeModel *
00544 create_lib_tree_model (GhidLibraryWindow * library_window)
00545 {
00546   GtkTreeStore *tree;
00547   char *rel_path, empty_string[] = ""; /* writable */
00548   GtkTreeIter *iter, p_iter, e_iter, c_iter;
00549   char *tok_start, *tok_end;
00550   gchar *name;
00551   gboolean exists;
00552 
00553   tree = gtk_tree_store_new (N_MENU_COLUMNS,
00554                              G_TYPE_STRING, G_TYPE_STRING,
00555                              G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
00556 
00557   MENU_LOOP (&Library);
00558   {
00559     /* Watch for directory changes of library parts and create new
00560        |  parent iter at each change.
00561      */
00562     if (!menu->directory)       /* Shouldn't happen */
00563       menu->directory = g_strdup ("???");
00564 
00565     rel_path = menu->Name;
00566 
00567     if (strncmp(rel_path, menu->directory, strlen(menu->directory)) == 0)
00568       {
00569         if (rel_path[strlen(menu->directory)] == '\0')
00570           rel_path = empty_string;
00571         else if (rel_path[strlen(menu->directory)] == PCB_DIR_SEPARATOR_C)
00572           rel_path += strlen(menu->directory) + 1;
00573       }
00574 
00575     iter = NULL;
00576     tok_start = tok_end = rel_path;
00577 
00578     do
00579       {
00580         char saved_ch = *tok_end;
00581         *tok_end = '\0';
00582 
00583         exists = FALSE;
00584         if (gtk_tree_model_iter_children (GTK_TREE_MODEL (tree), &e_iter, iter))
00585           do
00586             {
00587               gtk_tree_model_get (GTK_TREE_MODEL (tree), &e_iter,
00588                                   MENU_TOPPATH_COLUMN, &name, -1);
00589               if (strcmp (name, menu->directory) != 0)
00590                 continue;
00591 
00592               gtk_tree_model_get (GTK_TREE_MODEL (tree), &e_iter,
00593                                   MENU_SUBPATH_COLUMN, &name, -1);
00594               if (strcmp (name, rel_path) != 0)
00595                 continue;
00596 
00597               exists = TRUE;
00598               break;
00599             }
00600           while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tree), &e_iter));
00601 
00602         if (exists)
00603           p_iter = e_iter;
00604         else
00605           {
00606             gtk_tree_store_append (tree, &p_iter, iter);
00607             gtk_tree_store_set (tree, &p_iter,
00608                                 MENU_TOPPATH_COLUMN, menu->directory,
00609                                 MENU_SUBPATH_COLUMN, rel_path,
00610                                 MENU_NAME_COLUMN,
00611                                   tok_end == rel_path ?
00612                                     g_path_get_basename(menu->directory) : tok_start,
00613                                 MENU_LIBRARY_COLUMN,
00614                                   saved_ch == '\0' ? menu : NULL,
00615                                 MENU_ENTRY_COLUMN, NULL, -1);
00616           }
00617         iter = &p_iter;
00618 
00619         *tok_end = saved_ch;
00620 
00621         tok_start = tok_end;
00622         if (*tok_start == PCB_DIR_SEPARATOR_C)
00623           tok_start++;
00624         tok_end = strchr(tok_start, PCB_DIR_SEPARATOR_C);
00625     if (!tok_end) tok_end = tok_start + strlen(tok_start);
00626       }
00627     while (*tok_start != '\0');
00628 
00629     ENTRY_LOOP (menu);
00630     {
00631       gtk_tree_store_append (tree, &c_iter, iter);
00632       gtk_tree_store_set (tree, &c_iter,
00633                           MENU_TOPPATH_COLUMN, menu->directory,
00634                           MENU_SUBPATH_COLUMN, rel_path,
00635                           MENU_NAME_COLUMN, entry->ListEntry,
00636                           MENU_LIBRARY_COLUMN, menu,
00637                           MENU_ENTRY_COLUMN, entry, -1);
00638     }
00639     END_LOOP;
00640 
00641   }
00642   END_LOOP;
00643 
00644   return (GtkTreeModel *) tree;
00645 }
00646 
00647 
00648 #if 0
00649 /* \brief On-demand refresh of the footprint library.
00650  * \par Function Description
00651  * Requests a rescan of the footprint library in order to pick up any
00652  * new signals, and then updates the library window.
00653  */
00654 static void
00655 library_window_callback_refresh_library (GtkButton * button,
00656                                          gpointer user_data)
00657 {
00658   GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (user_data);
00659   GtkTreeModel *model;
00660 
00661   /* Rescan the libraries for symbols */
00662   /*  TODO: How do we do this in PCB?  */
00663 
00664   /* Refresh the "Library" view */
00665   model = (GtkTreeModel *)
00666     g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
00667                   "child-model", create_lib_tree_model (library_window),
00668                   "virtual-root", NULL, NULL);
00669 
00670   gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter *) model,
00671                                           lib_model_filter_visible_func,
00672                                           library_window, NULL);
00673 
00674   gtk_tree_view_set_model (library_window->libtreeview, model);
00675   maybe_expand_toplevel_node (library_window->libtreeview);
00676 }
00677 #endif
00678 
00679 
00681 static GtkWidget *
00682 create_lib_treeview (GhidLibraryWindow * library_window)
00683 {
00684   GtkWidget *libtreeview, *vbox, *scrolled_win, *label,
00685     *hbox, *entry, *button;
00686   GtkTreeModel *child_model, *model;
00687   GtkTreeSelection *selection;
00688   GtkCellRenderer *renderer;
00689   GtkTreeViewColumn *column;
00690 
00691   /* -- library selection view -- */
00692 
00693   /* vertical box for footprint selection and search entry */
00694   vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
00695                                    /* GtkContainer */
00696                                    "border-width", 5,
00697                                    /* GtkBox */
00698                                    "homogeneous", FALSE, "spacing", 5, NULL));
00699 
00700   child_model = create_lib_tree_model (library_window);
00701   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (child_model),
00702                                         MENU_NAME_COLUMN, GTK_SORT_ASCENDING);
00703   model = (GtkTreeModel *) g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
00704                                          "child-model", child_model,
00705                                          "virtual-root", NULL, NULL);
00706 
00707   scrolled_win = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
00708                                            /* GtkScrolledWindow */
00709                                            "hscrollbar-policy",
00710                                            GTK_POLICY_AUTOMATIC,
00711                                            "vscrollbar-policy",
00712                                            GTK_POLICY_ALWAYS, "shadow-type",
00713                                            GTK_SHADOW_ETCHED_IN, NULL));
00714   /* create the treeview */
00715   libtreeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
00716                                           /* GtkTreeView */
00717                                           "model", model,
00718                                           "rules-hint", TRUE,
00719                                           "headers-visible", FALSE, NULL));
00720 
00721   g_signal_connect (libtreeview,
00722                     "row-activated",
00723                     G_CALLBACK (tree_row_activated),
00724                     NULL);
00725 
00726   g_signal_connect (libtreeview,
00727                     "key-press-event",
00728                     G_CALLBACK (tree_row_key_pressed),
00729                     NULL);
00730 
00731   maybe_expand_toplevel_node (GTK_TREE_VIEW (libtreeview));
00732 
00733   /* connect callback to selection */
00734   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (libtreeview));
00735   gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
00736   g_signal_connect (selection,
00737                     "changed",
00738                     G_CALLBACK
00739                     (library_window_callback_tree_selection_changed),
00740                     library_window);
00741 
00742   /* insert a column to treeview for library/symbol name */
00743   renderer = GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
00744                                               /* GtkCellRendererText */
00745                                               "editable", FALSE, NULL));
00746   column = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
00747                                                /* GtkTreeViewColumn */
00748                                                "title", _("Components"),
00749                                                NULL));
00750   gtk_tree_view_column_pack_start (column, renderer, TRUE);
00751   gtk_tree_view_column_set_attributes (column, renderer,
00752                                        "text", MENU_NAME_COLUMN, NULL);
00753   gtk_tree_view_append_column (GTK_TREE_VIEW (libtreeview), column);
00754 
00755   /* add the treeview to the scrolled window */
00756   gtk_container_add (GTK_CONTAINER (scrolled_win), libtreeview);
00757 
00758   /* add the scrolled window for directories to the vertical box */
00759   gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
00760 
00761 
00762   /* -- filter area -- */
00763   hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
00764                                    /* GtkBox */
00765                                    "homogeneous", FALSE, "spacing", 3, NULL));
00766 
00767   /* create the entry label */
00768   label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
00769                                     /* GtkMisc */
00770                                     "xalign", 0.0,
00771                                     /* GtkLabel */
00772                                     "label", _("Filter:"), NULL));
00773   /* add the search label to the filter area */
00774   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
00775 
00776   /* create the text entry for filter in footprints */
00777   entry = GTK_WIDGET (g_object_new (GTK_TYPE_ENTRY,
00778                                     /* GtkEntry */
00779                                     "text", "", NULL));
00780   g_signal_connect (entry,
00781                     "changed",
00782                     G_CALLBACK (library_window_callback_filter_entry_changed),
00783                     library_window);
00784 
00785   /* now that that we have an entry, set the filter func of model */
00786   gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter *) model,
00787                                           lib_model_filter_visible_func,
00788                                           library_window, NULL);
00789 
00790   /* add the filter entry to the filter area */
00791   gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
00792   /* set filter entry of library_window */
00793   library_window->entry_filter = GTK_ENTRY (entry);
00794   /* and init the event source for footprint filter */
00795   library_window->filter_timeout = 0;
00796 
00797   /* create the erase button for filter entry */
00798   button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
00799                                      /* GtkWidget */
00800                                      "sensitive", FALSE,
00801                                      /* GtkButton */
00802                                      "relief", GTK_RELIEF_NONE, NULL));
00803 
00804   gtk_container_add (GTK_CONTAINER (button),
00805                      gtk_image_new_from_stock (GTK_STOCK_CLEAR,
00806                                                GTK_ICON_SIZE_SMALL_TOOLBAR));
00807   g_signal_connect (button,
00808                     "clicked",
00809                     G_CALLBACK
00810                     (library_window_callback_filter_button_clicked),
00811                     library_window);
00812   /* add the clear button to the filter area */
00813   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
00814   /* set clear button of library_window */
00815   library_window->button_clear = GTK_BUTTON (button);
00816 
00817 #if 0
00818   /* create the refresh button */
00819   button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
00820                                      /* GtkWidget */
00821                                      "sensitive", TRUE,
00822                                      /* GtkButton */
00823                                      "relief", GTK_RELIEF_NONE, NULL));
00824   gtk_container_add (GTK_CONTAINER (button),
00825                      gtk_image_new_from_stock (GTK_STOCK_REFRESH,
00826                                                GTK_ICON_SIZE_SMALL_TOOLBAR));
00827   /* add the refresh button to the filter area */
00828   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
00829   g_signal_connect (button,
00830                     "clicked",
00831                     G_CALLBACK (library_window_callback_refresh_library),
00832                     library_window);
00833 #endif
00834 
00835   /* add the filter area to the vertical box */
00836   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
00837 
00838   /* save pointer to libtreeview in library_window */
00839   library_window->libtreeview = GTK_TREE_VIEW (libtreeview);
00840 
00841   return vbox;
00842 }
00843 
00844 
00845 static GObject *
00846 library_window_constructor (GType type,
00847                             guint n_construct_properties,
00848                             GObjectConstructParam * construct_params)
00849 {
00850   GObject *object;
00851   GhidLibraryWindow *library_window;
00852   GtkWidget *content_area;
00853   GtkWidget *hpaned, *notebook;
00854   GtkWidget *libview;
00855   GtkWidget *preview;
00856   GtkWidget *alignment, *frame;
00857 
00858   /* chain up to constructor of parent class */
00859   object = G_OBJECT_CLASS (library_window_parent_class)->
00860     constructor (type, n_construct_properties, construct_params);
00861   library_window = GHID_LIBRARY_WINDOW (object);
00862 
00863   /* dialog initialization */
00864   g_object_set (object,
00865                 /* GtkWindow */
00866                 "type", GTK_WINDOW_TOPLEVEL,
00867                 "title", _("Select Footprint..."),
00868                 "default-height", 300,
00869                 "default-width", 400,
00870                 "modal", FALSE, "window-position", GTK_WIN_POS_NONE,
00871                 /* GtkDialog */
00872                 "has-separator", TRUE, NULL);
00873   g_object_set (gtk_dialog_get_content_area (GTK_DIALOG (library_window)),
00874                 "homogeneous", FALSE, NULL);
00875 
00876   /* horizontal pane containing selection and preview */
00877   hpaned = GTK_WIDGET (g_object_new (GTK_TYPE_HPANED,
00878                                      /* GtkContainer */
00879                                      "border-width", 5, NULL));
00880   library_window->hpaned = hpaned;
00881 
00882   /* notebook for library views */
00883   notebook = GTK_WIDGET (g_object_new (GTK_TYPE_NOTEBOOK,
00884                                        "show-tabs", FALSE, NULL));
00885   library_window->viewtabs = GTK_NOTEBOOK (notebook);
00886 
00887   libview = create_lib_treeview (library_window);
00888   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), libview,
00889                             gtk_label_new (_("Libraries")));
00890 
00891   /* include the vertical box in horizontal box */
00892   gtk_paned_pack1 (GTK_PANED (hpaned), notebook, TRUE, FALSE);
00893 
00894 
00895   /* -- preview area -- */
00896   frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
00897                                     /* GtkFrame */
00898                                     "label", _("Preview"), NULL));
00899   alignment = GTK_WIDGET (g_object_new (GTK_TYPE_ALIGNMENT,
00900                                         /* GtkAlignment */
00901                                         "left-padding", 5,
00902                                         "right-padding", 5,
00903                                         "top-padding", 5,
00904                                         "bottom-padding", 5,
00905                                         "xscale", 1.0,
00906                                         "yscale", 1.0,
00907                                         "xalign", 0.5, "yalign", 0.5, NULL));
00908   preview = (GtkWidget *)g_object_new (GHID_TYPE_PINOUT_PREVIEW,
00909                           /* GhidPinoutPreview */
00910                           "element-data", NULL,
00911                           /* GtkWidget */
00912                           "width-request", 150, "height-request", 150, NULL);
00913   gtk_container_add (GTK_CONTAINER (alignment), preview);
00914   gtk_container_add (GTK_CONTAINER (frame), alignment);
00915   /* set preview of library_window */
00916   library_window->preview = preview;
00917 
00918   gtk_paned_pack2 (GTK_PANED (hpaned), frame, FALSE, FALSE);
00919 
00920   /* add the hpaned to the dialog content area */
00921   content_area = gtk_dialog_get_content_area (GTK_DIALOG (library_window));
00922   gtk_box_pack_start (GTK_BOX (content_area), hpaned, TRUE, TRUE, 0);
00923   gtk_widget_show_all (hpaned);
00924 
00925 
00926   /* now add buttons in the action area */
00927   gtk_dialog_add_buttons (GTK_DIALOG (library_window),
00928                           /*  - close button */
00929                           GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
00930 
00931   return object;
00932 }
00933 
00934 static void
00935 library_window_finalize (GObject * object)
00936 {
00937   GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (object);
00938 
00939   if (library_window->filter_timeout != 0)
00940     {
00941       g_source_remove (library_window->filter_timeout);
00942       library_window->filter_timeout = 0;
00943     }
00944 
00945   G_OBJECT_CLASS (library_window_parent_class)->finalize (object);
00946 }
00947 
00948 
00949 static void
00950 library_window_class_init (GhidLibraryWindowClass * klass)
00951 {
00952   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
00953 
00954   gobject_class->constructor = library_window_constructor;
00955   gobject_class->finalize = library_window_finalize;
00956 
00957   library_window_parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
00958 }
00959 
00960 
00961 GType
00962 ghid_library_window_get_type ()
00963 {
00964   static GType library_window_type = 0;
00965 
00966   if (!library_window_type)
00967     {
00968       static const GTypeInfo library_window_info = {
00969         sizeof (GhidLibraryWindowClass),
00970         NULL,                   /* base_init */
00971         NULL,                   /* base_finalize */
00972         (GClassInitFunc) library_window_class_init,
00973         NULL,                   /* class_finalize */
00974         NULL,                   /* class_data */
00975         sizeof (GhidLibraryWindow),
00976         0,                      /* n_preallocs */
00977         NULL                    /* instance_init */
00978       };
00979 
00980       library_window_type = g_type_register_static (GTK_TYPE_DIALOG,
00981                                                     "GhidLibraryWindow",
00982                                                     &library_window_info, (GTypeFlags)0);
00983     }
00984 
00985   return library_window_type;
00986 }