view python/ide.py @ 252:c4370696ccc7

added optimize function
author Windel Bouwman
date Tue, 30 Jul 2013 17:57:46 +0200
parents 6ed3d3a82a63
children bd26dc13f270
line wrap: on
line source

#!/usr/bin/python

import sys
import os

from PyQt4.QtCore import *
from PyQt4.QtGui import *

# Compiler imports:
import ppci
from astviewer import AstViewer
from codeedit import CodeEdit
stutil = __import__('st-util')
import c3
import zcc
import outstream


class BuildOutput(QTextEdit):
    """ Build output component """
    def __init__(self, parent=None):
      super(BuildOutput, self).__init__(parent)
      self.setCurrentFont(QFont('Courier'))
      self.setReadOnly(True)
      self.append('Build output will appear here!')


class BuildErrors(QTreeView):
    sigErrorSelected = pyqtSignal(object)
    def __init__(self, parent=None):
        super(BuildErrors, self).__init__(parent)
        model = QStandardItemModel()
        self.setModel(model)
        self.clicked.connect(self.itemSelected)
        self.errorIcon = QIcon('icons/error.png')
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Message', 'Row', 'Column'])
        self.setModel(self.model)

    def setErrorList(self, errorlist):
      c = self.model.rowCount()
      self.model.removeRows(0, c)
      for e in errorlist:
         item = QStandardItem(self.errorIcon, str(e.msg))
         item.setData(e)
         irow = QStandardItem(str(e.loc.row))
         irow.setData(e)
         icol = QStandardItem(str(e.loc.col))
         icol.setData(e)
         self.model.appendRow([item, irow, icol])

    def itemSelected(self, index):
      if not index.isValid():
         return
      item = self.model.itemFromIndex(index)
      err = item.data()
      self.sigErrorSelected.emit(err)


class AboutDialog(QDialog):
    def __init__(self, parent=None):
        super(AboutDialog, self).__init__(parent)
        self.setWindowTitle('About')
        l = QVBoxLayout(self)
        txt = QTextEdit(self)
        txt.setReadOnly(True)
        aboutText = """<h1>lcfOS IDE</h1>
        <p>An all-in-one IDE for OS development.</p>
        <p>https://www.assembla.com/spaces/lcfOS/wiki</p>
        <p>Author: Windel Bouwman</p>
        """
        txt.append(aboutText)
        l.addWidget(txt)
        but = QPushButton('OK')
        but.setDefault(True)
        but.clicked.connect(self.close)
        l.addWidget(but)


