Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 python-tkfilebrowser (2.3.2-2~guideos1) unstable; urgency=medium
 .
   * Added: New Icons
Author: Actionschnitzel <actionschnitzel@guideos.de>

---
The information above should follow the Patch Tagging Guidelines, please
checkout https://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: (upstream|backport|vendor|other), (<patch-url>|commit:<commit-id>)
Bug: <upstream-bugtracker-url>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: (no|not-needed|<patch-forwarded-url>)
Applied-Upstream: <version>, (<commit-url>|commit:<commid-id>)
Reviewed-By: <name and email of someone who approved/reviewed the patch>
Last-Update: 2025-02-10

--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/.pydistutils.cfg
@@ -0,0 +1,10 @@
+[clean]
+all=1
+[build]
+build_lib=/home/actionschnitzel/Downloads/python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build
+[install]
+force=1
+install_layout=deb
+install_scripts=$base/bin
+install_lib=/usr/lib/python3.11/dist-packages
+prefix=/usr
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+
+from tkfilebrowser.filebrowser import FileBrowser
+from tkfilebrowser.functions import *
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/__main__.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+Example
+"""
+
+from tkfilebrowser import askopendirname, askopenfilenames, asksaveasfilename
+try:
+    import tkinter as tk
+    from tkinter import ttk
+    from tkinter import filedialog
+except ImportError:
+    import Tkinter as tk
+    import ttk
+    import tkFileDialog as filedialog
+
+root = tk.Tk()
+
+style = ttk.Style(root)
+style.theme_use("clam")
+root.configure(bg=style.lookup('TFrame', 'background'))
+
+def c_open_file_old():
+    rep = filedialog.askopenfilenames(parent=root, initialdir='/', initialfile='tmp',
+                                      filetypes=[("PNG", "*.png"),
+                                                 ("JPEG", "*.jpg"),
+                                                 ("All files", "*")])
+    print(rep)
+
+
+def c_open_dir_old():
+    rep = filedialog.askdirectory(parent=root, initialdir='/tmp')
+    print(rep)
+
+
+def c_save_old():
+    rep = filedialog.asksaveasfilename(parent=root, defaultextension=".png",
+                                       initialdir='/tmp', initialfile='image.png',
+                                       filetypes=[("PNG", "*.png"),
+                                                  ("JPEG", "*.jpg"),
+                                                  ("Text files", "*.txt"),
+                                                  ("All files", "*")])
+    print(rep)
+
+
+def c_open_file():
+    rep = askopenfilenames(parent=root, initialdir='/', initialfile='tmp',
+                           filetypes=[("Pictures", "*.png|*.jpg|*.JPG"),
+                                      ("All files", "*")])
+    print(rep)
+
+
+def c_open_dir():
+    rep = askopendirname(parent=root, initialdir='/', initialfile='tmp')
+    print(rep)
+
+
+def c_save():
+    rep = asksaveasfilename(parent=root, defaultext=".png", initialdir='/tmp', initialfile='image.png',
+                            filetypes=[("Pictures", "*.png|*.jpg|*.JPG"),
+                                       ("Text files", "*.txt"),
+                                       ("All files", "*")])
+    print(rep)
+
+
+ttk.Label(root, text='Default dialogs').grid(row=0, column=0, padx=4, pady=4, sticky='ew')
+ttk.Label(root, text='tkfilebrowser dialogs').grid(row=0, column=1, padx=4, pady=4, sticky='ew')
+ttk.Button(root, text="Open files", command=c_open_file_old).grid(row=1, column=0, padx=4, pady=4, sticky='ew')
+ttk.Button(root, text="Open folder", command=c_open_dir_old).grid(row=2, column=0, padx=4, pady=4, sticky='ew')
+ttk.Button(root, text="Save file", command=c_save_old).grid(row=3, column=0, padx=4, pady=4, sticky='ew')
+ttk.Button(root, text="Open files", command=c_open_file).grid(row=1, column=1, padx=4, pady=4, sticky='ew')
+ttk.Button(root, text="Open folder", command=c_open_dir).grid(row=2, column=1, padx=4, pady=4, sticky='ew')
+ttk.Button(root, text="Save file", command=c_save).grid(row=3, column=1, padx=4, pady=4, sticky='ew')
+
+root.mainloop()
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/autoscrollbar.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017 Juliette Monsel <j_4321@protonmail.com>
+based on code by Fredrik Lundh copyright 1998
+<http://effbot.org/zone/tkinter-autoscrollbar.htm>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+Scrollbar that hides automatically when not needed
+"""
+
+
+from tkfilebrowser.constants import tk, ttk
+
+
+class AutoScrollbar(ttk.Scrollbar):
+    """Scrollbar that hides itself if it's not needed."""
+
+    def set(self, lo, hi):
+        if float(lo) <= 0.0 and float(hi) >= 1.0:
+            self.grid_remove()
+        else:
+            self.grid()
+        ttk.Scrollbar.set(self, lo, hi)
+
+    def pack(self, **kw):
+        raise tk.TclError("cannot use pack with this widget")
+
+    def place(self, **kw):
+        raise tk.TclError("cannot use place with this widget")
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/constants.py
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017-2018 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+The icons are modified versions of icons from the elementary project
+(the xfce fork to be precise https://github.com/shimmerproject/elementary-xfce)
+Copyright 2007-2013 elementary LLC.
+
+
+Constants and functions
+"""
+import locale
+from babel.numbers import format_number
+from babel.dates import format_date, format_datetime
+from datetime import datetime
+import os
+from math import log, floor
+
+try:
+    import tkinter as tk
+    from tkinter import ttk
+    from tkinter.messagebox import askyesnocancel, showerror
+    from urllib.parse import unquote
+except ImportError:
+    import Tkinter as tk
+    import ttk
+    from tkMessageBox import askyesnocancel, showerror
+    from urllib import unquote
+    import sys
+    reload(sys)
+    sys.setdefaultencoding('utf8')
+
+PATH = os.path.dirname(__file__)
+
+LOCAL_PATH = os.path.join(os.path.expanduser('~'), '.config', 'tkfilebrowser')
+
+if not os.path.exists(LOCAL_PATH):
+    try:
+        if not os.path.exists(os.path.join(os.path.expanduser('~'), '.config')):
+            os.mkdir(os.path.join(os.path.expanduser('~'), '.config'))
+        os.mkdir(LOCAL_PATH)
+    except Exception:
+        # avoid raising error if the path is not writtable
+        pass
+
+RECENT_FILES = os.path.join(LOCAL_PATH, 'recent_files')
+
+# ---  images
+if tk.TkVersion < 8.6:
+    from PIL.ImageTk import PhotoImage
+else:
+    PhotoImage = tk.PhotoImage
+
+IM_HOME = os.path.join(PATH, "images", "home.png")
+IM_DESKTOP = os.path.join(PATH, "images", "desktop.png")
+IM_FOLDER = os.path.join(PATH, "images", "folder.png")
+IM_FOLDER_LINK = os.path.join(PATH, "images", "folder_link.png")
+IM_NEW = os.path.join(PATH, "images", "new_folder.png")
+IM_FILE = os.path.join(PATH, "images", "file.png")
+IM_FILE_LINK = os.path.join(PATH, "images", "file_link.png")
+IM_LINK_BROKEN = os.path.join(PATH, "images", "link_broken.png")
+IM_DRIVE = os.path.join(PATH, "images", "drive.png")
+IM_RECENT = os.path.join(PATH, "images", "recent.png")
+IM_RECENT_24 = os.path.join(PATH, "images", "recent_24.png")
+
+# ---  translation
+try:
+    LANG = locale.getdefaultlocale()[0]
+except ValueError:
+    LANG = 'en'
+
+EN = {}
+FR = {"B": "octets", "MB": "Mo", "kB": "ko", "GB": "Go", "TB": "To",
+      "Name: ": "Nom : ", "Folder: ": "Dossier : ", "Size": "Taille",
+      "Name": "Nom", "Modified": "Modifié", "Save": "Enregistrer",
+      "Open": "Ouvrir", "Cancel": "Annuler", "Location": "Emplacement",
+      "Today": "Aujourd'hui", "Confirmation": "Confirmation",
+      "Error": "Erreur",
+      "The file {file} already exists, do you want to replace it?": "Le fichier {file} existe déjà, voulez-vous le remplacer ?",
+      "Shortcuts": "Raccourcis", "Save As": "Enregistrer sous",
+      "Recent": "Récents", "Recently used": "Récemment utilisés"}
+LANGUAGES = {"fr": FR, "en": EN}
+if LANG[:2] == "fr":
+    TR = LANGUAGES["fr"]
+else:
+    TR = LANGUAGES["en"]
+
+
+def _(text):
+    """ translation function """
+    return TR.get(text, text)
+
+
+fromtimestamp = datetime.fromtimestamp
+
+
+def locale_date(date=None):
+    return format_date(date, 'short', locale=LANG)
+
+
+def locale_datetime(date=None):
+    return format_datetime(date, 'EEEE HH:mm', locale=LANG)
+
+
+def locale_number(nb):
+    return format_number(nb, locale=LANG)
+
+
+SIZES = [_("B"), _("kB"), _("MB"), _("GB"), _("TB")]
+
+# ---  locale settings for dates
+TODAY = locale_date()
+YEAR = datetime.now().year
+DAY = int(format_date(None, 'D', locale=LANG))
+
+
+# ---  functions
+def add_trace(variable, mode, callback):
+    """
+    Add trace to variable.
+
+    Ensure compatibility with old and new trace method.
+    mode: "read", "write", "unset" (new syntax)
+    """
+    try:
+        return variable.trace_add(mode, callback)
+    except AttributeError:
+        # fallback to old method
+        return variable.trace(mode[0], callback)
+
+
+def remove_trace(variable, mode, cbname):
+    """
+    Remove trace from variable.
+
+    Ensure compatibility with old and new trace method.
+    mode: "read", "write", "unset" (new syntax)
+    """
+    try:
+        variable.trace_remove(mode, cbname)
+    except AttributeError:
+        # fallback to old method
+        variable.trace_vdelete(mode[0], cbname)
+
+
+def get_modification_date(file):
+    """Return the modification date of file."""
+    try:
+        tps = fromtimestamp(os.path.getmtime(file))
+    except OSError:
+        tps = TODAY
+    date = locale_date(tps)
+    if date == TODAY:
+        date = _("Today") + tps.strftime(" %H:%M")
+    elif tps.year == YEAR and (DAY - int(tps.strftime("%j"))) < 7:
+        date = locale_datetime(tps)
+    return date
+
+
+def display_modification_date(mtime):
+    """Return the modDification date of file."""
+    if isinstance(mtime, str):
+        return mtime
+    tps = fromtimestamp(mtime)
+    date = locale_date(tps)
+    if date == TODAY:
+        date = _("Today") + tps.strftime(" %H:%M")
+    elif tps.year == YEAR and (DAY - int(tps.strftime("%j"))) < 7:
+        date = locale_datetime(tps)
+    return date
+
+
+def display_size(size_o):
+    """Return the size of file."""
+    if isinstance(size_o, str):
+        return size_o
+    if size_o > 0:
+        m = int(floor(log(size_o) / log(1024)))
+        if m < len(SIZES):
+            unit = SIZES[m]
+            s = size_o / (1024 ** m)
+        else:
+            unit = SIZES[-1]
+            s = size_o / (1024**(len(SIZES) - 1))
+        size = "%s %s" % (locale_number("%.1f" % s), unit)
+    else:
+        size = "0 " + _("B")
+    return size
+
+
+def key_sort_files(file):
+    return file.is_file(), file.name.lower()
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/filebrowser.py
@@ -0,0 +1,1529 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017-2018 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+Main class
+"""
+
+
+import psutil
+from re import search
+from subprocess import check_output
+from os import walk, mkdir, stat, access, W_OK, listdir
+from os import name as OSNAME
+from os.path import sep as SEP
+from os.path import exists, join, getmtime, realpath, split, expanduser, \
+    abspath, isabs, splitext, dirname, getsize, isdir, isfile, islink
+try:
+    from os import scandir
+    SCANDIR = True
+except ImportError:
+    SCANDIR = False
+import traceback
+import tkfilebrowser.constants as cst
+from tkfilebrowser.constants import unquote, tk, ttk, key_sort_files, \
+    get_modification_date, display_modification_date, display_size
+from tkfilebrowser.autoscrollbar import AutoScrollbar
+from tkfilebrowser.path_button import PathButton
+from tkfilebrowser.tooltip import TooltipTreeWrapper
+from tkfilebrowser.recent_files import RecentFiles
+
+if OSNAME == 'nt':
+    from win32com.shell import shell, shellcon
+
+_ = cst._
+
+
+class Stats:
+    """Fake stats class to create dummy stats for broken links."""
+    def __init__(self, **kwargs):
+        self._prop = kwargs
+
+    def __getattr__(self, attr):
+        if attr not in self._prop:
+            raise AttributeError("Stats has no attribute %s." % attr)
+        else:
+            return self._prop[attr]
+
+
+class FileBrowser(tk.Toplevel):
+    """Filebrowser dialog class."""
+    def __init__(self, parent, initialdir="", initialfile="", mode="openfile",
+                 multiple_selection=False, defaultext="", title="Filebrowser",
+                 filetypes=[], okbuttontext=None, cancelbuttontext=_("Cancel"),
+                 foldercreation=True, **kw):
+        """
+        Create a filebrowser dialog.
+
+        Arguments:
+
+        parent : Tk or Toplevel instance
+            parent window
+
+        title : str
+            the title of the filebrowser window
+
+        initialdir : str
+            directory whose content is initially displayed
+
+        initialfile : str
+            initially selected item (just the name, not the full path)
+
+        mode : str
+            kind of dialog: "openfile", "opendir" or "save"
+
+        multiple_selection : bool
+            whether to allow multiple items selection (open modes only)
+
+        defaultext : str (e.g. '.png')
+            extension added to filename if none is given (default is none)
+
+        filetypes : list :obj:`[("name", "*.ext1|*.ext2|.."), ...]`
+          only the files of given filetype will be displayed,
+          e.g. to allow the user to switch between displaying only PNG or JPG
+          pictures or dispalying all files:
+          :obj:`filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]`
+
+        okbuttontext : str
+            text displayed on the validate button, default is "Open".
+
+        cancelbuttontext : str
+            text displayed on the button that cancels the selection, default is "Cancel".
+
+        foldercreation : bool
+            enable the user to create new folders if True (default)
+        """
+        # compatibility with tkinter.filedialog arguments: the parent window is called 'master'
+        if 'master' in kw and parent is None:
+            parent = kw.pop('master')
+        if 'defaultextension' in kw and not defaultext:
+            defaultext = kw.pop('defaultextension')
+        tk.Toplevel.__init__(self, parent, **kw)
+
+        # python version compatibility
+        if SCANDIR:
+            self.display_folder = self._display_folder_scandir
+        else:
+            self.display_folder = self._display_folder_walk
+
+        # keep track of folders to be able to move backward/foreward in history
+        if initialdir:
+            self.history = [initialdir]
+        else:
+            self.history = [expanduser("~")]
+        self._hist_index = -1
+
+        self.transient(parent)
+        self.grab_set()
+        self.protocol("WM_DELETE_WINDOW", self.quit)
+        self.title(title)
+
+        self.rowconfigure(2, weight=1)
+        self.columnconfigure(0, weight=1)
+
+        self.mode = mode
+        self.result = ""
+        self.foldercreation = foldercreation
+
+        # hidden files/folders visibility
+        self.hide = False
+        # hidden items
+        self.hidden = ()
+
+        # ---  style
+        style = ttk.Style(self)
+        bg = style.lookup("TFrame", "background")
+        style.layout("right.tkfilebrowser.Treeview.Item",
+                     [('Treeitem.padding',
+                       {'children':
+                           [('Treeitem.image', {'side': 'left', 'sticky': ''}),
+                            ('Treeitem.focus',
+                             {'children':
+                                 [('Treeitem.text',
+                                   {'side': 'left', 'sticky': ''})],
+                              'side': 'left',
+                              'sticky': ''})],
+                        'sticky': 'nswe'})])
+        style.layout("left.tkfilebrowser.Treeview.Item",
+                     [('Treeitem.padding',
+                       {'children':
+                           [('Treeitem.image', {'side': 'left', 'sticky': ''}),
+                            ('Treeitem.focus',
+                             {'children':
+                                 [('Treeitem.text', {'side': 'left', 'sticky': ''})],
+                              'side': 'left',
+                              'sticky': ''})],
+                        'sticky': 'nswe'})])
+        style.configure("right.tkfilebrowser.Treeview", font="TkDefaultFont")
+        style.configure("right.tkfilebrowser.Treeview.Item", padding=2)
+        style.configure("right.tkfilebrowser.Treeview.Heading",
+                        font="TkDefaultFont")
+        style.configure("left.tkfilebrowser.Treeview.Heading",
+                        font="TkDefaultFont")
+        style.configure("left.tkfilebrowser.Treeview.Item", padding=2)
+        style.configure("listbox.tkfilebrowser.TFrame", background="white", relief="sunken")
+        field_bg = style.lookup("TEntry", "fieldbackground", default='white')
+        tree_field_bg = style.lookup("ttk.Treeview", "fieldbackground",
+                                     default='white')
+        fg = style.lookup('TLabel', 'foreground', default='black')
+        active_bg = style.lookup('TButton', 'background', ('active',))
+        sel_bg = style.lookup('Treeview', 'background', ('selected',))
+        sel_fg = style.lookup('Treeview', 'foreground', ('selected',))
+        self.option_add('*TCombobox*Listbox.selectBackground', sel_bg)
+        self.option_add('*TCombobox*Listbox.selectForeground', sel_fg)
+        style.map('types.tkfilebrowser.TCombobox', foreground=[], fieldbackground=[])
+        style.configure('types.tkfilebrowser.TCombobox', lightcolor=bg,
+                        fieldbackground=bg)
+        style.configure('types.tkfilebrowser.TCombobox.Item', background='red')
+        style.configure("left.tkfilebrowser.Treeview", background=active_bg,
+                        font="TkDefaultFont",
+                        fieldbackground=active_bg)
+        self.configure(background=bg)
+        # path button style
+        style.configure("path.tkfilebrowser.TButton", padding=2)
+        selected_bg = style.lookup("TButton", "background", ("pressed",))
+        map_bg = style.map("TButton", "background")
+        map_bg.append(("selected", selected_bg))
+        style.map("path.tkfilebrowser.TButton",
+                  background=map_bg,
+                  font=[("selected", "TkDefaultFont 9 bold")])
+        # tooltip style
+        style.configure('tooltip.tkfilebrowser.TLabel', background='black',
+                        foreground='white')
+
+        # ---  images
+        self.im_file = cst.PhotoImage(file=cst.IM_FILE, master=self)
+        self.im_folder = cst.PhotoImage(file=cst.IM_FOLDER, master=self)
+        self.im_desktop = cst.PhotoImage(file=cst.IM_DESKTOP, master=self)
+        self.im_file_link = cst.PhotoImage(file=cst.IM_FILE_LINK, master=self)
+        self.im_link_broken = cst.PhotoImage(file=cst.IM_LINK_BROKEN, master=self)
+        self.im_folder_link = cst.PhotoImage(file=cst.IM_FOLDER_LINK, master=self)
+        self.im_new = cst.PhotoImage(file=cst.IM_NEW, master=self)
+        self.im_drive = cst.PhotoImage(file=cst.IM_DRIVE, master=self)
+        self.im_home = cst.PhotoImage(file=cst.IM_HOME, master=self)
+        self.im_recent = cst.PhotoImage(file=cst.IM_RECENT, master=self)
+        self.im_recent_24 = cst.PhotoImage(file=cst.IM_RECENT_24, master=self)
+
+        # ---  filetypes
+        self.filetype = tk.StringVar(self)
+        self.filetypes = {}
+        if filetypes:
+            for name, exts in filetypes:
+                if name not in self.filetypes:
+                    self.filetypes[name] = []
+                self.filetypes[name] = r'%s$' % exts.strip().replace('.', '\.').replace('*', '.*')
+            values = list(self.filetypes.keys())
+            w = max([len(f) for f in values] + [5])
+            b_filetype = ttk.Combobox(self, textvariable=self.filetype,
+                                      state='readonly',
+                                      style='types.tkfilebrowser.TCombobox',
+                                      values=values,
+                                      width=w)
+            b_filetype.grid(row=3, sticky="e", padx=10, pady=(4, 0))
+            self.filetype.set(filetypes[0][0])
+            try:
+                self.filetype.trace_add('write', lambda *args: self._change_filetype())
+            except AttributeError:
+                self.filetype.trace('w', lambda *args: self._change_filetype())
+        else:
+            self.filetypes[""] = r".*$"
+
+        # ---  recent files
+        self._recent_files = RecentFiles(cst.RECENT_FILES, 30)
+
+        # ---  path completion
+        self.complete = self.register(self._completion)
+        self.listbox_var = tk.StringVar(self)
+        self.listbox_frame = ttk.Frame(self, style="listbox.tkfilebrowser.TFrame", borderwidth=1)
+        self.listbox = tk.Listbox(self.listbox_frame,
+                                  listvariable=self.listbox_var,
+                                  highlightthickness=0,
+                                  borderwidth=0,
+                                  background=field_bg,
+                                  foreground=fg,
+                                  selectforeground=sel_fg,
+                                  selectbackground=sel_bg)
+        self.listbox.pack(expand=True, fill="x")
+
+        # ---  path bar
+        self.path_var = tk.StringVar(self)
+        frame_bar = ttk.Frame(self)
+        frame_bar.columnconfigure(0, weight=1)
+        frame_bar.grid(row=1, sticky="ew", pady=10, padx=10)
+        frame_recent = ttk.Frame(frame_bar)
+        frame_recent.grid(row=0, column=0, sticky="w")
+        ttk.Label(frame_recent, image=self.im_recent_24).pack(side="left")
+        ttk.Label(frame_recent, text=_("Recently used"),
+                  font="TkDefaultFont 9 bold").pack(side="left", padx=4)
+        self.path_bar = ttk.Frame(frame_bar)
+        self.path_bar.grid(row=0, column=0, sticky="ew")
+        self.path_bar_buttons = []
+        self.b_new_folder = ttk.Button(frame_bar, image=self.im_new,
+                                       command=self.create_folder)
+        if self.foldercreation:
+            self.b_new_folder.grid(row=0, column=1, sticky="e")
+        if mode == "save":
+            ttk.Label(self.path_bar, text=_("Folder: ")).grid(row=0, column=0)
+            self.defaultext = defaultext
+
+            frame_name = ttk.Frame(self)
+            frame_name.grid(row=0, pady=(10, 0), padx=10, sticky="ew")
+            ttk.Label(frame_name, text=_("Name: ")).pack(side="left")
+            self.entry = ttk.Entry(frame_name, validate="key",
+                                   validatecommand=(self.complete, "%d", "%S",
+                                                    "%i", "%s"))
+            self.entry.pack(side="left", fill="x", expand=True)
+
+            if initialfile:
+                self.entry.insert(0, initialfile)
+        else:
+            self.multiple_selection = multiple_selection
+            self.entry = ttk.Entry(frame_bar, validate="key",
+                                   validatecommand=(self.complete, "%d", "%S",
+                                                    "%i", "%s"))
+            self.entry.grid(row=1, column=0, columnspan=2, sticky="ew", padx=0,
+                            pady=(10, 0))
+            self.entry.grid_remove()
+
+        paned = ttk.PanedWindow(self, orient="horizontal")
+        paned.grid(row=2, sticky="eswn", padx=10)
+
+        # ---  left pane
+        left_pane = ttk.Frame(paned)
+        left_pane.columnconfigure(0, weight=1)
+        left_pane.rowconfigure(0, weight=1)
+
+        paned.add(left_pane, weight=0)
+        self.left_tree = ttk.Treeview(left_pane, selectmode="browse",
+                                      style="left.tkfilebrowser.Treeview")
+        wrapper = TooltipTreeWrapper(self.left_tree)
+        self.left_tree.column("#0", width=150)
+        self.left_tree.heading("#0", text=_("Shortcuts"), anchor="w")
+        self.left_tree.grid(row=0, column=0, sticky="sewn")
+
+        scroll_left = AutoScrollbar(left_pane, command=self.left_tree.yview)
+        scroll_left.grid(row=0, column=1, sticky="ns")
+        self.left_tree.configure(yscrollcommand=scroll_left.set)
+
+        # list devices and bookmarked locations
+        # -------- recent
+        self.left_tree.insert("", "end", iid="recent", text=_("Recent"),
+                              image=self.im_recent)
+        wrapper.add_tooltip("recent", _("Recently used"))
+
+        # -------- devices
+        devices = psutil.disk_partitions(all=True if OSNAME == "nt" else False)
+
+        for d in devices:
+            m = d.mountpoint
+            if m == "/":
+                txt = "/"
+            else:
+                if OSNAME == 'nt':
+                    txt = m
+                else:
+                    txt = split(m)[-1]
+            self.left_tree.insert("", "end", iid=m, text=txt,
+                                  image=self.im_drive)
+            wrapper.add_tooltip(m, m)
+
+        # -------- home
+        home = expanduser("~")
+        self.left_tree.insert("", "end", iid=home, image=self.im_home,
+                              text=split(home)[-1])
+        wrapper.add_tooltip(home, home)
+
+        # -------- desktop
+        if OSNAME == 'nt':
+            desktop = shell.SHGetFolderPath(0, shellcon.CSIDL_DESKTOP, None, 0)
+        else:
+            try:
+                desktop = check_output(['xdg-user-dir', 'DESKTOP']).decode().strip()
+            except Exception:
+                # FileNotFoundError in python3 if xdg-users-dir is not installed,
+                # but OSError in python2
+                desktop = join(home, 'Desktop')
+            if exists(desktop):
+                self.left_tree.insert("", "end", iid=desktop, image=self.im_desktop,
+                                      text=split(desktop)[-1])
+                wrapper.add_tooltip(desktop, desktop)
+
+        # -------- bookmarks
+        if OSNAME == 'nt':
+            bm = []
+            for folder in [shellcon.CSIDL_PERSONAL, shellcon.CSIDL_MYPICTURES,
+                           shellcon.CSIDL_MYMUSIC, shellcon.CSIDL_MYVIDEO]:
+                try:
+                    bm.append([shell.SHGetFolderPath(0, folder, None, 0)])
+                except Exception:
+                    pass
+        else:
+            path_bm = join(home, ".config", "gtk-3.0", "bookmarks")
+            path_bm2 = join(home, ".gtk-bookmarks")  # old location
+            if exists(path_bm):
+                with open(path_bm) as f:
+                    bms = f.read().splitlines()
+            elif exists(path_bm2):
+                with open(path_bm) as f:
+                    bms = f.read().splitlines()
+            else:
+                bms = []
+            bms = [ch.split() for ch in bms]
+            bm = []
+            for ch in bms:
+                ch[0] = unquote(ch[0]).replace("file://", "")
+                bm.append(ch)
+        for l in bm:
+            if len(l) == 1:
+                txt = split(l[0])[-1]
+            else:
+                txt = l[1]
+            self.left_tree.insert("", "end", iid=l[0],
+                                  text=txt,
+                                  image=self.im_folder)
+            wrapper.add_tooltip(l[0], l[0])
+
+        # ---  right pane
+        right_pane = ttk.Frame(paned)
+        right_pane.columnconfigure(0, weight=1)
+        right_pane.rowconfigure(0, weight=1)
+        paned.add(right_pane, weight=1)
+
+        if mode != "save" and multiple_selection:
+            selectmode = "extended"
+        else:
+            selectmode = "browse"
+
+        self.right_tree = ttk.Treeview(right_pane, selectmode=selectmode,
+                                       style="right.tkfilebrowser.Treeview",
+                                       columns=("location", "size", "date"),
+                                       displaycolumns=("size", "date"))
+        # headings
+        self.right_tree.heading("#0", text=_("Name"), anchor="w",
+                                command=lambda: self._sort_files_by_name(True))
+        self.right_tree.heading("location", text=_("Location"), anchor="w",
+                                command=lambda: self._sort_by_location(False))
+        self.right_tree.heading("size", text=_("Size"), anchor="w",
+                                command=lambda: self._sort_by_size(False))
+        self.right_tree.heading("date", text=_("Modified"), anchor="w",
+                                command=lambda: self._sort_by_date(False))
+        # columns
+        self.right_tree.column("#0", width=250)
+        self.right_tree.column("location", width=100)
+        self.right_tree.column("size", stretch=False, width=85)
+        self.right_tree.column("date", width=120)
+        # tags
+        self.right_tree.tag_configure("0", background=tree_field_bg)
+        self.right_tree.tag_configure("1", background=active_bg)
+        self.right_tree.tag_configure("folder", image=self.im_folder)
+        self.right_tree.tag_configure("file", image=self.im_file)
+        self.right_tree.tag_configure("folder_link", image=self.im_folder_link)
+        self.right_tree.tag_configure("file_link", image=self.im_file_link)
+        self.right_tree.tag_configure("link_broken", image=self.im_link_broken)
+        if mode == "opendir":
+            self.right_tree.tag_configure("file", foreground="gray")
+            self.right_tree.tag_configure("file_link", foreground="gray")
+
+        self.right_tree.grid(row=0, column=0, sticky="eswn")
+        # scrollbar
+        self._scroll_h = AutoScrollbar(right_pane, orient='horizontal',
+                                       command=self.right_tree.xview)
+        self._scroll_h.grid(row=1, column=0, sticky='ew')
+        scroll_right = AutoScrollbar(right_pane, command=self.right_tree.yview)
+        scroll_right.grid(row=0, column=1, sticky="ns")
+        self.right_tree.configure(yscrollcommand=scroll_right.set,
+                                  xscrollcommand=self._scroll_h.set)
+
+        # ---  buttons
+        frame_buttons = ttk.Frame(self)
+        frame_buttons.grid(row=4, sticky="ew", pady=10, padx=10)
+        if okbuttontext is None:
+            if mode == "save":
+                okbuttontext = _("Save")
+            else:
+                okbuttontext = _("Open")
+        ttk.Button(frame_buttons, text=okbuttontext,
+                   command=self.validate).pack(side="right")
+        ttk.Button(frame_buttons, text=cancelbuttontext,
+                   command=self.quit).pack(side="right", padx=4)
+
+        # ---  key browsing entry
+        self.key_browse_var = tk.StringVar(self)
+        self.key_browse_entry = ttk.Entry(self, textvariable=self.key_browse_var,
+                                          width=10)
+        cst.add_trace(self.key_browse_var, "write", self._key_browse)
+        # list of folders/files beginning by the letters inserted in self.key_browse_entry
+        self.paths_beginning_by = []
+        self.paths_beginning_by_index = 0  # current index in the list
+
+        # ---  initialization
+        if not initialdir:
+            initialdir = expanduser("~")
+
+        self.display_folder(initialdir)
+        initialpath = join(initialdir, initialfile)
+        if initialpath in self.right_tree.get_children(""):
+            self.right_tree.see(initialpath)
+            self.right_tree.selection_add(initialpath)
+
+        # ---  bindings
+        # filetype combobox
+        self.bind_class('TCombobox', '<<ComboboxSelected>>',
+                        lambda e: e.widget.selection_clear(),
+                        add=True)
+        # left tree
+        self.left_tree.bind("<<TreeviewSelect>>", self._shortcut_select)
+        # right tree
+        self.right_tree.bind("<Double-1>", self._select)
+        self.right_tree.bind("<Return>", self._select)
+        self.right_tree.bind("<Left>", self._go_left)
+        if multiple_selection:
+            self.right_tree.bind("<Control-a>", self._right_tree_select_all)
+
+        if mode == "opendir":
+            self.right_tree.bind("<<TreeviewSelect>>",
+                                 self._file_selection_opendir)
+        elif mode == "openfile":
+            self.right_tree.bind("<<TreeviewSelect>>",
+                                 self._file_selection_openfile)
+        else:
+            self.right_tree.bind("<<TreeviewSelect>>",
+                                 self._file_selection_save)
+        self.right_tree.bind("<KeyPress>", self._key_browse_show)
+        # listbox
+        self.listbox.bind("<FocusOut>",
+                          lambda e: self.listbox_frame.place_forget())
+        # path entry
+        self.entry.bind("<Escape>",
+                        lambda e: self.listbox_frame.place_forget())
+        self.entry.bind("<Down>", self._down)
+        self.entry.bind("<Return>", self.validate)
+        self.entry.bind("<Right>", self._tab)
+        self.entry.bind("<Tab>", self._tab)
+        self.entry.bind("<Control-a>", self._select_all)
+
+        # key browse entry
+        self.key_browse_entry.bind("<FocusOut>", self._key_browse_hide)
+        self.key_browse_entry.bind("<Escape>", self._key_browse_hide)
+        self.key_browse_entry.bind("<Return>", self._key_browse_validate)
+
+        # main bindings
+        self.bind("<Control-h>", self.toggle_hidden)
+        self.bind("<Alt-Left>", self._hist_backward)
+        self.bind("<Alt-Right>", self._hist_forward)
+        self.bind("<Alt-Up>", self._go_to_parent)
+        self.bind("<Alt-Down>", self._go_to_child)
+        self.bind("<Button-1>", self._unpost, add=True)
+        self.bind("<FocusIn>", self._hide_listbox)
+
+        if mode != "save":
+            self.bind("<Control-l>", self.toggle_path_entry)
+        if self.foldercreation:
+            self.right_tree.bind("<Control-Shift-N>", self.create_folder)
+
+        self.update_idletasks()
+        self.lift()
+        if mode == 'save':
+            self.entry.selection_range(0, 'end')
+            self.entry.focus_set()
+
+    def _right_tree_select_all(self, event):
+        if self.mode == 'opendir':
+            tags = ['folder', 'folder_link']
+        else:
+            tags = ['file', 'file_link']
+        items = self.right_tree.tag_has(tags[0]) + self.right_tree.tag_has(tags[1])
+        self.right_tree.selection_clear()
+        self.right_tree.selection_set(items)
+
+    def _select_all(self, event):
+        """Select all entry content."""
+        event.widget.selection_range(0, "end")
+        return "break"  # suppress class binding
+
+    # ---  key browsing
+    def _key_browse_hide(self, event):
+        """Hide key browsing entry."""
+        if self.key_browse_entry.winfo_ismapped():
+            self.key_browse_entry.place_forget()
+            self.key_browse_entry.delete(0, "end")
+
+    def _key_browse_show(self, event):
+        """Show key browsing entry."""
+        if event.char.isalnum() or event.char in [".", "_", "(", "-", "*", "$"]:
+            self.key_browse_entry.place(in_=self.right_tree, relx=0, rely=1,
+                                        y=4, x=1, anchor="nw")
+            self.key_browse_entry.focus_set()
+            self.key_browse_entry.insert(0, event.char)
+
+    def _key_browse_validate(self, event):
+        """Hide key browsing entry and validate selection."""
+        self._key_browse_hide(event)
+        self.right_tree.focus_set()
+        self.validate()
+
+    def _key_browse(self, *args):
+        """Use keyboard to browse tree."""
+        self.key_browse_entry.unbind("<Up>")
+        self.key_browse_entry.unbind("<Down>")
+        deb = self.key_browse_entry.get().lower()
+        if deb:
+            if self.mode == 'opendir':
+                children = list(self.right_tree.tag_has("folder"))
+                children.extend(self.right_tree.tag_has("folder_link"))
+                children.sort()
+            else:
+                children = self.right_tree.get_children("")
+            self.paths_beginning_by = [i for i in children if split(i)[-1][:len(deb)].lower() == deb]
+            sel = self.right_tree.selection()
+            if sel:
+                self.right_tree.selection_remove(*sel)
+            if self.paths_beginning_by:
+                self.paths_beginning_by_index = 0
+                self._browse_list(0)
+                self.key_browse_entry.bind("<Up>",
+                                           lambda e: self._browse_list(-1))
+                self.key_browse_entry.bind("<Down>",
+                                           lambda e: self._browse_list(1))
+
+    def _browse_list(self, delta):
+        """
+        Navigate between folders/files with Up/Down keys.
+
+        Navigation between folders/files beginning by the letters in
+        self.key_browse_entry.
+        """
+        self.paths_beginning_by_index += delta
+        self.paths_beginning_by_index %= len(self.paths_beginning_by)
+        sel = self.right_tree.selection()
+        if sel:
+            self.right_tree.selection_remove(*sel)
+        path = abspath(join(self.history[self._hist_index],
+                            self.paths_beginning_by[self.paths_beginning_by_index]))
+        self.right_tree.see(path)
+        self.right_tree.selection_add(path)
+
+    # ---  column sorting
+    def _sort_files_by_name(self, reverse):
+        """Sort files and folders by (reversed) alphabetical order."""
+        files = list(self.right_tree.tag_has("file"))
+        files.extend(list(self.right_tree.tag_has("file_link")))
+        folders = list(self.right_tree.tag_has("folder"))
+        folders.extend(list(self.right_tree.tag_has("folder_link")))
+        files.sort(reverse=reverse)
+        folders.sort(reverse=reverse)
+
+        for index, item in enumerate(folders):
+            self.move_item(item, index)
+        l = len(folders)
+
+        for index, item in enumerate(files):
+            self.move_item(item, index + l)
+        self.right_tree.heading("#0",
+                                command=lambda: self._sort_files_by_name(not reverse))
+
+    def _sort_by_location(self, reverse):
+        """Sort files by location."""
+        l = [(self.right_tree.set(k, "location"), k) for k in self.right_tree.get_children('')]
+        l.sort(reverse=reverse)
+        for index, (val, k) in enumerate(l):
+            self.move_item(k, index)
+        self.right_tree.heading("location",
+                                command=lambda: self._sort_by_location(not reverse))
+
+    def _sort_by_size(self, reverse):
+        """Sort files by size."""
+        files = list(self.right_tree.tag_has("file"))
+        files.extend(list(self.right_tree.tag_has("file_link")))
+        nb_folders = len(self.right_tree.tag_has("folder"))
+        nb_folders += len(list(self.right_tree.tag_has("folder_link")))
+        files.sort(reverse=reverse, key=getsize)
+
+        for index, item in enumerate(files):
+            self.move_item(item, index + nb_folders)
+
+        self.right_tree.heading("size",
+                                command=lambda: self._sort_by_size(not reverse))
+
+    def _sort_by_date(self, reverse):
+        """Sort files and folders by modification date."""
+        files = list(self.right_tree.tag_has("file"))
+        files.extend(list(self.right_tree.tag_has("file_link")))
+        folders = list(self.right_tree.tag_has("folder"))
+        folders.extend(list(self.right_tree.tag_has("folder_link")))
+        l = len(folders)
+        folders.sort(reverse=reverse, key=getmtime)
+        files.sort(reverse=reverse, key=getmtime)
+
+        for index, item in enumerate(folders):
+            self.move_item(item, index)
+        for index, item in enumerate(files):
+            self.move_item(item, index + l)
+
+        self.right_tree.heading("date",
+                                command=lambda: self._sort_by_date(not reverse))
+
+    # ---  file selection
+    def _file_selection_save(self, event):
+        """Save mode only: put selected file name in name_entry."""
+        sel = self.right_tree.selection()
+        if sel:
+            sel = sel[0]
+            tags = self.right_tree.item(sel, "tags")
+            if ("file" in tags) or ("file_link" in tags):
+                self.entry.delete(0, "end")
+                if self.path_bar.winfo_ismapped():
+                    self.entry.insert(0, self.right_tree.item(sel, "text"))
+                else:
+                    # recently used files
+                    self.entry.insert(0, sel)
+                self.entry.selection_clear()
+                self.entry.icursor("end")
+
+    def _file_selection_openfile(self, event):
+        """Put selected file name in path_entry if visible."""
+        sel = self.right_tree.selection()
+        if sel and self.entry.winfo_ismapped():
+            self.entry.delete(0, 'end')
+            self.entry.insert("end", self.right_tree.item(sel[0], "text"))
+            self.entry.selection_clear()
+            self.entry.icursor("end")
+
+    def _file_selection_opendir(self, event):
+        """
+        Prevent selection of files in opendir mode and put selected folder
+        name in path_entry if visible.
+        """
+        sel = self.right_tree.selection()
+        if sel:
+            for s in sel:
+                tags = self.right_tree.item(s, "tags")
+                if ("file" in tags) or ("file_link" in tags):
+                    self.right_tree.selection_remove(s)
+            sel = self.right_tree.selection()
+            if len(sel) == 1 and self.entry.winfo_ismapped():
+                self.entry.delete(0, 'end')
+                self.entry.insert("end", self.right_tree.item(sel[0], "text"))
+                self.entry.selection_clear()
+                self.entry.icursor("end")
+
+    def _shortcut_select(self, event):
+        """Selection of a shortcut (left pane)."""
+        sel = self.left_tree.selection()
+        if sel:
+            sel = sel[0]
+            if sel != "recent":
+                self.display_folder(sel)
+            else:
+                self._display_recents()
+
+    def _display_recents(self):
+        """Display recently used files/folders."""
+        self.path_bar.grid_remove()
+        self.right_tree.configure(displaycolumns=("location", "size", "date"))
+        w = self.right_tree.winfo_width() - 305
+        if w < 0:
+            w = 250
+        self.right_tree.column("#0", width=w)
+        self.right_tree.column("location", stretch=False, width=100)
+        self.right_tree.column("size", stretch=False, width=85)
+        self.right_tree.column("date", width=120)
+        if self.foldercreation:
+            self.b_new_folder.grid_remove()
+        extension = self.filetypes[self.filetype.get()]
+        files = self._recent_files.get()
+        self.right_tree.delete(*self.right_tree.get_children(""))
+        i = 0
+        if self.mode == "opendir":
+            paths = []
+            for p in files:
+                if isfile(p):
+                    p = dirname(p)
+                d, f = split(p)
+                tags = [str(i % 2)]
+                vals = ()
+                if f:
+                    if f[0] == ".":
+                        tags.append("hidden")
+                else:
+                    f = "/"
+                if isdir(p):
+                    if islink(p):
+                        tags.append("folder_link")
+                    else:
+                        tags.append("folder")
+                    vals = (p, "", get_modification_date(p))
+                if vals and p not in paths:
+                    i += 1
+                    paths.append(p)
+                    self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                           values=vals)
+        else:
+            for p in files:
+                d, f = split(p)
+                tags = [str(i % 2)]
+                vals = ()
+                if f:
+                    if f[0] == ".":
+                        tags.append("hidden")
+                else:
+                    f = "/"
+                if islink(p):
+                    if isfile(p):
+                        if extension == r".*$" or search(extension, f):
+                            tags.append("file_link")
+                            stats = stat(p)
+                            vals = (p, display_size(stats.st_size),
+                                    display_modification_date(stats.st_mtime))
+                    elif isdir(p):
+                        tags.append("folder_link")
+                        vals = (p, "", get_modification_date(p))
+                elif isfile(p):
+                    if extension == r".*$" or search(extension, f):
+                        tags.append("file")
+                        stats = stat(p)
+                        vals = (p, display_size(stats.st_size),
+                                display_modification_date(stats.st_mtime))
+                elif isdir(p):
+                    tags.append("folder")
+                    vals = (p, "", get_modification_date(p))
+                if vals:
+                    i += 1
+                    self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                           values=vals)
+
+    def _select(self, event):
+        """display folder content on double click / Enter, validate if file."""
+        sel = self.right_tree.selection()
+        if sel:
+            sel = sel[0]
+            tags = self.right_tree.item(sel, "tags")
+            if ("folder" in tags) or ("folder_link" in tags):
+                self.display_folder(sel)
+            elif self.mode != "opendir":
+                self.validate(event)
+        elif self.mode == "opendir":
+            self.validate(event)
+
+    def _unpost(self, event):
+        """Hide self.key_browse_entry."""
+        if event.widget != self.key_browse_entry:
+            self._key_browse_hide(event)
+
+    def _hide_listbox(self, event):
+        """Hide the path proposition listbox."""
+        if event.widget not in [self.listbox, self.entry, self.listbox_frame]:
+            self.listbox_frame.place_forget()
+
+    def _change_filetype(self):
+        """Update view on filetype change."""
+        if self.path_bar.winfo_ismapped():
+            self.display_folder(self.history[self._hist_index])
+        else:
+            self._display_recents()
+        if self.mode == 'save':
+            filename = self.entry.get()
+            new_ext = self.filetypes[self.filetype.get()]
+            if filename and not search(new_ext, filename):
+                old_ext = search(r'\..+$', filename).group()
+                exts = [e[2:].replace('\.', '.') for e in new_ext[:-1].split('|')]
+                exts = [e for e in exts if search(r'\.[^\*]+$', e)]
+                if exts:
+                    filename = filename.replace(old_ext, exts[0])
+                self.entry.delete(0, 'end')
+                self.entry.insert(0, filename)
+
+    # ---  path completion in entries: key bindings
+    def _down(self, event):
+        """Focus listbox on Down arrow press in entry."""
+        self.listbox.focus_set()
+        self.listbox.selection_set(0)
+
+    def _tab(self, event):
+        """Go to the end of selected text and remove selection on tab press."""
+        self.entry = event.widget
+        self.entry.selection_clear()
+        self.entry.icursor("end")
+        return "break"
+
+    def _select_enter(self, event, d):
+        """Change entry content on Return key press in listbox."""
+        self.entry.delete(0, "end")
+        self.entry.insert(0, join(d, self.listbox.selection_get()))
+        self.entry.selection_clear()
+        self.entry.focus_set()
+        self.entry.icursor("end")
+
+    def _select_mouse(self, event, d):
+        """Change entry content on click in listbox."""
+        self.entry.delete(0, "end")
+        self.entry.insert(0, join(d, self.listbox.get("@%i,%i" % (event.x, event.y))))
+        self.entry.selection_clear()
+        self.entry.focus_set()
+        self.entry.icursor("end")
+
+    def _completion(self, action, modif, pos, prev_txt):
+        """Complete the text in the path entry with existing folder/file names."""
+        if self.entry.selection_present():
+            sel = self.entry.selection_get()
+            txt = prev_txt.replace(sel, '')
+        else:
+            txt = prev_txt
+        if action == "0":
+            self.listbox_frame.place_forget()
+            txt = txt[:int(pos)] + txt[int(pos) + 1:]
+        elif isabs(txt) or self.path_bar.winfo_ismapped():
+            txt = txt[:int(pos)] + modif + txt[int(pos):]
+            d, f = split(txt)
+            if f and not (f[0] == "." and self.hide):
+                if not isabs(txt):
+                    d2 = join(self.history[self._hist_index], d)
+                else:
+                    d2 = d
+
+                try:
+                    root, dirs, files = walk(d2).send(None)
+                    dirs.sort(key=lambda n: n.lower())
+                    l2 = []
+                    if self.mode != "opendir":
+                        files.sort(key=lambda n: n.lower())
+                        extension = self.filetypes[self.filetype.get()]
+                        if extension == r".*$":
+                            l2.extend([i.replace(" ", "\ ") for i in files if i[:len(f)] == f])
+                        else:
+                            for i in files:
+                                if search(extension, i) and i[:len(f)] == f:
+                                    l2.append(i.replace(" ", "\ "))
+                    l2.extend([i.replace(" ", "\ ") + "/" for i in dirs if i[:len(f)] == f])
+
+                except StopIteration:
+                    # invalid content
+                    l2 = []
+
+                if len(l2) == 1:
+                    self.listbox_frame.place_forget()
+                    i = self.entry.index("insert")
+                    self.entry.delete(0, "end")
+                    self.entry.insert(0, join(d, l2[0]))
+                    self.entry.selection_range(i + 1, "end")
+                    self.entry.icursor(i + 1)
+
+                elif len(l2) > 1:
+                    self.listbox.bind("<Return>", lambda e, arg=d: self._select_enter(e, arg))
+                    self.listbox.bind("<Button-1>", lambda e, arg=d: self._select_mouse(e, arg))
+                    self.listbox_var.set(" ".join(l2))
+                    self.listbox_frame.lift()
+                    self.listbox.configure(height=len(l2))
+                    self.listbox_frame.place(in_=self.entry, relx=0, rely=1,
+                                             anchor="nw", relwidth=1)
+                else:
+                    self.listbox_frame.place_forget()
+        return True
+
+    def _go_left(self, event):
+        """Move focus to left pane."""
+        sel = self.left_tree.selection()
+        if not sel:
+            sel = expanduser("~")
+        else:
+            sel = sel[0]
+        self.left_tree.focus_set()
+        self.left_tree.focus(sel)
+
+    # ---  go to parent/children folder with Alt+Up/Down
+    def _go_to_parent(self, event):
+        """Go to parent directory."""
+        parent = dirname(self.path_var.get())
+        self.display_folder(parent, update_bar=False)
+
+    def _go_to_child(self, event):
+        """Go to child directory."""
+        lb = [b.get_value() for b in self.path_bar_buttons]
+        i = lb.index(self.path_var.get())
+        if i < len(lb) - 1:
+            self.display_folder(lb[i + 1], update_bar=False)
+
+    # ---  navigate in history with Alt+Left/ Right keys
+    def _hist_backward(self, event):
+        """Navigate backward in folder selection history."""
+        if self._hist_index > -len(self.history):
+            self._hist_index -= 1
+            self.display_folder(self.history[self._hist_index], reset=False)
+
+    def _hist_forward(self, event):
+        """Navigate forward in folder selection history."""
+        try:
+            self.left_tree.selection_remove(*self.left_tree.selection())
+        except TypeError:
+            # error raised in python 2 by empty selection
+            pass
+        if self._hist_index < -1:
+            self._hist_index += 1
+            self.display_folder(self.history[self._hist_index], reset=False)
+
+    def _update_path_bar(self, path):
+        """Update the buttons in path bar."""
+        for b in self.path_bar_buttons:
+            b.destroy()
+        self.path_bar_buttons = []
+        if path == "/":
+            folders = []
+        else:
+            folders = path.split(SEP)
+            while '' in folders:
+                folders.remove('')
+        if OSNAME == 'nt':
+            p = folders.pop(0) + '\\'
+            b = PathButton(self.path_bar, self.path_var, p, text=p,
+                           command=lambda path=p: self.display_folder(path, update_bar=False))
+        else:
+            p = "/"
+            b = PathButton(self.path_bar, self.path_var, p, image=self.im_drive,
+                           command=lambda path=p: self.display_folder(path, update_bar=False))
+        self.path_bar_buttons.append(b)
+        b.grid(row=0, column=1, sticky="ns")
+        for i, folder in enumerate(folders):
+            p = join(p, folder)
+            b = PathButton(self.path_bar, self.path_var, p, text=folder,
+                           command=lambda f=p: self.display_folder(f, update_bar=False),
+                           style="path.tkfilebrowser.TButton")
+            self.path_bar_buttons.append(b)
+            b.grid(row=0, column=i + 2, sticky="ns")
+
+    def _display_folder_listdir(self, folder, reset=True, update_bar=True):
+        """
+        Display the content of folder in self.right_tree.
+        Arguments:
+            * reset (boolean): forget all the part of the history right of self._hist_index
+            * update_bar (boolean): update the buttons in path bar
+        """
+        # remove trailing / if any
+        folder = abspath(folder)
+        # reorganize display if previous was 'recent'
+        if not self.path_bar.winfo_ismapped():
+            self.path_bar.grid()
+            self.right_tree.configure(displaycolumns=("size", "date"))
+            w = self.right_tree.winfo_width() - 205
+            if w < 0:
+                w = 250
+            self.right_tree.column("#0", width=w)
+            self.right_tree.column("size", stretch=False, width=85)
+            self.right_tree.column("date", width=120)
+            if self.foldercreation:
+                self.b_new_folder.grid()
+        # reset history
+        if reset:
+            if not self._hist_index == -1:
+                self.history = self.history[:self._hist_index + 1]
+                self._hist_index = -1
+            self.history.append(folder)
+        # update path bar
+        if update_bar:
+            self._update_path_bar(folder)
+        self.path_var.set(folder)
+        # disable new folder creation if no write access
+        if self.foldercreation:
+            if access(folder, W_OK):
+                self.b_new_folder.state(('!disabled',))
+            else:
+                self.b_new_folder.state(('disabled',))
+        # clear self.right_tree
+        self.right_tree.delete(*self.right_tree.get_children(""))
+        self.right_tree.delete(*self.hidden)
+        self.hidden = ()
+        root = folder
+        extension = self.filetypes[self.filetype.get()]
+        content = listdir(folder)
+        i = 0
+        for f in content:
+            p = join(root, f)
+            if f[0] == ".":
+                tags = ("hidden",)
+                if not self.hide:
+                    tags = (str(i % 2),)
+                    i += 1
+            else:
+                tags = (str(i % 2),)
+                i += 1
+            if isfile(p):
+                if extension == r".*$" or search(extension, f):
+                    if islink(p):
+                        tags = tags + ("file_link",)
+                    else:
+                        tags = tags + ("file",)
+                    try:
+                        stats = stat(p)
+                    except OSError:
+                        self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                               values=("", "??", "??"))
+                    else:
+                        self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                               values=("",
+                                                       display_size(stats.st_size),
+                                                       display_modification_date(stats.st_mtime)))
+            elif isdir(p):
+                if islink(p):
+                    tags = tags + ("folder_link",)
+                else:
+                    tags = tags + ("folder",)
+
+                self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                       values=("", "", get_modification_date(p)))
+            else:  # broken link
+                tags = tags + ("link_broken",)
+                self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                       values=("", "??", "??"))
+
+        items = self.right_tree.get_children("")
+        if items:
+            self.right_tree.focus_set()
+            self.right_tree.focus(items[0])
+        if self.hide:
+            self.hidden = self.right_tree.tag_has("hidden")
+            self.right_tree.detach(*self.right_tree.tag_has("hidden"))
+        self._sort_files_by_name(False)
+
+    def _display_folder_walk(self, folder, reset=True, update_bar=True):
+        """
+        Display the content of folder in self.right_tree.
+        Arguments:
+            * reset (boolean): forget all the part of the history right of self._hist_index
+            * update_bar (boolean): update the buttons in path bar
+        """
+        # remove trailing / if any
+        folder = abspath(folder)
+        # reorganize display if previous was 'recent'
+        if not self.path_bar.winfo_ismapped():
+            self.path_bar.grid()
+            self.right_tree.configure(displaycolumns=("size", "date"))
+            w = self.right_tree.winfo_width() - 205
+            if w < 0:
+                w = 250
+            self.right_tree.column("#0", width=w)
+            self.right_tree.column("size", stretch=False, width=85)
+            self.right_tree.column("date", width=120)
+            if self.foldercreation:
+                self.b_new_folder.grid()
+        # reset history
+        if reset:
+            if not self._hist_index == -1:
+                self.history = self.history[:self._hist_index + 1]
+                self._hist_index = -1
+            self.history.append(folder)
+        # update path bar
+        if update_bar:
+            self._update_path_bar(folder)
+        self.path_var.set(folder)
+        # disable new folder creation if no write access
+        if self.foldercreation:
+            if access(folder, W_OK):
+                self.b_new_folder.state(('!disabled',))
+            else:
+                self.b_new_folder.state(('disabled',))
+        # clear self.right_tree
+        self.right_tree.delete(*self.right_tree.get_children(""))
+        self.right_tree.delete(*self.hidden)
+        self.hidden = ()
+        try:
+            root, dirs, files = walk(folder).send(None)
+            # display folders first
+            dirs.sort(key=lambda n: n.lower())
+            i = 0
+            for d in dirs:
+                p = join(root, d)
+                if islink(p):
+                    tags = ("folder_link",)
+                else:
+                    tags = ("folder",)
+                if d[0] == ".":
+                    tags = tags + ("hidden",)
+                    if not self.hide:
+                        tags = tags + (str(i % 2),)
+                        i += 1
+                else:
+                    tags = tags + (str(i % 2),)
+                    i += 1
+                self.right_tree.insert("", "end", p, text=d, tags=tags,
+                                       values=("", "", get_modification_date(p)))
+            # display files
+            files.sort(key=lambda n: n.lower())
+            extension = self.filetypes[self.filetype.get()]
+            for f in files:
+                if extension == r".*$" or search(extension, f):
+                    p = join(root, f)
+                    if islink(p):
+                        tags = ("file_link",)
+                    else:
+                        tags = ("file",)
+                    try:
+                        stats = stat(p)
+                    except FileNotFoundError:
+                        stats = Stats(st_size="??", st_mtime="??")
+                        tags = ("link_broken",)
+                    if f[0] == ".":
+                        tags = tags + ("hidden",)
+                        if not self.hide:
+                            tags = tags + (str(i % 2),)
+                            i += 1
+                    else:
+                        tags = tags + (str(i % 2),)
+                        i += 1
+
+                    self.right_tree.insert("", "end", p, text=f, tags=tags,
+                                           values=("",
+                                                   display_size(stats.st_size),
+                                                   display_modification_date(stats.st_mtime)))
+            items = self.right_tree.get_children("")
+            if items:
+                self.right_tree.focus_set()
+                self.right_tree.focus(items[0])
+            if self.hide:
+                self.hidden = self.right_tree.tag_has("hidden")
+                self.right_tree.detach(*self.right_tree.tag_has("hidden"))
+        except StopIteration:
+            self._display_folder_listdir(folder, reset, update_bar)
+        except PermissionError as e:
+            cst.showerror('PermissionError', str(e), master=self)
+
+    def _display_folder_scandir(self, folder, reset=True, update_bar=True):
+        """
+        Display the content of folder in self.right_tree.
+
+        Arguments:
+            * reset (boolean): forget all the part of the history right of self._hist_index
+            * update_bar (boolean): update the buttons in path bar
+        """
+        # remove trailing / if any
+        folder = abspath(folder)
+        # reorganize display if previous was 'recent'
+        if not self.path_bar.winfo_ismapped():
+            self.path_bar.grid()
+            self.right_tree.configure(displaycolumns=("size", "date"))
+            w = self.right_tree.winfo_width() - 205
+            if w < 0:
+                w = 250
+            self.right_tree.column("#0", width=w)
+            self.right_tree.column("size", stretch=False, width=85)
+            self.right_tree.column("date", width=120)
+            if self.foldercreation:
+                self.b_new_folder.grid()
+        # reset history
+        if reset:
+            if not self._hist_index == -1:
+                self.history = self.history[:self._hist_index + 1]
+                self._hist_index = -1
+            self.history.append(folder)
+        # update path bar
+        if update_bar:
+            self._update_path_bar(folder)
+        self.path_var.set(folder)
+        # disable new folder creation if no write access
+        if self.foldercreation:
+            if access(folder, W_OK):
+                self.b_new_folder.state(('!disabled',))
+            else:
+                self.b_new_folder.state(('disabled',))
+        # clear self.right_tree
+        self.right_tree.delete(*self.right_tree.get_children(""))
+        self.right_tree.delete(*self.hidden)
+        self.hidden = ()
+        extension = self.filetypes[self.filetype.get()]
+        try:
+            content = sorted(scandir(folder), key=key_sort_files)
+            i = 0
+            tags_array = [["folder", "folder_link"],
+                          ["file", "file_link"]]
+            for f in content:
+                b_file = f.is_file()
+                name = f.name
+                try:
+                    stats = f.stat()
+                    tags = (tags_array[b_file][f.is_symlink()],)
+                except FileNotFoundError:
+                    stats = Stats(st_size="??", st_mtime="??")
+                    tags = ("link_broken",)
+                if name[0] == '.':
+                    tags = tags + ("hidden",)
+                    if not self.hide:
+                        tags = tags + (str(i % 2),)
+                        i += 1
+                else:
+                    tags = tags + (str(i % 2),)
+                    i += 1
+                if b_file:
+                    if extension == r".*$" or search(extension, name):
+                        self.right_tree.insert("", "end", f.path, text=name, tags=tags,
+                                               values=("",
+                                                       display_size(stats.st_size),
+                                                       display_modification_date(stats.st_mtime)))
+                else:
+                    self.right_tree.insert("", "end", f.path, text=name, tags=tags,
+                                           values=("", "",
+                                                   display_modification_date(stats.st_mtime)))
+            items = self.right_tree.get_children("")
+            if items:
+                self.right_tree.focus_set()
+                self.right_tree.focus(items[0])
+            if self.hide:
+                self.hidden = self.right_tree.tag_has("hidden")
+                self.right_tree.detach(*self.right_tree.tag_has("hidden"))
+        except FileNotFoundError:
+            self._display_folder_scandir(expanduser('~'), reset=True, update_bar=True)
+        except PermissionError as e:
+            cst.showerror('PermissionError', str(e), master=self)
+
+    def create_folder(self, event=None):
+        """Create new folder in current location."""
+        def ok(event):
+            name = e.get()
+            e.destroy()
+            if name:
+                folder = join(path, name)
+                try:
+                    mkdir(folder)
+                except Exception:
+                    # show exception to the user (typically PermissionError or FileExistsError)
+                    cst.showerror(_("Error"), traceback.format_exc())
+                self.display_folder(path)
+
+        def cancel(event):
+            e.destroy()
+            self.right_tree.delete("tmp")
+
+        path = self.path_var.get()
+
+        if self.path_bar.winfo_ismapped() and access(path, W_OK):
+            self.right_tree.insert("", 0, "tmp", tags=("folder", "1"))
+            self.right_tree.see("tmp")
+            e = ttk.Entry(self)
+            x, y, w, h = self.right_tree.bbox("tmp", column="#0")
+            e.place(in_=self.right_tree, x=x + 24, y=y,
+                    width=w - x - 4)
+            e.bind("<Return>", ok)
+            e.bind("<Escape>", cancel)
+            e.bind("<FocusOut>", cancel)
+            e.focus_set()
+
+    def move_item(self, item, index):
+        """Move item to index and update dark/light line alternance."""
+        self.right_tree.move(item, "", index)
+        tags = [t for t in self.right_tree.item(item, 'tags')
+                if t not in ['1', '0']]
+        tags.append(str(index % 2))
+        self.right_tree.item(item, tags=tags)
+
+    def toggle_path_entry(self, event):
+        """Toggle visibility of path entry."""
+        if self.entry.winfo_ismapped():
+            self.entry.grid_remove()
+            self.entry.delete(0, "end")
+        else:
+            self.entry.grid()
+            self.entry.focus_set()
+
+    def toggle_hidden(self, event=None):
+        """Toggle the visibility of hidden files/folders."""
+        if self.hide:
+            self.hide = False
+            for item in reversed(self.hidden):
+                self.right_tree.move(item, "", 0)
+            self.hidden = ()
+        else:
+            self.hide = True
+            self.hidden = self.right_tree.tag_has("hidden")
+            self.right_tree.detach(*self.right_tree.tag_has("hidden"))
+        # restore color alternance
+        for i, item in enumerate(self.right_tree.get_children("")):
+            tags = [t for t in self.right_tree.item(item, 'tags')
+                    if t not in ['1', '0']]
+            tags.append(str(i % 2))
+            self.right_tree.item(item, tags=tags)
+
+    def get_result(self):
+        """Return selection."""
+        return self.result
+
+    def quit(self):
+        """Destroy dialog."""
+        self.destroy()
+        if self.result:
+            if isinstance(self.result, tuple):
+                for path in self.result:
+                    self._recent_files.add(path)
+            else:
+                self._recent_files.add(self.result)
+
+    def _validate_save(self):
+        """Validate selection in save mode."""
+        name = self.entry.get()
+        if name:
+            ext = splitext(name)[-1]
+            if not ext and not name[-1] == "/":
+                # append default extension if none given
+                name += self.defaultext
+            if isabs(name):
+                # name is an absolute path
+                if exists(dirname(name)):
+                    rep = True
+                    if isfile(name):
+                        rep = cst.askyesnocancel(_("Confirmation"),
+                                                 _("The file {file} already exists, do you want to replace it?").format(file=name),
+                                                 icon="warning")
+                    elif isdir(name):
+                        # it's a directory
+                        rep = False
+                        self.display_folder(name)
+                    path = name
+                else:
+                    # the path is invalid
+                    rep = False
+            elif self.path_bar.winfo_ismapped():
+                # we are not in the "recent files"
+                path = join(self.history[self._hist_index], name)
+                rep = True
+                if exists(path):
+                    if isfile(path):
+                        rep = cst.askyesnocancel(_("Confirmation"),
+                                                 _("The file {file} already exists, do you want to replace it?").format(file=name),
+                                                 icon="warning")
+                    else:
+                        # it's a directory
+                        rep = False
+                        self.display_folder(path)
+                elif not exists(dirname(path)):
+                    # the path is invalid
+                    rep = False
+            else:
+                # recently used file
+                sel = self.right_tree.selection()
+                if len(sel) == 1:
+                    path = sel[0]
+                    tags = self.right_tree.item(sel, "tags")
+                    if ("folder" in tags) or ("folder_link" in tags):
+                        rep = False
+                        self.display_folder(path)
+                    elif isfile(path):
+                        rep = cst.askyesnocancel(_("Confirmation"),
+                                                 _("The file {file} already exists, do you want to replace it?").format(file=name),
+                                                 icon="warning")
+                    else:
+                        rep = True
+                else:
+                    rep = False
+
+            if rep:
+                self.result = realpath(path)
+                self.quit()
+            elif rep is None:
+                self.quit()
+            else:
+                self.entry.delete(0, "end")
+                self.entry.focus_set()
+
+    def _validate_from_entry(self):
+        """
+        Validate selection from path entry in open mode.
+
+        Return False if the entry is empty, True otherwise.
+        """
+        name = self.entry.get()
+        if name:  # get file/folder from entry
+            if not isabs(name) and self.path_bar.winfo_ismapped():
+                # we are not in the "recent files"
+                name = join(self.history[self._hist_index], name)
+            if not exists(name):
+                self.entry.delete(0, "end")
+            elif self.mode == "openfile":
+                if isfile(name):
+                    if self.multiple_selection:
+                        self.result = (realpath(name),)
+                    else:
+                        self.result = realpath(name)
+                    self.quit()
+                else:
+                    self.display_folder(name)
+                    self.entry.grid_remove()
+                    self.entry.delete(0, "end")
+            else:
+                if self.multiple_selection:
+                    self.result = (realpath(name),)
+                else:
+                    self.result = realpath(name)
+                self.quit()
+            return True
+        else:
+            return False
+
+    def _validate_multiple_sel(self):
+        """Validate selection in open mode with multiple selection."""
+        sel = self.right_tree.selection()
+        if self.mode == "opendir":
+            if sel:
+                self.result = tuple(realpath(s) for s in sel)
+            else:
+                self.result = (realpath(self.history[self._hist_index]),)
+            self.quit()
+        else:  # mode == openfile
+            if len(sel) == 1:
+                sel = sel[0]
+                tags = self.right_tree.item(sel, "tags")
+                if ("folder" in tags) or ("folder_link" in tags):
+                    self.display_folder(sel)
+                else:
+                    self.result = (realpath(sel),)
+                    self.quit()
+            elif len(sel) > 1:
+                files = tuple(s for s in sel if "file" in self.right_tree.item(s, "tags"))
+                files = files + tuple(realpath(s) for s in sel if "file_link" in self.right_tree.item(s, "tags"))
+                if files:
+                    self.result = files
+                    self.quit()
+                else:
+                    self.right_tree.selection_remove(*sel)
+
+    def _validate_single_sel(self):
+        """Validate selection in open mode without multiple selection."""
+        sel = self.right_tree.selection()
+        if self.mode == "openfile":
+            if len(sel) == 1:
+                sel = sel[0]
+                tags = self.right_tree.item(sel, "tags")
+                if ("folder" in tags) or ("folder_link" in tags):
+                    self.display_folder(sel)
+                else:
+                    self.result = realpath(sel)
+                    self.quit()
+        else:  # mode is "opendir"
+            if len(sel) == 1:
+                self.result = realpath(sel[0])
+            else:
+                self.result = realpath(self.history[self._hist_index])
+            self.quit()
+
+    def validate(self, event=None):
+        """Validate selection and store it in self.results if valid."""
+        if self.mode == "save":
+            self._validate_save()
+        else:
+            validation = self._validate_from_entry()
+            if not validation:
+                # the entry is empty
+                if self.multiple_selection:
+                    self._validate_multiple_sel()
+                else:
+                    self._validate_single_sel()
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/functions.py
@@ -0,0 +1,228 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017-2018 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+Functions
+"""
+
+
+from tkfilebrowser.constants import _
+from tkfilebrowser.filebrowser import FileBrowser
+
+
+def askopendirname(parent=None, title=_("Open"), **kwargs):
+    """
+    Return :obj:`''` or the absolute path of the chosen directory.
+
+    Arguments:
+    
+        parent : Tk or Toplevel instance
+            parent window
+
+        title : str
+            the title of the filebrowser window
+
+        initialdir : str
+            directory whose content is initially displayed
+
+        initialfile : str
+            initially selected item (just the name, not the full path)
+
+        filetypes : list :obj:`[("name", "*.ext1|*.ext2|.."), ...]`
+          only the files of given filetype will be displayed,
+          e.g. to allow the user to switch between displaying only PNG or JPG
+          pictures or dispalying all files:
+          :obj:`filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]`
+
+        okbuttontext : str
+            text displayed on the validate button, default is "Open".
+
+        cancelbuttontext : str
+            text displayed on the button that cancels the selection, default is "Cancel".
+
+        foldercreation : bool
+            enable the user to create new folders if True (default)
+    """
+    dialog = FileBrowser(parent, mode="opendir", multiple_selection=False,
+                         title=title, **kwargs)
+    dialog.wait_window(dialog)
+    return dialog.get_result()
+
+
+def askopendirnames(parent=None, title=_("Open"), **kwargs):
+    """
+    Return :obj:`()` or the tuple of the absolute paths of the chosen directories
+
+    Arguments:
+    
+        parent : Tk or Toplevel instance
+            parent window
+
+        title : str
+            the title of the filebrowser window
+
+        initialdir : str
+            directory whose content is initially displayed
+
+        initialfile : str
+            initially selected item (just the name, not the full path)
+
+        filetypes : list :obj:`[("name", "*.ext1|*.ext2|.."), ...]`
+          only the files of given filetype will be displayed,
+          e.g. to allow the user to switch between displaying only PNG or JPG
+          pictures or dispalying all files:
+          :obj:`filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]`
+
+        okbuttontext : str
+            text displayed on the validate button, default is "Open".
+
+        cancelbuttontext : str
+            text displayed on the button that cancels the selection, default is "Cancel".
+
+        foldercreation : bool
+            enable the user to create new folders if True (default)
+    """
+    dialog = FileBrowser(parent, mode="opendir", multiple_selection=True,
+                         title=title, **kwargs)
+    dialog.wait_window(dialog)
+    res = dialog.get_result()
+    if not res:  # type consistency: always return a tuple
+        res = ()
+    return res
+
+
+def askopenfilename(parent=None, title=_("Open"), **kwargs):
+    """
+    Return :obj:`''` or the absolute path of the chosen file
+
+    Arguments:
+    
+        parent : Tk or Toplevel instance
+            parent window
+
+        title : str
+            the title of the filebrowser window
+
+        initialdir : str
+            directory whose content is initially displayed
+
+        initialfile : str
+            initially selected item (just the name, not the full path)
+
+        filetypes : list :obj:`[("name", "*.ext1|*.ext2|.."), ...]`
+          only the files of given filetype will be displayed,
+          e.g. to allow the user to switch between displaying only PNG or JPG
+          pictures or dispalying all files:
+          :obj:`filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]`
+
+        okbuttontext : str
+            text displayed on the validate button, default is "Open".
+
+        cancelbuttontext : str
+            text displayed on the button that cancels the selection, default is "Cancel".
+
+        foldercreation : bool
+            enable the user to create new folders if True (default)
+    """
+    dialog = FileBrowser(parent, mode="openfile", multiple_selection=False,
+                         title=title, **kwargs)
+    dialog.wait_window(dialog)
+    return dialog.get_result()
+
+
+def askopenfilenames(parent=None, title=_("Open"), **kwargs):
+    """
+    Return :obj:`()` or the tuple of the absolute paths of the chosen files
+
+    Arguments:
+    
+        parent : Tk or Toplevel instance
+            parent window
+
+        title : str
+            the title of the filebrowser window
+
+        initialdir : str
+            directory whose content is initially displayed
+
+        initialfile : str
+            initially selected item (just the name, not the full path)
+
+        filetypes : list :obj:`[("name", "*.ext1|*.ext2|.."), ...]`
+          only the files of given filetype will be displayed,
+          e.g. to allow the user to switch between displaying only PNG or JPG
+          pictures or dispalying all files:
+          :obj:`filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]`
+
+        okbuttontext : str
+            text displayed on the validate button, default is "Open".
+
+        cancelbuttontext : str
+            text displayed on the button that cancels the selection, default is "Cancel".
+
+        foldercreation : bool
+            enable the user to create new folders if True (default)
+    """
+    dialog = FileBrowser(parent, mode="openfile", multiple_selection=True,
+                         title=title, **kwargs)
+    dialog.wait_window(dialog)
+    res = dialog.get_result()
+    if not res:  # type consistency: always return a tuple
+        res = ()
+    return res
+
+
+def asksaveasfilename(parent=None, title=_("Save As"), **kwargs):
+    """
+    Return :obj:`''` or the chosen absolute path (the file might not exist)
+    
+    Arguments:
+    
+        parent : Tk or Toplevel instance
+            parent window
+
+        title : str
+            the title of the filebrowser window
+
+        initialdir : str
+            directory whose content is initially displayed
+
+        initialfile : str
+            initially selected item (just the name, not the full path)
+            
+        defaultext : str (e.g. '.png')
+            extension added to filename if none is given (default is none)  
+
+        filetypes : list :obj:`[("name", "*.ext1|*.ext2|.."), ...]`
+          only the files of given filetype will be displayed,
+          e.g. to allow the user to switch between displaying only PNG or JPG
+          pictures or dispalying all files:
+          :obj:`filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]`
+
+        okbuttontext : str
+            text displayed on the validate button, default is "Open".
+
+        cancelbuttontext : str
+            text displayed on the button that cancels the selection, default is "Cancel".
+
+        foldercreation : bool
+            enable the user to create new folders if True (default)
+    """
+    dialog = FileBrowser(parent, mode="save", title=title, **kwargs)
+    dialog.wait_window(dialog)
+    return dialog.get_result()
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/path_button.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+Path bar button class
+"""
+
+
+from tkfilebrowser.constants import add_trace, remove_trace, ttk
+
+
+class PathButton(ttk.Button):
+    """Toggle button class to make the path bar."""
+
+    def __init__(self, parent, variable, value, **kwargs):
+        """
+        Create a PathButton.
+
+        Like Radiobuttons, only one PathButton in the group (all PathButtons
+        sharing the same control variable) can be selected.
+
+        Options:
+            * parent: parent widget
+            * variable: control variable that the PathButton shares with the
+                        other PathButtons in the group (like for Radiobuttons)
+            * value: when the PathButton is clicked, the control variable is set
+                     to value
+            * all ttk.Button options
+        """
+        kwargs["style"] = "path.tkfilebrowser.TButton"
+        kwargs.setdefault("text", "")
+        txt = kwargs['text']
+        kwargs.setdefault("width", len(txt) + 1 + txt.count('m') + txt.count('M'))
+        ttk.Button.__init__(self, parent, **kwargs)
+        self.variable = variable
+        self.value = value
+        self._trace = add_trace(self.variable, "write", self.var_change)
+        self.bind("<Button-1>", self.on_press)
+
+    def on_press(self, event):
+        """Change the control variable value when the button is pressed."""
+        self.variable.set(self.value)
+
+    def get_value(self):
+        """Return value."""
+        return self.value
+
+    def destroy(self):
+        """Remove trace from variable and destroy widget."""
+        remove_trace(self.variable, "write", self._trace)
+        ttk.Button.destroy(self)
+
+    def var_change(self, *args):
+        """Change the state of the button when the control variable changes."""
+        self.master.update()
+        self.master.update_idletasks()
+        if self.variable.get() == self.value:
+            self.state(("selected",))
+        else:
+            self.state(("!selected",))
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/recent_files.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+The icons are modified versions of icons from the elementary project
+(the xfce fork to be precise https://github.com/shimmerproject/elementary-xfce)
+Copyright 2007-2013 elementary LLC.
+
+
+Recent files management
+"""
+
+
+class RecentFiles:
+    """Recent files manager."""
+    def __init__(self, filename, nbmax=30):
+        """
+        Create a recent file manager.
+
+        Options:
+            * filename: file where the recent file list is read/saved
+            * nbmax: maximum number of recent files to remember
+        """
+        self._filename = filename
+        self.nbmax = nbmax
+        self._files = []  # most recent files first
+        try:
+            with open(filename) as file:
+                self._files = file.read().splitlines()
+        except Exception:
+            pass
+
+    def get(self):
+        """Return recent file list."""
+        return self._files
+
+    def add(self, file):
+        """Add file to recent files."""
+        if file not in self._files:
+            self._files.insert(0, file)
+            if len(self._files) > self.nbmax:
+                del(self._files[-1])
+        else:
+            self._files.remove(file)
+            self._files.insert(0, file)
+        try:
+            with open(self._filename, 'w') as file:
+                file.write('\n'.join(self._files))
+        except Exception:
+            # avoid raising errors if location is read-only or invalid path
+            pass
--- /dev/null
+++ python-tkfilebrowser-2.3.2/.pybuild/cpython3_3.11_tkfilebrowser/build/tkfilebrowser/tooltip.py
@@ -0,0 +1,130 @@
+# *** coding: utf-8 -*-
+"""
+tkfilebrowser - Alternative to filedialog for Tkinter
+Copyright 2017 Juliette Monsel <j_4321@protonmail.com>
+
+tkfilebrowser is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+tkfilebrowser is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+Tooltip and TooltipTreeWrapper classes to display the full path of a shortcut
+when the mouse stays over long enough
+"""
+
+
+from tkfilebrowser.constants import tk, ttk
+from sys import platform
+
+
+class Tooltip(tk.Toplevel):
+    """Tooltip to display when the mouse stays long enough on an item."""
+    def __init__(self, parent, **kwargs):
+        """
+        Create Tooltip.
+
+        Options:
+            * parent: parent window
+            * text: text (str) to display in the tooltip
+            * compound: relative orientation of the graphic relative to the text
+            * alpha: opacity of the tooltip (0 for transparent, 1 for opaque),
+                     the text is affected too, so 0 would mean an invisible tooltip
+        """
+        tk.Toplevel.__init__(self, parent)
+        self.transient(parent)
+        if platform.startswith('linux'):
+            self.attributes('-type', 'tooltip')
+        self.attributes('-alpha', kwargs.get('alpha', 0.8))
+        self.overrideredirect(True)
+        style = kwargs.get('style', 'tooltip.tkfilebrowser.TLabel')
+
+        bg = ttk.Style(self).lookup(style, 'background')
+        self.configure(background=bg)
+
+        self.label = ttk.Label(self, text=kwargs.get('text', ''),
+                               style=style, compound=kwargs.get('compound', 'left'),
+                               padding=kwargs.get('padding', 4))
+        self.label.pack()
+
+    def configure(self, **kwargs):
+        if 'text' in kwargs:
+            self.label.configure(text=kwargs.pop('text'))
+        if 'image' in kwargs:
+            self.label.configure(image=kwargs.pop('image'))
+        if 'alpha' in kwargs:
+            self.attributes('-alpha', kwargs.pop('alpha'))
+        tk.Toplevel.configure(self, **kwargs)
+
+
+class TooltipTreeWrapper:
+    """Tooltip wrapper for a Treeview."""
+    def __init__(self, tree, delay=1500, **kwargs):
+        """
+        Create a Tooltip wrapper for the Treeview tree.
+
+        This wrapper enables the creation of tooltips for tree's items with all
+        the bindings to make them appear/disappear.
+
+        Options:
+            * tree: wrapped Treeview
+            * delay: hover delay before displaying the tooltip (ms)
+            * all keyword arguments of a Tooltip
+        """
+        self.tree = tree
+        self.delay = delay
+        self._timer_id = ''
+        self.tooltip_text = {}
+        self.tooltip = Tooltip(tree, **kwargs)
+        self.tooltip.withdraw()
+        self.current_item = None
+
+        self.tree.bind('<Motion>', self._on_motion)
+        self.tree.bind('<Leave>', self._on_leave)
+
+    def _on_leave(self, event):
+        try:
+            self.tree.after_cancel(self._timer_id)
+        except ValueError:
+            # nothing to cancel
+            pass
+
+    def add_tooltip(self, item, text):
+        """Add a tooltip with given text to the item."""
+        self.tooltip_text[item] = text
+
+    def _on_motion(self, event):
+        """Withdraw tooltip on mouse motion and cancel its appearance."""
+        if self.tooltip.winfo_ismapped():
+            x, y = self.tree.winfo_pointerxy()
+            if self.tree.winfo_containing(x, y) != self.tooltip:
+                if self.tree.identify_row(y - self.tree.winfo_rooty()):
+                    self.tooltip.withdraw()
+                    self.current_item = None
+        else:
+            try:
+                self.tree.after_cancel(self._timer_id)
+            except ValueError:
+                # nothing to cancel
+                pass
+            self._timer_id = self.tree.after(self.delay, self.display_tooltip)
+
+    def display_tooltip(self):
+        """Display the tooltip corresponding to the hovered item."""
+        item = self.tree.identify_row(self.tree.winfo_pointery() - self.tree.winfo_rooty())
+        text = self.tooltip_text.get(item, '')
+        self.current_item = item
+        if text:
+            self.tooltip.configure(text=text)
+            self.tooltip.deiconify()
+            x = self.tree.winfo_pointerx() + 14
+            y = self.tree.winfo_rooty() + self.tree.bbox(item)[1] + self.tree.bbox(item)[3]
+            self.tooltip.geometry('+%i+%i' % (x, y))
--- python-tkfilebrowser-2.3.2.orig/tkfilebrowser.egg-info/PKG-INFO
+++ python-tkfilebrowser-2.3.2/tkfilebrowser.egg-info/PKG-INFO
@@ -6,317 +6,7 @@ Home-page: https://github.com/j4321/tkFi
 Author: Juliette Monsel
 Author-email: j_4321@protonmail.com
 License: GPLv3
-Description: tkfilebrowser
-        =============
-        
-        |Release| |Linux| |Windows| |Travis| |Codecov| |License| |Doc|
-        
-        tkfilebrowser is an alternative to tkinter.filedialog that allows the
-        user to select files or directories. The GUI is written with tkinter but
-        the look is closer to GTK and the application uses GTK bookmarks (the
-        one displayed in nautilus or thunar for instance). This filebrowser
-        supports new directory creation and filtype filtering.
-        
-        This module contains a general ``FileBrowser`` class which implements the
-        filebrowser and the following functions, similar to the one in filedialog:
-        
-            * ``askopenfilename`` that allow the selection of a single file
-        
-            * ``askopenfilenames`` that allow the selection of multiple files
-        
-            * ``askopendirname`` that allow the selection a single folder
-        
-            * ``askopendirnames`` that allow the selection of multiple folders
-        
-            * ``asksaveasfilename`` that returns a single filename and give a warning if the file already exists
-        
-        
-        The documentation is also available here: https://tkfilebrowser.readthedocs.io
-        
-        .. contents:: Table of Contents
-        
-        
-        Requirements
-        ------------
-        
-        - Linux or Windows
-        - Python 2.7 or 3.x
-        
-        And the python packages:
-        
-        - tkinter (included in the python distribution for Windows)
-        - `psutil <https://pypi.org/project/psutil/>`_
-        - `babel <https://pypi.org/project/babel/>`_
-        - `pywin32 <https://pypi.org/project/pywin32/>`_ (Windows only)
-        - `pillow <https://pypi.org/project/pillow/>`_ (only if tkinter.TkVersion < 8.6)
-        
-        
-        Installation
-        ------------
-        
-        - Ubuntu: use the PPA `ppa:j-4321-i/ppa <https://launchpad.net/~j-4321-i/+archive/ubuntu/ppa>`__
-        
-            ::
-        
-                $ sudo add-apt-repository ppa:j-4321-i/ppa
-                $ sudo apt-get update
-                $ sudo apt-get install python(3)-tkfilebrowser
-        
-        
-        - Archlinux:
-        
-            the package is available on `AUR <https://aur.archlinux.org/packages/python-tkfilebrowser>`__
-        
-        
-        - With pip:
-        
-            ::
-        
-                $ pip install tkfilebrowser
-        
-        
-        Documentation
-        -------------
-        
-        * Optional keywords arguments common to each function
-        
-            - parent: parent window
-        
-            - title: the title of the filebrowser window
-        
-            - initialdir: directory whose content is initially displayed
-        
-            - initialfile: initially selected item (just the name, not the full path)
-        
-            - filetypes list: [("name", "\*.ext1|\*.ext2|.."), ...]
-              only the files of given filetype will be displayed,
-              e.g. to allow the user to switch between displaying only PNG or JPG
-              pictures or dispalying all files:
-              filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]
-        
-            - okbuttontext: text displayed on the validate button, if None, the
-              default text corresponding to the mode is used (either "Open" or "Save")
-        
-            - cancelbuttontext: text displayed on the button that cancels the
-              selection.
-        
-            - foldercreation: enable the user to create new folders if True (default)
-        
-        * askopendirname
-        
-            Allow the user to choose a single directory. The absolute path of the
-            chosen directory is returned. If the user cancels, an empty string is
-            returned.
-        
-        * askopendirnames
-        
-            Allow the user to choose multiple directories. A tuple containing the absolute
-            path of the chosen directories is returned. If the user cancels,
-            an empty tuple is returned.
-        
-        * askopenfilename
-        
-            Allow the user to choose a single file. The absolute path of the
-            chosen file is returned. If the user cancels, an empty string is
-            returned.
-        
-        * askopenfilenames
-        
-            Allow the user to choose multiple files. A tuple containing the absolute
-            path of the chosen files is returned. If the user cancels,
-            an empty tuple is returned.
-        
-        * asksaveasfilename
-        
-            Allow the user to choose a file path. The file may not exist but
-            the path to its directory does. If the file already exists, the user
-            is asked to confirm its replacement.
-        
-            Additional option:
-        
-                - defaultext: extension added to filename if none is given (default is none)
-        
-        
-        Changelog
-        ---------
-        
-        - tkfilebrowser 2.3.2
-            * Show networked drives on Windows
-            * Fix click on root button in path bar
-        
-        - tkfilebrowser 2.3.1
-            * Fix path bar navigation in Linux
-        
-        - tkfilebrowser 2.3.0
-            * Make package compatible with Windows
-            * Set initial focus on entry in save mode
-        
-        - tkfilebrowser 2.2.6
-            * No longer reset path bar when clicking on a path button
-            * Fix bug caused by broken links
-        
-        - tkfilebrowser 2.2.5
-            * Add compatibility with Tk < 8.6.0 (requires PIL.ImageTk)
-            * Add desktop icon in shortcuts
-            * Fix handling of spaces in bookmarks
-            * Fix bug due to spaces in recent file names
-        
-        - tkfilebrowser 2.2.4
-            * Fix bug in desktop folder identification
-        
-        - tkfilebrowser 2.2.3
-            * Fix FileNotFoundError if initialdir does not exist
-            * Add Desktop in shortcuts (if found)
-            * Improve filetype filtering
-        
-        - tkfilebrowser 2.2.2
-            * Fix ValueError in after_cancel with Python 3.6.5
-        
-        - tkfilebrowser 2.2.1
-            * Fix __main__.py for python 2
-        
-        - tkfilebrowser 2.2.0
-            * Use babel instead of locale in order not to change the locale globally
-            * Speed up (a little) folder content display
-            * Improve example: add comparison with default dialogs
-            * Add select all on Ctrl+A if multiple selection is enabled
-            * Disable folder creation button if the user does not have write access
-            * Improve extension management in save mode
-        
-        - tkfilebrowser 2.1.1
-            * Fix error if LOCAL_PATH does not exists or is not writtable
-        
-        - tkfilebrowser 2.1.0
-            * Add compatibility with tkinter.filedialog keywords 'master' and 'defaultextension'
-            * Change look of filetype selector
-            * Fix bugs when navigating without displaying hidden files
-            * Fix color alternance bug when hiding hidden files
-            * Fix setup.py
-            * Hide suggestion drop-down when nothing matches anymore
-        
-        - tkfilebrowser 2.0.0
-            * Change package name to tkfilebrowser to respect PEP 8
-            * Display error message when an issue occurs during folder creation
-            * Cycle only through folders with key browsing in "opendir" mode
-            * Complete only with folder names in "opendir" mode
-            * Fix bug: grey/white color alternance not always respected
-            * Add __main__.py with an example
-            * Add "Recent files" shortcut
-            * Make the text of the validate and cancel buttons customizable
-            * Add possibility to disable new folder creation
-            * Add python 2 support
-            * Add horizontal scrollbar
-        
-        - tkFileBrowser 1.1.2
-            * Add tooltips to display the full path of the shortcut if the mouse stays
-              long enough over it.
-            * Fix bug: style of browser treeview applied to parent
-        
-        - tkFileBrowser 1.1.1
-            * Fix bug: key browsing did not work with capital letters
-            * Add specific icons for symlinks
-            * Add handling of symlinks, the real path is returned instead of the link path
-        
-        - tkFileBrowser 1.1.0
-            * Fix bug concerning the initialfile argument
-            * Add column sorting (by name, size, modification date)
-        
-        - tkFileBrowser 1.0.1
-            * Set default filebrowser parent to None as for the usual filedialogs and messageboxes.
-        
-        - tkFileBrowser 1.0.0
-            * Initial version
-        
-        
-        Example
-        =======
-        
-        .. code:: python
-        
-            try:
-                import tkinter as tk
-                import tkinter.ttk as ttk
-                from tkinter import filedialog
-            except ImportError:
-                import Tkinter as tk
-                import ttk
-                import tkFileDialog as filedialog
-            from tkfilebrowser import askopendirname, askopenfilenames, asksaveasfilename
-        
-        
-            root = tk.Tk()
-        
-            style = ttk.Style(root)
-            style.theme_use("clam")
-        
-        
-            def c_open_file_old():
-                rep = filedialog.askopenfilenames(parent=root, initialdir='/', initialfile='tmp',
-                                                  filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("All files", "*")])
-                print(rep)
-        
-        
-            def c_open_dir_old():
-                rep = filedialog.askdirectory(parent=root, initialdir='/tmp')
-                print(rep)
-        
-        
-            def c_save_old():
-                rep = filedialog.asksaveasfilename(parent=root, defaultextension=".png", initialdir='/tmp', initialfile='image.png',
-                                                   filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("All files", "*")])
-                print(rep)
-        
-        
-            def c_open_file():
-                rep = askopenfilenames(parent=root, initialdir='/', initialfile='tmp',
-                                       filetypes=[("Pictures", "*.png|*.jpg|*.JPG"), ("All files", "*")])
-                print(rep)
-        
-        
-            def c_open_dir():
-                rep = askopendirname(parent=root, initialdir='/', initialfile='tmp')
-                print(rep)
-        
-        
-            def c_save():
-                rep = asksaveasfilename(parent=root, defaultext=".png", initialdir='/tmp', initialfile='image.png',
-                                        filetypes=[("Pictures", "*.png|*.jpg|*.JPG"), ("All files", "*")])
-                print(rep)
-        
-        
-            ttk.Label(root, text='Default dialogs').grid(row=0, column=0, padx=4, pady=4, sticky='ew')
-            ttk.Label(root, text='tkfilebrowser dialogs').grid(row=0, column=1, padx=4, pady=4, sticky='ew')
-            ttk.Button(root, text="Open files", command=c_open_file_old).grid(row=1, column=0, padx=4, pady=4, sticky='ew')
-            ttk.Button(root, text="Open folder", command=c_open_dir_old).grid(row=2, column=0, padx=4, pady=4, sticky='ew')
-            ttk.Button(root, text="Save file", command=c_save_old).grid(row=3, column=0, padx=4, pady=4, sticky='ew')
-            ttk.Button(root, text="Open files", command=c_open_file).grid(row=1, column=1, padx=4, pady=4, sticky='ew')
-            ttk.Button(root, text="Open folder", command=c_open_dir).grid(row=2, column=1, padx=4, pady=4, sticky='ew')
-            ttk.Button(root, text="Save file", command=c_save).grid(row=3, column=1, padx=4, pady=4, sticky='ew')
-        
-            root.mainloop()
-        
-        .. |Release| image:: https://badge.fury.io/py/tkfilebrowser.svg
-            :alt: Latest Release
-            :target: https://pypi.org/project/tkfilebrowser/
-        .. |Linux| image:: https://img.shields.io/badge/platform-Linux-blue.svg
-            :alt: Platform Linux
-        .. |Windows| image:: https://img.shields.io/badge/platform-Windows-blue.svg
-            :alt: Platform Windows
-        .. |Travis| image:: https://travis-ci.org/j4321/tkFileBrowser.svg?branch=master
-            :target: https://travis-ci.org/j4321/tkFileBrowser
-            :alt: Travis CI Build Status
-        .. |Codecov| image:: https://codecov.io/gh/j4321/tkFileBrowser/branch/master/graph/badge.svg
-            :target: https://codecov.io/gh/j4321/tkFileBrowser
-            :alt: Code coverage
-        .. |License| image:: https://img.shields.io/github/license/j4321/tkFileBrowser.svg
-            :target: https://www.gnu.org/licenses/gpl-3.0.en.html
-            :alt: License
-        .. |Doc| image:: https://readthedocs.org/projects/tkfilebrowser/badge/?version=latest
-            :target: https://tkfilebrowser.readthedocs.io/en/latest/?badge=latest
-            :alt: Documentation Status
-        
 Keywords: tkinter,filedialog,filebrowser
-Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: Topic :: Software Development :: Widget Sets
@@ -333,3 +23,313 @@ Classifier: Natural Language :: French
 Classifier: Operating System :: POSIX :: Linux
 Classifier: Operating System :: Microsoft :: Windows
 Provides-Extra: tk<8.6.0
+License-File: LICENSE.txt
+
+tkfilebrowser
+=============
+
+|Release| |Linux| |Windows| |Travis| |Codecov| |License| |Doc|
+
+tkfilebrowser is an alternative to tkinter.filedialog that allows the
+user to select files or directories. The GUI is written with tkinter but
+the look is closer to GTK and the application uses GTK bookmarks (the
+one displayed in nautilus or thunar for instance). This filebrowser
+supports new directory creation and filtype filtering.
+
+This module contains a general ``FileBrowser`` class which implements the
+filebrowser and the following functions, similar to the one in filedialog:
+
+    * ``askopenfilename`` that allow the selection of a single file
+
+    * ``askopenfilenames`` that allow the selection of multiple files
+
+    * ``askopendirname`` that allow the selection a single folder
+
+    * ``askopendirnames`` that allow the selection of multiple folders
+
+    * ``asksaveasfilename`` that returns a single filename and give a warning if the file already exists
+
+
+The documentation is also available here: https://tkfilebrowser.readthedocs.io
+
+.. contents:: Table of Contents
+
+
+Requirements
+------------
+
+- Linux or Windows
+- Python 2.7 or 3.x
+
+And the python packages:
+
+- tkinter (included in the python distribution for Windows)
+- `psutil <https://pypi.org/project/psutil/>`_
+- `babel <https://pypi.org/project/babel/>`_
+- `pywin32 <https://pypi.org/project/pywin32/>`_ (Windows only)
+- `pillow <https://pypi.org/project/pillow/>`_ (only if tkinter.TkVersion < 8.6)
+
+
+Installation
+------------
+
+- Ubuntu: use the PPA `ppa:j-4321-i/ppa <https://launchpad.net/~j-4321-i/+archive/ubuntu/ppa>`__
+
+    ::
+
+        $ sudo add-apt-repository ppa:j-4321-i/ppa
+        $ sudo apt-get update
+        $ sudo apt-get install python(3)-tkfilebrowser
+
+
+- Archlinux:
+
+    the package is available on `AUR <https://aur.archlinux.org/packages/python-tkfilebrowser>`__
+
+
+- With pip:
+
+    ::
+
+        $ pip install tkfilebrowser
+
+
+Documentation
+-------------
+
+* Optional keywords arguments common to each function
+
+    - parent: parent window
+
+    - title: the title of the filebrowser window
+
+    - initialdir: directory whose content is initially displayed
+
+    - initialfile: initially selected item (just the name, not the full path)
+
+    - filetypes list: [("name", "\*.ext1|\*.ext2|.."), ...]
+      only the files of given filetype will be displayed,
+      e.g. to allow the user to switch between displaying only PNG or JPG
+      pictures or dispalying all files:
+      filtypes=[("Pictures", "\*.png|\*.PNG|\*.jpg|\*.JPG'), ("All files", "\*")]
+
+    - okbuttontext: text displayed on the validate button, if None, the
+      default text corresponding to the mode is used (either "Open" or "Save")
+
+    - cancelbuttontext: text displayed on the button that cancels the
+      selection.
+
+    - foldercreation: enable the user to create new folders if True (default)
+
+* askopendirname
+
+    Allow the user to choose a single directory. The absolute path of the
+    chosen directory is returned. If the user cancels, an empty string is
+    returned.
+
+* askopendirnames
+
+    Allow the user to choose multiple directories. A tuple containing the absolute
+    path of the chosen directories is returned. If the user cancels,
+    an empty tuple is returned.
+
+* askopenfilename
+
+    Allow the user to choose a single file. The absolute path of the
+    chosen file is returned. If the user cancels, an empty string is
+    returned.
+
+* askopenfilenames
+
+    Allow the user to choose multiple files. A tuple containing the absolute
+    path of the chosen files is returned. If the user cancels,
+    an empty tuple is returned.
+
+* asksaveasfilename
+
+    Allow the user to choose a file path. The file may not exist but
+    the path to its directory does. If the file already exists, the user
+    is asked to confirm its replacement.
+
+    Additional option:
+
+        - defaultext: extension added to filename if none is given (default is none)
+
+
+Changelog
+---------
+
+- tkfilebrowser 2.3.2
+    * Show networked drives on Windows
+    * Fix click on root button in path bar
+
+- tkfilebrowser 2.3.1
+    * Fix path bar navigation in Linux
+
+- tkfilebrowser 2.3.0
+    * Make package compatible with Windows
+    * Set initial focus on entry in save mode
+
+- tkfilebrowser 2.2.6
+    * No longer reset path bar when clicking on a path button
+    * Fix bug caused by broken links
+
+- tkfilebrowser 2.2.5
+    * Add compatibility with Tk < 8.6.0 (requires PIL.ImageTk)
+    * Add desktop icon in shortcuts
+    * Fix handling of spaces in bookmarks
+    * Fix bug due to spaces in recent file names
+
+- tkfilebrowser 2.2.4
+    * Fix bug in desktop folder identification
+
+- tkfilebrowser 2.2.3
+    * Fix FileNotFoundError if initialdir does not exist
+    * Add Desktop in shortcuts (if found)
+    * Improve filetype filtering
+
+- tkfilebrowser 2.2.2
+    * Fix ValueError in after_cancel with Python 3.6.5
+
+- tkfilebrowser 2.2.1
+    * Fix __main__.py for python 2
+
+- tkfilebrowser 2.2.0
+    * Use babel instead of locale in order not to change the locale globally
+    * Speed up (a little) folder content display
+    * Improve example: add comparison with default dialogs
+    * Add select all on Ctrl+A if multiple selection is enabled
+    * Disable folder creation button if the user does not have write access
+    * Improve extension management in save mode
+
+- tkfilebrowser 2.1.1
+    * Fix error if LOCAL_PATH does not exists or is not writtable
+
+- tkfilebrowser 2.1.0
+    * Add compatibility with tkinter.filedialog keywords 'master' and 'defaultextension'
+    * Change look of filetype selector
+    * Fix bugs when navigating without displaying hidden files
+    * Fix color alternance bug when hiding hidden files
+    * Fix setup.py
+    * Hide suggestion drop-down when nothing matches anymore
+
+- tkfilebrowser 2.0.0
+    * Change package name to tkfilebrowser to respect PEP 8
+    * Display error message when an issue occurs during folder creation
+    * Cycle only through folders with key browsing in "opendir" mode
+    * Complete only with folder names in "opendir" mode
+    * Fix bug: grey/white color alternance not always respected
+    * Add __main__.py with an example
+    * Add "Recent files" shortcut
+    * Make the text of the validate and cancel buttons customizable
+    * Add possibility to disable new folder creation
+    * Add python 2 support
+    * Add horizontal scrollbar
+
+- tkFileBrowser 1.1.2
+    * Add tooltips to display the full path of the shortcut if the mouse stays
+      long enough over it.
+    * Fix bug: style of browser treeview applied to parent
+
+- tkFileBrowser 1.1.1
+    * Fix bug: key browsing did not work with capital letters
+    * Add specific icons for symlinks
+    * Add handling of symlinks, the real path is returned instead of the link path
+
+- tkFileBrowser 1.1.0
+    * Fix bug concerning the initialfile argument
+    * Add column sorting (by name, size, modification date)
+
+- tkFileBrowser 1.0.1
+    * Set default filebrowser parent to None as for the usual filedialogs and messageboxes.
+
+- tkFileBrowser 1.0.0
+    * Initial version
+
+
+Example
+=======
+
+.. code:: python
+
+    try:
+        import tkinter as tk
+        import tkinter.ttk as ttk
+        from tkinter import filedialog
+    except ImportError:
+        import Tkinter as tk
+        import ttk
+        import tkFileDialog as filedialog
+    from tkfilebrowser import askopendirname, askopenfilenames, asksaveasfilename
+
+
+    root = tk.Tk()
+
+    style = ttk.Style(root)
+    style.theme_use("clam")
+
+
+    def c_open_file_old():
+        rep = filedialog.askopenfilenames(parent=root, initialdir='/', initialfile='tmp',
+                                          filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("All files", "*")])
+        print(rep)
+
+
+    def c_open_dir_old():
+        rep = filedialog.askdirectory(parent=root, initialdir='/tmp')
+        print(rep)
+
+
+    def c_save_old():
+        rep = filedialog.asksaveasfilename(parent=root, defaultextension=".png", initialdir='/tmp', initialfile='image.png',
+                                           filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("All files", "*")])
+        print(rep)
+
+
+    def c_open_file():
+        rep = askopenfilenames(parent=root, initialdir='/', initialfile='tmp',
+                               filetypes=[("Pictures", "*.png|*.jpg|*.JPG"), ("All files", "*")])
+        print(rep)
+
+
+    def c_open_dir():
+        rep = askopendirname(parent=root, initialdir='/', initialfile='tmp')
+        print(rep)
+
+
+    def c_save():
+        rep = asksaveasfilename(parent=root, defaultext=".png", initialdir='/tmp', initialfile='image.png',
+                                filetypes=[("Pictures", "*.png|*.jpg|*.JPG"), ("All files", "*")])
+        print(rep)
+
+
+    ttk.Label(root, text='Default dialogs').grid(row=0, column=0, padx=4, pady=4, sticky='ew')
+    ttk.Label(root, text='tkfilebrowser dialogs').grid(row=0, column=1, padx=4, pady=4, sticky='ew')
+    ttk.Button(root, text="Open files", command=c_open_file_old).grid(row=1, column=0, padx=4, pady=4, sticky='ew')
+    ttk.Button(root, text="Open folder", command=c_open_dir_old).grid(row=2, column=0, padx=4, pady=4, sticky='ew')
+    ttk.Button(root, text="Save file", command=c_save_old).grid(row=3, column=0, padx=4, pady=4, sticky='ew')
+    ttk.Button(root, text="Open files", command=c_open_file).grid(row=1, column=1, padx=4, pady=4, sticky='ew')
+    ttk.Button(root, text="Open folder", command=c_open_dir).grid(row=2, column=1, padx=4, pady=4, sticky='ew')
+    ttk.Button(root, text="Save file", command=c_save).grid(row=3, column=1, padx=4, pady=4, sticky='ew')
+
+    root.mainloop()
+
+.. |Release| image:: https://badge.fury.io/py/tkfilebrowser.svg
+    :alt: Latest Release
+    :target: https://pypi.org/project/tkfilebrowser/
+.. |Linux| image:: https://img.shields.io/badge/platform-Linux-blue.svg
+    :alt: Platform Linux
+.. |Windows| image:: https://img.shields.io/badge/platform-Windows-blue.svg
+    :alt: Platform Windows
+.. |Travis| image:: https://travis-ci.org/j4321/tkFileBrowser.svg?branch=master
+    :target: https://travis-ci.org/j4321/tkFileBrowser
+    :alt: Travis CI Build Status
+.. |Codecov| image:: https://codecov.io/gh/j4321/tkFileBrowser/branch/master/graph/badge.svg
+    :target: https://codecov.io/gh/j4321/tkFileBrowser
+    :alt: Code coverage
+.. |License| image:: https://img.shields.io/github/license/j4321/tkFileBrowser.svg
+    :target: https://www.gnu.org/licenses/gpl-3.0.en.html
+    :alt: License
+.. |Doc| image:: https://readthedocs.org/projects/tkfilebrowser/badge/?version=latest
+    :target: https://tkfilebrowser.readthedocs.io/en/latest/?badge=latest
+    :alt: Documentation Status
--- python-tkfilebrowser-2.3.2.orig/tkfilebrowser.egg-info/SOURCES.txt
+++ python-tkfilebrowser-2.3.2/tkfilebrowser.egg-info/SOURCES.txt
@@ -2,6 +2,7 @@
 LICENSE.txt
 MANIFEST.in
 README.rst
+setup.cfg
 setup.py
 tkfilebrowser/__init__.py
 tkfilebrowser/__main__.py
--- python-tkfilebrowser-2.3.2.orig/tkfilebrowser.egg-info/requires.txt
+++ python-tkfilebrowser-2.3.2/tkfilebrowser.egg-info/requires.txt
@@ -1,5 +1,5 @@
-psutil
 babel
+psutil
 
 [tk<8.6.0]
 Pillow
