FileChooser and FileDialog
| Chapter 22. Recently Used Documents |

## FileChooser and FileDialog

`FileChooser` is an interface that can be implemented by widgets displaying a list of files. gtkmm provides three built-in implementations for choosing recent files or other files: `FileChooserWidget`, `FileChooserDialog`, and `FileChooserNative`.

`FileChooserWidget` is a simple widget for displaying a list of recently used files or other files. `FileChooserWidget` is the basic building block for `FileChooserDialog`, but you can embed it into your user interface if you want to.

| Note
`FileChooser` and the classes that implement it are deprecated since gtkmm 4.10. They have been replaced by `FileDialog`, which is available since gtkmm 4.10.

### Simple FileDialog example

Shown below is a simple example of how to use the `FileDialog` class in a program. This simple program has a menubar with a File Dialog menu item. When you select this menu item, a dialog pops up showing a list of files. If you select Recent in the sidebar, the list of recently used files is shown.

| Note
If this is the first time you're using a program that uses the Recent Files framework, the dialog may be empty at first. Otherwise it should show the list of recently used documents registered by other applications.

After selecting the File Dialog menu item and the Recent sidebar item, you should see something similar to the following window.

Source Code

File: `examplewindow.h` (For use with gtkmm 4)

    #ifndef GTKMM_EXAMPLEWINDOW_H
    #define GTKMM_EXAMPLEWINDOW_H

    #include <gtkmm.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow(const Glib::RefPtr<Gtk::Application>& app);
      ~ExampleWindow() override;

    protected:
      //Signal handlers:
      void on_menu_file_files_dialog();
      void on_menu_file_quit();
      void on_menu_file_new();
      void on_dialog_finish(Glib::RefPtr<Gio::AsyncResult>& result);

      //Child widgets:
      Gtk::Box m_Box;

      Glib::RefPtr<Gtk::Builder> m_refBuilder;
      Glib::RefPtr<Gio::SimpleActionGroup> m_refActionGroup;

      Glib::RefPtr<Gtk::RecentManager> m_refRecentManager;
      Glib::RefPtr<Gtk::FileDialog> m_refFileDialog;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `examplewindow.cc` (For use with gtkmm 4)

    #include "examplewindow.h"
    #include <iostream>

    ExampleWindow::ExampleWindow(const Glib::RefPtr<Gtk::Application>& app)
    : m_Box(Gtk::Orientation::VERTICAL),
      m_refRecentManager(Gtk::RecentManager::get_default())
    {
      set_title("Recent files example");
      set_default_size(300, 150);

      //We can put a PopoverMenuBar at the top of the box and other stuff below it.
      set_child(m_Box);

      //Create actions for menus and toolbars:
      m_refActionGroup = Gio::SimpleActionGroup::create();

      //File menu:
      m_refActionGroup->add_action("new",
        sigc::mem_fun(*this, &ExampleWindow::on_menu_file_new));

      //A menu item to open the file dialog:
      m_refActionGroup->add_action("files-dialog",
        sigc::mem_fun(*this, &ExampleWindow::on_menu_file_files_dialog));

      m_refActionGroup->add_action("quit",
        sigc::mem_fun(*this, &ExampleWindow::on_menu_file_quit) );

      insert_action_group("example", m_refActionGroup);

      m_refBuilder = Gtk::Builder::create();

      // When the menubar is a child of a Gtk::Window, keyboard accelerators are not
      // automatically fetched from the Gio::Menu.
      // See the examples/book/menus/main_menu example for an alternative way of
      // adding the menubar when using Gtk::ApplicationWindow.
      app->set_accel_for_action("example.new", "<Primary>n");
      app->set_accel_for_action("example.files-dialog", "<Primary>o");
      app->set_accel_for_action("example.quit", "<Primary>q");

      //Layout the actions in a menubar and a toolbar:
      const char* ui_info =
        "<interface>"
        "  <menu id='menubar'>"
        "    <submenu>"
        "      <attribute name='label' translatable='yes'>_File</attribute>"
        "      <item>"
        "        <attribute name='label' translatable='yes'>_New</attribute>"
        "        <attribute name='action'>example.new</attribute>"
        "        <attribute name='accel'>&lt;Primary&gt;n</attribute>"
        "      </item>"
        "      <item>"
        "        <attribute name='label' translatable='yes'>File _Dialog</attribute>"
        "        <attribute name='action'>example.files-dialog</attribute>"
        "        <attribute name='accel'>&lt;Primary&gt;o</attribute>"
        "      </item>"
        "      <item>"
        "        <attribute name='label' translatable='yes'>_Quit</attribute>"
        "        <attribute name='action'>example.quit</attribute>"
        "        <attribute name='accel'>&lt;Primary&gt;q</attribute>"
        "      </item>"
        "    </submenu>"
        "  </menu>"
        "  <object class='GtkBox' id='toolbar'>"
        "    <property name='can_focus'>False</property>"
        "    <child>"
        "      <object class='GtkButton' id='toolbutton_new'>"
        "        <property name='can_focus'>False</property>"
        "        <property name='tooltip_text' translatable='yes'>New</property>"
        "        <property name='action_name'>example.new</property>"
        "        <property name='icon_name'>document-new</property>"
        "        <property name='hexpand'>False</property>"
        "        <property name='vexpand'>False</property>"
        "      </object>"
        "    </child>"
        "    <child>"
        "      <object class='GtkButton' id='toolbutton_quit'>"
        "        <property name='can_focus'>False</property>"
        "        <property name='tooltip_text' translatable='yes'>Quit</property>"
        "        <property name='action_name'>example.quit</property>"
        "        <property name='icon_name'>application-exit</property>"
        "        <property name='hexpand'>False</property>"
        "        <property name='vexpand'>False</property>"
        "      </object>"
        "    </child>"
        "  </object>"
        "</interface>";

      try
      {
        m_refBuilder->add_from_string(ui_info);
      }
      catch(const Glib::Error& ex)
      {
        std::cerr << "building menubar and toolbar failed: " <<  ex.what();
      }

      //Get the menubar and toolbar widgets, and add them to a container widget:
      auto object = m_refBuilder->get_object("menubar");
      auto gmenu = std::dynamic_pointer_cast<Gio::Menu>(object);
      if (gmenu)
      {
        //Menubar:
        auto pMenubar = Gtk::make_managed<Gtk::PopoverMenuBar>(gmenu);
        m_Box.append(*pMenubar);
      }
      else
        g_warning("GMenu not found");

      auto pToolbar = m_refBuilder->get_widget<Gtk::Box>("toolbar");
      if (pToolbar)
        //Toolbar:
        m_Box.append(*pToolbar);
      else
        g_warning("toolbar not found");
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_menu_file_new()
    {
      std::cout << " New File" << std::endl;
    }

    void ExampleWindow::on_menu_file_quit()
    {
      close(); // Closes the main window to stop the app->make_window_and_run().
    }

    void ExampleWindow::on_menu_file_files_dialog()
    {
      if (!m_refFileDialog)
      {
        m_refFileDialog = Gtk::FileDialog::create();
        m_refFileDialog->set_modal(true);
      }
      m_refFileDialog->open(*this, sigc::mem_fun(*this, &ExampleWindow::on_dialog_finish));
    }

    void ExampleWindow::on_dialog_finish(Glib::RefPtr<Gio::AsyncResult>& result)
    {
      Glib::RefPtr<Gio::File> file;
      try
      {
        file = m_refFileDialog->open_finish(result);
      }
      catch (const Gtk::DialogError& err)
      {
        std::cout << "No file selected, " << err.what() << std::endl;
        return;
      }

      auto selected_uri = file->get_uri();
      std::cout << "URI selected = " << selected_uri << std::endl;
      std::cout << (m_refRecentManager->has_item(selected_uri) ? "A" : "Not a")
        << " recently used file" << std::endl;
    }

File: `main.cc` (For use with gtkmm 4)

    #include "examplewindow.h"
    #include <gtkmm/application.h>

    int main(int argc, char *argv[])
    {
      auto app = Gtk::Application::create("org.gtkmm.example");

      //Shows the window and returns when it is closed.
      return app->make_window_and_run<ExampleWindow>(argc, argv, app);
    }

The constructor for `ExampleWindow` creates the menu and the toolbar using `Builder` (see Chapter 15, Menus and Toolbars for more information). It then adds the menu and the toolbar to the window.

### Filtering Files

For any of the `FileChooser` classes, if you don't wish to display all of the items in the list of files, you can filter the list to show only those that you want. You can filter the list with the help of the `FileFilter` class. This class allows you to filter files by their name (`add_pattern()`), or their mime type (`add_mime_type()`).

After you've created and set up the filter to match only the items you want, you can apply a filter to a chooser widget with the `FileChooser::add_filter()` function.

Chapter 22. Recently Used Documents |  | Chapter 23. Keyboard and Mouse Events