Fix #624: Filter files by shell or regular expression pattern
authorColin Clark <colin.clark@cclark.uk>
Wed, 15 Aug 2018 18:43:06 +0000 (19:43 +0100)
committerColin Clark <colin.clark@cclark.uk>
Wed, 15 Aug 2018 18:43:06 +0000 (19:43 +0100)
https://github.com/BestImageViewer/geeqie/issues/624

An option on Select/Show File Filter (or the toolbar) to provide regular
expression file-filtering of the currently displayed folder.

19 files changed:
doc/docbook/GuideMainWindowFilePane.xml
src/filedata.c
src/filedata.h
src/icons/Makefile.am
src/icons/icon_file_filter.png [new file with mode: 0644]
src/layout.c
src/layout.h
src/layout_util.c
src/layout_util.h
src/options.c
src/pixbuf_util.c
src/pixbuf_util.h
src/toolbar.c
src/typedefs.h
src/view_file.h
src/view_file/view_file.c
src/view_file/view_file_icon.c
src/view_file/view_file_list.c
web/help/GuideMainWindowFilePane.html

index fc86303..98b2493 100644 (file)
     </para>\r
     <para />\r
   </section>\r
+  <section id="Filefilter">\r
+    <title id="titleFilefilter">File Filter</title>\r
+    <para>\r
+      A filter box can be opened by selecting\r
+      <emphasis role="bold">Show File Filter</emphasis>\r
+      from the View menu.\r
+    </para>\r
+    <para>\r
+      Characters you type into this box will be used for pattern matching to select the files displayed.\r
+      <link linkend="GuideReferencePCRE">Regular expressions</link>\r
+      are used in this field.\r
+      <para />\r
+      For basic pattern matching "JPG" will match any filename containing those characters.\r
+      <para />\r
+      To make a case-insensitive search, use "(?i)JPG"\r
+      <para />\r
+      If you type a newline, the text will be saved in the dropdown box list. The last 10 items are saved.\r
+    </para>\r
+    <para />\r
+  </section>\r
   <section id="Multipleselection">\r
     <title>Multiple selection</title>\r
     <para>It is possible to select more than one image from the file pane. Multiple files can be selected with several methods:</para>\r
index 0461755..af6e59d 100644 (file)
@@ -1817,6 +1817,33 @@ GList *file_data_filter_marks_list(GList *list, guint filter)
        return list;
 }
 
+gboolean file_data_filter_file_filter(FileData *fd, GRegex *filter)
+{
+       return g_regex_match(filter, fd->name, 0, NULL);
+}
+
+GList *file_data_filter_file_filter_list(GList *list, GRegex *filter)
+{
+       GList *work;
+
+       work = list;
+       while (work)
+               {
+               FileData *fd = work->data;
+               GList *link = work;
+               work = work->next;
+
+               if (!file_data_filter_file_filter(fd, filter))
+                       {
+                       list = g_list_remove_link(list, link);
+                       file_data_unref(fd);
+                       g_list_free(link);
+                       }
+               }
+
+       return list;
+}
+
 static void file_data_notify_mark_func(gpointer key, gpointer value, gpointer user_data)
 {
        FileData *fd = value;
index 1b4e097..878bbb9 100644 (file)
@@ -99,6 +99,9 @@ void file_data_set_mark(FileData *fd, gint n, gboolean value);
 gboolean file_data_filter_marks(FileData *fd, guint filter);
 GList *file_data_filter_marks_list(GList *list, guint filter);
 
+gboolean file_data_filter_file_filter(FileData *fd, GRegex *filter);
+GList *file_data_filter_file_filter_list(GList *list, GRegex *filter);
+
 gint file_data_get_user_orientation(FileData *fd);
 void file_data_set_user_orientation(FileData *fd, gint value);
 
index dcca29f..589b269 100644 (file)
@@ -39,7 +39,8 @@ ICONS_INLINE = \
        icon_select_all.png \
        icon_select_none.png \
        icon_select_invert.png \
-       icon_select_rectangle.png
+       icon_select_rectangle.png \
+       icon_file_filter.png
 
 
 ICONS_INLINE_PAIRS = \
@@ -78,7 +79,8 @@ ICONS_INLINE_PAIRS = \
        icon_select_all $(srcdir)/icon_select_all.png \
        icon_select_none        $(srcdir)/icon_select_none.png \
        icon_select_invert      $(srcdir)/icon_select_invert.png \
-       icon_select_rectangle   $(srcdir)/icon_select_rectangle.png
+       icon_select_rectangle   $(srcdir)/icon_select_rectangle.png \
+       icon_file_filter        $(srcdir)/icon_file_filter.png
 
 icons_inline.h: $(ICONS_INLINE) Makefile.in
        @sh -ec "echo '/* Auto generated file, do not edit */'; echo; \
diff --git a/src/icons/icon_file_filter.png b/src/icons/icon_file_filter.png
new file mode 100644 (file)
index 0000000..321c7cc
Binary files /dev/null and b/src/icons/icon_file_filter.png differ
index 14ae251..5006241 100644 (file)
@@ -862,6 +862,11 @@ static void layout_list_sync_thumb(LayoutWindow *lw)
        if (lw->vf) vf_thumb_set(lw->vf, lw->options.show_thumbnails);
 }
 
