fix Makefiles
[enigma2.git] / lib / python / Screens / LocationBox.py
1 #
2 # Generic Screen to select a path/filename combination
3 #
4
5 # GUI (Screens)
6 from Screens.Screen import Screen
7 from Screens.MessageBox import MessageBox
8 from Screens.InputBox import InputBox
9
10 # Generic
11 from Tools.BoundFunction import boundFunction
12
13 # Quickselect
14 from Tools.NumericalTextInput import NumericalTextInput
15
16 # GUI (Components)
17 from Components.ActionMap import NumberActionMap
18 from Components.Label import Label
19 from Components.Pixmap import Pixmap
20 from Components.Button import Button
21 from Components.FileList import FileList
22
23 # Timer
24 from enigma import eTimer
25
26 class LocationBox(Screen, NumericalTextInput):
27         """Simple Class similar to MessageBox / ChoiceBox but used to choose a folder/pathname combination"""
28
29         skin = """<screen name="LocationBox" position="100,130" size="540,340" >
30                         <widget name="text" position="0,2" size="540,22" font="Regular;22" />
31                         <widget name="filelist" position="0,25" size="540,235" />
32                         <widget name="target" position="0,260" size="540,40" valign="center" font="Regular;22" />
33                         <widget name="yellow" position="260,300" zPosition="1" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
34                         <widget name="key_yellow" position="260,300" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
35                         <widget name="green" position="400,300" zPosition="1" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
36                         <widget name="key_green" position="400,300" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
37                 </screen>"""
38
39         def __init__(self, session, text = "", filename = "", currDir = None, windowTitle = _("Select Location"), minFree = None):
40                 # Init parents
41                 Screen.__init__(self, session)
42                 NumericalTextInput.__init__(self, handleTimeout = False)
43
44                 # Set useable chars
45                 self.setUseableChars(u'1234567890abcdefghijklmnopqrstuvwxyz')
46
47                 # Quickselect Timer
48                 self.qs_timer = eTimer()
49                 self.qs_timer.callback.append(self.timeout)
50                 self.qs_timer_type = 0
51
52                 # Initialize Quickselect
53                 self.curr_pos = -1
54                 self.quickselect = ""
55
56                 # Set Text
57                 self["text"] = Label(text)
58
59                 # Save parameters locally
60                 self.text = text
61                 self.filename = filename
62                 self.minFree = minFree
63
64                 # Initialize FileList
65                 self["filelist"] = FileList(currDir, showDirectories = True, showFiles = False)
66
67                 # Buttons
68                 self["key_green"] = Button(_("Confirm"))
69                 self["key_yellow"] = Button(_("Rename"))
70
71                 # Background for Buttons
72                 self["green"] = Pixmap()
73                 self["yellow"] = Pixmap()
74
75                 # Initialize Target
76                 self["target"] = Label()
77
78                 # Custom Action Handler
79                 class LocationBoxActionMap(NumberActionMap):
80                         def __init__(self, box, contexts = [ ], actions = { }, prio=0):                                                                                                                                                                                                                                    
81                                 NumberActionMap.__init__(self, contexts, actions, prio)
82                                 self.box = box
83
84                         def action(self, contexts, action):
85                                 # Reset Quickselect
86                                 self.box.timeout(force = True)
87
88                                 return NumberActionMap.action(self, contexts, action)
89
90                 # Actions that will reset quickselect
91                 self["actions"] = LocationBoxActionMap(self, ["WizardActions", "ColorActions"],
92                 {
93                         "ok": self.ok,
94                         "back": self.cancel,
95                         "green": self.select,
96                         "yellow": self.changeName,
97                         "left": self.left,
98                         "right": self.right,
99                         "up": self.up,
100                         "down": self.down,
101                 }, -2)
102
103                 # Actions used by quickselect
104                 self["NumberActions"] = NumberActionMap(["NumberActions"],
105                 {
106                         "1": self.keyNumberGlobal,
107                         "2": self.keyNumberGlobal,
108                         "3": self.keyNumberGlobal,
109                         "4": self.keyNumberGlobal,
110                         "5": self.keyNumberGlobal,
111                         "6": self.keyNumberGlobal,
112                         "7": self.keyNumberGlobal,
113                         "8": self.keyNumberGlobal,
114                         "9": self.keyNumberGlobal,
115                         "0": self.keyNumberGlobal
116                 })
117
118                 # Run some functions when shown
119                 self.onShown.extend([
120                         boundFunction(self.setTitle, windowTitle),
121                         self.updateTarget,
122                         self.showHideRename
123                 ])
124  
125                 # Make sure we remove our callback
126                 self.onClose.append(self.disableTimer)
127
128         def disableTimer(self):
129                 self.qs_timer.callback.remove(self.timeout)
130
131         def showHideRename(self):
132                 # Don't allow renaming when filename is empty
133                 if self.filename == "":
134                         self["yellow"].hide()
135                         self["key_yellow"].hide()
136
137         def up(self):
138                 self["filelist"].up()
139
140         def down(self):
141                 self["filelist"].down()
142
143         def left(self):
144                 self["filelist"].pageUp()
145
146         def right(self):
147                 self["filelist"].pageDown()
148
149         def ok(self):
150                 if self["filelist"].canDescent():
151                         self["filelist"].descent()
152                         self.updateTarget()
153
154         def cancel(self):
155                 self.close(None)
156
157         def selectConfirmed(self, res):
158                 if res: 
159                         self.close(''.join([self["filelist"].getCurrentDirectory(), self.filename]))
160
161         def select(self):
162                 # Do nothing unless current Directory is valid
163                 if self["filelist"].getCurrentDirectory() is not None:
164                         # Check if we need to have a minimum of free Space available
165                         if self.minFree is not None:
166                                 # Try to read fs stats
167                                 try:
168                                         from os import statvfs
169
170                                         s = statvfs(self["filelist"].getCurrentDirectory())
171                                         if (s.f_bavail * s.f_bsize) / 1000000 > self.minFree:
172                                                 # Automatically confirm if we have enough free disk Space available
173                                                 return self.selectConfirmed(True)
174                                 except OSError:
175                                         pass
176
177                                 # Ask User if he really wants to select this folder
178                                 self.session.openWithCallback(
179                                         self.selectConfirmed,
180                                         MessageBox,
181                                         _("There might not be enough Space on the selected Partition.\nDo you really want to continue?"),
182                                         type = MessageBox.TYPE_YESNO
183                                 )
184                         # No minimum free Space means we can safely close
185                         else:   
186                                 self.selectConfirmed(True)
187
188         def changeName(self):
189                 if self.filename != "":
190                         # TODO: Add Information that changing extension is bad? disallow?
191                         # TODO: decide if using an inputbox is ok - we could also keep this in here
192                         self.session.openWithCallback(
193                                 self.nameChanged,
194                                 InputBox,
195                                 title = _("Please enter a new filename"),
196                                 text = self.filename
197                         )
198
199         def nameChanged(self, res):
200                 if res is not None:
201                         if len(res):
202                                 self.filename = res
203                                 self.updateTarget()
204                         else:
205                                 self.session.open(
206                                         MessageBox,
207                                         _("An empty filename is illegal."),
208                                         type = MessageBox.TYPE_ERROR,
209                                         timeout = 5
210                                 )
211
212         def updateTarget(self):
213                 # Write Combination of Folder & Filename when Folder is valid
214                 if self["filelist"].getCurrentDirectory() is not None:
215                         self["target"].setText(''.join([self["filelist"].getCurrentDirectory(), self.filename]))
216                 # Warning else
217                 else:
218                         self["target"].setText(_("Invalid Location"))
219
220         def keyNumberGlobal(self, number):
221                 # Cancel Timeout
222                 self.qs_timer.stop()
223
224                 # See if another key was pressed before
225                 if number != self.lastKey:
226                         # Reset lastKey again so NumericalTextInput triggers its keychange
227                         self.nextKey()
228
229                         # Try to select what was typed
230                         self.selectByStart()
231
232                         # Increment position
233                         self.curr_pos += 1
234
235                 # Get char and append to text
236                 char = self.getKey(number)
237                 self.quickselect = self.quickselect[:self.curr_pos] + unicode(char)
238
239                 # Start Timeout
240                 self.qs_timer_type = 0
241                 self.qs_timer.start(1000, 1)
242
243         def selectByStart(self):
244                 # Don't do anything on initial call
245                 if not len(self.quickselect):
246                         return
247
248                 # Don't select if no dir
249                 if self["filelist"].getCurrentDirectory():
250                         # TODO: implement proper method in Components.FileList
251                         files = self["filelist"].getFileList()
252
253                         # Initialize index
254                         idx = 0
255
256                         # We select by filename which is absolute
257                         lookfor = self["filelist"].getCurrentDirectory() + self.quickselect
258
259                         # Select file starting with generated text
260                         for file in files:
261                                 if file[0][0] and file[0][0].lower().startswith(lookfor):
262                                         self["filelist"].instance.moveSelectionTo(idx)
263                                         break
264                                 idx += 1
265
266         def timeout(self, force = False):
267                 # Timeout Key
268                 if not force and self.qs_timer_type == 0:
269                         # Try to select what was typed
270                         self.selectByStart()
271
272                         # Reset Key
273                         self.lastKey = -1
274
275                         # Change type
276                         self.qs_timer_type = 1
277
278                         # Start timeout again
279                         self.qs_timer.start(1000, 1)
280                 # Timeout Quickselect
281                 else:
282                         # Eventually stop Timer
283                         self.qs_timer.stop()
284
285                         # Invalidate
286                         self.lastKey = -1
287                         self.curr_pos = -1
288                         self.quickselect = ""
289
290         def __repr__(self):
291                 return str(type(self)) + "(" + self.text + ")"
292