SF.net SVN: fclient:[915] trunk/fclient/fclient
Status: Pre-Alpha
Brought to you by:
jurner
From: <jU...@us...> - 2008-08-16 08:10:41
|
Revision: 915 http://fclient.svn.sourceforge.net/fclient/?rev=915&view=rev Author: jUrner Date: 2008-08-16 08:10:49 +0000 (Sat, 16 Aug 2008) Log Message: ----------- isolated downloads view Modified Paths: -------------- trunk/fclient/fclient/fclient.py Added Paths: ----------- trunk/fclient/fclient/impl/BaseRequestsWidget/ trunk/fclient/fclient/impl/BaseRequestsWidget/BaseRequestsWidget.py trunk/fclient/fclient/impl/BaseRequestsWidget/RequestsWidget.ui trunk/fclient/fclient/impl/BaseRequestsWidget/Ui_RequestsWidget.py trunk/fclient/fclient/impl/BaseRequestsWidget/__init__.py trunk/fclient/fclient/impl/BaseRequestsWidget/_fix_mexec.py trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/ trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDisk.py trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDiskTpl.ui trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/Ui_DlgDownloadKeyToDiskTpl.py trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/__init__.py trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/_fix_mexec.py trunk/fclient/fclient/impl/ViewDownloads/ trunk/fclient/fclient/impl/ViewDownloads/ViewDownloads.py trunk/fclient/fclient/impl/ViewDownloads/__init__.py trunk/fclient/fclient/impl/ViewDownloads/_fix_mexec.py Removed Paths: ------------- trunk/fclient/fclient/impl/ViewDownloads.py trunk/fclient/fclient/impl/tpls/DlgDownloadKeyToDiskTpl.ui trunk/fclient/fclient/impl/tpls/Ui_DlgDownloadKeyToDiskTpl.py trunk/fclient/fclient/impl/tpls/Ui_SideBarLoadDetailsTpl.py Modified: trunk/fclient/fclient/fclient.py =================================================================== --- trunk/fclient/fclient/fclient.py 2008-08-16 08:01:13 UTC (rev 914) +++ trunk/fclient/fclient/fclient.py 2008-08-16 08:10:49 UTC (rev 915) @@ -16,7 +16,7 @@ from .impl.View import ViewWidget from .impl.ViewBrowser import ViewBrowser from .impl.ViewConnection import ViewConnection -from .impl.ViewDownloads import ViewDownloadsWidget +from .impl.ViewDownloads import ViewDownloads from .impl.ViewLogger import ViewLogger from .impl.ViewUploads import ViewUploadsWidget @@ -78,7 +78,7 @@ viewWidget.addTopViews( ViewConnection.ViewConnectionWidget(mainWindow), ViewBrowser.ViewBrowserWidget(mainWindow), - ViewDownloadsWidget(mainWindow), + ViewDownloads.ViewDownloadsWidget(mainWindow), ViewUploadsWidget(mainWindow), ) viewWidget.addBottomViews(ViewLogger.ViewLoggerWidget(mainWindow)) Added: trunk/fclient/fclient/impl/BaseRequestsWidget/BaseRequestsWidget.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/BaseRequestsWidget.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/BaseRequestsWidget.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,561 @@ + +#************************************************************************************************************** +#TODO: +# +# x. prtty tricky to get dls right when the node or client may disconnect unexpectedly +# problem: dls that we send and that have not reached the node +# problem: what to do when the user wants to quit and we still have dls to push to the node +# +# solution would require keeping track of all requests +# a. keep identifiers of requests that reached the node (have to do it anyways) +# b. keep track of requests ahead of sending them to the node (feels not too good doubeling downloads.dat.gz) +# +# best idea seems to be to ignore the problem +# 1. wait till (if ever) freenet devels fdrop node keeping track of client requests +# +# 2. a box thrown to the user (x. do not show this message again) to inform him about pendings +# should be enough. maybe along with a separate widget or some separate color code for pendings +# +# x. performance +# start with a standard model and improve it over time. no need to set any hard +# limits. the user will find out by himself how many dls his machine can handle. +# have to be carefrul though when adding dls, like from a *.frdx to provide appropriate +# warnings +# x. it may take a while untill the final DataFound message arrives when a request is % completed. feedback would be nice +# x. DataFound for a request the file has been removed by the user. no idea what happens. have to test this +# x. when the node is about to start up, looks like persistents may arrive or not. check +# x. how to get early information about mimetype/size? maybe use FcpClient.getFileInfo() +# x. show/hide header izems +# x. sort by header +# x. indicate over all time / dl speed +# x. indicate status / remove items by status +# x. item properties +# x. how to handle inserting huge number of dls? +# idea: insert with lowest priority to get the node to know them, increase priority when a slot in +# MaxSimultaneousDls (if set) is free. atatch progressBar no sooner as priority > MinDlPriority +# x. how to handle huge numbers of dls. the node will flood us on startup with persistents. looks +# like the only way to control the flood is to have one connection/dl. maybe wait for freenet devels +# to realize that this is a serious problem... +# x. byte amount postfixes must be transllated ++ use Kib or Kb or let the user decide? +# x. sometimes groups of dls get not removed +#************************************************************************************************************** +# some fixes for relative imports +# see --> [http://bugs.python.org/issue1510172] absolute/rellative import not working (works only current dir and below) +# see --> [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] PEP for executing a module in a +# ...package containing relative imports +from __future__ import absolute_import +if __name__ == '__main__': + import os + __path__ = [os.path.dirname(__file__)] + from ._fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec +import mimetypes +import os +from PyQt4 import QtCore, QtGui + +from .. import config +from ..lib import fcp2 +from ..lib.fcp2.lib import pmstruct +from ..lib.qt4ex import treewidgetwrap +from ..lib import numbers + +from .dlgs import DlgDownloadKeyToDisk + +from .Ui_RequestsWidget import Ui_ViewRequestsWidget +#********************************************************************************** +# +#********************************************************************************** +BLOCK_SIZE = 32768 # from CHKBlock.java + +#********************************************************************************** +# +#********************************************************************************** +class PersistentRequestData(pmstruct.PMStruct): + _fields_ = ( + ('ClientName', pmstruct.STRING), + ) + +#********************************************************************************** +# +#********************************************************************************** +class TreeItem(QtGui.QTreeWidgetItem): + + IndexName = 0 + IndexSize = 1 + IndexMimeType = 2 + IndexStatus = 3 + IndexProgress = 4 + IndexPriority = 5 + IndexElapsed = 6 + + ProgressBarName = 'downloadKey' + + StatusPending = 'pending' + StatusLoading = 'loading' + StatusComplete = 'complete' + StatusError = 'error' + StatusRemoved = 'removed' + StatusCompressing = 'compressing' + ##StatusCompressed = 'compressed' #TODO: no way to distinguish compressed an loading + + def __init__(self, fcpRequest, *params): + QtGui.QTreeWidgetItem.__init__(self, *params) + self.fcpRequest = fcpRequest + self.fcOldStatus = self.StatusPending + + def status(self): + if self.fcpRequest is None: + return self.StatusRemoved + elif self.fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Success: + return self.StatusComplete + elif self.fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Error: + return self.StatusError + + #TODO: more or less aguess ..have to check this in detail + elif self.fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Started: + if self.fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Compressing: + if self.fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Compressed: + return self.StatusLoading + else: + return self.compressing + else: + return self.StatusLoading + else: + return self.StatusPending + +# exposes status property for stylesheets +class ProgressBar(QtGui.QProgressBar): + + def __init__(self, parent, item): + QtGui.QProgressBar.__init__(self, parent) + self.item = item + + def _get_status(self): + return self.item.status() + status= QtCore.pyqtProperty("QString", _get_status) + + +class RequestsWidgetActions(config.ActionsBase): + + def __init__(self, parent): + config.ActionsBase.__init__(self, parent) + + self.action( + name='ActionDownloadKeyToDisk', + text=self.trUtf8('Download &key...'), + trigger=parent.onDlgDownloadKey, + ) + self.action( + name='ActionRemoveSelectedDownloads', + text=self.trUtf8('Remove download'), + trigger=parent.onRemoveSelectedDownloads, + isEnabled=False, + ) + self.action( + name='ActionRestartSelectedDownloads', + text=self.trUtf8('Restart download'), + trigger=parent.onRestartSelectedDownloads, + isEnabled=False, + ) + + #TODO: enable/disable if items of that type are available? + group = self.group( + name='GroupRemoveGroup', + trigger=parent.onRemoveGroup, + ) + self.action( + name='ActionRemoveFailed', + group=group, + text=self.trUtf8('Failed'), + isEnabled=False, + ) + self.action( + name='ActionRemoveCompleted', + group=group, + text=self.trUtf8('Completed'), + isEnabled=False, + ) + +#********************************************************************************** +# +#********************************************************************************** +class RequestsWidget(QtGui.QWidget, Ui_ViewRequestsWidget): + + IdTree = 'tree' + + def __init__(self, parent, idGlobalFeedback=config.IdMainWindow): + QtGui.QWidget.__init__(self, parent) + self._isCreated = False + self.fcHeaderLabels = {} # fcpIdentifier --> treeItem + self.fcActions = RequestsWidgetActions(self) + self.fcpRequests = {} + self.fcRequestStatusNames = {} + self.menuRemoveGroup = QtGui.QMenu(self) + + self.setupUi(self) + self.fcpClientEvents = ( + (config.fcpClient.events.ClientConnected, self.onFcpClientConnected), + (config.fcpClient.events.ClientDisconnected, self.onFcpClientDisconnected), + (config.fcpClient.events.ConfigData, self.onFcpConfigData), + (config.fcpClient.events.RequestCompleted, self.onFcpClientRequestCompleted), + (config.fcpClient.events.RequestFailed, self.onFcpClientRequestFailed), + (config.fcpClient.events.RequestModified, self.onFcpClientRequestModified), + (config.fcpClient.events.RequestProgress, self.onFcpClientRequestProgress), + (config.fcpClient.events.RequestStarted, self.onFcpClientRequestStarted), + (config.fcpClient.events.RequestRemoved, self.onFcpClientRequestRemoved), + (config.fcpClient.events.RequestCompressionStarted, self.onFcpClientRequestCompressionStarted), + (config.fcpClient.events.RequestCompressionCompleted, self.onFcpClientRequestCompressionCompleted), + ) + config.fcpClient.events += self.fcpClientEvents + + + ############################ + ## private methods + ############################ + def _adjustItemStatus(self, item): + # to take Css styling into account we have to set a new statusBar for each state change + tree = self.controlById(self.IdTree) + oldProgressBar = progressBar = self.tree.itemWidget(item, TreeItem.IndexProgress) + itemStatus = item.status() + itemStatusChanged = itemStatus != item.fcOldStatus + if itemStatusChanged: + progressBar = ProgressBar(self.tree, item) + + # adjust statusBar and set a new one if necessary + # ..bit much work here, but necessary, cos Fcp might come up with + # ..a completed message without any prior progress notifications + if itemStatus == TreeItem.StatusPending: + progressBar.setRange(0, 0) + elif itemStatus == TreeItem.StatusLoading: + progressBar.setRange(0, item.fcpRequest['ProgressRequired']) + progressBar.setValue(item.fcpRequest['ProgressSucceeded']) + elif itemStatus == TreeItem.StatusComplete: + progressBar.setRange(0, 1) + progressBar.setValue(progressBar.maximum()) + elif itemStatus == TreeItem.StatusError: + progressBar.setMinimum(oldProgressBar.minimum()) + progressBar.setMaximum(oldProgressBar.maximum()) + progressBar.setValue(oldProgressBar.value()) + elif itemStatus == TreeItem.StatusRemoved: + pass + elif itemStatus == TreeItem.StatusCompressing: + progressBar.setRange(0, 0) + else: + raise ValueError('Unknown status: %r' % itemStatus) + if itemStatusChanged: + progressBar.setObjectName(TreeItem.ProgressBarName) + tree.setItemWidget(item, TreeItem.IndexProgress, progressBar) + item.setData( + TreeItem.IndexStatus, + QtCore.Qt.DisplayRole, + QtCore.QVariant(self.fcRequestStatusNames[itemStatus]), + ) + item.fcOldStatus = itemStatus + + ############################ + ## + ############################ + def retranslateUi(self, parent): + Ui_ViewRequestsWidget.retranslateUi(self, parent) + tree = self.controlById(self.IdTree) + root = tree.invisibleRootItem() + + # adjust header labels + self.fcHeaderLabels = { + TreeItem.IndexName: self.trUtf8('Name'), + TreeItem.IndexSize: self.trUtf8('Size'), + TreeItem.IndexMimeType: self.trUtf8('MimeType'), + TreeItem.IndexStatus: self.trUtf8('Status'), + TreeItem.IndexPriority: self.trUtf8('Priority'), + TreeItem.IndexProgress: self.trUtf8('Progress'), + TreeItem.IndexElapsed: self.trUtf8('Elapsed'), + } + tree.setHeaderLabels([i[1] for i in sorted(self.fcHeaderLabels.items())]) + + # adjust status names and retranslate all items + self.fcRequestStatusNames = { + TreeItem.StatusPending: self.trUtf8('Pending'), + TreeItem.StatusLoading: self.trUtf8('Loading'), + TreeItem.StatusComplete: self.trUtf8('Complete'), + TreeItem.StatusError: self.trUtf8('Error'), + TreeItem.StatusRemoved: self.trUtf8('Removed'), + TreeItem.StatusCompressing: self.trUtf8('Compressing'), + ##TreeItem.StatusCompressed: self.trUtf8('Compressed'), #TODO: no way to distinguish compressed an loading + } + for item in treewidgetwrap.walkItem(root): + fcpRequest = getattr(item, 'fcpRequest', None) + if hasattr(item, 'fcpRequest'): + item.setText(TreeItem.IndexStatus, self.fcRequestStatusNames[item.status()]) + + # others + self.menuRemoveGroup.setTitle(self.trUtf8('Remove group')) + + def closeEvent(self): + self.viewClose() + + def hideEvent(self, event): + self.fcGlobalFeedback.setVisible(False) + + def showEvent(self, event): + self.fcGlobalFeedback.setVisible(True) + if not self._isCreated: + self._isCreated = True + + # setup tree + tree = self.controlById(self.IdTree) + tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + tree.setRootIsDecorated(False) + tree.setSelectionMode(tree.ExtendedSelection) + tree.setUniformRowHeights(True) + self.connect(tree, QtCore.SIGNAL('customContextMenuRequested(const QPoint &)'), self.onTreeCustomContextMenuRequested) + self.connect(tree, QtCore.SIGNAL('itemSelectionChanged() '), self.onTreeItemSelectionChanged) + + def viewClose(self): + config.fcpClient.events -= self.fcpClientEvents + + ######################################### + ## methods + ######################################### + #TODO: much... + def addFcpRequest(self, fcpRequest): + """ + @note: if you add a newly created request, make shure to set the requests PersistentUserData + to the result of the call to L{persistentFcpRequestData} + """ + tree = self.controlById(self.IdTree) + root = tree.invisibleRootItem() + item= TreeItem(fcpRequest, root) + progressBar = ProgressBar(self.tree, item) + + progressBar.setObjectName(TreeItem.ProgressBarName) + tree.setItemWidget(item, TreeItem.IndexProgress, progressBar) + fileName = fcpRequest['Filename'] + mimeType = mimetypes.guess_type(fileName)[0] + icon = config.fcResources.getIcon( + config.mimeTypeIconName(mimeType), + config.fcSettings.value('IconSize'), + config.fcSettings.value('IconTheme'), + ) + item.setIcon(0, icon) + item.setData( + TreeItem.IndexName, + QtCore.Qt.DisplayRole, + QtCore.QVariant(os.path.basename(fcpRequest['Filename'])) + ) + + #TODO: take a wild guess at the size. no other way to do it currently + estimatedSize = int((BLOCK_SIZE * fcpRequest['ProgressRequired']) + 1) + item.setData( + TreeItem.IndexSize, + QtCore.Qt.DisplayRole, + QtCore.QVariant(self.trUtf8('< ') + numbers.format_num_bytes(estimatedSize)), + ) + + self.fcpRequests[fcpRequest['Identifier']] = item + self._adjustItemStatus(item) + return item + + self.fcpRequests[fcpRequest['Identifier']] = item + self._adjustItemStatus(item) + return item + + + def controlById(idGlobalFeedback, idControl): + return getattr(idGlobalFeedback, idControl) + + # overwrite + def populateMenu(self, menu): + return menu + + def execDlgDownloadKey(self, fcpKey=None): + """pops up the dialog to allow the user to download a key to disk + @param fcpKey: key to initialize the key with or None + """ + dlg = DlgDownloadKeyToDisk.DlgDownloadKeyToDisk(self, fcpKey=fcpKey) + if dlg.exec_() == dlg.Accepted: + self.downloadFile( + dlg.fcpKey(), + dlg.fileName(), + persistence=fcp2.ConstPersistence.Forever, + handleFilenameCollision=True, + ) + + def persistentFcpRequestData(self): + return PersistentRequestData(ClientName=unicode(self.objectName())).dump() + + ######################################### + ## event handlers + ######################################### + def onDlgDownloadKey(self, action): + self.execDlgDownloadKey(fcpKey=None) + + def onRemoveSelectedDownloads(self, action): + tree = self.controlById(self.IdTree) + selectedItems = tree.selectedItems() + + # remove items + for item in selectedItems: + parent = item.parent() + if parent is None: + parent = tree.invisibleRootItem() + parent.removeChild(item) + + # cancel all requests + for item in selectedItems: + for tmp_item in treewidgetwrap.walkItem(item): + if tmp_item.fcpRequest is not None: # we may come across the same item multiple times + if tmp_item.fcpRequest['Identifier'] in self.fcpRequests: #TODO: should never be False?! check + del self.fcpRequests[tmp_item.fcpRequest['Identifier']] + config.fcpClient.removeRequest(tmp_item.fcpRequest) + tmp_item.fcpRequest = None + + def onRestartSelectedDownloads(self, action): + tree = self.controlById(self.IdTree) + for item in tree.selectedItems(): + if item.fcpRequest is None: + raise RuntimeError('fcpRequest is None. should not happen') + del self.fcpRequests[item.fcpRequest['Identifier']] + item.fcpRequest = config.fcpClient.resendRequest(item.fcpRequest) + self.fcpRequests[item.fcpRequest['Identifier']] = item + self._adjustItemStatus(item) + + def onRemoveGroup(self, action): + tree = self.controlById(self.IdTree) + root = tree.invisibleRootItem() + + if action == self.fcActions['ActionRemoveCompleted']: + flag = fcp2.ConstRequestStatus.Success + elif action == self.fcActions['ActionRemoveFailed']: + flag = fcp2.ConstRequestStatus.Error + else: + raise ValueError('Not implemented') + + for item in treewidgetwrap.walkItem(root, topdown=False): + fcpRequest = getattr(item, 'fcpRequest', None) + if fcpRequest is not None: + if fcpRequest['Identifier'] in self.fcpRequests: #TODO: should never be False?! check + del self.fcpRequests[fcpRequest['Identifier']] + + if fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Removed: + pass + elif not fcpRequest['RequestStatus'] & flag: + continue + else: + item.fcpRequest = None + config.fcpClient.removeRequest(fcpRequest) + parent = item.parent() + if parent is None: + parent = root + parent.removeChild(item) + + + # overwrite + def onTreeCustomContextMenuRequested(self, pt): + pass + + # overwrite + def onTreeItemSelectionChanged(self): + pass + + ######################################### + ## fcp event handlers + ######################################### + def onFcpClientConnected(self, event, msg): + for action in self.fcActions: + action.setEnabled(True) + + + def onFcpClientDisconnected(self, event, msg): + for action in self.fcActions: + action.setEnabled(False) + + def onFcpConfigData(self, fcpEvent, fcpRequest): + pass + + + def onFcpClientRequestCompleted(self, fcpEvent, fcpRequest): + item = self.fcpRequests.get(fcpRequest['Identifier'], None) + if item is not None: + mimeType = fcpRequest['MetadataContentType'] + item.setData( + TreeItem.IndexSize, + QtCore.Qt.DisplayRole, + QtCore.QVariant(numbers.format_num_bytes(fcpRequest['MetadataSize'])) + ) + item.setData( + TreeItem.IndexMimeType, + QtCore.Qt.DisplayRole, + QtCore.QVariant(mimeType) + ) + icon = config.fcResources.getIcon( + config.mimeTypeIconName(mimeType), + config.fcSettings.value('IconSize'), + config.fcSettings.value('IconTheme'), + ) + item.setIcon(0, icon) + self._adjustItemStatus(item) + + def onFcpClientRequestCompressionStarted(self, fcpEvent, fcpRequest): + item = self.fcpRequests.get(fcpRequest['Identifier'], None) + if item is not None: + self._adjustItemStatus(item) + + def onFcpClientRequestCompressionCompleted(self, fcpEvent, fcpRequest): + item = self.fcpRequests.get(fcpRequest['Identifier'], None) + if item is not None: + self._adjustItemStatus(item) + + def onFcpClientRequestFailed(self, fcpEvent, fcpRequest): + item = self.fcpRequests.get(fcpRequest['Identifier'], None) + if item is not None: + self._adjustItemStatus(item) + + #TODO: not tested + def onFcpClientRequestModified(self, fcpEvent, fcpRequest): + + requestIdentifier = fcpRequest['Modified'].get(fcp2.ConstRequestModified.Identifier, None) + if requestIdentifier is None: + requestIdentifier = fcpRequest['Identifier'] + item = self.fcpRequests.get(requestIdentifier, None) + + if item is not None: + if fcp2.ConstRequestModified.Identifier in fcpRequest['Modified']: + newFcpIdentifier = fcpRequest['Identifier'] + del self.fcpRequests[requestIdentifier] + self.fcpRequests[newFcpIdentifier] = item + + if fcp2.ConstRequestModified.Filename in fcpRequest['Modified']: + item.setData( + TreeItem.IndexName, + QtCore.Qt.DisplayRole, + QtCore.QVariant(os.path.basename(fcpRequest['Filename'])) + ) + + + def onFcpClientRequestProgress(self, fcpEvent, fcpRequest): + item = self.fcpRequests.get(fcpRequest['Identifier'], None) + if item is not None: + self._adjustItemStatus(item) + + def onFcpClientRequestRemoved(self, fcpEvent, fcpRequest): + pass + + def onFcpClientRequestStarted(self, fcpEvent, fcpRequest): + if fcpRequest['RequestStatus'] & fcp2.ConstRequestStatus.Restored: + try: + requestData = PersistentRequestData.load(fcpRequest['PersistentUserData']) + except pmstruct.PMStructError: + pass + else: + if requestData.get('ClientName', None) == self.objectName(): + item = self.addFcpRequest(fcpRequest) + else: + item = self.fcpRequests.get(fcpRequest['Identifier'], None) + if item is not None: + self._adjustItemStatus(item) + + +#********************************************************************************** +# +#********************************************************************************** Added: trunk/fclient/fclient/impl/BaseRequestsWidget/RequestsWidget.ui =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/RequestsWidget.ui (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/RequestsWidget.ui 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,35 @@ +<ui version="4.0" > + <class>ViewRequestsWidget</class> + <widget class="QWidget" name="ViewRequestsWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>0</number> + </property> + <item row="0" column="0" > + <widget class="QTreeWidget" name="tree" > + <column> + <property name="text" > + <string>1</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> Added: trunk/fclient/fclient/impl/BaseRequestsWidget/Ui_RequestsWidget.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/Ui_RequestsWidget.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/Ui_RequestsWidget.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '/home/me/src/fclient/trunk/fclient/fclient/impl/XBaseRequestsWidget/RequestsWidget.ui' +# +# Created: Sat Aug 16 10:04:59 2008 +# by: PyQt4 UI code generator 4.4.3-snapshot-20080705 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_ViewRequestsWidget(object): + def setupUi(self, ViewRequestsWidget): + ViewRequestsWidget.setObjectName("ViewRequestsWidget") + ViewRequestsWidget.resize(400, 300) + self.gridLayout = QtGui.QGridLayout(ViewRequestsWidget) + self.gridLayout.setMargin(0) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.tree = QtGui.QTreeWidget(ViewRequestsWidget) + self.tree.setObjectName("tree") + self.gridLayout.addWidget(self.tree, 0, 0, 1, 1) + + self.retranslateUi(ViewRequestsWidget) + QtCore.QMetaObject.connectSlotsByName(ViewRequestsWidget) + + def retranslateUi(self, ViewRequestsWidget): + ViewRequestsWidget.setWindowTitle(QtGui.QApplication.translate("ViewRequestsWidget", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.tree.headerItem().setText(0, QtGui.QApplication.translate("ViewRequestsWidget", "1", None, QtGui.QApplication.UnicodeUTF8)) + + +if __name__ == "__main__": + import sys + app = QtGui.QApplication(sys.argv) + ViewRequestsWidget = QtGui.QWidget() + ui = Ui_ViewRequestsWidget() + ui.setupUi(ViewRequestsWidget) + ViewRequestsWidget.show() + sys.exit(app.exec_()) + Added: trunk/fclient/fclient/impl/BaseRequestsWidget/__init__.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/__init__.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/__init__.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1 @@ + Added: trunk/fclient/fclient/impl/BaseRequestsWidget/_fix_mexec.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/_fix_mexec.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/_fix_mexec.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,99 @@ +'''in python 2.5 relative impports are srsly broken ..fix this to make relative imports work +when executing a module as main (-m), including relative imports up to the root package + +see: [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] + +@note: root package is the highest available package in the package hirarchy. +don't look at __name__ too closely. it gets adjusted for a module to just "do the right +thing" in __name__ == '__main__' comparisons +@note: this patch does not work if relative imports are done in __init__.py. no idea why +and to be honest, I don't wanna* know.. +@note: this is more or less a hack. so it may have unwanted side effects for example +when importing parent packages. use at your own risk. could improve this module +by adding a __main__.py to stop at this level or by fixing the __init__.py bug, but +I don't think its worth it. see what python2.6 or 3k brings.. + +usage:: + + # place this at the top a module, before doing any relative imports + from fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + from ...foo import bar + + + +##<-- copy and paste code, assuming _fix_mexec resides in the current dir.. + +# some fixes for relative imports +# see --> [http://bugs.python.org/issue1510172] absolute/rellative import not working (works only current dir and below) +# see --> [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] PEP for executing a module in a +# ...package containing relative imports +from __future__ import absolute_import +if __name__ == '__main__': + import os + __path__ = [os.path.dirname(__file__)] + from ._fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + +##--> copy and paste code +''' + +import imp, os, sys +#******************************************************************************** +# +#******************************************************************************** +class MainName(str): + def __eq__(self, other): + if other == '__main__': return True + return str.__eq__(self, other) + def __ne__(self, other): + if other == '__main__': return False + return str.__ne__(self, other) + + +def fix_mexec(_name_, _file_): + """bugfix for relative imports not working + @param _name_: __name__ of the module + @param _file_: __file__ of the module + + @note: not complete: relies on __init__.py, .pyo (...) is ignored currently + """ + if _name_ == '__main__': + out = [] + # find allparent packages + p = os.path.dirname(os.path.abspath(_file_)) + prev = p + while True: + pkg = os.path.join(p, '__init__.py') + if os.path.isfile(pkg): + out.append([pkg, os.path.basename(p)]) + else: + break + prev = p + p = os.path.dirname(p) + if p == prev: + break + out.reverse() + + # adjust sub package names an import parent modules + name = None + for n, (fpath, name) in enumerate(out): + if n > 0: + name = out[n][1] = out[n -1][1] + '.' + out[n][1] + m = imp.load_source(name, fpath) + m.__path__ = [os.path.dirname(fpath)] + + # adjust name of the __main__ module + if name is not None: + m = sys.modules.pop('__main__') + # 'foo.bar..__main__' does not work for some reason. 'foo.bar' seems to work as expected + ##m.__name__ = _Name_(name + '.' + '__main__') + m.__name__ = MainName(name) + sys.modules[m.__name__] = m + + + Added: trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDisk.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDisk.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDisk.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,153 @@ +#*************************************************************************************** +#TODO: +# x. have to inject (..whatebver) a checkbox into msg box invalid key warning <x don't show this message again> +# x. save dialog pos/size on exit +# +#************************************************************************************* +# some fixes for relative imports +# see --> [http://bugs.python.org/issue1510172] absolute/rellative import not working (works only current dir and below) +# see --> [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] PEP for executing a module in a +# ...package containing relative imports +from __future__ import absolute_import +if __name__ == '__main__': + import os + __path__ = [os.path.dirname(__file__)] + from ._fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + +import os +from PyQt4 import QtCore, QtGui + +from ... import config +from ...lib import fcp2 + +from .Ui_DlgDownloadKeyToDiskTpl import Ui_DlgDownloadKeyToDisk +#********************************************************************************** +# +#********************************************************************************** +class Settings(config.SettingsBase): + _key_ = 'DlgDownloadKeyToDisk' + _settings_ = ( + ('Geometry', 'ByteArray', QtCore.QByteArray()), + ) + + +#********************************************************************************** +# +#********************************************************************************** +class DlgDownloadKeyToDisk(QtGui.QDialog, Ui_DlgDownloadKeyToDisk): + + IdEdKey = 'edKey' + IdEdFileName = 'edFileName' + IdEdDirectory = 'edDirectory' + IdBtChooseDirectory = 'btChooseDirectory' + + + def __init__(self, parent=None, fcpKey=None): + QtGui.QDialog.__init__(self, parent) + + self.setupUi(self) + self.setWindowTitle(config.FcAppName + self.trUtf8(' - Download key..')) + self.fcSettings = Settings(self).restore() + + self._fileName = None + self._fcpKey = fcpKey + + # setup key editbox + ed = self.controlById(self.IdEdKey) + if fcpKey is not None: + ed.setText(fcpKey.toString()) + + # setup filename editbox + ed = self.controlById(self.IdEdFileName) + if fcpKey is not None: + # find out fileName to dl key to + fileName = config.guessFileNameFromKey(self._fcpKey) + if fileName is None: + fileName = self.trUtf8('UNKNOWN') + ed.setText(fileName) + + # setup directory editbox + ed = self.controlById(self.IdEdDirectory) + ed.setText(unicode(config.fcSettings.value('DownloadDir'))) + bt = self.controlById(self.IdBtChooseDirectory) + self.connect(bt, QtCore.SIGNAL('clicked()'), self.onChooseDirectory) + + + self.restoreGeometry(self.fcSettings.value('Geometry')) + + ############################## + ## methods + ############################## + def controlById(self, idControl): + return getattr(self, idControl) + + def fileName(self): + return self._fileName + + def fcpKey(self): + return self._fcpKey + + ############################## + ## overwritten methods + ############################## + def accept(self): + edKey = self.controlById(self.IdEdKey) + edFileName = self.controlById(self.IdEdFileName) + edDirectory = self.controlById(self.IdEdDirectory) + + key = unicode(edKey.text()) + if not key: + return QtGui.QMessageBox.warning(self, self.windowTitle(), 'Please enter a key to download') + try: + self._fcpKey = fcp2.Key(key) + except fcp2.ErrorKey: + return QtGui.QMessageBox.warning(self, self.windowTitle(), 'Looks like the key entered is not valid') + + fileName = edFileName.text() + if fileName.isEmpty(): + return QtGui.QMessageBox.warning(self, self.windowTitle(), 'Please enter a filename for the key') + + directory = edDirectory.text() + if directory.isEmpty(): + return QtGui.QMessageBox.warning(self, self.windowTitle(), 'Please enter a directory under wich to save the key') + + self._fileName = os.path.join(unicode(directory), unicode(fileName)) + self.done(self.Accepted) + + ############################## + ## overwritten events + ############################## + def hideEvent(self, event): + self.fcSettings.setValues(Geometry=self.saveGeometry()) + + ############################## + ## event handlers + ############################## + def onChooseDirectory(self): + edDirectory = self.controlById(self.IdEdDirectory) + directory = QtGui.QFileDialog.getExistingDirectory( + self, + config.FcAppName + self.trUtf8(' - Download key to..'), + edDirectory.text(), + ) + if directory: + edDirectory.setText(directory) + +#********************************************************************************** +# +#********************************************************************************** +if __name__ == '__main__': + import sys + + app = QtGui.QApplication(sys.argv) + w = DlgDownloadKeyToDisk( + #None, + fcpKey=fcp2.KeyKSK('foo.txt') + ) + w.show() + res = app.exec_() + sys.exit(res) + + Added: trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDiskTpl.ui =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDiskTpl.ui (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/DlgDownloadKeyToDiskTpl.ui 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,136 @@ +<ui version="4.0" > + <class>DlgDownloadKeyToDisk</class> + <widget class="QDialog" name="DlgDownloadKeyToDisk" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>431</width> + <height>243</height> + </rect> + </property> + <property name="windowTitle" > + <string>Dialog</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <item row="0" column="0" > + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QLabel" name="fieldHeader" > + <property name="text" > + <string>Key:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="edKey" > + <property name="dragEnabled" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="fieldHeader_2" > + <property name="text" > + <string>File name:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="edFileName" /> + </item> + <item> + <widget class="QLabel" name="fieldHeader_3" > + <property name="text" > + <string>Directory:</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <widget class="QLineEdit" name="edDirectory" > + <property name="dragEnabled" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btChooseDirectory" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item row="1" column="0" > + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>15</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" > + <widget class="Line" name="line" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>DlgDownloadKeyToDisk</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>DlgDownloadKeyToDisk</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> Added: trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/Ui_DlgDownloadKeyToDiskTpl.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/Ui_DlgDownloadKeyToDiskTpl.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/Ui_DlgDownloadKeyToDiskTpl.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '/home/me/src/fclient/trunk/fclient/fclient/impl/XBaseRequestsWidget/dlgs/DlgDownloadKeyToDiskTpl.ui' +# +# Created: Sat Aug 16 10:03:40 2008 +# by: PyQt4 UI code generator 4.4.3-snapshot-20080705 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_DlgDownloadKeyToDisk(object): + def setupUi(self, DlgDownloadKeyToDisk): + DlgDownloadKeyToDisk.setObjectName("DlgDownloadKeyToDisk") + DlgDownloadKeyToDisk.resize(431, 243) + self.gridLayout = QtGui.QGridLayout(DlgDownloadKeyToDisk) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout = QtGui.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.fieldHeader = QtGui.QLabel(DlgDownloadKeyToDisk) + self.fieldHeader.setObjectName("fieldHeader") + self.verticalLayout.addWidget(self.fieldHeader) + self.edKey = QtGui.QLineEdit(DlgDownloadKeyToDisk) + self.edKey.setDragEnabled(True) + self.edKey.setObjectName("edKey") + self.verticalLayout.addWidget(self.edKey) + self.fieldHeader_2 = QtGui.QLabel(DlgDownloadKeyToDisk) + self.fieldHeader_2.setObjectName("fieldHeader_2") + self.verticalLayout.addWidget(self.fieldHeader_2) + self.edFileName = QtGui.QLineEdit(DlgDownloadKeyToDisk) + self.edFileName.setObjectName("edFileName") + self.verticalLayout.addWidget(self.edFileName) + self.fieldHeader_3 = QtGui.QLabel(DlgDownloadKeyToDisk) + self.fieldHeader_3.setObjectName("fieldHeader_3") + self.verticalLayout.addWidget(self.fieldHeader_3) + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.edDirectory = QtGui.QLineEdit(DlgDownloadKeyToDisk) + self.edDirectory.setDragEnabled(True) + self.edDirectory.setObjectName("edDirectory") + self.horizontalLayout.addWidget(self.edDirectory) + self.btChooseDirectory = QtGui.QPushButton(DlgDownloadKeyToDisk) + self.btChooseDirectory.setObjectName("btChooseDirectory") + self.horizontalLayout.addWidget(self.btChooseDirectory) + self.verticalLayout.addLayout(self.horizontalLayout) + self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) + spacerItem = QtGui.QSpacerItem(20, 15, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 1, 0, 1, 1) + self.line = QtGui.QFrame(DlgDownloadKeyToDisk) + self.line.setFrameShape(QtGui.QFrame.HLine) + self.line.setFrameShadow(QtGui.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 2, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(DlgDownloadKeyToDisk) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) + + self.retranslateUi(DlgDownloadKeyToDisk) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), DlgDownloadKeyToDisk.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), DlgDownloadKeyToDisk.reject) + QtCore.QMetaObject.connectSlotsByName(DlgDownloadKeyToDisk) + + def retranslateUi(self, DlgDownloadKeyToDisk): + DlgDownloadKeyToDisk.setWindowTitle(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "Dialog", None, QtGui.QApplication.UnicodeUTF8)) + self.fieldHeader.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "Key:", None, QtGui.QApplication.UnicodeUTF8)) + self.fieldHeader_2.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "File name:", None, QtGui.QApplication.UnicodeUTF8)) + self.fieldHeader_3.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "Directory:", None, QtGui.QApplication.UnicodeUTF8)) + self.btChooseDirectory.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "...", None, QtGui.QApplication.UnicodeUTF8)) + + +if __name__ == "__main__": + import sys + app = QtGui.QApplication(sys.argv) + DlgDownloadKeyToDisk = QtGui.QDialog() + ui = Ui_DlgDownloadKeyToDisk() + ui.setupUi(DlgDownloadKeyToDisk) + DlgDownloadKeyToDisk.show() + sys.exit(app.exec_()) + Added: trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/__init__.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/__init__.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/__init__.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1 @@ + Added: trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/_fix_mexec.py =================================================================== --- trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/_fix_mexec.py (rev 0) +++ trunk/fclient/fclient/impl/BaseRequestsWidget/dlgs/_fix_mexec.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,99 @@ +'''in python 2.5 relative impports are srsly broken ..fix this to make relative imports work +when executing a module as main (-m), including relative imports up to the root package + +see: [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] + +@note: root package is the highest available package in the package hirarchy. +don't look at __name__ too closely. it gets adjusted for a module to just "do the right +thing" in __name__ == '__main__' comparisons +@note: this patch does not work if relative imports are done in __init__.py. no idea why +and to be honest, I don't wanna* know.. +@note: this is more or less a hack. so it may have unwanted side effects for example +when importing parent packages. use at your own risk. could improve this module +by adding a __main__.py to stop at this level or by fixing the __init__.py bug, but +I don't think its worth it. see what python2.6 or 3k brings.. + +usage:: + + # place this at the top a module, before doing any relative imports + from fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + from ...foo import bar + + + +##<-- copy and paste code, assuming _fix_mexec resides in the current dir.. + +# some fixes for relative imports +# see --> [http://bugs.python.org/issue1510172] absolute/rellative import not working (works only current dir and below) +# see --> [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] PEP for executing a module in a +# ...package containing relative imports +from __future__ import absolute_import +if __name__ == '__main__': + import os + __path__ = [os.path.dirname(__file__)] + from ._fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + +##--> copy and paste code +''' + +import imp, os, sys +#******************************************************************************** +# +#******************************************************************************** +class MainName(str): + def __eq__(self, other): + if other == '__main__': return True + return str.__eq__(self, other) + def __ne__(self, other): + if other == '__main__': return False + return str.__ne__(self, other) + + +def fix_mexec(_name_, _file_): + """bugfix for relative imports not working + @param _name_: __name__ of the module + @param _file_: __file__ of the module + + @note: not complete: relies on __init__.py, .pyo (...) is ignored currently + """ + if _name_ == '__main__': + out = [] + # find allparent packages + p = os.path.dirname(os.path.abspath(_file_)) + prev = p + while True: + pkg = os.path.join(p, '__init__.py') + if os.path.isfile(pkg): + out.append([pkg, os.path.basename(p)]) + else: + break + prev = p + p = os.path.dirname(p) + if p == prev: + break + out.reverse() + + # adjust sub package names an import parent modules + name = None + for n, (fpath, name) in enumerate(out): + if n > 0: + name = out[n][1] = out[n -1][1] + '.' + out[n][1] + m = imp.load_source(name, fpath) + m.__path__ = [os.path.dirname(fpath)] + + # adjust name of the __main__ module + if name is not None: + m = sys.modules.pop('__main__') + # 'foo.bar..__main__' does not work for some reason. 'foo.bar' seems to work as expected + ##m.__name__ = _Name_(name + '.' + '__main__') + m.__name__ = MainName(name) + sys.modules[m.__name__] = m + + + Added: trunk/fclient/fclient/impl/ViewDownloads/ViewDownloads.py =================================================================== --- trunk/fclient/fclient/impl/ViewDownloads/ViewDownloads.py (rev 0) +++ trunk/fclient/fclient/impl/ViewDownloads/ViewDownloads.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,203 @@ +"""""" + +# some fixes for relative imports +# see --> [http://bugs.python.org/issue1510172] absolute/rellative import not working (works only current dir and below) +# see --> [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] PEP for executing a module in a +# ...package containing relative imports +from __future__ import absolute_import +if __name__ == '__main__': + import os + __path__ = [os.path.dirname(__file__)] + from ._fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + +from PyQt4 import QtCore, QtGui + +from .. import config +from ..BaseRequestsWidget import RequestsWidget +#************************************************************************************ +# +#************************************************************************************ +class DownloadsWidgetGlobalFeedback(config.GlobalFeedbackBase): + """wrapper for global statusbar widgets, menus""" + + def __init__(self, parent, idGlobalFeedback): + config.GlobalFeedbackBase.__init__(self, parent, idGlobalFeedback) + + # menus + self.menus = [] + if self.menuBar is not None and hasattr(parent, 'fcViewObject'): + menu = QtGui.QMenu(parent.fcViewObject.displayName, self.menuBar) + parent.populateMenu(menu) + self.menus.append(menu) + self.menuBar.addViewMenu(menu) + + # status bar widgets + self.labelStatus = None + self.progress = None + self.labelFeedbackWrap = None + #if self.statusBar is not None: + # self.labelStatus = QtGui.QLabel(QtCore.QString(), self.statusBar) + # self.statusBar.addWidget(self.labelStatus) + # + # self.progress = QtGui.QProgressBar(self.statusBar) + # self.progress.setRange(0, Browser.MaxProgress) + # self.progress.setValue(0) + # self.statusBar.addWidget(self.progress) + # + # label = QtGui.QLabel(self.statusBar) + # label.setFrameStyle(QtGui.QLabel.Sunken | QtGui.QLabel.Box) + # self.labelFeedbackWrap = pathlabelwrap.PathLabelWrap( + # label, + # path_module=config.CompactPathFcpKeyModule, + # ) + # self.statusBar.addWidget(self.labelFeedbackWrap.label, 1) + + + def setVisible(self, flag): + if self.menuBar is not None: + for menu in self.menus: + menu.children()[0].setEnabled(flag) + #if self.statusBar is not None: + # self.progress.setVisible(flag) + # self.labelStatus.setVisible(flag) + # self.labelFeedbackWrap.label.setVisible(flag) + + #def setProgress(self, n): + # if self.progress is not None: + # self.progress.setValue(n) + + #def setStatusMessage(self, qString): + # if self.labelStatus is not None: + # self.labelStatus.setText(qString) + + #def setFeedback(self, qString): + # if self.labelFeedbackWrap is not None: + # self.labelFeedbackWrap.setPath(unicode(qString)) + + + +class DownloadsViewObject(config.ViewObject): + + def __init__(self, parent): + config.ViewObject. __init__(self, parent) + + self.name=parent.objectName() + self.displayName=self.trUtf8('Downloads') + self.icon=QtGui.QIcon() + + +class DownloadsWidgetSettings(config.SettingsBase): + + + _key_ = config.IdViewDownloadsWidget + _settings_ = ( + ('MaxSimultaneousDownloads', 'UInt', 3), + ) + + +class ViewDownloadsWidget(RequestsWidget): + + def __init__(self, parent, idGlobalFeedback=config.IdMainWindow): + + self.menuRemoveGroup = None + + RequestsWidget.__init__(self, parent) + + self.setObjectName(config.IdViewDownloadsWidget) + config.ObjectRegistry.register(self) + self.fcSettings = DownloadsWidgetSettings(self).restore() + self.fcViewObject = DownloadsViewObject(self) + self.fcGlobalFeedback = DownloadsWidgetGlobalFeedback(self, idGlobalFeedback) + + # setup menus + self.menuRemoveGroup = QtGui.QMenu(self) + self.menuRemoveGroup.setTitle(self.trUtf8('Remove group')) + for action in self.fcActions['GroupRemoveGroup'].actions(): + self.menuRemoveGroup.addAction(action) + + + ################################### + ## overwritten methods + ################################### + def hideEvent(self, event): + self.fcGlobalFeedback.setVisible(False) + RequestsWidget.hideEvent(self, event) + + def showEvent(self, event): + self.fcGlobalFeedback.setVisible(True) + RequestsWidget.showEvent(self, event) + + def populateMenu(self, menu): + menu.addAction(self.fcActions['ActionDownloadKeyToDisk']) + return menu + + def retranslateUi(self, parent): + RequestsWidget.retranslateUi(self, parent) + if self.menuRemoveGroup is not None: + self.menuRemoveGroup.setTitle(self.trUtf8('Remove group')) + + ################################### + ## methods + ################################### + def downloadFile(self, fcpKey, fileName, **kws): + """""" + fileName = unicode(fileName) + fcpRequest = config.fcpClient.getFile( + fcpKey, + fileName, + persistentUserData = self.persistentFcpRequestData(), + #TODO: browser sets this. ok or not? + #handleFilenameCollision=True, + handlePermanentRedirect=True, + **kws + ) + item = self.addFcpRequest(fcpRequest) + + ################################### + ## event handlers + ################################### + def onTreeCustomContextMenuRequested(self, pt): + tree = self.controlById(self.IdTree) + pt = tree.viewport().mapToGlobal(pt) + + menu = QtGui.QMenu(self) + menu.addAction(self.fcActions['ActionRemoveSelectedDownloads']) + menu.addAction(self.fcActions['ActionRestartSelectedDownloads']) + menu.addMenu(self.menuRemoveGroup) + menu.exec_(pt) + + def onTreeItemSelectionChanged(self): + tree = self.controlById(self.IdTree) + hasSelectedItems = tree.selectionModel().hasSelection() + self.fcActions['ActionRemoveSelectedDownloads'].setEnabled(hasSelectedItems) + self.fcActions['ActionRestartSelectedDownloads'].setEnabled(hasSelectedItems) + + +#********************************************************************************** +# +#********************************************************************************** +if __name__ == '__main__': + import sys + from .. import View + from ..ViewConnection import ViewConnection + from ..ViewLogger import ViewLogger + from ..MainWindow import MainWindow + + app = QtGui.QApplication(sys.argv) + + mainWindow = MainWindow.MainWindow() + viewWidget = View.ViewWidget(mainWindow) + mainWindow.setCentralWidget(viewWidget) + + viewWidget.addTopViews( + ViewConnection.ViewConnectionWidget(None), + ViewDownloadsWidget(None), + ) + viewWidget.addBottomViews(ViewLogger.ViewLoggerWidget(None)) + + mainWindow.show() + res = app.exec_() + sys.exit(res) \ No newline at end of file Added: trunk/fclient/fclient/impl/ViewDownloads/__init__.py =================================================================== --- trunk/fclient/fclient/impl/ViewDownloads/__init__.py (rev 0) +++ trunk/fclient/fclient/impl/ViewDownloads/__init__.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1 @@ + Added: trunk/fclient/fclient/impl/ViewDownloads/_fix_mexec.py =================================================================== --- trunk/fclient/fclient/impl/ViewDownloads/_fix_mexec.py (rev 0) +++ trunk/fclient/fclient/impl/ViewDownloads/_fix_mexec.py 2008-08-16 08:10:49 UTC (rev 915) @@ -0,0 +1,93 @@ +'''python 2.5 relative impports are srsly broken ..fix this to make relative imports work +when executing a module as main (-m), including relative imports up to the root package + +see: [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] + +@note: root package is the highest available package in the package hirarchy. +don't look at __name__ too closely. it gets adjusted for a module to just "do the right +thing" in __name__ == '__main__' comparisons. + +usage:: + + # place this at the top a module, before doing any relative imports + from fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + from ...foo import bar + + + +##<-- copy and paste code, assuming _fix_mexec resides in the current dir.. + +# some fixes for relative imports +# see --> [http://bugs.python.org/issue1510172] absolute/rellative import not working (works only current dir and below) +# see --> [http://mail.python.org/pipermail/python-ideas/2007-February/000232.html] PEP for executing a module in a +# ...package containing relative imports +from __future__ import absolute_import +if __name__ == '__main__': + import os + __path__ = [os.path.dirname(__file__)] + from ._fix_mexec import fix_mexec + fix_mexec(__name__, __file__) + del fix_mexec + + +##--> copy and paste code +''' + +import imp, os, sys +#******************************************************************************** +# +#******************************************************************************** +class MainName(str): + def __eq__(self, other): + if other == '__main__': return True + return str.__eq__(self, other) + def __ne__(self, other): + if other == '__main__': return False + return str.__ne__(self, other) + + +def fix_mexec(_name_, _file_): + """bugfix for relative imports not working + @param _name_: __name__ of the module + @param _file_: __file__ of the module + + @note: not complete: relies on __init__.py, .pyo (...) is ignored currently + """ + if _name_ == '__main__': + out = [] + # find allparent packages + p = os.path.dirname(os.path.abspath(_file_)) + prev = p + while True: + pkg = os.path.join(p, '__init__.py') + if os.path.isfile(pkg): + out.append([pkg, os.path.basename(p)]) + else: + break + prev = p + p = os.path.dirname(p) + if p == prev: + break + out.reverse() + + # adjust sub package names an import parent modules + name = None + for n, (fpath, name) in enumerate(out): + if n > 0: + name = out[n][1] = out[n -1][1] + '.' + out[n][1] + m = imp.load_source(name, fpath) + m.__path__ = [os.path.dirname(fpath)] + + # adjust name of the __main__ module + if name is not None: + m = sys.modules.pop('__main__') + # 'foo.bar..__main__' does not work for some reason. 'foo.bar' seems to work as expected + ##m.__name__ = _Name_(name + '.' + '__main__') + m.__name__ = MainName(name) + sys.modules[m.__name__] = m + + + Deleted: trunk/fclient/fclient/impl/ViewDownloads.py =================================================================== --- trunk/fclient/fclient/impl/ViewDownloads.py 2008-08-16 08:01:13 UTC (rev 914) +++ trunk/fclient/fclient/impl/ViewDownloads.py 2008-08-16 08:10:49 UTC (rev 915) @@ -1,196 +0,0 @@ -"""""" - - -from __future__ import absolute_import -if __name__ == '__main__': # see --> http://bugs.python.org/issue1510172 . works only current dir and below - import os; __path__ = [os.path.dirname(__file__)] - - -from PyQt4 import QtCore, QtGui - -from . import config -from .BaseRequestsWidget import RequestsWidget -#************************************************************************************ -# -#***********************************************************************************... [truncated message content] |