[profitpy commit] r330 - in trunk/profit: lib lib/widgets models session strategy workbench workbench/widgets

3 views
Skip to first unread message

codesite...@google.com

unread,
Aug 12, 2008, 4:32:40 AM8/12/08
to profitp...@googlegroups.com
Author: troy.melhase
Date: Tue Aug 12 01:32:07 2008
New Revision: 330

Added:
trunk/profit/lib/widgets/ui_localtableviewframe.ui (contents, props
changed)
trunk/profit/models/seriesitem.py (contents, props changed)
Modified:
trunk/profit/lib/__init__.py
trunk/profit/lib/widgets/extendedshell.py
trunk/profit/lib/widgets/localtabwidget.py
trunk/profit/lib/widgets/ui_extendedshell.ui
trunk/profit/lib/widgets/ui_plot.ui
trunk/profit/models/histdata.py
trunk/profit/models/strategy.py
trunk/profit/models/tickers.py
trunk/profit/session/__init__.py
trunk/profit/strategy/builder.py
trunk/profit/workbench/centraltabs.py
trunk/profit/workbench/historicaldatadisplay.py
trunk/profit/workbench/main.py
trunk/profit/workbench/tickerdisplay.py
trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui
trunk/profit/workbench/widgets/ui_main.ui
trunk/profit/workbench/widgets/ui_strategydisplay.ui
trunk/profit/workbench/widgets/ui_tickerdisplay.ui

Log:
Work in progress for the historical data model and display. Still missing
correct export to csv, and other minor fixes.

Modified: trunk/profit/lib/__init__.py
==============================================================================
--- trunk/profit/lib/__init__.py (original)
+++ trunk/profit/lib/__init__.py Tue Aug 12 01:32:07 2008
@@ -59,7 +59,42 @@
return getattr(mod, itemname)


-class Signals:
+def maybeFloat(value, default=None):
+ """ Returns the given value as a float, or default if doesn't float.
+
+ """
+ try:
+ return float(value)
+ except (ValueError, ):
+ return default
+
+
+def generateUserRoles():
+ """ Yields Qt.UserRoles sequentially.
+
+ """
+ i = Qt.UserRole
+ while True:
+ yield i
+ i += 1
+nextUserRole = generateUserRoles().next
+
+
+class DataRoles(object):
+ """ Namespace for our user data roles.
+
+ """
+ tickerId = nextUserRole()
+ tickerSymbol = nextUserRole()
+ histDataReqId = nextUserRole()
+ url = nextUserRole()
+ urlTitle = nextUserRole()
+ strategyName = nextUserRole()
+ displayImportName = nextUserRole()
+ tickerField = nextUserRole()
+
+
+class Signals(object):
""" Contains SIGNAL attributes for easy and consistent reference.

"""
@@ -105,36 +140,36 @@
triggeredBool = SIGNAL('triggered(bool)')
zoomed = SIGNAL('zoomed(const QwtDoubleRect &)')

- class contract:
+ class contract(object):
added = SIGNAL('contractAdded(int, PyQt_PyObject)')
created = SIGNAL('createdContract')

- class histdata:
+ class histdata(object):
request = SIGNAL('historicalDataRequest')
start = SIGNAL('historicalDataStart')
finish = SIGNAL('historicalDataFinish')

- class session:
+ class session(object):
created = SIGNAL('sessionCreated(PyQt_PyObject)')
reference = SIGNAL('sessionReference(PyQt_PyObject)')
request = SIGNAL('sessionRequest')
status = SIGNAL('sessionStatus')

- class strategy:
+ class strategy(object):
loaded = SIGNAL('strategyLoaded(PyQt_PyObject)')
loadFailed = SIGNAL('strategyLoadFaield(PyQt_PyObject)')
fileUpdated = SIGNAL('strategyFileUpdated(PyQt_PyObject)')
requestActivate = SIGNAL('strategyActivated(PyQt_PyObject, bool)')

- class ticker:
+ class ticker(object):
created = SIGNAL('tickerCreated_')

- class tws:
+ class tws(object):
connected = SIGNAL('connectedTWS')
disconnected = SIGNAL('disconnectedTWS')


-class Slots:
+class Slots(object):
""" Contains SLOT attributes for easy and consistent reference.

"""
@@ -189,17 +224,13 @@
QSettings.setValue(self, key, QVariant(value))

def setValueDump(self, key, value):
- self.setValue(key, dumps(value))
+ """ Sets value of setting as a pickled string.

- def valueLoad(self, key, default=None):
- v = self.value(key, default=default)
- if v:
- try:
- v = loads(str(v.toString()))
- except (Exception, ), exc:
- logging.debug('Exception valueLoad: %s, %r', exc, exc)
- v = default
- return v
+ @param key setting key as string
+ @param value anything supported by pickle.dumps
+ @return None
+ """
+ self.setValue(key, dumps(value))

def value(self, key, default=None):
""" Returns value for key, or default if key doesn't exist.
@@ -214,24 +245,21 @@
default = QVariant(default)
return QSettings.value(self, key, default)

+ def valueLoad(self, key, default=None):
+ """ Returns unpickled value for key, or default.

-def generateUserRoles():
- i = Qt.UserRole
- while True:
- yield i
- i += 1
-nextUserRole = generateUserRoles().next
-
-
-class DataRoles:
- tickerId = nextUserRole()
- tickerSymbol = nextUserRole()
- histDataReqId = nextUserRole()
- url = nextUserRole()
- urlTitle = nextUserRole()
- strategyName = nextUserRole()
- displayImportName = nextUserRole()
- tickerField = nextUserRole()
+ @param key setting key as string
+ @param default value returned if key does not exist
+ @return value of key or default
+ """
+ v = self.value(key, default=default)
+ if v:
+ try:
+ v = loads(str(v.toString()))
+ except (Exception, ), exc:
+ logging.debug('Exception valueLoad: %s, %r', exc, exc)
+ v = default
+ return v


class SessionHandler(object):
@@ -244,9 +272,15 @@
sessionRef = None

def sessionGetter(self):
+ """ Returns the session or None.
+
+ """
return self.sessionRef

def sessionSetter(self, value):
+ """ Sets the 'session' attribute on this instance.
+
+ """
session = self.sessionRef
if session:
for child in self.children() + [self, ]:
@@ -270,8 +304,8 @@
@param session Session instance
@return None
"""
- self.disconnect(
- instance(), Signals.session.reference, self.existingSession)
+ app = instance()
+ self.disconnect(app, Signals.session.reference,
self.existingSession)
if session is not self.session:
self.setSession(session)

@@ -302,25 +336,50 @@
settingsRef = None

