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

1 view
Skip to first unread message

codesite...@google.com

unread,
Aug 8, 2008, 10:19:46 PM8/8/08
to profitp...@googlegroups.com
Author: troy.melhase
Date: Fri Aug 8 19:19:24 2008
New Revision: 329

Added:
trunk/profit/lib/widgets/localtabwidget.py (contents, props changed)
Removed:
trunk/profit/lib/widgets/localtable.py
Modified:
trunk/profit/lib/__init__.py
trunk/profit/models/histdata.py
trunk/profit/session/__init__.py
trunk/profit/workbench/centraltabs.py
trunk/profit/workbench/historicaldatadisplay.py
trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui

Log:
Work in progress on historical data display. Abstracted tab widget with
close/detach buttons.

Modified: trunk/profit/lib/__init__.py
==============================================================================
--- trunk/profit/lib/__init__.py (original)
+++ trunk/profit/lib/__init__.py Fri Aug 8 19:19:24 2008
@@ -29,15 +29,6 @@
format='%(asctime)s %(levelname)s %(message)s')


-def makeCheckNames(*names):
- def checkNames(obj):
- try:
- return obj.typeName in names
- except (AttributeError, ):
- return False
- return checkNames
-
-
def importName(name, reloaded=False):
""" import and return a module by name in dotted form


Added: trunk/profit/lib/widgets/localtabwidget.py
==============================================================================
--- (empty file)
+++ trunk/profit/lib/widgets/localtabwidget.py Fri Aug 8 19:19:24 2008
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2007 Troy Melhase
+# Distributed under the terms of the GNU General Public License v2
+# Author: Troy Melhase <tr...@gci.net>
+
+from sys import platform
+
+from PyQt4.QtCore import Qt, QTimer
+from PyQt4.QtGui import QTabWidget
+
+from profit.lib import Signals
+from profit.lib.gui import addCloseAction
+from profit.lib.widgets.buttons import CloseTabButton, DetachTabButton
+
+
+class LocalTabWidget(QTabWidget):
+ def __init__(self, parent=None):
+ QTabWidget.__init__(self, parent)
+ self.closeTabButton = CloseTabButton(self)
+ self.detachTabButton = DetachTabButton(self)
+ self.setCornerWidget(self.closeTabButton, Qt.TopRightCorner)
+ self.setCornerWidget(self.detachTabButton, Qt.TopLeftCorner)
+ connect = self.connect
+ connect(self.closeTabButton, Signals.clicked, self.closeTab)
+ connect(self.detachTabButton, Signals.clicked, self.detachTab)
+
+ def closeTab(self):
+ """ Closes the current tab.
+
+ """
+ index = self.currentIndex()
+ widget = self.widget(index)
+ if widget:
+ self.removeTab(index)
+ widget.setAttribute(Qt.WA_DeleteOnClose)
+ widget.close()
+
+ def closeTabs(self):
+ """ Closes all tabs.
+
+ """
+ while self.currentIndex() != -1:
+ self.closeTab()
+
+ def detachTab(self):
+ """ Deatches the current tab and makes it a top-level window.
+
+ @return None
+ """
+ index = self.currentIndex()
+ text = str(self.tabText(index))
+ widget = self.widget(index)
+ widget.setWindowIcon(self.tabIcon(index))
+ try:
+ widget.setWindowTitle(str(widget.windowTitle()) % text)
+ except (TypeError, ):
+ pass
+ addCloseAction(widget)
+ if platform.startswith('win'):
+ def show():
+ widget.setParent(QApplication.desktop())
+ widget.setWindowFlags(Qt.Dialog)
+ widget.show()
+ else:
+ def show():
+ widget.setParent(self.window())
+ widget.setWindowFlags(Qt.Window)
+ widget.show()
+ QTimer.singleShot(100, show)

Modified: trunk/profit/models/histdata.py
==============================================================================
--- trunk/profit/models/histdata.py (original)
+++ trunk/profit/models/histdata.py Fri Aug 8 19:19:24 2008
@@ -13,8 +13,155 @@
## object list.


-class HistoricalDataModel(BasicItemModel):
- """ HistoricalDataModel -> model of hist data requests and responses
+##
+## First is the parent model and it's items.
+##
+
+class HistDataRequestModel(BasicItemModel):
+ """ HistDataRequestModel -> logical parent of individual hist data
models
+
+ 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.
+
+ """
+ def __init__(self, session=None, parent=None):
+ """ Initializer.
+
+ @param session=None session reference or None
+ @param parent=None ancestor of this object or None
+ """
+ BasicItemModel.__init__(self, RootHistDataRequestItem(), parent)
+ 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.
+
+ @param index QModelIndex instance
+ @param role Qt.DisplayRole flags
+ @return QVariant instance
+ """
+ if not index.isValid():
+ return QVariant()
+ item = index.internalPointer()
+ data = QVariant()
+ column = index.column()
+ if role == Qt.DecorationRole and column==2:
+ 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):
+ """ 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
+ item = self.findHistDataRequest(reqId)
+ if item:
+ if message.date.startswith('finished-'):
+ item[1] = 'Finished'
+ self.reset()
+ else:
+ root = self.invisibleRootItem
+ root.append(HistDataRequestItem.fromMessage(reqId, message,
root, {}))
+ ## 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)
+ return
+ requests[reqId] = params.copy()
+ root = self.invisibleRootItem
+ root.append(HistDataRequestItem.fromRequest(reqId, params, root))
+ self.reset()
+
+
+class HistDataRequestItem(BasicItem):
+ columnLookups = [
+ ('Request Id', None),
+ ('Status', None),
+ ('Symbol', None),
+ ('Security Type', None),
+ ('Expiry', None),
+ ('Right', None),
+ ]
+
+ def __init__(self, values, parent=None):
+ BasicItem.__init__(self, values, parent)
+
+ @classmethod
+ def fromRequest(cls, reqId, req, parent):
+ values = [None for i in cls.columnLookups]
+ values[0] = reqId
+ values[1] = 'Queued'
+ item = cls(values, parent)
+ item.reqId = reqId
+ item.req = req
+ return item
+
+ @classmethod
+ def fromMessage(cls, reqId, message, parent, req):
+ values = [None for i in cls.columnLookups]
+ values[0] = reqId
+ values[1] = 'Queued'
+ item = cls(values, parent)
+ item.reqId = reqId
+ item.req = req
+ return item
+
+ def symbol(self):
+ """ Returns the symbol for this item or ''
+
+ """
+ try:
+ return self.message.contract.m_symbol
+ except (AttributeError, ):
+ return ''
+
+class RootHistDataRequestItem(HistDataRequestItem):
+ def __init__(self):
+ HistDataRequestItem.__init__(self, self.horizontalLabels())
+
+ def horizontalLabels(self):
+ """ Generates list of horizontal header values.
+
+ """
+ return map(QVariant, [label for label, lookup in
self.columnLookups])
+
+
+##
+## 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

