gnome-specimen r165 - in branches/import-from-bzr: . data specimen



Author: wbolster
Date: Tue Jun 17 18:54:53 2008
New Revision: 165
URL: http://svn.gnome.org/viewvc/gnome-specimen?rev=165&view=rev

Log:
* NEWS:
* TODO:
* data/gnome-specimen.glade:
* specimen/specimenwindow.py:
  - Implemented search interface. The interface shows a menu
    item (with ctrl-f shortcut) and a find bar now. Typing
    into the entry filters the list of fonts. Pressing Enter
    activates the listing for better keyboard navigation.
  - Font loading on startup should be much faster because
    the model is disconnected from the view while it is
    populated with all available fonts.


Modified:
   branches/import-from-bzr/   (props changed)
   branches/import-from-bzr/NEWS
   branches/import-from-bzr/TODO
   branches/import-from-bzr/data/gnome-specimen.glade
   branches/import-from-bzr/specimen/specimenwindow.py

Modified: branches/import-from-bzr/NEWS
==============================================================================
--- branches/import-from-bzr/NEWS	(original)
+++ branches/import-from-bzr/NEWS	Tue Jun 17 18:54:53 2008
@@ -3,9 +3,11 @@
 ==================
 
 User-visible changes since the previous release:
-- Add keyboard shortcut for zooming (Ctrl-Plus, Ctrl-Minus)
+- Search interface for the font listing
+- Add keyboard shortcuts for zooming (Ctrl-Plus, Ctrl-Minus)
 
 Other changes:
+- Font loading on startup should be much faster
 - Added debian/ directory for easy Debian packaging
 - Updated copyright notices (email address and year)
 

Modified: branches/import-from-bzr/TODO
==============================================================================
--- branches/import-from-bzr/TODO	(original)
+++ branches/import-from-bzr/TODO	Tue Jun 17 18:54:53 2008
@@ -2,9 +2,5 @@
 ========================================
 
 - Allow drag and drop from the left pane to the preview pane
-
 - Make hyperlinks in the about dialog work
-
 - Add tooltips for the buttons
-
-- Search interface for the font listing (needs thinking)

Modified: branches/import-from-bzr/data/gnome-specimen.glade
==============================================================================
--- branches/import-from-bzr/data/gnome-specimen.glade	(original)
+++ branches/import-from-bzr/data/gnome-specimen.glade	Tue Jun 17 18:54:53 2008
@@ -6,8 +6,8 @@
     <property name="title" translatable="yes">Specimen Font Previewer</property>
     <property name="default_width">640</property>
     <property name="default_height">480</property>
-    <signal name="destroy" handler="on_destroy_event"/>
     <signal name="key_press_event" handler="on_main_window_key_press_event"/>
+    <signal name="destroy" handler="on_destroy_event"/>
     <child>
       <widget class="GtkVBox" id="vbox1">
         <property name="visible">True</property>
@@ -74,8 +74,18 @@
                       </widget>
                     </child>
                     <child>
-                      <widget class="GtkSeparatorMenuItem" id="separator1">
+                      <widget class="GtkImageMenuItem" id="find_item">
                         <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Find...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_find_item_activate"/>
+                        <accelerator key="F" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="menu-item-image5">
+                            <property name="stock">gtk-find</property>
+                          </widget>
+                        </child>
                       </widget>
                     </child>
                     <child>