def settingsGetter(self):
- settingsRef = self.settingsRef
- if not settingsRef:
- self.settingsRef = settingsRef = Settings()
- return settingsRef
+ """ Returns the settings or None.
+
+ """
+ settingsRef = self.settingsRef
+ if not settingsRef:
+ self.settingsRef = settingsRef = Settings()
+ return settingsRef

def settingsSetter(self, value):
+ """ Sets the 'setting' attribute on this instance.
+
+ """
self.settingsRef = value

settings = property(settingsGetter, settingsSetter)


class InstanceReflector(object):
- def reflectSignal(self, signal):
- app = instance()
- if app:
- self.connect(self, signal, app, signal)
+ """ Provides clients a method to resend signals via the application.
+
+ """
+ def reflectSignals(self, *signals, **kwds):
+ """ Bounce the signals from this instance to the app.
+
+ @param *signals sequence of signals to reflect
+ @param **kwds supports target=other reflection target.
+ default is the application instance.
+ @return None
+ """
+ if 'target' in kwds:
+ target = kwds['target']
else:
- logging.warn('No application instance to connect %s', signal)
+ target = instance()
+ if target:
+ for signal in signals:
+ self.connect(self, signal, target, signal)
+ else:
+ msg = 'No target object to connect signal(s): %s'
+ logging.warn(msg, (signals, ))
+
+
+class BasicHandler(InstanceReflector, SessionHandler, SettingsHandler, ):
+ """ Clients should use this class as a one-stop mixin-shop.
+
+ """


-class BasicHandler(SessionHandler, SettingsHandler, InstanceReflector):
- pass

Modified: trunk/profit/lib/widgets/extendedshell.py
==============================================================================
--- trunk/profit/lib/widgets/extendedshell.py (original)
+++ trunk/profit/lib/widgets/extendedshell.py Tue Aug 12 01:32:07 2008
@@ -25,10 +25,6 @@
""" Make our widgets like we like.

"""
- self.tb = QToolBar(self.editorFrame)
- self.tb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
- self.verticalLayout.insertWidget(0, self.tb)
- self.tb.addAction(self.actionExecute)
settings = self.settings
settings.beginGroup(self.__class__.__name__)
defaultState = defaults.leftSplitterState()
@@ -49,7 +45,7 @@
settings.endGroup()

@pyqtSignature('')
- def on_actionExecute_triggered(self):
+ def on_executeButton_clicked(self):
""" Execute the source code in the shell.

"""

Modified: trunk/profit/lib/widgets/localtabwidget.py
==============================================================================
--- trunk/profit/lib/widgets/localtabwidget.py (original)
+++ trunk/profit/lib/widgets/localtabwidget.py Tue Aug 12 01:32:07 2008
@@ -16,7 +16,14 @@


class LocalTabWidget(QTabWidget):
+ """ LocalTabWidget -> tab widget with special powers
+
+ """
def __init__(self, parent=None):
+ """ Initializer.
+
+ @param parent ancestor of this widget
+ """
QTabWidget.__init__(self, parent)
self.closeTabButton = CloseTabButton(self)
self.detachTabButton = DetachTabButton(self)
@@ -69,3 +76,33 @@
widget.setWindowFlags(Qt.Window)
widget.show()
QTimer.singleShot(100, show)
+
+ def pageMap(self):
+ """ Makes a mapping like {'connection':1, 'account':3, ...}
+
+ @return mapping of tab name to tab index
+ """
+ return dict([(str(self.tabText(i)), i) for i in
range(self.count())])
+
+ def setCurrentLabel(self, label):
+ """ Sets current tab by name if possible.
+
+ @param label text of tab to make current
+ @return True if successful, otherwise None
+ """
+ index = self.pageMap().get(label)
+ if index is not None:
+ self.setCurrentIndex(index)
+ return True
+
+ def setTextIconCurrentTab(self, index, text, icon):
+ """ Sets tab text and icon, and makes tab current.
+
+ @param index index of tab to modify and display
+ @param text text for tab
+ @param icon icon for tab
+ @return None
+ """
+ self.setTabText(index, text)
+ self.setTabIcon(index, icon)
+ self.setCurrentIndex(index)

Modified: trunk/profit/lib/widgets/ui_extendedshell.ui
==============================================================================
--- trunk/profit/lib/widgets/ui_extendedshell.ui (original)
+++ trunk/profit/lib/widgets/ui_extendedshell.ui Tue Aug 12 01:32:07 2008
@@ -62,7 +62,7 @@
</spacer>
</item>
<item>
- <widget class="QToolButton" name="toolButton" >
+ <widget class="QPushButton" name="executeButton" >
<property name="text" >
<string>Execute</string>
</property>
@@ -70,11 +70,8 @@
<iconset resource="profit.qrc" >

<normaloff>:/images/icons/misc.png</normaloff>:/images/icons/misc.png</iconset>
</property>
- <property name="shortcut" >
- <string>Ctrl+E</string>
- </property>
- <property name="toolButtonStyle" >
- <enum>Qt::ToolButtonTextBesideIcon</enum>
+ <property name="flat" >
+ <bool>true</bool>
</property>
</widget>
</item>
@@ -85,15 +82,6 @@
</widget>
</item>
</layout>
- <action name="actionExecute" >
- <property name="icon" >
- <iconset resource="profit.qrc" >
-
<normaloff>:/images/icons/misc.png</normaloff>:/images/icons/misc.png</iconset>
- </property>
- <property name="text" >
- <string>Execute</string>
- </property>
- </action>
</widget>
<customwidgets>
<customwidget>
@@ -112,22 +100,5 @@
<resources>
<include location="profit.qrc" />
</resources>
- <connections>
- <connection>
- <sender>toolButton</sender>
- <signal>clicked()</signal>
- <receiver>actionExecute</receiver>
- <slot>trigger()</slot>
- <hints>
- <hint type="sourcelabel" >
- <x>355</x>
- <y>363</y>
- </hint>
- <hint type="destinationlabel" >
- <x>-1</x>
- <y>-1</y>
- </hint>
- </hints>
- </connection>
- </connections>
+ <connections/>
</ui>

Added: trunk/profit/lib/widgets/ui_localtableviewframe.ui
==============================================================================
--- (empty file)
+++ trunk/profit/lib/widgets/ui_localtableviewframe.ui Tue Aug 12 01:32:07
2008
@@ -0,0 +1,51 @@
+<ui version="4.0" >
+ <class>LocalTableViewFrame</class>
+ <widget class="QFrame" name="LocalTableViewFrame" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTableView" name="tableView" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="alternatingRowColors" >
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior" >
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="gridStyle" >
+ <enum>Qt::DotLine</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

