1515
1616# ---- Third party imports
1717from qtpy .QtCore import Signal
18+ from qtpy .QtGui import QIcon
1819from qtpy .QtWidgets import (
1920 QCheckBox , QFrame , QLineEdit , QLabel , QFileDialog , QPushButton ,
2021 QGridLayout , QWidget )
2122
23+ # ---- Local imports
24+ from qtapputils .qthelpers import create_toolbutton
25+
2226
2327class PathBoxWidget (QFrame ):
2428 """
25- A widget to display and select a directory or file location.
29+ a widget to display and select a directory or file location.
30+
31+ Features
32+ --------
33+ - Read-only line edit showing the current path.
34+ - Browse button to open a QFileDialog for selecting a path.
35+ - Optionally, uses a custom icon for the browse button.
36+ - Emits `sig_path_changed` when the path changes.
37+
38+ Parameters
39+ ----------
40+ parent : QWidget, optional
41+ Parent widget.
42+ path_type : str, optional
43+ Type of path dialog: 'getExistingDirectory', 'getOpenFileName', or
44+ 'getSaveFileName'.
45+ filters : str, optional
46+ Filter string for file dialogs.
47+ gettext : Callable, optional
48+ Translation function for GUI strings.
49+ browse_icon : QIcon, optional
50+ Custom icon for the browse button.
2651 """
2752 sig_path_changed = Signal (str )
2853
29- def __init__ (self , parent : QWidget = None , path : str = '' ,
30- directory : str = '' , path_type : str = 'getExistingDirectory' ,
31- filters : str = None , gettext : Callable = None ):
54+ def __init__ (
55+ self ,
56+ parent : QWidget = None ,
57+ path_type : str = 'getExistingDirectory' ,
58+ filters : str = None ,
59+ gettext : Callable = None ,
60+ browse_icon : QIcon = None ):
3261 super ().__init__ (parent )
3362
3463 _ = gettext if gettext else lambda x : x
@@ -39,43 +68,56 @@ def __init__(self, parent: QWidget = None, path: str = '',
3968 elif path_type == 'getSaveFileName' :
4069 self ._caption = _ ('Save File' )
4170
42- self ._directory = directory
71+ self ._directory = osp . expanduser ( '~' )
4372 self .filters = filters
4473 self ._path_type = path_type
4574
46- self .browse_btn = QPushButton (_ ("Browse..." ))
47- self .browse_btn .setDefault (False )
48- self .browse_btn .setAutoDefault (False )
49- self .browse_btn .clicked .connect (self .browse_path )
50-
5175 self .path_lineedit = QLineEdit ()
5276 self .path_lineedit .setReadOnly (True )
53- self .path_lineedit .setText (path )
54- self .path_lineedit .setToolTip (path )
55- self .path_lineedit .setFixedHeight (
56- self .browse_btn .sizeHint ().height () - 2 )
77+ if browse_icon is None :
78+ self .browse_btn = QPushButton (_ ("Browse..." ))
79+ self .browse_btn .setDefault (False )
80+ self .browse_btn .setAutoDefault (False )
81+ self .browse_btn .clicked .connect (self .browse_path )
82+ # Align line edit height with button.
83+ self .path_lineedit .setFixedHeight (
84+ self .browse_btn .sizeHint ().height () - 2 )
85+ else :
86+ self .browse_btn = create_toolbutton (
87+ self ,
88+ icon = browse_icon ,
89+ text = _ ("Browse..." ),
90+ triggered = self .browse_path ,
91+ )
5792
5893 layout = QGridLayout (self )
5994 layout .setContentsMargins (0 , 0 , 0 , 0 )
6095 layout .setSpacing (3 )
6196 layout .addWidget (self .path_lineedit , 0 , 0 )
6297 layout .addWidget (self .browse_btn , 0 , 1 )
6398
64- def is_valid (self ):
65- """Return whether path is valid ."""
99+ def is_valid (self ) -> bool :
100+ """Return True if the current path exists on disk ."""
66101 return osp .exists (self .path ())
67102
68- def is_empty (self ):
69- """Return whether the path is empty."""
70- return self .path_lineedit .text () == ''
103+ def is_empty (self ) -> bool :
104+ """Return True if the current path is empty."""
105+ return not self .path_lineedit .text (). strip ()
71106
72- def path (self ):
73- """Return the path of this pathbox widget ."""
107+ def path (self ) -> str :
108+ """Return the currently displayed path ."""
74109 return self .path_lineedit .text ()
75110
76111 def set_path (self , path : str ):
77- """Set the path to the specified value."""
78- if path == self .path :
112+ """
113+ Set the path to the specified value.
114+
115+ Parameters
116+ ----------
117+ path : str
118+ The new path to display and set as default directory.
119+ """
120+ if path == self .path ():
79121 return
80122
81123 self .path_lineedit .setText (path )
@@ -90,22 +132,29 @@ def browse_path(self):
90132 self , self ._caption , self .directory (),
91133 options = QFileDialog .ShowDirsOnly )
92134 elif self ._path_type == 'getOpenFileName' :
93- path , ext = QFileDialog .getOpenFileName (
135+ path , _ = QFileDialog .getOpenFileName (
94136 self , self ._caption , self .directory (), self .filters )
95137 elif self ._path_type == 'getSaveFileName' :
96- path , ext = QFileDialog .getSaveFileName (
138+ path , _ = QFileDialog .getSaveFileName (
97139 self , self ._caption , self .directory (), self .filters )
98140
99141 if path :
100142 self .set_path (path )
101143
102- def directory (self ):
144+ def directory (self ) -> str :
103145 """Return the directory that is used by the QFileDialog."""
104146 return (self ._directory if osp .exists (self ._directory ) else
105147 osp .expanduser ('~' ))
106148
107149 def set_directory (self , directory : str = path ):
108- """Set the default directory that will be used by the QFileDialog."""
150+ """
151+ Set the default directory for file dialogs.
152+
153+ Parameters
154+ ----------
155+ directory : str or None
156+ Directory path to set as default.
157+ """
109158 if directory is not None and osp .exists (directory ):
110159 self ._directory = directory
111160
0 commit comments