view python/ide.py @ 247:dd8bbb963458

project remove
author Windel Bouwman
date Fri, 26 Jul 2013 10:44:26 +0200
parents 6259856841a0
children b10d46e5c8dd
line wrap: on
line source

#!/usr/bin/python

import sys, os, base64
assert sys.version_info.major == 3, "Needs to be run in python version 3.x"

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

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

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.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()

    ce = self.newFile()
    self.diag = ppci.DiagnosticsManager()
    self.c3front = c3.Builder(self.diag)

  # File handling:
  def newFile(self):
     ce = CodeEdit()
     ce.textChanged.connect(self.buildFile)
     w = self.mdiArea.addSubWindow(ce)
     ce.show()
     w.resize(500, 700)
     return ce

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

  def saveFile(self):
     ac = self.activeMdiChild()
     if ac:
         ac.save()
  
  def loadFile(self, filename):
     # Find existing mdi widget:
     wid = self.findMdiChild(filename)
     if wid:
        self.mdiArea.setActiveSubWindow(wid.parent())
        return wid

     # Create a new one:
     ce = CodeEdit()

     #source = self.project.loadProjectFile(filename)
     try:
        with open(filename) as f:
          source = f.read()
          ce.setSource(source)
     except Exception as e:
        print('exception opening file', e)
     self.mdiArea.addSubWindow(ce)
     ce.setFileName(filename)
     ce.show()
     return ce

  # MDI:
  def activeMdiChild(self):
     aw = self.mdiArea.activeSubWindow()
     if aw:
        return aw.widget()
     else:
        return None

  def findMdiChild(self, filename):
     for window in self.mdiArea.subWindowList():
        wid = window.widget()
        if wid.filename == filename:
           return wid
     return None
  
  def allChildren(self):
     c = []
     for window in self.mdiArea.subWindowList():
        wid = window.widget()
        c.append(wid)
     return c

  # 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('lastfile'):
        self.loadFile(self.settings.value('lastfile'))
  
  def closeEvent(self, ev):
     self.settings.setValue('mainwindowstate', self.saveState())
     self.settings.setValue('mainwindowgeometry', self.saveGeometry())
     #   # TODO: ask for save of opened files
     ac = self.activeMdiChild()
     if ac:
        if hasattr(ac, 'filename') and ac.filename:
           self.settings.setValue('lastfile', ac.filename)
        else:
           self.settings.remove('lastfile')
     else:
        self.settings.remove('lastfile')
     ev.accept()

  # Error handling:
  def nodeSelected(self, node):
      ce = self.activeMdiChild()
      if not ce:
         return
      if node.loc:
         row, col = node.loc.row, node.loc.col
         ce.setRowCol(row, col)
         ce.setFocus()
      else:
         ce.clearErrors()

  def errorSelected(self, err):
     ce = self.activeMdiChild()
     if not ce:
        return
     ce.setRowCol(err.loc.row, err.loc.col)
     ce.setFocus()

  def pointCode(self, p):
        print('PC', p)


  # Build recepy:
  def buildFile(self):
     ce = self.activeMdiChild()
     if ce:
        source = ce.Source
        self.buildOutput.clear()
        self.buildOutput.append('Starting build')
        ir = self.c3front.build(source)
        ast = self.c3front.pkg
        self.astViewer.setAst(ast)
        self.buildOutput.append("Done!")

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