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

1 view
Skip to first unread message

codesite...@google.com

unread,
Jul 31, 2008, 1:34:42 PM7/31/08
to profitp...@googlegroups.com
Author: troy.melhase
Date: Thu Jul 24 17:28:43 2008
New Revision: 307

Modified:
trunk/profit/lib/core.py
trunk/profit/lib/models/messages.py
trunk/profit/lib/widgets/messagetypeselect.py
trunk/profit/lib/widgets/searchbar.py
trunk/profit/lib/widgets/ui_searchbar.ui
trunk/profit/workbench/messagedisplay.py
trunk/profit/workbench/widgets/ui_messagedisplay.ui

Log:
Added text filtering to message display.

Modified: trunk/profit/lib/core.py
==============================================================================
--- trunk/profit/lib/core.py (original)
+++ trunk/profit/lib/core.py Thu Jul 24 17:28:43 2008
@@ -41,6 +41,7 @@
dialogFinished = SIGNAL('finished(int)')
disconnectedTWS = SIGNAL('disconnectedTWS')
doubleValueChanged = SIGNAL('valueChanged(double)')
+ editingFinished = SIGNAL('editingFinished()')
enableCurve = SIGNAL('enableCurve')
finished = SIGNAL('finished()')
headerDataChanged = SIGNAL('headerDataChanged(Qt::Orientation,
int, int)')

Modified: trunk/profit/lib/models/messages.py
==============================================================================
--- trunk/profit/lib/models/messages.py (original)
+++ trunk/profit/lib/models/messages.py Thu Jul 24 17:28:43 2008
@@ -14,6 +14,7 @@

"""
columnTitles = ['Index', 'Time', 'Type', 'Fields']
+ sync = True

def __init__(self, session, brushes, parent=None):
""" Constructor.
@@ -55,7 +56,8 @@
#self.beginInsertRows(QModelIndex(), count, count)
#self.endInsertRows()
## temporary:
- self.reset()
+ if self.sync:
+ self.reset()

def data(self, index, role):
""" Framework hook to determine data stored at index for given role.
@@ -106,37 +108,24 @@
"""
return len(self.columnTitles)

+ def setSync(self, sync):
+ """

- ## crufty crufty
-
- def setPaused(self, paused):
- """ Pauses or resumes signals emitted from this model.
-
- @param paused if True, disconnects from session, otherwise reconnects
+ @param sync if True, model is reset after messages received
@return None
"""
- session = self.session
- regcall = session.deregisterAll if paused else session.registerAll
- regcall(self.on_sessionMessage)
+ self.sync = sync
+ if sync:
+ self.reset()

def __insertRows(self, row, count, parent=QModelIndex()):
self.beginInsertRows(parent, row, row+count-1)
self.endInsertRows()
return True

+ ## crufty crufty
def message(self, idx):
return self.messages[idx]
-
- def __enableTypesFilter(self, types):
- self.messageTypes = list(types)
- self.messagesReference = list(
- m for m in self.messages if m[1].typeName in types)
- self.reset()
-
- def __disableTypesFilter(self):
- self.messageTypes = []
- self.messagesReference = self.messages
- self.reset()


def messageRow(index, mtuple, model):

Modified: trunk/profit/lib/widgets/messagetypeselect.py
==============================================================================
--- trunk/profit/lib/widgets/messagetypeselect.py (original)
+++ trunk/profit/lib/widgets/messagetypeselect.py Thu Jul 24 17:28:43 2008
@@ -5,20 +5,14 @@
# Distributed under the terms of the GNU General Public License v2

from PyQt4.QtCore import Qt, pyqtSignature
-from PyQt4.QtCore import QAbstractTableModel, QSize, QVariant, Qt
-from PyQt4.QtGui import QApplication, QFrame, QStandardItemModel, QStandardItem
+from PyQt4.QtGui import QFrame, QStandardItem

-from profit.lib.core import SessionHandler, Signals, valueAlign
-from profit.lib.gui import colorIcon, complementColor
-from profit.lib.series import Series
-from profit.lib.widgets.plot import PlotCurve, ControlTreeValueItem
-
-from profit.lib.widgets.ui_messagetypeselect import Ui_MessageTypeSelect
from ib.opt.message import messageTypeNames
+from profit.lib.widgets.ui_messagetypeselect import Ui_MessageTypeSelect


class MessageTypeSelect(QFrame, Ui_MessageTypeSelect):
- """ Widget for selecting various IB message types.
+ """ MessageTypeSelect -> widget for selecting various IB message types.

"""
def __init__(self, parent=None):
@@ -28,22 +22,31 @@
"""
QFrame.__init__(self, parent)
self.setupUi(self)
- self.populateTypeList()
+ self.setupTypesList()
+
+ def setupTypesList(self):
+ """ Clears and fills the types list.
+
+ """
+ typesList = self.typesList
+ typesList.clear()
+ self.allTypeNames = typeNames = messageTypeNames()
+ for typeRow, typeName in enumerate(sorted(typeNames)):
+ typesList.addItem(typeName)
+ item = typesList.item(typeRow)
+ item.setCheckState(Qt.Checked)

def listItems(self):
- listWidget = self.typesList
- return [listWidget.item(r) for r in range(listWidget.count())]
+ """ Returns the QStandardItems in the types list.

