comparison python/ide.py @ 248:b10d46e5c8dd

ide refactor
author Windel Bouwman
date Fri, 26 Jul 2013 16:46:02 +0200
parents dd8bbb963458
children e41e4109addd
comparison
equal deleted inserted replaced
247:dd8bbb963458 248:b10d46e5c8dd
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 import sys, os, base64 3 import sys
4 assert sys.version_info.major == 3, "Needs to be run in python version 3.x" 4 import os
5 5
6 from PyQt4.QtCore import * 6 from PyQt4.QtCore import *
7 from PyQt4.QtGui import * 7 from PyQt4.QtGui import *
8 8
9 # Compiler imports: 9 # Compiler imports:
10 import ppci 10 import ppci
11 from astviewer import AstViewer 11 from astviewer import AstViewer
12 #from codeeditor import CodeEdit
13 from codeedit import CodeEdit 12 from codeedit import CodeEdit
14 stutil = __import__('st-util') 13 stutil = __import__('st-util')
15 import c3 14 import c3
16 15
16
17 class BuildOutput(QTextEdit): 17 class BuildOutput(QTextEdit):
18 """ Build output component """ 18 """ Build output component """
19 def __init__(self, parent=None): 19 def __init__(self, parent=None):
20 super(BuildOutput, self).__init__(parent) 20 super(BuildOutput, self).__init__(parent)
21 self.setCurrentFont(QFont('Courier')) 21 self.setCurrentFont(QFont('Courier'))
22 self.setReadOnly(True) 22 self.setReadOnly(True)
23 self.append('Build output will appear here!') 23 self.append('Build output will appear here!')
24 24
25
25 class BuildErrors(QTreeView): 26 class BuildErrors(QTreeView):
26 sigErrorSelected = pyqtSignal(object) 27 sigErrorSelected = pyqtSignal(object)
27 def __init__(self, parent=None): 28 def __init__(self, parent=None):
28 super(BuildErrors, self).__init__(parent) 29 super(BuildErrors, self).__init__(parent)
29 model = QStandardItemModel() 30 model = QStandardItemModel()
30 self.setModel(model) 31 self.setModel(model)
31 self.clicked.connect(self.itemSelected) 32 self.clicked.connect(self.itemSelected)
32 self.errorIcon = QIcon('icons/error.png') 33 self.errorIcon = QIcon('icons/error.png')
33 self.model = QStandardItemModel() 34 self.model = QStandardItemModel()
34 self.model.setHorizontalHeaderLabels(['Message', 'Row', 'Column']) 35 self.model.setHorizontalHeaderLabels(['Message', 'Row', 'Column'])
35 self.setModel(self.model) 36 self.setModel(self.model)
36 37
37 def setErrorList(self, errorlist): 38 def setErrorList(self, errorlist):
38 c = self.model.rowCount() 39 c = self.model.rowCount()
39 self.model.removeRows(0, c) 40 self.model.removeRows(0, c)
40 for e in errorlist: 41 for e in errorlist:
41 item = QStandardItem(self.errorIcon, str(e.msg)) 42 item = QStandardItem(self.errorIcon, str(e.msg))
42 item.setData(e) 43 item.setData(e)
43 irow = QStandardItem(str(e.loc.row)) 44 irow = QStandardItem(str(e.loc.row))
44 irow.setData(e) 45 irow.setData(e)
45 icol = QStandardItem(str(e.loc.col)) 46 icol = QStandardItem(str(e.loc.col))
46 icol.setData(e) 47 icol.setData(e)
47 self.model.appendRow([item, irow, icol]) 48 self.model.appendRow([item, irow, icol])
48 def itemSelected(self, index): 49
50 def itemSelected(self, index):
49 if not index.isValid(): 51 if not index.isValid():
50 return 52 return
51 item = self.model.itemFromIndex(index) 53 item = self.model.itemFromIndex(index)
52 err = item.data() 54 err = item.data()
53 self.sigErrorSelected.emit(err) 55 self.sigErrorSelected.emit(err)
54 56
55 57
56 class AboutDialog(QDialog): 58 class AboutDialog(QDialog):
57 def __init__(self, parent=None): 59 def __init__(self, parent=None):
58 super(AboutDialog, self).__init__(parent) 60 super(AboutDialog, self).__init__(parent)
59 self.setWindowTitle('About') 61 self.setWindowTitle('About')
60 l = QVBoxLayout(self) 62 l = QVBoxLayout(self)
61 txt = QTextEdit(self) 63 txt = QTextEdit(self)
62 txt.setReadOnly(True) 64 txt.setReadOnly(True)
63 aboutText = """<h1>lcfOS IDE</h1> 65 aboutText = """<h1>lcfOS IDE</h1>
64 <p>An all-in-one IDE for OS development.</p> 66 <p>An all-in-one IDE for OS development.</p>
65 <p>https://www.assembla.com/spaces/lcfOS/wiki</p> 67 <p>https://www.assembla.com/spaces/lcfOS/wiki</p>
66 <p>Author: Windel Bouwman</p> 68 <p>Author: Windel Bouwman</p>
67 """ 69 """
68 txt.append(aboutText) 70 txt.append(aboutText)
69 l.addWidget(txt) 71 l.addWidget(txt)
70 but = QPushButton('OK') 72 but = QPushButton('OK')
71 but.setDefault(True) 73 but.setDefault(True)
72 but.clicked.connect(self.close) 74 but.clicked.connect(self.close)
73 l.addWidget(but) 75 l.addWidget(but)
76
74 77
75 class Ide(QMainWindow): 78 class Ide(QMainWindow):
76 def __init__(self, parent=None): 79 def __init__(self, parent=None):
77 super(Ide, self).__init__(parent) 80 super(Ide, self).__init__(parent)
78 self.setWindowTitle('LCFOS IDE') 81 self.setWindowTitle('LCFOS IDE')
79 icon = QIcon('icons/logo.png') 82 icon = QIcon('icons/logo.png')
80 self.setWindowIcon(icon) 83 self.setWindowIcon(icon)
81 84
82 # Create menus: 85 # Create menus:
83 mb = self.menuBar() 86 mb = self.menuBar()
84 self.fileMenu = mb.addMenu('File') 87 self.fileMenu = mb.addMenu('File')
85 self.viewMenu = mb.addMenu('View') 88 self.viewMenu = mb.addMenu('View')
86 self.helpMenu = mb.addMenu('Help') 89 self.helpMenu = mb.addMenu('Help')
87 90
88 # Create mdi area: 91 # Create mdi area:
89 self.mdiArea = QMdiArea() 92 self.mdiArea = QMdiArea()
90 self.setCentralWidget(self.mdiArea) 93 self.mdiArea.setViewMode(QMdiArea.TabbedView)
91 94 self.setCentralWidget(self.mdiArea)
92 # Create components: 95
93 def addComponent(name, widget): 96 # Create components:
94 dw = QDockWidget(name) 97 def addComponent(name, widget):
95 dw.setWidget(widget) 98 dw = QDockWidget(name)
96 dw.setObjectName(name) 99 dw.setWidget(widget)
97 self.addDockWidget(Qt.RightDockWidgetArea, dw) 100 dw.setObjectName(name)
98 self.viewMenu.addAction(dw.toggleViewAction()) 101 self.addDockWidget(Qt.RightDockWidgetArea, dw)
99 return widget 102 self.viewMenu.addAction(dw.toggleViewAction())
100 103 return widget
101 self.buildOutput = addComponent('Build output', BuildOutput()) 104
102 self.astViewer = addComponent('AST viewer', AstViewer()) 105 self.buildOutput = addComponent('Build output', BuildOutput())
103 self.astViewer.sigNodeSelected.connect(self.nodeSelected) 106 self.astViewer = addComponent('AST viewer', AstViewer())
104 self.builderrors = addComponent('Build errors', BuildErrors()) 107 self.astViewer.sigNodeSelected.connect(self.nodeSelected)
105 self.builderrors.sigErrorSelected.connect(self.errorSelected) 108 self.builderrors = addComponent('Build errors', BuildErrors())
106 self.devxplr = addComponent('Device explorer', stutil.DeviceExplorer()) 109 self.builderrors.sigErrorSelected.connect(self.errorSelected)
107 self.regview = addComponent('Registers', stutil.RegisterView()) 110 self.devxplr = addComponent('Device explorer', stutil.DeviceExplorer())
108 self.memview = addComponent('Memory', stutil.MemoryView()) 111 self.regview = addComponent('Registers', stutil.RegisterView())
109 self.ctrlToolbar = stutil.DebugToolbar() 112 self.memview = addComponent('Memory', stutil.MemoryView())
110 self.addToolBar(self.ctrlToolbar) 113 self.ctrlToolbar = stutil.DebugToolbar()
111 self.ctrlToolbar.setObjectName('debugToolbar') 114 self.addToolBar(self.ctrlToolbar)
112 self.devxplr.deviceSelected.connect(self.regview.mdl.setDevice) 115 self.ctrlToolbar.setObjectName('debugToolbar')
113 self.ctrlToolbar.statusChange.connect(self.memview.refresh) 116 self.devxplr.deviceSelected.connect(self.regview.mdl.setDevice)
114 self.devxplr.deviceSelected.connect(self.memview.setDevice) 117 self.ctrlToolbar.statusChange.connect(self.memview.refresh)
115 self.devxplr.deviceSelected.connect(self.ctrlToolbar.setDevice) 118 self.devxplr.deviceSelected.connect(self.memview.setDevice)
116 self.ctrlToolbar.statusChange.connect(self.regview.refresh) 119 self.devxplr.deviceSelected.connect(self.ctrlToolbar.setDevice)
117 self.ctrlToolbar.codePosition.connect(self.pointCode) 120 self.ctrlToolbar.statusChange.connect(self.regview.refresh)
118 121 self.ctrlToolbar.codePosition.connect(self.pointCode)
119 # About dialog: 122
120 self.aboutDialog = AboutDialog() 123 # About dialog:
121 self.aboutDialog.setWindowIcon(icon) 124 self.aboutDialog = AboutDialog()
122 # Create actions: 125 self.aboutDialog.setWindowIcon(icon)
123 def addMenuEntry(name, menu, callback, shortcut=None): 126 # Create actions:
124 a = QAction(name, self) 127 def addMenuEntry(name, menu, callback, shortcut=None):
125 menu.addAction(a) 128 a = QAction(name, self)
126 a.triggered.connect(callback) 129 menu.addAction(a)
127 if shortcut: 130 a.triggered.connect(callback)
128 a.setShortcut(shortcut) 131 if shortcut:
129 132 a.setShortcut(shortcut)
130 addMenuEntry("New", self.fileMenu, self.newFile, shortcut=QKeySequence(QKeySequence.New)) 133
131 addMenuEntry("Open", self.fileMenu, self.openFile, shortcut=QKeySequence(QKeySequence.Open)) 134 addMenuEntry("New", self.fileMenu, self.newFile, shortcut=QKeySequence(QKeySequence.New))
132 addMenuEntry("Save", self.fileMenu, self.saveFile, shortcut=QKeySequence(QKeySequence.Save)) 135 addMenuEntry("Open", self.fileMenu, self.openFile, shortcut=QKeySequence(QKeySequence.Open))
133 addMenuEntry("Build", self.fileMenu, self.buildFile, shortcut=QKeySequence("F7")) 136 addMenuEntry("Save", self.fileMenu, self.saveFile, shortcut=QKeySequence(QKeySequence.Save))
134 137 addMenuEntry("Build", self.fileMenu, self.buildFile, shortcut=QKeySequence("F7"))
135 self.helpAction = QAction('Help', self) 138
136 self.helpAction.setShortcut(QKeySequence('F1')) 139 self.helpAction = QAction('Help', self)
137 self.helpMenu.addAction(self.helpAction) 140 self.helpAction.setShortcut(QKeySequence('F1'))
138 addMenuEntry('About', self.helpMenu, self.aboutDialog.open) 141 self.helpMenu.addAction(self.helpAction)
139 142 addMenuEntry('About', self.helpMenu, self.aboutDialog.open)
140 addMenuEntry('Cascade windows', self.viewMenu, self.mdiArea.cascadeSubWindows) 143
141 addMenuEntry('Tile windows', self.viewMenu, self.mdiArea.tileSubWindows) 144 addMenuEntry('Cascade windows', self.viewMenu, self.mdiArea.cascadeSubWindows)
142 145 addMenuEntry('Tile windows', self.viewMenu, self.mdiArea.tileSubWindows)
143 sb = self.statusBar() 146 sb = self.statusBar()
144 147
145 # Load settings: 148 # Load settings:
146 self.settings = QSettings('windelsoft', 'lcfoside') 149 self.settings = QSettings('windelsoft', 'lcfoside')
147 self.loadSettings() 150 self.loadSettings()
148 151 self.diag = ppci.DiagnosticsManager()
149 ce = self.newFile() 152 self.c3front = c3.Builder(self.diag)
150 self.diag = ppci.DiagnosticsManager() 153
151 self.c3front = c3.Builder(self.diag) 154 # File handling:
152 155 def newFile(self):
153 # File handling: 156 self.newCodeEdit()
154 def newFile(self): 157
155 ce = CodeEdit() 158 def openFile(self):
156 ce.textChanged.connect(self.buildFile) 159 filename = QFileDialog.getOpenFileName(self, "Open C3 file...", "*.c3",
157 w = self.mdiArea.addSubWindow(ce) 160 "C3 source files (*.c3)")
158 ce.show() 161 if filename:
159 w.resize(500, 700) 162 self.loadFile(filename)
160 return ce 163
161 164 def saveFile(self):
162 def openFile(self): 165 ac = self.activeMdiChild()
163 filename = QFileDialog.getOpenFileName(self, "Open C3 file...", "*.c3", "C3 source files (*.ks)") 166 if ac:
164 if filename: 167 ac.save()
165 self.loadFile(filename) 168
166 169 def loadFile(self, filename):
167 def saveFile(self): 170 ce = self.newCodeEdit()
168 ac = self.activeMdiChild() 171 try:
169 if ac: 172 with open(filename) as f:
170 ac.save() 173 ce.Source = f.read()
171 174 ce.FileName = filename
172 def loadFile(self, filename): 175 except Exception as e:
173 # Find existing mdi widget: 176 print('exception opening file', e)
174 wid = self.findMdiChild(filename) 177
175 if wid: 178 # MDI:
176 self.mdiArea.setActiveSubWindow(wid.parent()) 179 def newCodeEdit(self):
177 return wid 180 ce = CodeEdit()
178 181 ce.textChanged.connect(self.buildFile)
179 # Create a new one: 182 w = self.mdiArea.addSubWindow(ce)
180 ce = CodeEdit() 183 ce.show()
181 184 return ce
182 #source = self.project.loadProjectFile(filename) 185
183 try: 186 def activeMdiChild(self):
184 with open(filename) as f: 187 aw = self.mdiArea.activeSubWindow()
185 source = f.read() 188 if aw:
186 ce.setSource(source) 189 return aw.widget()
187 except Exception as e: 190
188 print('exception opening file', e) 191 def findMdiChild(self, filename):
189 self.mdiArea.addSubWindow(ce) 192 for wid in self.allChildren():
190 ce.setFileName(filename) 193 if wid.filename == filename:
191 ce.show() 194 return wid
192 return ce 195
193 196 def allChildren(self):
194 # MDI: 197 return [w.widget() for w in self.mdiArea.subWindowList()]
195 def activeMdiChild(self): 198
196 aw = self.mdiArea.activeSubWindow() 199 # Settings:
197 if aw: 200 def loadSettings(self):
198 return aw.widget() 201 if self.settings.contains('mainwindowstate'):
199 else: 202 self.restoreState(self.settings.value('mainwindowstate'))
200 return None 203 if self.settings.contains('mainwindowgeometry'):
201 204 self.restoreGeometry(self.settings.value('mainwindowgeometry'))
202 def findMdiChild(self, filename): 205 if self.settings.contains('lastfiles'):
203 for window in self.mdiArea.subWindowList(): 206 lfs = self.settings.value('lastfiles')
204 wid = window.widget() 207 for lf in lfs:
205 if wid.filename == filename: 208 self.loadFile(lf)
206 return wid 209
207 return None 210 def closeEvent(self, ev):
208 211 self.settings.setValue('mainwindowstate', self.saveState())
209 def allChildren(self): 212 self.settings.setValue('mainwindowgeometry', self.saveGeometry())
210 c = [] 213 ac = self.activeMdiChild()
211 for window in self.mdiArea.subWindowList(): 214 lfs = [ce.FileName for ce in self.allChildren() if ce.FileName]
212 wid = window.widget() 215 self.settings.setValue('lastfiles', lfs)
213 c.append(wid) 216 ev.accept()
214 return c 217
215 218 # Error handling:
216 # Settings: 219 def nodeSelected(self, node):
217 def loadSettings(self): 220 self.showLoc(node.loc)
218 if self.settings.contains('mainwindowstate'): 221
219 self.restoreState(self.settings.value('mainwindowstate')) 222 def errorSelected(self, err):
220 if self.settings.contains('mainwindowgeometry'): 223 self.showLoc(err.loc)
221 self.restoreGeometry(self.settings.value('mainwindowgeometry')) 224
222 if self.settings.contains('lastfile'): 225 def showLoc(self, loc):
223 self.loadFile(self.settings.value('lastfile')) 226 ce = self.activeMdiChild()
224 227 if not ce:
225 def closeEvent(self, ev): 228 return
226 self.settings.setValue('mainwindowstate', self.saveState()) 229 if loc:
227 self.settings.setValue('mainwindowgeometry', self.saveGeometry()) 230 ce.setRowCol(loc.row, loc.col)
228 # # TODO: ask for save of opened files 231 ce.setFocus()
229 ac = self.activeMdiChild()
230 if ac:
231 if hasattr(ac, 'filename') and ac.filename:
232 self.settings.setValue('lastfile', ac.filename)
233 else: 232 else:
234 self.settings.remove('lastfile') 233 ce.clearErrors()
235 else: 234
236 self.settings.remove('lastfile') 235 def pointCode(self, p):
237 ev.accept()
238
239 # Error handling:
240 def nodeSelected(self, node):
241 ce = self.activeMdiChild()
242 if not ce:
243 return
244 if node.loc:
245 row, col = node.loc.row, node.loc.col
246 ce.setRowCol(row, col)
247 ce.setFocus()
248 else:
249 ce.clearErrors()
250
251 def errorSelected(self, err):
252 ce = self.activeMdiChild()
253 if not ce:
254 return
255 ce.setRowCol(err.loc.row, err.loc.col)
256 ce.setFocus()
257
258 def pointCode(self, p):
259 print('PC', p) 236 print('PC', p)
260 237
261 238 # Build recepy:
262 # Build recepy: 239 def buildFile(self):
263 def buildFile(self): 240 ce = self.activeMdiChild()
264 ce = self.activeMdiChild() 241 if not ce:
265 if ce: 242 return
266 source = ce.Source
267 self.buildOutput.clear() 243 self.buildOutput.clear()
244 self.diag.clear()
268 self.buildOutput.append('Starting build') 245 self.buildOutput.append('Starting build')
269 ir = self.c3front.build(source) 246 ir = self.c3front.build(ce.Source)
247
248 # Set errors:
249 for err in self.diag.diags:
250 self.buildOutput.append(str(err))
251 self.builderrors.setErrorList(self.diag.diags)
252 ce.setErrors(self.diag.diags)
270 ast = self.c3front.pkg 253 ast = self.c3front.pkg
271 self.astViewer.setAst(ast) 254 self.astViewer.setAst(ast)
272 self.buildOutput.append("Done!") 255 self.buildOutput.append("Done!")
273 256
274 if __name__ == '__main__': 257 if __name__ == '__main__':