This model supports online and offline processing of messages. In
the case of missing requests (as in when messages are read from
@@ -28,7 +175,7 @@
@param session=None session reference or None
@param parent=None ancestor of this object or None
"""
- BasicItemModel.__init__(self, RootHistoricalDataItem(), parent)
+ BasicItemModel.__init__(self, RootHistDataItem(), parent)
self.requests = {}
self.session = session
if session is not None:
@@ -83,13 +230,13 @@
req = self.requests.get(reqId, {})
item = self.findHistDataItem(reqId)
if item:
- item.append(HistoricalDataItem.fromMessage(reqId, message,
item, req))
+ 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(HistoricalDataItem.fromMessage(reqId, message,
root, req))
+ root.append(HistDataItem.fromMessage(reqId, message, root,
req))
self.emit(Signals.histdata.start, reqId)
## cheater
self.reset()
@@ -105,7 +252,7 @@
return
requests[reqId] = params.copy()
root = self.invisibleRootItem
- root.append(HistoricalDataItem.fromRequest(reqId, params, root))
+ root.append(HistDataItem.fromRequest(reqId, params, root))
self.reset()

def busy(self):
@@ -136,7 +283,7 @@
}


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

"""
@@ -227,12 +374,12 @@
pass


-class RootHistoricalDataItem(HistoricalDataItem):
- """ HistoricalData model item with automatic values (for horizontal
headers).
+class RootHistDataItem(HistDataItem):
+ """ HistData model item with automatic values (for horizontal headers).

"""
def __init__(self):
- HistoricalDataItem.__init__(self, self.horizontalLabels())
+ HistDataItem.__init__(self, self.horizontalLabels())

def horizontalLabels(self):
""" Generates list of horizontal header values.

Modified: trunk/profit/session/__init__.py
==============================================================================
--- trunk/profit/session/__init__.py (original)
+++ trunk/profit/session/__init__.py Fri Aug 8 19:19:24 2008
@@ -17,7 +17,7 @@

from profit.lib import Signals, logging
from profit.models.executions import ExecutionsModel
-from profit.models.histdata import HistoricalDataModel
+from profit.models.histdata import HistDataRequestModel
from profit.models.orders import OrdersModel
from profit.models.portfolio import PortfolioModel
from profit.models.strategy import StrategyModel
@@ -38,7 +38,7 @@
class DataModels(object):
def __init__(self, session):
self.executions = ExecutionsModel(session)
- self.histdata = HistoricalDataModel(session)
+ self.histdata = HistDataRequestModel(session)
self.orders = OrdersModel(session)
self.portfolio = PortfolioModel(session)
self.strategy = StrategyModel(session)

Modified: trunk/profit/workbench/centraltabs.py
==============================================================================
--- trunk/profit/workbench/centraltabs.py (original)
+++ trunk/profit/workbench/centraltabs.py Fri Aug 8 19:19:24 2008
@@ -8,16 +8,16 @@
from functools import partial
from sys import platform

-from PyQt4.QtCore import QTimer, QVariant, Qt, pyqtSignature
-from PyQt4.QtGui import QIcon, QTabWidget, QStandardItem
+from PyQt4.QtCore import Qt
+from PyQt4.QtGui import QIcon, QStandardItem

from profit.lib import importItem, logging
from profit.lib import BasicHandler, Signals, DataRoles, instance
-from profit.lib.gui import addCloseAction, makeUrlItem
-from profit.lib.widgets.buttons import CloseTabButton, DetachTabButton
+from profit.lib.gui import makeUrlItem
+from profit.lib.widgets.localtabwidget import LocalTabWidget


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

"""
@@ -26,22 +26,16 @@

@param parent ancestor of this widget
"""
- QTabWidget.__init__(self, parent)
+ LocalTabWidget.__init__(self, parent)
self.createHandlers = [
self.createBrowserTab,
self.createTickerPlotTab,
self.createDisplayTab
]
- self.closeTabButton = CloseTabButton(self)
- self.detachTabButton = DetachTabButton(self)
- self.setCornerWidget(self.closeTabButton, Qt.TopRightCorner)
- self.setCornerWidget(self.detachTabButton, Qt.TopLeftCorner)
app, connect = instance(), self.connect
connect(app, Signals.itemActivated, self.createTab)
connect(app, Signals.openUrl, self.createTab)
connect(app, Signals.tickerClicked, self.createTab)
- connect(self.closeTabButton, Signals.clicked, self.closeTab)
- connect(self.detachTabButton, Signals.clicked, self.detachTab)
self.requestSession()

def createTab(self, value):
@@ -124,50 +118,6 @@
@return mapping of tab name to tab index
"""
return dict([(str(self.tabText(i)), i) for i in
range(self.count())])
-
- def closeTab(self):
- """ Closes the current tab.
-
- """
- index = self.currentIndex()
- widget = self.widget(index)
- if widget:
- self.removeTab(index)
- widget.setAttribute(Qt.WA_DeleteOnClose)
- widget.close()
-
- def closeTabs(self):
- """ Closes all tabs.
-
- """
- while self.pageMap():
- self.closeTab()
-
- def detachTab(self):
- """ Deatches the current tab and makes it a top-level window.
-
- @return None
- """
- index = self.currentIndex()
- text = str(self.tabText(index))
- widget = self.widget(index)
- widget.setWindowIcon(self.tabIcon(index))
- try:
- widget.setWindowTitle(str(widget.windowTitle()) % text)
- except (TypeError, ):
- pass
- addCloseAction(widget)
- if platform.startswith('win'):
- def show():
- widget.setParent(QApplication.desktop())
- widget.setWindowFlags(Qt.Dialog)
- widget.show()
- else:
- def show():
- widget.setParent(self.window())
- widget.setWindowFlags(Qt.Window)
- widget.show()
- QTimer.singleShot(100, show)

def resetBrowserTab(self, okay, browser=None):
""" Reconfigures a tab based on a web browser widget state.

Modified: trunk/profit/workbench/historicaldatadisplay.py
==============================================================================
--- trunk/profit/workbench/historicaldatadisplay.py (original)
+++ trunk/profit/workbench/historicaldatadisplay.py Fri Aug 8 19:19:24 2008
@@ -4,13 +4,9 @@
# Copyright 2007 Troy Melhase <tr...@gci.net>
# Distributed under the terms of the GNU General Public License v2

-from itertools import ifilter
-
-from PyQt4.QtCore import Qt
-from PyQt4.QtGui import QFrame, QIcon
-
-from profit.lib import BasicHandler, makeCheckNames
-from profit.lib.gui import ValueTableItem, symbolIcon
+from PyQt4.QtGui import QFrame
+from profit.lib import BasicHandler
+from profit.lib.gui import symbolIcon
from profit.workbench.widgets.ui_historicaldatadisplay import
Ui_HistoricalDataDisplay


@@ -24,5 +20,20 @@
self.session = session
model = session.models.histdata
model.symbolIcon = symbolIcon
- self.histDataView.setModel(model)
+ view = self.requestsView
+ view.verticalHeader().hide()
+ view.setModel(model)
session.registerMeta(self)
+
+
+ def on_requestsView_doubleClicked(self, index):
+ if not index.isValid():
+ return
+ reqId = index.internalPointer()[0]
+ print '##', reqId
+
+
+
+ def createTab(self, requestId):
+ pass
+

Modified: trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui (original)
+++ trunk/profit/workbench/widgets/ui_historicaldatadisplay.ui Fri Aug 8
19:19:24 2008
@@ -5,41 +5,120 @@
<rect>
<x>0</x>
<y>0</y>
- <width>521</width>
- <height>407</height>
+ <width>553</width>
+ <height>161</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
- <layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>0</number>
- </property>
- <property name="margin" >
- <number>0</number>
- </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
- <widget class="QTreeView" name="histDataView" >
- <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="uniformRowHeights" >
- <bool>true</bool>
- </property>
- <property name="animated" >
- <bool>true</bool>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
</property>
+ <widget class="QWidget" name="" >
+ <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>
+ <property name="dragDropOverwriteMode" >
+ <bool>false</bool>
+ </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>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton" >
+ <property name="text" >
+ <string>New Request...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="LocalTabWidget" name="requestTabs" >
+ <property name="currentIndex" >
+ <number>0</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>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>LocalTabWidget</class>
+ <extends>QTabWidget</extends>
+ <header location="global" >profit.lib.widgets.localtabwidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>

Reply all
Reply to author
Forward
0 new messages