- def populateTypeList(self):
+ """
listWidget = self.typesList
- listWidget.clear()
- self.allTypeNames = messageTypeNames()
- for row, typeName in enumerate(sorted(self.allTypeNames)):
- listWidget.addItem(typeName)
- item = listWidget.item(row)
- item.setCheckState(Qt.Checked)
+ return [listWidget.item(r) for r in range(listWidget.count())]

def selectedTypes(self):
+ """ Returns list of seleected type names (as strings)
+
+ """
if self.allCheck.checkState()==Qt.Checked:
return self.allTypeNames
return [str(i.text()) for i in self.listItems()
@@ -51,18 +54,16 @@

@pyqtSignature('')
def on_checkNoneButton_clicked(self):
+ """ Unchecks every item in the types list.
+
+ """
for item in self.listItems():
item.setCheckState(Qt.Unchecked)

@pyqtSignature('')
def on_checkAllButton_clicked(self):
+ """ Checks every item in the types list.
+
+ """
for item in self.listItems():
item.setCheckState(Qt.Checked)
-
-
-if __name__ == '__main__':
- import sys
- app = QApplication([])
- win = MessageTypeSelect()
- win.show()
- sys.exit(app.exec_())

Modified: trunk/profit/lib/widgets/searchbar.py
==============================================================================
--- trunk/profit/lib/widgets/searchbar.py (original)
+++ trunk/profit/lib/widgets/searchbar.py Thu Jul 24 17:28:43 2008
@@ -7,6 +7,7 @@
from PyQt4.QtCore import pyqtSignature
from PyQt4.QtGui import QWidget

+from profit.lib.core import Signals
from profit.lib.widgets.ui_searchbar import Ui_SearchBar


@@ -29,6 +30,7 @@
@return None
"""
self.searchEdit.clear()
+ self.searchEdit.emit(Signals.editingFinished)

