Merge branch 'bug_263_fix_timeshift_live_transition' into experimental
[enigma2.git] / lib / python / Components / FileList.py
1 from re import compile as re_compile
2 from os import path as os_path, listdir
3 from MenuList import MenuList
4 from Components.Harddisk import harddiskmanager
5
6 from Tools.Directories import SCOPE_CURRENT_SKIN, resolveFilename, fileExists
7
8 from enigma import RT_HALIGN_LEFT, eListboxPythonMultiContent, \
9         eServiceReference, eServiceCenter, gFont
10 from Tools.LoadPixmap import LoadPixmap
11
12 EXTENSIONS = {
13                 "m4a": "music",
14                 "mp2": "music",
15                 "mp3": "music",
16                 "wav": "music",
17                 "ogg": "music",
18                 "flac": "music",
19                 "jpg": "picture",
20                 "jpeg": "picture",
21                 "png": "picture",
22                 "bmp": "picture",
23                 "ts": "movie",
24                 "avi": "movie",
25                 "divx": "movie",
26                 "mpg": "movie",
27                 "mpeg": "movie",
28                 "mkv": "movie",
29                 "mp4": "movie",
30                 "mov": "movie"
31         }
32
33 def FileEntryComponent(name, absolute = None, isDir = False):
34         res = [ (absolute, isDir) ]
35         res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 470, 20, 0, RT_HALIGN_LEFT, name))
36         if isDir:
37                 png = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "extensions/directory.png"))
38         else:
39                 extension = name.split('.')
40                 extension = extension[-1].lower()
41                 if EXTENSIONS.has_key(extension):
42                         png = LoadPixmap(resolveFilename(SCOPE_CURRENT_SKIN, "extensions/" + EXTENSIONS[extension] + ".png"))
43                 else:
44                         png = None
45         if png is not None:
46                 res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
47         
48         return res
49
50 class FileList(MenuList):
51         def __init__(self, directory, showDirectories = True, showFiles = True, showMountpoints = True, matchingPattern = None, useServiceRef = False, inhibitDirs = False, inhibitMounts = False, isTop = False, enableWrapAround = False, additionalExtensions = None):
52                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
53                 self.additional_extensions = additionalExtensions
54                 self.mountpoints = []
55                 self.current_directory = None
56                 self.current_mountpoint = None
57                 self.useServiceRef = useServiceRef
58                 self.showDirectories = showDirectories
59                 self.showMountpoints = showMountpoints
60                 self.showFiles = showFiles
61                 self.isTop = isTop
62                 # example: matching .nfi and .ts files: "^.*\.(nfi|ts)"
63                 self.matchingPattern = matchingPattern
64                 self.inhibitDirs = inhibitDirs or []
65                 self.inhibitMounts = inhibitMounts or []
66
67                 self.refreshMountpoints()
68                 self.changeDir(directory)
69                 self.l.setFont(0, gFont("Regular", 18))
70                 self.l.setItemHeight(23)
71                 self.serviceHandler = eServiceCenter.getInstance()
72
73         def refreshMountpoints(self):
74                 self.mountpoints = [os_path.join(p.mountpoint, "") for p in harddiskmanager.getMountedPartitions()]
75                 self.mountpoints.sort(reverse = True)
76
77         def getMountpoint(self, file):
78                 file = os_path.join(os_path.realpath(file), "")
79                 for m in self.mountpoints:
80                         if file.startswith(m):
81                                 return m
82                 return False
83
84         def getMountpointLink(self, file):
85                 if os_path.realpath(file) == file:
86                         return self.getMountpoint(file)
87                 else:
88                         if file[-1] == "/":
89                                 file = file[:-1]
90                         mp = self.getMountpoint(file)
91                         last = file
92                         file = os_path.dirname(file)
93                         while last != "/" and mp == self.getMountpoint(file):
94                                 last = file
95                                 file = os_path.dirname(file)
96                         return os_path.join(last, "")
97
98         def getSelection(self):
99                 if self.l.getCurrentSelection() is None:
100                         return None
101                 return self.l.getCurrentSelection()[0]
102
103         def getCurrentEvent(self):
104                 l = self.l.getCurrentSelection()
105                 if not l or l[0][1] == True:
106                         return None
107                 else:
108                         return self.serviceHandler.info(l[0][0]).getEvent(l[0][0])
109
110         def getFileList(self):
111                 return self.list
112
113         def inParentDirs(self, dir, parents):
114                 dir = os_path.realpath(dir)
115                 for p in parents:
116                         if dir.startswith(p):
117                                 return True
118                 return False
119
120         def changeDir(self, directory, select = None):
121                 self.list = []
122
123                 # if we are just entering from the list of mount points:
124                 if self.current_directory is None:
125                         if directory and self.showMountpoints:
126                                 self.current_mountpoint = self.getMountpointLink(directory)
127                         else:
128                                 self.current_mountpoint = None
129                 self.current_directory = directory
130                 directories = []
131                 files = []
132
133                 if directory is None and self.showMountpoints: # present available mountpoints
134                         for p in harddiskmanager.getMountedPartitions():
135                                 path = os_path.join(p.mountpoint, "")
136                                 if path not in self.inhibitMounts and not self.inParentDirs(path, self.inhibitDirs):
137                                         self.list.append(FileEntryComponent(name = p.description, absolute = path, isDir = True))
138                         files = [ ]
139                         directories = [ ]
140                 elif directory is None:
141                         files = [ ]
142                         directories = [ ]
143                 elif self.useServiceRef:
144                         root = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + directory)
145                         if self.additional_extensions:
146                                 root.setName(self.additional_extensions)
147                         serviceHandler = eServiceCenter.getInstance()
148                         list = serviceHandler.list(root)
149
150                         while 1:
151                                 s = list.getNext()
152                                 if not s.valid():
153                                         del list
154                                         break
155                                 if s.flags & s.mustDescent:
156                                         directories.append(s.getPath())
157                                 else:
158                                         files.append(s)
159                         directories.sort()
160                         files.sort()
161                 else:
162                         if fileExists(directory):
163                                 try:
164                                         files = listdir(directory)
165                                 except:
166                                         files = []
167                                 files.sort()
168                                 tmpfiles = files[:]
169                                 for x in tmpfiles:
170                                         if os_path.isdir(directory + x):
171                                                 directories.append(directory + x + "/")
172                                                 files.remove(x)
173
174                 if directory is not None and self.showDirectories and not self.isTop:
175                         if directory == self.current_mountpoint and self.showMountpoints:
176                                 self.list.append(FileEntryComponent(name = "<" +_("List of Storage Devices") + ">", absolute = None, isDir = True))
177                         elif (directory != "/") and not (self.inhibitMounts and self.getMountpoint(directory) in self.inhibitMounts):
178                                 self.list.append(FileEntryComponent(name = "<" +_("Parent Directory") + ">", absolute = '/'.join(directory.split('/')[:-2]) + '/', isDir = True))
179
180                 if self.showDirectories:
181                         for x in directories:
182                                 if not (self.inhibitMounts and self.getMountpoint(x) in self.inhibitMounts) and not self.inParentDirs(x, self.inhibitDirs):
183                                         name = x.split('/')[-2]
184                                         self.list.append(FileEntryComponent(name = name, absolute = x, isDir = True))
185
186                 if self.showFiles:
187                         for x in files:
188                                 if self.useServiceRef:
189                                         path = x.getPath()
190                                         name = path.split('/')[-1]
191                                 else:
192                                         path = directory + x
193                                         name = x
194
195                                 if (self.matchingPattern is None) or re_compile(self.matchingPattern).search(path):
196                                         self.list.append(FileEntryComponent(name = name, absolute = x , isDir = False))
197
198                 self.l.setList(self.list)
199
200                 if select is not None:
201                         i = 0
202                         self.moveToIndex(0)
203                         for x in self.list:
204                                 p = x[0][0]
205                                 
206                                 if isinstance(p, eServiceReference):
207                                         p = p.getPath()
208                                 
209                                 if p == select:
210                                         self.moveToIndex(i)
211                                 i += 1
212
213         def getCurrentDirectory(self):
214                 return self.current_directory
215
216         def canDescent(self):
217                 if self.getSelection() is None:
218                         return False
219                 return self.getSelection()[1]
220
221         def descent(self):
222                 if self.getSelection() is None:
223                         return
224                 self.changeDir(self.getSelection()[0], select = self.current_directory)
225
226         def getFilename(self):
227                 if self.getSelection() is None:
228                         return None
229                 x = self.getSelection()[0]
230                 if isinstance(x, eServiceReference):
231                         x = x.getPath()
232                 return x
233
234         def getServiceRef(self):
235                 if self.getSelection() is None:
236                         return None
237                 x = self.getSelection()[0]
238                 if isinstance(x, eServiceReference):
239                         return x
240                 return None
241
242         def execBegin(self):
243                 harddiskmanager.on_partition_list_change.append(self.partitionListChanged)
244
245         def execEnd(self):
246                 harddiskmanager.on_partition_list_change.remove(self.partitionListChanged)
247
248         def refresh(self):
249                 self.changeDir(self.current_directory, self.getFilename())
250
251         def partitionListChanged(self, action, device):
252                 self.refreshMountpoints()
253                 if self.current_directory is None:
254                         self.refresh()
255
256
257 def MultiFileSelectEntryComponent(name, absolute = None, isDir = False, selected = False):
258         res = [ (absolute, isDir, selected, name) ]
259         res.append((eListboxPythonMultiContent.TYPE_TEXT, 55, 1, 470, 20, 0, RT_HALIGN_LEFT, name))
260         if isDir:
261                 png = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "extensions/directory.png"))
262         else:
263                 extension = name.split('.')
264                 extension = extension[-1].lower()
265                 if EXTENSIONS.has_key(extension):
266                         png = LoadPixmap(resolveFilename(SCOPE_CURRENT_SKIN, "extensions/" + EXTENSIONS[extension] + ".png"))
267                 else:
268                         png = None
269         if png is not None:
270                 res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 30, 2, 20, 20, png))
271
272         if not name.startswith('<'):
273                 if selected is False:
274                         icon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/icons/lock_off.png"))
275                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 2, 0, 25, 25, icon))
276                 else:
277                         icon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/icons/lock_on.png"))
278                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 2, 0, 25, 25, icon))
279         
280         return res
281
282
283 class MultiFileSelectList(FileList):
284         def __init__(self, preselectedFiles, directory, showMountpoints = False, matchingPattern = None, showDirectories = True, showFiles = True,  useServiceRef = False, inhibitDirs = False, inhibitMounts = False, isTop = False, enableWrapAround = False, additionalExtensions = None):
285                 self.selectedFiles = preselectedFiles
286                 if self.selectedFiles is None:
287                         self.selectedFiles = []
288                 FileList.__init__(self, directory, showMountpoints = showMountpoints, matchingPattern = matchingPattern, showDirectories = showDirectories, showFiles = showFiles,  useServiceRef = useServiceRef, inhibitDirs = inhibitDirs, inhibitMounts = inhibitMounts, isTop = isTop, enableWrapAround = enableWrapAround, additionalExtensions = additionalExtensions)
289                 self.changeDir(directory)                       
290                 self.l.setItemHeight(25)
291                 self.l.setFont(0, gFont("Regular", 20))
292                 self.onSelectionChanged = [ ]
293
294         def selectionChanged(self):
295                 for f in self.onSelectionChanged:
296                         f()
297
298         def changeSelectionState(self):
299                 idx = self.l.getCurrentSelectionIndex()
300                 count = 0
301                 newList = []
302                 for x in self.list:
303                         if idx == count:
304                                 if x[0][3].startswith('<'):
305                                         newList.append(x)
306                                 else:
307                                         if x[0][1] is True:
308                                                 realPathname = x[0][0]
309                                         else:
310                                                 realPathname = self.current_directory + x[0][0]
311                                         if x[0][2] == True:
312                                                 SelectState = False
313                                                 for entry in self.selectedFiles:
314                                                         if entry == realPathname:
315                                                                 self.selectedFiles.remove(entry)
316         
317                                         else:
318                                                 SelectState = True
319                                                 alreadyinList = False   
320                                                 for entry in self.selectedFiles:
321                                                         if entry == realPathname:
322                                                                 alreadyinList = True
323                                                 if not alreadyinList:
324                                                         self.selectedFiles.append(realPathname)
325                                         newList.append(MultiFileSelectEntryComponent(name = x[0][3], absolute = x[0][0], isDir = x[0][1], selected = SelectState ))
326                         else:
327                                 newList.append(x)
328                         
329                         count += 1
330                 
331                 self.list = newList
332                 self.l.setList(self.list)
333         
334         def getSelectedList(self):
335                 return self.selectedFiles
336
337         def changeDir(self, directory, select = None):
338                 self.list = []
339
340                 # if we are just entering from the list of mount points:
341                 if self.current_directory is None:
342                         if directory and self.showMountpoints:
343                                 self.current_mountpoint = self.getMountpointLink(directory)
344                         else:
345                                 self.current_mountpoint = None
346                 self.current_directory = directory
347                 directories = []
348                 files = []
349
350                 if directory is None and self.showMountpoints: # present available mountpoints
351                         for p in harddiskmanager.getMountedPartitions():
352                                 path = os_path.join(p.mountpoint, "")
353                                 if path not in self.inhibitMounts and not self.inParentDirs(path, self.inhibitDirs):
354                                         self.list.append(MultiFileSelectEntryComponent(name = p.description, absolute = path, isDir = True))
355                         files = [ ]
356                         directories = [ ]
357                 elif directory is None:
358                         files = [ ]
359                         directories = [ ]
360                 elif self.useServiceRef:
361                         root = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + directory)
362                         if self.additional_extensions:
363                                 root.setName(self.additional_extensions)
364                         serviceHandler = eServiceCenter.getInstance()
365                         list = serviceHandler.list(root)
366
367                         while 1:
368                                 s = list.getNext()
369                                 if not s.valid():
370                                         del list
371                                         break
372                                 if s.flags & s.mustDescent:
373                                         directories.append(s.getPath())
374                                 else:
375                                         files.append(s)
376                         directories.sort()
377                         files.sort()
378                 else:
379                         if fileExists(directory):
380                                 try:
381                                         files = listdir(directory)
382                                 except:
383                                         files = []
384                                 files.sort()
385                                 tmpfiles = files[:]
386                                 for x in tmpfiles:
387                                         if os_path.isdir(directory + x):
388                                                 directories.append(directory + x + "/")
389                                                 files.remove(x)
390
391                 if directory is not None and self.showDirectories and not self.isTop:
392                         if directory == self.current_mountpoint and self.showMountpoints:
393                                 self.list.append(MultiFileSelectEntryComponent(name = "<" +_("List of Storage Devices") + ">", absolute = None, isDir = True))
394                         elif (directory != "/") and not (self.inhibitMounts and self.getMountpoint(directory) in self.inhibitMounts):
395                                 self.list.append(MultiFileSelectEntryComponent(name = "<" +_("Parent Directory") + ">", absolute = '/'.join(directory.split('/')[:-2]) + '/', isDir = True))
396
397                 if self.showDirectories:
398                         for x in directories:
399                                 if not (self.inhibitMounts and self.getMountpoint(x) in self.inhibitMounts) and not self.inParentDirs(x, self.inhibitDirs):
400                                         name = x.split('/')[-2]
401                                         alreadySelected = False
402                                         for entry in self.selectedFiles:
403                                                 if entry  == x:
404                                                         alreadySelected = True                                  
405                                         if alreadySelected:             
406                                                 self.list.append(MultiFileSelectEntryComponent(name = name, absolute = x, isDir = True, selected = True))
407                                         else:
408                                                 self.list.append(MultiFileSelectEntryComponent(name = name, absolute = x, isDir = True, selected = False))
409                                                 
410                 if self.showFiles:
411                         for x in files:
412                                 if self.useServiceRef:
413                                         path = x.getPath()
414                                         name = path.split('/')[-1]
415                                 else:
416                                         path = directory + x
417                                         name = x
418
419                                 if (self.matchingPattern is None) or re_compile(self.matchingPattern).search(path):
420                                         alreadySelected = False
421                                         for entry in self.selectedFiles:
422                                                 if os_path.basename(entry)  == x:
423                                                         alreadySelected = True  
424                                         if alreadySelected:
425                                                 self.list.append(MultiFileSelectEntryComponent(name = name, absolute = x , isDir = False, selected = True))
426                                         else:
427                                                 self.list.append(MultiFileSelectEntryComponent(name = name, absolute = x , isDir = False, selected = False))
428
429                 self.l.setList(self.list)
430
431                 if select is not None:
432                         i = 0
433                         self.moveToIndex(0)
434                         for x in self.list:
435                                 p = x[0][0]
436                                 
437                                 if isinstance(p, eServiceReference):
438                                         p = p.getPath()
439                                 
440                                 if p == select:
441                                         self.moveToIndex(i)
442                                 i += 1
443