2 @package libtextworker.interface.tk.dirctrl
3 @brief Directory tree for Tkinter
14 from tkinter
import TclError, ttk, Misc
16 from ..base.dirctrl
import *
18 from ...general
import CraftItems
21 from watchdog.observers
import Observer
25 FileEditedEvent =
"<<FileEdited>>"
26 FileCreatedEvent =
"<<FileCreated>>"
27 FileDeletedEvent =
"<<FileDeleted>>"
28 FileOpenedEvent =
"<<FileOpened>>"
29 FileClosedEvent =
"<<FileClosed>>"
30 FileMovedEvent =
"<<FileMoved>>"
32 DirEditedEvent =
"<<DirEdited>>"
33 DirCreatedEvent =
"<<DirCreated>>"
34 DirMovedEvent =
"<<DirMoved>>"
35 DirDeletedEvent =
"<<DirDeleted>>"
39 A file system events handler derived from watchdog's FileSystemEventHandler.
41 On both wx and Tk, a new event will be generated.
42 Set the Target attribute which the handler sends the event to.
44 On Tk, since a new event is just a new event: no custom value allowed. However
45 you can do a bind_class to connect the event to all widgets with your specified
49 # Binds FileDeletedEvent to all StyledTextControl instances
50 root.bind_class('StyledTextControl', FileDeletedEvent, callback)
51 # Or this (add=True won't replace the current callback if any)
52 widget.bind(FileDeletedEvent, callback, add=True)
55 Or, if you use this for your own widget, derive this class like any other classes
56 you use for that widget, and set TargetIsSelf = True instead of Target.
57 This class does not use __init__.
59 Currently only one target is supported. You need to do something else to handle the
60 events generated here.
66 def evtIsDir(this, event: FileSystemEvent):
return "Dir" if event.is_directory
else "File"
67 def getTarget(this):
return this.Target
if not this.TargetIsSelf
else this
72 def on_moved(this, event: FileSystemEvent):
73 if this.evtIsDir(event) ==
"Dir": what_to_use = DirMovedEvent
74 else: what_to_use = FileMovedEvent
75 this.getTarget().event_generate(what_to_use, path=event.src_path)
77 def on_created(this, event: FileSystemEvent):
78 if this.evtIsDir(event) ==
"Dir": what_to_use = DirCreatedEvent
79 else: what_to_use = FileCreatedEvent
80 this.getTarget().event_generate(what_to_use, path=event.src_path)
82 def on_deleted(this, event: FileSystemEvent):
83 if this.evtIsDir(event) ==
"Dir": what_to_use = DirDeletedEvent
84 else: what_to_use = FileDeletedEvent
85 this.getTarget().event_generate(what_to_use, path=event.src_path)
87 def on_modified(this, event: FileSystemEvent):
88 if this.evtIsDir(event) ==
"Dir": what_to_use = DirEditedEvent
89 else: what_to_use = FileEditedEvent
90 this.getTarget().event_generate(what_to_use, path=event.src_path)
92 def on_closed(this, event: FileSystemEvent):
93 this.getTarget().event_generate(FileClosedEvent, path=event.src_path)
95 def on_opened(this, event: FileSystemEvent):
96 this.getTarget().event_generate(FileOpenedEvent, path=event.src_path)
99 Parent_ArgName =
"master"
101 Observers: dict[str, Observer] = {}
106 A ttkTreeview customized to show folder list using os.listdir.
107 Multiple roots is supported, but only adding new for now.
108 Lacks label editing, DND, right-click menu, item icon.
110 DirCtrl's custom styles can be defined via the "w_styles" keyword.
112 args, kwds = DirCtrlBase.__init__(this, *args, **kwds)
113 ttk.Treeview.__init__(this, this.Frame, *args, **kwds)
115 ysb = ttk.Scrollbar(this.Frame, orient=
"vertical", command=this.yview)
116 xsb = ttk.Scrollbar(this.Frame, orient=
"horizontal", command=this.xview)
117 this.configure(yscroll=ysb.set, xscroll=xsb.set)
123 this.grid(column=0, row=0)
124 ysb.grid(column=1, row=0, sticky=
"ns")
125 xsb.grid(column=0, row=1, sticky=
"ew")
129 for key
in this.Observers:
130 this.Observers[key].stop()
131 this.Observers[key].join()
132 this.Observers.clear()
133 ttk.Treeview.destroy(this)
136 def insert_node(node: str, folderpath: str):
137 for item
in os.listdir(folderpath):
139 new = this.insert(node,
"end", text=item, open=
False)
140 if os.path.isdir(os.path.join(folderpath, item)):
141 this.insert(new,
"end")
148 this.item(path, open=
True)
149 fullpath = os.path.normpath(this.GetFullPath())
150 iter = os.listdir(fullpath)
155 this.delete(this.get_children(path))
159 insert_node(path, fullpath)
161 DirCtrlBase.SetFolder(this, path, newroot)
163 first = this.insert(
"",
"end", text=path)
164 insert_node(first, path)
166 this.Observers[path] = Observer()
167 this.Observers[path].schedule(this, path, recursive=
True)
168 this.Observers[path].start()
170 this.bind(
"<<TreeviewOpen>>", Expand)
172 def GetFullPath(this, item: str |
None =
None) -> str:
177 parent = this.parent(item)
182 text = this.item(parent,
"text")
185 parent = this.parent(parent)
194 return CraftItems(*tuple(node), this.item(item,
"text"))
198 Parent_ArgName =
"master"
203 A directory items list.
204 By default contains these columns:
206 * Item type (file, folder)
209 Navigate history support. Not much customizable for now.
210 No libtextworker custom style support for now.
213 args, kwds = DirCtrlBase.__init__(this, *args, **kwds)
214 ttk.Treeview.__init__(this, this.Frame, show=
"headings",
215 columns=[_(
"Name"), _(
"Item type"), _(
"Last modified"), _(
"Size")],
218 ysb = ttk.Scrollbar(this.Frame, orient=
"vertical", command=this.yview)
219 xsb = ttk.Scrollbar(this.Frame, orient=
"horizontal", command=this.xview)
220 this.configure(yscroll=ysb.set, xscroll=xsb.set)
226 this.grid(column=0, row=0, sticky=
"nsew")
227 ysb.grid(column=1, row=0, sticky=
"nse")
228 xsb.grid(column=0, row=1, sticky=
"ews")
232 Navigate to the specified folder.
234 DirCtrlBase.SetFolder(this, path,
False)
235 this.delete(*this.get_children())
237 for it
in os.listdir(path):
238 fullpath = os.path.join(path, it)
239 statinfo = os.stat(fullpath)
241 if os.path.isdir(os.path.join(path, it)):
242 it_type = _(
"Folder")
244 elif DC_DIRONLY
not in this.Styles:
246 it_size = this.sizeof_fmt(statinfo.st_size)
248 lastmod = time.strftime(
249 "%d %b %Y, %H:%M:%S", time.localtime(statinfo.st_mtime)
252 this.insert(
"",
"end", values=(it, it_type, lastmod, it_size))
def __init__(this, *args, **kwds)
def SetFolder(this, str path, bool newroot=False)
def SetFolder(this, str path)
def __init__(this, *args, **kwds)