Modified: trunk/profit/lib/widgets/ui_plot.ui
==============================================================================
--- trunk/profit/lib/widgets/ui_plot.ui (original)
+++ trunk/profit/lib/widgets/ui_plot.ui Tue Aug 12 01:32:07 2008
@@ -52,6 +52,9 @@
</widget>
</item>
<item>
+ <widget class="QTreeView" name="controlsView" />
+ </item>
+ <item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
@@ -81,6 +84,9 @@
<iconset resource="profit.qrc" >

<normaloff>:/images/icons/kchart.png</normaloff>:/images/icons/kchart.png</iconset>
</property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
@@ -91,6 +97,9 @@
<property name="icon" >
<iconset resource="profit.qrc" >

<normaloff>:/images/icons/kcontrol.png</normaloff>:/images/icons/kcontrol.png</iconset>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
</property>
</widget>
</item>

Modified: trunk/profit/models/histdata.py
==============================================================================
--- trunk/profit/models/histdata.py (original)
+++ trunk/profit/models/histdata.py Tue Aug 12 01:32:07 2008
@@ -12,18 +12,28 @@
## TODO: add the incoming requests to the parent session's extra
## object list.

+## Note: these classes have intentionally simple names. Clients
+## should use the alias HistDataRequestModel instead of RequestModel.

-##
-## First is the parent model and it's items.
-##
+## This is what the hist data request looks like, as returned from
+## the request dialog:
+#
+# params = {'endDateTime': '20080707 08:00:00',
+# 'durationStr': '2 D',
+# 'whatToShow': 'TRADES',
+# 'contract': <ib.ext.Contract.Contract object at 0x8dd8f0c>,
+# 'barSizeSetting': '1 min',
+# 'formatDate': 1,
+# 'tickerId': 1146,
+# 'useRTH': 1}

-class HistDataRequestModel(BasicItemModel):
- """ HistDataRequestModel -> logical parent of individual hist data
models
+
+class RequestModel(BasicItemModel):
+ """ RequestModel -> models historical data requests

This class receives, queues, and submits historical data requests.
As new requests are received (or when un-requested historical data
- messages are received), instances create child models of type
HistDataModel.
-
+ messages are received), instances create child models of type SubModel.
"""
def __init__(self, session=None, parent=None):
""" Initializer.
@@ -31,11 +41,12 @@
@param session=None session reference or None
@param parent=None ancestor of this object or None
"""
- BasicItemModel.__init__(self, RootHistDataRequestItem(), parent)
+ BasicItemModel.__init__(self, RootRequestItem(), parent)
self.session = session
if session is not None:
session.registerMeta(self)
- self.startTimer(1000)
+ self.busy = False
+ self.startTimer(1500)

def data(self, index, role):
""" Framework hook to retreive data stored at index for given role.
@@ -49,138 +60,220 @@
item = index.internalPointer()
data = QVariant()
column = index.column()
- if role == Qt.DecorationRole and column==2:
+ if role == Qt.DecorationRole and column==item.symbolColumnolumn:
data = QVariant(self.symbolIcon(item.symbol()))
elif role in (Qt.DisplayRole, Qt.ToolTipRole):
data = QVariant(item[column])
- elif role in (Qt.TextAlignmentRole, ):
- try:
- float(item[column])
- data = QVariant(valueAlign)
- except (TypeError, ValueError, ):
- pass
return data

- def findHistDataRequest(self, reqId):
+ def findItem(self, requestId):
""" Returns the item for the given hist data message, or None.

+ @param requestId historical data request id
+ @return item or None
"""
- items = self.invisibleRootItem.children
- try:
- return [i for i in items if i.reqId==reqId][0]
- except (IndexError, ):
- pass
+ for item in iter(self.invisibleRootItem.children):
+ if item.requestId==requestId:
+ return item
+
+ def iterrows(self, *requestIds):
+ children = self.invisibleRootItem.children
+ for sub in [c for c in children if c.requestId in requestIds]:
+ for item in sub.model.invisibleRootItem.children:
+ yield item.data
+
+ def on_session_Error(self, message):
+ """ Matches error messages to the requests in this model.
+
+ @param message ib.opt.message instance
+ """
+ item = self.findItem(message.id)
+ if item:
+ item[item.statusColumn] = 'Error: %s' % message.errorMsg
+ index = QModelIndex()
+ col = item.statusColumn
+ row = item.row()
+ index = self.index(row, col, QModelIndex())
+ self.emit(Signals.dataChanged, index, index)

def on_session_HistoricalData(self, message):
""" Called when the session receives a HistoricalData message.

@param message ib.opt.message instance
+ @return None
"""
- reqId = message.reqId
- item = self.findHistDataRequest(reqId)
+ requestId = message.reqId
+ item = self.findItem(requestId)
if item:
+ row, col = item.row(), item.statusColumn
if message.date.startswith('finished-'):
- item[1] = 'Finished'
- self.reset()
+ item[col] = 'Finished'
+ else:
+ item[col] = 'Receiving'
+ index = self.index(row, col, QModelIndex())
+ self.emit(Signals.dataChanged, index, index)
else:
root = self.invisibleRootItem
- root.append(HistDataRequestItem.fromMessage(reqId, message,
root, {}))
- ## cheater
- self.reset()
+ row = root.childCount()
+ self.beginInsertRows(QModelIndex(), row, row)
+ root.append(RequestItem.fromMessage(message, self.session,
root))
+ self.endInsertRows()

def on_session_historicalDataRequest(self, params):
""" Called when a request for historical data is made.

+ @param params historical data request parameters
+ @return None
"""
- reqId = params['tickerId']
- requests = self.requests
- if reqId in requests:
- logging.warn('Ignoring duplicate hist data request %s', reqId)
- return
- requests[reqId] = params.copy()
+ requestId = params['tickerId']
root = self.invisibleRootItem
- root.append(HistDataRequestItem.fromRequest(reqId, params, root))
- self.reset()
+ requests = [r.requestId for r in root.children]
+ if requestId in requests:
+ logging.warn('Ignoring duplicate hist data request %s',
requestId)
+ return
+ row = root.childCount()
+ self.beginInsertRows(QModelIndex(), row, row)
+ root.append(RequestItem.fromRequest(params, self.session, root))
+ self.endInsertRows()

