Example #1
0
 def setupSysTray(self):
     settings = Settings()
     settings.beginGroup(settings.keys.main)
     if settings.value('useSystemTrayIcon', QVariant(1)).toInt()[0]:
         icon = self.windowIcon()
         try:
             trayIcon = self.trayIcon
         except (AttributeError, ):
             self.trayIcon = trayIcon = QSystemTrayIcon(self)
             self.trayMenu = trayMenu = QMenu()
             trayIcon.setIcon(icon)
             trayMenu.addAction(icon, applicationName())
             trayMenu.addSeparator()
             for action in self.menuFile.actions():
                 trayMenu.addAction(action)
                 trayIcon.setContextMenu(trayMenu)
             self.connect(trayIcon, Signals.trayIconActivated,
                          self.on_trayIcon_activated)
         trayIcon.show()
     else:
         try:
             trayIcon = self.trayIcon
         except (AttributeError, ):
             pass
         else:
             trayIcon.hide()
Example #2
0
 def setupColors(self):
     settings = Settings()
     settings.beginGroup(settings.keys.appearance)
     cls = ValueColorItem
     keys = ['increaseColor', 'neutralColor', 'decreaseColor']
     attrs = [k.replace('Color', '') for k in keys]
     values = [QColor(settings.value(key, getattr(cls, attr)))
                  for key, attr in zip(keys, attrs)]
     cls.setColors(*values)
Example #3
0
    def __init__(self, parent=None):
        """ Initializer.

        @param parent ancestor of this widget
        """
        QFrame.__init__(self, parent)
        self.setupUi(self)
        self.settings = Settings()
        self.settings.beginGroup(self.settings.keys.plots)
        self.setupOptionsMenu()
        self.setupPlotsMenu()
        self.setupPlot()
Example #4
0
 def readSettings(self):
     settings = Settings()
     settings.beginGroup(settings.keys.main)
     size = settings.value(settings.keys.size,
                           defaults.windowSize).toSize()
     pos = settings.value(settings.keys.position,
                          defaults.windowPosition).toPoint()
     maxed = settings.value(settings.keys.maximized, False).toBool()
     self.resize(size)
     self.move(pos)
     if maxed:
         self.showMaximized()
     state = settings.value(settings.keys.winstate, QVariant())
     self.restoreState(state.toByteArray())
     settings.endGroup()
Example #5
0
    def readSettings(self):
        """ Reads selected keys from saved settings.

        @return None
        """
        settings = Settings()
        settings.beginGroup(settings.keys.account)
        keys = settings.value(self.settingKey)
        if keys.isValid():
            keys = [[str(b) for b in a.toStringList()] for a in keys.toList()]
        else:
            keys = self.defaultKeys
        setup = self.dataModel.setAccountKeyDisplay
        for key, currency in keys:
            setup(key, currency, True, self.summaryView)
Example #6
0
 def updateRecentSessions(self):
     settings = Settings()
     settings.beginGroup(settings.keys.main)
     files = settings.value('recentSessions').toStringList()
     files = set([abspath(str(s)) for s in files])
     files = list(files)
     count = min(len(files), self.maxRecentSessions)
     for i in range(count):
         text = files[i]
         action = self.recentSessionsActions[i]
         action.setText(basename(str(text)))
         action.setData(QVariant(text))
         action.setVisible(True)
     for i in range(count, self.maxRecentSessions):
         action = self.recentSessionsActions[i]
         action.setVisible(False)
     self.recentSeparator.setVisible(count > 0)
Example #7
0
 def setCurrentSession(self, filename):
     settings = Settings()
     settings.beginGroup(settings.keys.main)
     files = settings.value('recentSessions').toStringList()
     files.removeAll(filename)
     files.prepend(filename)
     files = files[:self.maxRecentSessions]
     settings.setValue('recentSessions', files)
     self.updateRecentSessions()
Example #8
0
    def setSessionPlot(self, session, collection, tickerId, *args):
        """ Associate a session with this instance.

        @param session Session instance
        @param tickerId id of ticker as integer
        @param *indexes unused
        @return None
        """
        self.sessionArgs = (session, collection, tickerId, args)
        if not self.plotWidgets:
            settings = Settings()
            settings.beginGroup("Plots")
            settings.beginGroup("%s" % tickerId)
            # count = settings.value('displaycount', QVariant(1)).toInt()[0]
            count = 1
            for i in range(count):
                self.addPlot()
        else:
            for plot in self.plotWidgets:
                plot.setSessionPlot(session, collection, tickerId, *args)
Example #9
0
    def __init__(self, parent=None):
        """ Initializer.

        @param parent ancestor of this widget
        """
        QFrame.__init__(self, parent)
        self.setupUi(self)
        self.settings = Settings()
        self.settings.beginGroup(self.settings.keys.plots)
        self.setupOptionsMenu()
        self.setupPlotsMenu()
        self.setupPlot()
Example #10
0
 def checkClose(self):
     check = True
     settings = Settings()
     settings.beginGroup(settings.keys.main)
     confirm = settings.value('confirmCloseWhenModified', QVariant(1))
     confirm = confirm.toInt()[0]
     if self.session.isModified() and confirm:
         buttons = QMessageBox.Save|QMessageBox.Discard|QMessageBox.Cancel
         text = 'This session has been modified'
         if self.session.isConnected():
             text += ' and is connected and receiving messages.'
         else:
             text += '.'
         text += '\n\nDo you want to save your changes?'
         msg = QMessageBox.question(
             self, applicationName(), text, buttons, QMessageBox.Save)
         if msg == QMessageBox.Discard:
             pass
         elif msg == QMessageBox.Cancel:
             check = False
         elif msg == QMessageBox.Save:
             self.actionSaveSession.trigger()
     return check
Example #11
0
    def saveSettings(self):
        """ Signal handler for last window closing.  Saves selected keys.

        @return None
        """
        settings = Settings()
        settings.beginGroup(settings.keys.account)
        keys = [QVariant([key, currency]) for (key, currency), item in
                    self.sharedKeys.items() if item is not None]
        settings.setValue(self.settingKey, keys)
Example #12
0
    def readSettings(self):
        """ Applies stored setting values to instance.

        @return None
        """
        self.settings = obj = Settings()
        obj.beginGroup(obj.keys.designer)
        self.resize(obj.value(obj.keys.size, defaults.windowSize).toSize())
        self.move(
            obj.value(obj.keys.position, defaults.windowPosition).toPoint())
        if obj.value(obj.keys.maximized, False).toBool():
            self.showMaximized()
        self.restoreState(
            obj.value(obj.keys.winstate, QVariant()).toByteArray())
        self.splitter.restoreState(
            obj.value(obj.keys.splitstate, QVariant()).toByteArray())
Example #13
0
 def on_actionStrategyDesigner_triggered(self):
     from profit.strategydesigner.main import StrategyDesigner
     settings = Settings()
     settings.beginGroup(settings.keys.strategy)
     if settings.value('type', '').toString()=='file':
         filename = settings.value('location', '').toString()
         def x(name):
             print '## strategy file named %s updated' % (name, )
     else:
         def x(name):
             print "## strategy file updated but i don't care"
         filename = None
     win = StrategyDesigner(filename=filename, parent=self)
     win.show()
Example #14
0
 def urlActions(self, symbol):
     settings = Settings()
     settings.beginGroup(settings.keys.urls)
     urls = settings.value(settings.keys.tickerurls, defaults.tickerUrls())
     settings.endGroup()
     urls = [str(s) for s in defaults.tickerUrls()]
     actions = []
     for url in urls:  #urls.toStringList():
         try:
             name, url = str(url).split(':', 1)
             url = Template(url).substitute(symbol=symbol)
         except (
                 KeyError,
                 ValueError,
         ):
             continue
         action = makeUrlAction(name, url, toolTip='%s %s' % (symbol, name))
         actions.append(action)
     return actions
Example #15
0
 def urlActions(self, symbol):
     settings = Settings()
     settings.beginGroup(settings.keys.urls)
     urls = settings.value(settings.keys.tickerurls, defaults.tickerUrls())
     settings.endGroup()
     urls = [str(s) for s in defaults.tickerUrls()]
     actions = []
     for url in urls: #urls.toStringList():
         try:
             name, url = str(url).split(':', 1)
             url = Template(url).substitute(symbol=symbol)
         except (KeyError, ValueError, ):
             continue
         action = makeUrlAction(name, url, toolTip='%s %s' % (symbol, name))
         actions.append(action)
     return actions
