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] |