Modules |
Files |
Inheritance Tree |
Inheritance Graph |
Name Index |
Config
File: Synopsis/UI/Qt/project.py
1| # $Id: project.py,v 1.6 2002/10/11 06:03:23 chalky Exp $
2| #
3| # This file is a part of Synopsis.
4| # Copyright (C) 2000, 2001 Stefan Seefeld
5| # Copyright (C) 2000, 2001 Stephen Davies
6| #
7| # Synopsis is free software; you can redistribute it and/or modify it
8| # under the terms of the GNU General Public License as published by
9| # the Free Software Foundation; either version 2 of the License, or
10| # (at your option) any later version.
11| #
12| # This program is distributed in the hope that it will be useful,
13| # but WITHOUT ANY WARRANTY; without even the implied warranty of
14| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15| # General Public License for more details.
16| #
17| # You should have received a copy of the GNU General Public License
18| # along with this program; if not, write to the Free Software
19| # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20| # 02111-1307, USA.
21| #
22| # $Log: project.py,v $
23| # Revision 1.6 2002/10/11 06:03:23 chalky
24| # Use config from project
25| #
26| # Revision 1.5 2002/09/28 05:53:31 chalky
27| # Refactored display into separate project and browser windows. Execute projects
28| # in the background
29| #
30| # Revision 1.4 2002/06/22 07:03:27 chalky
31| # Updates to GUI - better editing of Actions, and can now execute some.
32| #
33| # Revision 1.3 2002/01/09 10:16:35 chalky
34| # Centralized navigation, clicking links in (html) docs works.
35| #
36| # Revision 1.2 2001/11/09 08:06:59 chalky
37| # More GUI fixes and stuff. Double click on Source Actions for a dialog.
38| #
39| # Revision 1.1 2001/11/07 05:58:21 chalky
40| # Reorganised UI, opening a .syn file now builds a simple project to view it
41| #
42|
43| """The project window. Displays the output of the project."""
44|
45| import os, sys, tempfile, traceback
46| from qt import *
47| from Synopsis.Core import Action, Executor, AST
48| from Synopsis.Core.Project import Project
49|
50| from actionvis import CanvasWindow
51| from browse import BrowserWindow
52|
53| class ProjectWindow (QSplitter):
54| def __init__(self, main_window, filename):
55| QSplitter.__init__(self, main_window.workspace)
56| self.setOrientation(Qt.Vertical)
57| self.setCaption('Project Window')
58|
59| self.main_window = main_window
60| self.project = Project()
61| self.browser = None
62| self.__activated = 0
63|
64| self.actions_display = CanvasWindow(self, self.main_window, self.project)
65| self.exec_output = QMultiLineEdit(self)
66| self.exec_output.setReadOnly(1)
67| self.exec_output.hide()
68|
69| if filename:
70| self.project.load(filename)
71| self.setCaption(self.project.name()+' : Project Window')
72|
73| self.connect(self.parent(), SIGNAL('windowActivated(QWidget*)'), self.windowActivated)
74|
75| #CanvasWindow(parent, main_window, self.project)
76|
77| self.setSizes([30,70])
78| #self.showMaximized()
79| #self.show()
80| main_window.add_window(self)
81|
82| def windowActivated(self, widget):
83| if self.__activated:
84| if widget is not self: self.deactivate()
85| elif widget is self: self.activate()
86|
87| def activate(self):
88| self.__activated = 1
89| self._menu_id = self.main_window.menuBar().insertItem('&Project', self.main_window.project_menu)
90|
91| def deactivate(self):
92| self.__activated = 0
93| self.main_window.menuBar().removeItem(self._menu_id)
94|
95|
96| def execute_project(self):
97| """Tries to show some output in the browser parts of the project
98| window. To do this is searches for an appropriate FormatAction (ie,
99| one that has HTML options), checks that everything is up to date, and
100| loads the AST into the browser windows."""
101| # Find output
102| formatter = None
103| if formatter is None:
104| # Try to get default from Project
105| formatter = self.project.default_formatter()
106| if formatter is None:
107| # Try to find a HTML formatter
108| for action in self.project.actions().actions():
109| if isinstance(action, Action.FormatAction):
110| # Check html..
111| formatter = action
112| if not formatter:
113| # Maybe tell user..
114| return
115| self.format_action = formatter
116|
117| # Find input to formatter
118| inputs = formatter.inputs()
119| if len(inputs) != 1:
120| # Maybe tell user..
121| return
122| self.cache_action = cache = inputs[0]
123| if not isinstance(cache, Action.CacherAction) or len(cache.inputs()) != 1:
124| print "Error: Selected formatter must have a cache with a single input"
125| return
126|
127| # Now that we have verified the action to use, fork a process to do
128| # the work in the background
129| self.tempfile = file = tempfile.TemporaryFile('w+b', 64, 'synopsis-output')
130| self.temp_pos = 0
131|
132| #TODO: use popen for windows compat.
133| self.child_pid = os.fork()
134| if self.child_pid == 0:
135| try:
136| # Redirect output to file
137| os.dup2(self.tempfile.fileno(), 1)
138| os.dup2(self.tempfile.fileno(), 2)
139| print "Executing project "+self.project.name()
140| # Create executor for the input
141| input_exec = Executor.ExecutorCreator(self.project, 1).create(cache)
142|
143| # Get AST from the input (forces project creation)
144| names = input_exec.get_output_names()
145| ast = input_exec.get_output(names[0][0])
146| # Ignore the ast, since parent process will read it
147| print "Done."
148| except:
149| print "An exception occurred"
150| traceback.print_exc()
151| self.tempfile.flush()
152| sys.exit(0)
153|
154| # Create a timer
155| self.timer = QTimer()
156| self.timer.changeInterval(100)
157| self.connect(self.timer, SIGNAL('timeout()'), self.checkThreadOutput)
158|
159| self.exec_output.show()
160| self.setSizes([80,20])
161|
162| def checkThreadOutput(self):
163| """This method is called periodically to check output on the
164| tempfile"""
165|
166| # Read doesn't work, so we have to pull these seek tricks
167| self.tempfile.seek(0, 2)
168| end = self.tempfile.tell()
169| if end != self.temp_pos:
170| self.tempfile.seek(self.temp_pos)
171| input = self.tempfile.read(end - self.temp_pos)
172| self.temp_pos = end
173| self.exec_output.append(input)
174| self.exec_output.setCursorPosition(self.exec_output.numLines(), 0)
175|
176| # Check if child finished
177| pid, status = os.waitpid(self.child_pid, os.WNOHANG)
178| if pid != 0:
179| # Thread ended
180| # Give AST to browser
181| if not self.browser:
182| config = self.format_action.config()
183| self.browser = BrowserWindow(self.main_window, None, self, config)
184| self.browser.setCaption(self.project.name()+' : Browser Window')
185|
186| # Now load ast from cache
187| try:
188| input_exec = Executor.ExecutorCreator(self.project, 0).create(self.cache_action)
189| file = input_exec.get_cache_filename(input_exec.get_output_names()[0][0])
190| ast = AST.load(file)
191| if ast:
192| self.browser.set_current_ast(ast)
193| except:
194| print "An exception occurred"
195| traceback.print_exc()
196|
197| # Destroy timer
198| self.timer.stop()
199| del self.timer
200|
201| # Restore file descriptors
202| self.tempfile.close()
203| del self.tempfile
204|
205|
206|