Mercurial > lcfOS
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__': |