+ def subModel(self, requestId):
+ """ Returns the submodel for the given request id or None

-class HistDataRequestItem(BasicItem):
- columnLookups = [
- ('Request Id', None),
- ('Status', None),
- ('Symbol', None),
- ('Security Type', None),
- ('Expiry', None),
- ('Right', None),
+ @param requestId historical data request id
+ @return submodel associated with request id or None
+ """
+ item = self.findItem(requestId)
+ return item.model if item else None
+
+ def next(self):
+ for item in iter(self.invisibleRootItem.children):
+ if item.queued:
+ return item
+
+ def timerEvent(self, event):
+ if not self.session.isConnected():
+ return
+ next = self.next()
+ if next:
+ self.session.connection.reqHistoricalData(**next.request)
+ next[next.statusColumn] = 'Requested'
+ next.queued = False
+ index = self.index(next.row(), next.statusColumn,
QModelIndex())
+ self.emit(Signals.dataChanged, index, index)
+
+
+class RequestItem(BasicItem):
+ """ RequestItem -> items for the hist data request model.
+
+ """
+ columnLabels = [
+ 'Request Id', 'Status', 'Symbol', 'Sec Type', 'Expiry', 'Right'
]
+ columnLookups = (
+ (requestColumn, requestLabel),
+ (statusColumn, statusLabel),
+ (symbolColumnolumn, symbolLabel),
+ (securityColumn, securityLabel),
+ (expireColumn, expireLabel),
+ (rightColumn, rightLabel)
+ ) = list(enumerate(columnLabels))

- def __init__(self, values, parent=None):
+ def __init__(self, values, requestId=None, request={}, model=None,
+ parent=None):
+ """ Initializer.
+
+ @param values sequence of values for this item
+ @param requestId=None historical data request id as int
+ @param request={} request parameters as dictionary
+ @param model=None data model with messages for this request
+ @param parent=None parent of this item
+ """
BasicItem.__init__(self, values, parent)
+ self.requestId = requestId
+ self.request = request
+ self.model = model
+ self.queued = False

@classmethod
- def fromRequest(cls, reqId, req, parent):
+ def fromMessage(cls, message, session, parent):
+ """ New instance from a historical data message.
+
+ @param cls class object
+ @param message ib.opt.message object
+ @param session session instance
+ @param parent parent of this item
+ @return new instance of cls
+ """
+ requestId = message.reqId
+ request = {}
values = [None for i in cls.columnLookups]
- values[0] = reqId
- values[1] = 'Queued'
- item = cls(values, parent)
- item.reqId = reqId
- item.req = req
+ values[0] = requestId
+ values[1] = 'Loading'
+ ## without a request the other values can't be filled.
+ ## TODO: try to find a matching request in the session
+ submodel = SubModel(requestId, request, session)
+ item = cls(values, requestId, request, submodel, parent)
return item

@classmethod
- def fromMessage(cls, reqId, message, parent, req):
+ def fromRequest(cls, request, session, parent):
+ """ New instance from a historical data request.
+
+ @param cls class object
+ @param request dictionary of request parameters
+ @param session session instance
+ @param parent parent of this item
+ @return new instance of cls
+ """
+ requestId = request['tickerId']
+ contract = request['contract']
values = [None for i in cls.columnLookups]
- values[0] = reqId
+ values[0] = requestId
values[1] = 'Queued'
- item = cls(values, parent)
- item.reqId = reqId
- item.req = req
+ values[2] = contract.m_symbol
+ values[3] = contract.m_secType
+ ## the other values aren't set in the contract -- dialog is
incomplete
+ ## TODO: complete the dialog
+ submodel = SubModel(requestId, request, session)
+ item = cls(values, requestId, request, submodel, parent)
+ item.queued = True
return item

def symbol(self):
""" Returns the symbol for this item or ''

"""
- try:
- return self.message.contract.m_symbol
- except (AttributeError, ):
- return ''
+ contract = self.request.get('contract')
+ return contract.m_symbol if contract else ''

-class RootHistDataRequestItem(HistDataRequestItem):
- def __init__(self):
- HistDataRequestItem.__init__(self, self.horizontalLabels())

- def horizontalLabels(self):
- """ Generates list of horizontal header values.
+class RootRequestItem(RequestItem):
+ """ RootRequestItem -> an item class for the root of the request view.

- """
- return map(QVariant, [label for label, lookup in
self.columnLookups])
+ """
+ def __init__(self):
+ """ Initializer.

+ """
+ RequestItem.__init__(self, map(QVariant, self.columnLabels))

-##
-## Next is the model and items for an individual request and it's messages.
-##

-class HistDataModel(BasicItemModel):
- """ HistDataModel -> model of hist data requests and responses
+class SubModel(BasicItemModel):
+ """ SubModel -> model of hist data requests and responses

- This model supports online and offline processing of messages. In
- the case of missing requests (as in when messages are read from
- disk), the model simply fills in what it can. In the case where
- the model is given a request, it enqueues the request with the
- session and then associates the responses accordingly.
"""
- def __init__(self, session=None, parent=None):
+ def __init__(self, requestId, request, session=None, parent=None):
""" Initializer.

@param session=None session reference or None
@param parent=None ancestor of this object or None
"""
- BasicItemModel.__init__(self, RootHistDataItem(), parent)
- self.requests = {}
+ BasicItemModel.__init__(self, RootSubItem(), parent)
+ self.requestId = requestId
+ self.request = request
self.session = session
if session is not None:
session.registerMeta(self)
- self.startTimer(1000)

def data(self, index, role):
""" Framework hook to retreive data stored at index for given role.
@@ -194,15 +287,8 @@
item = index.internalPointer()
data = QVariant()
column = index.column()
- amChild = index.parent().isValid()
- if role == Qt.DecorationRole and column==2:
- if not amChild:
- data = QVariant(self.symbolIcon(item.symbol()))
- elif role in (Qt.DisplayRole, Qt.ToolTipRole):
- if amChild and (column==0):
- data = QVariant(item.row())
- else:
- data = QVariant(item[column])
+ if role in (Qt.DisplayRole, Qt.ToolTipRole):
+ data = QVariant(item[column])
elif role in (Qt.TextAlignmentRole, ):
try:
float(item[column])
@@ -211,86 +297,30 @@
pass
return data