Example #16
0
    def setSessionPlot(self, session, collection, tickerId, *args):
        """ Associate a session with this instance.

        @param session Session instance
        @param tickerId id of ticker as integer
        @param *indexes unused
        @return None
        """
        self.sessionArgs = (session, collection, tickerId, args)
        if not self.plotWidgets:
            settings = Settings()
            settings.beginGroup('Plots')
            settings.beginGroup('%s' % tickerId)
            #count = settings.value('displaycount', QVariant(1)).toInt()[0]
            count = 1
            for i in range(count):
                self.addPlot()
        else:
            for plot in self.plotWidgets:
                plot.setSessionPlot(session, collection, tickerId, *args)
Example #17
0
 def on_actionClearRecentMenu_triggered(self, checked=False):
     for action in self.recentSessionsActions:
         action.setVisible(False)
     settings = Settings()
     settings.beginGroup(settings.keys.main)
     settings.remove('recentSessions')
Example #18
0
 def saveCount(self):
     settings = Settings()
     settings.beginGroup('Plots')
     settings.beginGroup('%s' % self.sessionArgs[1].__class__.__name__)
     settings.setValue('displaycount', len(self.plotWidgets))
Example #19
0
class Plot(QFrame, Ui_Plot):
    """ Plot container.

    """
    def __init__(self, parent=None):
        """ Initializer.

        @param parent ancestor of this widget
        """
        QFrame.__init__(self, parent)
        self.setupUi(self)
        self.settings = Settings()
        self.settings.beginGroup(self.settings.keys.plots)
        self.setupOptionsMenu()
        self.setupPlotsMenu()
        self.setupPlot()

    def setupOptionsMenu(self):
        """ Configure the options button menu.

        @return None
        """
        self.dataDialog = None
        optionsButton = self.optionsButton
        pop = QMenu(optionsButton)
        optionsButton.setMenu(pop)
        pop.addAction(self.actionDrawMajorX)
        pop.addAction(self.actionDrawMajorY)
        pop.addAction(self.actionChangeMajorGridStyle)
        pop.addSeparator()
        pop.addAction(self.actionDrawMinorX)
        pop.addAction(self.actionDrawMinorY)
        pop.addAction(self.actionChangeMinorGridStyle)
        pop.addSeparator()
        pop.addAction(self.actionShowDataDialog)
        pop.addAction(self.actionDrawLegend)
        pop.addAction(self.actionChangeCanvasColor)

    def setupPlotsMenu(self):
        """ Configure the plots button menu.

        @return None
        """
        plotButton = self.plotButton
        pop = QMenu(plotButton)
        plotButton.setMenu(pop)
        pop.addAction(self.actionNewPlot)
        pop.addAction(self.actionClosePlot)
        pop.addSeparator()
        pop.addAction(self.actionSyncWithData)

    def setupPlot(self):
        """ Configure the plot widget.

        @return None
        """
        pen = QPen(Qt.black)
        plot = self.plot
        plot.setFrameStyle(plot.NoFrame | plot.Plain)
        plot.insertLegend(Legend(), plot.LeftLegend)
        canvas = plot.canvas()
        canvas.setFrameStyle(plot.NoFrame | plot.Plain)
        layout = plot.plotLayout()
        layout.setCanvasMargin(0)
        layout.setAlignCanvasToScales(True)
        self.grid = PlotGrid()
        self.grid.attach(plot)
        self.panner = PlotPanner(canvas)
        self.zoomer = PlotZoomer(canvas)
        self.zoomer.setRubberBandPen(pen)
        self.picker = PlotPicker(canvas)
        self.picker.setTrackerPen(pen)
        self.connect(self.zoomer, Signals.zoomed, self.on_zoomer_zoomed)
        self.enableAutoScale()

    def setSessionPlot(self, session, collection, key, *indexes):
        """ Associate a session with this instance.

        @param session Session instance
        @param key id of ticker as integer
        @param *indexes unused
        @return None
        """
        self.controlsTreeItems = []
        self.highlightMarkers = []
        self.session = session
        self.collection = collection
        self.key = key
        settings = self.settings
        name = self.plotName()
        statekey = '%s/%s' % (name, settings.keys.splitstate)
        state = settings.value(statekey, defaults.rightSplitterState())
        self.plotSplitter.restoreState(state.toByteArray())
        self.setupTree()
        self.loadGrids()
        self.loadSelections()
        self.loadCanvasColor()
        self.loadLegend()
        self.updateAxis()
        scaler = self.plot.axisScaleEngine(xBottom)
        scaler.setMargins(0.0, 0.05)
        axisactions = [self.actionChangeAxesFont, self.actionChangeAxesColor]
        for widget in self.axisWidgets():
            widget.addActions(axisactions)
            widget.setContextMenuPolicy(Qt.ActionsContextMenu)
        color = settings.value('%s/axiscolor' % name)
        if color.isValid():
            self.setAxisColor(QColor(color))
        font = settings.value('%s/axisfont' % name)
        if font.isValid():
            self.setAxisFont(QFont(font))
        self.plot.replot()
        if settings.value('%s/datadialog' % name).toBool():
            ## tab might not be available
            QTimer.singleShot(500, self.actionShowDataDialog.trigger)
        session.registerMeta(self)

    def setupTree(self):
        """ Configure the model and initial items for this instance.

        @return None
        """
        tree = self.controlsTree
        self.controlsTreeModel = model = QStandardItemModel(self)
        tree.setModel(model)
        model.setHorizontalHeaderLabels(['Line', 'Value'])
        tree.sortByColumn(0, Qt.AscendingOrder)
        try:
            ticker = self.collection[self.key]
        except (
                KeyError,
                TypeError,
        ):
            pass
        else:
            for field, series in ticker.series.items():
                self.addSeries(TickType.getField(field), series)
        self.connect(model, Signals.standardItemChanged,
                     self.on_controlsTree_itemChanged)
        for col in range(model.columnCount()):
            tree.resizeColumnToContents(col)
        tree.addActions([
            self.actionChangeCurveStyle,
            self.actionChangeDataMarker,
            self.actionChangeCurveAxisX,
            self.actionChangeCurveAxisY,
        ])
        tree.expandAll()

    def addSeries(self, name, series, parent=None, items=[], checkable=True):
        """ Creates new controls and curve for an individual series.

        @param name series key
        @return None
        """
        try:
            name + ()
        except (TypeError, ):
            key = name
        else:
            key = '/'.join(name)
            name = name[0]
        if parent is None:
            parent = self.controlsTreeModel.invisibleRootItem()
        item = ControlTreeItem(name, series, key, checkable=checkable)
        self.controlsTreeItems.append(item)
        if not items:
            items = [
                ControlTreeValueItem(''),
            ]
        parent.appendRow([
            item,
        ] + items)
        if checkable:
            item.setColor(self.loadItemPen(item).color())
        for index in getattr(series, 'indexes', []):
            self.addSeries(index.key, index, parent=item)
        self.loadSelection(item)
        return item

    def anyCheckedItems(self):
        """ True if any control is checked.

        """
        return bool(self.checkedItems())

    def axisWidgets(self):
        """ Yields each plot axis widget.

        """
        for axis in allAxes:
            yield self.plot.axisWidget(axis)

    def checkedItems(self):
        """ Sequence of checked controls.

        """
        return [item for item in self.controlsTreeItems if item.isChecked()]

    def checkedNames(self):
        """ Sequence of checked control names.

        """
        return [self.itemName(item) for item in self.checkedItems()]

    def on_zoomer_zoomed(self, rect):
        """ Sets autoscaling mode when plot is zoomed to its base.

        @param rect ignored
        @return None
        """
        if not self.zoomer.zoomRectIndex():
            self.enableAutoScale()

    def enableAutoScale(self):
        """ Sets autoscaling mode on all four axes.

        @return None
        """
        for axis in allAxes:
            self.plot.setAxisAutoScale(axis)

    def enableCurve(self, item, enable=True):
        """ Sets the visibility and style of a plot curve.

        @param item tree widget item
        @param enabled sets curve visible if True, otherwise invisible
        @return None
        """
        curve = item.curve
        curve.hide()
        plot = self.plot
        legend = plot.legend()
        drawLegend = self.actionDrawLegend
        if enable:
            if not curve.settingsLoaded:
                self.loadCurve(self.itemName(item), curve)
            curve.setData(item.data.x, item.data.y)
            curve.attach(plot)
            if self.actionDrawLegend.isChecked():
                curve.updateLegend(legend, True)
            curve.show()
        else:
            legend.remove(curve)
            curve.detach()
        self.emit(Signals.enableCurve, item, enable)
        checked = self.anyCheckedItems()
        self.actionDrawLegend.setEnabled(checked)
        if not checked:
            legend.clear()
            legend.hide()
        plot.updateAxes()
        plot.replot()

    def getAxisColor(self):
        """ Returns the foreground color of the axis widgets.

        @return QColor instance
        """
        widget = self.referenceAxisWidget()
        palette = widget.palette()
        return palette.color(palette.WindowText)

    def itemName(self, item):
        """ Name for given item, including name of this plot.

        @param item ControlTreeItem instance
        @return name full item name including plot name
        """
        return '%s/%s' % (self.plotName(), item.name())

    def loadCanvasColor(self):
        """ Reads and sets the canvas color from saved settings.

        @return None
        """
        color = self.settings.value('%s/canvascolor' % self.plotName(),
                                    defaults.canvasColor())
        self.plot.setCanvasBackground(QColor(color))

    def loadCurve(self, name, curve):
        """ Reads and configures a plot curve.

        @param name of curve
        @param curve QwtPlotCurve instance
        @return None
        """
        getv = self.settings.value
        curve.setBrush(QBrush(getv('%s/brush' % name, QBrush())))
        curve.setPen(QPen(getv('%s/pen' % name, QPen())))
        curve.setStyle(
            curve.CurveStyle(
                getv('%s/style' % name, QVariant(curve.Lines)).toInt()[0]))
        curve.setBaseline(
            getv('%s/baseline' % name, QVariant(0.0)).toDouble()[0])
        curve.setCurveAttribute(curve.Inverted,
                                getv('%s/inverted' % name).toBool())
        curve.setCurveAttribute(curve.Fitted,
                                getv('%s/fitted' % name).toBool())
        curve.setPaintAttribute(curve.PaintFiltered,
                                getv('%s/filtered' % name).toBool())
        curve.setPaintAttribute(curve.ClipPolygons,
                                getv('%s/clippoly' % name).toBool())
        curve.setXAxis(
            QwtPlot.Axis(getv('%s/xaxis' % name, xBottom).toInt()[0]))
        curve.setYAxis(QwtPlot.Axis(
            getv('%s/yaxis' % name, yRight).toInt()[0]))

        def applySymbol(symname, symobj):
            symobj.setBrush(QBrush(getv('%s/brush' % symname, QBrush())))
            symobj.setPen(QPen(getv('%s/pen' % symname, QPen())))
            style = getv('%s/style' % symname, QVariant(symobj.NoSymbol))
            symobj.setStyle(symobj.Style(style.toInt()[0]))
            symobj.setSize(getv('%s/size' % symname).toSize())

        applySymbol('%s/symbol' % name, curve.symbol())
        curve.dataMarker = marker = PlotDataMarker()
        marksym = QwtSymbol()
        applySymbol('%s/dataselect/symbol' % name, marksym)
        marker.setSymbol(marksym)
        markstyle = getv('%s/dataselect/style' % name, PlotDataMarker.VLine)
        marker.setLineStyle(marker.LineStyle(markstyle.toInt()[0]))
        marker.setLinePen(QPen(getv('%s/dataselect/pen' % name, Qt.red)))
        curve.settingsLoaded = True

    def loadGrids(self):
        """ Reads and sets the major and minor grid pens and visibility.

        @return None
        """
        name = self.plotName()
        grid = self.grid
        getv = self.settings.value
        pen = getv('%s/major/pen' % name, defaults.majorGridPen())
        grid.setMajPen(QPen(pen))
        pen = getv('%s/minor/pen' % name, defaults.minorGridPen())
        grid.setMinPen(QPen(pen))
        items = [('%s/major/x/enabled', self.actionDrawMajorX),
                 ('%s/major/y/enabled', self.actionDrawMajorY),
                 ('%s/minor/x/enabled', self.actionDrawMinorX),
                 ('%s/minor/y/enabled', self.actionDrawMinorY)]
        for key, action in items:
            v = getv(key % name)
            if not v.isValid() or v.toBool():
                action.trigger()

    def loadItemPen(self, item):
        """ Creates a pen from saved settings.

        @param item ControlTreeItem instance
        @return QPen instance
        """
        pen = self.settings.value('%s/pen' % self.itemName(item))
        if pen.isValid():
            pen = QPen(pen)
        else:
            pen = defaults.itemPen(item.name())
        return pen

    def loadLegend(self):
        """ Restores the plot legend visibility from saved settings.

        """
        key = '%s/legend/enabled' % self.plotName()
        if self.settings.value(key).toBool():
            self.actionDrawLegend.trigger()

    def loadSelection(self, item):
        """ Restores an item check state and pen from saved settings.

        """
        key = '%s/checkeditems' % self.plotName()
        if self.itemName(item) in self.settings.valueLoad(key, ''):
            item.setCheckState(Qt.Checked)
            item.setColor(self.loadItemPen(item).color())

    def loadSelections(self):
        """ Restores each control tree item check state and pen.

        """
        for item in self.controlsTreeItems:
            self.loadSelection(item)

    def saveSelections(self):
        """ Saves the selected control item names.

        """
        key = '%s/checkeditems' % self.plotName()
        names = self.checkedNames()
        if names:
            # don't save an empty list because the user might be
            # closing an empty plot that really does have selections
            # saved in the settings.
            self.settings.setValueDump(key, names)

    def plotName(self):
        """ The name of this plot.

        """
        try:
            return '%s/%s' % (self.key, self.objectName())
        except (AttributeError, ):
            return 'noname/%s' % (self.objectName(), )

    def referenceAxisWidget(self):
        """ Returns a referece axis widget.

        """
        return self.plot.axisWidget(xBottom)

    def saveCanvasColor(self):
        """ Saves the canvas background color to user settings.

        @return None
        """
        prefix = self.plotName()
        self.settings.setValue('%s/canvascolor' % prefix,
                               self.plot.canvasBackground())

    def saveCurve(self, name, curve):
        """ Saves visual settings of a curve.

        @param name curve name, used as settings key
        @param curve QwtPlotCurve instance
        @return None
        """
        setv = self.settings.setValue
        setv('%s/brush' % name, curve.brush())
        setv('%s/pen' % name, curve.pen())
        setv('%s/style' % name, curve.style())
        setv('%s/baseline' % name, curve.baseline())
        setv('%s/inverted' % name, curve.testCurveAttribute(curve.Inverted))
        setv('%s/fitted' % name, curve.testCurveAttribute(curve.Fitted))
        setv('%s/filtered' % name,
             curve.testPaintAttribute(curve.PaintFiltered))
        setv('%s/clippoly' % name,
             curve.testPaintAttribute(curve.ClipPolygons))
        setv('%s/xaxis' % name, curve.xAxis())
        setv('%s/yaxis' % name, curve.yAxis())
        name = '%s/symbol' % name
        symbol = curve.symbol()
        setv('%s/brush' % name, symbol.brush())
        setv('%s/pen' % name, symbol.pen())
        setv('%s/style' % name, symbol.style())
        setv('%s/size' % name, symbol.size())

    def saveMarker(self, name, marker):
        """ Saves visual settings of a marker.

        @param name curve name, used as settings key
        @param curve QwtPlotMarker instance
        @return None
        """
        setv = self.settings.setValue
        setv('%s/dataselect/style' % name, marker.lineStyle())
        setv('%s/dataselect/pen' % name, marker.linePen())
        symname = '%s/dataselect/symbol' % name
        symbol = marker.symbol()
        setv('%s/brush' % symname, symbol.brush())
        setv('%s/pen' % symname, symbol.pen())
        setv('%s/style' % symname, symbol.style())
        setv('%s/size' % symname, symbol.size())

    def saveLegend(self):
        """ Saves the visibility of the plot legend to user settings.

        @return None
        """
        key = '%s/legend/enabled' % self.plotName()
        self.settings.setValue(key, self.actionDrawLegend.isChecked())

    def saveMajorX(self):
        """ Saves the state and pen of the major grid x axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/major/x/enabled' % name, self.actionDrawMajorX.isChecked())
        setv('%s/major/pen' % name, self.grid.majPen())

    def saveMajorY(self):
        """ Saves the state and pen of the major grid y axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/major/y/enabled' % name, self.actionDrawMajorY.isChecked())
        setv('%s/major/pen' % name, self.grid.majPen())

    def saveMinorX(self):
        """ Saves the state and pen of the minor grid x axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/minor/x/enabled' % name, self.actionDrawMinorX.isChecked())
        setv('%s/minor/pen' % name, self.grid.minPen())

    def saveMinorY(self):
        """ Saves the state and pen of the minor grid y axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/minor/y/enabled' % name, self.actionDrawMinorY.isChecked())
        setv('%s/minor/pen' % name, self.grid.minPen())

    def setAxisColor(self, color):
        """ Sets the axis widgets foreground and text color.

        @param color QColor instance
        @return None
        """
        for widget in self.axisWidgets():
            palette = widget.palette()
            palette.setColor(palette.WindowText, color)
            palette.setColor(palette.Text, color)
            widget.setPalette(palette)

    def setAxisFont(self, font):
        """ Sets the axis widgets font.

        @param font QFont instance
        @return None
        """
        for widget in self.axisWidgets():
            widget.setFont(font)

    def updateAxis(self):
        """ Enables each y axis if there are curves attached to it.

        @return None
        """
        enable = self.plot.enableAxis
        items = self.checkedItems()
        for pair, pred in [([yRight,
                             yLeft], lambda i, a: i.curve.yAxis() == a),
                           ([xTop,
                             xBottom], lambda i, a: i.curve.xAxis() == a)]:
            for axis in pair:
                enable(axis, any(item for item in items if pred(item, axis)))

    ## session signal handlers

    def on_session_createdSeries(self, key, field):
        """ Signal handler called when new Series objects are created.

        @param key id of ticker with new series
        @param field series field
        """
        if key != self.key:
            return
        series = self.collection[self.key].series[field]
        self.addSeries(TickType.getField(field), series)
        self.controlsTree.sortByColumn(0, Qt.AscendingOrder)

    def setItemValue(self, item):
        idx = self.controlsTreeModel.indexFromItem(item)
        parent = item.parent()
        if parent:
            getc = parent.child
        else:
            getc = self.controlsTreeModel.item
        next = getc(item.row(), item.column() + 1)
        try:
            next.setText('%.2f' % item.data[-1])
        except (
                AttributeError,
                IndexError,
                TypeError,
        ):
            pass
        else:
            for c in [item.child(r, 0) for r in range(item.rowCount())]:
                self.setItemValue(c)

    def on_session_TickPrice_TickSize(self, message):
        """ Signal handler for TickPrice and TickSize session messages.

        @param message Message instance
        @return None
        """
        if message.tickerId != self.key:
            return
        for item in self.controlsTreeItems:
            self.setItemValue(item)
        items = [i for i in self.controlsTreeItems if i.curve.isVisible()]
        for item in items:
            item.curve.setData(item.data.x, item.data.y)
        if items:
            self.plot.replot()
        self.on_zoomer_zoomed(None)

    def on_session_UpdateAccountValue(self, message):
        if self.key != 'account':
            return
        items = [i for i in self.controlsTreeItems if i.curve.isVisible()]
        for item in items:
            item.curve.setData(item.data.x, item.data.y)
        if items:
            self.plot.replot()
        self.on_zoomer_zoomed(None)

    ## action signal handlers

    @pyqtSignature('')
    def on_actionChangeCurveStyle_triggered(self):
        """ Signal handler called to edit a curve.

        @return None
        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            indexZero = self.controlsTreeModel.sibling(index.row(), 0, index)
            first = self.controlsTreeModel.itemFromIndex(indexZero)
            try:
                curve = first.curve
                color = first.color
            except (AttributeError, ):
                return
            else:
                item = first
            if not curve.settingsLoaded:
                self.loadCurve(self.itemName(item), curve)
            cplot = curve.plot()
            if cplot is None:
                curve.attach(self.plot)
            dlg = PlotItemDialog(curve, self)
            if dlg.exec_() == dlg.Accepted:
                dlg.applyToCurve(curve)
                item.setColor(curve.pen().color())
                self.saveCurve(self.itemName(item), curve)
                self.enableCurve(item, enable=item.checkState() == Qt.Checked)
            if cplot is None:
                curve.detach()

    @pyqtSignature('')
    def on_actionChangeCurveAxisX_triggered(self):
        """ Signal handler called to toggle the x axis of a curve.

        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            curve = item.curve
            if curve.xAxis() == xTop:
                curve.setXAxis(xBottom)
            else:
                curve.setXAxis(xTop)
            self.updateAxis()
            self.saveCurve(self.itemName(item), curve)
            self.plot.replot()

    @pyqtSignature('')
    def on_actionChangeCurveAxisY_triggered(self):
        """ Signal handler called to toggle the y axis of a curve.

        @return None
        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            curve = item.curve
            if curve.yAxis() == yLeft:
                curve.setYAxis(yRight)
            else:
                curve.setYAxis(yLeft)
            self.updateAxis()
            self.saveCurve(self.itemName(item), curve)
            self.plot.replot()

    @pyqtSignature('')
    def on_actionChangeDataMarker_triggered(self):
        """ Signal handler called to edit data marker.

        @return None
        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            curve = item.curve
            if not curve.settingsLoaded:
                self.loadCurve(self.itemName(item), curve)
            cplot = curve.plot()
            if cplot is None:
                curve.attach(self.plot)
            dlg = PlotItemDialog(curve, marker=curve.dataMarker, parent=self)
            if dlg.exec_() == dlg.Accepted:
                dlg.applyToMarker(curve.dataMarker)
                self.saveMarker(self.itemName(item), curve.dataMarker)
                for marker in self.highlightMarkers:
                    marker.restyleFrom(curve.dataMarker)
                self.plot.replot()
            if cplot is None:
                curve.detach()

    @pyqtSignature('bool')
    def on_actionDrawLegend_triggered(self, enable):
        """ Signal handler called to toggle the plot legend visibility.

        @param enable if True, legend is enabled
        @return False
        """
        legend = self.plot.legend()
        legend.setVisible(enable)
        if enable:
            items = self.checkedItems()
            if items:
                for item in items:
                    item.curve.updateLegend(legend, True)
            else:
                self.actionDrawLegend.setChecked(False)
        else:
            legend.clear()
        self.saveLegend()

    @pyqtSignature('bool')
    def on_actionDrawMajorX_triggered(self, enable):
        """ Signal handler called to toggle visiblity of major grid x axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableX(enable)
        self.plot.replot()
        self.saveMajorX()

    @pyqtSignature('bool')
    def on_actionDrawMajorY_triggered(self, enable):
        """ Signal handler called to toggle visiblity of major grid y axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableY(enable)
        self.plot.replot()
        self.saveMajorY()

    @pyqtSignature('bool')
    def on_actionDrawMinorX_triggered(self, enable):
        """ Signal handler called to toggle visiblity of minor grid x axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableXMin(enable)
        self.plot.replot()
        self.saveMinorX()

    @pyqtSignature('bool')
    def on_actionDrawMinorY_triggered(self, enable):
        """ Signal handler called to toggle visiblity of minor grid y axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableYMin(enable)
        self.plot.replot()
        self.saveMinorY()

    @pyqtSignature('')
    def on_actionChangeMajorGridStyle_triggered(self):
        """ Signal handler called to edit the major grid pen.

        @return None
        """
        pen = changePen(self.grid.majPen, self.grid.setMajPen, self)
        if pen:
            self.plot.replot()
            self.saveMajorX()
            self.saveMajorY()

    @pyqtSignature('')
    def on_actionChangeMinorGridStyle_triggered(self):
        """ Signal handler called to edit the minor grid pen.

        @return None
        """
        pen = changePen(self.grid.minPen, self.grid.setMinPen, self)
        if pen:
            self.plot.replot()
            self.saveMinorX()
            self.saveMinorY()

    @pyqtSignature('')
    def on_actionChangeCanvasColor_triggered(self):
        """ Signal handler called to edit the plot canvas background.

        @return None
        """
        plot = self.plot
        color = changeColor(plot.canvasBackground, plot.setCanvasBackground,
                            self)
        if color:
            pen = QPen(complementColor(color))
            self.zoomer.setRubberBandPen(pen)
            self.picker.setTrackerPen(pen)
            plot.replot()
            self.saveCanvasColor()

    @pyqtSignature('')
    def on_actionChangeAxesFont_triggered(self):
        """ Signal handler called to edit the axes font.

        @return None
        """
        widget = self.referenceAxisWidget()
        default = widget.font()
        font, okay = QFontDialog.getFont(default, self, 'Select Axis Font')
        if okay:
            self.setAxisFont(font)
            self.settings.setValue('%s/axisfont' % self.plotName(), font)

    @pyqtSignature('')
    def on_actionChangeAxesColor_triggered(self):
        """ Signal handler called to edit the axes color.

        @return None
        """
        color = changeColor(self.getAxisColor, self.setAxisColor, self)
        if color:
            self.settings.setValue('%s/axiscolor' % self.plotName(), color)

    @pyqtSignature('bool')
    def on_actionShowDataDialog_triggered(self, enable):
        """ Signal handler called to show or hide the data dialog.

        @return None
        """
        if enable:
            dlg = self.dataDialog = PlotDataDialog(self)
            try:
                tabs = self.window().centralTabs
            except (AttributeError, ):
                pass
            else:
                name = tabs.tabText(tabs.currentIndex())
                dlg.setWindowTitle(str(dlg.windowTitle()) % name)
                dlg.setWindowIcon(tabs.tabIcon(tabs.currentIndex()))
            self.connect(dlg, Signals.dialogFinished,
                         self.on_dataDialog_finished)
            self.connect(dlg, Signals.highlightSelections,
                         self.on_dataDialog_selected)
            dlg.show()
        elif self.dataDialog:
            self.dataDialog.close()
            self.dataDialog = None
        self.settings.setValue('%s/datadialog' % self.plotName(), enable)

    ## controls tree signal handlers

    def on_controlsTree_doubleClicked(self, index):
        """ Signal handler for control tree double click.

        @param index QModelIndex instance
        @return None
        """
        tree = self.controlsTree
        if index.isValid():
            pos = tree.visualRect(index).center()
            actions = tree.actions()
            for action in actions:
                action.setData(QVariant(pos))
            self.actionChangeCurveStyle.trigger()

    def on_controlsTree_itemChanged(self, item):
        """ Signal handler for all changes to control tree items.

        @param item changed tree widget item
        @return None
        """
        try:
            curve = item.curve
        except (AttributeError, ):
            pass
        else:
            self.enableCurve(item, enable=item.checkState() == Qt.Checked)
            self.updateAxis()
            self.saveSelections()

    def on_controlsTree_customContextMenuRequested(self, pos):
        """ Signal handler for context menu request over control tree.

        @param pos QPoint of mouse click
        @return None
        """
        tree = self.controlsTree
        index = tree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            if not hasattr(item, 'curve'):
                return
            if item.curve.yAxis() == yRight:
                self.actionChangeCurveAxisY.setText('Move to Left Axis')
            else:
                self.actionChangeCurveAxisY.setText('Move to Right Axis')
            if item.curve.xAxis() == xTop:
                self.actionChangeCurveAxisX.setText('Move to Bottom Axis')
            else:
                self.actionChangeCurveAxisX.setText('Move to Top Axis')
            actions = tree.actions()
            for action in actions:
                action.setData(QVariant(pos))
            QMenu.exec_(actions, tree.mapToGlobal(pos))

    def on_dataDialog_finished(self, result):
        """ Signal handler for data dialog finish.

        Sets and saves state of data dialog display after its closed.

        @param result ignored
        @return None
        """
        self.actionShowDataDialog.setChecked(False)
        self.dataDialog = None
        self.on_dataDialog_selected([])
        self.settings.setValue('%s/datadialog' % self.plotName(), False)

    def on_dataDialog_selected(self, items):
        """ Signal handler for data dialog selection changes.

        @params items list of (index, item) two-tuples
        @return None
        """
        for marker in self.highlightMarkers:
            marker.detach()
        self.highlightMarkers = markers = []
        for index, item in items:
            try:
                x, y = index.row(), item.data[index.row()]
            except (IndexError, ):
                continue
            if x is None or y is None:
                continue
            curve = item.curve
            marker = curve.dataMarker.cloneFromValue(curve, x, y)
            markers.append(marker)
            marker.attach(self.plot)
        self.plot.replot()

    def on_plotSplitter_splitterMoved(self, pos, index):
        """ Signal handler for splitter move; saves state to user settings.

        @param pos ignored
        @param index ignored
        @return None
        """
        settings = self.settings
        statekey = '%s/%s' % (self.plotName(), settings.keys.splitstate)
        settings.setValue(statekey, self.plotSplitter.saveState())

    def syncPlot(self, sync=None):
        print '## sync?', sync
        session = self.session
        (session.registerMeta if sync else session.deregisterMeta)(self)
