Source code for libdesktop.dialog.files

# coding: utf-8

# This file is part of libdesktop

# The MIT License (MIT)
#
# Copyright (c) 2016 Bharadwaj Raju
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


from libdesktop import system
import sys
import os


[docs]def open_file(default_dir='~', extensions=None, title='Choose a file', multiple_files=False, directory=False): '''Start the native file dialog for opening file(s). Starts the system native file dialog in order to open a file (or multiple files). The toolkit used for each platform: +-------------------------------------+------------------------------+ | Windows | Windows API (Win32) | +-------------------------------------+------------------------------+ | Mac OS X | Cocoa | +-------------------------------------+------------------------------+ | GNOME, Unity, Cinnamon, Pantheon | GTK+ 3 | +-------------------------------------+------------------------------+ | KDE, LXQt | Qt 5 (fallback: Qt 4/GTK+ 3) | +-------------------------------------+------------------------------+ | Other desktops (Xfce, WMs etc) | GTK+ 2 (fallback: GTK+ 3) | +-------------------------------------+------------------------------+ **Note on Dependencies** It depends on pywin32 for Windows (installed by default in Python for Windows) It depends on `PyQt <https://riverbankcomputing.com/software/pyqt>`_ for KDE and LxQt (usually installed by default on these). It depends on `PyGObject <https://wiki.gnome.org/Projects/PyGObject>`_ for GNOME etc. (virtually every Linux desktop has this). It depends on `PyGTK <https://pygtk.org>`_ for other desktops (not usually installed, so has a GTK+ 3 fallback). Args: default_dir (str) : The directory to start the dialog in. Default: User home directory. extensions (dict) : The extensions to filter by. Format: .. code-block:: python { 'Filter Name (example: Image Files)': ['*.png', '*.whatever', '*'] } title (str) : The title of the dialog. Default: `Choose a file` multiple_files (bool): Whether to choose multiple files or single files only. Default: `False` directory (bool): Whether to choose directories. Default: `False` Returns: list: `list` of `str` s (each `str` being a selected file). If nothing is selected/dialog is cancelled, it is `None`. ''' default_dir = os.path.expanduser(default_dir) if not extensions: extensions = {} if system.get_name() == 'windows': pass # TODO: Implement Win32 file dialog elif system.get_name() == 'mac': pass # TODO: Implement Cocoa file dialog else: def gtk3_dialog(): # GTK+ 3 import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk class FileChooserWindow(Gtk.Window): def __init__(self): self.path = '' Gtk.Window.__init__(self, title='') dialog = Gtk.FileChooserDialog(title, None, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) ) if extensions: for entry in extensions: file_filter = Gtk.FileFilter() file_filter.set_name(entry) for pattern in extensions[entry]: file_filter.add_pattern(pattern) dialog.add_filter(file_filter) dialog.set_select_multiple(multiple_files) dialog.set_current_folder(default_dir) response = dialog.run() if response == Gtk.ResponseType.OK: self.path = dialog.get_filenames() dialog.destroy() elif response == Gtk.ResponseType.CANCEL: self.path = None dialog.destroy() win = FileChooserWindow() win.connect('destroy', Gtk.main_quit) win.connect('delete-event', Gtk.main_quit) win.show_all() win.destroy() win.close() return win.path def qt5_dialog(): # Qt 5 try: from PyQt5 import Qt except ImportError: # The API is the same for what this uses from PyQt4 import Qt class FileChooserWindow(Qt.QWidget): def __init__(self): super().__init__() extensions_string = '' if extensions: for entry in extensions: # entry → Filter name (i.e. 'Image Files' etc) # value → Filter expression (i.e. '*.png, *.jpg' # etc) extensions_string += '%s (%s);;' % (entry, ' '.join(extensions[entry])) else: extensions_string = 'All Files (*)' dialog = Qt.QFileDialog() if multiple_files: dialog.setFileMode(Qt.QFileDialog.ExistingFiles) if directory: dialog.setFileMode(Qt.QFileDialog.Directory) dialog.setWindowTitle(title) dialog.setDirectory(default_dir) dialog.setNameFilter(extensions_string) if dialog.exec_(): self.path = dialog.selectedFiles() else: self.path = None app = Qt.QApplication(sys.argv) win = FileChooserWindow() win.close() if win.path: return win.path else: return None app.exec_() def gtk2_dialog(): # GTK+ 2 import pygtk pygtk.require('2.0') dialog = gtk.FileChooserDialog(title, None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) if extensions: for entry in extensions: file_filter = gtk.FileFilter() file_filter.set_name(entry) for pattern in extensions[entry]: file_filter.add_pattern(pattern) dialog.add_filter(file_filter) dialog.set_select_multiple(multiple_files) response = dialog.run() if response == gtk.RESPONSE_OK: return dialog.get_filenames() elif response == gtk.RESPONSE_CANCEL: return None dialog.destroy() if system.get_name() in ['gnome', 'unity', 'cinnamon', 'pantheon']: return gtk3_dialog() elif system.get_name() in ['kde', 'lxqt']: try: return qt5_dialog() except ImportError: return gtk3_dialog() else: try: return gtk2_dialog() except ImportError: return gtk3_dialog()