- def findHistDataItem(self, reqId):
- """ Returns the item for the given hist data message, or None.
-
- """
- items = self.invisibleRootItem.children
- try:
- return [i for i in items if i.reqId==reqId][0]
- except (IndexError, ):
- pass
-
def on_session_HistoricalData(self, message):
""" Called when the session receives a HistoricalData message.

@param message ib.opt.message instance
"""
- reqId = message.reqId
- req = self.requests.get(reqId, {})
- item = self.findHistDataItem(reqId)
- if item:
- item.append(HistDataItem.fromMessage(reqId, message, item,
req))
- if message.date.startswith('finished'):
- item.setStatus('Finished')
- self.emit(Signals.histdata.finish, reqId)
- else:
- root = self.invisibleRootItem
- root.append(HistDataItem.fromMessage(reqId, message, root,
req))
- self.emit(Signals.histdata.start, reqId)
- ## cheater
- self.reset()
-
- def on_session_historicalDataRequest(self, params):
- """ Called when a request for historical data is made.
-
- """
- reqId = params['tickerId']
- requests = self.requests
- if reqId in requests:
- logging.warn('Ignoring duplicate hist data request %s', reqId)
+ requestId = message.reqId
+ if requestId != self.requestId:
return
- requests[reqId] = params.copy()
+ request = self.request
root = self.invisibleRootItem
- root.append(HistDataItem.fromRequest(reqId, params, root))
- self.reset()
-
- def busy(self):
- for item in iter(self.invisibleRootItem.children):
- if item[1] == States.active:
- return True
-
- def next(self):
- for item in iter(self.invisibleRootItem.children):
- if item[1] == States.unsubmitted and item.req:
- return item
-
- def timerEvent(self, event):
- if not self.session.isConnected() or self.busy():
- return
- next = self.next()
- if next:
- self.session.connection.reqHistoricalData(**next.req)
-
+ if message.date.startswith('finished'):
+ self.emit(Signals.histdata.finish, requestId)
+ row = root.childCount()
+ self.beginInsertRows(QModelIndex(), row, row)
+ root.append(SubItem.fromMessage(requestId, request, message, root))
+ self.endInsertRows()

-class States(object):
- unsubmitted, active, finished, errored = range(4)
- labelMap = {
- unsubmitted:'Unsubmitted',
- active:'Active',
- finished:'Finished',
- errored:'Errored',
- }

-
-class HistDataItem(BasicItem):
+class SubItem(BasicItem):
""" Base class for items in the portfolio model.

"""
columnLookups = [
('Request Id', lambda x:x.reqId),
- ('Status', lambda x:x.request.status),
- ('Symbol', lambda x:x.request.contract.symbol),
('Date', lambda x:x.date),
('Open', lambda x:x.open),
('High', lambda x:x.high),
@@ -302,35 +332,22 @@
('Has Gaps', lambda x:x.hasGaps),
]

- def __init__(self, data, parent=None, message=None,
- reqId=None,
- req={},
- state=States.unsubmitted):
- BasicItem.__init__(self, data, parent)
- self.message = message
- self.reqId = reqId
- self.req = req
- self.state = state
-
- def setStatus(self, text):
- self.data[1] = text
-
- @classmethod
- def fromRequest(cls, requestId, params, parent):
- """ New instance from a request
+ def __init__(self, values, requestId, request, message, parent=None):
+ """ Initializer.

- @param cls class object
- @param requestId client identifier for request as int
- @param params request parameter as dictionary
- @param parent parent of this item
- @return new instance of cls
+ @param values sequence of data for this item
+ @param requestId historical data request id as int
+ @param request request parameters as dictionary
+ @param message ib.opt.message object
+ @param parent=None parent of this item
"""
- values = [None for item in cls.columnLookups]
- values[0] = requestId
- return cls(values, parent, None, requestId, params.copy())
+ BasicItem.__init__(self, values, parent)
+ self.requestId = requestId
+ self.request = request
+ self.message = message

@classmethod
- def fromMessage(cls, requestId, message, parent, request):
+ def fromMessage(cls, requestId, request, message, parent):
""" New instance from message values

@param cls class object
@@ -346,53 +363,24 @@
except (AttributeError, ):
value = None
values.append(value)
- item = cls(values, parent, message, requestId, request)
+ item = cls(values, requestId, request, message, parent)
if message.date.startswith('finished-'):
- parent.data[1] = item.data[1] =
States.labelMap[States.finished]
- item[2:] = [None for i in item[2:]]
+ item[1] = item[1][len('finished-'):]
return item

- def symbol(self):
- """ Returns the symbol for this item or ''
-
- """
- try:
- return self.message.contract.m_symbol
- except (AttributeError, ):
- return ''
-
- def update(self, message):
- """ Update the item with values from a message.
-
- @param message ib.opt.message object
- @return None
- """
- for column, (label, lookup) in enumerate(self.columnLookups):
- try:
- self[column] = lookup(message)
- except (AttributeError, ):
- pass

-
-class RootHistDataItem(HistDataItem):
+class RootSubItem(SubItem):
""" HistData model item with automatic values (for horizontal headers).

"""
def __init__(self):
- HistDataItem.__init__(self, self.horizontalLabels())
-
- def horizontalLabels(self):
- """ Generates list of horizontal header values.
+ """ Initializer.