Example #20
0
    def writeSettings(self):
        """ Saves some main window settings.

        """
        settings = Settings()
        settings.beginGroup(settings.keys.main)
        settings.setValue(settings.keys.size, self.size())
        settings.setValue(settings.keys.position, self.pos())
        settings.setValue(settings.keys.maximized, self.isMaximized())
        settings.setValue(settings.keys.winstate, self.saveState())
        settings.setValueDump(settings.keys.ctabstate, self.centralTabState())
        settings.endGroup()
Example #21
0
 def saveCount(self):
     settings = Settings()
     settings.beginGroup("Plots")
     settings.beginGroup("%s" % self.sessionArgs[1].__class__.__name__)
     settings.setValue("displaycount", len(self.plotWidgets))
Example #22
0
    @pyqtSignature('')
    def on_tickerUrlUp_clicked(self):
        self.moveTickerUrl(-1)

    @pyqtSignature('')
    def on_tickerUrlDown_clicked(self):
        self.moveTickerUrl(1)

    def moveTickerUrl(self, offset):
        widget = self.tickerUrls
        item = widget.currentItem()
        other = widget.item(widget.currentRow() + offset)
        itemtext, othertext = item.text(), other.text()
        item.setText(othertext)
        other.setText(itemtext)
        selmodel = widget.selectionModel()
        selmodel.clear()
        selmodel.setCurrentIndex(widget.indexFromItem(other), selmodel.Select)

    def accept(self):
        self.writeSettings(Settings())
        QDialog.accept(self)


