SF.net SVN: fclient: [77] trunk/fclient/fclient_widgets/download_widget.py
Status: Pre-Alpha
Brought to you by:
jurner
|
From: <jU...@us...> - 2007-11-14 11:03:08
|
Revision: 77
http://fclient.svn.sourceforge.net/fclient/?rev=77&view=rev
Author: jUrner
Date: 2007-11-14 03:03:13 -0800 (Wed, 14 Nov 2007)
Log Message:
-----------
continued working on menu actions
Modified Paths:
--------------
trunk/fclient/fclient_widgets/download_widget.py
Modified: trunk/fclient/fclient_widgets/download_widget.py
===================================================================
--- trunk/fclient/fclient_widgets/download_widget.py 2007-11-13 21:00:35 UTC (rev 76)
+++ trunk/fclient/fclient_widgets/download_widget.py 2007-11-14 11:03:13 UTC (rev 77)
@@ -80,9 +80,9 @@
#TODO: implement or not ???
IndexLastProgress = 6
IndexDuration = 7
-
-
- StatusNone = 0x0
+
+ #TODO: order as appears in groups context menu... needs adjustment
+ StatusQueued = 0x0
StatusPending = 0x1
StatusRequestInfo = 0x2
StatusRequestInfoComplete = 0x4
@@ -112,7 +112,7 @@
self._requestName = None
self._requestNamePostfix = None
self._requestPriority = None
- self._requestStatus = self.StatusNone
+ self._requestStatus = self.StatusQueued
self._requestInitTime = time.time()
self._uri = uri
@@ -292,7 +292,8 @@
]
self.headerSections.sort()
- self.itemStatus = {
+ self.itemStatus = { # DownloadItem.Status* --> shortName
+ DownloadItem.StatusQueued: self.trUtf8('Queued'),
DownloadItem.StatusPending: self.trUtf8('Pending'),
DownloadItem.StatusRequestInfo: self.trUtf8('Requesting'),
DownloadItem.StatusRequestInfoComplete: self.trUtf8('Found'),
@@ -303,14 +304,14 @@
DownloadItem.StatusError: self.trUtf8('Error'),
}
- self.requestPriorities = { # Priority* --> (shortName, longName)
- downloadWidget.PriorityHighest: (self.trUtf8('0'), self.trUtf8('0 Highest')),
- downloadWidget.PriorityHigher: (self.trUtf8('1'), self.trUtf8('1 High')),
- downloadWidget.PriorityHigh: (self.trUtf8('2'), self.trUtf8('2 Higher')),
- downloadWidget.PriorityNormal: (self.trUtf8('3'), self.trUtf8('3 Normal')),
- downloadWidget.PriorityLow: (self.trUtf8('4'), self.trUtf8('4 Low')),
- downloadWidget.PriorityLower: (self.trUtf8('5'), self.trUtf8('5 Lower')),
- downloadWidget.PriorityLowest: (self.trUtf8('6'), self.trUtf8('6 Lowest')),
+ self.requestPriorities = { # Priority* --> (shortText, longText)
+ downloadWidget.PriorityHighest: (self.trUtf8('1'), self.trUtf8('1 Highest')),
+ downloadWidget.PriorityHigher: (self.trUtf8('2'), self.trUtf8('2 High')),
+ downloadWidget.PriorityHigh: (self.trUtf8('3'), self.trUtf8('3 Higher')),
+ downloadWidget.PriorityNormal: (self.trUtf8('4'), self.trUtf8('4 Normal')),
+ downloadWidget.PriorityLow: (self.trUtf8('5'), self.trUtf8('5 Low')),
+ downloadWidget.PriorityLower: (self.trUtf8('6'), self.trUtf8('6 Lower')),
+ downloadWidget.PriorityLowest: (self.trUtf8('7'), self.trUtf8('7 Lowest')),
}
self.unknown = self.trUtf8('???')
@@ -323,16 +324,16 @@
# track by other means. Uh.. how?
class DownloadWidget(QtGui.QTreeWidget):
- PriorityHighest = 0
- PriorityHigher = 1
- PriorityHigh = 2
- PriorityNormal = 3
- PriorityLow = 4
- PriorityLower = 5
- PriorityLowest = 6
+ PriorityHighest = 1
+ PriorityHigher = 2
+ PriorityHigh = 3
+ PriorityNormal = 4
+ PriorityLow = 5
+ PriorityLower = 6
+ PriorityLowest = 7
- # menu action names
- ActAdjustPrioritiy = 'DownloadWidgetActAdjustPriority'
+ # menu and action names for priorities
+ MenuNameAdjustPrioritiy = 'DownloadWidgetMenuAdjustPriority'
ActNamePriorityHighest = 'DownloadWidgetActPriorityHighest'
ActNamePriorityHigher = 'DownloadWidgetActPriorityHigh'
@@ -342,7 +343,7 @@
ActNamePriorityLower = 'DownloadWidgetActPriorityLower'
ActNamePriorityLowest = 'DownloadWidgetActPriorityLowest'
- ActNameMapping = {
+ ActNamePriorityMapping = {
PriorityHighest: ActNamePriorityHighest,
PriorityHigher: ActNamePriorityHigher,
PriorityHigh: ActNamePriorityHigh,
@@ -352,7 +353,33 @@
PriorityLowest: ActNamePriorityLowest,
}
+ # menu and action names for groups
+ MenuNameClearGroup = 'DownloadWidgetMenuClearGroup'
+ ActNameStatusQueued = 'DownloadWidgetActStatusQueued'
+ ActNameStatusPending = 'DownloadWidgetActStatusPending'
+ ActNameStatusRequestInfo = 'DownloadWidgetActStatusRequestInfo'
+ ActNameStatusRequestInfoComplete = 'DownloadWidgetActStatusRequestInfoComplete'
+ ActNameStatusDownloading = 'DownloadWidgetActStatusDownloading'
+ ActNameStatusDownloadComplete = 'DownloadWidgetActStatusDownloadComplete'
+
+ #ActNameStatusStopped = 'DownloadWidgetActStatusStopped'
+ ActNameStatusError = 'DownloadWidgetActStatusError'
+
+ ActNameStatusMapping = {
+ DownloadItem.StatusQueued: ActNameStatusQueued,
+ DownloadItem.StatusPending: ActNameStatusPending,
+ DownloadItem.StatusRequestInfo: ActNameStatusRequestInfo,
+ DownloadItem.StatusRequestInfoComplete: ActNameStatusRequestInfoComplete,
+ DownloadItem.StatusDownloading: ActNameStatusDownloading,
+ DownloadItem.StatusDownloadComplete: ActNameStatusDownloadComplete,
+
+ #DownloadItem.StatusStopped: ActNameStatusStopped,
+ DownloadItem.StatusError: ActNameStatusError,
+ }
+
+
+
def __init__(self,
parent,
connectionName='',
@@ -365,6 +392,10 @@
@param directory: (str) directory to sownload items to or None to use default directory
@param connectionName: name of the connection to the node
@param cfg: (configConfig) instance or None
+
+ @signal: 'hasCurrentItem(bool)' emitted when selection or current item changes. Param is true if there is a
+ current item or a selection
+
"""
QtGui.QTreeWidget.__init__(self, parent)
@@ -395,12 +426,27 @@
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.connect(
- self,
- QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
- self.handleCustomContextMenu
- )
+ self,
+ QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
+ self.handleCustomContextMenu
+ )
+ # used to inform acts about has current item / selection available
+ self.connect(
+ self,
+ QtCore.SIGNAL('currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)'),
+ self.handleCurrentItemChanged
+ )
+ self.connect(
+ self,
+ QtCore.SIGNAL('itemSelectionChanged()'),
+ self.handleCurrentItemChanged
+ )
+
+
+
+
self.retranslate()
@@ -420,7 +466,7 @@
if not self._isCreated:
self._isCreated = True
self._fcpClient = self._cfg.fcpClientManager.newClient(self._connectionName, self.handleFcpClientConnected)
- self._fcpClient.setVerbosity(self._fcpClient.Verbosity.Debug)
+ #self._fcpClient.setVerbosity(self._fcpClient.Verbosity.Debug)
# map Fcp priorities to our priorities, in case priority defines change
# if self._fcpClient.Version == blah: (...)
@@ -441,31 +487,16 @@
#############################################################
def handleCustomContextMenu(self, pt):
m = QtGui.QMenu(self)
+ m.setTearOffEnabled(True)
self.populateMenu(m)
pt = self.viewport().mapToGlobal(pt)
act = m.exec_(pt)
return
-
- def handleAdjustPriority(self, priority):
- """Slot called when a priority change of all currently selected items is triggered
- @param priority: one of the Priority* consts
- """
- items = self.selectedItems()
- if not items:
- item = self.currentItem()
- if item is not None:
- items = (item, )
-
- priorityName = self._strings.requestPriorities[priority][0]
- for item in items:
- item.setRequestPriority(priority, priorityName)
-
- #TODO: more or less a guess that the item is still in the queue. We don't know
- # exactly on context menu for example. Check if the node complains
- if item.requestStatus() & DownloadItem.StatusMaskInNodeQueue:
- self.adjustPriority(item.requestIdentifier(), priority)
-
+
+ def handleCurrentItemChanged(self, *params):
+ self.emit(QtCore.SIGNAL('hasCurrentItem(bool)'), self.hasCurrentItem())
+
#############################################################
##
## handlers for Fcp events
@@ -573,12 +604,24 @@
#raise self._fcpClient.FetchError(params)
- #TODO: not yet handled
+ #TODO: not tested!!
def handleFcpClientIdentifierCollision(self, event, params):
- pass
-
-
- #TODO: handle priorityClass in clientGetFile() and clientRequestInfo() and sortf()
+ identifier = params['Identifier']
+ item = self._requests['Downloads'].get(identifier, None)
+ if item is not None:
+ del self._requests['Downloads'][identifier]
+
+ if self._fcpClient.isClientGetFile(identifier):
+ self._startDownload(item)
+
+ elif isClientRequestInfo(identifier):
+ self._startRequestInfo(item)
+
+ else:
+ #TODO: more here
+ pass
+
+
def handleFcpClientIdle(self, event, params):
# check if there are downloads queued
@@ -622,7 +665,10 @@
def sortf(item1, item2):
"""Sort function to sort items in queue by priority / time"""
- return cmp(item1.requestInitTime(), item2.requestInitTime())
+ result = cmp(item1.requestPriority(), item2.requestPriority())
+ if not result:
+ result = cmp(item1.requestInitTime(), item2.requestInitTime())
+ return result
# start downloads with info requested complete
if downloadsToBeStarted > 0:
@@ -632,21 +678,10 @@
downloadsToBeStarted -= 1
item = downloadsRequestInfoComplete.pop(0)
- filename = os.path.join(self.downloadDirectoryFromItem(item), item.requestName())
- identifier = self._uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientGetFile)
- priorityClass = item.requestPriority()
- priorityClass = priorityClass if priorityClass else None # play it save
- uri = item.requestUri()
-
- # tell node to remove completed RequestInfo
+ # tell node to remove info complete
self._fcpClient.removePersistentRequest(item.requestIdentifier())
-
- item.setRequestIdentifier(identifier)
- self._adjustItemStatus(item, DownloadItem.StatusDownloading)
- self._fcpClient.clientGetFile(uri, filename, identifier=identifier, priorityClass=priorityClass)
-
- self._requests['Downloads'][identifier] = item
-
+ self._startDownload(item)
+
# start pending downloads
if downloadsToBeStarted > 0:
downloadsPending = items[DownloadItem.StatusPending]
@@ -654,33 +689,18 @@
while downloadsPending and downloadsToBeStarted > 0:
downloadsToBeStarted -= 1
- identifier = self._uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientRequestInfo)
item = downloadsPending.pop(0)
- priorityClass = item.requestPriority()
- priorityClass = priorityClass if priorityClass else None # play it save + pendings may not have a priority
- uri = item.requestUri()
-
- # ClientToken will be set to item parent identifier
- parent = item.parent()
- if parent is None:
- clientToken = None
- else:
- clientToken = parent.requestIdentifier()
-
- item.setRequestIdentifier(identifier)
- self._adjustItemStatus(item, DownloadItem.StatusRequestInfo)
- self._fcpClient.clientRequestInfo(uri, identifier=identifier, clientToken=clientToken, priorityClass=priorityClass)
-
- self._requests['Downloads'][identifier] = item
-
+ self._startRequestInfo(item)
+
def handleFcpClientPersistentGet(self, event, params):
identifier = params['Identifier']
item = self._requests['Downloads'].get(identifier, None)
if item is None:
- #self._fcpClient.removePersistentRequest(identifier)
- #return
+ # uncommment for testing... removes all requests the node passes on connect
+ ##self._fcpClient.removePersistentRequest(identifier)
+ ##return
#TODO: no idea if the node passes PersistentGet messages in insertion order
# ..if not, we will have to cache items and wait for parent item to arrive
@@ -812,46 +832,110 @@
## methods
##
#######################################################
- def adjustPriority(self, identifier, priority):
- """Adjusts the priority of a request
- @param identifier: identifier of the request
+ def adjustPriority(self, priority):
+ """Adjusts the priority of all currently selected items or if no items are selected the current item
@param priority: one of the Priority* consts
@return: always None
"""
- keys, values = self._priorityMapping.keys(), self._priorityMapping.values()
- n = values.index(priority)
- fcpPriority = keys[n]
- self._fcpClient.modifyPersistantRequest(identifier, priorityClass=fcpPriority)
+ items = self.selectedItems()
+ if not items:
+ item = self.currentItem()
+ if item is not None:
+ items = (item, )
+ priorityName = self._strings.requestPriorities[priority][0]
+ for item in items:
+ item.setRequestPriority(priority, priorityName)
+
+ #TODO: more or less a guess that the item is still in the queue. We don't know
+ # exactly on context menu for example. Check if the node complains
+ if item.requestStatus() & DownloadItem.StatusMaskInNodeQueue:
+ self._fcpClient.modifyPersistentRequest(
+ item.requestIdentifier(),
+ self._prorityToFcpPriority(priority)
+ )
+
+
+
+ #TODO: not yet implemented
+ #TODO: check if we don't run into race conditions when called from actions
+ def clearGroup(self, status):
+ """Removes all items with the specified status
+ @param status: DownloadItem.Status*
+ """
+
+
def download(self, uri, parent=None):
self._requests['DownloadQueue'].append( (parent, uri) )
+
+ def hasCurrentItem(self):
+ """Checks if there is a current item or a selection
+ @return: (bool)
+ """
+ hasCurrentItem = True
+ if self.currentItem() is None:
+ if not self.selectedItems():
+ hasCurrentItem = False
+ return hasCurrentItem
- #TODO: how do we get to know when to adjust actions (enable / disable)?
+
def populateMenu(self, menu):
+ """Populates a menu with all available actions
+ @return: (list) containing actions and emidiate submenus added to the menu
+ """
+
acts = []
# add priorities submenu
#
- m = QtGui.QMenu(self.trUtf8('Adjust Priority'), menu)
+ hasCurrentItem = self.hasCurrentItem()
+ m = QtGui.QMenu(self.trUtf8('Adjust priority'), menu)
+ m.setObjectName(self.MenuNameAdjustPrioritiy)
+ m.setTearOffEnabled(True)
+ m.setEnabled(hasCurrentItem)
+
menu.addMenu(m)
acts.append(m)
+ m.connect(self, QtCore.SIGNAL('hasCurrentItem(bool)'), m.setEnabled)
priorities = self._priorityMapping.values()
priorities.sort()
for priority in priorities:
- actName = self.ActNameMapping[priority]
+ actName = self.ActNamePriorityMapping[priority]
actText = self._strings.requestPriorities[priority][1]
act = QtGui.QAction(actText, menu)
- cb = lambda method=self.handleAdjustPriority, arg=priority: method(arg)
- print act.connect(act, QtCore.SIGNAL('triggered()'), cb)
- act._cb = cb
-
+ act.setObjectName(actName)
+ act.setEnabled(hasCurrentItem)
+ cb = lambda method=self.adjustPriority, arg=priority: method(arg)
+ act.connect(act, QtCore.SIGNAL('triggered()'), cb)
+ act._downloadWidgetCb = cb
+ act.connect(self, QtCore.SIGNAL('hasCurrentItem(bool)'), act.setEnabled)
m.addAction(act)
+ # add clear groups menu
+ #
+ m = QtGui.QMenu(self.trUtf8('Clear group'), menu)
+ m.setObjectName(self.MenuNameClearGroup)
+ m.setTearOffEnabled(True)
+
+ menu.addMenu(m)
+ acts.append(m)
+
+ groups = self.ActNameStatusMapping.items()
+ groups.sort()
+ for status, actName in groups:
+ actText = self._strings.itemStatus[status]
+ act = QtGui.QAction(actText, menu)
+ cb = lambda method=self.clearGroup, arg=status: method(arg)
+ act.connect(act, QtCore.SIGNAL('triggered()'), cb)
+ act._downloadWidgetCb = cb
+ m.addAction(act)
+
+
return acts
@@ -945,6 +1029,55 @@
return item
+ def _prorityToFcpPriority(self, priority):
+ keys, values = self._priorityMapping.keys(), self._priorityMapping.values()
+ n = values.index(priority)
+ return keys[n]
+
+
+ def _startDownload(self, item):
+ """Starts downloading an item
+ @param item: (DownloadItem)
+ @note: no check is done to enshure the item is not already being downloaded
+ """
+ filename = os.path.join(self.downloadDirectoryFromItem(item), item.requestName())
+ identifier = self._uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientGetFile)
+ priorityClass = item.requestPriority()
+ priorityClass = priorityClass if priorityClass else None # play it save
+ uri = item.requestUri()
+
+ item.setRequestIdentifier(identifier)
+ self._adjustItemStatus(item, DownloadItem.StatusDownloading)
+ self._fcpClient.clientGetFile(uri, filename, identifier=identifier, priorityClass=priorityClass)
+
+ self._requests['Downloads'][identifier] = item
+
+
+ def _startRequestInfo(self, item):
+ """Starts requesting info for an item
+ @param item: (DownloadItem)
+ @note: no check is done to enshure the item is not already being requested
+ """
+ identifier = self._uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientRequestInfo)
+ priorityClass = item.requestPriority()
+ priorityClass = priorityClass if priorityClass else None # play it save + pendings may not have a priority
+ uri = item.requestUri()
+
+ # ClientToken will be set to item parent identifier
+ parent = item.parent()
+ if parent is None:
+ clientToken = None
+ else:
+ clientToken = parent.requestIdentifier()
+
+ item.setRequestIdentifier(identifier)
+ self._adjustItemStatus(item, DownloadItem.StatusRequestInfo)
+ self._fcpClient.clientRequestInfo(uri, identifier=identifier, clientToken=clientToken, priorityClass=priorityClass)
+
+ self._requests['Downloads'][identifier] = item
+
+
+
def _uniqueDownloadsIdentifier(self, identifierPrefix):
"""Creates a new identifier that is unique to the internal sownloads dict
@param identifierPrefix: FcpClient.IdentifierPrefix.*
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|