+static void layout_list_sync_file_filter(LayoutWindow *lw)
+{
+       if (lw->vf) vf_file_filter_set(lw->vf, lw->options.show_file_filter);
+}
+
 static GtkWidget *layout_list_new(LayoutWindow *lw)
 {
        lw->vf = vf_new(lw->options.file_view_type, NULL);
@@ -873,6 +878,7 @@ static GtkWidget *layout_list_new(LayoutWindow *lw)
        vf_marks_set(lw->vf, lw->options.show_marks);
 
        layout_list_sync_thumb(lw);
+       layout_list_sync_file_filter(lw);
 
        return lw->vf->widget;
 }
@@ -1178,6 +1184,18 @@ void layout_thumb_set(LayoutWindow *lw, gboolean enable)
        layout_list_sync_thumb(lw);
 }
 
+void layout_file_filter_set(LayoutWindow *lw, gboolean enable)
+{
+       if (!layout_valid(&lw)) return;
+
+       if (lw->options.show_file_filter == enable) return;
+
+       lw->options.show_file_filter = enable;
+
+       layout_util_sync_file_filter(lw);
+       layout_list_sync_file_filter(lw);
+}
+
 void layout_marks_set(LayoutWindow *lw, gboolean enable)
 {
        if (!layout_valid(&lw)) return;
@@ -2476,6 +2494,7 @@ void layout_write_attributes(LayoutOptions *layout, GString *outstr, gint indent
        WRITE_NL(); WRITE_UINT(*layout, dir_view_type);
        WRITE_NL(); WRITE_UINT(*layout, file_view_type);
        WRITE_NL(); WRITE_BOOL(*layout, show_marks);
+       WRITE_NL(); WRITE_BOOL(*layout, show_file_filter);
        WRITE_NL(); WRITE_BOOL(*layout, show_thumbnails);
        WRITE_NL(); WRITE_BOOL(*layout, show_directory_date);
        WRITE_NL(); WRITE_CHAR(*layout, home_path);
@@ -2565,6 +2584,7 @@ void layout_load_attributes(LayoutOptions *layout, const gchar **attribute_names
                if (READ_UINT(*layout, dir_view_type)) continue;
                if (READ_UINT(*layout, file_view_type)) continue;
                if (READ_BOOL(*layout, show_marks)) continue;
+               if (READ_BOOL(*layout, show_file_filter)) continue;
                if (READ_BOOL(*layout, show_thumbnails)) continue;
                if (READ_BOOL(*layout, show_directory_date)) continue;
                if (READ_CHAR(*layout, home_path)) continue;
index 61f68c3..2b33843 100644 (file)
@@ -89,6 +89,8 @@ gboolean layout_thumb_get(LayoutWindow *lw);
 void layout_marks_set(LayoutWindow *lw, gboolean enable);
 gboolean layout_marks_get(LayoutWindow *lw);
 
+void layout_file_filter_set(LayoutWindow *lw, gboolean enable);
+
 void layout_sort_set(LayoutWindow *lw, SortType type, gboolean ascend);
 gboolean layout_sort_get(LayoutWindow *lw, SortType *type, gboolean *ascend);
 
index ca78abc..cf1cf46 100644 (file)
@@ -117,6 +117,15 @@ gboolean layout_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
                        return TRUE;
                        }
                }
+
+       if (lw->vf->file_filter_combo && gtk_widget_has_focus(gtk_bin_get_child(GTK_BIN(lw->vf->file_filter_combo))))
+               {
+               if (gtk_widget_event(gtk_bin_get_child(GTK_BIN(lw->vf->file_filter_combo)), (GdkEvent *)event))
+                       {
+                       return TRUE;
+                       }
+               }
+
        if (lw->vd && lw->options.dir_view_type == DIRVIEW_TREE && gtk_widget_has_focus(lw->vd->view) &&
            !layout_key_match(event->keyval) &&
            gtk_widget_event(lw->vd->view, (GdkEvent *)event))
@@ -1387,6 +1396,13 @@ static void layout_menu_invert_selection_cb(GtkAction *action, gpointer data)
        layout_select_invert(lw);
 }
 