@@ -134,21 +144,76 @@
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <child>
-              <widget class="GtkScrolledWindow" id="fonts-treeview-window">
+              <widget class="GtkVBox" id="vbox3">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
-                <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-                <property name="shadow_type">GTK_SHADOW_IN</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                 <child>
-                  <widget class="GtkTreeView" id="fonts-treeview">
+                  <widget class="GtkScrolledWindow" id="fonts-treeview-window">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="can_default">True</property>
-                    <property name="headers_visible">False</property>
-                    <property name="rules_hint">True</property>
-                    <signal name="key_release_event" handler="on_previews_treeview_key_release_event"/>
+                    <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="fonts-treeview">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="headers_visible">False</property>
+                        <property name="rules_hint">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkHBox" id="find-controls">
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <widget class="GtkLabel" id="find-label">
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Find:</property>
+                      </widget>
+                      <packing>
+                        <property name="padding">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="find-entry">
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <signal name="changed" handler="on_find_entry_changed"/>
+                        <signal name="activate" handler="on_find_entry_activated"/>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="find-close-button">
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="tooltip" translatable="yes">Close find</property>
+                        <property name="relief">GTK_RELIEF_NONE</property>
+                        <signal name="clicked" handler="cancel_find_cb"/>
+                        <child>
+                          <widget class="GtkImage" id="image1">
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="stock">gtk-close</property>
+                          </widget>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
                   </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
               </widget>
               <packing>
@@ -247,31 +312,31 @@
                     <property name="visible">True</property>
                     <property name="spacing">6</property>
                     <child>
-                      <widget class="GtkButton" id="add-button">
+                      <widget class="GtkButton" id="clear-button">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="label">gtk-add</property>
+                        <property name="label">gtk-clear</property>
                         <property name="relief">GTK_RELIEF_NONE</property>
                         <property name="use_stock">True</property>
                         <property name="focus_on_click">False</property>
-                        <signal name="clicked" handler="on_add_button_clicked"/>
+                        <signal name="clicked" handler="on_clear_button_clicked"/>
                       </widget>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
                         <property name="pack_type">GTK_PACK_END</property>
-                        <property name="position">2</property>
+                        <property name="position">3</property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkButton" id="remove-button">
+                      <widget class="GtkButton" id="add-button">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="label">gtk-remove</property>
+                        <property name="label">gtk-add</property>
                         <property name="relief">GTK_RELIEF_NONE</property>
                         <property name="use_stock">True</property>
                         <property name="focus_on_click">False</property>
-                        <signal name="clicked" handler="on_remove_button_clicked"/>
+                        <signal name="clicked" handler="on_add_button_clicked"/>
                       </widget>
                       <packing>
                         <property name="expand">False</property>
@@ -281,19 +346,20 @@
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkButton" id="clear-button">
+                      <widget class="GtkButton" id="remove-button">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="label">gtk-clear</property>
+                        <property name="label">gtk-remove</property>
                         <property name="relief">GTK_RELIEF_NONE</property>
                         <property name="use_stock">True</property>
                         <property name="focus_on_click">False</property>
-                        <signal name="clicked" handler="on_clear_button_clicked"/>
+                        <signal name="clicked" handler="on_remove_button_clicked"/>
                       </widget>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
                         <property name="pack_type">GTK_PACK_END</property>
+                        <property name="position">1</property>
                       </packing>
                     </child>
                   </widget>

Modified: branches/import-from-bzr/specimen/specimenwindow.py
==============================================================================
--- branches/import-from-bzr/specimen/specimenwindow.py	(original)
+++ branches/import-from-bzr/specimen/specimenwindow.py	Tue Jun 17 18:54:53 2008
@@ -114,8 +114,9 @@
         self.gconf_client.notify(self.gconf_path_preview_text)
         self.gconf_client.notify(self.gconf_path_preview_size)
 
-        # show the window
+        # show the window, but hide the form controls
         self.window.show_all()
+        self.find_controls.hide()
 
     def quit(self):
         'Quits the application'
@@ -146,13 +147,19 @@
         # populate the UI
         self.load_fonts()
 
+        # font finding
+        self.find_controls = glade_tree.get_widget('find-controls')
+        self.find_entry = glade_tree.get_widget('find-entry')
+
     def load_fonts(self):
         'Loads all fonts and updates the fonts treeview'
 
         # prepare the tree model