def on_searchEdit_textChanged(self, text):
""" signal handler called when line edit text changed

Modified: trunk/profit/lib/widgets/ui_searchbar.ui
==============================================================================
--- trunk/profit/lib/widgets/ui_searchbar.ui (original)
+++ trunk/profit/lib/widgets/ui_searchbar.ui Thu Jul 24 17:28:43 2008
@@ -1,9 +1,6 @@
<ui version="4.0" >
<class>SearchBar</class>
<widget class="QWidget" name="SearchBar" >
- <property name="enabled" >
- <bool>false</bool>
- </property>
<property name="geometry" >
<rect>
<x>0</x>
@@ -46,7 +43,7 @@
<item>
<widget class="QLineEdit" name="searchEdit" >
<property name="text" >
- <string>this search feature is not implemented yet</string>
+ <string/>
</property>
</widget>
</item>

Modified: trunk/profit/workbench/messagedisplay.py
==============================================================================
--- trunk/profit/workbench/messagedisplay.py (original)
+++ trunk/profit/workbench/messagedisplay.py Thu Jul 24 17:28:43 2008
@@ -7,44 +7,88 @@
from time import ctime

from PyQt4.QtCore import Qt, QVariant, pyqtSignature
-from PyQt4.QtGui import (QBrush, QColor, QColorDialog, QIcon, QFrame,
- QMenu, QTableWidgetItem, QSortFilterProxyModel)

+from PyQt4.QtGui import (QBrush, QColor, QColorDialog, QIcon, QFrame,
+ QSortFilterProxyModel, QTableWidgetItem, )

from ib.opt.message import messageTypeNames

from profit.lib import defaults
-from profit.lib.core import SessionHandler, SettingsHandler, Signals, Slots
+from profit.lib.core import SessionHandler, SettingsHandler, Slots
from profit.lib.gui import colorIcon
from profit.lib.models.messages import MessagesTableModel
from profit.workbench.widgets.ui_messagedisplay import Ui_MessageDisplay


-class TypesFilter(QSortFilterProxyModel):
- def __init__(self, session, acceptTypes=[], parent=None):
+class MessagesFilter(QSortFilterProxyModel):
+ """ MessagesFilter -> proxy model for filtering a message model by types
+
+ """
+ def __init__(self, messages, parent=None):
+ """ Initializer.
+
+ @param messages sequence of broker messages
+ @param parent ancestor object
+ """
QSortFilterProxyModel.__init__(self, parent)
- self.messagesBare = session.messagesBare
- self.acceptTypes = acceptTypes
+ self.acceptTypes = None
+ self.messages = messages

def filterAcceptsRow(self, row, parent):
- msg = self.messagesBare[row]
- return msg.typeName in self.acceptTypes
+ """ Framework hook to filter rows.
+
+ @param row source model rown number
+ @param parent QModelIndex instance
+ @return True if row should be included in view
+ """
+ baseAccepts = QSortFilterProxyModel.filterAcceptsRow(self,
row, parent)
+ if self.acceptTypes is None:
+ return True and baseAccepts
+ msg = self.messages[row]
+ return msg.typeName in self.acceptTypes and baseAccepts
+
+ def includeAll(self):
+ """ Sets filter to accept all message types.
+
+ """
+ self.acceptTypes = None
+ self.reset()
+
+ def includeTypes(self, *names):
+ """ Sets filter to include specified message types.
+
+ """
+ if self.acceptTypes is None:
+ self.acceptTypes = []
+ for name in names:
+ if name not in self.acceptTypes:
+ self.acceptTypes.append(name)
+ self.reset()
+
+ def excludeAll(self):
+ """ Sets filter to reject all message types.

+ """
+ self.acceptTypes = []
+ self.reset()

-class MessageDisplay(QFrame, Ui_MessageDisplay, SessionHandler,
- SettingsHandler):
- """ Table view of session messages with nifty controls.
+ def excludeTypes(self, *names):
+ """ Sets filter to reject specified message types.
+
+ """
+ if self.acceptTypes is None:
+ self.acceptTypes = []
+ for name in names:
+ if name in self.acceptTypes:
+ self.acceptTypes.remove(name)
+ self.reset()
+
+
+class MessageDisplay(QFrame, Ui_MessageDisplay, SessionHandler, SettingsHandler):
+ """ MessageDisplay -> table view of session messages with nifty controls

"""
- pauseButtonIcons = {
- True:':/images/icons/player_play.png',
- False:':/images/icons/player_pause.png',
- }
-
- pauseButtonText = {
- True:'Resume',
- False:'Pause',
- }
+ filterModel = None