+static void layout_menu_file_filter_cb(GtkToggleAction *action, gpointer data)
+{
+       LayoutWindow *lw = data;
+
+       layout_file_filter_set(lw, gtk_toggle_action_get_active(action));
+}
+
 static void layout_menu_marks_cb(GtkToggleAction *action, gpointer data)
 {
        LayoutWindow *lw = data;
@@ -1940,6 +1956,7 @@ static GtkActionEntry menu_entries[] = {
 static GtkToggleActionEntry menu_toggle_entries[] = {
   { "Thumbnails",      PIXBUF_INLINE_ICON_THUMB,N_("Show _Thumbnails"),                "T",                    N_("Show Thumbnails"),                  CB(layout_menu_thumb_cb),        FALSE },
   { "ShowMarks",        PIXBUF_INLINE_ICON_MARKS,      N_("Show _Marks"),                      "M",                    N_("Show Marks"),                       CB(layout_menu_marks_cb),        FALSE  },
+  { "ShowFileFilter", PIXBUF_INLINE_ICON_FILE_FILTER,  N_("Show File Filter"), NULL,   N_("Show File Filter"), CB(layout_menu_file_filter_cb),  FALSE  },
   { "ShowInfoPixel",   GTK_STOCK_COLOR_PICKER, N_("Pi_xel Info"),                      NULL,                   N_("Show Pixel Info"),                  CB(layout_menu_info_pixel_cb),   FALSE  },
   { "FloatTools",      PIXBUF_INLINE_ICON_FLOAT,N_("_Float file list"),                "L",                    N_("Float file list"),                  CB(layout_menu_float_cb),        FALSE  },
   { "HideToolbar",     NULL,                   N_("Hide tool_bar"),                    NULL,                   N_("Hide toolbar"),                     CB(layout_menu_toolbar_cb),      FALSE  },
@@ -2053,6 +2070,7 @@ static const gchar *menu_ui_description =
 "      <menuitem action='SelectNone'/>"
 "      <menuitem action='SelectInvert'/>"
 "      <menuitem action='RectangularSelection'/>"
+"      <menuitem action='ShowFileFilter'/>"
 "      <placeholder name='SelectSection'/>"
 "      <separator/>"
 "      <menuitem action='CopyPath'/>"
@@ -3004,6 +3022,16 @@ void layout_util_sync_color(LayoutWindow *lw)
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_get_desaturate(lw));
 }
 
+void layout_util_sync_file_filter(LayoutWindow *lw)
+{
+       GtkAction *action;
+
+       if (!lw->action_group) return;
+
+       action = gtk_action_group_get_action(lw->action_group, "ShowFileFilter");
+       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_file_filter);
+}
+
 void layout_util_sync_marks(LayoutWindow *lw)
 {
        GtkAction *action;
@@ -3078,6 +3106,9 @@ static void layout_util_sync_views(LayoutWindow *lw)
        action = gtk_action_group_get_action(lw->action_group, "RectangularSelection");
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->collections.rectangular_selection);
 
