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