SF.net SVN: fclient: [75] trunk/fclient/fclient_widgets/download_widget.py
Status: Pre-Alpha
Brought to you by:
jurner
|
From: <jU...@us...> - 2007-11-13 20:59:42
|
Revision: 75
http://fclient.svn.sourceforge.net/fclient/?rev=75&view=rev
Author: jUrner
Date: 2007-11-13 12:59:47 -0800 (Tue, 13 Nov 2007)
Log Message:
-----------
started implementing priority handling + first glimpse of a context menu
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 20:57:40 UTC (rev 74)
+++ trunk/fclient/fclient_widgets/download_widget.py 2007-11-13 20:59:47 UTC (rev 75)
@@ -27,7 +27,6 @@
from fclient_lib.qt4ex.ctrls import treewidgetwrap
-
sys.path.pop(0)
del parentdir
#<-- rel import hack
@@ -58,7 +57,7 @@
('MaxSimultaniousDownloads', ['toInt', 2]),
('MaxNewDownloadsPerHop', ['toInt', 100]),
-
+
('ClearCompletedDownloads', ['toBool', False]),
('ItemTipsShow', ['toBool', True]),
('ItemTipsDelay', ['toInt', areatips.DEFAULT_SHOW_DELAY])
@@ -90,12 +89,15 @@
StatusDownloading = 0x8
StatusDownloadComplete = 0x10
- StatusStopped = 0x1000
+ #StatusStopped = 0x1000 # ???
StatusError = 0x20000
+ # currently busy loading
StatusMaskBusy = StatusRequestInfo | StatusDownloading
+ # the node knows about our request
+ StatusMaskInNodeQueue = StatusMaskBusy | StatusRequestInfoComplete | StatusDownloadComplete
+
-
def __init__(self, parent, requestIdentifier, uri):
"""
@param parent: parent of the item
@@ -109,6 +111,7 @@
self._requestIdentifier = requestIdentifier
self._requestName = None
self._requestNamePostfix = None
+ self._requestPriority = None
self._requestStatus = self.StatusNone
self._requestInitTime = time.time()
self._uri = uri
@@ -195,17 +198,19 @@
return self._requestName
- def setRequestPriority(self, priority):
+ def setRequestPriority(self, priority, text):
"""Sets the request priority of the item
- @param prority: (FcpClient.Priority)
+ @param prority: (DownloadWidget.Priority*)
+ @param text: text to display
"""
- self.setText(self.IndexPriority, priority)
+ self._requestPriority = priority
+ self.setText(self.IndexPriority, text)
def requestPriority(self):
"""Returns the request priority of the item
- @return: (unicode) request priority
+ @return: (DownloadWidget.Priority*) request priority
"""
- return unicode(self.text(self.IndexPriority))
+ return self._requestPriority
def setProgressWidget(self, tree, widget):
"""Associates a progress widget to the item
@@ -254,11 +259,16 @@
"""Returns the request uri of the item"""
return self._uri
-
def setDDATested(self, flag):
+ """Sets wether the item is dda tested r not
+ @param flag: True if already tested, False otherwise
+ """
self._ddaTested = flag
def ddaTested(self):
+ """Checks if the item was already dda tested
+ @return: (bool)
+ """
return self._ddaTested
#*****************************************************************************
@@ -267,10 +277,9 @@
class DownloadWidgetStrings(QtCore.QObject):
"""Strings for the download widget"""
- def __init__(self, parent):
- QtCore.QObject.__init__(self, parent)
-
-
+ def __init__(self, downloadWidget):
+ QtCore.QObject.__init__(self, downloadWidget)
+
self.headerSections = [
(DownloadItem.IndexName, self.trUtf8('Name')),
(DownloadItem.IndexStatus, self.trUtf8('Status')),
@@ -290,20 +299,60 @@
DownloadItem.StatusDownloading: self.trUtf8('Loading'),
DownloadItem.StatusDownloadComplete: self.trUtf8('Complete'),
- DownloadItem.StatusStopped: self.trUtf8('Stopped'),
+ #DownloadItem.StatusStopped: self.trUtf8('Stopped'),
DownloadItem.StatusError: self.trUtf8('Error'),
}
-
- self.unknown = self.trUtf8('Unknown')
+ 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.unknown = self.trUtf8('???')
+
#****************************************************************************
#
#****************************************************************************
-#TODO: when closing we have to empty queues by sending ClientGet requests
+#TODO: when closing we have to send ClientGet for all pending requests by, so they don't get lost.
+#HINT: might take a while, so take care to handle gracefully (user panic). Alternative is to keep
+# track by other means. Uh.. how?
class DownloadWidget(QtGui.QTreeWidget):
+
+ PriorityHighest = 0
+ PriorityHigher = 1
+ PriorityHigh = 2
+ PriorityNormal = 3
+ PriorityLow = 4
+ PriorityLower = 5
+ PriorityLowest = 6
+
+ # menu action names
+ ActAdjustPrioritiy = 'DownloadWidgetActAdjustPriority'
+ ActNamePriorityHighest = 'DownloadWidgetActPriorityHighest'
+ ActNamePriorityHigher = 'DownloadWidgetActPriorityHigh'
+ ActNamePriorityHigh = 'DownloadWidgetActPriorityHigh'
+ ActNamePriorityNormal = 'DownloadWidgetActPriorityNormal'
+ ActNamePriorityLow = 'DownloadWidgetActPriorityLow'
+ ActNamePriorityLower = 'DownloadWidgetActPriorityLower'
+ ActNamePriorityLowest = 'DownloadWidgetActPriorityLowest'
+
+ ActNameMapping = {
+ PriorityHighest: ActNamePriorityHighest,
+ PriorityHigher: ActNamePriorityHigher,
+ PriorityHigh: ActNamePriorityHigh,
+ PriorityNormal: ActNamePriorityNormal,
+ PriorityLow: ActNamePriorityLow,
+ PriorityLower: ActNamePriorityLower,
+ PriorityLowest: ActNamePriorityLowest,
+ }
+
+
def __init__(self,
parent,
connectionName='',
@@ -317,7 +366,6 @@
@param connectionName: name of the connection to the node
@param cfg: (configConfig) instance or None
"""
-
QtGui.QTreeWidget.__init__(self, parent)
self._connectionName = connectionName
@@ -331,10 +379,10 @@
self._fcpClient = None
self._isCreated = False
self._itemTips = areatips.ItemTips(self)
+ self._priorityMapping = {}
self._strings = None
self._userSettings = UserSettings()
-
-
+
# setup item tips
self._itemTips.setEnabled(self._userSettings['ItemTipsShow'])
self._itemTips.setShowDelay(self._userSettings['ItemTipsDelay'])
@@ -364,23 +412,60 @@
#self._requests['DownloadDirectories'][self._directory] = (self, uris)
+
+ #TODO: "PriorityLowest" might be a bit misleading in priorityMapping
+ # ... according to docs it equals "will never complete". If true, implement
+ # DownloadItem.StatusStopped and leave out FcpClient.Priority.Minimum
def showEvent(self, event):
if not self._isCreated:
self._isCreated = True
self._fcpClient = self._cfg.fcpClientManager.newClient(self._connectionName, self.handleFcpClientConnected)
self._fcpClient.setVerbosity(self._fcpClient.Verbosity.Debug)
-
-
+
+ # map Fcp priorities to our priorities, in case priority defines change
+ # if self._fcpClient.Version == blah: (...)
+ self._priorityMapping = {
+ self._fcpClient.Priority.Maximum: self.PriorityHighest,
+ self._fcpClient.Priority.Interactive: self.PriorityHigher,
+ self._fcpClient.Priority.SemiInteractive: self.PriorityHigh,
+ self._fcpClient.Priority.Updatable: self.PriorityNormal,
+ self._fcpClient.Priority.Bulk: self.PriorityLow,
+ self._fcpClient.Priority.Prefetch: self.PriorityLower,
+ self._fcpClient.Priority.Minimum: self.PriorityLowest,
+ }
+
#############################################################
##
## handlers for Qt events
##
#############################################################
- def handleCustomContextMenu(self):
- pass
+ def handleCustomContextMenu(self, pt):
+ m = QtGui.QMenu(self)
+ 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)
+
#############################################################
##
## handlers for Fcp events
@@ -398,6 +483,7 @@
(self._fcpClient.events.SimpleProgress, self.handleFcpClientSimpleProgress),
(self._fcpClient.events.DataFound, self.handleFcpClientDataFound),
(self._fcpClient.events.PersistentGet, self.handleFcpClientPersistentGet),
+ (self._fcpClient.events.PersistentRequestModified, self.handleFcpClientPersistentRequestModified),
(self._fcpClient.events.GetFailed, self.handleFcpClientGetFailed),
(self._fcpClient.events.IdentifierCollision, self.handleFcpClientIdentifierCollision),
@@ -492,9 +578,10 @@
pass
+ #TODO: handle priorityClass in clientGetFile() and clientRequestInfo() and sortf()
def handleFcpClientIdle(self, event, params):
- # check if there are sownloads queued
+ # check if there are downloads queued
n = 0
maxNewDls = self._userSettings['MaxNewDownloadsPerHop']
while self._requests['DownloadQueue'] and n < maxNewDls:
@@ -533,9 +620,8 @@
downloadsToBeStarted = self._userSettings['MaxSimultaniousDownloads'] - itemsBusy
-
- #TODO: sort by priority
def sortf(item1, item2):
+ """Sort function to sort items in queue by priority / time"""
return cmp(item1.requestInitTime(), item2.requestInitTime())
# start downloads with info requested complete
@@ -548,6 +634,8 @@
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
@@ -555,7 +643,7 @@
item.setRequestIdentifier(identifier)
self._adjustItemStatus(item, DownloadItem.StatusDownloading)
- self._fcpClient.clientGetFile(uri, filename, identifier=identifier)
+ self._fcpClient.clientGetFile(uri, filename, identifier=identifier, priorityClass=priorityClass)
self._requests['Downloads'][identifier] = item
@@ -568,6 +656,8 @@
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
@@ -579,7 +669,7 @@
item.setRequestIdentifier(identifier)
self._adjustItemStatus(item, DownloadItem.StatusRequestInfo)
- self._fcpClient.clientRequestInfo(uri, identifier=identifier, clientToken=clientToken)
+ self._fcpClient.clientRequestInfo(uri, identifier=identifier, clientToken=clientToken, priorityClass=priorityClass)
self._requests['Downloads'][identifier] = item
@@ -614,7 +704,26 @@
status = DownloadItem.StatusRequestInfo
self._adjustItemStatus(item, status)
-
+
+ #
+ fcpPriority = params['PriorityClass']
+ priority = self._priorityMapping[fcpPriority]
+ priorityText = self._strings.requestPriorities[priority][0]
+ item.setRequestPriority(priority, priorityText)
+
+
+ def handleFcpClientPersistentRequestModified(self, event, params):
+ identifier = params['Identifier']
+ item = self._requests['Downloads'].get(identifier, None)
+ if item is not None:
+
+ fcpPriority = params.get('PriorityClass', None)
+ if fcpPriority is not None:
+ priority = self._priorityMapping[fcpPriority]
+ priorityText = self._strings.requestPriorities[priority][0]
+ tem.setRequestPriority(priority, priorityText)
+
+
def handleFcpClientProtocolError(self, event, params):
identifier = params.get('Identifier', None)
@@ -703,10 +812,48 @@
## methods
##
#######################################################
+ def adjustPriority(self, identifier, priority):
+ """Adjusts the priority of a request
+ @param identifier: identifier of the request
+ @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)
+
+
def download(self, uri, parent=None):
self._requests['DownloadQueue'].append( (parent, uri) )
- #TODO: adjust priority?
+
+
+ #TODO: how do we get to know when to adjust actions (enable / disable)?
+ def populateMenu(self, menu):
+ acts = []
+
+ # add priorities submenu
+ #
+ m = QtGui.QMenu(self.trUtf8('Adjust Priority'), menu)
+ menu.addMenu(m)
+ acts.append(m)
+
+ priorities = self._priorityMapping.values()
+ priorities.sort()
+ for priority in priorities:
+ actName = self.ActNameMapping[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
+
+ m.addAction(act)
+
+
+ return acts
+
def retranslate(self):
self._strings = DownloadWidgetStrings(self)
@@ -808,6 +955,7 @@
if identifier not in self._requests['Downloads']:
return identifier
+
#***************************************************************************************************
#
#***************************************************************************************************
@@ -838,7 +986,7 @@
w.setCentralWidget(peers)
#m = w.menuBar()
- #m1 = m.addMenu('Peers')
+ #m1 = m.addMenu('Requests')
#peers.populateMenu(m1)
w.show()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|