"""
- return map(QVariant, [label for label, lookup in
self.columnLookups])
+ labels = map(QVariant, [i[0] for i in self.columnLookups])
+ SubItem.__init__(self, labels, None, None, None)


-## params = {'endDateTime': '20080707 08:00:00',
-## 'durationStr': '2 D',
-## 'whatToShow': 'TRADES',
-## 'contract': <ib.ext.Contract.Contract object at 0x8dd8f0c>,
-## 'barSizeSetting': '1 min',
-## 'formatDate': 1,
-## 'tickerId': 1146,
-## 'useRTH': 1}
+## clients should use this alias
+#
+HistDataRequestModel = RequestModel

Added: trunk/profit/models/seriesitem.py
==============================================================================
--- (empty file)
+++ trunk/profit/models/seriesitem.py Tue Aug 12 01:32:07 2008
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2007 Troy Melhase <tr...@gci.net>
+# Distributed under the terms of the GNU General Public License v2
+
+from PyQt4.QtCore import Qt, QModelIndex, QVariant, QString
+from profit.lib import maybeFloat, valueAlign
+from profit.models import BasicItem, BasicItemModel
+
+
+class SeriesItemModel(BasicItemModel):
+ """
+
+ """
+ def __init__(self, session=None, parent=None):
+ BasicItemModel.__init__(self, RootSeriesItem(), parent)
+ self.session = session
+ if session is not None:
+ session.registerMeta(self)
+
+ def data(self, index, role):
+ """
+
+ """
+ if not index.isValid():
+ return QVariant()
+ item = index.internalPointer()
+ data = QVariant()
+ column = index.column()
+ if role == Qt.DisplayRole:
+ data = item[column]
+ elif role == Qt.ToolTipRole:
+ data = item[column]
+ elif role == Qt.DecorationRole and column==0:
+ data = item.colorIcon()
+ elif role == Qt.CheckStateRole and column==0 and item.checkable:
+ data = item.checked
+ elif role in (Qt.TextAlignmentRole, ):
+ data = maybeFloat(item[column], Qt.AlignRight|Qt.AlignVCenter)
+ return QVariant(data)
+
+
+ def flags(self, index):
+ if not index.isValid():
+ return QVariant()
+ item = index.internalPointer()
+ flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+ if item.column==0 and item.checkable:
+ flags |= Qt.ItemIsEditable | Qt.ItemIsUserCheckable
+ return flags
+
+ def findItem(self, key):
+ """ Returns the item for the given contract, or None.
+
+ """
+ items = self.invisibleRootItem.children
+ try:
+ return [i for i in items if i.message.key==key][0]
+ except (IndexError, ):
+ pass
+
+
+class SeriesItem(BasicItem):
+ """ Base class for items in the account model.
+
+ """
+ columnLookups = [
+ ('Series', lambda x:x.key),
+ ('Value', lambda x:x.value),
+ ]
+
+ def __init__(self, data, parent=None):
+ BasicItem.__init__(self, data, parent)
+ self.checkable = False
+ self.checked = False
+ self.color = None
+ self.curve = None
+
+
+class RootSeriesItem(SeriesItem):
+ """ SeriesItem model item with automatic values (for horizontal
headers).
+
+ """
+ def __init__(self):
+ SeriesItem.__init__(self, self.horizontalLabels())
+
+ def horizontalLabels(self):
+ """ Generates list of horizontal header values.
+
+ """
+ return map(QVariant, [label for label, lookup in
self.columnLookups])

Modified: trunk/profit/models/strategy.py
==============================================================================
--- trunk/profit/models/strategy.py (original)
+++ trunk/profit/models/strategy.py Tue Aug 12 01:32:07 2008
@@ -24,7 +24,7 @@
self.session = session
if session is not None:
session.registerMeta(self)
- self.reflectSignal(Signals.strategy.requestActivate)
+ self.reflectSignals(Signals.strategy.requestActivate)
self.readSettings()

def data(self, index, role=Qt.DisplayRole):

Modified: trunk/profit/models/tickers.py
==============================================================================
--- trunk/profit/models/tickers.py (original)
+++ trunk/profit/models/tickers.py Tue Aug 12 01:32:07 2008
@@ -168,7 +168,7 @@
columnLookups = list(extraFieldSpecs()) + list(fieldSpecs())
valueLookups = {
ExtraFields.tid : lambda m:m.tickerId,
- ## tie value lookups to the portfolio model ????
+ ## TODO: tie value lookups to the portfolio model
ExtraFields.sym : lambda m:None,
ExtraFields.pos : lambda m:None,
ExtraFields.val : lambda m:None,

Modified: trunk/profit/session/__init__.py
==============================================================================
--- trunk/profit/session/__init__.py (original)
+++ trunk/profit/session/__init__.py Tue Aug 12 01:32:07 2008
@@ -32,7 +32,6 @@
def __init__(self, session):
self.account = collection.AccountCollection(session)
self.ticker = collection.TickerCollection(session)
- self.historical = collection.HistoricalDataCollection(session)


class DataModels(object):

Modified: trunk/profit/strategy/builder.py
==============================================================================
--- trunk/profit/strategy/builder.py (original)
+++ trunk/profit/strategy/builder.py Tue Aug 12 01:32:07 2008
@@ -40,7 +40,7 @@
self.isActive = self.loadMessage = False
self.threads = []
self.tickers = []
- self.reflectSignal(Signals.contract.created)
+ self.reflectSignals(Signals.contract.created)
app = instance()
if app:
connect = self.connect

Modified: trunk/profit/workbench/centraltabs.py
==============================================================================
--- trunk/profit/workbench/centraltabs.py (original)
+++ trunk/profit/workbench/centraltabs.py Tue Aug 12 01:32:07 2008
@@ -13,12 +13,12 @@

from profit.lib import importItem, logging
from profit.lib import BasicHandler, Signals, DataRoles, instance
-from profit.lib.gui import makeUrlItem
+from profit.lib.gui import makeUrlItem, symbolIcon
from profit.lib.widgets.localtabwidget import LocalTabWidget


class CentralTabs(LocalTabWidget, BasicHandler):
- """ CentralTabs -> tab widget with special powers
+ """ CentralTabs -> tab widget with extra special powers

"""
def __init__(self, parent=None):
@@ -30,12 +30,13 @@
self.createHandlers = [
self.createBrowserTab,
self.createTickerPlotTab,
+ self.createTickerPlotFromView,
self.createDisplayTab
]
- app, connect = instance(), self.connect
- connect(app, Signals.itemActivated, self.createTab)
- connect(app, Signals.openUrl, self.createTab)
- connect(app, Signals.tickerClicked, self.createTab)
+ app, connect, createTab = instance(), self.connect, self.createTab
+ connect(app, Signals.itemActivated, createTab)
+ connect(app, Signals.openUrl, createTab)
+ connect(app, Signals.tickerClicked, createTab)
self.requestSession()

def createTab(self, value):
@@ -49,7 +50,8 @@
if handler(value):
break
except (Exception, ), exc:
- logging.debug("Exception (debug): %r:%s (h:%s)", exc, exc,
handler, )
+ msg = 'Exception (debug): %r:%s (h:%s)'
+ logging.debug(msg, exc, exc, handler, )

def createBrowserTab(self, item):
""" Creates a new web browser tab.
@@ -74,6 +76,36 @@
self.connect(widget, Signals.loadFinished, loadHandler)
return True

+ def createTickerPlotFromView(self, data):
+ """
+
+ """
+ from profit.workbench.tickerplotdisplay import TickerPlotDisplay
+ try:
+ tid, sym = data[0:2]
+ except (TypeError, ValueError, ):
+ return
+ sym = sym or self.symbolName(tid)
+ icon = symbolIcon(sym) if sym else
QIcon(':/images/icons/kchart.png')
+ sym = sym or '%s' % tid
+ widget = TickerPlotDisplay(self)
+ session = self.session
+ widget.setSessionPlot(session, session.maps.ticker, tid)
+ index = self.addTab(widget, sym)
+ self.setTextIconCurrentTab(index, sym, icon)
+ return True
+
+ def symbolName(self, tickerId):
+ """ Returns the symbol name given a ticker id.
+
+ This should reference self.session.models.contracts instead.
+ """
+ symbols = self.session.strategy.symbols()
+ try:
+ return dict([(b, a) for a, b in symbols.items()])[tickerId]
or ''
+ except (KeyError, ):
+ return ''
+
def createTickerPlotTab(self, item):
""" Creates or displays a ticker plot tab.

@@ -112,13 +144,6 @@
self.setTextIconCurrentTab(index, text, icon)
return True