-        self.fonts_treestore = gtk.TreeStore(str, pango.FontFamily, pango.FontFace)
+        self.fonts_treestore = gtk.TreeStore(str, pango.FontFamily, pango.FontFace, bool)
         self.fonts_treemodelsort = gtk.TreeModelSort(self.fonts_treestore)
-        self.fonts_treeview.set_model(self.fonts_treemodelsort)
+        self.fonts_treemodelfilter = self.fonts_treemodelsort.filter_new()
+        self.fonts_treemodelfilter.set_visible_column(3)
+        self.fonts_treeview.set_model(self.fonts_treemodelfilter)
         self.fonts_treemodelsort.set_sort_func(0, self.font_name_sort)
         self.fonts_treemodelsort.set_sort_column_id(0, gtk.SORT_ASCENDING)
 
@@ -162,7 +169,6 @@
         cell_renderer = gtk.CellRendererText()
         name_column.pack_start(cell_renderer, True)
         name_column.add_attribute(cell_renderer, 'text', 0)
-        self.window.show_all()
 
         # setup the treeselection
         self.fonts_treeview_selection = self.fonts_treeview.get_selection()
@@ -170,7 +176,7 @@
         self.fonts_treeview_selection.connect('changed', self.update_ui_sensitivity)
 
         # setup interaction
-        self.fonts_treeview.connect('row-activated', self.on_row_activated)
+        self.fonts_treeview.connect('row-activated', self.on_fonts_treeview_row_activated)
 
         # populate the treemodel with all available fonts
         context = self.window.get_pango_context()
@@ -180,32 +186,37 @@
     def load_fonts_cb(self, user_data=None):
         'Idle callback that adds font families to the tree model'
 
-        howmany_at_once = 25
+        # loading is done when the list of remaining families is empty
+        if len(self.families) == 0:
+            return False
 
-        try:
-            # speed up insertion
-            self.fonts_treeview.freeze_child_notify()
+        howmany_at_once = 50
+
+        model = self.fonts_treeview.get_model()
+        self.fonts_treeview.set_model(None);
 
-            # add a bunch of fonts and faces to the treemodel
-            for i in range(howmany_at_once):
-                family = self.families.pop(-1)
-                piter = self.fonts_treestore.append(None,
-                        [family.get_name(), family, None])
-                for face in family.list_faces():
-                    self.fonts_treestore.append(piter,
-                            [face.get_face_name(), family, face])
-
-            # thaw the treeview
-            self.fonts_treeview.thaw_child_notify()
-
-            # scroll to the top, since the treeview may have scrolled after all
-            # the insertions
-            self.fonts_treeview_window.set_vadjustment(gtk.Adjustment(0))
+        # add a bunch of fonts and faces to the treemodel
+        for i in range(min(howmany_at_once, len(self.families))):
+            family = self.families.pop(-1)
+            piter = self.fonts_treestore.append(None,
+                    [family.get_name(), family, None, True])
+            for face in family.list_faces():
+                self.fonts_treestore.append(piter,
+                        [face.get_face_name(), family, face, True])
+
+        self.fonts_treeview.set_model(model);
+
+        # scroll to the top, since the treeview may have scrolled after all
+        # the insertions
+        self.fonts_treeview_window.set_vadjustment(gtk.Adjustment(0))
+
+        # the user may have typed something in the find bar while the
+        # listing was still being loaded. Make sure the filter is correct at
+        # all times.
+        self.update_find_filter()
 
-            return True
-        except (IndexError):
-            # loading is done; the list of remaining families is empty
-            return False
+        # run again
+        return True
 
     def font_name_sort(self, model, iter1, iter2, user_data=None):
         'Sorting function for the font listing'
@@ -252,6 +263,54 @@
                     # regular string comparison.
                     return cmp(name1, name2)
 
