Bastian
Bastian

Reputation: 630

How to get files from selected folder with GtkFileChooserButton?

I am making a GTK+3 App with GJS where users select a folder from a GtkFileChooserButton (action property set to select-folder). I want to find all image files in the given folder the user have selected, so I can display one of the images.

I tried this._fileChooserButton.get_files() and this._folderChooseButton.get_uris() but they only return one file, which is the path to the selected folder. Like this:

    _init(application) {
        this._folderChooseButton.connect('file-set', () => {
          this._onFolderChosen();
        });
    }

    _onFolderChosen() {
      let folder = this._folderChooseButton.get_file();
      // somehow get files from the folder here
      this._image.set_from_file(files[1]);
    }

From the API it is not really clear to me, how do I find out which image files are inside the user's selected directory (and subdirectories)?

Upvotes: 0

Views: 1174

Answers (1)

Bastian
Bastian

Reputation: 630

OK, after help from patrick, georges and matthias at guadec, here is what I got.

The get_file() function I tried returns a GFile, which in this case is a folder (in UNIX, folders are also files). In order to get the files within the directory path, we need to call enumerate_children_async() on our GFile, returned by the get_file() function.

The enumate_children_async() function takes five parameters:

  1. A comma-separated attribute list. In our case, since we want the identifiers of the children in the directory, we want to use the attribute called standard::name.

  2. FileQueryInfoFlag: This allows to either follow or not follow symbolic links. In this case, we will use FileQueryInfoFlag.NONE which will not follow symbolic links.

  3. io_priority: How high priority the IO operation should have (we will use GLib.PRIORITY_DEFAULT)

  4. cancellable: A cancellable, which is a way to cancel this operation, in this case we will leave it as null.

  5. callback: This is the function/code you want to run in response to the files having been retreived.

More info on this function is at GJS-Docs at GNOME.org

The enumerate_children_async() function returns a GFileEnumerator, which we can use to retreive a number of the files, by calling next_files_async(), which takes these arguments:

  1. num_files: How many files you want to retreive. In your case, we use 1.

  2. io_priority and cancellable (same as above).

  3. callback: Where we can run a function or code to actually retreive the file.

Below, is the final code for doing this.

const { Gio, GLib, GObject, Gtk } = imports.gi; // import Gio and GLib API at top of your document.
_onFolderChosen() {
  let folder = this._folderChooseButton.get_file();
  let files = folder.enumerate_children_async(
    'standard::name',
    Gio.FileQueryInfoFlags.NONE,
    GLib.PRIORITY_DEFAULT,
    null,
    (source, result, data) => {
      this._fileEnumerator = null;
      try {
        this._fileEnumerator = folder.enumerate_children_finish(result);
      } catch (e) {
        log('(Error) Could not retreive list of files! Error:' + e);
        return;
      }
      this._readNextFile();
    });
}

_readNextFile() {
  if (!this._fileEnumerator)
    return;

  let fileInfo = null;
  this._fileEnumerator.next_files_async(
    1,
    GLib.PRIORITY_DEFAULT,
    null,
    (source, result, data) => {
      try {
        fileInfo = this._fileEnumerator.next_files_finish(result);
      } catch (e) {
        log('Could not retreive the next file! Error:' + e);
        return;
      }
      let file = fileInfo[0].get_name();
      let filePath = GLib.build_filenamev([this._folderChooseButton.get_filename(), file]);
      this._carousselImage.set_from_file(filePath);
  });
}

Upvotes: 3

Related Questions