if __name__ == '__main__':
    app = QApplication([])
    win = SettingsDialog()
    win.readSettings(Settings())
    win.exec_()
Example #23
0
 def accept(self):
     self.writeSettings(Settings())
     QDialog.accept(self)
Example #24
0
class Plot(QFrame, Ui_Plot):
    """ Plot container.

    """
    def __init__(self, parent=None):
        """ Initializer.

        @param parent ancestor of this widget
        """
        QFrame.__init__(self, parent)
        self.setupUi(self)
        self.settings = Settings()
        self.settings.beginGroup(self.settings.keys.plots)
        self.setupOptionsMenu()
        self.setupPlotsMenu()
        self.setupPlot()

    def setupOptionsMenu(self):
        """ Configure the options button menu.

        @return None
        """
        self.dataDialog = None
        optionsButton = self.optionsButton
        pop = QMenu(optionsButton)
        optionsButton.setMenu(pop)
        pop.addAction(self.actionDrawMajorX)
        pop.addAction(self.actionDrawMajorY)
        pop.addAction(self.actionChangeMajorGridStyle)
        pop.addSeparator()
        pop.addAction(self.actionDrawMinorX)
        pop.addAction(self.actionDrawMinorY)
        pop.addAction(self.actionChangeMinorGridStyle)
        pop.addSeparator()
        pop.addAction(self.actionShowDataDialog)
        pop.addAction(self.actionDrawLegend)
        pop.addAction(self.actionChangeCanvasColor)

    def setupPlotsMenu(self):
        """ Configure the plots button menu.

        @return None
        """
        plotButton = self.plotButton
        pop = QMenu(plotButton)
        plotButton.setMenu(pop)
        pop.addAction(self.actionNewPlot)
        pop.addAction(self.actionClosePlot)
        pop.addSeparator()
        pop.addAction(self.actionSyncWithData)

    def setupPlot(self):
        """ Configure the plot widget.

        @return None
        """
        pen = QPen(Qt.black)
        plot = self.plot
        plot.setFrameStyle(plot.NoFrame|plot.Plain)
        plot.insertLegend(Legend(), plot.LeftLegend)
        canvas = plot.canvas()
        canvas.setFrameStyle(plot.NoFrame|plot.Plain)
        layout = plot.plotLayout()
        layout.setCanvasMargin(0)
        layout.setAlignCanvasToScales(True)
        self.grid = PlotGrid()
        self.grid.attach(plot)
        self.panner = PlotPanner(canvas)
        self.zoomer = PlotZoomer(canvas)
        self.zoomer.setRubberBandPen(pen)
        self.picker = PlotPicker(canvas)
        self.picker.setTrackerPen(pen)
        self.connect(self.zoomer, Signals.zoomed, self.on_zoomer_zoomed)
        self.enableAutoScale()

    def setSessionPlot(self, session, collection, key, *indexes):
        """ Associate a session with this instance.

        @param session Session instance
        @param key id of ticker as integer
        @param *indexes unused
        @return None
        """
        self.controlsTreeItems = []
        self.highlightMarkers = []
        self.session = session
        self.collection = collection
        self.key = key
        settings = self.settings
        name = self.plotName()
        statekey = '%s/%s' % (name, settings.keys.splitstate)
        state = settings.value(statekey, defaults.rightSplitterState())
        self.plotSplitter.restoreState(state.toByteArray())
        self.setupTree()
        self.loadGrids()
        self.loadSelections()
        self.loadCanvasColor()
        self.loadLegend()
        self.updateAxis()
        scaler = self.plot.axisScaleEngine(xBottom)
        scaler.setMargins(0.0, 0.05)
        axisactions = [self.actionChangeAxesFont, self.actionChangeAxesColor]
        for widget in self.axisWidgets():
            widget.addActions(axisactions)
            widget.setContextMenuPolicy(Qt.ActionsContextMenu)
        color = settings.value('%s/axiscolor' % name)
        if color.isValid():
            self.setAxisColor(QColor(color))
        font = settings.value('%s/axisfont' % name)
        if font.isValid():
            self.setAxisFont(QFont(font))
        self.plot.replot()
        if settings.value('%s/datadialog' % name).toBool():
            ## tab might not be available
            QTimer.singleShot(500, self.actionShowDataDialog.trigger)
        session.registerMeta(self)

    def setupTree(self):
        """ Configure the model and initial items for this instance.

        @return None
        """
        tree = self.controlsTree
        self.controlsTreeModel = model = QStandardItemModel(self)
        tree.setModel(model)
        model.setHorizontalHeaderLabels(['Line', 'Value'])
        tree.sortByColumn(0, Qt.AscendingOrder)
        try:
            ticker = self.collection[self.key]
        except (KeyError, TypeError, ):
            pass
        else:
            for field, series in ticker.series.items():
                self.addSeries(TickType.getField(field), series)
        self.connect(model, Signals.standardItemChanged,
                     self.on_controlsTree_itemChanged)
        for col in range(model.columnCount()):
            tree.resizeColumnToContents(col)
        tree.addActions(
            [self.actionChangeCurveStyle,
             self.actionChangeDataMarker,
             self.actionChangeCurveAxisX,
             self.actionChangeCurveAxisY,])
        tree.expandAll()

    def addSeries(self, name, series, parent=None, items=[], checkable=True):
        """ Creates new controls and curve for an individual series.

        @param name series key
        @return None
        """
        try:
            name + ()
        except (TypeError, ):
            key = name
        else:
            key = '/'.join(name)
            name = name[0]
        if parent is None:
            parent = self.controlsTreeModel.invisibleRootItem()
        item = ControlTreeItem(name, series, key, checkable=checkable)
        self.controlsTreeItems.append(item)
        if not items:
            items = [ControlTreeValueItem(''), ]
        parent.appendRow([item, ] + items)
        if checkable:
            item.setColor(self.loadItemPen(item).color())
        for index in getattr(series, 'indexes', []):
            self.addSeries(index.key, index, parent=item)
        self.loadSelection(item)
        return item


    def anyCheckedItems(self):
        """ True if any control is checked.

        """
        return bool(self.checkedItems())

    def axisWidgets(self):
        """ Yields each plot axis widget.

        """
        for axis in allAxes:
            yield self.plot.axisWidget(axis)

    def checkedItems(self):
        """ Sequence of checked controls.

        """
        return [item for item in self.controlsTreeItems if item.isChecked()]

    def checkedNames(self):
        """ Sequence of checked control names.

        """
        return [self.itemName(item) for item in self.checkedItems()]

    def on_zoomer_zoomed(self, rect):
        """ Sets autoscaling mode when plot is zoomed to its base.

        @param rect ignored
        @return None
        """
        if not self.zoomer.zoomRectIndex():
            self.enableAutoScale()

    def enableAutoScale(self):
        """ Sets autoscaling mode on all four axes.

        @return None
        """
        for axis in allAxes:
            self.plot.setAxisAutoScale(axis)

    def enableCurve(self, item, enable=True):
        """ Sets the visibility and style of a plot curve.

        @param item tree widget item
        @param enabled sets curve visible if True, otherwise invisible
        @return None
        """
        curve = item.curve
        curve.hide()
        plot = self.plot
        legend = plot.legend()
        drawLegend = self.actionDrawLegend
        if enable:
            if not curve.settingsLoaded:
                self.loadCurve(self.itemName(item), curve)
            curve.setData(item.data.x, item.data.y)
            curve.attach(plot)
            if self.actionDrawLegend.isChecked():
                curve.updateLegend(legend, True)
            curve.show()
        else:
            legend.remove(curve)
            curve.detach()
        self.emit(Signals.enableCurve, item, enable)
        checked = self.anyCheckedItems()
        self.actionDrawLegend.setEnabled(checked)
        if not checked:
            legend.clear()
            legend.hide()
        plot.updateAxes()
        plot.replot()

    def getAxisColor(self):
        """ Returns the foreground color of the axis widgets.

        @return QColor instance
        """
        widget = self.referenceAxisWidget()
        palette = widget.palette()
        return palette.color(palette.WindowText)

    def itemName(self, item):
        """ Name for given item, including name of this plot.

        @param item ControlTreeItem instance
        @return name full item name including plot name
        """
        return '%s/%s' % (self.plotName(), item.name())

    def loadCanvasColor(self):
        """ Reads and sets the canvas color from saved settings.

        @return None
        """
        color = self.settings.value(
            '%s/canvascolor' % self.plotName(), defaults.canvasColor())
        self.plot.setCanvasBackground(QColor(color))

    def loadCurve(self, name, curve):
        """ Reads and configures a plot curve.

        @param name of curve
        @param curve QwtPlotCurve instance
        @return None
        """
        getv = self.settings.value
        curve.setBrush(QBrush(getv('%s/brush' % name, QBrush())))
        curve.setPen(QPen(getv('%s/pen' % name, QPen())))
        curve.setStyle(curve.CurveStyle(
            getv('%s/style' % name, QVariant(curve.Lines)).toInt()[0]))
        curve.setBaseline(
            getv('%s/baseline' % name, QVariant(0.0)).toDouble()[0])
        curve.setCurveAttribute(
            curve.Inverted, getv('%s/inverted' % name).toBool())
        curve.setCurveAttribute(
            curve.Fitted, getv('%s/fitted' % name).toBool())
        curve.setPaintAttribute(
            curve.PaintFiltered, getv('%s/filtered' % name).toBool())
        curve.setPaintAttribute(
            curve.ClipPolygons, getv('%s/clippoly' % name).toBool())
        curve.setXAxis(
            QwtPlot.Axis(getv('%s/xaxis' % name, xBottom).toInt()[0]))
        curve.setYAxis(
            QwtPlot.Axis(getv('%s/yaxis' % name, yRight).toInt()[0]))

        def applySymbol(symname, symobj):
            symobj.setBrush(QBrush(getv('%s/brush' % symname, QBrush())))
            symobj.setPen(QPen(getv('%s/pen' % symname, QPen())))
            style = getv('%s/style' % symname, QVariant(symobj.NoSymbol))
            symobj.setStyle(symobj.Style(style.toInt()[0]))
            symobj.setSize(getv('%s/size' % symname).toSize())

        applySymbol('%s/symbol' % name, curve.symbol())
        curve.dataMarker = marker = PlotDataMarker()
        marksym = QwtSymbol()
        applySymbol('%s/dataselect/symbol' % name, marksym)
        marker.setSymbol(marksym)
        markstyle = getv('%s/dataselect/style' % name, PlotDataMarker.VLine)
        marker.setLineStyle(marker.LineStyle(markstyle.toInt()[0]))
        marker.setLinePen(QPen(getv('%s/dataselect/pen' % name, Qt.red)))
        curve.settingsLoaded = True

    def loadGrids(self):
        """ Reads and sets the major and minor grid pens and visibility.

        @return None
        """
        name = self.plotName()
        grid = self.grid
        getv = self.settings.value
        pen = getv('%s/major/pen' % name, defaults.majorGridPen())
        grid.setMajPen(QPen(pen))
        pen = getv('%s/minor/pen' % name, defaults.minorGridPen())
        grid.setMinPen(QPen(pen))
        items = [('%s/major/x/enabled', self.actionDrawMajorX),
                 ('%s/major/y/enabled', self.actionDrawMajorY),
                 ('%s/minor/x/enabled', self.actionDrawMinorX),
                 ('%s/minor/y/enabled', self.actionDrawMinorY)]
        for key, action in items:
            v = getv(key % name)
            if not v.isValid() or v.toBool():
                action.trigger()

    def loadItemPen(self, item):
        """ Creates a pen from saved settings.

        @param item ControlTreeItem instance
        @return QPen instance
        """
        pen = self.settings.value('%s/pen' % self.itemName(item))
        if pen.isValid():
            pen = QPen(pen)
        else:
            pen = defaults.itemPen(item.name())
        return pen

    def loadLegend(self):
        """ Restores the plot legend visibility from saved settings.

        """
        key = '%s/legend/enabled' % self.plotName()
        if self.settings.value(key).toBool():
            self.actionDrawLegend.trigger()

    def loadSelection(self, item):
        """ Restores an item check state and pen from saved settings.

        """
        key = '%s/checkeditems' % self.plotName()
        if self.itemName(item) in self.settings.valueLoad(key, ''):
            item.setCheckState(Qt.Checked)
            item.setColor(self.loadItemPen(item).color())

    def loadSelections(self):
        """ Restores each control tree item check state and pen.

        """
        for item in self.controlsTreeItems:
            self.loadSelection(item)

    def saveSelections(self):
        """ Saves the selected control item names.

        """
        key = '%s/checkeditems' % self.plotName()
        names = self.checkedNames()
        if names:
            # don't save an empty list because the user might be
            # closing an empty plot that really does have selections
            # saved in the settings.
            self.settings.setValueDump(key, names)

    def plotName(self):
        """ The name of this plot.

        """
        try:
            return '%s/%s' % (self.key, self.objectName())
        except (AttributeError, ):
            return 'noname/%s' % (self.objectName(), )

    def referenceAxisWidget(self):
        """ Returns a referece axis widget.

        """
        return self.plot.axisWidget(xBottom)

    def saveCanvasColor(self):
        """ Saves the canvas background color to user settings.

        @return None
        """
        prefix = self.plotName()
        self.settings.setValue(
            '%s/canvascolor' % prefix, self.plot.canvasBackground())

    def saveCurve(self, name, curve):
        """ Saves visual settings of a curve.

        @param name curve name, used as settings key
        @param curve QwtPlotCurve instance
        @return None
        """
        setv = self.settings.setValue
        setv('%s/brush' % name, curve.brush())
        setv('%s/pen' % name, curve.pen())
        setv('%s/style' % name, curve.style())
        setv('%s/baseline' % name, curve.baseline())
        setv('%s/inverted' % name,
                 curve.testCurveAttribute(curve.Inverted))
        setv('%s/fitted' % name,
                 curve.testCurveAttribute(curve.Fitted))
        setv('%s/filtered' % name,
                 curve.testPaintAttribute(curve.PaintFiltered))
        setv('%s/clippoly' % name,
                 curve.testPaintAttribute(curve.ClipPolygons))
        setv('%s/xaxis' % name, curve.xAxis())
        setv('%s/yaxis' % name, curve.yAxis())
        name = '%s/symbol' % name
        symbol = curve.symbol()
        setv('%s/brush' % name, symbol.brush())
        setv('%s/pen' % name, symbol.pen())
        setv('%s/style' % name, symbol.style())
        setv('%s/size' % name, symbol.size())

    def saveMarker(self, name, marker):
        """ Saves visual settings of a marker.

        @param name curve name, used as settings key
        @param curve QwtPlotMarker instance
        @return None
        """
        setv = self.settings.setValue
        setv('%s/dataselect/style' % name, marker.lineStyle())
        setv('%s/dataselect/pen' % name, marker.linePen())
        symname = '%s/dataselect/symbol' % name
        symbol = marker.symbol()
        setv('%s/brush' % symname, symbol.brush())
        setv('%s/pen' % symname, symbol.pen())
        setv('%s/style' % symname, symbol.style())
        setv('%s/size' % symname, symbol.size())

    def saveLegend(self):
        """ Saves the visibility of the plot legend to user settings.

        @return None
        """
        key = '%s/legend/enabled' % self.plotName()
        self.settings.setValue(key, self.actionDrawLegend.isChecked())

    def saveMajorX(self):
        """ Saves the state and pen of the major grid x axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/major/x/enabled' % name,
             self.actionDrawMajorX.isChecked())
        setv('%s/major/pen' % name, self.grid.majPen())

    def saveMajorY(self):
        """ Saves the state and pen of the major grid y axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/major/y/enabled' % name,
             self.actionDrawMajorY.isChecked())
        setv('%s/major/pen' % name, self.grid.majPen())

    def saveMinorX(self):
        """ Saves the state and pen of the minor grid x axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/minor/x/enabled' % name,
             self.actionDrawMinorX.isChecked())
        setv('%s/minor/pen' % name, self.grid.minPen())

    def saveMinorY(self):
        """ Saves the state and pen of the minor grid y axis.

        @return None
        """
        name = self.plotName()
        setv = self.settings.setValue
        setv('%s/minor/y/enabled' % name,
             self.actionDrawMinorY.isChecked())
        setv('%s/minor/pen' % name, self.grid.minPen())

    def setAxisColor(self, color):
        """ Sets the axis widgets foreground and text color.

        @param color QColor instance
        @return None
        """
        for widget in self.axisWidgets():
            palette = widget.palette()
            palette.setColor(palette.WindowText, color)
            palette.setColor(palette.Text, color)
            widget.setPalette(palette)

    def setAxisFont(self, font):
        """ Sets the axis widgets font.

        @param font QFont instance
        @return None
        """
        for widget in self.axisWidgets():
            widget.setFont(font)

    def updateAxis(self):
        """ Enables each y axis if there are curves attached to it.

        @return None
        """
        enable = self.plot.enableAxis
        items = self.checkedItems()
        for pair, pred in [
            ([yRight, yLeft], lambda i, a:i.curve.yAxis()==a),
            ([xTop, xBottom],  lambda i, a:i.curve.xAxis()==a)]:
            for axis in pair:
                enable(axis, any(item for item in items if pred(item, axis)))

    ## session signal handlers

    def on_session_createdSeries(self, key, field):
        """ Signal handler called when new Series objects are created.

        @param key id of ticker with new series
        @param field series field
        """
        if key != self.key:
            return
        series = self.collection[self.key].series[field]
        self.addSeries(TickType.getField(field), series)
        self.controlsTree.sortByColumn(0, Qt.AscendingOrder)

    def setItemValue(self, item):
        idx = self.controlsTreeModel.indexFromItem(item)
        parent = item.parent()
        if parent:
            getc = parent.child
        else:
            getc = self.controlsTreeModel.item
        next = getc(item.row(), item.column()+1)
        try:
            next.setText('%.2f' % item.data[-1])
        except (AttributeError, IndexError, TypeError, ):
            pass
        else:
            for c in [item.child(r, 0) for r in range(item.rowCount())]:
                self.setItemValue(c)

    def on_session_TickPrice_TickSize(self, message):
        """ Signal handler for TickPrice and TickSize session messages.

        @param message Message instance
        @return None
        """
        if message.tickerId != self.key:
            return
        for item in self.controlsTreeItems:
            self.setItemValue(item)
        items = [i for i in self.controlsTreeItems if i.curve.isVisible()]
        for item in items:
            item.curve.setData(item.data.x, item.data.y)
        if items:
            self.plot.replot()
        self.on_zoomer_zoomed(None)

    def on_session_UpdateAccountValue(self, message):
        if self.key != 'account':
            return
        items = [i for i in self.controlsTreeItems if i.curve.isVisible()]
        for item in items:
            item.curve.setData(item.data.x, item.data.y)
        if items:
            self.plot.replot()
        self.on_zoomer_zoomed(None)


    ## action signal handlers

    @pyqtSignature('')
    def on_actionChangeCurveStyle_triggered(self):
        """ Signal handler called to edit a curve.

        @return None
        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            indexZero = self.controlsTreeModel.sibling(index.row(), 0, index)
            first = self.controlsTreeModel.itemFromIndex(indexZero)
            try:
                curve = first.curve
                color = first.color
            except (AttributeError, ):
                return
            else:
                item = first
            if not curve.settingsLoaded:
                self.loadCurve(self.itemName(item), curve)
            cplot = curve.plot()
            if cplot is None:
                curve.attach(self.plot)
            dlg = PlotItemDialog(curve, self)
            if dlg.exec_() == dlg.Accepted:
                dlg.applyToCurve(curve)
                item.setColor(curve.pen().color())
                self.saveCurve(self.itemName(item), curve)
                self.enableCurve(item, enable=item.checkState()==Qt.Checked)
            if cplot is None:
                curve.detach()

    @pyqtSignature('')
    def on_actionChangeCurveAxisX_triggered(self):
        """ Signal handler called to toggle the x axis of a curve.

        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            curve = item.curve
            if curve.xAxis() == xTop:
                curve.setXAxis(xBottom)
            else:
                curve.setXAxis(xTop)
            self.updateAxis()
            self.saveCurve(self.itemName(item), curve)
            self.plot.replot()

    @pyqtSignature('')
    def on_actionChangeCurveAxisY_triggered(self):
        """ Signal handler called to toggle the y axis of a curve.

        @return None
        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            curve = item.curve
            if curve.yAxis() == yLeft:
                curve.setYAxis(yRight)
            else:
                curve.setYAxis(yLeft)
            self.updateAxis()
            self.saveCurve(self.itemName(item), curve)
            self.plot.replot()

    @pyqtSignature('')
    def on_actionChangeDataMarker_triggered(self):
        """ Signal handler called to edit data marker.

        @return None
        """
        pos = self.sender().data().toPoint()
        index = self.controlsTree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            curve = item.curve
            if not curve.settingsLoaded:
                self.loadCurve(self.itemName(item), curve)
            cplot = curve.plot()
            if cplot is None:
                curve.attach(self.plot)
            dlg = PlotItemDialog(curve, marker=curve.dataMarker, parent=self)
            if dlg.exec_() == dlg.Accepted:
                dlg.applyToMarker(curve.dataMarker)
                self.saveMarker(self.itemName(item), curve.dataMarker)
                for marker in self.highlightMarkers:
                    marker.restyleFrom(curve.dataMarker)
                self.plot.replot()
            if cplot is None:
                curve.detach()

    @pyqtSignature('bool')
    def on_actionDrawLegend_triggered(self, enable):
        """ Signal handler called to toggle the plot legend visibility.

        @param enable if True, legend is enabled
        @return False
        """
        legend = self.plot.legend()
        legend.setVisible(enable)
        if enable:
            items = self.checkedItems()
            if items:
                for item in items:
                    item.curve.updateLegend(legend, True)
            else:
                self.actionDrawLegend.setChecked(False)
        else:
            legend.clear()
        self.saveLegend()

    @pyqtSignature('bool')
    def on_actionDrawMajorX_triggered(self, enable):
        """ Signal handler called to toggle visiblity of major grid x axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableX(enable)
        self.plot.replot()
        self.saveMajorX()

    @pyqtSignature('bool')
    def on_actionDrawMajorY_triggered(self, enable):
        """ Signal handler called to toggle visiblity of major grid y axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableY(enable)
        self.plot.replot()
        self.saveMajorY()

    @pyqtSignature('bool')
    def on_actionDrawMinorX_triggered(self, enable):
        """ Signal handler called to toggle visiblity of minor grid x axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableXMin(enable)
        self.plot.replot()
        self.saveMinorX()

    @pyqtSignature('bool')
    def on_actionDrawMinorY_triggered(self, enable):
        """ Signal handler called to toggle visiblity of minor grid y axis.

        @param enable if True, grid axis is enabled
        @return None
        """
        self.grid.enableYMin(enable)
        self.plot.replot()
        self.saveMinorY()

    @pyqtSignature('')
    def on_actionChangeMajorGridStyle_triggered(self):
        """ Signal handler called to edit the major grid pen.

        @return None
        """
        pen = changePen(self.grid.majPen, self.grid.setMajPen, self)
        if pen:
            self.plot.replot()
            self.saveMajorX()
            self.saveMajorY()

    @pyqtSignature('')
    def on_actionChangeMinorGridStyle_triggered(self):
        """ Signal handler called to edit the minor grid pen.

        @return None
        """
        pen = changePen(self.grid.minPen, self.grid.setMinPen, self)
        if pen:
            self.plot.replot()
            self.saveMinorX()
            self.saveMinorY()

    @pyqtSignature('')
    def on_actionChangeCanvasColor_triggered(self):
        """ Signal handler called to edit the plot canvas background.

        @return None
        """
        plot = self.plot
        color = changeColor(
            plot.canvasBackground, plot.setCanvasBackground, self)
        if color:
            pen = QPen(complementColor(color))
            self.zoomer.setRubberBandPen(pen)
            self.picker.setTrackerPen(pen)
            plot.replot()
            self.saveCanvasColor()

    @pyqtSignature('')
    def on_actionChangeAxesFont_triggered(self):
        """ Signal handler called to edit the axes font.

        @return None
        """
        widget = self.referenceAxisWidget()
        default = widget.font()
        font, okay = QFontDialog.getFont(default, self, 'Select Axis Font')
        if okay:
            self.setAxisFont(font)
            self.settings.setValue(
                '%s/axisfont' % self.plotName(), font)

    @pyqtSignature('')
    def on_actionChangeAxesColor_triggered(self):
        """ Signal handler called to edit the axes color.

        @return None
        """
        color = changeColor(self.getAxisColor, self.setAxisColor, self)
        if color:
            self.settings.setValue('%s/axiscolor' % self.plotName(), color)

    @pyqtSignature('bool')
    def on_actionShowDataDialog_triggered(self, enable):
        """ Signal handler called to show or hide the data dialog.

        @return None
        """
        if enable:
            dlg = self.dataDialog = PlotDataDialog(self)
            try:
                tabs = self.window().centralTabs
            except (AttributeError, ):
                pass
            else:
                name = tabs.tabText(tabs.currentIndex())
                dlg.setWindowTitle(str(dlg.windowTitle()) % name)
                dlg.setWindowIcon(tabs.tabIcon(tabs.currentIndex()))
            self.connect(
                dlg, Signals.dialogFinished, self.on_dataDialog_finished)
            self.connect(
                dlg, Signals.highlightSelections, self.on_dataDialog_selected)
            dlg.show()
        elif self.dataDialog:
            self.dataDialog.close()
            self.dataDialog = None
        self.settings.setValue('%s/datadialog' % self.plotName(), enable)

    ## controls tree signal handlers

    def on_controlsTree_doubleClicked(self, index):
        """ Signal handler for control tree double click.

        @param index QModelIndex instance
        @return None
        """
        tree = self.controlsTree
        if index.isValid():
            pos = tree.visualRect(index).center()
            actions = tree.actions()
            for action in actions:
                action.setData(QVariant(pos))
            self.actionChangeCurveStyle.trigger()

    def on_controlsTree_itemChanged(self, item):
        """ Signal handler for all changes to control tree items.

        @param item changed tree widget item
        @return None
        """
        try:
            curve = item.curve
        except (AttributeError, ):
            pass
        else:
            self.enableCurve(item, enable=item.checkState()==Qt.Checked)
            self.updateAxis()
            self.saveSelections()

    def on_controlsTree_customContextMenuRequested(self, pos):
        """ Signal handler for context menu request over control tree.

        @param pos QPoint of mouse click
        @return None
        """
        tree = self.controlsTree
        index = tree.indexAt(pos)
        if index.isValid():
            item = self.controlsTreeModel.itemFromIndex(index)
            if not hasattr(item, 'curve'):
                return
            if item.curve.yAxis() == yRight:
                self.actionChangeCurveAxisY.setText('Move to Left Axis')
            else:
                self.actionChangeCurveAxisY.setText('Move to Right Axis')
            if item.curve.xAxis() == xTop:
                self.actionChangeCurveAxisX.setText('Move to Bottom Axis')
            else:
                self.actionChangeCurveAxisX.setText('Move to Top Axis')
            actions = tree.actions()
            for action in actions:
                action.setData(QVariant(pos))
            QMenu.exec_(actions, tree.mapToGlobal(pos))

    def on_dataDialog_finished(self, result):
        """ Signal handler for data dialog finish.

        Sets and saves state of data dialog display after its closed.

        @param result ignored
        @return None
        """
        self.actionShowDataDialog.setChecked(False)
        self.dataDialog = None
        self.on_dataDialog_selected([])
        self.settings.setValue('%s/datadialog' % self.plotName(), False)

    def on_dataDialog_selected(self, items):
        """ Signal handler for data dialog selection changes.

        @params items list of (index, item) two-tuples
        @return None
        """
        for marker in self.highlightMarkers:
            marker.detach()
        self.highlightMarkers = markers = []
        for index, item in items:
            try:
                x, y = index.row(), item.data[index.row()]
            except (IndexError, ):
                continue
            if x is None or y is None:
                continue
            curve = item.curve
            marker = curve.dataMarker.cloneFromValue(curve, x, y)
            markers.append(marker)
            marker.attach(self.plot)
        self.plot.replot()

    def on_plotSplitter_splitterMoved(self, pos, index):
        """ Signal handler for splitter move; saves state to user settings.

        @param pos ignored
        @param index ignored
        @return None
        """
        settings = self.settings
        statekey = '%s/%s' % (self.plotName(), settings.keys.splitstate)
        settings.setValue(statekey, self.plotSplitter.saveState())

    def syncPlot(self, sync=None):
        print '## sync?', sync
        session = self.session
        (session.registerMeta if sync else session.deregisterMeta)(self)
Example #25
0
 def on_actionSettings_triggered(self):
     from profit.workbench.settingsdialog import SettingsDialog
     dlg = SettingsDialog()
     dlg.readSettings(Settings())
     if dlg.exec_() == dlg.Accepted:
         self.emit(Signals.settingsChanged)