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