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