def __init__(self, parent=None):
""" Initializer.
@@ -54,81 +98,86 @@
QFrame.__init__(self, parent)
self.setupUi(self)
self.brushMap = {}
- self.displayTypes = messageTypeNames()
-
+ self.messageTypeNames = messageTypeNames()
for widget in (self.messageTable, self.messageDetail):
widget.verticalHeader().hide()
- widget.verticalHeader().hide()
## widget is the messageDetail widget
horizHeader = widget.horizontalHeader()
horizHeader.setResizeMode(horizHeader.ResizeToContents)
-
settings = self.settings
settings.beginGroup(settings.keys.messages)
- self.setupColors()
self.splitter.restoreState(defaults.rightMainSplitterState())
+ self.setupColors()
self.requestSession()

+ def on_searchEdit_editingFinished(self):
+ self.filterModel.setFilterWildcard(self.searchBar.searchEdit.text())
+
+
@pyqtSignature('int')
def on_allCheck_stateChanged(self, state):
- try:
- filterModel = self.filterModel
- except (AttributeError, ):
- # not initialized yet
- return
+ """ Updates the filter model with all types or those checked.
+
+ @param state 0 if unchecked, 1 if checked
+ @return None
+ """
+ model = self.filterModel
if state:
- filterModel.acceptTypes = list(self.colorTypes)
+ model.includeAll()
else:
- types = self.messageTypeDisplay.selectedTypes()
- filterModel.acceptTypes = types
- filterModel.reset()
+ model.excludeAll()
+ model.includeTypes(*self.messageTypeDisplay.selectedTypes())

@pyqtSignature('')
def on_checkNoneButton_clicked(self):
- self.filterModel.acceptTypes = []
- self.filterModel.reset()
+ """ Updates the filter model to exclude all message types.
+
+ """
+ self.filterModel.excludeAll()

@pyqtSignature('')
def on_checkAllButton_clicked(self):
- ## should swap out model
- self.filterModel.acceptTypes = list(self.colorTypes)
- self.filterModel.reset()
+ """ Updates the filter model to include all message types.
+
+ """
+ self.filterModel.includeAll()

def on_typesList_itemChanged(self, item):
- try:
- filterModel = self.filterModel
- except (AttributeError, ):
- # not initialized yet
+ model = self.filterModel
+ if model is None:
return
- text = str(item.text())
- types = filterModel.acceptTypes
- checked = item.checkState()
- if checked and text not in types:
- types.append(text)
- filterModel.reset()
- elif checked and (text in types):
- types.remove(text)
- filterModel.reset()
+ call = model.includeTypes if item.checkState() else model.excludeTypes
+ call(str(item.text()))

def on_typesList_itemDoubleClicked(self, item):
- color = QColor(item.data(Qt.DecorationRole))
- color = QColorDialog.getColor(color, self)
+ """ Displays a dialog for selecting the color of a message type.
+
+ """
+ currentColor = QColor(item.data(Qt.DecorationRole))
+ color = QColorDialog.getColor(currentColor, self)
if color.isValid():
item.setData(Qt.DecorationRole, QVariant(color))
item.setIcon(colorIcon(color))
- self.brushMap[str(item.text())] = QBrush(color)
- self.model.reset()
+ self.brushMap[str(item.text())] = itemBrush = QBrush(color)
+ self.messagesModel.reset()
self.settings.setValue('%s/color' % item.text(), color)
+ messageDetail = self.messageDetail
+ typeItem = messageDetail.item(1, 1) # yuk
+ if typeItem.text() == item.text():
+ for row in range(messageDetail.rowCount()):
+ nameItem = messageDetail.item(row, 0)
+ valueItem = messageDetail.item(row, 1)
+ nameItem.setForeground(itemBrush)
+ valueItem.setForeground(itemBrush)

def setupColors(self):
""" Configures the color highlight button.

@return None
"""
- self.colorTypes = messageTypeNames()
getValue = self.settings.value
defaultColor = QColor(0,0,0)
- for name in self.colorTypes:
+ for name in self.messageTypeNames:
self.brushMap[name] = getValue('%s/color' % name, defaultColor)
items = self.messageTypeDisplay.listItems()
for item in items:
@@ -143,40 +192,41 @@
@return None
"""
self.session = session
- self.messages = session.messages
- self.model = model = MessagesTableModel(session,
self.brushMap, self)
- self.filterModel = TypesFilter(session, self.colorTypes, self)
- self.filterModel.setSourceModel(model)
- self.proxyModel = None
+ self.messagesModel = MessagesTableModel(session,
self.brushMap, self)
+ self.filterModel = MessagesFilter(session.messagesBare, self)
+ self.filterModel.setFilterKeyColumn(3)
+ self.filterModel.setSourceModel(self.messagesModel)
self.messageTable.setModel(self.filterModel)
if 0:
session.registerAll(self.messageTable, Slots.scrollToBottom)

