libtextworker 0.1.4
Cross-platform, free and open library for Python projects
dirctrl.py
1 """
2 @package libtextworker.interface.base.dirctrl
3 @brief The base of DirCtrl - directory tree widget
4 """
5 
6 # A cross-platform library for Python apps.
7 # Copyright (C) 2023-2024 Le Bao Nguyen and contributors.
8 # This is a part of the libtextworker project.
9 # Licensed under the GNU General Public License version 3.0 or later.
10 
11 import os
12 from libtextworker.general import libTewException
13 from typing import Callable, Literal, Any
14 from . import DC_FLAGS, WidgetBase
15 
16 __all__ = (
17  "DC_ONEROOT",
18  "DC_EDIT",
19  "DC_HIDEROOT",
20  "DC_MULTIPLE",
21  "DC_DIRONLY",
22  "DC_RIGHTCL",
23  "DC_USEICON",
24  "DirCtrlBase"
25 )
26 
27 DC_ONEROOT = DC_FLAGS.DC_ONEROOT
28 DC_EDIT = DC_FLAGS.DC_EDIT
29 DC_HIDEROOT = DC_FLAGS.DC_HIDEROOT
30 DC_MULTIPLE = DC_FLAGS.DC_MULTIPLE
31 DC_DIRONLY = DC_FLAGS.DC_DIRONLY
32 DC_RIGHTCL = DC_FLAGS.DC_RIGHTCL
33 DC_USEICON = DC_FLAGS.DC_USEICON
34 
35 
36 class DirCtrlBase(WidgetBase):
37  """
38  A directory tree.
39  Styles are defined in ..DC_FLAGS class and called in this module.
40 
41  Enabled by default:
42  * DC_EDIT (toolkit-specific)
43  * DC_USEICON (toolkit-specific)
44 
45  Features can be different on different platforms - this depends on the developer.
46  The actual tree, also scrollbars if enabled - must be placed in a frame (named Frame).
47  Custom flags (styles above) should be checked & implemented manually.
48  """
49 
50  currpath: str
51  Styles = DC_EDIT | DC_USEICON
52  History: dict[Any, list[str]]
53  HistoryIdx: int = 0
54 
55  def SetFolder(this, path: str, newroot: bool):
56  """
57  Make DirCtrl to show a directory tree.
58  If the directory is already used, will find that one and redraw.
59  @param path (str): Target folder
60  @param newroot (bool): Multiple root? Depends on DC_ONEROOT flag not to be included.
61  """
62 
63  path = os.path.normpath(path)
64  if not os.path.isdir(path):
65  raise NotADirectoryError(path)
66  else:
67  this.currpath = path
68 
69  if DC_ONEROOT in this.Styles and newroot == True:
70  raise libTewException(
71  "DirCtrl.SetFolder: Attemping to create a new root node but"
72  "DC_ONEROOT style is enabled, which blocks that behaviour."
73  "Report this to the developer."
74  )
75 
77  this, item: str | Callable | None = None, event: Callable | None = None
78  ) -> str:
79  """
80  Get the full path of an item if specified, else the path of the curernt selection.
81  @param event (Callable | None): GUI toolkit's event. Optional.
82  @param item (str | Callable | None). Item to use.
83  @returns str
84  """
85 
86  def GoForward(this):
87  # print(this.History)
88  if this.History and this.HistoryIdx < len(this.History):
89  this.SetFolder(this.History[this.HistoryIdx + 1])
90  this.HistoryIdx = this.HistoryIdx + 1
91  else:
92  return
93  this.PostSetDir(this.History[this.HistoryIdx], "forward")
94 
95  def GoBack(this):
96  # print(this.History)
97  if this.History and this.HistoryIdx > 0:
98  this.SetFolder(this.History[this.HistoryIdx - 1])
99  this.HistoryIdx = this.HistoryIdx - 1
100  else:
101  return
102  this.PostSetDir(this.History[this.HistoryIdx], "back")
103 
104  def PostSetDir(this, path, mode: Literal["forward", "back", "go"]) -> bool:
105  if not this.History or this.HistoryIdx:
106  return False
107  if mode == "forward":
108  if this.HistoryIdx == len(this.History):
109  return False # Can't go forward
110  else:
111  this.HistoryIdx = this.HistoryIdx + 1
112  if mode == "back":
113  if this.HistoryIdx == 0:
114  return False # Can't go back
115  else:
116  this.HistoryIdx = this.HistoryIdx - 1
117  if mode == "go":
118  if this.HistoryIdx not in [0, len(this.History)]:
119  for i in range(this.HistoryIdx, len(this.History)):
120  this.History.pop(i)
121  this.History.append(path)
122  this.HistoryIdx = len(this.History)
123 
124  # By default os.path.getsize/os.stat.st_size output will return a value in bytes
125  # So this is how we convert it to other units
126  # *from SO: a/1094933*
127  def sizeof_fmt(this, num, suffix="B"):
128  for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
129  if abs(num) < 1024.0:
130  return f"{num:3.1f}{unit}{suffix}"
131  num /= 1024.0
132  return f"{num:.1f}Yi{suffix}"
str GetFullPath(this, str|Callable|None item=None, Callable|None event=None)
Definition: dirctrl.py:78
def SetFolder(this, str path, bool newroot)
Definition: dirctrl.py:55