- def pageMap(self):
- """ Makes a mapping like {'connection':1, 'account':3, ...}
-
- @return mapping of tab name to tab index
- """
- return dict([(str(self.tabText(i)), i) for i in
range(self.count())])
-
def resetBrowserTab(self, okay, browser=None):
""" Reconfigures a tab based on a web browser widget state.

@@ -134,26 +159,3 @@
title = title[0:13] + '...'
self.setTabText(index, title)
self.setTabToolTip(index, tooltip)
-
- def setTextIconCurrentTab(self, index, text, icon):
- """ Sets tab text and icon, and makes tab current.
-
- @param index index of tab to modify and display
- @param text text for tab
- @param icon icon for tab
- @return None
- """
- self.setTabText(index, text)
- self.setTabIcon(index, icon)
- self.setCurrentIndex(index)
-
- def setCurrentLabel(self, label):
- """ Sets current tab by name if possible.
-
- @param label text of tab to make current
- @return True if successful, otherwise None
- """
- index = self.pageMap().get(label)
- if index is not None:
- self.setCurrentIndex(index)
- return True

Modified: trunk/profit/workbench/historicaldatadisplay.py
==============================================================================
--- trunk/profit/workbench/historicaldatadisplay.py (original)
+++ trunk/profit/workbench/historicaldatadisplay.py Tue Aug 12 01:32:07 2008
@@ -4,36 +4,145 @@
# Copyright 2007 Troy Melhase <tr...@gci.net>
# Distributed under the terms of the GNU General Public License v2

-from PyQt4.QtGui import QFrame
-from profit.lib import BasicHandler
+import csv
+
+from PyQt4.QtCore import Qt, pyqtSignature
+from PyQt4.QtGui import QFileDialog, QFrame, QIcon
+
+from profit.lib import BasicHandler, Signals, defaults
from profit.lib.gui import symbolIcon
-from profit.workbench.widgets.ui_historicaldatadisplay import
Ui_HistoricalDataDisplay
+from profit.lib.widgets.historicaldatadialog import HistoricalDataDialog
+from profit.lib.widgets.ui_localtableviewframe import
Ui_LocalTableViewFrame
+from profit.workbench.widgets.ui_historicaldatadisplay import \
+ Ui_HistoricalDataDisplay


class HistoricalDataDisplay(QFrame, Ui_HistoricalDataDisplay,
BasicHandler):
+ """ HistoricalDataDisplay -> displays historical data requests, of
course.
+
+ """
def __init__(self, parent=None):
+ """ Initializer.
+
+ @param parent ancestor of this object
+ """
QFrame.__init__(self, parent)
self.setupUi(self)
+ self.splitter.restoreState(defaults.rightSplitterState())
+ self.requestTabs.closeTabButton.actionCloseTab.setShortcuts([])
+ self.requestTabs.detachTabButton.actionDetachTab.setShortcuts([])
self.requestSession()

def setSession(self, session):
+ """ Configures this instance for a session.
+
+ @param session Session instance
+ @return None
+ """
self.session = session
model = session.models.histdata
model.symbolIcon = symbolIcon
view = self.requestsView
view.verticalHeader().hide()
view.setModel(model)
+ self.connect(view.selectionModel(),
+ Signals.selectionChanged,
+ self.on_requestsView_selectionChanged)
session.registerMeta(self)

+ def on_session_HistoricalData(self, message):
+ self.requestsView.resizeColumnsToContents()
+ self.session.deregisterMeta(self)
+
+ def createTab(self, requestId):
+ """ Creates a new tab for the hist data request.
+
+ @param requestId hist data request identifier, int
+ @return None
+ """
+ tabs = self.requestTabs
+ name = '%s' % requestId
+ if tabs.setCurrentLabel(name):
+ return
+ title = 'Historical Data Request %s' % requestId
+ widget = DataView(requestId, title, tabs)
+ index = tabs.addTab(widget, name)
+ icon = QIcon(':images/icons/log.png')
+ tabs.setTextIconCurrentTab(index, name, icon)
+
+ @pyqtSignature('')
+ def on_exportButton_clicked(self):
+ """
+
+ """
+ filename = QFileDialog.getSaveFileName(self, 'Export Historical
Data')
+ if not filename:
+ return
+ writer = csv.writer(open(filename, 'wb'))
+ def iterIndexes():
+ for index in
self.requestsView.selectionModel().selectedIndexes():
+ model = index.model()
+ print '###', model
+ for row in model.iterrows():
+ yield row
+ writer.writerows(iterIndexes())
+
+ @pyqtSignature('')
+ def on_newRequestButton_clicked(self):
+ """ Shows new hist data request dialog and signal its results, if
any.
+
+ @return None
+ """
+ dlg = HistoricalDataDialog(self)
+ if dlg.exec_() != dlg.Accepted:
+ return
+ params = dlg.historicalRequestParameters()
+ self.session.emit(Signals.histdata.request, params)

def on_requestsView_doubleClicked(self, index):
+ """ Creates a new display tab when a request is double-clicked.
+
+ @return None
+ """
if not index.isValid():
return
reqId = index.internalPointer()[0]
- print '##', reqId
+ self.createTab(reqId)

+ def on_requestsView_selectionChanged(self, selected, deselected):
+ """ Enables or disables the export button as requests are selected.

+ @return None
+ """
+ selected =
bool(self.requestsView.selectionModel().selectedIndexes())
+ self.exportButton.setEnabled(selected)

- def createTab(self, requestId):
- pass

+class DataView(QFrame, Ui_LocalTableViewFrame, BasicHandler):
+ """ DataView -> viewer for a historical data message request
+
+ """
+ def __init__(self, requestId, title, parent=None):
+ """ Initializer.
+
+ @param requestId hist data request identifier, int
+ @param title window title for this widget, string
+ @param parent ancestor of this widget
+ """
+ QFrame.__init__(self, parent)
+ self.setupUi(self)
+ self.requestId = requestId
+ self.setWindowTitle(title)
+ self.requestSession()
+
+ def setSession(self, session):
+ """ Configures this instance for a session.
+
+ @param session Session instance
+ @return None
+ """
+ view = self.tableView
+ view.verticalHeader().hide()
+ model = session.models.histdata.subModel(self.requestId)
+ if model:
+ view.setModel(model)

Modified: trunk/profit/workbench/main.py
==============================================================================
--- trunk/profit/workbench/main.py (original)
+++ trunk/profit/workbench/main.py Tue Aug 12 01:32:07 2008
@@ -67,7 +67,6 @@
connect(app, Signals.session.request, sessreq)
connect(app, Signals.lastWindowClosed, self.writeSettings)
connect(self, Signals.openUrl, app, Signals.openUrl)
- connect(self, Signals.histdata.request, app,
Signals.histdata.request)
connect(self, Signals.session.created, app,
Signals.session.created)
connect(self, Signals.settingsChanged, self.setupColors)
connect(self, Signals.settingsChanged, self.setupSysTray)
@@ -182,16 +181,6 @@
@pyqtSignature('')
def on_actionBrowserTwsHome_triggered(self):
self.emit(Signals.openUrl, self.twsUrl)
-
- @pyqtSignature('')
- def on_actionHistoricalData_triggered(self):
- from profit.lib.widgets.historicaldatadialog import
HistoricalDataDialog
- dlg = HistoricalDataDialog(self)
- if dlg.exec_() != dlg.Accepted:
- return
- params = dlg.historicalRequestParameters()
- ## cheater!
- self.session.emit(Signals.histdata.request, params)

@pyqtSignature('')
def on_actionExportSession_triggered(self, filename=None):

Modified: trunk/profit/workbench/tickerdisplay.py
==============================================================================
--- trunk/profit/workbench/tickerdisplay.py (original)
+++ trunk/profit/workbench/tickerdisplay.py Tue Aug 12 01:32:07 2008
@@ -45,9 +45,13 @@
defaultFields = defaults.tickerDisplayFields()
userFields = settings.valueLoad('selectedFields', defaultFields)
#self.tickFieldSelect.setCheckedFields(userFields)
+ #self.infoBar.barHelp.setText('Right click column headers to
select some.')
settings.endGroup()
- self.reflectSignal(Signals.openUrl)
- self.reflectSignal(Signals.tickerClicked)
+ self.reflectSignals(Signals.openUrl, Signals.tickerClicked)
+
+ def on_tickersView_doubleClick(self, index):
+ item = index.internalPointer()
+ self.emit(Signals.tickerClicked, item)

def setSession(self, session):
""" Configures this instance for a session.
@@ -62,6 +66,8 @@
model.valueBrushMap = ValueColorItem.compMap
view = self.tickersView
view.setModel(model)
+ connect(view, Signals.modelDoubleClicked,
+ self.on_tickersView_doubleClick)
header = view.header()
header.setContextMenuPolicy(Qt.ActionsContextMenu)
def makeActions():