def on_messageTable_clicked(self, index):
- row = index.row()
- mtime, msg = self.model.message(row) ## WRONG
- tbl = self.messageDetail
- tbl.clearContents()
- items = [('index', row),
- ('message type', type(msg).__name__),
- ('received time', ctime(mtime)), ]
- items += list(sorted(msg.items()))
- tbl.setRowCount(len(items))
- for idx, (name, value) in enumerate(items):
- tbl.setItem(idx, 0, QTableWidgetItem(name))
- tbl.setItem(idx, 1, QTableWidgetItem(str(value)))
+ """ Displays the message keys and values.

- def on_pauseButton_clicked(self, checked=False):
- """ Signal handler for pause button.
-
- @param checked toggled state of button
+ @param index QModelIndex instance; filterModel index, not messageModel.
@return None
"""
- #self.model.setPaused(checked)
- session = self.session
- ## if checked:
- ## session.deregisterAll(self.messageTable, Slots.scrollToBottom)
- ## else:
- ## session.registerAll(self.messageTable, Slots.scrollToBottom)
- self.pauseButton.setText(self.pauseButtonText[checked])
- self.pauseButton.setIcon(QIcon(self.pauseButtonIcons[checked]))
+ row = index.row()
+ messageIndex, validIndex = index.sibling(row, 0).data().toInt()
+ if not validIndex:
+ return
+ row = messageIndex
+ mtime, message = self.messagesModel.message(messageIndex)
+ messageDetail = self.messageDetail
+ messageDetail.clearContents()
+ typeName = message.typeName
+ items = [('index', row), ('type', typeName), ('received', ctime(mtime))]
+ items += list(sorted(message.items()))
+ messageDetail.setRowCount(len(items))
+ itemBrush = QBrush(self.brushMap[typeName])
+ for row, (name, value) in enumerate(items):
+ nameItem = QTableWidgetItem(name)
+ valueItem = QTableWidgetItem(str(value))
+ nameItem.setForeground(itemBrush)
+ valueItem.setForeground(itemBrush)
+ messageDetail.setItem(row, 0, nameItem)
+ messageDetail.setItem(row, 1, valueItem)
+
+ def on_syncSource_stateChanged(self, state):
+ self.messagesModel.setSync(bool(state))
+

Modified: trunk/profit/workbench/widgets/ui_messagedisplay.ui
==============================================================================
--- trunk/profit/workbench/widgets/ui_messagedisplay.ui (original)
+++ trunk/profit/workbench/widgets/ui_messagedisplay.ui Thu Jul 24
17:28:43 2008
@@ -30,8 +30,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>334</width>
- <height>459</height>
+ <width>321</width>
+ <height>457</height>
</rect>
</property>
<attribute name="title" >
@@ -60,7 +60,7 @@
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="gridStyle" >
- <enum>Qt::DashLine</enum>
+ <enum>Qt::DotLine</enum>
</property>
<column>
<property name="text" >
@@ -81,8 +81,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>334</width>
- <height>459</height>
+ <width>321</width>
+ <height>457</height>
</rect>
</property>
<attribute name="title" >
@@ -94,37 +94,6 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3" >
<item>
- <layout class="QHBoxLayout" name="horizontalLayout" >
- <item>
- <widget class="QPushButton" name="pauseButton" >
- <property name="text" >
- <string>Pause</string>
- </property>
- <property name="icon" >
- <iconset resource="../../lib/widgets/profit.qrc" >
- <normaloff>:/images/icons/player_pause.png</normaloff>:/images/icons/player_pause.png</iconset>
- </property>
- <property name="checkable" >
- <bool>true</bool>
- </property>
- <property name="checked" >
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="SearchBar" native="1" name="searchBar" >
- <property name="sizePolicy" >
- <sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
<widget class="MessageTypeSelect" native="1"
name="messageTypeDisplay" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
@@ -151,6 +120,30 @@
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QCheckBox" name="syncSource" >
+ <property name="text" >
+ <string>Sync</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="SearchBar" native="1" name="searchBar" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<widget class="QTableView" name="messageTable" >
<property name="sizePolicy" >

Reply all
Reply to author
Forward
0 new messages