116. How to filter by file type in GtkFileChooser using GtkFileFilter?

Problem

You want to allow user to filter by file type (e.g. listing only HTML files or image files) when selecting a file using GtkFileChooser as shown below:

How to filter by file type in GtkFileChooser using GtkFileFilter?


Solution


Sample Code

1   
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
16   
17   
18   
19   
21   
22   
23   
24   
25   
26   
28   
29   
32   
33   
34   
35   
36   
37   
38   
39   
40   
41   
42   
43   
44   
46   
47   
48   
52   
53   
54   
55   
56   
57   
58   
59   
60   
62   
63   
64   
65   
66   
68   
69   
70   
71   
72   
73   
74   
75   
76   
77   
78   
79   
80   
81   
82   
83   
84   
87   
89   
90   
91   
92   
93   
94   
100   
101   
102   
103   
107   
108   
109   
111   
112   
113   
114   
115   
116   
117   
118   
119   
120   
121   
123   
124   
125   
126   
127   
128   
129   
130   
131   
132   
133   
134   
135   
138   
139   
140   
146   
147   
149   
151   
152   
153   
154   
155   
156   
158   
165   
166   
167   
169   
170   
174   
175   
176   
177   
178   
179   
181   
184   
185   
191   
192   
193   
194   
195   
196   
197   
198   
199   
200   
201   
202   
203   
204   
211   
212   
213   
214   
215   
216   
217   
218   
219   
220   
221   
222   
223   
224   
225   
226   
227   
228   
229   
230   
231   
232   
233   
234   
235   
236   
237   
238   
239   
240   
241   
242   
243   
244   
245   
246   
247   
248   
249   
250   
251   
252   
256   
257   
258   
260   
261   
262   
263   
264   
266   
267   
268   
<?php
$window = new GtkWindow();
$window->set_size_request(400, 150);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->add($vbox = new GtkVBox());
$accel_group = new GtkAccelGroup();
$window->add_accel_group($accel_group);

// define menu definition
$menu_definition = array(
    '_File' => array('_New|N', '_Open|O', '_Close|C', '<hr>',
        '_Save|S', 'Save _As','<hr>', 'E_xit'),
    '_Edit' => array('Cu_t|X', '_Copy|C', '_Paste|V', '<hr>',
        'Select _All|A', '<hr>', '_Undo|Z','_Redo|Y'),
    '_Test' => array('Test_1|1', 'Test_2|2', 'Test_3|3', '<hr>',
                array('Selection 1', 'Selection 2', 'Selection 3'),
                '<hr>', 'Test_4|4')
);
$menu = new Menu($vbox, $menu_definition, $accel_group);

// display title
$title = new GtkLabel("         Open a file with GtkFileChooser".
"with filter by file type using GtkFileFilter");
$title->modify_font(new PangoFontDescription("Times New Roman Italic 10"));
$title->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#0000ff"));
$vbox->pack_start($title);
$vbox->pack_start(new GtkLabel("Press Ctrl-O to open the file chooser"));
$vbox->pack_start(new GtkLabel(""));

$window->show_all();
Gtk::main();

// class Menu
class Menu {
    var $prev_keyval = 0;
    var $prev_state = 0;
    var $prev_keypress = '';
    function Menu($vbox, $menu_definition, $accel_group) {
        $this->menu_definition = $menu_definition;
        $menubar = new GtkMenuBar();
        $vbox->pack_start($menubar, 0, 0);
        foreach($menu_definition as $toplevel => $sublevels) {
            $top_menu = new GtkMenuItem($toplevel);
            $menubar->append($top_menu);
            $menu = new GtkMenu();
            $top_menu->set_submenu($menu);

            // let's ask php-gtk to tell us when user press the 2nd Alt key
            $menu->connect('key-press-event',
                array(&$this, 'on_menu_keypress'), $toplevel);

            foreach($sublevels as $submenu) {
                if (strpos("$submenu", '|') === false) {
                    $accel_key = '';
                } else {
                    list($submenu, $accel_key) = explode('|', $submenu);
                }

                if (is_array($submenu)) { // set up radio menus
                    $i=0;
                    $radio[0] = null;
                    foreach($submenu as $radio_item) {
                        $radio[$i] = new GtkRadioMenuItem($radio[0], $radio_item);
                        $radio[$i]->connect('toggled', array(&$this, "on_toggle"));
                        $menu->append($radio[$i]);
                        ++$i;
                    }
                    $radio[0]->set_active(1); // select the first item
                } else {
                    if ($submenu=='<hr>') {
                        $menu->append(new GtkSeparatorMenuItem());
                    } else {
                        $submenu2 = str_replace('_', '', $submenu);
                        $submenu2 = str_replace(' ', '_', $submenu2);
                        $stock_image_name = 'Gtk::STOCK_'.strtoupper($submenu2);
                        if (defined($stock_image_name)) {
                            $menu_item = new GtkImageMenuItem(
                                constant($stock_image_name));
                        } else {
                            $menu_item = new GtkMenuItem($submenu);
                        }
                        if ($accel_key!='') {
                            $menu_item->add_accelerator("activate",
                                $accel_group, ord($accel_key), Gdk::CONTROL_MASK, 1);
                        }

                        $menu->append($menu_item);
                        $menu_item->connect('activate', array(&$this, 'on_menu_select'));
                        $this->menuitem[$toplevel][$submenu] = $menu_item;
                    }
                }
            }
        }
    }

