home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / folder.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  9.0 KB  |  254 lines

  1. # Miro - an RSS based video player application
  2. # Copyright (C) 2005-2007 Participatory Culture Foundation
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  17.  
  18. from gtcache import gettext as _
  19.  
  20. import app
  21. import dialogs
  22. import indexes
  23. import menu
  24. import playlist
  25. import sorts
  26. import util
  27. import views
  28. from database import DDBObject
  29. from databasehelper import makeSimpleGetSet
  30.  
  31. class FolderBase(DDBObject):
  32.     """Base class for ChannelFolder and Playlist folder classes."""
  33.  
  34.     def __init__(self, title):
  35.         self.title = title
  36.         self.expanded = True
  37.         DDBObject.__init__(self)
  38.  
  39.     getTitle, setTitle = makeSimpleGetSet('title')
  40.  
  41.     def getExpanded(self):
  42.         self.confirmDBThread()
  43.         return self.expanded
  44.  
  45.     def setExpanded(self, newExpanded):
  46.         self.confirmDBThread()
  47.         self.expanded = newExpanded
  48.         self.signalChange()
  49.         for child in self.getChildrenView():
  50.             child.signalChange(needsSave=False)
  51.  
  52.     def getNextTab(self):
  53.         """Get the first tab that isn't in this folder our.  If there are no
  54.         items afterwards, return None.
  55.         """
  56.  
  57.         anchorItem = None
  58.         seenSelf = False
  59.         # Find the tab directly after this folder and move the tabs above
  60.         # that one.
  61.         for tab in self.getTabOrder().getView():
  62.             if not seenSelf and tab.obj is self: 
  63.                 seenSelf = True
  64.             elif seenSelf and tab.obj.getFolder() is not self:
  65.                 return tab.obj
  66.         return None
  67.  
  68.     def handleDNDAppend(self, draggedIDs):
  69.         tabOrder = self.getTabOrder()
  70.         for id in draggedIDs:
  71.             tab = tabOrder.tabView.getObjectByID(id)
  72.             tab.obj.setFolder(self)
  73.         tabOrder.moveTabs(self.getNextTab(), draggedIDs)
  74.         selection = app.controller.selection.tabListSelection
  75.         if len(selection.currentSelection) == 0:
  76.             # we appended tabs to a non-expanded folder and now nothing is
  77.             # selected.  Select that folder.
  78.             app.controller.selection.selectItem('tablist', tabOrder.tabView,
  79.                     self.getID(), False, False)
  80.         self.signalChange()
  81.  
  82.     def rename(self):
  83.         def callback(dialog):
  84.             if self.idExists() and dialog.choice == dialogs.BUTTON_OK:
  85.                 self.setTitle(dialog.value)
  86.         dialogs.TextEntryDialog(self.renameTitle(), self.renameText(), 
  87.                 dialogs.BUTTON_OK, dialogs.BUTTON_CANCEL).run(callback)
  88.  
  89.     def remove(self, moveItemsTo=None):
  90.         children = [child for child in self.getChildrenView()]
  91.         for child in children:
  92.             child.remove(moveItemsTo)
  93.         DDBObject.remove(self)
  94.  
  95.     # getFolder and setFolder are here so that channels/playlists and folders
  96.     # have a consistent API.  They don't do much since we don't allow nested
  97.     # folders.
  98.     def getFolder(self):
  99.         return None
  100.  
  101.     def setFolder(self, newFolder):
  102.         if newFolder is not None:
  103.             raise TypeError("Nested folders not allowed")
  104.  
  105.     def renameTitle(self):
  106.         """Return the title to use for the rename dialog"""
  107.         raise NotImplementedError()
  108.     def renameText(self):
  109.         """Return the description text to use for the rename dialog"""
  110.         raise NotImplementedError()
  111.     def getTabOrder(self):
  112.         """Return the TabOrder object that this folder belongs to."""
  113.         raise NotImplementedError()
  114.     def getChildrenView(self):
  115.         """Return the children of this folder."""
  116.         raise NotImplementedError()
  117.  
  118. class ChannelFolder(FolderBase):
  119.     def __init__(self, title):
  120.         FolderBase.__init__(self, title)
  121.         self._initRestore()
  122.  
  123.     def onRestore(self):
  124.         self._initRestore()
  125.  
  126.     def _initRestore(self):
  127.         self.itemSort = sorts.ItemSort()
  128.         self.itemSortDownloading = sorts.ItemSort()
  129.         self.itemSortWatchable = sorts.ItemSortUnwatchedFirst()
  130.  
  131.     def renameTitle(self):
  132.         return _("Rename Channel Folder")
  133.     def renameText(self):
  134.         return _("Enter a new name for the channel folder %s" % 
  135.                 self.getTitle())
  136.     def getTabOrder(self):
  137.         return util.getSingletonDDBObject(views.channelTabOrder)
  138.     def getChildrenView(self):
  139.         return views.feeds.filterWithIndex(indexes.byFolder, self)
  140.  
  141.     def hasDownloadedItems(self):
  142.         for feed in self.getChildrenView():
  143.             if feed.hasDownloadedItems():
  144.                 return True
  145.         return False
  146.  
  147.     def hasDownloadingItems(self):
  148.         for feed in self.getChildrenView():
  149.             if feed.hasDownloadingItems():
  150.                 return True
  151.         return False
  152.  
  153.     def makeContextMenu(self, templateName, view):
  154.         return menu.makeMenu([
  155.             (self.rename, _('Rename Channel Folder')),
  156.             (lambda: app.controller.removeFeed(self), _('Remove')),
  157.         ])
  158.  
  159.     # Returns true iff unwatched should be shown 
  160.     def showU(self):
  161.         return self.numUnwatched() > 0
  162.  
  163.     # Returns string with number of unwatched videos in feed
  164.     def numUnwatched(self):
  165.         unwatched = 0
  166.         for child in self.getChildrenView():
  167.             if child.showU():
  168.                 unwatched += child.numUnwatched()
  169.         return unwatched
  170.  
  171.     # Returns true iff unwatched should be shown 
  172.     def showA(self):
  173.         return self.numAvailable() > 0
  174.  
  175.     # Returns string with number of available videos in feed
  176.     def numAvailable(self):
  177.         available = 0
  178.         for child in self.getChildrenView():
  179.             if child.showA():
  180.                 available += child.numAvailable()
  181.         return available
  182.     
  183. class PlaylistFolder(FolderBase, playlist.PlaylistMixin):
  184.     def __init__(self, title):
  185.         self.item_ids = []
  186.         self.setupTrackedItemView()
  187.         FolderBase.__init__(self, title)
  188.  
  189.     def onRestore(self):
  190.         self.setupTrackedItemView()
  191.  
  192.     def handleDNDAppend(self, draggedIDs):
  193.         FolderBase.handleDNDAppend(self, draggedIDs)
  194.         for id in draggedIDs:
  195.             tab = self.getTabOrder().tabView.getObjectByID(id)
  196.             for item in tab.obj.getView():
  197.                 if item.getID() not in self.trackedItems:
  198.                     self.trackedItems.appendID(item.getID())
  199.         self.signalChange()
  200.  
  201.     def checkItemIDRemoved(self, id):
  202.         index = indexes.playlistsByItemAndFolderID
  203.         value = (id, self.getID())
  204.         view = views.playlists.filterWithIndex(index, value)
  205.         if view.len() == 0 and id in self.trackedItems:
  206.             self.removeID(id)
  207.  
  208.     def makeContextMenu(self, templateName, view):
  209.         return menu.makeMenu([
  210.             (self.rename, _('Rename Playlist Folder')),
  211.             (lambda: app.controller.removePlaylist(self), _('Remove')),
  212.         ])
  213.  
  214.     def renameTitle(self):
  215.         return _("Rename Playlist Folder")
  216.     def renameText(self):
  217.         return _("Enter a new name for the playlist folder %s" % 
  218.                 self.getTitle())
  219.     def getTabOrder(self):
  220.         return util.getSingletonDDBObject(views.playlistTabOrder)
  221.     def getChildrenView(self):
  222.         return views.playlists.filterWithIndex(indexes.byFolder, self)
  223.  
  224. def createNewChannelFolder(childIDs=None):
  225.     title = _("Create Channel Folder")
  226.     description = _("Enter a name for the new channel folder")
  227.  
  228.     def callback(dialog):
  229.         if dialog.choice == dialogs.BUTTON_CREATE:
  230.             folder = ChannelFolder(dialog.value)
  231.             app.controller.selection.selectTabByObject(folder)
  232.             if childIDs:
  233.                 folder.handleDNDAppend(childIDs)
  234.  
  235.     dialogs.TextEntryDialog(title, description, dialogs.BUTTON_CREATE,
  236.             dialogs.BUTTON_CANCEL).run(callback)
  237.  
  238. def createNewPlaylistFolder(childIDs=None):
  239.     title = _("Create Playlist Folder")
  240.     description = _("Enter a name for the new playlist folder")
  241.  
  242.     def callback(dialog):
  243.         if dialog.choice == dialogs.BUTTON_CREATE:
  244.             folder = PlaylistFolder(dialog.value)
  245.             app.controller.selection.selectTabByObject(folder)
  246.             if childIDs:
  247.                 folder.handleDNDAppend(childIDs)
  248.  
  249.     dialogs.TextEntryDialog(title, description, dialogs.BUTTON_CREATE,
  250.             dialogs.BUTTON_CANCEL).run(callback)
  251.  
  252. def getFolderByTitle(title):
  253.     return views.channelFolders.getItemWithIndex(indexes.foldersByTitle, title)
  254.