+    
+    # font finding
+
+    def start_find(self):
+        self.find_controls.show_all()
+        self.find_entry.grab_focus()
+
+        # force update when the find bar is closed while it had text in the
+        # entry and opened again (the filtered view should be restored)
+        self.find_entry.emit('changed')
+
+    def stop_find(self):
+        self.remove_find_filter()
+        self.find_controls.hide()
+
+    def cancel_find_cb(self, button, data=None):
+        self.stop_find()
+
+    def update_find_filter(self):
+        filter = self.find_entry.get_text().strip().lower()
+        if not filter:
+            self.remove_find_filter()
+            return
+
+        # set row visibility; temporarily unlink model for speed
+        model = self.fonts_treeview.get_model();
+        self.fonts_treeview.set_model(None);
+        for row in self.fonts_treestore: row[3] = filter in row[0].lower()
+        self.fonts_treeview.set_model(model);
+
+    def remove_find_filter(self):
+        # set all rows to visible; temporarily unlink model for speed
+        model = self.fonts_treeview.get_model();
+        self.fonts_treeview.set_model(None);
+        for row in self.fonts_treestore: row[3] = True
+        self.fonts_treeview.set_model(model);
+
+    def on_find_entry_changed(self, entry, data=None):
+        self.update_find_filter()
+
+    def on_find_entry_activated(self, entry, data=None):
+        '''Callback for Enter key in the find entry.'''
+
+        # select first row, if any
+        if len(self.fonts_treemodelfilter) > 0:
+            self.fonts_treeview.get_selection().select_path((0,))
+            self.fonts_treeview.grab_focus()
+
 
     # previews
 
@@ -276,7 +335,6 @@
         cell_renderer = gtk.CellRendererText()
         self.previews_preview_column.pack_start(cell_renderer, True)
         self.previews_preview_column.set_cell_data_func(cell_renderer, self.cell_data_cb)
-        self.window.show_all()
 
         # setup the treeselection
         self.previews_treeview_selection = self.previews_treeview.get_selection()
@@ -437,7 +495,7 @@
 
         self.update_ui_sensitivity()
 
-    def on_row_activated(self, treeview, path, viewcolumn, *user_data):
+    def on_fonts_treeview_row_activated(self, treeview, path, viewcolumn, *user_data):
         self.add_preview_from_path(path)
 
     def increase_preview_size(self):
@@ -497,23 +555,31 @@
         # Propagate further in all other cases
         return False
 
-    def on_main_window_key_press_event(self, treeview, event, data=None):
+    def on_main_window_key_press_event(self, window, event, data=None):
         '''Change the preview size when a keyboard shortcut for zooming
         (Control-Plus or Control-Minus) is pressed.'''
 
-        # Only act if the Control key is pressed
+        # Searching: / and Escape
+        if event.keyval == gtk.keysyms.Escape:
+            self.stop_find()
+            return True
+        if event.keyval == gtk.keysyms.slash:
+            self.start_find()
+            return True
+
+        # Keyboard shortcuts with control key pressed
         if event.state & gtk.gdk.CONTROL_MASK:
             if event.keyval in (gtk.keysyms.plus, gtk.keysyms.equal, gtk.keysyms.KP_Add):
                 self.increase_preview_size()
+                return True
             elif event.keyval in (gtk.keysyms.minus, gtk.keysyms.underscore, gtk.keysyms.KP_Subtract):
                 self.decrease_preview_size()
-
-            # We handled this event
-            return True
+                return True
 
         # Propagate further in all other cases
         return False
 
+
     # preview colors
 
     def set_colors(self, fgcolor, bgcolor):
@@ -677,6 +743,10 @@
         'Callback for the Edit->Clear menu item'
         self.clear_previews()
 
+    def on_find_item_activate(self, widget, data=None):
+        'Callback for the Edit->Find menu item'
+        self.start_find()
+
     def on_change_colors_item_activate(self, widget, data=None):
         'Callback for the Edit->Change Colors menu item'
         self.show_colors_dialog()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]