class Ide(QMainWindow):
    def __init__(self, parent=None):
        super(Ide, self).__init__(parent)
        self.setWindowTitle('LCFOS IDE')
        icon = QIcon('icons/logo.png')
        self.setWindowIcon(icon)

        # Create menus:
        mb = self.menuBar()
        self.fileMenu = mb.addMenu('File')
        self.viewMenu = mb.addMenu('View')
        self.helpMenu = mb.addMenu('Help')

        # Create mdi area:
        self.mdiArea = QMdiArea()
        self.mdiArea.setViewMode(QMdiArea.TabbedView)
        self.mdiArea.setTabsClosable(True)
        self.setCentralWidget(self.mdiArea)

        # Create components:
        def addComponent(name, widget):
           dw = QDockWidget(name)
           dw.setWidget(widget)
           dw.setObjectName(name)
           self.addDockWidget(Qt.RightDockWidgetArea, dw)
           self.viewMenu.addAction(dw.toggleViewAction())
           return widget

        self.buildOutput = addComponent('Build output', BuildOutput())
        self.astViewer = addComponent('AST viewer', AstViewer())
        self.astViewer.sigNodeSelected.connect(self.nodeSelected)
        self.builderrors = addComponent('Build errors', BuildErrors())
        self.builderrors.sigErrorSelected.connect(self.errorSelected)
        self.devxplr = addComponent('Device explorer', stutil.DeviceExplorer())
        self.regview = addComponent('Registers', stutil.RegisterView())
        self.memview = addComponent('Memory', stutil.MemoryView())
        self.ctrlToolbar = stutil.DebugToolbar()
        self.addToolBar(self.ctrlToolbar)
        self.ctrlToolbar.setObjectName('debugToolbar')
        self.devxplr.deviceSelected.connect(self.regview.mdl.setDevice)
        self.ctrlToolbar.statusChange.connect(self.memview.refresh)
        self.devxplr.deviceSelected.connect(self.memview.setDevice)
        self.devxplr.deviceSelected.connect(self.ctrlToolbar.setDevice)
        self.ctrlToolbar.statusChange.connect(self.regview.refresh)
        self.ctrlToolbar.codePosition.connect(self.pointCode)

        # About dialog:
        self.aboutDialog = AboutDialog()
        self.aboutDialog.setWindowIcon(icon)
        # Create actions:
        def addMenuEntry(name, menu, callback, shortcut=None):
          a = QAction(name, self)
          menu.addAction(a)
          a.triggered.connect(callback)
          if shortcut:
             a.setShortcut(shortcut)

        addMenuEntry("New", self.fileMenu, self.newFile, shortcut=QKeySequence(QKeySequence.New))
        addMenuEntry("Open", self.fileMenu, self.openFile, shortcut=QKeySequence(QKeySequence.Open))
        addMenuEntry("Save", self.fileMenu, self.saveFile, shortcut=QKeySequence(QKeySequence.Save))
        addMenuEntry("Build", self.fileMenu, self.buildFile, shortcut=QKeySequence("F7"))

        self.helpAction  = QAction('Help', self)
        self.helpAction.setShortcut(QKeySequence('F1'))
        self.helpMenu.addAction(self.helpAction)
        addMenuEntry('About', self.helpMenu, self.aboutDialog.open)

        addMenuEntry('Cascade windows', self.viewMenu, self.mdiArea.cascadeSubWindows)
        addMenuEntry('Tile windows', self.viewMenu, self.mdiArea.tileSubWindows)
        sb = self.statusBar()

        # Load settings:
        self.settings = QSettings('windelsoft', 'lcfoside')
        self.loadSettings()
        self.diag = ppci.DiagnosticsManager()
        self.c3front = c3.Builder(self.diag)

    # File handling:
    def newFile(self):
        self.newCodeEdit()

    def openFile(self):
        filename = QFileDialog.getOpenFileName(self, "Open C3 file...", "*.c3",
            "C3 source files (*.c3)")
        if filename:
            self.loadFile(filename)

    def saveFile(self):
        ac = self.activeMdiChild()
        if ac:
            ac.save()

    def loadFile(self, filename):
        ce = self.newCodeEdit()
        try:
            with open(filename) as f:
                ce.Source = f.read()
                ce.FileName = filename
        except Exception as e:
            print('exception opening file', e)

    # MDI:
    def newCodeEdit(self):
        ce = CodeEdit()
        ce.textChanged.connect(self.parseFile)
        w = self.mdiArea.addSubWindow(ce)
        self.mdiArea.setActiveSubWindow(w)
        ce.showMaximized()
        return ce

    def activeMdiChild(self):
        aw = self.mdiArea.activeSubWindow()
        if aw:
            return aw.widget()

    def findMdiChild(self, filename):
        for wid in self.allChildren():
            if wid.filename == filename:
                return wid

    def allChildren(self):
        return [w.widget() for w in self.mdiArea.subWindowList()]

    # Settings:
    def loadSettings(self):
        if self.settings.contains('mainwindowstate'):
            self.restoreState(self.settings.value('mainwindowstate'))
        if self.settings.contains('mainwindowgeometry'):
            self.restoreGeometry(self.settings.value('mainwindowgeometry'))
        if self.settings.contains('lastfiles'):
            lfs = self.settings.value('lastfiles')
            for lf in lfs:
                self.loadFile(lf)

    def closeEvent(self, ev):
        self.settings.setValue('mainwindowstate', self.saveState())
        self.settings.setValue('mainwindowgeometry', self.saveGeometry())
        ac = self.activeMdiChild()
        lfs = [ce.FileName for ce in self.allChildren() if ce.FileName]
        self.settings.setValue('lastfiles', lfs)
        ev.accept()

    # Error handling:
    def nodeSelected(self, node):
        self.showLoc(node.loc)

    def errorSelected(self, err):
        self.showLoc(err.loc)

    def showLoc(self, loc):
        ce = self.activeMdiChild()
        if not ce:
            return
        if loc:
            ce.setRowCol(loc.row, loc.col)
            ce.setFocus()
        else:
            ce.clearErrors()

    def pointCode(self, p):
        # Lookup pc in debug infos:
        loc = None
        if hasattr(self, 'debugInfo'):
            for di in self.debugInfo:
                if di.address > p:
                    loc = di.info
                    break
        if loc:
            ce = self.activeMdiChild()
            if ce:
                ce.ic.arrow = loc
            self.showLoc(loc)

    # Build recepy:
    def parseFile(self):
        ce = self.activeMdiChild()
        if not ce:
            return
        self.diag.clear()
        self.buildOutput.append('Starting parse')
        pkg = self.c3front.parse(ce.Source)

        # Set errors:
        for err in self.diag.diags:
            self.buildOutput.append(str(err))
        self.builderrors.setErrorList(self.diag.diags)
        ce.setErrors(self.diag.diags)
        self.astViewer.setAst(pkg)
        self.buildOutput.append("Done!")

    def buildFile(self):
        ce = self.activeMdiChild()
        if not ce:
            return
        self.diag.clear()
        self.buildOutput.append('Starting build')
        outs = outstream.TextOutputStream()
        if not zcc.zcc(ce.Source, outs, self.diag):
            # Set errors:
            for err in self.diag.diags:
                self.buildOutput.append(str(err))
            self.builderrors.setErrorList(self.diag.diags)
            ce.setErrors(self.diag.diags)
            return

        code_s = outs.getSection('code')
        self.debugInfo = code_s.debugInfos()
        self.buildOutput.append("Flashing stm32f4 discovery")
        if self.ctrlToolbar.device:
            bts = code_s.to_bytes()
            self.ctrlToolbar.device.writeFlash(0x08000000, bts)
            stl = self.ctrlToolbar.device.iface
            stl.reset()
            stl.halt()

        self.buildOutput.append("Done!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ide = Ide()
    ide.show()
    app.exec_()