comparison python/apps/ide/ide.py @ 63:32078200cdd6

Several move action
author windel
date Sun, 07 Oct 2012 17:04:10 +0200
parents python/ide/ide/ide.py@fd7d5069734e
children 4a27c28c7d0f
comparison
equal deleted inserted replaced
62:fd7d5069734e 63:32078200cdd6
1 from PyQt4.QtCore import *
2 from PyQt4.QtGui import *
3 # ide components:
4 from .codeeditor import CodeEdit
5 from .astviewer import AstViewer
6 import base64
7 from project import Project
8 import os.path
9
10 lcfospng = base64.decodestring(b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A\n/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEhMKBk7B678AAAA/SURBVFjD\n7dbBCQAgDATBi9h/y7EFA4Kf2QLCwH1S6XQu6sqoujublc8BAAAAAAAAAAB8B+zXT6YJAAAAAKYd\nWSgFQNUyijIAAAAASUVORK5CYII=\n')
11
12 class BuildOutput(QTextEdit):
13 """ Build output component """
14 def __init__(self, parent=None):
15 super(BuildOutput, self).__init__(parent)
16 self.setCurrentFont(QFont('Courier'))
17 self.setReadOnly(True)
18 self.append('Build output will appear here!')
19
20 class BuildErrors(QListView):
21 sigErrorSelected = pyqtSignal(object)
22 def __init__(self, parent=None):
23 super(BuildErrors, self).__init__(parent)
24 model = QStandardItemModel()
25 self.setModel(model)
26 self.clicked.connect(self.itemSelected)
27 def setErrorList(self, errorlist):
28 model = QStandardItemModel()
29 for e in errorlist:
30 row, col, msg = e
31 item = QStandardItem(str(msg))
32 item.setData(e)
33 model.appendRow(item)
34 self.setModel(model)
35 def itemSelected(self, index):
36 if not index.isValid():
37 return
38 model = self.model()
39 item = model.itemFromIndex(index)
40 err = item.data()
41 self.sigErrorSelected.emit(err)
42
43 class ProjectView(QWidget):
44 sigLoadFile = pyqtSignal(str)
45 def __init__(self, parent=None):
46 super(ProjectView, self).__init__(parent)
47 self.treeview = QTreeView(self)
48 self.treeview.setContextMenuPolicy(Qt.CustomContextMenu)
49 l = QVBoxLayout(self)
50 l.addWidget(self.treeview)
51 pm = QPixmap()
52 pm.loadFromData(lcfospng)
53 self.projectIcon = QIcon(pm)
54 # Connect signals:
55 self.treeview.activated.connect(self.activate)
56 self.treeview.customContextMenuRequested.connect(self.contextMenu)
57 def setProject(self, project):
58 self.project = project
59 model = QStandardItemModel()
60 root = model.invisibleRootItem()
61 pitem = QStandardItem(self.projectIcon, project.name)
62 pitem.setEditable(False)
63 pitem.setData(project)
64 root.appendRow(pitem)
65 for f in self.project.files:
66 fitem = QStandardItem(f)
67 pitem.appendRow(fitem)
68 fitem.setEditable(False)
69 fitem.setData(f)
70 self.treeview.setModel(model)
71 self.treeview.expandAll()
72 def contextMenu(self, pos):
73 idx = self.treeview.indexAt(pos)
74 if not idx.isValid():
75 return
76 item = self.treeview.model().itemFromIndex(idx)
77 def activate(self, index):
78 if not index.isValid():
79 return
80 model = self.treeview.model()
81 item = model.itemFromIndex(index)
82 fn = item.data()
83 if type(fn) is str:
84 self.sigLoadFile.emit(fn)
85
86 class AboutDialog(QDialog):
87 def __init__(self, parent=None):
88 super(AboutDialog, self).__init__(parent)
89 self.setWindowTitle('About')
90 l = QVBoxLayout(self)
91 txt = QTextEdit(self)
92 txt.setReadOnly(True)
93 aboutText = """<h1>lcfOS IDE</h1>
94 <p>An all-in-one IDE for OS development.</p>
95 <p>https://www.assembla.com/spaces/lcfOS/wiki</p>
96 <p>Author: Windel Bouwman</p>
97 """
98 txt.append(aboutText)
99 l.addWidget(txt)
100 but = QPushButton('OK')
101 but.setDefault(True)
102 but.clicked.connect(self.close)
103 l.addWidget(but)
104
105 class ProjectOptions(QDialog):
106 pass
107 # TODO: project options in here
108
109 class Ide(QMainWindow):
110 def __init__(self, parent=None):
111 super(Ide, self).__init__(parent)
112 self.setWindowTitle('LCFOS IDE')
113 icon = QPixmap()
114 icon.loadFromData(lcfospng)
115 self.setWindowIcon(QIcon(icon))
116
117 # Create menus:
118 self.fileMenu = self.menuBar().addMenu('File')
119 self.viewMenu = self.menuBar().addMenu('View')
120 self.projectMenu = self.menuBar().addMenu('Project')
121 self.helpMenu = self.menuBar().addMenu('Help')
122
123 # Create mdi area:
124 self.mdiArea = QMdiArea()
125 self.setCentralWidget(self.mdiArea)
126
127 # Create components:
128 self.buildOutput = BuildOutput()
129 self.addComponent('Build output', self.buildOutput)
130
131 self.astViewer = AstViewer()
132 self.addComponent('AST viewer', self.astViewer)
133 self.astViewer.sigNodeSelected.connect(self.nodeSelected)
134
135 self.builderrors = BuildErrors()
136 self.addComponent('Build errors', self.builderrors)
137 self.builderrors.sigErrorSelected.connect(self.errorSelected)
138
139 self.projectview = ProjectView()
140 self.addComponent('Project', self.projectview)
141 self.projectview.sigLoadFile.connect(self.loadFile)
142
143 # About dialog:
144 self.aboutDialog = AboutDialog()
145 self.aboutDialog.setWindowIcon(QIcon(icon))
146 # Create actions:
147 self.buildAction = QAction('Build!', self)
148 self.buildAction.setShortcut(QKeySequence('F7'))
149 self.projectMenu.addAction(self.buildAction)
150 self.buildAction.triggered.connect(self.buildFile)
151 self.openProjectAction = QAction("Open project", self)
152 self.openProjectAction.triggered.connect(self.openProject)
153 self.projectMenu.addAction(self.openProjectAction)
154 self.helpAction = QAction('Help', self)
155 self.helpAction.setShortcut(QKeySequence('F1'))
156 self.helpMenu.addAction(self.helpAction)
157 self.aboutAction = QAction('About', self)
158 self.helpMenu.addAction(self.aboutAction)
159 self.aboutAction.triggered.connect(self.aboutDialog.open)
160
161 self.newFileAction = QAction("New File", self)
162 self.fileMenu.addAction(self.newFileAction)
163 self.newFileAction.triggered.connect(self.newFile)
164 self.saveFileAction = QAction("Save File", self)
165 self.fileMenu.addAction(self.saveFileAction)
166 self.saveFileAction.triggered.connect(self.saveFile)
167 self.closeFileAction = QAction("Close File", self)
168 self.fileMenu.addAction(self.closeFileAction)
169 self.closeFileAction.triggered.connect(self.closeFile)
170
171 cascadeAction = QAction("Cascade windows", self)
172 cascadeAction.triggered.connect(self.mdiArea.cascadeSubWindows)
173 self.viewMenu.addAction(cascadeAction)
174 tileAction = QAction('Tile windows', self)
175 tileAction.triggered.connect(self.mdiArea.tileSubWindows)
176 self.viewMenu.addAction(tileAction)
177
178 # Load settings:
179 self.settings = QSettings('windelsoft', 'lcfoside')
180 self.loadSettings()
181
182 def addComponent(self, name, widget):
183 dw = QDockWidget(name)
184 dw.setWidget(widget)
185 dw.setObjectName(name)
186 self.addDockWidget(Qt.RightDockWidgetArea, dw)
187 self.viewMenu.addAction(dw.toggleViewAction())
188
189 # File handling:
190 def newFile(self):
191 ce = CodeEdit()
192 w = self.mdiArea.addSubWindow(ce)
193 ce.show()
194
195 def saveFile(self):
196 ac = self.activeMdiChild()
197 if ac:
198 ac.saveFile()
199
200 def saveAll(self):
201 pass
202
203 def openFile(self):
204 # TODO
205 pass
206
207 def closeFile(self):
208 ac = self.activeMdiChild()
209 if ac:
210 self.mdiArea.removeSubWindow(ac)
211
212 def loadFile(self, filename):
213 # Find existing mdi widget:
214 wid = self.findMdiChild(filename)
215 if wid:
216 self.mdiArea.setActiveSubWindow(wid.parent())
217 return wid
218
219 # Create a new one:
220 ce = CodeEdit()
221 source = self.project.loadProjectFile(filename)
222 ce.setSource(source)
223 self.mdiArea.addSubWindow(ce)
224 ce.show()
225 return ce
226
227 # MDI:
228 def activeMdiChild(self):
229 aw = self.mdiArea.activeSubWindow()
230 if aw:
231 return aw.widget()
232 else:
233 return None
234
235 def findMdiChild(self, filename):
236 for window in self.mdiArea.subWindowList():
237 wid = window.widget()
238 if wid.filename == filename:
239 return wid
240 return None
241
242 def allChildren(self):
243 c = []
244 for window in self.mdiArea.subWindowList():
245 wid = window.widget()
246 c.append(wid)
247 return c
248
249 # Settings:
250 def loadSettings(self):
251 if self.settings.contains('mainwindowstate'):
252 self.restoreState(self.settings.value('mainwindowstate'))
253 if self.settings.contains('mainwindowgeometry'):
254 self.restoreGeometry(self.settings.value('mainwindowgeometry'))
255 if self.settings.contains('openedproject'):
256 projectfile = self.settings.value('openedproject')
257 self.loadProject(projectfile)
258
259 def closeEvent(self, ev):
260 self.settings.setValue('mainwindowstate', self.saveState())
261 self.settings.setValue('mainwindowgeometry', self.saveGeometry())
262 if self.project:
263 self.settings.setValue('openedproject', self.project.filename)
264 # TODO: ask for save of opened files
265 ev.accept()
266
267 # Error handling:
268 def nodeSelected(self, node):
269 ce = self.activeMdiChild()
270 if not ce:
271 return
272 if node.location:
273 row, col = node.location
274 ce.highlightErrorLocation( row, col )
275 else:
276 ce.clearErrors()
277
278 def errorSelected(self, err):
279 row, col, msg = err
280 ce = self.activeMdiChild()
281 if not ce:
282 return
283 ce.highlightErrorLocation(row, col)
284
285 # Project loading:
286 def loadProject(self, filename):
287 self.project = Project(filename)
288 self.projectview.setProject(self.project)
289
290 def openProject(self):
291 filename = QFileDialog.getOpenFileName(self, \
292 "Choose project file", "", "lcfos Project files (*.lcp)")
293 if filename:
294 self.loadProject(filename)
295
296 # Build recepy:
297 def buildFile(self):
298 """ Build project """
299 self.saveAll()
300 self.buildOutput.clear()
301 self.buildOutput.append(str(self.compiler))
302 mods = self.compiler.compileProject(self.project)
303
304 self.builderrors.setErrorList(self.compiler.errorlist)
305 self.astViewer.setAst(mods[0])
306 for err in self.compiler.errorlist:
307 self.buildOutput.append(str(err))
308 self.buildOutput.append("Done!")
309