Modified: trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui (original)
+++ trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui Tue Aug 12
01:32:07 2008
@@ -6,25 +6,28 @@
<x>0</x>
<y>0</y>
<width>553</width>
- <height>161</height>
+ <height>206</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
<item>
<widget class="QSplitter" name="splitter" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
- <widget class="QWidget" name="" >
+ <widget class="QWidget" name="layoutWidget" >
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="QTableView" name="requestsView" >
- <property name="frameShape" >
- <enum>QFrame::NoFrame</enum>
- </property>
<property name="editTriggers" >
<set>QAbstractItemView::NoEditTriggers</set>
</property>
@@ -61,9 +64,33 @@
</spacer>
</item>
<item>
- <widget class="QPushButton" name="pushButton" >
+ <widget class="QPushButton" name="newRequestButton" >
+ <property name="text" >
+ <string>New...</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="../../lib/widgets/profit.qrc" >
+
<normaloff>:/images/icons/filenew.png</normaloff>:/images/icons/filenew.png</iconset>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="exportButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
<property name="text" >
- <string>New Request...</string>
+ <string>Export...</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="../../lib/widgets/profit.qrc" >
+
<normaloff>:/images/icons/filesaveas.png</normaloff>:/images/icons/filesaveas.png</iconset>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
</property>
</widget>
</item>
@@ -72,40 +99,12 @@
</layout>
</widget>
<widget class="LocalTabWidget" name="requestTabs" >
+ <property name="tabPosition" >
+ <enum>QTabWidget::South</enum>
+ </property>
<property name="currentIndex" >
- <number>0</number>
+ <number>-1</number>
</property>
- <widget class="QWidget" name="protoTab" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>174</width>
- <height>114</height>
- </rect>
- </property>
- <attribute name="title" >
- <string>Tab 1</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_3" >
- <item>
- <widget class="QTableView" name="histDataView" />
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_2" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>174</width>
- <height>114</height>
- </rect>
- </property>
- <attribute name="title" >
- <string>Tab 2</string>
- </attribute>
- </widget>
</widget>
</widget>
</item>
@@ -119,6 +118,8 @@
<container>1</container>
</customwidget>
</customwidgets>
- <resources/>
+ <resources>
+ <include location="../../lib/widgets/profit.qrc" />
+ </resources>
<connections/>
</ui>

Modified: trunk/profit/workbench/widgets/ui_main.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_main.ui (original)
+++ trunk/profit/workbench/widgets/ui_main.ui Tue Aug 12 01:32:07 2008
@@ -49,8 +49,6 @@
</property>
<addaction name="actionStrategyDesigner" />
<addaction name="actionSettings" />
- <addaction name="separator" />
- <addaction name="actionHistoricalData" />
</widget>
<widget class="QMenu" name="menuHelp" >
<property name="title" >
@@ -310,11 +308,6 @@
</property>
<property name="text" >
<string>Status Bar</string>
- </property>
- </action>
- <action name="actionHistoricalData" >
- <property name="text" >
- <string>Historical Data...</string>
</property>
</action>
<action name="actionProfitPyHome" >

Modified: trunk/profit/workbench/widgets/ui_strategydisplay.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_strategydisplay.ui (original)
+++ trunk/profit/workbench/widgets/ui_strategydisplay.ui Tue Aug 12
01:32:07 2008
@@ -158,6 +158,9 @@
<iconset resource="../../lib/widgets/profit.qrc" >

<normaloff>:/images/icons/kedit.png</normaloff>:/images/icons/kedit.png</iconset>
</property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
@@ -172,6 +175,9 @@
<iconset resource="../../lib/widgets/profit.qrc" >

<normaloff>:/images/icons/editdelete.png</normaloff>:/images/icons/editdelete.png</iconset>
</property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
@@ -182,6 +188,9 @@
<property name="icon" >
<iconset resource="../../lib/widgets/profit.qrc" >

<normaloff>:/images/icons/filenew.png</normaloff>:/images/icons/filenew.png</iconset>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
</property>
</widget>
</item>

Modified: trunk/profit/workbench/widgets/ui_tickerdisplay.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_tickerdisplay.ui (original)
+++ trunk/profit/workbench/widgets/ui_tickerdisplay.ui Tue Aug 12 01:32:07
2008
@@ -14,22 +14,6 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
- <widget class="InfoBar" name="frame_2" >
- <property name="sizePolicy" >
- <sizepolicy vsizetype="Minimum" hsizetype="Preferred" >
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="frameShape" >
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow" >
- <enum>QFrame::Raised</enum>
- </property>
- </widget>
- </item>
- <item>
<widget class="QFrame" name="frame" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
@@ -113,12 +97,6 @@
<class>FilterBar</class>
<extends>QWidget</extends>
<header location="global" >profit.lib.widgets.filterbar.h</header>
- </customwidget>
- <customwidget>
- <class>InfoBar</class>
- <extends>QFrame</extends>
- <header location="global" >profit.lib.widgets.infobar.h</header>
- <container>1</container>
</customwidget>
</customwidgets>
<resources/>

Reply all
Reply to author
Forward
0 new messages