SF.net SVN: fclient: [66] trunk/fclient/fclient_widgets/download_widget.py
Status: Pre-Alpha
Brought to you by:
jurner
From: <jU...@us...> - 2007-11-10 11:30:23
|
Revision: 66 http://fclient.svn.sourceforge.net/fclient/?rev=66&view=rev Author: jUrner Date: 2007-11-10 03:30:27 -0800 (Sat, 10 Nov 2007) Log Message: ----------- implemented actual download of uris 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-10 11:28:52 UTC (rev 65) +++ trunk/fclient/fclient_widgets/download_widget.py 2007-11-10 11:30:27 UTC (rev 66) @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + """Sketch for a download widget """ @@ -105,6 +107,8 @@ self._requestError = None self._requestIdentifier = requestIdentifier + self._requestName = None + self._requestNamePostfix = None self._requestStatus = self.StatusNone self._requestInitTime = time.time() self._uri = uri @@ -144,20 +148,50 @@ self.setText(self.IndexMimeType, mimeType) def requestMimeType(self): - """Returns the mime type of the item""" - return self.text(self.IndexMimeType) + """Returns the mime type of the item + @return: (unicode) request mime type + """ + return unicode(self.text(self.IndexMimeType)) + def setRequestName(self, name): """Sets the request name of the item @param name: (str) name + @return: (unicode) name (including filename collision handling postfix) + @note: the name should not include the filename collision handling postfix """ + self._requestName = name + if self._requestNamePostfix is not None: + name, exts = namespace.split_extensions(name) + name = '%s (%s)%s' % (name, self._requestNamePostfix, ''.join(exts)) self.setText(self.IndexName, name) + return name - def requestName(self): + + def increaseRequestNamePostfix(self): + """Increases the filename collision handling postfix by one + @return: (unicode) new request name + @note: use this to compose one of these 'filename (1).txt' filenames in case of + filename collisons + """ + if self._requestNamePostfix is None: + self._requestNamePostfix = 1 + else: + self._requestNamePostfix += 1 + return self.setRequestName(self.requestName(includePostfix=False)) + + + def requestName(self, includePostfix=True): """Returns the request name of the item + @param includePostfix: if True, returns the request name including file collision handling postfi, + if False the request name is returned without postfix + @return: (unicode) request name """ - return self.text(self.IndexName) + if includePostfix: + return unicode(self.text(self.IndexName)) + return self._requestName + def setRequestPriority(self, priority): """Sets the request priority of the item @param prority: (FcpClient.Priority) @@ -165,8 +199,10 @@ self.setText(self.IndexPriority, priority) def requestPriority(self): - """Returns the request priority of the item""" - return self.text(self.IndexPriority) + """Returns the request priority of the item + @return: (unicode) request priority + """ + return unicode(self.text(self.IndexPriority)) def setProgressWidget(self, tree, widget): """Associates a progress widget to the item @@ -200,8 +236,10 @@ self.setText(self.IndexSize, size) def requestSize(self): - """Returns the request size of the item""" - return self.text(self.IndexSize) + """Returns the request size of the item + @return: (unicode) request size + """ + return unicode(self.text(self.IndexSize)) def setRequestUri(self, uri): """Sets the request uri of the item @@ -253,6 +291,9 @@ #**************************************************************************** # #**************************************************************************** + +#TODO: no idea if the node removes requests when complete or on error or +# if RemovePersistentRequest has to be send explicitely class DownloadWidget(QtGui.QTreeWidget): def __init__(self, @@ -341,9 +382,11 @@ (self._fcpClient.events.TestDDAComplete, self.handleFcpClientTestDDAComplete), (self._fcpClient.events.ClientRequestInfo, self.handleFcpClientRequestInfo), - (self._fcpClient.events.ClientRequestInfoProgress, self.handleFcpClientRequestInfoProgress), + (self._fcpClient.events.SimpleProgress, self.handleFcpClientSimpleProgress), + (self._fcpClient.events.DataFound, self.handleFcpClientDataFound), (self._fcpClient.events.GetFailed, self.handleFcpClientGetFailed), + (self._fcpClient.events.IdentifierCollision, self.handleFcpClientIdentifierCollision), (self._fcpClient.events.ProtocolError, self.handleFcpClientProtocolError), ) # take care not to connect twice @@ -356,17 +399,52 @@ self._fcpClient.testDDA(directory, wantWriteDirectory=True) + #TODO: not yet handled def handleFcpClientDisconnected(self, event, params): """ """ + def handleFcpClientDataFound(self, event, params): + """ + """ + identifier = params['Identifier'] + item = self._downloads['Downloads'].get(identifier, None) + if item is not None: + del self._downloads['Downloads'][identifier] + + progress = item.progressWidget(self) + status = DownloadItem.StatusDownloadComplete + + item.setRequestStatus(status, self._strings.itemStatus[status]) + progress.setColors( + colorBar=self._userSettings['ColorProgressBarDownloadComplete'], + colorBg=self._userSettings['ColorProgressBgDownloadComplete'] + ) + + #TODO: how to provide extra information to the user? def handleFcpClientGetFailed(self, event, params): identifier = params['Identifier'] item = self._downloads['Downloads'].get(identifier, None) if item is not None: del self._downloads['Downloads'][identifier] + code = params['Code'] + # handle file name collision + if code == self._fcpClient.ProtocolError.DiskTargetExists: + if item.requestStatus() == DownloadItem.StatusDownloading: + filename = os.path.join( + self.downloadDirectoryFromItem(item), + item.increaseRequestNamePostfix() + ) + identifier = self.uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientGetFile) + uri = item.requestUri() + + self._fcpClient.clientGetFile(uri, filename, identifier=identifier) + self._downloads['Downloads'][identifier] = item + return + + # handle error progress = item.progressWidget(self) status = DownloadItem.StatusError @@ -381,8 +459,14 @@ colorBar=self._userSettings['ColorProgressBarError'], colorBg=self._userSettings['ColorProgressBgError'] ) + #raise self._fcpClient.FetchError(params) + #TODO: not yet handled + def handleFcpClientIdentifierCollision(self, vent, params): + pass + + def handleFcpClientIdle(self, event, params): # check if there are sownloads queued @@ -423,31 +507,49 @@ elif status & item.StatusRequestInfoComplete: items[status].append(item) - # start items with info requested - itemsToBeStarted = self._userSettings['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 - + downloadsToBeStarted = self._userSettings['MaxSimultaniousDownloads'] - itemsBusy - # start pending items - if itemsToBeStarted > 0: - pendingItems = items[DownloadItem.StatusPending] - pendingItems.sort(cmp=sortf) - while pendingItems: - itemsToBeStarted -= 1 - if itemsToBeStarted < 0: + #TODO: sort by priority + def sortf(item1, item2): + return cmp(item1.requestInitTime(), item2.requestInitTime()) + + # start downloads with info requested complete + if downloadsToBeStarted > 0: + downloadsRequestInfoComplete = items[DownloadItem.StatusRequestInfoComplete] + downloadsRequestInfoComplete.sort(cmp=sortf) + while downloadsRequestInfoComplete: + downloadsToBeStarted -= 1 + if downloadsToBeStarted < 0: break - item = pendingItems.pop(0) + item = downloadsRequestInfoComplete.pop(0) + filename = os.path.join( self.downloadDirectoryFromItem(item), item.requestName()) + identifier = self.uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientGetFile) + progress = item.progressWidget(self) + status = DownloadItem.StatusDownloading + uri = item.requestUri() + + progress.setRange(0, 0) + progress.setValue(0) + progress.setColors( + colorBar=self._userSettings['ColorProgressBarDownloading'], + colorBg=self._userSettings['ColorProgressBgDownloading'] + ) + item.setRequestStatus(status, self._strings.itemStatus[status]) + self._fcpClient.clientGetFile(uri, filename, identifier=identifier) + self._downloads['Downloads'][identifier] = item + + # start pending downloads + if downloadsToBeStarted > 0: + downloadsPending = items[DownloadItem.StatusPending] + downloadsPending.sort(cmp=sortf) + while downloadsPending: + downloadsToBeStarted -= 1 + if downloadsToBeStarted < 0: + break + + identifier = self.uniqueDownloadsIdentifier(self._fcpClient.IdentifierPrefix.ClientRequestInfo) + item = downloadsPending.pop(0) progress = progressbarwrap.ProgressBarEx(self) status = DownloadItem.StatusRequestInfo uri = item.requestUri() @@ -460,11 +562,9 @@ ) item.setProgressWidget(self, progress) item.setRequestStatus(status, self._strings.itemStatus[status]) - - identifier = self._fcpClient.clientRequestInfo(uri) + self._fcpClient.clientRequestInfo(uri, identifier=identifier) self._downloads['Downloads'][identifier] = item - - + def handleFcpClientProtocolError(self, event, params): identifier = params.get('Identifier', None) @@ -505,7 +605,7 @@ item.setRequestSize(dataLength) - def handleFcpClientRequestInfoProgress(self, event, params): + def handleFcpClientSimpleProgress(self, event, params): identifier = params['Identifier'] item = self._downloads['Downloads'].get(identifier, None) @@ -558,6 +658,33 @@ #TODO: retranslate item status + def downloadDirectoryFromItem(self, item): + """Returns the dirctory an item should be downloaded to + @param item: (QTreeWidgetItem) + @return: (str) directory + """ + out = [] + parent = item.parent() + while parent is not None: + out.append(parent.requestName()) + parent = parent.parent() + + out.append(self._directory) + out.reverse() + return os.path.join(*out) + + + def uniqueDownloadsIdentifier(self, identifierPrefix): + """Creates a new identifier that is unique to the internal sownloads dict + @param identifierPrefix: FcpClient.IdentifierPrefix.* + @return: (str) identifier + """ + while True: + identifier = identifierPrefix + self._fcpClient.newIdentifier() + if identifier not in self._downloads['Downloads']: + return identifier + + #*************************************************************************************************** # #*************************************************************************************************** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |