Modified:
trunk/profit/lib/models/messages.py
trunk/profit/lib/widgets/messagetypeselect.py
trunk/profit/lib/widgets/ui_messagetypeselect.ui
trunk/profit/workbench/messagedisplay.py
trunk/profit/workbench/widgets/ui_messagedisplay.ui
Log:
Reworked message display ui. Added QSortFilterProxy subclass to
implement filtering by message type.
Modified: trunk/profit/lib/models/messages.py
==============================================================================
--- trunk/profit/lib/models/messages.py (original)
+++ trunk/profit/lib/models/messages.py Thu Jul 24 02:16:24 2008
@@ -51,8 +51,11 @@
"""
self.messageCount += 1
count = self.messageCount
- self.beginInsertRows(QModelIndex(), count, count)
- self.endInsertRows()
+ ## this doesn't work with the filter model; causes segfaults:
+ #self.beginInsertRows(QModelIndex(), count, count)
+ #self.endInsertRows()
+ ## temporary:
+ self.reset()
def data(self, index, role):
""" Framework hook to determine data stored at index for given role.
Modified: trunk/profit/lib/widgets/messagetypeselect.py
==============================================================================
--- trunk/profit/lib/widgets/messagetypeselect.py (original)
+++ trunk/profit/lib/widgets/messagetypeselect.py Thu Jul 24 02:16:24 2008
@@ -1,69 +1,68 @@
-#!/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, pyqtSignature
-from PyQt4.QtCore import QAbstractTableModel, QSize, QVariant, Qt
-from PyQt4.QtGui import QApplication, QFrame, QStandardItemModel, 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 import message
-
-
-class MessageTypeSelect(QFrame, Ui_MessageTypeSelect):
- """ Widget for selecting various IB message types.
-
- """
- def __init__(self, parent=None):
- """ Constructor.
-
- @param parent ancestor object
- """
- QFrame.__init__(self, parent)
- self.setupUi(self)
- self.populateTypeList()
-
- def listItems(self):
- listWidget = self.typesList
- return [listWidget.item(r) for r in range(listWidget.count())]
-
- def populateTypeList(self):
- listWidget = self.typesList
- listWidget.clear()
- self.allTypeNames = [c.typeName for c in message.registry.values()]
- for row, typeName in enumerate(sorted(self.allTypeNames)):
- listWidget.addItem(typeName)
- item = listWidget.item(row)
- item.setCheckState(Qt.Checked)
-
- def selectedTypes(self):
- if self.allCheck.checkState()==Qt.Checked:
- return self.allTypeNames
- return [str(i.text()) for i in self.listItems()
- if i.checkState()==Qt.Checked]
-
- @pyqtSignature('')
- def on_checkNoneButton_clicked(self):
- for item in self.listItems():
- item.setCheckState(Qt.Unchecked)
-
- @pyqtSignature('')
- def on_checkAllButton_clicked(self):
- for item in self.listItems():
- item.setCheckState(Qt.Checked)
-
-
-if __name__ == '__main__':
- import sys
- app = QApplication([])
- win = MessageTypeSelect()
- win.show()
- sys.exit(app.exec_())
+#!/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, pyqtSignature
+from PyQt4.QtCore import QAbstractTableModel, QSize, QVariant, Qt
+from PyQt4.QtGui import QApplication, QFrame, QStandardItemModel, 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
+
+
+class MessageTypeSelect(QFrame, Ui_MessageTypeSelect):
+ """ Widget for selecting various IB message types.
+
+ """
+ def __init__(self, parent=None):
+ """ Initializer.
+
+ @param parent ancestor object
+ """
+ QFrame.__init__(self, parent)
+ self.setupUi(self)
+ self.populateTypeList()
+
+ def listItems(self):
+ listWidget = self.typesList
+ return [listWidget.item(r) for r in range(listWidget.count())]
+
+ 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)
+
+ def selectedTypes(self):
+ if self.allCheck.checkState()==Qt.Checked:
+ return self.allTypeNames
+ return [str(i.text()) for i in self.listItems()
+ if i.checkState()==Qt.Checked]
+
+ @pyqtSignature('')
+ def on_checkNoneButton_clicked(self):
+ for item in self.listItems():
+ item.setCheckState(Qt.Unchecked)
+
+ @pyqtSignature('')
+ def on_checkAllButton_clicked(self):
+ 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/ui_messagetypeselect.ui
==============================================================================
--- trunk/profit/lib/widgets/ui_messagetypeselect.ui (original)
+++ trunk/profit/lib/widgets/ui_messagetypeselect.ui Thu Jul 24
02:16:24 2008
@@ -14,16 +14,6 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
- <widget class="QCheckBox" name="allCheck" >
- <property name="text" >
- <string>All Message Types</string>
- </property>
- <property name="checked" >
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
<widget class="QLabel" name="typesListText" >
<property name="enabled" >
<bool>false</bool>
@@ -54,6 +44,16 @@
<property name="margin" >
<number>0</number>
</property>
+ <item>
+ <widget class="QCheckBox" name="allCheck" >
+ <property name="text" >
+ <string>All Message Types</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QPushButton" name="checkAllButton" >
<property name="enabled" >
Modified: trunk/profit/workbench/messagedisplay.py
==============================================================================
--- trunk/profit/workbench/messagedisplay.py (original)
+++ trunk/profit/workbench/messagedisplay.py Thu Jul 24 02:16:24 2008
@@ -6,9 +6,10 @@
from time import ctime
-from PyQt4.QtCore import pyqtSignature
+from PyQt4.QtCore import Qt, QVariant, pyqtSignature
from PyQt4.QtGui import (QBrush, QColor, QColorDialog, QIcon, QFrame,
- QMenu, QTableWidgetItem, )
+ QMenu, QTableWidgetItem, QSortFilterProxyModel)
+
from ib.opt.message import messageTypeNames
@@ -19,6 +20,17 @@
from profit.workbench.widgets.ui_messagedisplay import Ui_MessageDisplay
+class TypesFilter(QSortFilterProxyModel):
+ def __init__(self, session, acceptTypes=[], parent=None):
+ QSortFilterProxyModel.__init__(self, parent)
+ self.messagesBare = session.messagesBare
+ self.acceptTypes = acceptTypes
+
+ def filterAcceptsRow(self, row, parent):
+ msg = self.messagesBare[row]
+ return msg.typeName in self.acceptTypes
+
+
class MessageDisplay(QFrame, Ui_MessageDisplay, SessionHandler,
SettingsHandler):
""" Table view of session messages with nifty controls.
@@ -35,7 +47,7 @@
}
def __init__(self, parent=None):
- """ Constructor.
+ """ Initializer.
@param parent ancestor of this widget
"""
@@ -53,48 +65,76 @@
settings = self.settings
settings.beginGroup(settings.keys.messages)
- self.setupColorButton()
- self.setupDisplayButton()
+ self.setupColors()
self.splitter.restoreState(defaults.rightMainSplitterState())
self.requestSession()
- def setupColorButton(self):
+ @pyqtSignature('int')
+ def on_allCheck_stateChanged(self, state):
+ try:
+ filterModel = self.filterModel
+ except (AttributeError, ):
+ # not initialized yet
+ return
+ if state:
+ filterModel.acceptTypes = list(self.colorTypes)
+ else:
+ types = self.messageTypeDisplay.selectedTypes()
+ filterModel.acceptTypes = types
+ filterModel.reset()
+
+ @pyqtSignature('')
+ def on_checkNoneButton_clicked(self):
+ self.filterModel.acceptTypes = []
+ self.filterModel.reset()
+
+ @pyqtSignature('')
+ def on_checkAllButton_clicked(self):
+ ## should swap out model
+ self.filterModel.acceptTypes = list(self.colorTypes)
+ self.filterModel.reset()
+
+ def on_typesList_itemChanged(self, item):
+ try:
+ filterModel = self.filterModel
+ except (AttributeError, ):
+ # not initialized yet
+ 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()
+
+ def on_typesList_itemDoubleClicked(self, item):
+ color = QColor(item.data(Qt.DecorationRole))
+ color = QColorDialog.getColor(color, 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.settings.setValue('%s/color' % item.text(), color)
+
+ def setupColors(self):
""" Configures the color highlight button.
@return None
"""
- self.colorPop = pop = QMenu(self.colorButton)
- self.colorButton.setMenu(pop)
self.colorTypes = messageTypeNames()
- self.colorActions = actions = \
- [pop.addAction(v) for v in sorted(self.colorTypes)]
- getv = self.settings.value
- defc = QColor(0,0,0)
- for action in actions:
- actc = getv('%s/color' % action.text(), defc)
- action.color = color = QColor(actc)
- action.setIcon(colorIcon(color))
- self.connect(action, Signals.triggered, self.on_colorChange)
- self.brushMap.update(
- dict([(str(a.text()), QBrush(a.color)) for a in actions])
- )
-
- def setupDisplayButton(self):
- """ Configures the display types button.
-
- @return None
- """
- self.displayPop = pop = QMenu(self.displayButton)
- self.displayButton.setMenu(pop)
- self.displayActions = actions = []
- allAction = pop.addAction('All')
- actions.append(allAction)
- pop.addSeparator()
- actions.extend([pop.addAction(v) for v in sorted(self.displayTypes)])
- for action in actions:
- action.setCheckable(True)
- self.connect(action, Signals.triggered, self.on_displayChange)
- allAction.setChecked(True)
+ getValue = self.settings.value
+ defaultColor = QColor(0,0,0)
+ for name in self.colorTypes:
+ self.brushMap[name] = getValue('%s/color' % name, defaultColor)
+ items = self.messageTypeDisplay.listItems()
+ for item in items:
+ color = QColor(self.brushMap[str(item.text())])
+ item.setData(Qt.DecorationRole, QVariant(color))
+ item.setIcon(colorIcon(color))
def setSession(self, session):
""" Configures this instance for a session.
@@ -105,13 +145,16 @@
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.messageTable.setModel(model)
- #session.registerAll(self.messageTable, Slots.scrollToBottom)
+ self.messageTable.setModel(self.filterModel)
+ if 0:
+ session.registerAll(self.messageTable, Slots.scrollToBottom)
def on_messageTable_clicked(self, index):
row = index.row()
- mtime, msg = index.model().message(row)
+ mtime, msg = self.model.message(row) ## WRONG
tbl = self.messageDetail
tbl.clearContents()
items = [('index', row),
@@ -123,78 +166,6 @@
tbl.setItem(idx, 0, QTableWidgetItem(name))
tbl.setItem(idx, 1, QTableWidgetItem(str(value)))
- def on_colorChange(self):
- """ Signal handler for color change actions.
-
- @return None
- """
- action = self.sender()
- color = QColorDialog.getColor(action.color, self)
- if color.isValid():
- action.color = color
- action.setIcon(colorIcon(color))
- self.brushMap[str(action.text())] = QBrush(color)
- self.model.reset()
- self.settings.setValue('%s/color' % action.text(), color)
-
- def on_displayChange(self):
- """ Signal handler for display types actions.
-
- @return None
- """
- action = self.sender()
- index = self.displayActions.index(action)
- allAction = self.displayActions[0]
- allChecked = allAction.isChecked()
- actionChecked = action.isChecked()
- if allChecked and action is not allAction:
- allAction.setChecked(False)
- self.displayTypes.clear()
- self.displayTypes.add(str(action.text()))
- #self.model.enableTypesFilter(self.displayTypes)
- ## add proxy and one regex
- if 0:
- self.proxyModel = MessagesFilterModel(self)
- self.proxyModel.setSourceModel(self.model)
- self.proxyModel.setFilterKeyColumn(2) # type
- self.proxyModel.setFilterRegExp(action.text())
- self.messageTable.setModel(self.proxyModel)
-
- elif allChecked and action is allAction:
- self.displayTypes.clear()
- self.displayTypes.update(messageTypeNames())
- for act in self.displayActions[1:]:
- act.setChecked(False)
- self.model.disableTypesFilter()
- if 0:
- self.messageTable.setModel(self.model)
- if self.proxyModel is not None:
- proxyModel = self.proxyModel
- proxyModel.deleteLater()
- self.proxyModel = None
-
- elif not allChecked and action is not allAction:
- text = str(action.text())
- if actionChecked:
- self.displayTypes.add(text)
- #self.model.enableTypesFilter(self.displayTypes)
- if 0:
- ## add text to proxy regex
- self.proxyModel.setFilterRegExp(
- self.proxyModel.filterRegExp().pattern() + '|'
+ text
- )
- else:
- self.displayTypes.discard(text)
- #self.model.enableTypesFilter(self.displayTypes)
- ## remove text from proxy regex
- if 0:
- pattern = self.proxyModel.filterRegExp().pattern()
- pattern.remove(text + '|')
- print '## pattern:', pattern
- self.proxyModel.setFilterRegExp(pattern)
- self.model.reset()
-
- @pyqtSignature('bool')
def on_pauseButton_clicked(self, checked=False):
""" Signal handler for pause button.
@@ -209,4 +180,3 @@
## session.registerAll(self.messageTable, Slots.scrollToBottom)
self.pauseButton.setText(self.pauseButtonText[checked])
self.pauseButton.setIcon(QIcon(self.pauseButtonIcons[checked]))
-
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
02:16:24 2008
@@ -5,48 +5,44 @@
<rect>
<x>0</x>
<y>0</y>
- <width>623</width>
- <height>299</height>
+ <width>669</width>
+ <height>511</height>
</rect>
</property>
<property name="windowTitle" >
<string>Message Display</string>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_3" >
- <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 class="QHBoxLayout" name="horizontalLayout_2" >
<item>
<widget class="QSplitter" name="splitter" >
- <property name="sizePolicy" >
- <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
- <horstretch>0</horstretch>
- <verstretch>3</verstretch>
- </sizepolicy>
- </property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
- <widget class="QFrame" name="frame_2" >
- <property name="frameShape" >
- <enum>QFrame::NoFrame</enum>
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="tabPosition" >
+ <enum>QTabWidget::South</enum>
</property>
- <property name="frameShadow" >
- <enum>QFrame::Plain</enum>
+ <property name="currentIndex" >
+ <number>1</number>
</property>
- <layout class="QVBoxLayout" name="verticalLayout" >
- <item>
- <widget class="QSplitter" name="splitter_2" >
- <property name="orientation" >
- <enum>Qt::Vertical</enum>
- </property>
+ <widget class="QWidget" name="propertyTab" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>334</width>
+ <height>459</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Properties</string>
+ </attribute>
+ <attribute name="icon" >
+ <iconset resource="../../lib/widgets/profit.qrc" >
+ <normaloff>:/images/icons/view_text.png</normaloff>:/images/icons/view_text.png</iconset>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
<widget class="QTableWidget" name="messageDetail" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
@@ -54,9 +50,18 @@
<verstretch>3</verstretch>
</sizepolicy>
</property>
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="alternatingRowColors" >
+ <bool>true</bool>
+ </property>
<property name="selectionMode" >
<enum>QAbstractItemView::SingleSelection</enum>
</property>
+ <property name="gridStyle" >
+ <enum>Qt::DashLine</enum>
+ </property>
<column>
<property name="text" >
<string>Property</string>
@@ -68,75 +73,71 @@
</property>
</column>
</widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="displayTab" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>334</width>
+ <height>459</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Display</string>
+ </attribute>
+ <attribute name="icon" >
+ <iconset resource="../../lib/widgets/profit.qrc" >
+ <normaloff>:/images/icons/display.png</normaloff>:/images/icons/display.png</iconset>
+ </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="enabled" >
- <bool>false</bool>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
</property>
</widget>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout" >
- <item>
- <widget class="QPushButton" name="displayButton" >
- <property name="contextMenuPolicy" >
- <enum>Qt::DefaultContextMenu</enum>
- </property>
- <property name="text" >
- <string>Display</string>
- </property>
- <property name="icon" >
- <iconset resource="../../lib/widgets/profit.qrc" >
- <normaloff>:/images/icons/filter.png</normaloff>:/images/icons/filter.png</iconset>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="colorButton" >
- <property name="text" >
- <string>Highlight</string>
- </property>
- <property name="icon" >
- <iconset resource="../../lib/widgets/profit.qrc" >
- <normaloff>:/images/icons/colorize.png</normaloff>:/images/icons/colorize.png</iconset>
- </property>
- </widget>
- </item>
- <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>
- <spacer name="horizontalSpacer" >
- <property name="orientation" >
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0" >
- <size>
- <width>13</width>
- <height>24</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
+ </item>
+ </layout>
+ </widget>
</widget>
- <widget class="QFrame" name="frame" >
+ <widget class="QFrame" name="messageTableFrame" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
<horstretch>0</horstretch>