+       action = gtk_action_group_get_action(lw->action_group, "ShowFileFilter");
+       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_file_filter);
+
        if (osd_flags & OSD_SHOW_HISTOGRAM)
                {
                action = gtk_action_group_get_action(lw->action_group, "HistogramChanR");
index 49f3642..c2a4d3a 100644 (file)
@@ -29,6 +29,7 @@ gboolean layout_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
 
 void layout_util_sync_thumb(LayoutWindow *lw);
 void layout_util_sync_marks(LayoutWindow *lw);
+void layout_util_sync_file_filter(LayoutWindow *lw);
 void layout_util_sync_color(LayoutWindow *lw);
 void layout_util_sync(LayoutWindow *lw);
 
index e7d1f0d..ff98542 100644 (file)
@@ -273,6 +273,7 @@ LayoutOptions *init_layout_options(LayoutOptions *options)
        options->order = g_strdup("123");
        options->show_directory_date = FALSE;
        options->show_marks = FALSE;
+       options->show_file_filter = FALSE;
        options->show_thumbnails = FALSE;
        options->style = 0;
        options->show_info_pixel = FALSE;
index c694158..f32e110 100644 (file)
@@ -138,6 +138,7 @@ static PixbufInline inline_pixbuf_data[] = {
        { PIXBUF_INLINE_ICON_SELECT_NONE,       icon_select_none },
        { PIXBUF_INLINE_ICON_SELECT_INVERT,     icon_select_invert },
        { PIXBUF_INLINE_ICON_SELECT_RECTANGLE,  icon_select_rectangle },
+       { PIXBUF_INLINE_ICON_FILE_FILTER,       icon_file_filter },
        { NULL, NULL }
 };
 
index cfa8ffc..fe124fb 100644 (file)
@@ -72,6 +72,7 @@ gboolean pixbuf_scale_aspect(gint req_w, gint req_h, gint old_w, gint old_h, gin
 #define PIXBUF_INLINE_ICON_SELECT_NONE "icon_select_none"
 #define PIXBUF_INLINE_ICON_SELECT_INVERT       "icon_select_invert"
 #define PIXBUF_INLINE_ICON_SELECT_RECTANGLE    "icon_select_rectangle"
+#define PIXBUF_INLINE_ICON_FILE_FILTER "icon_file_filter"
 
 GdkPixbuf *pixbuf_copy_rotate_90(GdkPixbuf *src, gboolean counter_clockwise);
 GdkPixbuf *pixbuf_copy_mirror(GdkPixbuf *src, gboolean mirror, gboolean flip);
index 2a6d913..008fafe 100644 (file)
@@ -94,6 +94,7 @@ static const UseableToolbarItems useable_toolbar_items[] = {
        {"SelectAll",   N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
        {"SelectNone",  N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
        {"SelectInvert",        N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
+       {"ShowFileFilter",      N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
        {"RectangularSelection",        N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
        {"Print",       N_("Print"), GTK_STOCK_PRINT},
        {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
index 9d9d985..1217eac 100644 (file)
@@ -619,6 +619,7 @@ struct _LayoutOptions
 
        gboolean show_thumbnails;
        gboolean show_marks;
+       gboolean show_file_filter;
        gboolean show_directory_date;
        gboolean show_info_pixel;
 
@@ -861,6 +862,8 @@ struct _ViewFile
        GtkWidget *scrolled;
        GtkWidget *filter;
        GtkWidget *filter_check[FILEDATA_MARKS_SIZE];
+       GtkWidget *file_filter_combo;
+       GtkWidget *file_filter_frame;
 
        FileData *dir_fd;
        GList *list;
index 4802589..ec9dff8 100644 (file)
@@ -74,5 +74,7 @@ void vf_thumb_update(ViewFile *vf);
 void vf_thumb_cleanup(ViewFile *vf);
 void vf_thumb_stop(ViewFile *vf);
 void vf_read_metadata_in_idle(ViewFile *vf);
+void vf_file_filter_set(ViewFile *vf, gboolean enable);
+GRegex *vf_file_filter_get_filter(ViewFile *vf);
 #endif /* VIEW_FILE_H */
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index c4da36b..1532450 100644 (file)
@@ -25,6 +25,7 @@
 #include "collect.h"
 #include "collect-table.h"
 #include "editors.h"
+#include "history_list.h"
 #include "layout.h"
 #include "menu.h"
 #include "thumb.h"
@@ -844,6 +845,35 @@ static gboolean vf_marks_tooltip_cb(GtkWidget *widget,
        return FALSE;
 }
 
+static void vf_file_filter_save_cb(GtkWidget *widget, gpointer data)
+{
+       ViewFile *vf = data;
+       gchar *entry_text;
+
+       entry_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(vf->file_filter_combo)))));
+
+       history_list_add_to_key("file_filter", entry_text, 10);
+
+       vf_refresh(vf);
+
+       g_free(entry_text);
+}
+
+static void vf_file_filter_cb(GtkWidget *widget, gpointer data)
+{
+       ViewFile *vf = data;
+
+       vf_refresh(vf);
+}
+
+static gboolean vf_file_filter_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+{
+       ViewFile *vf = data;
+
+       gtk_widget_grab_focus(widget);
+
+       return TRUE;
+}
 
 static GtkWidget *vf_marks_filter_init(ViewFile *vf)
 {
@@ -870,6 +900,61 @@ static GtkWidget *vf_marks_filter_init(ViewFile *vf)
        return frame;
 }
 
+void vf_file_filter_set(ViewFile *vf, gboolean enable)
+{
+       if (enable)
+               {
+               gtk_widget_show(vf->file_filter_combo);
+               gtk_widget_show(vf->file_filter_frame);
+               }
+       else
+               {
+               gtk_widget_hide(vf->file_filter_combo);
+               gtk_widget_hide(vf->file_filter_frame);
+               }
+
+       vf_refresh(vf);
+}
+
+static GtkWidget *vf_file_filter_init(ViewFile *vf)
+{
+       GtkWidget *frame = gtk_frame_new(NULL);
+       GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
+       GList *work;
+       gint n = 0;
+       GtkWidget *combo_entry;
+
+       vf->file_filter_combo = gtk_combo_box_text_new_with_entry();
+       combo_entry = gtk_bin_get_child(GTK_BIN(vf->file_filter_combo));
+       gtk_widget_show(gtk_bin_get_child(GTK_BIN(vf->file_filter_combo)));
+       gtk_widget_show((GTK_WIDGET(vf->file_filter_combo)));
+
+       work = history_list_get_by_key("file_filter");
+       while (work)
+               {
+               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(vf->file_filter_combo), (gchar *)work->data);
+               work = work->next;
+               n++;
+               }
+       gtk_combo_box_set_active(GTK_COMBO_BOX(vf->file_filter_combo), 0);
+
+       g_signal_connect(G_OBJECT(combo_entry), "activate",
+               G_CALLBACK(vf_file_filter_save_cb), vf);
+               
+       g_signal_connect(G_OBJECT(vf->file_filter_combo), "changed",
+               G_CALLBACK(vf_file_filter_cb), vf);
+
+       g_signal_connect(G_OBJECT(combo_entry), "button_press_event",
+                        G_CALLBACK(vf_file_filter_press_cb), vf);
+
+       gtk_box_pack_start(GTK_BOX(hbox), vf->file_filter_combo, FALSE, FALSE, 0);
+       gtk_widget_show(vf->file_filter_combo);
+       gtk_container_add(GTK_CONTAINER(frame), hbox);
+       gtk_widget_show(hbox);
+
+       return frame;
+}
+
 void vf_mark_filter_toggle(ViewFile *vf, gint mark)
 {
        gint n = mark - 1;
@@ -894,9 +979,11 @@ ViewFile *vf_new(FileViewType type, FileData *dir_fd)
                                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
        vf->filter = vf_marks_filter_init(vf);
+       vf->file_filter_frame = vf_file_filter_init(vf);
 
        vf->widget = gtk_vbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(vf->widget), vf->filter, FALSE, FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(vf->widget), vf->file_filter_frame, FALSE, FALSE, 0);
        gtk_box_pack_start(GTK_BOX(vf->widget), vf->scrolled, TRUE, TRUE, 0);
        gtk_widget_show(vf->scrolled);
 
@@ -1171,6 +1258,39 @@ guint vf_marks_get_filter(ViewFile *vf)
        return ret;
 }
 
+GRegex *vf_file_filter_get_filter(ViewFile *vf)
+{
+       GRegex *ret = NULL;
+       GError *error = NULL;
+       gchar *file_filter_text = NULL;
+
+       if (!gtk_widget_get_visible(vf->file_filter_combo))
+               {
+               return g_regex_new("", 0, 0, NULL);
+               }
+
+       file_filter_text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(vf->file_filter_combo));
+
+       if (file_filter_text[0] != '\0')
+               {
+               ret = g_regex_new(file_filter_text, 0, 0, &error);
+               if (error)
+                       {
+                       log_printf("Error: could not compile regular expression %s\n%s\n", file_filter_text, error->message);
+                       g_error_free(error);
+                       error = NULL;
+                       ret = g_regex_new("", 0, 0, NULL);
+                       }
+               g_free(file_filter_text);
+               }
+       else
+               {
+               ret = g_regex_new("", 0, 0, NULL);
+               }
+
+       return ret;
+}
+
 void vf_set_layout(ViewFile *vf, LayoutWindow *layout)
 {
        vf->layout = layout;
index 210af6c..866e342 100644 (file)
@@ -1842,6 +1842,8 @@ static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
                {
                ret = filelist_read(vf->dir_fd, &new_filelist, NULL);
                new_filelist = file_data_filter_marks_list(new_filelist, vf_marks_get_filter(vf));
+               new_filelist = g_list_first(new_filelist);
+               new_filelist = file_data_filter_file_filter_list(new_filelist, vf_file_filter_get_filter(vf));
                }
 
        vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend); /* the list might not be sorted if there were renames */
index 168bf57..b50abe7 100644 (file)
@@ -1801,6 +1801,8 @@ gboolean vflist_refresh(ViewFile *vf)
                        }
 
                vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
+               vf->list = g_list_first(vf->list);
+               vf->list = file_data_filter_file_filter_list(vf->list, vf_file_filter_get_filter(vf));
                file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
 
                DEBUG_1("%s vflist_refresh: sort", get_exec_time());
index 9d29445..6b062e2 100644 (file)
@@ -468,16 +468,19 @@ dd.answer div.label { float: left; }
 <span class="label">2.1.2. </span><a class="xref" href="GuideMainWindowFilePane.html#Iconview" title="Icon view">Icon view</a>
 </li>
 <li>
-<span class="label">2.1.3. </span><a class="xref" href="GuideMainWindowFilePane.html#Multipleselection" title="Multiple selection">Multiple selection</a>
+<span class="label">2.1.3. </span><a class="xref" href="GuideMainWindowFilePane.html#Filefilter" title="File Filter">File Filter</a>
 </li>
 <li>
-<span class="label">2.1.4. </span><a class="xref" href="GuideMainWindowFilePane.html#Sorting" title="Sorting">Sorting</a>
+<span class="label">2.1.4. </span><a class="xref" href="GuideMainWindowFilePane.html#Multipleselection" title="Multiple selection">Multiple selection</a>
 </li>
 <li>
-<span class="label">2.1.5. </span><a class="xref" href="GuideMainWindowFilePane.html#Contextmenu" title="Context menu">Context menu</a>
+<span class="label">2.1.5. </span><a class="xref" href="GuideMainWindowFilePane.html#Sorting" title="Sorting">Sorting</a>
 </li>
 <li>
-<span class="label">2.1.6. </span><a class="xref" href="GuideMainWindowFilePane.html#DragandDrop" title="Drag and Drop">Drag and Drop</a>
+<span class="label">2.1.6. </span><a class="xref" href="GuideMainWindowFilePane.html#Contextmenu" title="Context menu">Context menu</a>
+</li>
+<li>
+<span class="label">2.1.7. </span><a class="xref" href="GuideMainWindowFilePane.html#DragandDrop" title="Drag and Drop">Drag and Drop</a>
 </li>
 </ul></div>
 <div class="division section">
@@ -530,19 +533,39 @@ dd.answer div.label { float: left; }
 <p class="para block"></p>
 </div>
 <div class="division section">
-<a name="Multipleselection"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.3. </span>Multiple selection</span></h2></div>
+<a name="Filefilter"></a><div class="header"><h2 class="section title"><span class="title"><a name="titleFilefilter"></a><span class="label">2.1.3. </span>File Filter</span></h2></div>
+<p class="para block block-first">
+      A filter box can be opened by selecting
+      <span class="emphasis emphasis-bold">Show File Filter</span>
+      from the View menu.
+    </p>
+<p class="para block">
+      Characters you type into this box will be used for pattern matching to select the files displayed.
+      <a class="link" href="GuideReferencePCRE.html" title="Perl Compatible Regular Expressions">Regular expressions</a>
+      are used in this field.
+      <p class="para block"></p>
+      For basic pattern matching "JPG" will match any filename containing those characters.
+      <p class="para block"></p>
+      To make a case-insensitive search, use "(?i)JPG"
+      <p class="para block"></p>
+      If you type a newline, the text will be saved in the dropdown box list. The last 10 items are saved.
+    </p>
+<p class="para block"></p>
+</div>
+<div class="division section">
+<a name="Multipleselection"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.4. </span>Multiple selection</span></h2></div>
 <p class="para block block-first">It is possible to select more than one image from the file pane. Multiple files can be selected with several methods:</p>
 <p class="para block"></p>
 <div class="autotoc"><ul>
 <li>
-<span class="label">2.1.3.1. </span><a class="xref" href="GuideMainWindowFilePane.html#Mouse" title="Mouse">Mouse</a>
+<span class="label">2.1.4.1. </span><a class="xref" href="GuideMainWindowFilePane.html#Mouse" title="Mouse">Mouse</a>
 </li>
 <li>
-<span class="label">2.1.3.2. </span><a class="xref" href="GuideMainWindowFilePane.html#Keyboard" title="Keyboard">Keyboard</a>
+<span class="label">2.1.4.2. </span><a class="xref" href="GuideMainWindowFilePane.html#Keyboard" title="Keyboard">Keyboard</a>
 </li>
 </ul></div>
 <div class="division section">
-<a name="Mouse"></a><div class="header"><h3 class="section title"><span class="title"><span class="label">2.1.3.1. </span>Mouse</span></h3></div>
+<a name="Mouse"></a><div class="header"><h3 class="section title"><span class="title"><span class="label">2.1.4.1. </span>Mouse</span></h3></div>
 <div class="block list itemizedlist"><ul class="itemizedlist" compact>
 <li class="li-first">
           <span class="para"><span class="code" dir="ltr">Ctrl</span> + Primary mouse button will add or remove the file from the selection.</span>
@@ -560,7 +583,7 @@ dd.answer div.label { float: left; }
 <p class="para block"></p>
 </div>
 <div class="division section">
-<a name="Keyboard"></a><div class="header"><h3 class="section title"><span class="title"><span class="label">2.1.3.2. </span>Keyboard</span></h3></div>
+<a name="Keyboard"></a><div class="header"><h3 class="section title"><span class="title"><span class="label">2.1.4.2. </span>Keyboard</span></h3></div>
 <div class="block list itemizedlist"><ul class="itemizedlist" compact>
 <li class="li-first">
           <span class="para"><span class="code" dir="ltr">Ctrl + Arrows</span> will move the focus without changing the selection.</span>
@@ -593,13 +616,13 @@ dd.answer div.label { float: left; }
 </div>
 </div>
 <div class="division section">
-<a name="Sorting"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.4. </span>Sorting</span></h2></div>
+<a name="Sorting"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.5. </span>Sorting</span></h2></div>
 <p class="para block block-first">The order of the images can be changed by clicking the sort area of the status bar or from the context menu. The sort methods are by file name, number, file date, or file size. The number method will sort file names by their natural order, for example files with names of file_10, file_12, and file_9 will appear in order file_9, file_10, and file_12.</p>
 <p class="para block">Selecting the ascending menu item will toggle between increasing and decreasing sort order.</p>
 <p class="para block"></p>
 </div>
 <div class="division section">
-<a name="Contextmenu"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.5. </span>Context menu</span></h2></div>
+<a name="Contextmenu"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.6. </span>Context menu</span></h2></div>
 <p class="para block block-first">
       Right clicking the mouse or pressing the menu key while the file pane has focus will display a menu. The menu functions will perform the same as those that match the window's
       <a class="link" href="GuideMainWindowMenus.html" title="Menus">menu bar</a>
@@ -646,7 +669,7 @@ dd.answer div.label { float: left; }
 <p class="para block"></p>
 </div>
 <div class="division section">
-<a name="DragandDrop"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.6. </span>Drag and Drop</span></h2></div>
+<a name="DragandDrop"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.1.7. </span>Drag and Drop</span></h2></div>
 <p class="para block block-first">Drag and drop can be initialized with the primary or middle mouse buttons in the file pane. Dragging a file that is selected will include all selected files in the drag. Dragging a file that is not selected will first change the selection to the dragged file, and clear the previous selection.</p>
 <p class="para block"></p>
 </div>