1 |
#!/usr/bin/env python |
2 |
if __name__ == '__main__': |
3 |
print "ERROR: ASCEND Canvas should now be invoked using the file 'canvas.py' instead of 'blocklist.py'." |
4 |
exit(1) |
5 |
|
6 |
import gtk |
7 |
import os, os.path, glob |
8 |
import cairo |
9 |
import ascpy |
10 |
|
11 |
class BlockIconView(gtk.IconView): |
12 |
""" |
13 |
IconView containing the palette of BlockTypes available for use in the |
14 |
canvas. The list of blocks is supplied currently as an initialisation |
15 |
parameter, but it is intended that this would be dynamic in a final system. |
16 |
|
17 |
It should be possible drag icons from the palette into the canvas, but |
18 |
that is not yet implemented. |
19 |
""" |
20 |
def __init__(self,blocks=None,app=None): |
21 |
self.model = gtk.ListStore(str, gtk.gdk.Pixbuf) |
22 |
self.app = app |
23 |
self.otank = {} |
24 |
try: |
25 |
for b in blocks: |
26 |
pixbuf = b.get_icon(48,48) |
27 |
iter = self.model.append([b.type.getName(), pixbuf]) |
28 |
path = self.model.get_path(iter) |
29 |
self.otank[path] = b |
30 |
except Exception as e: |
31 |
pass |
32 |
|
33 |
gtk.IconView.__init__(self) |
34 |
self.set_model(self.model) |
35 |
self.set_text_column(0) |
36 |
self.set_pixbuf_column(1) |
37 |
self.set_columns(-1) |
38 |
self.set_size_request(180,100) |
39 |
self.connect("item-activated", self.item_activated) |
40 |
self.connect("selection-changed", self.selection_changed) |
41 |
|
42 |
def refresh_view(): |
43 |
pass |
44 |
|
45 |
def selection_changed(self,iconview): |
46 |
s = self.get_selected_items() |
47 |
if len(s)==1: |
48 |
b = self.otank[s[0]] |
49 |
self.app.set_placement_tool(b) |
50 |
|
51 |
def item_activated(self,iconview, path): |
52 |
self.app.set_placement_tool(self.otank[path]) |
53 |
|
54 |
|
55 |
from gaphas import GtkView, View |
56 |
from gaphas.tool import HoverTool, PlacementTool, HandleTool, ToolChain, DEBUG_TOOL_CHAIN |
57 |
#from gaphas.tool import LineSegmentTool |
58 |
from gaphas.tool import Tool, ItemTool, RubberbandTool |
59 |
from gaphas.painter import ItemPainter |
60 |
from blockconnecttool import BlockConnectTool |
61 |
from blockline import BlockLine |
62 |
from blockitem import DefaultBlockItem |
63 |
from contextmenutool import ContextMenuTool |
64 |
from connectortool import ConnectorTool |
65 |
from blockcanvas import BlockCanvas |
66 |
#from panzoom import ZoomTool |
67 |
#from panzoom import PanTool |
68 |
from gaphas.tool import PanTool, ZoomTool |
69 |
from blockinstance import BlockInstance |
70 |
from solverreporterforcanvas import PopupSolverReporter |
71 |
import canvasproperties |
72 |
import blockproperties |
73 |
import undo |
74 |
from undo import UndoMonitorTool |
75 |
import errorreporter |
76 |
import gaphas.view |
77 |
import pickle as pickle |
78 |
import gaphas.picklers |
79 |
import obrowser |
80 |
import urllib, help |
81 |
from preferences import Preferences |
82 |
|
83 |
def BlockToolChain(): |
84 |
""" |
85 |
ToolChain for working with BlockCanvas, including several custom Tools. |
86 |
""" |
87 |
chain = ToolChain() |
88 |
chain.append(UndoMonitorTool()) |
89 |
chain.append(HoverTool()) |
90 |
chain.append(BlockConnectTool()) # for connect/disconnect of lines |
91 |
chain.append(ConnectorTool()) # for creating new lines by drag from Port |
92 |
chain.append(ContextMenuTool()) # right-click |
93 |
# chain.append(LineSegmentTool()) # for moving line 'elbows' |
94 |
chain.append(ItemTool()) |
95 |
chain.append(PanTool()) |
96 |
chain.append(ZoomTool()) |
97 |
chain.append(RubberbandTool()) |
98 |
return chain |
99 |
|
100 |
class mainWindow(gtk.Window): |
101 |
|
102 |
menu_xml = '''<ui> |
103 |
<menubar name='MenuBar'> |
104 |
<menu action='File'> |
105 |
<menuitem action='New' /> |
106 |
<menuitem action='Open' /> |
107 |
<menuitem action='Save' /> |
108 |
<menuitem action='SaveAs' /> |
109 |
<separator /> |
110 |
<menuitem action='Export' /> |
111 |
<separator /> |
112 |
<menuitem action='Library' /> |
113 |
<separator /> |
114 |
<menuitem action='Quit' /> |
115 |
</menu> |
116 |
<menu action='Edit'> |
117 |
<menuitem action='Undo' /> |
118 |
<menuitem action='Redo' /> |
119 |
<separator /> |
120 |
<menuitem action='BlockProperties' /> |
121 |
<menuitem action='Delete' /> |
122 |
</menu> |
123 |
<menu action='View'> |
124 |
<menuitem action='Fullscreen' /> |
125 |
<separator /> |
126 |
<menuitem action='ZoomIn' /> |
127 |
<menuitem action='ZoomOut' /> |
128 |
</menu> |
129 |
<menu action='Tools'> |
130 |
<menuitem action='Debug' /> |
131 |
<menuitem action='Run' /> |
132 |
<menuitem action='Preview' /> |
133 |
</menu> |
134 |
<menu action='Help'> |
135 |
<menuitem action='Development' /> |
136 |
<menuitem action='ReportBug' /> |
137 |
<menuitem action='About' /> |
138 |
</menu> |
139 |
</menubar> |
140 |
<toolbar name='ToolBar'> |
141 |
</toolbar> |
142 |
</ui> |
143 |
''' |
144 |
|
145 |
def __init__(self,library,options=None): |
146 |
""" |
147 |
Initialise the application -- create all the widgets, and populate |
148 |
the icon palette. |
149 |
TODO: separate the icon palette into a separate method. |
150 |
""" |
151 |
self.ascwrap= library |
152 |
self.errorvars = [] |
153 |
self.errorblocks = [] |
154 |
self.status = gtk.Statusbar() |
155 |
self.temp = [] |
156 |
self.act = 1 #to be used for storing canvas zoom in/out related data. |
157 |
# the Gaphas canvas |
158 |
canvas = BlockCanvas() |
159 |
|
160 |
# the main window |
161 |
gtk.Window.__init__(self) |
162 |
self.iconok = self.render_icon(gtk.STOCK_YES,gtk.ICON_SIZE_MENU) |
163 |
self.iconinfo = self.render_icon(gtk.STOCK_DIALOG_INFO,gtk.ICON_SIZE_MENU) |
164 |
self.iconwarning = self.render_icon(gtk.STOCK_DIALOG_WARNING,gtk.ICON_SIZE_MENU) |
165 |
self.iconerror = self.render_icon(gtk.STOCK_DIALOG_ERROR,gtk.ICON_SIZE_MENU) |
166 |
|
167 |
self.set_title("ASCEND Canvas Modeller") |
168 |
self.set_default_size(650,650) |
169 |
self.connect("destroy", gtk.main_quit) |
170 |
|
171 |
windowicon = gtk.Image() |
172 |
windowicon.set_from_file(os.path.join('..','glade','ascend.svg')) |
173 |
self.set_icon(windowicon.get_pixbuf()) |
174 |
|
175 |
vbox = gtk.VBox() |
176 |
|
177 |
ui_manager = gtk.UIManager() |
178 |
accelgroup = ui_manager.get_accel_group() |
179 |
self.add_accel_group(accelgroup) |
180 |
|
181 |
actiongroup = gtk.ActionGroup('CanvasActionGroup') |
182 |
|
183 |
self.prefs = Preferences() |
184 |
|
185 |
actions = [('File', None, '_File') |
186 |
,('Quit', gtk.STOCK_QUIT, '_Quit', None,'Quit the Program', self.quit) |
187 |
,('New', gtk.STOCK_NEW,'_New',None,'Start a new Simulation', self.new) |
188 |
,('Open', gtk.STOCK_OPEN,'_Open',None,'Open a saved Canvas file', self.fileopen) |
189 |
,('Save', gtk.STOCK_SAVE,'_Save',None,'Open a saved Canvas file', self.save_canvas) |
190 |
,('SaveAs', gtk.STOCK_SAVE_AS,'_Save As...',None,'Open a saved Canvas file', self.filesave) |
191 |
,('Export', gtk.STOCK_PRINT, '_Export SVG', None,'Quit the Program', self.export_svg_as) |
192 |
,('Library', gtk.STOCK_OPEN, '_Load Library...', '<Control>l','Load Library', self.load_library_dialog) |
193 |
,('Edit', None, '_Edit') |
194 |
,('Undo', gtk.STOCK_UNDO, '_Undo', '<Control>z', 'Undo Previous Action', self.undo_canvas) |
195 |
,('Redo',gtk.STOCK_REDO, '_Redo', '<Control>y', 'Redo Previous Undo', self.redo_canvas) |
196 |
,('BlockProperties',gtk.STOCK_PROPERTIES, '_Block Properties', None, 'Edit Block Properties', self.bp) |
197 |
,('Delete', gtk.STOCK_DELETE, '_Delete', 'Delete', 'Delete Selected Item', self.delblock) |
198 |
,('View', None, '_View') |
199 |
,('Fullscreen', gtk.STOCK_FULLSCREEN, '_Full Screen', 'F11', 'Toggle Full Screen', self.fullscrn) |
200 |
,('ZoomIn', gtk.STOCK_ZOOM_IN, '_Zoom In', None, 'Zoom In Canvas', self.zoom) |
201 |
,('ZoomOut', gtk.STOCK_ZOOM_OUT, '_Zoom Out', None, 'Zoom Out Canvas', self.zoom) |
202 |
#,('BestFit', gtk.STOCK_ZOOM_FIT, '_Best Fit', None, 'Best Fit Canvas',self.zoom) |
203 |
,('Tools', None, '_Tools') |
204 |
,('Debug', None, '_Debug', None, 'View Instance Browser',self.debug_canvas) |
205 |
,('Run', gtk.STOCK_EXECUTE, '_Run', None, 'Solve Canvas', self.run_canvas) |
206 |
,('Preview', gtk.STOCK_PRINT_PREVIEW, '_Preview', None, 'Preview Generated Code', self.preview_canvas) |
207 |
,('Help', None, '_Help') |
208 |
,('Development', gtk.STOCK_INFO, '_Development', None, 'Check Development', self.on_get_help_online_click) |
209 |
,('ReportBug', None, '_Report Bug', None, 'Report a Bug!', self.on_report_a_bug_click) |
210 |
,('About', gtk.STOCK_ABOUT, '_About', None, 'About Us', self.about) |
211 |
] |
212 |
|
213 |
actiongroup.add_actions(actions) |
214 |
|
215 |
ui_manager.insert_action_group(actiongroup,0) |
216 |
ui_manager.add_ui_from_string(self.menu_xml) |
217 |
|
218 |
#Creating Menu Bar |
219 |
menubar = ui_manager.get_widget('/MenuBar') |
220 |
vbox.pack_start(menubar,False,False) |
221 |
|
222 |
#Creating Tool Bar |
223 |
#toolbar = ui_manager.get_widget('/ToolBar') |
224 |
#vbox.pack_start(toolbar,False) |
225 |
|
226 |
'''The Toolbar Definations start here''' |
227 |
|
228 |
tb = gtk.Toolbar() |
229 |
#Load Button |
230 |
loadbutton = gtk.ToolButton(gtk.STOCK_OPEN) |
231 |
loadbutton.connect("clicked",self.fileopen) |
232 |
tb.insert(loadbutton,0) |
233 |
|
234 |
#Save Button |
235 |
savebutton = gtk.ToolButton(gtk.STOCK_SAVE) |
236 |
savebutton.connect("clicked",self.save_canvas) |
237 |
tb.insert(savebutton,1) |
238 |
|
239 |
#Debug Button |
240 |
debugbutton = gtk.ToolButton(gtk.STOCK_PROPERTIES) |
241 |
debugbutton.set_label("Debug") |
242 |
debugbutton.connect("clicked",self.debug_canvas) |
243 |
tb.insert(debugbutton,2) |
244 |
|
245 |
#Preview Button |
246 |
previewb = gtk.ToolButton(gtk.STOCK_PRINT_PREVIEW) |
247 |
previewb.set_label("Preview") |
248 |
previewb.connect("clicked",self.preview_canvas) |
249 |
tb.insert(previewb,3) |
250 |
|
251 |
#Export Button |
252 |
exportbutton = gtk.ToolButton(gtk.STOCK_CONVERT) |
253 |
exportbutton.set_label("Export SVG") |
254 |
exportbutton.connect("clicked",self.export_svg_as) |
255 |
tb.insert(exportbutton,2) |
256 |
|
257 |
#Run Button |
258 |
runb = gtk.ToolButton(gtk.STOCK_EXECUTE) |
259 |
runb.set_label("Run") |
260 |
runb.connect("clicked",self.run_canvas) |
261 |
tb.insert(runb, 4) |
262 |
|
263 |
##Custom Entry |
264 |
#m_entry = gtk.ToolButton(gtk.STOCK_SAVE_AS) |
265 |
#m_entry.set_label("Custom METHOD") |
266 |
#m_entry.connect("clicked",self.custommethod) |
267 |
#tb.insert(m_entry,5) |
268 |
|
269 |
vbox.pack_start(tb, False, False) |
270 |
|
271 |
# hbox occupies top part of vbox, with icons on left & canvas on right. |
272 |
paned = gtk.HPaned() |
273 |
|
274 |
# the 'view' widget implemented by Gaphas |
275 |
#gaphas.view.DEBUG_DRAW_BOUNDING_BOX = True |
276 |
self.view = GtkView() |
277 |
self.view.tool = BlockToolChain() |
278 |
|
279 |
# table containing scrollbars and main canvas |
280 |
t = gtk.Table(2,2) |
281 |
self.view.canvas = canvas |
282 |
self.view.zoom(1) |
283 |
self.view.set_size_request(600, 450) |
284 |
hs = gtk.HScrollbar(self.view.hadjustment) |
285 |
vs = gtk.VScrollbar(self.view.vadjustment) |
286 |
t.attach(self.view, 0, 1, 0, 1) |
287 |
t.attach(hs, 0, 1, 1, 2, xoptions=gtk.FILL, yoptions=gtk.FILL) |
288 |
t.attach(vs, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.FILL) |
289 |
|
290 |
# a scrolling window to contain the icon palette |
291 |
self.scroll = gtk.ScrolledWindow() |
292 |
self.scroll.set_border_width(2) |
293 |
self.scroll.set_shadow_type(gtk.SHADOW_ETCHED_IN) |
294 |
|
295 |
self.scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
296 |
|
297 |
self.blockiconview = BlockIconView(blocks=self.ascwrap.canvas_blocks,app=self) |
298 |
self.scroll.add(self.blockiconview) |
299 |
self.reporter = self.ascwrap.reporter |
300 |
|
301 |
paned.pack1(self.scroll, True, True) |
302 |
paned.pack2(t, True, True) |
303 |
vbox.pack_start(paned, True, True) |
304 |
vpane = gtk.VPaned() |
305 |
vpane.pack1(vbox) |
306 |
lower_vbox = gtk.VBox() |
307 |
|
308 |
self.ET = errorreporter.ErrorReporter( self.reporter,self.iconok,self.iconinfo,self.iconwarning,self.iconerror) |
309 |
self.notebook = gtk.Notebook() |
310 |
self.notebook.set_tab_pos(gtk.POS_TOP) |
311 |
label = gtk.Label('Error / Status Reporter Console') |
312 |
scrolledwindow = gtk.ScrolledWindow() |
313 |
scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) |
314 |
scrolledwindow.add(self.ET.errorview) |
315 |
self.notebook.append_page(scrolledwindow, label) |
316 |
lower_vbox.pack_start(self.notebook,True, True) |
317 |
lower_vbox.pack_start(self.status, False, False) |
318 |
vpane.pack2(lower_vbox) |
319 |
|
320 |
self.undo_manager = undo.undoManager(self) |
321 |
self.undo_manager.start() |
322 |
|
323 |
self.add(vpane) |
324 |
self.show_all() |
325 |
|
326 |
@undo.block_observed |
327 |
def set_placement_tool(self,blocktype): |
328 |
""" |
329 |
Prepare the canvas for drawing a block of the type selected in the |
330 |
icon palette. |
331 |
""" |
332 |
# TODO: add undo handler |
333 |
label = blocktype.type.getName() |
334 |
def my_block_factory(): |
335 |
def wrapper(): |
336 |
b = BlockInstance(blocktype) |
337 |
bi = DefaultBlockItem(b) |
338 |
self.view.canvas.add(bi) |
339 |
return bi |
340 |
return wrapper |
341 |
self.view.unselect_all() |
342 |
self.view.tool.grab(PlacementTool(self.view,my_block_factory(), HandleTool(), 2)) |
343 |
self.status.push(0,"Selected '%s'..." % blocktype.type.getName()) |
344 |
|
345 |
def set_connector_tool(self,foobar): |
346 |
""" |
347 |
Prepare the canvas for drawing a connecting line (note that one can |
348 |
alternatively just drag from a port to another port). |
349 |
""" |
350 |
|
351 |
def my_line_factory(): |
352 |
def wrapper(): |
353 |
l = BlockLine() |
354 |
self.view.canvas.add(l) |
355 |
return l |
356 |
return wrapper |
357 |
self.view.tool.grab(PlacementTool(self.view,my_line_factory(), HandleTool(), 1)) |
358 |
|
359 |
@undo.block_observed |
360 |
def delblock(self, widget = None): |
361 |
if self.view.focused_item: |
362 |
self.view.canvas.remove(self.view.focused_item) |
363 |
self.status.push(0,"Item deleted.") |
364 |
self.view.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FFF')) |
365 |
|
366 |
@undo.block_observed |
367 |
def new(self, widget): |
368 |
for item in self.view.canvas.get_all_items(): |
369 |
self.view.canvas.remove(item) |
370 |
self.reporter.reportNote('Canvas cleared for new Model') |
371 |
self.view.canvas.filestate = 0 |
372 |
self.view.canvas.filename = None |
373 |
self.view.canvas.canvasmodelstate = 'Unsolved' |
374 |
self.status.push(0,"Canvasmodel state : %s"% self.view.canvas.canvasmodelstate) |
375 |
self.view.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FFF')) |
376 |
|
377 |
def debug_canvas(self,widget): |
378 |
""" |
379 |
Display an 'object browser' to allow inspection of the objects |
380 |
in the canvas. |
381 |
""" |
382 |
|
383 |
b = obrowser.Browser("canvas",self.view.canvas, False) |
384 |
self.status.push(0,"Canvasmodel state : %s"% self.view.canvas.canvasmodelstate) |
385 |
|
386 |
def save_canvas(self,widget): |
387 |
""" |
388 |
Save the canvas in 'pickle' format. Currently saving is jointly handled by both self.save_canvas and self.filesave methods |
389 |
""" |
390 |
if self.view.canvas.filestate == 0: |
391 |
self.filesave(widget) |
392 |
return |
393 |
else: |
394 |
f = file(self.view.canvas.filename,"w") |
395 |
try: |
396 |
pickle.dump(self.view.canvas,f) |
397 |
self.status.push(0,"Canvasmodel saved...") |
398 |
except Exception,e: |
399 |
print "ERROR:",str(e) |
400 |
self.status.push(0,"Canvasmodel could not be saved : " + str(e)) |
401 |
b = obrowser.Browser("canvas",self.view.canvas) |
402 |
d = gtk.Dialog("Error",self,gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) |
403 |
d.vbox.add(gtk.Label(str(e))) |
404 |
d.show_all() |
405 |
d.run() |
406 |
d.hide() |
407 |
finally: |
408 |
f.close() |
409 |
|
410 |
def load_canvas(self,widget): |
411 |
""" |
412 |
Restore a saved canvas in 'pickle' format. Currently not in use as loading now handled by self.fileopen(). |
413 |
""" |
414 |
f = file("./test.a4b","r") |
415 |
try: |
416 |
self.view.canvas = pickle.load(f) |
417 |
if self.view.canvas.model_library is not None: |
418 |
print "Loading Library...." |
419 |
self.loadlib(self, self.view.canvas.model_library,0) |
420 |
self.view.canvas.reattach_ascend(self.ascwrap.library,self.ascwrap.annodb) |
421 |
self.view.canvas.update_now() |
422 |
self.status.push(0,"Canvasmodel sucessfully loaded...") |
423 |
except Exception,e: |
424 |
self.status.push(0,"Canvasmodel could not be loaded : " + str(e)) |
425 |
self.reporter.ReportError("Canvasmodel could not be loaded : " + str(e)) |
426 |
self.reporter.ReportNote(" Error occured while attempting to 'Load' the file") |
427 |
finally: |
428 |
f.close() |
429 |
self.load_presaved_canvas(None) |
430 |
self.status.push(0,"Canvasmodel state : %s"% self.view.canvas.canvasmodelstate) |
431 |
|
432 |
|
433 |
def temp_canvas(self,widget): |
434 |
pass |
435 |
""" |
436 |
NOTE: re-implementation needed |
437 |
""" |
438 |
|
439 |
def undo_canvas(self,widget): |
440 |
""" |
441 |
NOTE: re-implementation needed |
442 |
|
443 |
""" |
444 |
self.undo_manager.undo() |
445 |
#pass |
446 |
|
447 |
def redo_canvas(self,widget): |
448 |
""" |
449 |
NOTE: re-implementation needed |
450 |
|
451 |
""" |
452 |
self.undo_manager.redo() |
453 |
#pass |
454 |
|
455 |
def preview_canvas(self,widget): |
456 |
""" |
457 |
Output an ASCEND representation of the canvas on the commandline. |
458 |
Under development. |
459 |
""" |
460 |
self.status.push(0,"Canvasmodel state : %s"% self.view.canvas.canvasmodelstate) |
461 |
#info.Info(self.view.parent.parent.parent.parent.parent,str(self.view.canvas),"Canvas Preview").run() |
462 |
canvasproperties.CanvasProperties(self).run() |
463 |
|
464 |
def export_svg_as(self,widget): |
465 |
|
466 |
f = None |
467 |
dialog = gtk.FileChooserDialog("Export Canvas As...", None, |
468 |
gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) |
469 |
dialog.set_default_response(gtk.RESPONSE_OK) |
470 |
filter = gtk.FileFilter() |
471 |
filter.set_name("Image File") |
472 |
filter.add_pattern("*.svg") |
473 |
dialog.add_filter(filter) |
474 |
dialog.show() |
475 |
response = dialog.run() |
476 |
|
477 |
svgview = View(self.view.canvas) |
478 |
svgview.painter = ItemPainter() |
479 |
|
480 |
# Update bounding boxes with a temporaly CairoContext |
481 |
# (used for stuff like calculating font metrics) |
482 |
tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0) |
483 |
tmpcr = cairo.Context(tmpsurface) |
484 |
svgview.update_bounding_box(tmpcr) |
485 |
tmpcr.show_page() |
486 |
tmpsurface.flush() |
487 |
|
488 |
if response == gtk.RESPONSE_OK: |
489 |
name = dialog.get_filename() |
490 |
if '.svg' not in name: |
491 |
name += '.svg' |
492 |
if f == None and f != name: |
493 |
f = open(name, 'w') |
494 |
elif f != None and name == f: |
495 |
dialog.set_do_overwrite_confirmation(True) |
496 |
dialog.connect("confirm-overwrite", self.confirm_overwrite_callback) |
497 |
|
498 |
fn = name |
499 |
w, h = svgview.bounding_box.width, svgview.bounding_box.height |
500 |
surface = cairo.SVGSurface(fn , w, h) |
501 |
cr = cairo.Context(surface) |
502 |
svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y) |
503 |
svgview.paint(cr) |
504 |
cr.show_page() |
505 |
surface.flush() |
506 |
surface.finish() |
507 |
self.reporter.reportNote(" File ' %s ' saved successfully." % name ) |
508 |
self.status.push(0,"Wrote SVG file '%s'." % fn) |
509 |
dialog.destroy() |
510 |
|
511 |
|
512 |
def export_svg(self,widget): |
513 |
svgview = View(self.view.canvas) |
514 |
svgview.painter = ItemPainter() |
515 |
|
516 |
# Update bounding boxes with a temporaly CairoContext |
517 |
# (used for stuff like calculating font metrics) |
518 |
tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0) |
519 |
tmpcr = cairo.Context(tmpsurface) |
520 |
svgview.update_bounding_box(tmpcr) |
521 |
tmpcr.show_page() |
522 |
tmpsurface.flush() |
523 |
|
524 |
fn = 'demo.svg' |
525 |
w, h = svgview.bounding_box.width, svgview.bounding_box.height |
526 |
surface = cairo.SVGSurface(fn , w, h) |
527 |
cr = cairo.Context(surface) |
528 |
svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y) |
529 |
svgview.paint(cr) |
530 |
cr.show_page() |
531 |
surface.flush() |
532 |
surface.finish() |
533 |
|
534 |
self.status.push(0,"Wrote SVG file '%s'." % fn) |
535 |
|
536 |
def run_presaved_canvas(self,widget): |
537 |
#TODO: Separate |
538 |
if self.view.canvas.saved_model is not None: |
539 |
model = self.view.canvas.saved_model |
540 |
self.ascwrap.library.loadString(model,"canvasmodel") |
541 |
|
542 |
T = self.ascwrap.library.findType("canvasmodel") |
543 |
M = T.getSimulation('canvassim',True) |
544 |
M.setSolver(ascpy.Solver("QRSlv")) |
545 |
M.solve(ascpy.Solver("QRSlv"),ascpy.SolverReporter()) |
546 |
|
547 |
for item in self.view.canvas.get_all_items(): |
548 |
if hasattr(item, 'blockinstance'): |
549 |
bi = item.blockinstance |
550 |
for i in self.ascwrap.library.modules.getChildren()[0].getChildren(): |
551 |
if str(bi.name) == str(i.getName()): |
552 |
bi.instance = i |
553 |
|
554 |
def load_presaved_canvas(self,widget): |
555 |
#TODO: Separate |
556 |
print self.view.canvas.saved_data |
557 |
try: |
558 |
if self.view.canvas.saved_data is not None: |
559 |
model = str(self.view.canvas) |
560 |
self.ascwrap.library.loadString(model,"canvasmodel") |
561 |
T = self.ascwrap.library.findType("canvasmodel") |
562 |
M = T.getSimulation('canvassim') |
563 |
|
564 |
def assignval(sim_inst, name): |
565 |
if sim_inst.isAtom(): |
566 |
try: |
567 |
sim_inst.setRealValue(self.view.canvas.saved_data[name]) |
568 |
except Exception,e: |
569 |
print e |
570 |
elif sim_inst.isRelation(): |
571 |
pass |
572 |
else: |
573 |
for i in sim_inst.getChildren(): |
574 |
k = name+"."+str(i.getName()) |
575 |
assignval(i,k) |
576 |
|
577 |
for i in M.getChildren()[0].getChildren(): |
578 |
assignval(i, str(i.getName())) |
579 |
|
580 |
for item in self.view.canvas.get_all_items(): |
581 |
if hasattr(item, 'blockinstance'): |
582 |
bi = item.blockinstance |
583 |
for i in M.getChildren()[0].getChildren(): |
584 |
if str(bi.name) == str(i.getName()): |
585 |
bi.instance = i |
586 |
self.status.push(0,"Canvasmodel state : %s"% self.view.canvas.canvasmodelstate) |
587 |
except AttributeError: |
588 |
self.status.push(0,"Canvasmodel state : Unsolved") |
589 |
|
590 |
def run_canvas(self,widget): |
591 |
#TODO: Separate |
592 |
""" |
593 |
Exports canvas to ASCEND solver and attempts to solve it. Also provides realtime feedback. |
594 |
""" |
595 |
self.undo_manager.reset() |
596 |
model = str(self.view.canvas) |
597 |
#print model |
598 |
self.view.canvas.saved_model = model |
599 |
self.view.canvas.saved_data = {} |
600 |
|
601 |
self.ascwrap.library.loadString(model,"canvasmodel") |
602 |
T = self.ascwrap.library.findType("canvasmodel") |
603 |
|
604 |
|
605 |
self.M = T.getSimulation('canvassim') |
606 |
self.M.setSolver(ascpy.Solver("QRSlv")) |
607 |
self.reporter = ascpy.getReporter() |
608 |
reporter = PopupSolverReporter(self,self.M.getNumVars()) |
609 |
|
610 |
try: |
611 |
self.M.build() |
612 |
except RuntimeError,e: |
613 |
print "Couldn't build system: %s" % str(e) |
614 |
self.status.push(0,"Couldn't build system: %s" % str(e)); |
615 |
return |
616 |
|
617 |
self.status.push(0,"Solving with 'QRSlv'. Please Wait...") |
618 |
|
619 |
try: |
620 |
self.M.solve(ascpy.Solver("QRSlv"),reporter) |
621 |
self.reporterrorblock(self.M) |
622 |
except RuntimeError: |
623 |
self.reporterrorblock(self.M) |
624 |
|
625 |
for item in self.view.canvas.get_all_items(): |
626 |
if hasattr(item, 'blockinstance'): |
627 |
bi = item.blockinstance |
628 |
for i in self.M.getChildren()[0].getChildren(): |
629 |
if str(bi.name) == str(i.getName()): |
630 |
bi.instance = i |
631 |
|
632 |
#Storing solved variables into a dictionary which will be pickled |
633 |
for i in self.M.getallVariables(): |
634 |
self.view.canvas.saved_data[str(i.getName())] = i.getValue() |
635 |
|
636 |
def about(self, widget): |
637 |
about = gtk.AboutDialog() |
638 |
about.set_program_name("ASCEND CANVAS") |
639 |
about.set_version("0.9.6x alpha") |
640 |
about.set_copyright("Carnegie Mellon University") |
641 |
about.set_comments("Canvas - Based GUI Modeller for Energy Systems") |
642 |
about.set_website("http://www.ascend.cheme.cmu.edu") |
643 |
windowicon = gtk.Image() |
644 |
windowicon.set_from_file(os.path.join("../glade/ascend.svg")) |
645 |
about.set_icon(windowicon.get_pixbuf()) |
646 |
about.set_logo(gtk.gdk.pixbuf_new_from_file("../glade/ascend.png")) |
647 |
about.run() |
648 |
about.destroy() |
649 |
|
650 |
def dummy(self, widget): |
651 |
dum = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Sorry ! This fuctionality is not implemented yet.") |
652 |
dum.run() |
653 |
dum.destroy() |
654 |
|
655 |
def fileopen(self, widget): |
656 |
dialog = gtk.FileChooserDialog("Open..",self,gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) |
657 |
dialog.set_default_response(gtk.RESPONSE_OK) |
658 |
filter = gtk.FileFilter() |
659 |
filter.set_name("Canvas Files") |
660 |
filter.add_mime_type("Canvas Files/a4b") |
661 |
filter.add_pattern("*.a4b") |
662 |
dialog.add_filter(filter) |
663 |
filter = gtk.FileFilter() |
664 |
filter.set_name("All files") |
665 |
filter.add_pattern("*") |
666 |
dialog.add_filter(filter) |
667 |
|
668 |
res = dialog.run() |
669 |
if res == gtk.RESPONSE_OK: |
670 |
result = dialog.get_filename() |
671 |
self.load_canvas_file(result) |
672 |
dialog.destroy() |
673 |
|
674 |
def load_canvas_file(self,filename): |
675 |
#TODO: Separate |
676 |
f = file(filename,"r") |
677 |
try: |
678 |
self.view.canvas = pickle.load(f) |
679 |
if self.view.canvas.model_library is not None: |
680 |
self.loadlib(self, self.view.canvas.model_library) |
681 |
self.view.canvas.reattach_ascend(self.ascwrap.library,self.ascwrap.annodb) |
682 |
self.view.canvas.update_now() |
683 |
self.view.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FFF')) |
684 |
self.load_presaved_canvas(None) |
685 |
self.reporter.reportError(" File %s successfully loaded." % filename) |
686 |
self.status.push(0,"File %s Loaded." % filename) |
687 |
self.view.canvas.filename = filename |
688 |
except Exception,e: |
689 |
self.reporter.reportError(" Error occured while attempting to 'Load' the file. File could be loaded properly.") |
690 |
print e |
691 |
finally: |
692 |
f.close() |
693 |
|
694 |
def filesave(self, widget): |
695 |
f = None |
696 |
dialog = gtk.FileChooserDialog("Save..", self, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) |
697 |
dialog.set_default_response(gtk.RESPONSE_OK) |
698 |
if self.view.canvas.filestate == 0: |
699 |
dialog.set_filename("untitled") |
700 |
filter = gtk.FileFilter() |
701 |
filter.set_name("Canvas File") |
702 |
filter.add_pattern("*.a4b") |
703 |
dialog.add_filter(filter) |
704 |
dialog.show() |
705 |
dialog.set_do_overwrite_confirmation(True) |
706 |
dialog.connect("confirm-overwrite", self.confirm_overwrite_callback) |
707 |
response = dialog.run() |
708 |
if response == gtk.RESPONSE_OK: |
709 |
name = dialog.get_filename() |
710 |
if '.a4b' not in name: |
711 |
name += '.a4b' |
712 |
if f == None and f != name: |
713 |
f = open(name, 'w') |
714 |
|
715 |
try: |
716 |
pickle.dump(self.view.canvas,f) |
717 |
self.reporter.reportNote(" File ' %s ' saved successfully." % name ) |
718 |
self.status.push(0,"CanvasModel Saved.") |
719 |
self.view.canvas.filestate = 1 |
720 |
self.view.canvas.filename = name |
721 |
except Exception,e: |
722 |
print "ERROR:",str(e) |
723 |
b = obrowser.Browser("canvas",self.view.canvas) |
724 |
d = gtk.Dialog("Error",self,gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) |
725 |
d.vbox.add(gtk.Label(str(e))) |
726 |
d.show_all() |
727 |
d.run() |
728 |
d.hide() |
729 |
finally: |
730 |
f.close() |
731 |
dialog.destroy() |
732 |
|
733 |
def confirm_overwrite_callback(self, widget): |
734 |
uri = gtk.FileChooserDialog.get_filename() |
735 |
if is_uri_read_only(uri): |
736 |
if user_wants_to_replace_read_only_file (uri): |
737 |
return gtk.FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME |
738 |
else: |
739 |
return gtk.FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN |
740 |
else: |
741 |
return gtk.FILE_CHOOSER_CONFIRMATION_CONFIRM |
742 |
return |
743 |
|
744 |
|
745 |
def bp(self, widget = None): |
746 |
if self.view.focused_item: |
747 |
blockproperties.BlockProperties(self, self.view.focused_item).run() |
748 |
else: |
749 |
m = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "No Block was selected! Please select a Block to view its properties.") |
750 |
m.run() |
751 |
m.destroy() |
752 |
|
753 |
def reporterrorblock(self, sim): |
754 |
#TODO: Separate |
755 |
self.errortext = "Canvasmodel could NOT be solved \n Blocks which couldnot be solved:" |
756 |
|
757 |
def checkifsolved(sim_inst, name): |
758 |
if sim_inst.getType().isRefinedSolverVar(): |
759 |
try: |
760 |
#if sim_inst.getStatus() == 2 : |
761 |
# print name + " -> " + str(sim_inst.getStatus()) |
762 |
# self.errorvars.append(name) |
763 |
if sim_inst.getStatus() == 3: |
764 |
self.errorvars.append(name) |
765 |
|
766 |
except Exception,e: |
767 |
print e |
768 |
elif sim_inst.isRelation(): |
769 |
pass |
770 |
else: |
771 |
for i in sim_inst.getChildren(): |
772 |
k = name+"."+str(i.getName()) |
773 |
checkifsolved(i,k) |
774 |
|
775 |
self.errorvars = [] |
776 |
self.errorblocks = [] |
777 |
self.activevar = [] |
778 |
for i in sim.getChildren()[0].getChildren(): |
779 |
print i.getName() |
780 |
checkifsolved(i, str(i.getName())) |
781 |
|
782 |
print self.errorvars |
783 |
for i in sim.getChildren()[0].getChildren(): |
784 |
for j in self.errorvars: |
785 |
if str(i.getName()) in j: |
786 |
if str(i.getName()) in self.errorblocks: |
787 |
pass |
788 |
else: |
789 |
self.errortext += '\n' |
790 |
self.errortext += str(i.getName()) #+' --> ' + ' couldnot be solved' |
791 |
self.errorblocks.append(str(i.getName())) |
792 |
print self.errorblocks |
793 |
self.fill_blocks() |
794 |
|
795 |
|
796 |
def fill_blocks(self): |
797 |
cr = self.view.canvas._obtain_cairo_context() |
798 |
for item in self.view.canvas.get_all_items(): |
799 |
if hasattr(item, 'blockinstance'): |
800 |
bi = item.blockinstance |
801 |
bi.color_r = 1 |
802 |
bi.color_g = 1 |
803 |
bi.color_b = 1 |
804 |
flag = 0 |
805 |
for item in self.view.canvas.get_all_items(): |
806 |
if hasattr(item, 'blockinstance'): |
807 |
bi = item.blockinstance |
808 |
for i in self.errorblocks: |
809 |
if str(bi.name) == str(i): |
810 |
bi.color_r = .5 |
811 |
bi.color_g = 0 |
812 |
bi.color_b = 0 |
813 |
flag = 1 |
814 |
|
815 |
print "updating canvas" |
816 |
self.view.canvas.update_now() |
817 |
if flag == 1: |
818 |
self.view.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#F88')) |
819 |
flag = 0 |
820 |
else: |
821 |
self.view.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#AFA')) |
822 |
|
823 |
def load_library_dialog(self,widget): |
824 |
#TODO: separate |
825 |
dialog = gtk.FileChooserDialog('Load Library...',self, gtk.FILE_CHOOSER_ACTION_OPEN,(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) |
826 |
dialog.set_default_response(gtk.RESPONSE_OK) |
827 |
dialog.set_current_folder(os.path.join(self.ascwrap.defaultlibraryfolder)) |
828 |
|
829 |
filter = gtk.FileFilter() |
830 |
filter.set_name("Canvas Files") |
831 |
filter.add_mime_type("Canvas Files/a4c") |
832 |
filter.add_pattern("*.a4c") |
833 |
dialog.add_filter(filter) |
834 |
|
835 |
filter = gtk.FileFilter() |
836 |
filter.set_name("All files") |
837 |
filter.add_pattern("*") |
838 |
dialog.add_filter(filter) |
839 |
|
840 |
res = dialog.run() |
841 |
if res == gtk.RESPONSE_OK: |
842 |
result = dialog.get_filename() |
843 |
self.loadlib(lib_name = os.path.basename(result)) |
844 |
dialog.destroy() |
845 |
|
846 |
|
847 |
def loadlib(self, widget = None, lib_name = None): |
848 |
##TODO: Separate |
849 |
#if loadcondition == 1: |
850 |
#if self.view.canvas.model_library == lib_name: |
851 |
#m = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, "The selected Library is already loaded. ") |
852 |
#m.run() |
853 |
#m.destroy() |
854 |
#return |
855 |
#if self.view.canvas.get_all_items(): |
856 |
#m = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to switch Library ! The canvas contains models from present Model Library. ") |
857 |
#m.run() |
858 |
#m.destroy() |
859 |
#return |
860 |
|
861 |
#print lib_path |
862 |
self.ascwrap.load_library(lib_name) |
863 |
|
864 |
self.view.canvas.model_library = lib_name |
865 |
|
866 |
self.scroll.remove(self.blockiconview) |
867 |
self.blockiconview = BlockIconView(self.ascwrap.canvas_blocks, self) |
868 |
self.scroll.add(self.blockiconview) |
869 |
self.show_all() |
870 |
|
871 |
#self.status.push(0, " Library '%s' loaded :: Found %d block types." %(lib_name, (len(blocks)))) |
872 |
|
873 |
def get_libraries_from_folder(self,path=None): |
874 |
'Returns a dictionary of library names with their paths' |
875 |
if path == None: |
876 |
return |
877 |
libs = {} |
878 |
locs = glob.glob(os.path.join(path,'*.a4c')) |
879 |
for loc in locs: |
880 |
name = loc.strip(path) |
881 |
libs[name] = loc |
882 |
return libs |
883 |
|
884 |
def zoom(self, widget): |
885 |
zoom = {'ZoomIn':1.2,'ZoomOut':0.8,'BestFit':1.0} |
886 |
x = zoom[widget.get_name()] |
887 |
self.act = self.act*x |
888 |
self.view.zoom(x) |
889 |
|
890 |
|
891 |
def fullscrn(self, widget): |
892 |
try: |
893 |
if self.flag == 1: |
894 |
self.unfullscreen() |
895 |
self.flag = 0 |
896 |
else: |
897 |
self.fullscreen() |
898 |
self.flag = 1 |
899 |
except: |
900 |
self.fullscreen() |
901 |
self.flag = 1 |
902 |
|
903 |
|
904 |
def on_contents_click(self, widget): |
905 |
_help = help.Help(url="http://ascendwiki.cheme.cmu.edu/Canvas-based_modeller_for_ASCEND ") |
906 |
_help.run() |
907 |
|
908 |
def on_get_help_online_click(self, widget): |
909 |
_help = help.Help(url="http://ascendwiki.cheme.cmu.edu/Canvas_Development") |
910 |
_help.run() |
911 |
|
912 |
def on_report_a_bug_click(self, widget): |
913 |
_help = help.Help(url="http://ascendbugs.cheme.cmu.edu/report/") |
914 |
_help.run() |
915 |
|
916 |
def quit(self,args): |
917 |
del(self.prefs) |
918 |
self.destroy() |