    // process radio menu selection
    function on_toggle($radio) {
        $label = $radio->child->get_label();
        $active = $radio->get_active();
        echo("radio menu selected: $label\n");
    }

    // process menu item selection
    function on_menu_select($menu_item) {
        $item = $menu_item->child->get_label();
        echo "menu selected: $item\n";
        if (method_exists($this, $item)) $this->$item();
        if ($item=='E_xit') Gtk::main_quit();
    }

    // let user choose a file with a file chooser dialog
    function _Open() {
        file_open();
    }

    // processing of menu keypress
    function on_menu_keypress($menu, $event, $toplevel) {
        if (!$event->state & Gdk::MOD1_MASK) return false;

        // get the ascii equivalent of the keypress
        $keypress = '';
        if ($event->keyval<255) {
            $keypress = chr($event->keyval); // ascii equivalent
            $keypress = strtolower($keypress); // convert to lowercase
        }

        $match = 0; // flag to see if there's a match
        foreach($this->menu_definition[$toplevel] as $submenu) {
            if (!preg_match("/.*_([a-zA-Z0-9]).*/", "$submenu", $matches)) continue;
            $key2 = strtolower($matches[1]);
            if ($keypress==$key2) {
                if (strpos("$submenu", '|') === false) {
                    $accel_key = '';
                } else {
                    list($submenu, $accel_key) = explode('|', $submenu);
                }
                $menuitem = $this->menuitem[$toplevel][$submenu];
                $menuitem->activate();
                $menu->popdown();
                $match = 1;
                break;
            }
        }
        return $match;
    }

}

function file_open() {
    global $dialog;
    $dialog = new GtkFileChooserDialog("File Open", null,
        Gtk::FILE_CHOOSER_ACTION_OPEN,
        array(Gtk::STOCK_OK, Gtk::RESPONSE_OK), null);
    $hbox = new GtkHBox();
    $dialog->vbox->pack_start($hbox, 0, 0);
    $hbox->pack_start(new GtkLabel('File type:'), 0, 0);

    // create a combobox listing the available filter options
    $combobox = &GtkComboBoxEntry::new_text(); 
// note 1
    $combobox->append_text("All Files");
    $combobox->append_text("Text Files");
    $combobox->append_text("HTML Files");
    $combobox->append_text("PHP Files");
    $combobox->append_text("Image Files");
    $combobox->get_child()->set_text('All Files');
    $combobox->connect('changed', 'on_change_filter'); 
// note 2
    

    $hbox->pack_start($combobox, 0, 0);

    $dialog->show_all();
    if ($dialog->run() == Gtk::RESPONSE_OK) {
        $selected_file = $dialog->get_filename(); // get the selected filename
        echo "selected_file = $selected_file\n";
    }
    $dialog->destroy();
}

function on_change_filter($combobox) {
    $model = $combobox->get_model(); // get the model
    $selected_value = $model->get_value(
        $combobox->get_active_iter(), 0);// note 3
    echo "selected_value = $selected_value\n";
    $filter = new GtkFileFilter(); // note 4
    switch($selected_value) { // note 5
        case 'All Files':
            $filter->add_pattern("*"); // note 5
            break;
        case 'Text Files':
            $filter->add_pattern("*.txt"); // note 5
            break;
        case 'HTML Files':
            $filter->add_mime_type("text/html"); // note 5
            break;
        case 'PHP Files':
            $filter->add_pattern("*.php"); // note 5
            break;
        case 'Image Files';
            $filter->add_pixbuf_formats(); // note 5
            break;
    }

    global $dialog;
    $dialog->set_filter($filter); // note 6

}
?>

Output

As shown above.

 

Explanation

This example makes use of the code in the article How to open a file with GtkFileChooser? to set up the menu and display a FileChooser dialog.

What's new here:

  1. Create a combobox and insert all the available filter options.
  2. Call the function on_change_filter() when user selects a filter.
  3. Get user selection.
  4. Create a new file filter.
  5. Set the filter accordingly. Note the three different ways of setting file filters.
  6. Go ahead and filter the files!

Related Links

Add comment


Security code
Refresh