SF.net SVN: fclient: [57] trunk/fclient/fclient_widgets/download_widget.py
Status: Pre-Alpha
Brought to you by:
jurner
From: <jU...@us...> - 2007-11-07 17:35:29
|
Revision: 57 http://fclient.svn.sourceforge.net/fclient/?rev=57&view=rev Author: jUrner Date: 2007-11-07 09:35:34 -0800 (Wed, 07 Nov 2007) Log Message: ----------- continued working on downloads widget 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-07 17:35:00 UTC (rev 56) +++ trunk/fclient/fclient_widgets/download_widget.py 2007-11-07 17:35:34 UTC (rev 57) @@ -17,15 +17,21 @@ from fclient_lib import fcp #from fclient_dlgs import frdx_viewer from fclient_lib.pyex import namespace, numbers + + #from fclient_lib.qt4ex import settingsbase -#from fclient_lib.qt4ex.ctrls import progressbarwrap +from fclient_lib.qt4ex.ctrls import progressbarwrap +from fclient_lib.qt4ex.ctrls import treewidgetwrap + + sys.path.pop(0) del parentdir #<-- rel import hack import thread +import time from PyQt4 import QtCore, QtGui #***************************************************************************** # @@ -40,15 +46,31 @@ IndexMimeType = 4 IndexPriority = 5 - ###################### + #TODO: implement or not ??? IndexLastProgress = 6 IndexDuration = 7 + StatusNone = 0x0 + StatusPending = 0x1 + StatusRequestInfo = 0x2 + StatusRequestInfoComplete = 0x4 + StatusDownloading = 0x8 + StatusDownloadComplete = 0x10 + + StatusError = 0x10000 + + StatusMaskBusy = StatusRequestInfo | StatusDownloading + + + + def __init__(self, parent, requestIdentifier, uri): QtGui.QTreeWidgetItem.__init__(self, parent) self._requestIdentifier = requestIdentifier + self._requestStatus = self.StatusNone + self._requestInitTime = time.time() self._uri = uri @@ -58,6 +80,9 @@ def requestIdentifier(self): return self._requestIdentifier + def requestInitTime(self): + return self._requestInitTime + def setRequestMimeType(self, mimeType): self.setText(self.IndexMimeType, mimeType) @@ -82,12 +107,13 @@ def progressWidget(self, tree): return tree.itemWidget(self, self.IndexProgress) - def setRequestStatus(self, status): - self.setText(self.IndexStatus, status) + def setRequestStatus(self, status, text=''): + self._requestStatus = status + self.setText(self.IndexStatus, text) def requestStatus(self): - return self.text(self.IndexStatus) - + return self._requestStatus + def setRequestSize(self, size): self.setText(self.IndexSize, size) @@ -122,6 +148,19 @@ ] self.headerSections.sort() + self.itemStatus = { + DownloadItem.StatusPending: self.trUtf8('Pending'), + DownloadItem.StatusRequestInfo: self.trUtf8('Requesting'), + DownloadItem.StatusRequestInfoComplete: self.trUtf8('Found'), + DownloadItem.StatusDownloading: self.trUtf8('Loading'), + DownloadItem.StatusDownloadComplete: self.trUtf8('Complete'), + + DownloadItem.StatusError: self.trUtf8('Error'), + } + + + self.unknown = self.trUtf8('Unknown') + #**************************************************************************** # @@ -161,24 +200,12 @@ self._lock = thread.allocate_lock() self._maxQueuedItemsPerHop = maxQueuedItemsPerHop #TODO: move to settings self._maxSimultaniousDownloads = maxSimultaniousDownloads #TODO: move to settings - self._strings = DownloadWidgetStrings(self) - - # timer to add scheduled downloads (add maxQueuedItemsPerHop / hop to avoid flooding of the tree) - self._timer = QtCore.QTimer(self) - self._timer.setInterval(300) # arbitrary delay - self.connect( - self._timer, - QtCore.SIGNAL('timeout()'), - self.addQueuedItems - ) - + self._strings = None + # setup tree - self.setHeaderLabels([i[1] for i in self._strings.headerSections]) - #self.setColumnCount(len(self._strings.HeaderSections)) self.setSelectionMode(self.ContiguousSelection) - header = self.header() - header.setResizeMode(header.ResizeToContents) + #header.setResizeMode(header.ResizeToContents) header.setStretchLastSection(True) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) @@ -188,7 +215,11 @@ self.handleContextMenu ) - # schedule initial uris + + self.retranslate() + + + # schedule initial uris for download if uris is not None: self._downloads['DownloadDirectories'][self._directory] = (self, uris) @@ -217,9 +248,12 @@ """ """ self._fcpEvents = ( + (self._fcpClient.events.Idle, self.handleClientIdle), (self._fcpClient.events.ClientDisconnected, self.handleClientDisconnected), (self._fcpClient.events.TestDDAComplete, self.handleTestDDAComplete), + (self._fcpClient.events.ClientGetInfo, self.handleClientGetInfo), + (self._fcpClient.events.ClientGetInfoProgress, self.handleClientGetInfoProgress), ) # take care not to connect twice for event, observer in self._fcpEvents: @@ -230,7 +264,82 @@ for directory in self._downloads['DownloadDirectories']: self._fcpClient.testDDA(directory, wantWriteDirectory=True) + + + def handleClientIdle(self, event, msg): + + # check if there are sownloads queued + n = 0 + while self._downloads['DownloadQueue'] and n < self._maxQueuedItemsPerHop: + n += 1 + + parent, uri = self._downloads['DownloadQueue'].pop(0) + item = DownloadItem(parent, '', uri) + fcpUri = self._fcpClient.FcpUri(uri) + fileName = fcpUri.fileName() + fileName = namespace.unquote_uri(fileName) + status = DownloadItem.StatusPending + + item.setRequestName(fileName) + item.setRequestStatus(status, self._strings.itemStatus[status]) + + #... more here + + # check how many downloads are currently running + items = { + DownloadItem.StatusPending: [], + DownloadItem.StatusRequestInfoComplete: [], + } + itemsBusy = 0 + enum = treewidgetwrap.TreeWidgetIterator(self) + for item in enum: + status = item.requestStatus() + if status & item.StatusMaskBusy: + itemsBusy += 1 + elif status & item.StatusPending: + items[status].append(item) + elif status & item.StatusRequestInfoComplete: + items[status].append(item) + + # start items with info requested + itemsToBeStarted = self._maxSimultaniousDownloads - itemsBusy + if itemsToBeStarted > 0: + def sortf(item1, item2): + return cmp(item1.requestInitTime(), item2.requestInitTime()) + + infoCompleteItems = items[DownloadItem.StatusRequestInfoComplete] + infoCompleteItems.sort(cmp=sortf) + while infoCompleteItems: + + #TODO: not yet implemented + break + itemsToBeStarted -= 1 + + + # start pending items + if itemsToBeStarted > 0: + pendingItems = items[DownloadItem.StatusPending] + pendingItems.sort(cmp=sortf) + while pendingItems: + itemsToBeStarted -= 1 + if itemsToBeStarted < 0: + break + + item = pendingItems.pop(0) + progress = progressbarwrap.ProgressBarEx(self) + uri = item.requestUri() + + + progress.setRange(0, 0) + progress.setValue(0) + item.setProgressWidget(self, progress) + + identifier = self._fcpClient.clientGetInfo(uri) + self._downloads['Downloads'][identifier] = item + + + def handleClientDisconnected(self, event, params): """ """ @@ -243,14 +352,9 @@ writeAllowed = params.get('WriteDirectoryAllowed') # check if there are items to be donloaded for the directory - downloads = None - self._lock.acquire(True) - try: - downloads = self._downloads['DownloadDirectories'].get(directory, None) - if downloads is not None: - del self._downloads['DownloadDirectories'][directory] # ??? - finally: - self._lock.release() + downloads = self._downloads['DownloadDirectories'].get(directory, None) + if downloads is not None: + del self._downloads['DownloadDirectories'][directory] # ??? if downloads: if writeAllowed == self._fcpClient.FcpTrue: @@ -261,52 +365,60 @@ else: pass #TODO: write access denied, error - + + + def handleClientGetInfo(self, event, params): + + identifier = params['Identifier'] + item = self._downloads['Downloads'].get(identifier, None) + if item is not None: + del self._downloads['Downloads'][identifier] + + status = DownloadItem.StatusRequestInfoComplete + mimeType = params.get('Metadata.ContentType', self._strings.unknown) + dataLength = params.get('DataLength', '') + try: + dataLength = int(dataLength) + except ValueError: + dataLength = self._strings.unknown + else: + dataLength = numbers.format_num_bytes(dataLength) + + item.setRequestStatus(status, self._strings.itemStatus[status]) + item.setRequestMimeType(mimeType) + item.setRequestSize(dataLength) + + + + def handleClientGetInfoProgress(self, event, params): + + identifier = params['Identifier'] + item = self._downloads['Downloads'].get(identifier, None) + if item is not None: + progress = item.progressWidget(self) + required=int(params['Required']) + succeeded=int(params['Succeeded']) + + if required != progress.maximum(): + progress.setRange(0, required) + progress.setValue(succeeded) + ####################################################### ## ## methods ## ####################################################### - def addQueuedItems(self): - - self._timer.stop() - - self._lock.acquire(True) - try: - n = 0 - while self._downloads['DownloadQueue'] and n < self._maxQueuedItemsPerHop: - n += 1 - - parent, uri = self._downloads['DownloadQueue'].pop(0) - item = DownloadItem(parent, '', uri) - fcpUri = self._fcpClient.FcpUri(uri) - fileName = fcpUri.fileName() - fileName = namespace.unquote_uri(fileName) - - item.setRequestName(fileName) - - #... more here - - if self._downloads['DownloadQueue']: - self._timer.start() - - finally: - self._lock.release() - - def download(self, uri, parent=None): - self._lock.acquire(True) - try: - self._downloads['DownloadQueue'].append( (parent, uri) ) - finally: - self._lock.release() + self._downloads['DownloadQueue'].append( (parent, uri) ) + #TODO: adjust priority? - if not self._timer.isActive(): - self._timer.start() - - + def retranslate(self): - pass + self._strings = DownloadWidgetStrings(self) + self.setHeaderLabels([i[1] for i in self._strings.headerSections]) + + #TODO: retranslate item status + #*************************************************************************************************** # This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |