Thread: SF.net SVN: fclient: [538] trunk/fclient/src/fclient
Status: Pre-Alpha
Brought to you by:
jurner
From: <jU...@us...> - 2008-07-07 21:31:51
|
Revision: 538 http://fclient.svn.sourceforge.net/fclient/?rev=538&view=rev Author: jUrner Date: 2008-07-07 14:32:00 -0700 (Mon, 07 Jul 2008) Log Message: ----------- added lib Added Paths: ----------- trunk/fclient/src/fclient/lib/ trunk/fclient/src/fclient/lib/__init__.py trunk/fclient/src/fclient/lib/fcp2/ trunk/fclient/src/fclient/lib/fcp2/LICENCE.MIT trunk/fclient/src/fclient/lib/fcp2/README trunk/fclient/src/fclient/lib/fcp2/__init__.py trunk/fclient/src/fclient/lib/fcp2/client.py trunk/fclient/src/fclient/lib/fcp2/config.py trunk/fclient/src/fclient/lib/fcp2/consts.py trunk/fclient/src/fclient/lib/fcp2/events.py trunk/fclient/src/fclient/lib/fcp2/iohandler.py trunk/fclient/src/fclient/lib/fcp2/key.py trunk/fclient/src/fclient/lib/fcp2/lib/ trunk/fclient/src/fclient/lib/fcp2/lib/__init__.py trunk/fclient/src/fclient/lib/fcp2/lib/events.py trunk/fclient/src/fclient/lib/fcp2/lib/namespace.py trunk/fclient/src/fclient/lib/fcp2/lib/node.py trunk/fclient/src/fclient/lib/fcp2/lib/numbers.py trunk/fclient/src/fclient/lib/fcp2/lib/tools.py trunk/fclient/src/fclient/lib/fcp2/message.py trunk/fclient/src/fclient/lib/fcp2/scripts/ trunk/fclient/src/fclient/lib/fcp2/scripts/__init__.py trunk/fclient/src/fclient/lib/fcp2/scripts/gen_docs.py trunk/fclient/src/fclient/lib/fcp2/scripts/gen_messagecheatsheet.py trunk/fclient/src/fclient/lib/fcp2/test/ trunk/fclient/src/fclient/lib/fcp2/test/__init__.py trunk/fclient/src/fclient/lib/fcp2/test/dummy_io.py trunk/fclient/src/fclient/lib/fcp2/test/test_all.py trunk/fclient/src/fclient/lib/fcp2/test/test_client.py trunk/fclient/src/fclient/lib/fcp2/test/test_config.py trunk/fclient/src/fclient/lib/fcp2/test/test_iohandler.py trunk/fclient/src/fclient/lib/fcp2/test/test_key.py trunk/fclient/src/fclient/lib/fcp2/test/test_message.py trunk/fclient/src/fclient/lib/fcp2/test/test_types.py trunk/fclient/src/fclient/lib/fcp2/types.py trunk/fclient/src/fclient/lib/qt4ex/ trunk/fclient/src/fclient/lib/qt4ex/LICENCE.MIT trunk/fclient/src/fclient/lib/qt4ex/README trunk/fclient/src/fclient/lib/qt4ex/__init__.py trunk/fclient/src/fclient/lib/qt4ex/assistant.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/ trunk/fclient/src/fclient/lib/qt4ex/ctrls/__init__.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/areatips.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/checkarraywrap.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/colorbutton.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/compactpatwrap.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/dragtool.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/editboxwrap.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/labelwrap.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/mrumenu.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/tablewidget.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/toolbarwrap.py trunk/fclient/src/fclient/lib/qt4ex/ctrls/treewidgetwrap.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/ trunk/fclient/src/fclient/lib/qt4ex/dlgs/__init__.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgabout/ trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgabout/DlgAbout.ui trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgabout/Ui_DlgAbout.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgabout/__init__.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgfindreplace/ trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgfindreplace/DlgFindReplace.ui trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgfindreplace/Ui_DlgFindReplace.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgfindreplace/__init__.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgpreferences/ trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgpreferences/DlgPreferencesTree.ui trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgpreferences/Ui_DlgPreferencesTree.py trunk/fclient/src/fclient/lib/qt4ex/dlgs/dlgpreferences/__init__.py trunk/fclient/src/fclient/lib/qt4ex/lang/ trunk/fclient/src/fclient/lib/qt4ex/lang/qt4ex_de.ts trunk/fclient/src/fclient/lib/qt4ex/lang/qt4ex_en.ts trunk/fclient/src/fclient/lib/qt4ex/language.py trunk/fclient/src/fclient/lib/qt4ex/qt4ex.pro trunk/fclient/src/fclient/lib/qt4ex/qtools.py trunk/fclient/src/fclient/lib/qt4ex/res/ trunk/fclient/src/fclient/lib/qt4ex/res/language/ trunk/fclient/src/fclient/lib/qt4ex/res/language/LangCodes-ISO 639-1.txt trunk/fclient/src/fclient/lib/qt4ex/resources.py trunk/fclient/src/fclient/lib/qt4ex/scripts/ trunk/fclient/src/fclient/lib/qt4ex/scripts/__init__.py trunk/fclient/src/fclient/lib/qt4ex/scripts/manifest.py trunk/fclient/src/fclient/lib/qt4ex/scripts/pylupdate.py trunk/fclient/src/fclient/lib/qt4ex/scripts/qtpro.py trunk/fclient/src/fclient/lib/qt4ex/settingsbase.py Added: trunk/fclient/src/fclient/lib/__init__.py =================================================================== --- trunk/fclient/src/fclient/lib/__init__.py (rev 0) +++ trunk/fclient/src/fclient/lib/__init__.py 2008-07-07 21:32:00 UTC (rev 538) @@ -0,0 +1 @@ + Added: trunk/fclient/src/fclient/lib/fcp2/LICENCE.MIT =================================================================== --- trunk/fclient/src/fclient/lib/fcp2/LICENCE.MIT (rev 0) +++ trunk/fclient/src/fclient/lib/fcp2/LICENCE.MIT 2008-07-07 21:32:00 UTC (rev 538) @@ -0,0 +1,20 @@ + Fcp2 - a python wraper library for the freenet client protocol version 2. See: [http://www.freenetproject.org] + +Copyright (c) 2008 J\xFCrgen Urner + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file Added: trunk/fclient/src/fclient/lib/fcp2/README =================================================================== --- trunk/fclient/src/fclient/lib/fcp2/README (rev 0) +++ trunk/fclient/src/fclient/lib/fcp2/README 2008-07-07 21:32:00 UTC (rev 538) @@ -0,0 +1,30 @@ +Fcp - a python wraper library for the freenet client protocol version 2 + +homepage: [http://fclient.sourceforge.net] +freenet: [http://www.freenetproject.org] + + +requirements: python >= 2.5 + +note: for one or the other reason the package is designed to be dropped into +any project or to be used directly from the folder it resides in. no need to install it +to 'lib/site-packages'. if you want to do so, make shure to remove any prior +fcp2 package and copy it to site-packages by hand. + + + +Version history: + +******************************************************************* +0.0.1 +******************************************************************* +(07.06.08) first alpha release for testing + +news: + + x. + +bugfixes: + + x. + Added: trunk/fclient/src/fclient/lib/fcp2/__init__.py =================================================================== --- trunk/fclient/src/fclient/lib/fcp2/__init__.py (rev 0) +++ trunk/fclient/src/fclient/lib/fcp2/__init__.py 2008-07-07 21:32:00 UTC (rev 538) @@ -0,0 +1,50 @@ +"""Python wrapper for the freenet client protocol version-2 + +See: [http://www.freenetproject.org] and [http://wiki.freenetproject.org/FreenetFCPSpec2Point0] + +@requires: python >= 2.5 +""" +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__)] + +__author__ = 'Juergen Urner' +__copyright__ = '(c) 2008 - Juergen Urner' +__email__ = 'jue...@ar...' +__licence__ = 'Mit' +__version__ = '0.0.1' + +from .client import Client +from .config import (Config, ConfigDataType, ConfigItem, ConfigKeySep, ConfigValueClass) +from .consts import (ConstByteAmountPostfix, ConstConnectReason, ConstDebugVerbosity, ConstDisconnectReason, + ConstFetchError, ConstFilenameCollision, ConstInsertError, ConstKeyType, ConstLogMessages, + ConstLogger, ConstMessage, ConstPeerNodeStatus, ConstPeerNoteType, ConstPersistence, + ConstPriority, ConstProtocolError, ConstPutDirType, ConstRequestModified, ConstRequestStatus, + ConstRequestType, ConstReturnType, ConstTimeDeltaPostfix, ConstUploadFrom, ConstVerbosity, + Error, ErrorIOBroken, ErrorIOClosed, ErrorIOConnectFailed, ErrorIOTimeout, ErrorMessageParse, + FcpFalse, FcpTrue) +from .key import (Key, KeyCHK, KeyKSK, KeySSK, KeyTypesAll, KeyUSK, TypeKey, base64UrlsaveDecode, keyNormkey) +from .message import (MessagesAll, MsgAddPeer, MsgAllData, MsgClientDisconnected, MsgClientGet, MsgClientHello, + MsgClientPut, MsgClientPutComplexDir, MsgClientPutDiskDir, MsgClientSocketDied, + MsgClientSocketTimeout, MsgCloseConnectionDuplicateClientName, MsgConfigData, MsgDataFound, + MsgEndListPeerNotes, MsgEndListPeers, MsgEndListPersistentRequests, MsgFCPPluginMessage, + MsgFCPPluginReply, MsgFinishedCompression, MsgGenerateSSK, MsgGetConfig, MsgGetFailed, + MsgGetNode, MsgGetPluginInfo, MsgGetRequestStatus, MsgIdentifierCollision, MsgListPeer, + MsgListPeerNotes, MsgListPeers, MsgListPersistentRequests, MsgModifyConfig, MsgModifyPeer, + MsgModifyPeerNote, MsgModifyPersistentRequest, MsgNodeData, MsgNodeHello, MsgPeer, MsgPeerNote, + MsgPeerRemoved, MsgPersistentGet, MsgPersistentPut, MsgPersistentPutDir, MsgPersistentRequestModified, + MsgPersistentRequestRemoved, MsgPluginInfo, MsgProtocolError, MsgPutFailed, MsgPutFetchable, + MsgPutSuccessful, MsgRemovePeer, MsgRemoveRequest, MsgSSKKeypair, MsgShutdown, MsgSimpleProgress, + MsgStartedCompression, MsgSubscribeUSK, MsgSubscribedUSK, MsgSubscribedUSKUpdate, + MsgTestDDAComplete, MsgTestDDAReply, MsgTestDDARequest, MsgTestDDAResponse, MsgURIGenerated, + MsgUnknownNodeIdentifier, MsgUnknownPeerNoteType, MsgWatchGlobal, PersistentParamsSep, + newMessageClass) +from .types import (Type, TypeBase64EncodedString, TypeBool, TypeByteAmount, TypeChoiceFProxyCss, TypeChoiceLoggerPriority, + TypeChoiceNodeDownloadAllowedDirs, TypeChoiceNodeUploadAllowedDirs, TypeChoicePriorityPolicy, + TypeChoiceSSLVersion, TypeDirname, TypeFilename, TypeFloat, TypeIP, TypeIPList, TypeIPort, TypeInt, + TypeIntWithBounds, TypeInt_GetFailed_ExpectedDataLenght, TypePercent, TypeString, TypeStringList, TypeTime, + TypeTimeDelta, TypeUri) +#**************************************************************************************** +# +#**************************************************************************************** + Added: trunk/fclient/src/fclient/lib/fcp2/client.py =================================================================== --- trunk/fclient/src/fclient/lib/fcp2/client.py (rev 0) +++ trunk/fclient/src/fclient/lib/fcp2/client.py 2008-07-07 21:32:00 UTC (rev 538) @@ -0,0 +1,2176 @@ +"""Fcp2 client implementation + +Compatibility: >= Freenet 0.7 Build #1107 + + +@newfield event: Event, Events +@newfield requestparam: RequestParam, RequestParams + +@note: The client implementation never uses or watches the global queue. No implementation +should ever do so. Global is evil. +@note: the client is not thread save. + + +Sample code. Connect to the freenet node:: + client = FcpClient() + nodeHello = client.connect() + if nodeHello is None: + pass + # something went wrong ..could not connect to the freenet node + else: + pass + # everything went well ..we are connected now + +Request data associated to a freenet key:: + myKey = client.key.key('CHK@ABCDE.......') + myRequestIdentifier = client.getData(myKey) + myRequest = c.getRequest(myIdentifier) + client.run() + print myRequest.data + +Usually you would connect handlers to client events to do processing or handle errors:: + def handleSuccess(event, request): + print 'Here is the data:', request.data + + def handleFailure(event, request): + print 'Too bad, something went wrong' + + client.events.RequestCompleted += handleSuccess + client.events.RequestFailed += handleFailure + myKey = client.key.key('CHK@ABCDE.......') + client.getData(myKey) + c.run() + + +Instead of calling run() you may run the client step by step:: + myKey = client.key.key('CHK@ABCDE.......') + client.getData(myKey) + for i in xrange(50): + client.next() + + +You may disconnect event handlers aswell:: + + client.events.RequestCompleted -= handleSuccess + client.events.RequestFailed -= handleFailure + + +Multiple event handlers may be connected / disconnected at once:: + + client.events += ( + (client.events.RequestCompleted, handleSuccess), + (client.events.RequestFailed, handleFailure) + ) + + +""" + +#Bug reports filed and open: +#-------------------------------------------------------------------------------------------------------------------------------------------- +# [0001931: Send EndListPersistentRequests following client connect] +# +# PendingRequests currently get lost if a.) the node goes down b.) if the client goes down unexpectedly. +# This affects IdentifierCollision + FilenameCollision + ClientPut when a SSK needs to be created first +# +# we can handle this case none short of maintaining a file keeping messages. But still there is the +# problem of knowing when the node has actually registered a request. The node does not send +# an EndListPersistentRequests on connect so it is impossible to tell when or if to restore one of +# the pending requests we stored. +# +#FIX: None +#--------------------------------------------------------------------------------------------------------------------------------------------- +# [0001893: CloseConnectionDuplicateClientName bug or feature?] +# +# CloseConnectionDuplicateClientName +# currently fcp takes down a our connection if another client (...) uses the same connection name. +# +#FIX: None +#---------------------------------------------------------------------------------------------------------------------------------------------- +# [0001888: explicite connection locale] +# +# Many strings are already translated by freenet, but there is no way to tell the node wich language +# to use to talk to a client. Maybe a good idea, maybe not. +# +#FIX: None +#----------------------------------------------------------------------------------------------------------------------------------------------- +# [0001781: unregister directories registered via TestDDARequest] +# +# With current state of the art DDA handling it is not possiblr to unregister directories (may pile +# up in memory over time). +# +#FIX: None +#------------------------------------------------------------------------------------------------------------------------------------------------ +# [0002019: Socket dies if first message is not ClientHello] +# +# minor one +# +#FIX: None +#------------------------------------------------------------------------------------------------------------------------------------------------- +# [0002015: Drop the global queue] +# +# this one is somewhat related to [0001931: Send EndListPersistentRequests following client connect] +# +# We never use or watch the global queue. It is to dangerous. But problems remain when it comes +# to restoring persistent requests. Shure these are our requests? Worst case is a client with a colliding +# connection name flooding our client with an unknown number of left overs. +# +#FIX: None (that is, this case is handled as savely as possible - except from possible slowdowns - but no +# guarantee that no unknown request may slip through) +#------------------------------------------------------------------------------------------------------------------------------------------------- +# [0001894: HandleCollision field in ClientGet] +# +# minor one. When downloading a file, filename collisions may occur. Fcp does not handle these very well +# It checks if the tempfile (filename ?) can be created newly when the request is started. IIRC In the final +# rename of the tempfile to filename no check is done and filename will get overwritten. +# +#FIX: we handle collisions in the client as savely as possible. But no guarantee either when a colliding file +# (...) finds his way into the download directory while downloading another. +#------------------------------------------------------------------------------------------------------------------------------------------------ +# [0002083: RemovePersistentRequest ignores unknown requests] +# +# minor one, but related to it a major one: you can not change the Priority of requests with +# Persistence=conncetion +# +#FIX: workaround for the "related" part +#------------------------------------------------------------------------------------------------------------------------------------------------ + # [0002200 - handle persistent and non-peristent request uniformly] +# +# removbe request is now handled uniformly in Fcp. modify request not yet. +# +#------------------------------------------------------------------------------------------------------------------------------------------------- +# [0002202: drop global persistents ] +# +# suggested dropping of global persistents. pretty dangerous and unhandy imo. +# +#FIX: at least some are implemented in the client +#-------------------------------------------------------------------------------------------------------------------------------------------------- + + + +# Todos +#------------------------------------------------------------------------------------------------------------------------------------------------ +# clean up +# +# x. move saveWriteFile and friends to a separate module +# +#------------------------------------------------------------------------------------------------------------------------------------------------ +# Fcp types vs. Python types +# +# x. Fcp seems to use kibibytes. Autoconvert to kilobytes? +# x. time intervals +# +#------------------------------------------------------------------------------------------------------------------------------------------------ +# logging +# +# x. should uris (...) always be visible in log output? Certainly in memory. Maybe a specialized +# "save" logger could be useful (like for user feedback). +# +#------------------------------------------------------------------------------------------------------------------------------------------------ +# runtime +# +# x. if the socket dies the client disconnects automatically, clearing all requests. +# No idea how to handle this. Would require at least an EndListPersistentRequest +# from the node to check wich requests arrived at the node ..and an auto resend +# requests the node does not know about. +# +#------------------------------------------------------------------------------------------------------------------------------------------------ +# request status +# +# x. have to set a dedicated flag when a request is about to be modified or removed +# Fcp gets confused if we disconnect emidiately after sending a modify or remove request +# Curretnly the RequestStatus.Completed flag is removed and later set again to get some +# control over the process. +# +# TODO: check if this is a bug in Fcp +# NOTE: seems to be fixed in [build 1112], fixes removed +#------------------------------------------------------------------------------------------------------------------------------------------------- + + + +# reminders to self +#------------------------------------------------------------------------------------------------------------------------------------------------ +# Key() +# +# we do not allow passing strings as uris. putting a CHK gets in the way here. would have to add another +# special case to handle 'CHK@myfilename' on input. so for uniformity reasons keys are enforced. +#------------------------------------------------------------------------------------------------------------------------------------------------ +# clientGet('USK@.../whatever/-1') +# +# will trigger a FetchError(PermanentRedirect) with the highest available version as RedirectURI +# we don't handle this automatically, cos it could be the desired result. maybe implement a flag +# someday to handle this +# +#------------------------------------------------------------------------------------------------------------------------------------------------ +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__)] + + +import os, sys + +import atexit +import copy +import logging +import random +import subprocess +import time + + +from . import consts +from . import config +from . import events +from . import message +from . import iohandler +from . import types +from . import key + +from .lib import namespace +from .lib import tools + + +__all__ = ['Client', ] +#************************************************************************************************* +# +#************************************************************************************************* +class Client(object): + """ + @cvar ExpectedFcpVersion: (float) minimum expected Freenet client protocol version + @cvar ExpectedNodeBuild: (int) minimum expected node build + @cvar DefaultFcpHost: (str) default Fcp host + @cvar DefaultFcpPort: (int) default Fcp port + @cvar MaxSizeKeyInfo: (bytes) maximum request size for key info requests + @cvar inimumRunTime: (seconds) minimum runtime when the L{run} method is called. + Required to make shure persistent requests can be taken up from the node. + + @ivar events: events the client supports + + + @todo: cvar MaxSizeKeyInfo. Check if required. + suggested by Mathew Toseland to use about 32k for mimeType requests + basic sizes of keys are: 1k for SSks and 32k for CHKs without MaxSize + DataFound will have DataLength set to 0 (?!) + + """ + ExpectedFcpVersion = 2.0 + ExpectedNodeBuild = 1153 + DefaultFcpHost = os.environ.get('FCP_HOST', '127.0.0.1') + DefaultFcpPort = int(os.environ.get('FCP_PORT', '9481')) + MaxSizeKeyInfo = 32768 + MinimumRunTime = 1 # FIX: 0001931 + + #consts = consts + #config = config + #message = message + #types = types + #key = key + + + def __init__(self, + connectionName=None, + debugVerbosity=None, + ): + """ + @param connectionName: name of the connection or None to use an arbitrary connection name + @param debugVerbosity: verbosity level for debugging. Default is L{consts.ConstDebugVerbosity.Warning} + + """ + self._connectionName = self.setConnectionName(connectionName) + self._ddaTests = [] # currently running DDA tests (request0, ... requestN) + self._nodeHelloMessage = None + self._requests = {} # currently running requests (requestIdentifier --> request) + + self.events = events.Events() + self.ioHandler = iohandler.IOHandler() + + for event in self.events: + event += self._captureEvent + self.setDebugVerbosity(consts.ConstDebugVerbosity.Warning if debugVerbosity is None else debugVerbosity) + atexit.register(self.close) + + ############################################################### + ## + ## private methods + ## + ############################################################### + def _captureEvent(self, event, request): + if event == self.events.Idle: + consts.ConstLogger.Event.log(consts.ConstDebugVerbosity.Chatty, consts.ConstLogMessages.EventTriggered + event.name) + else: + consts.ConstLogger.Event.info(consts.ConstLogMessages.EventTriggered + event.name) + + + def _close(self, msg): + """Closes the client + @param msg: message to pass to the ClientDisconnected event or None to not inform listeners + + @todo: complain if the client is already closed? + @todo: trigger ClientDisconnected() if the client is already closed? should be yes. otherwise + we'd have to distinguish between intentional and unintentional closing like on a broken io + """ + consts.ConstLogger.Client.info(consts.ConstLogMessages.Closing) + + # clean left over DDA test tmp files + for initialRequest in self._ddaTests: + if initialRequest['TestDDA'].get('TmpFile', None) is not None: + tools.saveRemoveFile(initialRequest['TestDDA']['TmpFile']) + + self._ddaTests = [] + self._requests = {} + + if msg is not None: + self.events.ClientDisconnected(msg) + if self.ioHandler.isOpen(): + self.ioHandler.close() + + + def _finalizeRequest(self, msg, request, event): + """Finalzes a request + @param msg: message that is the reason for finalizing + @param request: request to finalize + @param event: event to trigger or None + + @note: this method sets the requests L{consts.ConstRequestStatus.RemovedFromQueue} and + L{consts.ConstRequestStatus.Completed} flags accordingly + @note: Fcp removes Get / Put requests with Persistence == connection emidiately + from its queue. Same goes all requests on ProtocolError. We inform the caller + that the request has been completed and remove it fom our queue if necessary. + Non Get / Put requests will be removed in any case. + """ + removeRequest = msg == message.MsgProtocolError or msg == message.MsgPersistentRequestRemoved # TODO: PersistentRequestRemoved??? + if not removeRequest: + #NOTE: non Get / Put related requests do not have a Persistence param + removeRequest = request.params.get('Persistence', consts.ConstPersistence.Connection) == consts.ConstPersistence.Connection + if removeRequest: + request['RequestStatus'] |= consts.ConstRequestStatus.RemovedFromQueue + + request['RequestStatus'] |= consts.ConstRequestStatus.Completed + if event is not None: + event(request) + + if removeRequest: + del self._requests[request['Identifier']] + + + def _registerRequest(self, + msg, + requestType, + userData=None, + identifier=None, + initTime=None, + persistentUserData='', + filenameCollision=consts.ConstFilenameCollision.HandleNever, + ): + """Registers a request + @param msg: message to register + @param requestType: (L{consts.ConstRequestType}) type of request to register + @param filenameCollision: (L{consts.ConstFilenameCollision}) how to handle filename collisions. + Default is L{consts.ConstFilenameCollision.HandleNever} + @param identifier: (str) identifier of the request or None to create a new one + @param initTime: (int) init time of the request or None to set it to now + @param persistentUserData: (str) anyuser defined persistent data + @param userData: (any) any user defined non persistent data + + @return: (str) identifer of therequest + @note: the identifier returned is unique to the client but may not be unique to the node + """ + identifier = self.newIdentifier(identifiers=self._requests) if identifier is None else identifier + + # equip requests with some additional params + + #TODO: keep an eye on additional params, they may collide with Fcp parameters + msg['Identifier'] = self.newIdentifier(identifiers=self._requests) if identifier is None else identifier + msg['RequestType'] = requestType + msg['InitTime'] = time.time() if initTime is None else initTime + if requestType & consts.ConstRequestType.MaskGet: + msg['FilenameCollision'] = filenameCollision + msg['UserData'] = userData + msg['PersistentUserData'] = persistentUserData + msg['ClientToken'] = '' + msg.updatePersistentParams() + + elif requestType & consts.ConstRequestType.MaskPut: + msg['UserData'] = userData + msg['PersistentUserData'] = persistentUserData + msg['ClientToken'] = '' + msg.updatePersistentParams() + + elif requestType & consts.ConstRequestType.MaskGenerateKeypair: + pass + elif requestType & consts.ConstRequestType.SubscribeUSK: + msg['UserData'] = userData + elif requestType & consts.ConstRequestType.PluginInfo: + pass + else: + raise ValueError('Can not register request: ' + msg.name) + + self._requests[identifier] = msg + + ############################################################### + ## + ## connection related methods + ## + ############################################################### + def close(self): + """Closes the client + @note: make shure to call close() when done with the client + """ + msg = message.MsgClientDisconnected( + DisconnectReason=consts.ConstDisconnectReason.Close, + ) + self._close(msg) + + + def closeNode(self): + """Shuts down the freenet node""" + self.sendMessage(message.MsgShutdown()) + + + def connect(self, host=DefaultFcpHost, port=DefaultFcpPort, duration=20, timeout=0.5): + """Connects to the freenet node + @param host: (str) host of th node + @param port: (int) port of the node + @param duration: (int) how many seconds try to connect before giving up + @param timeout: (int) how much time to wait before another attempt to connect + + @return: (L{message.MsgNodeHello}) or None if no connection could be established + """ + nodeHello = None + for nodeHello in self.iterConnect(host=host, port=port, duration=duration, timeout=timeout): + pass + return nodeHello + + + def isOpen(self): + """Checks if the clients connection is open + @return: (bool) True if so, False otherwise + """ + return self.ioHandler.isOpen() + + + def iterConnect(self, host=DefaultFcpHost, port=DefaultFcpPort, duration=20, timeout=0.5): + """Iterator to stablish a connection to a freenet node + @param host: (str) host of th node + @param port: (int) port of the node + @param duration: (int) how many seconds try to connect before giving up + @param timeout: (int) how much time to wait before another attempt to connect + + @return: (L{message.MsgNodeHello}) if successful, None otherwise for the next iteration + + @event: ClientConnected(event, message) is triggered as soon as the client is connected + """ + + #TODO: we have to yield a few round here to make NodeHello injection work in unittests + # no idea exactly how many... + if self.ioHandler.isOpen(): + disconnectMsg = message.MsgClientDisconnected( + DisconnectReason=consts.ConstDisconnectReason.Reconnect, + ) + self._close(disconnectMsg) + + disconnectReason = consts.ConstDisconnectReason.IOConnectFailed + t0 = time.time() + for result in self.ioHandler.iterConnect(duration=duration, timeout=timeout, host=host, port=port): + yield None + + # try to get handshake + timeElapsed = time.time() - t0 + if result: + self.sendMessage( + message.MsgClientHello( + Name=self._connectionName, + ExpectedVersion=self.ExpectedFcpVersion, + ) + ) + + while timeElapsed <= duration: + yield None + msg = self.next(dispatch=False) + if msg == message.MsgClientSocketTimeout: + disconnectReason = consts.ConstDisconnectReason.NoNodeHello + timeElapsed += max(self.ioHandler.io.Timeout, 0.1) + yield None + elif msg == message.MsgNodeHello: + self._nodeHelloMessage = msg + # check if version is ok + if self.versionCheckNodeHello(msg): + self.events.ClientConnected(msg) + yield self._nodeHelloMessage + raise StopIteration + else: + disconnectReason = consts.ConstDisconnectReason.VersionMissmatch + break + else: + disconnectReason = consts.ConstDisconnectReason.UnknownNodeHello + break + + disconnectMsg = message.MsgClientDisconnected( + DisconnectReason=disconnectReason, + ) + self._close(disconnectMsg) + raise StopIteration + + + def getConnectionName(self): + """Returns the connection name used by the client + @return: (str) connection name + """ + return self._connectionName + + + def setConnectionName(self, connectionName=None): + """Sets the connection name to be used by the client + @param connectionName: (str) connection name or None to use an arbitrary connection name + @return: (str) connection name + """ + self._connectionName = self.newIdentifier() if connectionName is None else connectionName + return self._connectionName + + + def getDebugVerbosity(self): + """Returns the current verbosity level of the client + @return: L{consts.ConstDebugVerbosity} + """ + return consts.ConstLogger.Client.getEffectiveLevel() + + + def setDebugVerbosity(self, debugVerbosity): + """Sets the verbosity level of the client + @param debugVerbosity: L{consts.ConstDebugVerbosity} + """ + consts.ConstLogger.Client.setLevel(debugVerbosity) + + + def newIdentifier(self, identifiers=None): + """Creates a new identifier to be used as request identifer or whatever + @param identifiers: if desired any iterable containing identifiers to enshure the identifier is unique within the iterable + @return: (str) identifier + + """ + identifier = str(hex(random.getrandbits(128))) + if identifiers is not None: + while identifier in identifiers: + identifier = str(hex(random.getrandbits(128))) + return identifier + + + def startNode(self, cmdline): + """Starts the freenet node + @param cmdline: commandline to start freenet (like '/freenet/run.sh start' or 'c:\freenet\start.bat') + @return: (str) whatever freenet returns + + @todo: on windows it may be necessary to hide the command window + """ + p = subprocess.Popen( + args=cmdline, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + stdout, stderr = p.communicate() + return stdout + + + def versionCheckNodeHello(self, nodeHelloMessage): + """Performa a version check of the client against the specified NodeHello message + @return: (bool) True if version is ok, False otherwise + @note: this implementation checks for FCPVersion == L{ExpectedFcpVersion} + and a Build >= L{ExpectedNodeBuild} + """ + if nodeHelloMessage['FCPVersion'] == self.ExpectedFcpVersion: + if nodeHelloMessage['Build'] >= self.ExpectedNodeBuild: + return True + return False + + ######################################################### + ## + ## runtime related methods + ## + ######################################################### + def handleMessage(self, msg): + """Handles a message from the freenet node + @param msg: (Message) to handle + @return: True if the message was handled, False otherwise + """ + + CancelPersistentRequests = 0 # for testing... if True, cancels all PersistentRequests + + # check if we have an initial request corrosponding to msg + requestIdentifier = msg.get('Identifier', None) + initialRequest = None if requestIdentifier is None else self._requests.get(requestIdentifier, None) + #################################################### + ## + ## errors + ## + #################################################### + if msg == message.MsgIdentifierCollision: + if initialRequest is None: + self.events.IdentifierCollision(msg) + return False + + # resend request with new identifier + newIdentifier = self.newIdentifier(identifiers=self._requests) + self._requests[newIdentifier] = initialRequest + del self._requests[requestIdentifier] + initialRequest['Identifier'] = newIdentifier + initialRequest['Modified'] = {consts.ConstRequestModified.Identifier: requestIdentifier} + self.events.RequestModified(initialRequest) + self.sendMessage(initialRequest) + return True + + + elif msg == message.MsgProtocolError: + code = msg['Code'] + if code == consts.ConstProtocolError.ShuttingDown: + disconnectMsg = message.MsgClientDisconnected( + DisconnectReason=consts.ConstDisconnectReason.NodeClosing, + ) + self._close(disconnectMsg) + return True + + + if requestIdentifier is None: + self.events.ProtocolError(msg) + return True + + if initialRequest is None: + self.events.ProtocolError(msg) + return False + + # handle DDA errors + elif code == consts.ConstProtocolError.DDADenied: + ddaRequestMsg = message.MsgTestDDARequest() + if initialRequest == message.MsgClientGet: + ddaRequestMsg['WantWriteDirectory'] = True + directory = os.path.dirname(initialRequest['Filename']) + else: + ddaRequestMsg['WantReadDirectory'] = True + directory = os.path.dirname(initialRequest['Filename']) + ddaRequestMsg['Directory'] = directory + + # add params required for testing + initialRequest['TestDDA'] = { + 'Directory': directory, + 'Replied': False, + 'TmpFile': None, + 'WantWrite': ddaRequestMsg.get('WantWriteDirectory', False), + 'ErrorMsg': msg, + } + self._ddaTests.append(initialRequest) + self.sendMessage(ddaRequestMsg) + return True + + + # handle filename collisions + elif code == consts.ConstProtocolError.DiskTargetExists: + handleCollision = initialRequest.get('FilenameCollision', consts.ConstFilenameCollision.HandleNever) + collisionHandled = bool(handleCollision & consts.ConstFilenameCollision.CollisionHandled) + + # rename filename + if handleCollision & consts.ConstFilenameCollision.HandleRename: + filename = initialRequest['Filename'] + initialRequest['FilenameCollision'] |= consts.ConstFilenameCollision.CollisionHandled + newFilename = namespace.unique_filename(filename, extensions=1, ispostfixed=collisionHandled) + initialRequest['Filename'] = newFilename + initialRequest['Modified'] = {consts.ConstRequestModified.Filename: filename} + self.sendMessage(initialRequest) + self.events.RequestModified(initialRequest) + return True + + # don't handle + else: + initialRequest['FilenameCollision'] &= ~consts.ConstFilenameCollision.CollisionHandled + + + # handle plugin related request failures + elif code == consts.ConstProtocolError.NoSuchPlugin or code == consts.ConstProtocolError.AccessDenied: + if initialRequest == message.MsgGetPluginInfo: + initialRequest['ErrorMessage'] = msg + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Error + self._finalizeRequest(msg, initialRequest, self.events.PluginInfoFailed) + return True + + # only requests should get through to here + + # NOTE: Fcp already removed the request + initialRequest['ErrorMessage'] = msg + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Error + self._finalizeRequest(msg, initialRequest, self.events.RequestFailed) + return True + + + #################################################### + ## + ## TestDDA + ## + ## We assume that a DDATest messages do not get mixed up. 1st TestDDARequest is first to + ## enter TestDDAReply and TestDDAComplete. Hopefuly the freenet devels will rework the + ## TestDDA drill. + ## + #################################################### + elif msg == message.MsgTestDDAReply: + directory = msg['Directory'] + + # find message that triggered the call + for initialRequest in self._ddaTests: + if initialRequest['TestDDA']['Directory'] == directory: + if not initialRequest['TestDDA']['Replied']: + initialRequest['TestDDA']['Replied'] = True + break + else: + # fell through + raise ValueError('No inital message found in TestDDAReply') + + # perform read test if necessary + fpathRead = msg.params.get('ReadFilename', None) + readContent = '' + if fpathRead is not None: + readContent = tools.saveReadFile(fpathRead) + if readContent is None: + readContent = '' + + # perform write test if necessary + fpathWrite = msg.params.get('WriteFilename', None) + if fpathWrite is not None: + written = tools.saveWriteFile(fpathWrite, msg['ContentToWrite']) + if not written: + tools.saveRemoveFile(fpathWrite) + else: + initialRequest['TestDDA']['TmpFile'] = fpathWrite + + self.sendMessage( + message.MsgTestDDAResponse( + Directory=msg['Directory'], + ReadContent=readContent, + ) + ) + return True + + + elif msg == message.MsgTestDDAComplete: + # clean up tmp file + directory = msg['Directory'] + + # find message that triggered the call + for initialRequest in self._ddaTests: + if initialRequest['TestDDA']['Directory'] == directory: + if initialRequest['TestDDA']['Replied']: + break + else: + # fell through + raise ValueError('No initial message found in TestDDAComplete') + + # remove test and clean tmp data + #TODO: reset TestDDA params or not? + self._ddaTests.remove(initialRequest) + if initialRequest['TestDDA']['TmpFile'] is not None: + tools.saveRemoveFile(initialRequest['TestDDA']['TmpFile']) + wantWrite = initialRequest.params['TestDDA']['WantWrite'] + + # check if test was sucessful + testFailed = False + if wantWrite: + testFailed = not msg.params.get('WriteDirectoryAllowed', False) + else: + testFailed = not msg.params.get('ReadDirectoryAllowed', False) + + if testFailed: + initialRequest['RequestStatus'] = consts.ConstRequestStatus.Error + initialRequest['ErrorMessage'] = initialRequest['TestDDA']['ErrorMsg'] + self._finalizeRequest(msg, initialRequest, self.events.RequestFailed) + return True + + # else: resend message + self.sendMessage(initialRequest) + return True + + #################################################### + ## + ## config related + ## + #################################################### + elif msg == message.MsgConfigData: + self.events.ConfigData(msg) + return True + + elif msg == message.MsgNodeData: + self.events.NodeData(msg) + return True + + #################################################### + ## + ## get / put related + ## + #################################################### + elif msg == message.MsgAllData: + if initialRequest is None: + return False + + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Success + initialRequest.data = msg.data + self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted) + return True + + elif msg == message.MsgDataFound: + if initialRequest is None: + return False + + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Success + initialRequest['MetadataContentType'] = msg.get('Metadata.ContentType', '') + initialRequest['MetadataSize'] = msg.get('DataLength', '') + + # except from GetData all requests are complete here. Next GetData will run through AllData... + + # For GetData with persistence != connection the node sends no All Data message + # whatever that is good for ..fix this here to get all GetData request to complete on + # All Data. + if initialRequest['RequestType'] == consts.ConstRequestType.GetData: + if initialRequest['Persistence'] != consts.ConstPersistence.Connection: + self.sendMessage( + message.MsgGetRequestStatus( + Identifier=initialRequest['Identifier'], + Global=False, + OnlyData=True + ) + ) + else: + self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted) + + return True + + + elif msg == message.MsgGetFailed: + if initialRequest is None: + return False + + code = msg['Code'] + if code == consts.ConstFetchError.Canceled: + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Removed | \ + consts.ConstRequestStatus.Completed | \ + consts.ConstRequestStatus.RemovedFromQueue + del self._requests[requestIdentifier] + self.events.RequestRemoved(initialRequest) + return True + + # check if it is one of our requests for key information + if code == consts.ConstFetchError.TooBig and initialRequest['RequestType'] == consts.ConstRequestType.GetKeyInfo: + initialRequest['MetadataContentType'] = msg.get('ExpectedMetadata.ContentType', '') + initialRequest['DataLength'] = msg.get('ExpectedDataLength', -1) + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Success + self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted) + else: + initialRequest['ErrorMessage'] = msg + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Error + self._finalizeRequest(msg, initialRequest, self.events.RequestFailed) + return True + + + elif msg == message.MsgPersistentGet or msg == message.MsgPersistentPut or msg == message.MsgPersistentPutDir: + + # unknown request... try to restore it + if initialRequest is None: + if CancelPersistentRequests: + self.sendMessage( + message.MsgRemoveRequest( + Identifier=msg['Identifier'], + Global=msg['Global'], + ) + ) + return True + + requestType = msg['RequestType'] + if msg == message.MsgPersistentGet: + initialRequest = message.MsgClientGet() + elif msg == message.MsgPersistentPut: + initialRequest = message.MsgClientPut() + else: + #NOTE: PutDiskDir is just a subtype of PutComplexDir. check PutDirType param to tell appart + initialRequest = message.MsgClientPutComplexDir() + + initialRequest.params.update(msg.params) + self._requests[initialRequest['Identifier']] = initialRequest + + #FIX: remove Started param from PersistentGet / Put, not interesting + if 'Started' in initialRequest.params: + del initialRequest.params['Started'] + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Restored + self.events.RequestRestored(initialRequest) + return True + + #TODO: ignore handshake? + return False + + + elif msg == message.MsgPersistentRequestModified: + if initialRequest is None: + return False + + modified = {} + + # check if PersistentUserData has changed + clientToken = msg.get('ClientToken', None) + if clientToken is not None: + modified[consts.ConstRequestModified.PersistentUserData] = None + + #TODO: its more or less a guess that PersistentUserData has changed + # ...as long as no other param is changed at runtime we are ok + # otherwise we would have to set flags to indicate wich member + # of ClientToken changed. See --> modifyRequest() + # + # hmm ..thinking again, this would only work if we could make shure + # PersistentUserData can only be modified through modifyRequest(). + # So no way. + + #TODO: ??? try ...except + initialRequest._restoreParams(msg.params) + + # check if PriorityClass has changed + priorityClass = msg.get('PriorityClass', None) + if priorityClass is not None: + modified[consts.ConstRequestModified.PriorityClass] = None + initialRequest['PriorityClass'] = priorityClass + + initialRequest['Modified'] = modified + self.events.RequestModified(initialRequest) + return True + + #NOTE: fcp sends a GetFailed / PutFailed if the request was still running (code=canceled) + elif msg == message.MsgPersistentRequestRemoved: + if initialRequest is None: + return False + + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Removed | consts.ConstRequestStatus.Completed | consts.ConstRequestStatus.RemovedFromQueue + del self._requests[requestIdentifier] + self.events.RequestRemoved(initialRequest) + return True + + elif msg == message.MsgSimpleProgress: + if initialRequest is None: + return False + + initialRequest['ProgressTotal'] = msg['Total'] + initialRequest['ProgressRequired'] = msg['Required'] + initialRequest['ProgressFailed'] = msg['Failed'] + initialRequest['ProgressFatalyFailed'] = msg['FatallyFailed'] + initialRequest['ProgressSucceeded'] = msg['Succeeded'] + self.events.RequestProgress(initialRequest) + return True + + ## put related + + elif msg == message.MsgPutFailed: + if initialRequest is None: + return False + + code = msg['Code'] + if code == consts.ConstInsertError.Canceled: + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Removed | consts.ConstRequestStatus.Completed | consts.ConstRequestStatus.RemovedFromQueue + del self._requests[requestIdentifier] + self.events.RequestRemoved(initialRequest) + return True + + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Error + initialRequest['ErrorMessage'] = msg + self._finalizeRequest(msg, initialRequest, self.events.RequestFailed) + return True + + + elif msg == message.MsgPutFetchable: + if initialRequest is None: + # something went wrong + return False + + self.events.RequestFetchable(initialRequest) + return True + + + elif msg == message.MsgPutSuccessful: + if initialRequest is None: + return False + # TODO: StartupTime and CompletionTime are passed, but + # as long as no corrosponding params are passed in DataFound + # we ignore them + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Success + initialRequest['URI'] = msg['URI'] + self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted) + return True + + + elif msg == message.MsgURIGenerated: + if initialRequest is None: + return False + initialRequest['URI'] = msg['URI'] + return True + + elif msg == message.MsgFinishedCompression: + if initialRequest is None: + return False + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Compressed + self.events.RequestCompressionCompleted(initialRequest) + return True + + elif msg == message.MsgStartedCompression: + if initialRequest is None: + return False + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Compressing + self.events.RequestCompressionStarted(initialRequest) + return True + + #################################################### + ## + ## Peer related messages + ## + #################################################### + elif msg == message.MsgEndListPeers: + self.events.EndListPeers(msg) + return True + + elif msg == message.MsgEndListPeerNotes: + self.events.EndListPeerNotes(msg.params) + return True + + elif msg == message.MsgPeer: + self.events.Peer(msg) + return True + + elif msg == message.MsgPeerNote: + self.events.PeerNote(msg) + return True + + elif msg == message.MsgPeerRemoved: + self.events.PeerRemoved(msg) + return True + + elif msg == message.MsgUnknownNodeIdentifier: + self.events.PeerUnknown(msg) + return True + + elif msg == message.MsgUnknownPeerNoteType: + self.events.PeerNoteTypeUnknown(msg) + return True + #################################################### + ## + ## plugins + ## + #################################################### + elif msg == message.MsgPluginInfo: + if initialRequest is None: + return False + + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Success + self._finalizeRequest(msg, initialRequest, self.events.PluginInfo) + return True + + elif msg == message.MsgFCPPluginReply: + self.events.PluginMessage(msg) + return True + + #################################################### + ## + ## others + ## + #################################################### + elif msg == message.MsgCloseConnectionDuplicateClientName: + disconnectMsg = message.MsgClientDisconnected( + DisconnectReason=consts.ConstDisconnectReason.DuplicateClientName, + ) + self._close(disconnectMsg) + return True + + + elif msg == message.MsgSSKKeypair: + if initialRequest is None: + return False + + insertURI = msg['InsertURI'] + requestURI = msg['RequestURI'] + + if initialRequest['RequestType'] == consts.ConstRequestType.GenerateUSKKeypair: + insertURI = key.KeyUSK(insertURI.keyData, docName=insertURI.docName) + insertURI = key.KeyUSK(insertURI.keyData, docName=insertURI.docName) + requestURI = key.KeyUSK(requestURI.keyData, docName=requestURI.docName) + initialRequest['InsertURI'] = insertURI + initialRequest['RequestURI'] = requestURI + initialRequest['RequestStatus'] |= consts.ConstRequestStatus.Success + self._finalizeRequest(msg, initialRequest, self.events.KeypairGenerated) + return True + + elif msg == message.MsgSubscribedUSKUpdate: + if initialRequest is None: + return False + + initialRequest['Edition'] =msg['Edition'] + self.events.USKUpdated(initialRequest) + return True + + + # default + return False + + + def next(self, dispatch=True): + """Pumps the next message waiting + @param dispatch: if True the message is dispatched to L{handleMessage} + @note: use this method to run the client step by step. If you want to run the + client unconditionally use L{run} + """ + + #FIX: [0002083] we may run into persistents of other clients by accident. the client can not handle them. + # so remove them, no matter what.... + def hackyInvalidMessageCallback(msg, requests=self._requests): + if msg == message.MsgPersistentGet or msg == message.MsgPersistentPut or msg == message.MsgPersistentPutDir: + requestIdentifier = msg['Identifier'] + if requestIdentifier not in requests: + msgRemove = message.MsgRemoveRequest(Identifier=msg['Identifier'], Global=msg['Global']) + self.sendMessage(msgRemove) + + try: + msg = self.ioHandler.readMessage(hackyInvalidMessageCallback=hackyInvalidMessageCallback) + except consts.ErrorIOTimeout, details: + msg = message.MsgClientSocketTimeout() + if dispatch: + self.events.Idle(msg) + except consts.ErrorIOBroken, details: + msg = message.MsgClientDisconnected( + DisconnectReason=consts.ConstDisconnectReason.ConnectionDied, + ) + self._close(msg) + raise consts.ErrorIOBroken(details) + else: + if dispatch: + self.handleMessage(msg) + return msg + + + def run(self): + """Runs the client unconditionally untill all requests have completed + @note: a KeyboardInterrupt will stop the client + """ + + #FIX: 0001931 + # poll a few times to see if there are persistent requests waiting + t0 = time.time() + while time.time() - t0 <= self.MinimumRunTime: + try: + msg = self.next() + except KeyboardInterrupt: + consts.ConstLogger.Client.info(consts.ConstLogMessages.KeyboardInterrupt) + return + if msg == message.MsgClientSocketDied: + return + + #n = 0 + while True: + #n += 1 + #if n > 50: break + + # check if we have running requests. Assert False + haveRunningRequests = False + for request in self._requests.values(): + if not request['RequestStatus'] & consts.ConstRequestStatus.Completed: + haveRunningRequests = True + break + + if not haveRunningRequests: + consts.ConstLogger.Client.info(consts.ConstLogMessages.AllRequestsCompleted) + break + + try: + msg = self.next() + except KeyboardInterrupt: + sconsts.ConstLogger.Client.info(consts.ConstLogMessages.KeyboardInterrupt) + break + + if msg == message.MsgClientSocketDied: + break + + + def sendMessage(self, msg): + """Sends a message to freenet + @param msg: (L{message._MessageBase}) message to send + @return: always None + + @note: If an error occurs the client is closed + @note: you can use this method to send a message to the node, bypassing all + track keeping methods of the client + """ + + # Reminder to self: + # + # if socket dies on sendall there is no way to determine if and how much data was send + # ...so assume data was send + try: + self.ioHandler.sendMessage(msg) + except consts.ErrorIOBroken, details: + errorMsg = message.MsgClientDisconnected( + DisconnectReason=consts.ConstDisconnectReason.ConnectionDied, + ) + self._close(errorMsg) + raise consts.ErrorIOBroken(details) + + ######################################################### + ## + ## config related methods + ## + ######################################################### + def getConfig(self, + withCurrent=True, + withDefaults=True, + withExpertFlag=True, + withForceWriteFlag=True, + withSortOrder=True, + withShortDescription=True, + withLongDescription=True, + withDataTypes=True, + ): + """ + @event: ConfigData(event, msg) + """ + self.sendMessage( + message.MsgGetConfig( + WithSortOrder=withSortOrder, + WithCurrent=withCurrent, + WithDefaults=withDefaults, + WithExpertFlag=withExpertFlag, + WithForceWriteFlag=withForceWriteFlag, + WithShortDescription=withShortDescription, + WithLongDescription=withLongDescription, + WithDataTypes=withDataTypes, + ) + ) + + + def modifyConfig(self, params): + """Modifies node configuration values + @param params: (dict) containing parameters to modify + """ + msg = message.MsgModifyConfig() + msg.params = params + self.sendMessage(msg) + + ######################################################## + ## + ## ClientGet related methods + ## + ######################################################## + def clientGet(self, + uri, + requestType, + userData, + persistentUserData, + filenameCollision, + **messageParams + ): + """Requests a key from the node + @param uri: (L{key._KeyBase}) key to request + @param requestType: (L{consts.ConstRequestType}) sub type of the message + @param userData: any non persistent data to associate to the request or None + @param persistentUserData: any string to associate to the request as persistent data or None + @param filenameCollision: what to do if the disk target alreaady exists. One of the FilenameCollision.* consts + @param messageParams: keyword arguments to pass along with the ClientGet message (uppercase first letter!!). + If the value of a keyword is None, it is ignored. + + @return: (str) request identifier + """ + msg = message.MsgClientGet(URI=uri) + for paramName, value in messageParams.items(): + if value is not None: + msg[paramName] = value + + self._registerRequest( + msg, + requestType, + filenameCollision=filenameCollision, + persistentUserData=persistentUserData, + userData=userData, + ) + self.sendMessage(msg) + return msg['Identifier'] + + + def getData(self, + uri, + + allowedMimeTypes=None, + binaryBlob=False, + dsOnly=False, + ignoreDS=False, + maxRetries=None, + maxSize=None, + persistence=consts.ConstPersistence.Connection, + priorityClass=consts.ConstPriority.Medium, + + userData=None, + persistentUserData='', + ): + """Requests datae from the node + + @param uri: (L{key._KeyBase}) key to request + + @param allowedMimeTypes: (str) list of allowed mime types + @param binaryBlob: (bool) if True, the file is retrieved as binary blob file + @param dsOnly: (bool) if True, retrieves the file from the local data store only + @param ignoreDS: (bool) if True, ignores the local data store + @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide + @param maxSize: (int) maximum size of the file in bytes or None to set no limited + @param persistence: (L{consts.ConstPersistence}) persistence of the request + @param priorityClass: (L{consts.ConstPriority}) priority of the request + @param userData: any non persistent data to associate to the request + @param persistentUserData: any string to associate to the request as persistent data + + @return: (str) request identifier + + @event: L{events.Events.RequestCompleted} triggered as soon as the request is complete + @event: L{events.Events.RequestFailed} triggered if the request failes + @event: L{events.Events.RequestModified} trigggered if the request identifi... [truncated message content] |
From: <jU...@us...> - 2008-07-07 21:33:37
|
Revision: 539 http://fclient.svn.sourceforge.net/fclient/?rev=539&view=rev Author: jUrner Date: 2008-07-07 14:33:45 -0700 (Mon, 07 Jul 2008) Log Message: ----------- sarted working on fclient again Added Paths: ----------- trunk/fclient/src/fclient/PrefsGlobalTpl.ui trunk/fclient/src/fclient/Ui_Prefs.py trunk/fclient/src/fclient/Ui_PrefsGlobal.py trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py trunk/fclient/src/fclient/__init__.py trunk/fclient/src/fclient/config.py trunk/fclient/src/fclient/fclient.py Added: trunk/fclient/src/fclient/PrefsGlobalTpl.ui =================================================================== --- trunk/fclient/src/fclient/PrefsGlobalTpl.ui (rev 0) +++ trunk/fclient/src/fclient/PrefsGlobalTpl.ui 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1,64 @@ +<ui version="4.0" > + <class>PrefsGlobalTpl</class> + <widget class="QWidget" name="PrefsGlobalTpl" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>465</width> + <height>247</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0" > + <layout class="QHBoxLayout" > + <item> + <widget class="QCheckBox" name="ckStoreSettingsLocally" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="edStoreSettingsLocally" /> + </item> + <item> + <widget class="QPushButton" name="btStoreSettingsLocally" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> Added: trunk/fclient/src/fclient/Ui_Prefs.py =================================================================== --- trunk/fclient/src/fclient/Ui_Prefs.py (rev 0) +++ trunk/fclient/src/fclient/Ui_Prefs.py 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1,69 @@ +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 QtGui + +from .lib.qt4ex.dlgs import dlgpreferences +from .Ui_PrefsGlobal import PrefsPageGlobal +#********************************************************************************** +# +#********************************************************************************** +#*********************************************************************** +# +#*********************************************************************** +class PrefsPageRoot(dlgpreferences.Page): + + UUID = '{a61e2758-4c66-11dd-a3e6-8814a37cbeed}' + + def __init__(self): + dlgpreferences.Page.__init__(self, self.UUID) + self._widget = None + self.setDirty(True) + + def displayName(self): + return QtGui.QApplication.translate("PreferencesGlobal", 'All', None, QtGui.QApplication.UnicodeUTF8) + + def canApply(self): return False + def canHelp(self): return False + + def setVisible(self, parent, flag): + createdNew = False + if flag and self._widget is None: + createdNew = True + self._widget = QtGui.QWidget(parent) + self._widget.setVisible(flag) + return (createdNew, self._widget) + +#********************************************************************************** +# +#********************************************************************************** +class DlgPrefs(dlgpreferences.DlgPreferencesFlatTree): + + def __init__(self, parent): + + pages = PrefsPageRoot()( + PrefsPageGlobal() + ) + + dlgpreferences.DlgPreferencesFlatTree.__init__(self, + parent, + pages=pages, + startPage=PrefsPageGlobal.UUID, + ) + + +#********************************************************************************** +# +#********************************************************************************** +if __name__ == '__main__': + import sys + + app = QtGui.QApplication(sys.argv) + w = DlgPrefs(None) + w.show() + res = app.exec_() + sys.exit(res) + + Added: trunk/fclient/src/fclient/Ui_PrefsGlobal.py =================================================================== --- trunk/fclient/src/fclient/Ui_PrefsGlobal.py (rev 0) +++ trunk/fclient/src/fclient/Ui_PrefsGlobal.py 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1,66 @@ + +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 QtGui + +from . import config +from .lib.qt4ex.dlgs import dlgpreferences + +from .Ui_PrefsGlobalTpl import Ui_PrefsGlobalTpl +#********************************************************************************** +# +#********************************************************************************** +class PrefsWidgetGlobal(QtGui.QWidget, Ui_PrefsGlobalTpl): + + def __init__(self, parent, cfg=None): + QtGui.QWidget.__init__(self, parent) + + + self.cfg = config.Config(self) if cfg is None else cfg + + + self.setupUi(self) +#*********************************************************************** +# +#*********************************************************************** +class PrefsPageGlobal(dlgpreferences.Page): + + UUID = '{ba654bd8-4c63-11dd-b8b1-a11c9b5c3981}' + + def __init__(self): + dlgpreferences.Page.__init__(self, self.UUID) + self._widget = None + self.setDirty(True) + + def displayName(self): + return QtGui.QApplication.translate("PreferencesGlobal", 'Global', None, QtGui.QApplication.UnicodeUTF8) + + def canApply(self): return True + def canHelp(self): return True + + def setVisible(self, parent, flag): + createdNew = False + if flag and self._widget is None: + createdNew = True + self._widget = PrefsWidgetGlobal(parent) + self._widget.setVisible(flag) + return (createdNew, self._widget) + + + +#*********************************************************************** +# +#*********************************************************************** +if __name__ == '__main__': + from PyQt4 import QtGui + import sys + + app = QtGui.QApplication(sys.argv) + w = PrefsWidgetGlobal(None) + w.show() + res = app.exec_() + sys.exit(res) + Added: trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py =================================================================== --- trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py (rev 0) +++ trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/PrefsGlobalTpl.ui' +# +# Created: Mon Jul 7 23:23:43 2008 +# by: PyQt4 UI code generator 4.3.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_PrefsGlobalTpl(object): + def setupUi(self, PrefsGlobalTpl): + PrefsGlobalTpl.setObjectName("PrefsGlobalTpl") + PrefsGlobalTpl.resize(QtCore.QSize(QtCore.QRect(0,0,465,247).size()).expandedTo(PrefsGlobalTpl.minimumSizeHint())) + + self.gridlayout = QtGui.QGridLayout(PrefsGlobalTpl) + self.gridlayout.setObjectName("gridlayout") + + self.label = QtGui.QLabel(PrefsGlobalTpl) + self.label.setWordWrap(True) + self.label.setObjectName("label") + self.gridlayout.addWidget(self.label,0,0,1,1) + + self.hboxlayout = QtGui.QHBoxLayout() + self.hboxlayout.setObjectName("hboxlayout") + + self.ckStoreSettingsLocally = QtGui.QCheckBox(PrefsGlobalTpl) + self.ckStoreSettingsLocally.setObjectName("ckStoreSettingsLocally") + self.hboxlayout.addWidget(self.ckStoreSettingsLocally) + + self.edStoreSettingsLocally = QtGui.QLineEdit(PrefsGlobalTpl) + self.edStoreSettingsLocally.setObjectName("edStoreSettingsLocally") + self.hboxlayout.addWidget(self.edStoreSettingsLocally) + + self.btStoreSettingsLocally = QtGui.QPushButton(PrefsGlobalTpl) + self.btStoreSettingsLocally.setObjectName("btStoreSettingsLocally") + self.hboxlayout.addWidget(self.btStoreSettingsLocally) + self.gridlayout.addLayout(self.hboxlayout,1,0,1,1) + + spacerItem = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding) + self.gridlayout.addItem(spacerItem,2,0,1,1) + + self.retranslateUi(PrefsGlobalTpl) + QtCore.QMetaObject.connectSlotsByName(PrefsGlobalTpl) + + def retranslateUi(self, PrefsGlobalTpl): + PrefsGlobalTpl.setWindowTitle(QtGui.QApplication.translate("PrefsGlobalTpl", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.", None, QtGui.QApplication.UnicodeUTF8)) + self.btStoreSettingsLocally.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "...", None, QtGui.QApplication.UnicodeUTF8)) + + + +if __name__ == "__main__": + import sys + app = QtGui.QApplication(sys.argv) + PrefsGlobalTpl = QtGui.QWidget() + ui = Ui_PrefsGlobalTpl() + ui.setupUi(PrefsGlobalTpl) + PrefsGlobalTpl.show() + sys.exit(app.exec_()) Added: trunk/fclient/src/fclient/__init__.py =================================================================== --- trunk/fclient/src/fclient/__init__.py (rev 0) +++ trunk/fclient/src/fclient/__init__.py 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1,9 @@ + +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 . import config +from .ui import connection \ No newline at end of file Added: trunk/fclient/src/fclient/config.py =================================================================== --- trunk/fclient/src/fclient/config.py (rev 0) +++ trunk/fclient/src/fclient/config.py 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1,93 @@ +"""""" +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__)] + +import atexit +import os +from PyQt4 import QtCore + +from .lib import fcp2 +from .lib.qt4ex import settingsbase +#********************************************************************************** +# +#********************************************************************************** +FclientOrgName = 'fclient' +FclientAppName = 'fclient' + +SettingsDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'settings') +#********************************************************************************** +# +#********************************************************************************** +class ConfigSettings(settingsbase.SettingsBase): + + KEY_SETTINGS = 'ConfigSettings' + SETTINGS = [ + ('StoreSettingsLocally', ['UPyString', SettingsDir]), # if not None, settings are stored locally in the app folder + ] + + + +class Settings(settingsbase.Settings): + """customized settings class to allow to store settings locally""" + + def __init__(self): + settingsbase.Settings.__init__(self, FclientOrgName, FclientAppName) + self.format = QtCore.QSettings.IniFormat + self.scope = QtCore.QSettings.UserScope + self.directory = None + + self.setStoreLocal(SettingsDir) + + + def setStoreLocal(self, directory=None): + """should the settings be stored locally? + + @param directory: (str) if None, the default location of the os is used to store settings, if a directory + setings are stored there + """ + if directory is None: + self.format = QtCore.QSettings.NativeFormat + self.scope = QtCore.QSettings.UserScope + else: + self.format = QtCore.QSettings.IniFormat + self.scope = QtCore.QSettings.UserScope + QtCore.QSettings.setPath(self.format, self.scope, directory) + self.directory = directory + + + def getObject(self, parent): + o = QtCore.QSettings(self.format, self.scope, self.orgName, self.appName, parent) + o.setFallbacksEnabled(False) + #print o.fileName() + return o + +#********************************************************************************** +# +#********************************************************************************** +class Config(object): + + def __init__(self, parent): + + self.fcpClient = fcp2.Client() # global fcp client + self.settings = Settings() # global settings class + self.configSettings = ConfigSettings() # settings of the config + + + self.settings.readSettings(None, self.configSettings) + self.settings.setStoreLocal(directory=self.configSettings['StoreSettingsLocally']) + + atexit.register(self.close) + + + def close(self): + self.settings.dumpSettings(None, self.configSettings) + + + + +s = Config(None) + + + + Added: trunk/fclient/src/fclient/fclient.py =================================================================== --- trunk/fclient/src/fclient/fclient.py (rev 0) +++ trunk/fclient/src/fclient/fclient.py 2008-07-07 21:33:45 UTC (rev 539) @@ -0,0 +1 @@ + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 07:41:05
|
Revision: 540 http://fclient.svn.sourceforge.net/fclient/?rev=540&view=rev Author: jUrner Date: 2008-07-08 00:41:08 -0700 (Tue, 08 Jul 2008) Log Message: ----------- move to tpls to keep them out of the way Removed Paths: ------------- trunk/fclient/src/fclient/PrefsGlobalTpl.ui trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py Deleted: trunk/fclient/src/fclient/PrefsGlobalTpl.ui =================================================================== --- trunk/fclient/src/fclient/PrefsGlobalTpl.ui 2008-07-07 21:33:45 UTC (rev 539) +++ trunk/fclient/src/fclient/PrefsGlobalTpl.ui 2008-07-08 07:41:08 UTC (rev 540) @@ -1,64 +0,0 @@ -<ui version="4.0" > - <class>PrefsGlobalTpl</class> - <widget class="QWidget" name="PrefsGlobalTpl" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>465</width> - <height>247</height> - </rect> - </property> - <property name="windowTitle" > - <string>Form</string> - </property> - <layout class="QGridLayout" > - <item row="0" column="0" > - <widget class="QLabel" name="label" > - <property name="text" > - <string>Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.</string> - </property> - <property name="wordWrap" > - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="0" > - <layout class="QHBoxLayout" > - <item> - <widget class="QCheckBox" name="ckStoreSettingsLocally" > - <property name="text" > - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="edStoreSettingsLocally" /> - </item> - <item> - <widget class="QPushButton" name="btStoreSettingsLocally" > - <property name="text" > - <string>...</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="0" > - <spacer> - <property name="orientation" > - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" > - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> Deleted: trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py =================================================================== --- trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py 2008-07-07 21:33:45 UTC (rev 539) +++ trunk/fclient/src/fclient/Ui_PrefsGlobalTpl.py 2008-07-08 07:41:08 UTC (rev 540) @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/PrefsGlobalTpl.ui' -# -# Created: Mon Jul 7 23:23:43 2008 -# by: PyQt4 UI code generator 4.3.3 -# -# WARNING! All changes made in this file will be lost! - -from PyQt4 import QtCore, QtGui - -class Ui_PrefsGlobalTpl(object): - def setupUi(self, PrefsGlobalTpl): - PrefsGlobalTpl.setObjectName("PrefsGlobalTpl") - PrefsGlobalTpl.resize(QtCore.QSize(QtCore.QRect(0,0,465,247).size()).expandedTo(PrefsGlobalTpl.minimumSizeHint())) - - self.gridlayout = QtGui.QGridLayout(PrefsGlobalTpl) - self.gridlayout.setObjectName("gridlayout") - - self.label = QtGui.QLabel(PrefsGlobalTpl) - self.label.setWordWrap(True) - self.label.setObjectName("label") - self.gridlayout.addWidget(self.label,0,0,1,1) - - self.hboxlayout = QtGui.QHBoxLayout() - self.hboxlayout.setObjectName("hboxlayout") - - self.ckStoreSettingsLocally = QtGui.QCheckBox(PrefsGlobalTpl) - self.ckStoreSettingsLocally.setObjectName("ckStoreSettingsLocally") - self.hboxlayout.addWidget(self.ckStoreSettingsLocally) - - self.edStoreSettingsLocally = QtGui.QLineEdit(PrefsGlobalTpl) - self.edStoreSettingsLocally.setObjectName("edStoreSettingsLocally") - self.hboxlayout.addWidget(self.edStoreSettingsLocally) - - self.btStoreSettingsLocally = QtGui.QPushButton(PrefsGlobalTpl) - self.btStoreSettingsLocally.setObjectName("btStoreSettingsLocally") - self.hboxlayout.addWidget(self.btStoreSettingsLocally) - self.gridlayout.addLayout(self.hboxlayout,1,0,1,1) - - spacerItem = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding) - self.gridlayout.addItem(spacerItem,2,0,1,1) - - self.retranslateUi(PrefsGlobalTpl) - QtCore.QMetaObject.connectSlotsByName(PrefsGlobalTpl) - - def retranslateUi(self, PrefsGlobalTpl): - PrefsGlobalTpl.setWindowTitle(QtGui.QApplication.translate("PrefsGlobalTpl", "Form", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.", None, QtGui.QApplication.UnicodeUTF8)) - self.btStoreSettingsLocally.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "...", None, QtGui.QApplication.UnicodeUTF8)) - - - -if __name__ == "__main__": - import sys - app = QtGui.QApplication(sys.argv) - PrefsGlobalTpl = QtGui.QWidget() - ui = Ui_PrefsGlobalTpl() - ui.setupUi(PrefsGlobalTpl) - PrefsGlobalTpl.show() - sys.exit(app.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 07:43:59
|
Revision: 541 http://fclient.svn.sourceforge.net/fclient/?rev=541&view=rev Author: jUrner Date: 2008-07-08 00:44:05 -0700 (Tue, 08 Jul 2008) Log Message: ----------- move ui templates out of the way Added Paths: ----------- trunk/fclient/src/fclient/tpls/ trunk/fclient/src/fclient/tpls/PrefsGlobalTpl.ui trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalTpl.py trunk/fclient/src/fclient/tpls/__init__.py/ Added: trunk/fclient/src/fclient/tpls/PrefsGlobalTpl.ui =================================================================== --- trunk/fclient/src/fclient/tpls/PrefsGlobalTpl.ui (rev 0) +++ trunk/fclient/src/fclient/tpls/PrefsGlobalTpl.ui 2008-07-08 07:44:05 UTC (rev 541) @@ -0,0 +1,64 @@ +<ui version="4.0" > + <class>PrefsGlobalTpl</class> + <widget class="QWidget" name="PrefsGlobalTpl" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>465</width> + <height>247</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0" > + <layout class="QHBoxLayout" > + <item> + <widget class="QCheckBox" name="ckStoreSettingsLocally" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="edStoreSettingsLocally" /> + </item> + <item> + <widget class="QPushButton" name="btStoreSettingsLocally" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> Added: trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalTpl.py =================================================================== --- trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalTpl.py (rev 0) +++ trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalTpl.py 2008-07-08 07:44:05 UTC (rev 541) @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/PrefsGlobalTpl.ui' +# +# Created: Mon Jul 7 23:23:43 2008 +# by: PyQt4 UI code generator 4.3.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_PrefsGlobalTpl(object): + def setupUi(self, PrefsGlobalTpl): + PrefsGlobalTpl.setObjectName("PrefsGlobalTpl") + PrefsGlobalTpl.resize(QtCore.QSize(QtCore.QRect(0,0,465,247).size()).expandedTo(PrefsGlobalTpl.minimumSizeHint())) + + self.gridlayout = QtGui.QGridLayout(PrefsGlobalTpl) + self.gridlayout.setObjectName("gridlayout") + + self.label = QtGui.QLabel(PrefsGlobalTpl) + self.label.setWordWrap(True) + self.label.setObjectName("label") + self.gridlayout.addWidget(self.label,0,0,1,1) + + self.hboxlayout = QtGui.QHBoxLayout() + self.hboxlayout.setObjectName("hboxlayout") + + self.ckStoreSettingsLocally = QtGui.QCheckBox(PrefsGlobalTpl) + self.ckStoreSettingsLocally.setObjectName("ckStoreSettingsLocally") + self.hboxlayout.addWidget(self.ckStoreSettingsLocally) + + self.edStoreSettingsLocally = QtGui.QLineEdit(PrefsGlobalTpl) + self.edStoreSettingsLocally.setObjectName("edStoreSettingsLocally") + self.hboxlayout.addWidget(self.edStoreSettingsLocally) + + self.btStoreSettingsLocally = QtGui.QPushButton(PrefsGlobalTpl) + self.btStoreSettingsLocally.setObjectName("btStoreSettingsLocally") + self.hboxlayout.addWidget(self.btStoreSettingsLocally) + self.gridlayout.addLayout(self.hboxlayout,1,0,1,1) + + spacerItem = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding) + self.gridlayout.addItem(spacerItem,2,0,1,1) + + self.retranslateUi(PrefsGlobalTpl) + QtCore.QMetaObject.connectSlotsByName(PrefsGlobalTpl) + + def retranslateUi(self, PrefsGlobalTpl): + PrefsGlobalTpl.setWindowTitle(QtGui.QApplication.translate("PrefsGlobalTpl", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.", None, QtGui.QApplication.UnicodeUTF8)) + self.btStoreSettingsLocally.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "...", None, QtGui.QApplication.UnicodeUTF8)) + + + +if __name__ == "__main__": + import sys + app = QtGui.QApplication(sys.argv) + PrefsGlobalTpl = QtGui.QWidget() + ui = Ui_PrefsGlobalTpl() + ui.setupUi(PrefsGlobalTpl) + PrefsGlobalTpl.show() + sys.exit(app.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 15:49:39
|
Revision: 559 http://fclient.svn.sourceforge.net/fclient/?rev=559&view=rev Author: jUrner Date: 2008-07-08 08:49:12 -0700 (Tue, 08 Jul 2008) Log Message: ----------- ... Modified Paths: -------------- trunk/fclient/src/fclient/Ui_ViewLogger.py trunk/fclient/src/fclient/tpls/Ui_ViewLoggerWidgetTpl.py trunk/fclient/src/fclient/tpls/ViewLoggerWidgetTpl.ui Modified: trunk/fclient/src/fclient/Ui_ViewLogger.py =================================================================== --- trunk/fclient/src/fclient/Ui_ViewLogger.py 2008-07-08 15:46:33 UTC (rev 558) +++ trunk/fclient/src/fclient/Ui_ViewLogger.py 2008-07-08 15:49:12 UTC (rev 559) @@ -8,14 +8,14 @@ from . import config -from .tpls.Ui_ViewLoggerTpl import Ui_ViewLoggerTpl +from .tpls.Ui_ViewLoggerWidgetTpl import Ui_ViewLoggerWidget #********************************************************************************** # #********************************************************************************** #*********************************************************************** # #*********************************************************************** -class ViewWidgetLogger(QtGui.QWidget, Ui_ViewLoggerTpl): +class ViewLoggerWidget(QtGui.QWidget, Ui_ViewLoggerWidget): def __init__(self, parent, cfg=None): QtGui.QWidget.__init__(self, parent) @@ -33,7 +33,7 @@ import sys app = QtGui.QApplication(sys.argv) - w = ViewWidgetLogger(None) + w = ViewLoggerWidget(None) w.show() res = app.exec_() sys.exit(res) Modified: trunk/fclient/src/fclient/tpls/Ui_ViewLoggerWidgetTpl.py =================================================================== --- trunk/fclient/src/fclient/tpls/Ui_ViewLoggerWidgetTpl.py 2008-07-08 15:46:33 UTC (rev 558) +++ trunk/fclient/src/fclient/tpls/Ui_ViewLoggerWidgetTpl.py 2008-07-08 15:49:12 UTC (rev 559) @@ -1,23 +1,23 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/ViewLoggerTpl.ui' +# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/ViewLoggerWidgetTpl.ui' # -# Created: Tue Jul 8 10:17:24 2008 +# Created: Tue Jul 8 17:48:36 2008 # by: PyQt4 UI code generator 4.3.3 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui -class Ui_ViewLoggerTpl(object): - def setupUi(self, ViewLoggerTpl): - ViewLoggerTpl.setObjectName("ViewLoggerTpl") - ViewLoggerTpl.resize(QtCore.QSize(QtCore.QRect(0,0,550,471).size()).expandedTo(ViewLoggerTpl.minimumSizeHint())) +class Ui_ViewLoggerWidget(object): + def setupUi(self, ViewLoggerWidget): + ViewLoggerWidget.setObjectName("ViewLoggerWidget") + ViewLoggerWidget.resize(QtCore.QSize(QtCore.QRect(0,0,550,471).size()).expandedTo(ViewLoggerWidget.minimumSizeHint())) - self.gridlayout = QtGui.QGridLayout(ViewLoggerTpl) + self.gridlayout = QtGui.QGridLayout(ViewLoggerWidget) self.gridlayout.setObjectName("gridlayout") - self.edLogger = QtGui.QTextEdit(ViewLoggerTpl) + self.edLogger = QtGui.QTextEdit(ViewLoggerWidget) self.edLogger.setUndoRedoEnabled(False) self.edLogger.setLineWrapMode(QtGui.QTextEdit.NoWrap) self.edLogger.setReadOnly(True) @@ -26,19 +26,19 @@ self.edLogger.setObjectName("edLogger") self.gridlayout.addWidget(self.edLogger,0,0,1,1) - self.retranslateUi(ViewLoggerTpl) - QtCore.QMetaObject.connectSlotsByName(ViewLoggerTpl) + self.retranslateUi(ViewLoggerWidget) + QtCore.QMetaObject.connectSlotsByName(ViewLoggerWidget) - def retranslateUi(self, ViewLoggerTpl): - ViewLoggerTpl.setWindowTitle(QtGui.QApplication.translate("ViewLoggerTpl", "Form", None, QtGui.QApplication.UnicodeUTF8)) + def retranslateUi(self, ViewLoggerWidget): + ViewLoggerWidget.setWindowTitle(QtGui.QApplication.translate("ViewLoggerWidget", "Form", None, QtGui.QApplication.UnicodeUTF8)) if __name__ == "__main__": import sys app = QtGui.QApplication(sys.argv) - ViewLoggerTpl = QtGui.QWidget() - ui = Ui_ViewLoggerTpl() - ui.setupUi(ViewLoggerTpl) - ViewLoggerTpl.show() + ViewLoggerWidget = QtGui.QWidget() + ui = Ui_ViewLoggerWidget() + ui.setupUi(ViewLoggerWidget) + ViewLoggerWidget.show() sys.exit(app.exec_()) Modified: trunk/fclient/src/fclient/tpls/ViewLoggerWidgetTpl.ui =================================================================== --- trunk/fclient/src/fclient/tpls/ViewLoggerWidgetTpl.ui 2008-07-08 15:46:33 UTC (rev 558) +++ trunk/fclient/src/fclient/tpls/ViewLoggerWidgetTpl.ui 2008-07-08 15:49:12 UTC (rev 559) @@ -1,6 +1,6 @@ <ui version="4.0" > - <class>ViewLoggerTpl</class> - <widget class="QWidget" name="ViewLoggerTpl" > + <class>ViewLoggerWidget</class> + <widget class="QWidget" name="ViewLoggerWidget" > <property name="geometry" > <rect> <x>0</x> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 15:53:34
|
Revision: 561 http://fclient.svn.sourceforge.net/fclient/?rev=561&view=rev Author: jUrner Date: 2008-07-08 08:52:59 -0700 (Tue, 08 Jul 2008) Log Message: ----------- ... Modified Paths: -------------- trunk/fclient/src/fclient/Ui_PrefsGlobal.py trunk/fclient/src/fclient/tpls/PrefsGlobalWidgetTpl.ui trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalWidgetTpl.py Modified: trunk/fclient/src/fclient/Ui_PrefsGlobal.py =================================================================== --- trunk/fclient/src/fclient/Ui_PrefsGlobal.py 2008-07-08 15:50:30 UTC (rev 560) +++ trunk/fclient/src/fclient/Ui_PrefsGlobal.py 2008-07-08 15:52:59 UTC (rev 561) @@ -9,11 +9,11 @@ from . import config from .lib.qt4ex.dlgs import dlgpreferences -from .tpls.Ui_PrefsGlobalTpl import Ui_PrefsGlobalTpl +from .tpls.Ui_PrefsGlobalWidgetTpl import Ui_PrefsGlobalWidget #********************************************************************************** # #********************************************************************************** -class PrefsWidgetGlobal(QtGui.QWidget, Ui_PrefsGlobalTpl): +class PrefsGlobalWidget(QtGui.QWidget, Ui_PrefsGlobalWidget): def __init__(self, parent, cfg=None): QtGui.QWidget.__init__(self, parent) @@ -45,7 +45,7 @@ createdNew = False if flag and self._widget is None: createdNew = True - self._widget = PrefsWidgetGlobal(parent) + self._widget = PrefsGlobalWidget(parent) self._widget.setVisible(flag) return (createdNew, self._widget) @@ -59,7 +59,7 @@ import sys app = QtGui.QApplication(sys.argv) - w = PrefsWidgetGlobal(None) + w = PrefsGlobalWidget(None) w.show() res = app.exec_() sys.exit(res) Modified: trunk/fclient/src/fclient/tpls/PrefsGlobalWidgetTpl.ui =================================================================== --- trunk/fclient/src/fclient/tpls/PrefsGlobalWidgetTpl.ui 2008-07-08 15:50:30 UTC (rev 560) +++ trunk/fclient/src/fclient/tpls/PrefsGlobalWidgetTpl.ui 2008-07-08 15:52:59 UTC (rev 561) @@ -1,6 +1,6 @@ <ui version="4.0" > - <class>PrefsGlobalTpl</class> - <widget class="QWidget" name="PrefsGlobalTpl" > + <class>PrefsGlobalWidget</class> + <widget class="QWidget" name="PrefsGlobalWidget" > <property name="geometry" > <rect> <x>0</x> Modified: trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalWidgetTpl.py =================================================================== --- trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalWidgetTpl.py 2008-07-08 15:50:30 UTC (rev 560) +++ trunk/fclient/src/fclient/tpls/Ui_PrefsGlobalWidgetTpl.py 2008-07-08 15:52:59 UTC (rev 561) @@ -1,23 +1,23 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/PrefsGlobalTpl.ui' +# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/PrefsGlobalWidgetTpl.ui' # -# Created: Mon Jul 7 23:23:43 2008 +# Created: Tue Jul 8 17:51:29 2008 # by: PyQt4 UI code generator 4.3.3 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui -class Ui_PrefsGlobalTpl(object): - def setupUi(self, PrefsGlobalTpl): - PrefsGlobalTpl.setObjectName("PrefsGlobalTpl") - PrefsGlobalTpl.resize(QtCore.QSize(QtCore.QRect(0,0,465,247).size()).expandedTo(PrefsGlobalTpl.minimumSizeHint())) +class Ui_PrefsGlobalWidget(object): + def setupUi(self, PrefsGlobalWidget): + PrefsGlobalWidget.setObjectName("PrefsGlobalWidget") + PrefsGlobalWidget.resize(QtCore.QSize(QtCore.QRect(0,0,465,247).size()).expandedTo(PrefsGlobalWidget.minimumSizeHint())) - self.gridlayout = QtGui.QGridLayout(PrefsGlobalTpl) + self.gridlayout = QtGui.QGridLayout(PrefsGlobalWidget) self.gridlayout.setObjectName("gridlayout") - self.label = QtGui.QLabel(PrefsGlobalTpl) + self.label = QtGui.QLabel(PrefsGlobalWidget) self.label.setWordWrap(True) self.label.setObjectName("label") self.gridlayout.addWidget(self.label,0,0,1,1) @@ -25,15 +25,15 @@ self.hboxlayout = QtGui.QHBoxLayout() self.hboxlayout.setObjectName("hboxlayout") - self.ckStoreSettingsLocally = QtGui.QCheckBox(PrefsGlobalTpl) + self.ckStoreSettingsLocally = QtGui.QCheckBox(PrefsGlobalWidget) self.ckStoreSettingsLocally.setObjectName("ckStoreSettingsLocally") self.hboxlayout.addWidget(self.ckStoreSettingsLocally) - self.edStoreSettingsLocally = QtGui.QLineEdit(PrefsGlobalTpl) + self.edStoreSettingsLocally = QtGui.QLineEdit(PrefsGlobalWidget) self.edStoreSettingsLocally.setObjectName("edStoreSettingsLocally") self.hboxlayout.addWidget(self.edStoreSettingsLocally) - self.btStoreSettingsLocally = QtGui.QPushButton(PrefsGlobalTpl) + self.btStoreSettingsLocally = QtGui.QPushButton(PrefsGlobalWidget) self.btStoreSettingsLocally.setObjectName("btStoreSettingsLocally") self.hboxlayout.addWidget(self.btStoreSettingsLocally) self.gridlayout.addLayout(self.hboxlayout,1,0,1,1) @@ -41,21 +41,21 @@ spacerItem = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding) self.gridlayout.addItem(spacerItem,2,0,1,1) - self.retranslateUi(PrefsGlobalTpl) - QtCore.QMetaObject.connectSlotsByName(PrefsGlobalTpl) + self.retranslateUi(PrefsGlobalWidget) + QtCore.QMetaObject.connectSlotsByName(PrefsGlobalWidget) - def retranslateUi(self, PrefsGlobalTpl): - PrefsGlobalTpl.setWindowTitle(QtGui.QApplication.translate("PrefsGlobalTpl", "Form", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.", None, QtGui.QApplication.UnicodeUTF8)) - self.btStoreSettingsLocally.setText(QtGui.QApplication.translate("PrefsGlobalTpl", "...", None, QtGui.QApplication.UnicodeUTF8)) + def retranslateUi(self, PrefsGlobalWidget): + PrefsGlobalWidget.setWindowTitle(QtGui.QApplication.translate("PrefsGlobalWidget", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("PrefsGlobalWidget", "Specify directory to store settings to. If unchecked, settings are stored in an os dependend location.", None, QtGui.QApplication.UnicodeUTF8)) + self.btStoreSettingsLocally.setText(QtGui.QApplication.translate("PrefsGlobalWidget", "...", None, QtGui.QApplication.UnicodeUTF8)) if __name__ == "__main__": import sys app = QtGui.QApplication(sys.argv) - PrefsGlobalTpl = QtGui.QWidget() - ui = Ui_PrefsGlobalTpl() - ui.setupUi(PrefsGlobalTpl) - PrefsGlobalTpl.show() + PrefsGlobalWidget = QtGui.QWidget() + ui = Ui_PrefsGlobalWidget() + ui.setupUi(PrefsGlobalWidget) + PrefsGlobalWidget.show() sys.exit(app.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 15:57:08
|
Revision: 563 http://fclient.svn.sourceforge.net/fclient/?rev=563&view=rev Author: jUrner Date: 2008-07-08 08:56:38 -0700 (Tue, 08 Jul 2008) Log Message: ----------- ... Modified Paths: -------------- trunk/fclient/src/fclient/Ui_View.py trunk/fclient/src/fclient/tpls/Ui_ViewWidgetTpl.py trunk/fclient/src/fclient/tpls/ViewWidgetTpl.ui Modified: trunk/fclient/src/fclient/Ui_View.py =================================================================== --- trunk/fclient/src/fclient/Ui_View.py 2008-07-08 15:54:29 UTC (rev 562) +++ trunk/fclient/src/fclient/Ui_View.py 2008-07-08 15:56:38 UTC (rev 563) @@ -10,7 +10,7 @@ from . import config from .lib import fcp2 from .lib.qt4ex import settingsbase -from .tpls.Ui_ViewTpl import Ui_ViewTpl +from .tpls.Ui_ViewWidgetTpl import Ui_ViewWidget #********************************************************************************** # @@ -24,7 +24,7 @@ #*********************************************************************** # #*********************************************************************** -class ViewWidget(QtGui.QWidget, Ui_ViewTpl): +class ViewWidget(QtGui.QWidget, Ui_ViewWidget): IdTabTop = 'tabTop' IdTabBottom = 'tabBottom' Modified: trunk/fclient/src/fclient/tpls/Ui_ViewWidgetTpl.py =================================================================== --- trunk/fclient/src/fclient/tpls/Ui_ViewWidgetTpl.py 2008-07-08 15:54:29 UTC (rev 562) +++ trunk/fclient/src/fclient/tpls/Ui_ViewWidgetTpl.py 2008-07-08 15:56:38 UTC (rev 563) @@ -1,25 +1,25 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/ViewTpl.ui' +# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/ViewWidgetTpl.ui' # -# Created: Tue Jul 8 12:13:15 2008 +# Created: Tue Jul 8 17:55:38 2008 # by: PyQt4 UI code generator 4.3.3 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui -class Ui_ViewTpl(object): - def setupUi(self, ViewTpl): - ViewTpl.setObjectName("ViewTpl") - ViewTpl.resize(QtCore.QSize(QtCore.QRect(0,0,530,629).size()).expandedTo(ViewTpl.minimumSizeHint())) +class Ui_ViewWidget(object): + def setupUi(self, ViewWidget): + ViewWidget.setObjectName("ViewWidget") + ViewWidget.resize(QtCore.QSize(QtCore.QRect(0,0,530,629).size()).expandedTo(ViewWidget.minimumSizeHint())) - self.gridlayout = QtGui.QGridLayout(ViewTpl) + self.gridlayout = QtGui.QGridLayout(ViewWidget) self.gridlayout.setMargin(0) self.gridlayout.setSpacing(0) self.gridlayout.setObjectName("gridlayout") - self.splitter = QtGui.QSplitter(ViewTpl) + self.splitter = QtGui.QSplitter(ViewWidget) self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setObjectName("splitter") @@ -62,23 +62,23 @@ self.gridlayout2.addWidget(self.tabBottom,0,0,1,1) self.gridlayout.addWidget(self.splitter,0,0,1,1) - self.retranslateUi(ViewTpl) + self.retranslateUi(ViewWidget) self.tabTop.setCurrentIndex(0) self.tabBottom.setCurrentIndex(0) - QtCore.QMetaObject.connectSlotsByName(ViewTpl) + QtCore.QMetaObject.connectSlotsByName(ViewWidget) - def retranslateUi(self, ViewTpl): - ViewTpl.setWindowTitle(QtGui.QApplication.translate("ViewTpl", "Form", None, QtGui.QApplication.UnicodeUTF8)) - self.tabTop.setTabText(self.tabTop.indexOf(self.tab_3), QtGui.QApplication.translate("ViewTpl", "Tab 1", None, QtGui.QApplication.UnicodeUTF8)) - self.tabBottom.setTabText(self.tabBottom.indexOf(self.tab_5), QtGui.QApplication.translate("ViewTpl", "Tab 1", None, QtGui.QApplication.UnicodeUTF8)) + def retranslateUi(self, ViewWidget): + ViewWidget.setWindowTitle(QtGui.QApplication.translate("ViewWidget", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.tabTop.setTabText(self.tabTop.indexOf(self.tab_3), QtGui.QApplication.translate("ViewWidget", "Tab 1", None, QtGui.QApplication.UnicodeUTF8)) + self.tabBottom.setTabText(self.tabBottom.indexOf(self.tab_5), QtGui.QApplication.translate("ViewWidget", "Tab 1", None, QtGui.QApplication.UnicodeUTF8)) if __name__ == "__main__": import sys app = QtGui.QApplication(sys.argv) - ViewTpl = QtGui.QWidget() - ui = Ui_ViewTpl() - ui.setupUi(ViewTpl) - ViewTpl.show() + ViewWidget = QtGui.QWidget() + ui = Ui_ViewWidget() + ui.setupUi(ViewWidget) + ViewWidget.show() sys.exit(app.exec_()) Modified: trunk/fclient/src/fclient/tpls/ViewWidgetTpl.ui =================================================================== --- trunk/fclient/src/fclient/tpls/ViewWidgetTpl.ui 2008-07-08 15:54:29 UTC (rev 562) +++ trunk/fclient/src/fclient/tpls/ViewWidgetTpl.ui 2008-07-08 15:56:38 UTC (rev 563) @@ -1,6 +1,6 @@ <ui version="4.0" > - <class>ViewTpl</class> - <widget class="QWidget" name="ViewTpl" > + <class>ViewWidget</class> + <widget class="QWidget" name="ViewWidget" > <property name="geometry" > <rect> <x>0</x> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 16:50:08
|
Revision: 566 http://fclient.svn.sourceforge.net/fclient/?rev=566&view=rev Author: jUrner Date: 2008-07-08 09:49:12 -0700 (Tue, 08 Jul 2008) Log Message: ----------- experimental ..add a global object registry Modified Paths: -------------- trunk/fclient/src/fclient/Ui_View.py trunk/fclient/src/fclient/Ui_ViewConnection.py trunk/fclient/src/fclient/Ui_ViewLogger.py Modified: trunk/fclient/src/fclient/Ui_View.py =================================================================== --- trunk/fclient/src/fclient/Ui_View.py 2008-07-08 16:47:26 UTC (rev 565) +++ trunk/fclient/src/fclient/Ui_View.py 2008-07-08 16:49:12 UTC (rev 566) @@ -39,6 +39,7 @@ self.views = {} self.setupUi(self) + config.ObjectRegistry.register(self) tabTop = self.controlById(self.IdTabTop) tabTop.removeTab(0) Modified: trunk/fclient/src/fclient/Ui_ViewConnection.py =================================================================== --- trunk/fclient/src/fclient/Ui_ViewConnection.py 2008-07-08 16:47:26 UTC (rev 565) +++ trunk/fclient/src/fclient/Ui_ViewConnection.py 2008-07-08 16:49:12 UTC (rev 566) @@ -28,15 +28,11 @@ #*********************************************************************** class ViewConnectionWidget(QtGui.QWidget, Ui_ViewConnectionWidget): - UUID = '{2339cfb0-5e84-44eb-9c8d-00965b5bb460}' - - IdBtConnect = 'btConnect' IdEdConnectionHost = 'edConnectionHost' IdSpinConnectionPort = 'spinConnectionPort' - - + def __init__(self, parent, cfg=None): QtGui.QWidget.__init__(self, parent) @@ -46,7 +42,9 @@ self.cfg = config.Config(self) if cfg is None else cfg self.userSettings = UserSettings() + self.setupUi(self) + config.ObjectRegistry.register(self) def showEvent(self, event): @@ -100,10 +98,8 @@ bt.setText(QtGui.QApplication.translate("ViewConnectionWidget", "Disconnect", None, QtGui.QApplication.UnicodeUTF8)) else: bt.setText(QtGui.QApplication.translate("ViewConnectionWidget", "Connect", None, QtGui.QApplication.UnicodeUTF8)) - - - + #********************************************************************************** # #********************************************************************************** Modified: trunk/fclient/src/fclient/Ui_ViewLogger.py =================================================================== --- trunk/fclient/src/fclient/Ui_ViewLogger.py 2008-07-08 16:47:26 UTC (rev 565) +++ trunk/fclient/src/fclient/Ui_ViewLogger.py 2008-07-08 16:49:12 UTC (rev 566) @@ -25,6 +25,7 @@ self.setupUi(self) + config.ObjectRegistry.register(self) #********************************************************************************** # This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-08 18:01:38
|
Revision: 568 http://fclient.svn.sourceforge.net/fclient/?rev=568&view=rev Author: jUrner Date: 2008-07-08 11:00:50 -0700 (Tue, 08 Jul 2008) Log Message: ----------- plugin views into the gui seems to work as expected Modified Paths: -------------- trunk/fclient/src/fclient/Ui_View.py trunk/fclient/src/fclient/Ui_ViewConnection.py trunk/fclient/src/fclient/Ui_ViewLogger.py Modified: trunk/fclient/src/fclient/Ui_View.py =================================================================== --- trunk/fclient/src/fclient/Ui_View.py 2008-07-08 16:52:34 UTC (rev 567) +++ trunk/fclient/src/fclient/Ui_View.py 2008-07-08 18:00:50 UTC (rev 568) @@ -52,14 +52,14 @@ return getattr(self, idControl) - def addViews(top=True, *views): - tab = self.controlById(self.IdTabTop) if top else self.controlById(self.IdTabBottom) + def addViews(self, toTop, *views): + tab = self.controlById(self.IdTabTop) if toTop else self.controlById(self.IdTabBottom) for view in views: - uuid = view.uuid() - if uuid in self.views: - raise ValueError('view is already present: %s' % uuid) - i = tab.addTab(view.widget(tab), view.displayName(), view.icon()) - self.views[uuid] = (i, tab, view) + ido = str(view.objectName()) + if ido in self.views: + raise ValueError('view is already present: %s' % ido) + i = tab.addTab(view.widget(tab), view.icon(), view.displayName()) + self.views[ido] = (i, tab, view) def viewFromUuid(self, uuid): @@ -72,27 +72,39 @@ #********************************************************************************** # #********************************************************************************** +#NOTE: to self. no need to register views to config.ObjectRegistry. they are just +# opaque objects private to ViewWidget class View(object): - """base class for views""" + """base class for views handled by L{ViewWidget}""" - UUID = '' - def __init__(self): - pass + raise NotImplemetedError() - def displayName(self): - return 'tab' + """should return the user visible name of the view + @return: (QString) + """ + raise NotImplemetedError() def icon(self): - pass - - def uuid(self): - return self.UUID - + """should return the icon associated to the view + @return: (QIcon) + """ + raise NotImplemetedError() + + def objectName(self): + """should return the internally used id of the view + @return: (str) id + """ + raise NotImplemetedError() + def widget(self, parent): - pass - + """should return the widget contained in the view + @param parent: (QWidget) parent + @return: (QWidget) + note: if the widget is not already created _now_ is the right time to create it + """ + raise NotImplemetedError() #********************************************************************************** # Modified: trunk/fclient/src/fclient/Ui_ViewConnection.py =================================================================== --- trunk/fclient/src/fclient/Ui_ViewConnection.py 2008-07-08 16:52:34 UTC (rev 567) +++ trunk/fclient/src/fclient/Ui_ViewConnection.py 2008-07-08 18:00:50 UTC (rev 568) @@ -7,10 +7,12 @@ from . import config +from . import Ui_View + from .lib import fcp2 from .lib.qt4ex import settingsbase + from .tpls.Ui_ViewConnectionWidgetTpl import Ui_ViewConnectionWidget - #********************************************************************************** # #********************************************************************************** @@ -75,9 +77,7 @@ self.controlById(self.IdBtConnect).setChecked(True) self.onBtConnectClicked(True) - - - + def controlById(self, idControl): return getattr(self, idControl) @@ -88,7 +88,17 @@ if bt.isChecked(): bt.setText() + ######################################### + ## view methods + ######################################### + def displayName(self): + return QtGui.QApplication.translate("ViewConnectionWidget", "Connection", None, QtGui.QApplication.UnicodeUTF8) + + def icon(self): + return QtGui.QIcon() + + ######################################### ## ######################################### @@ -103,11 +113,41 @@ #********************************************************************************** # #********************************************************************************** +class ViewConnection(Ui_View.View): + + def __init__(self): + self._widget = None + + def displayName(self): + return QtGui.QApplication.translate("ViewConnectionWidget", "Connection", None, QtGui.QApplication.UnicodeUTF8) + + def icon(self): + return QtGui.QIcon() + + def objectName(self): + return 'ViewConnection' + + + def widget(self, parent): + if self._widget is None: + self._widget = ViewConnectionWidget(parent) + return self._widget + + +#********************************************************************************** +# +#********************************************************************************** if __name__ == '__main__': import sys + app = QtGui.QApplication(sys.argv) - app = QtGui.QApplication(sys.argv) - w = ViewConnectionWidget(None) + + from . import Ui_ViewLogger + + w = Ui_View.ViewWidget(None) + w.addViews(True, ViewConnection()) + w.addViews(False, Ui_ViewLogger.ViewLogger()) + w.show() res = app.exec_() sys.exit(res) Modified: trunk/fclient/src/fclient/Ui_ViewLogger.py =================================================================== --- trunk/fclient/src/fclient/Ui_ViewLogger.py 2008-07-08 16:52:34 UTC (rev 567) +++ trunk/fclient/src/fclient/Ui_ViewLogger.py 2008-07-08 18:00:50 UTC (rev 568) @@ -8,6 +8,8 @@ from . import config +from . import Ui_View + from .tpls.Ui_ViewLoggerWidgetTpl import Ui_ViewLoggerWidget #********************************************************************************** # @@ -30,6 +32,30 @@ #********************************************************************************** # #********************************************************************************** +class ViewLogger(Ui_View.View): + + def __init__(self): + self._widget = None + + def displayName(self): + return QtGui.QApplication.translate("ViewLogger", "Logger", None, QtGui.QApplication.UnicodeUTF8) + + def icon(self): + return QtGui.QIcon() + + def objectName(self): + return 'ViewLogger' + + + def widget(self, parent): + if self._widget is None: + self._widget = ViewLoggerWidget(parent) + return self._widget + + +#********************************************************************************** +# +#********************************************************************************** if __name__ == '__main__': import sys This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jU...@us...> - 2008-07-12 19:57:26
|
Revision: 596 http://fclient.svn.sourceforge.net/fclient/?rev=596&view=rev Author: jUrner Date: 2008-07-12 12:57:33 -0700 (Sat, 12 Jul 2008) Log Message: ----------- add main window Added Paths: ----------- trunk/fclient/src/fclient/Ui_MainWindow.py trunk/fclient/src/fclient/tpls/MainWindowTpl.ui trunk/fclient/src/fclient/tpls/Ui_MainWindowTpl.py Added: trunk/fclient/src/fclient/Ui_MainWindow.py =================================================================== --- trunk/fclient/src/fclient/Ui_MainWindow.py (rev 0) +++ trunk/fclient/src/fclient/Ui_MainWindow.py 2008-07-12 19:57:33 UTC (rev 596) @@ -0,0 +1,65 @@ +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__)] + +import logging +import sys +logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) + +from PyQt4 import QtCore, QtGui + + +from . import config +from . import Ui_View + +from .tpls.Ui_MainWindowTpl import Ui_MainWindow +#********************************************************************************** +# +#********************************************************************************** +class Settings(config.SettingsBase): + + _key_ = config.IdMainWindow + _settings_ = ( + ) + +#********************************************************************************** +# +#********************************************************************************** +class StatusBar(QtGui.QStatusBar): + + def __init__(self, parent): + QtGui.QStatusBar.__init__(self, parent) + self.setObjectName(config.IdMainWindowStatusBar) + +#********************************************************************************** +# +#********************************************************************************** +class MainWindow(QtGui.QMainWindow, Ui_MainWindow): + + def __init__(self, parent, cfg=None): + QtGui.QMainWindow.__init__(self, parent) + self.settings = Settings() + self.setupUi(self) + config.ObjectRegistry.register(self) + + # register menuBar + menuBar = self.menuBar() + menuBar.setObjectName(config.IdMainWindowMenuBar) + config.ObjectRegistry.register(menuBar) + + # register statusBar + statusBar = StatusBar(self) + self.setStatusBar(statusBar) + config.ObjectRegistry.register(statusBar) + +#********************************************************************************** +# +#********************************************************************************** +if __name__ == '__main__': + import sys + + app = QtGui.QApplication(sys.argv) + w = MainWindow(None) + w.show() + res = app.exec_() + sys.exit(res) \ No newline at end of file Added: trunk/fclient/src/fclient/tpls/MainWindowTpl.ui =================================================================== --- trunk/fclient/src/fclient/tpls/MainWindowTpl.ui (rev 0) +++ trunk/fclient/src/fclient/tpls/MainWindowTpl.ui 2008-07-12 19:57:33 UTC (rev 596) @@ -0,0 +1,30 @@ +<ui version="4.0" > + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle" > + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget" /> + <widget class="QMenuBar" name="menubar" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>26</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar" /> + </widget> + <resources/> + <connections/> +</ui> Added: trunk/fclient/src/fclient/tpls/Ui_MainWindowTpl.py =================================================================== --- trunk/fclient/src/fclient/tpls/Ui_MainWindowTpl.py (rev 0) +++ trunk/fclient/src/fclient/tpls/Ui_MainWindowTpl.py 2008-07-12 19:57:33 UTC (rev 596) @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/MainWindowTpl.ui' +# +# Created: Sat Jul 12 21:39:29 2008 +# by: PyQt4 UI code generator 4.3.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,800,600).size()).expandedTo(MainWindow.minimumSizeHint())) + + self.centralwidget = QtGui.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + MainWindow.setCentralWidget(self.centralwidget) + + self.menubar = QtGui.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0,0,800,26)) + self.menubar.setObjectName("menubar") + MainWindow.setMenuBar(self.menubar) + + self.statusbar = QtGui.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) + + + +if __name__ == "__main__": + import sys + app = QtGui.QApplication(sys.argv) + MainWindow = QtGui.QMainWindow() + ui = Ui_MainWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |