1 """Components for the top level of the QUB Express or Fitness.
2
3 Copyright 2008-2014 Research Foundation State University of New York
4 This file is part of QUB Express.
5
6 QUB Express is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 QUB Express is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License,
17 named LICENSE.txt, in the QUB Express program directory. If not, see
18 <http://www.gnu.org/licenses/>.
19
20
21 """
22
23
24 import os
25 import sys
26 for path in sys.path:
27 if 'dist' in path:
28 base, leaf = path, ''
29 while 'dist' in base:
30 base, leaf = os.path.split(base)
31 if leaf == 'dist':
32 sys.path.append(os.path.join(base, leaf))
33 break
34
35 import gc
36 import gtk
37 import gobject
38 import sys
39 import linecache
40 import multiprocessing
41 import argparse
42 import os
43 import platform
44 import re
45 import time
46 import traceback
47 import urllib
48 import webbrowser
49
50 import qubx.fast.fast_utils
51
52 import qubx.crash_rep
53 import qubx.data_types
54 import qubx.data_abf
55 import qubx.data_acquire
56 import qubx.data_tacidl
57 import qubx.data_pulse
58 import qubx.data_fit
59 import qubx.dataGTK
60 import qubx.extract
61 import qubx.fit
62 import qubx.fit_robots
63 import qubx.global_namespace
64 import qubx.GTK
65 import qubx.ideal_tools
66 import qubx.idealize
67 import qubx.kalman
68 import qubx.list_average
69 import qubx.list_figure
70 import qubx.select_charts
71 import qubx.simulate
72 import qubx.spectrum
73 import qubx.splash_main
74 import qubx.tree
75 import qubx.treeGTK
76 import qubx.trials
77 import qubx.modelGTK
78 import qubx.table
79 import qubx.tableGTK
80 import qubx.task
81 import qubx.toolspace
82 import qubx.pyenv
83 import qubx.settings
84 import qubx.pyenvGTK
85 import qubx.model
86 import qubx.model_charts
87 import qubx.model_link
88 import qubx.modeling_utils
89 import qubx.faces
90 import qubx.hist
91 import qubx.hill
92 import qubx.optimize
93 import qubx.optimizeGTK
94 import qubx.notebook
95 import qubx.notebookGTK
96 import qubx.notebook_qtiplot
97 import qubx.notebook_scidavis
98 import qubx.script_seq
99 import qubx.stimulus
100 import qubx.vcheck_client
101 import qubx.workflow
102
103 from gtk import gdk
104 from gtk import keysyms
105 from itertools import izip, count
106 from qubx.util_types import *
107 from qubx.accept import *
108 from qubx.data_panel import DataSourceFace, DataFace
109 from qubx.models_panel import ModelsFace
110 from qubx.table_panel import TablesFace
111 from qubx.toolspace import ColorInfo
112 from qubx.util_panels import TasksFace, ScriptsFace, AltKeysFace, AboutFace, SettingsFace, PluginsFace
113 from qubx.GTK import pack_item, pack_space, pack_hsep, pack_vsep, pack_label, pack_button, pack_check, pack_radio, pack_scrolled, build_menuitem
114
115 import numpy
116 import scipy
117 import scipy.signal
118 from math import *
119 from numpy import *
120
121 COLOR_VERSIONSTAMP = ('express.version', (1,1,1,1))
122 ColorInfo[COLOR_VERSIONSTAMP[0]].label = 'Window version'
123
124 COLOR_MENU_OTHER = ('qubx.cube.other.menu', (.2, 1, .2, 1))
125 ColorInfo[COLOR_MENU_OTHER[0]].label = 'Other panel menu'
126
127 TARGET_TYPE_URI_LIST = 80
128 dnd_list = [ ( 'text/uri-list', 0, TARGET_TYPE_URI_LIST ) ]
129
130
131 MAX_EVENTS_PER_SCRIPT_LINE = 128
132
134
135 path = ""
136 if uri.startswith('file:\\\\\\'):
137 path = uri[8:]
138 elif uri.startswith('file://'):
139 path = uri[7:]
140 elif uri.startswith('file:'):
141 path = uri[5:]
142
143 path = urllib.url2pathname(path)
144 path = path.strip('\r\n\x00')
145
146 return path
147
148 -class Cube(gtk.Window):
149 """Main window of QUB Express, Fitness.
150
151 @ivar appname: e.g. "QUB Express"
152 @ivar Layout: L{qubx.faces.ToolsToggleFace} controlling all left-hand panels and menus
153 @ivar Panels: L{qubx.faces.ToolsFace} in upper-left, for utilities; aka "Other"
154 @ivar Tools: link to Panels.Tools
155 @ivar Simulation: link to Panels.Simulation
156 @ivar Modeling: link to Panels.Modeling
157 @ivar Figures: link to Panels.Figures
158 @ivar Workflows: link to Panels.Workflows
159 @ivar Admin: link to Panels.Admin
160 @ivar Data: L{DataFace}
161 @ivar Tables: L{TablesFace}
162 @ivar Models: L{ModelsFace}
163 @ivar Tasks: L{TasksFace}
164 @ivar About: L{qubx.faces.ToolsFace} in upper-right, for context info
165 @ivar OnInit: L{WeakEvent}C{()} called on first idle
166 @ivar OnQuitting: L{WeakEvent}C{( do_cancel() )} called when trying to quit; call do_cancel() to stay open
167 @ivar OnQuit: L{WeakEvent}C{()} called just before gtk.main_quit()
168 """
169
170 __explore_featured = ['appname', 'Layout', 'Panels', 'Tools', 'Simulation', 'Modeling', 'Figures', 'Workflows', 'Admin',
171 'Data', 'Tables', 'Models', 'Charts', 'Tasks', 'About', 'OnInit', 'OnQuitting', 'OnQuit',
172 'vbox', 'left_right', 'subVersion', 'tasks_info_log', 'tasks_ds', 'info_log', 'boxNotebook', 'btnBugReport',
173 'mnuOther', 'mnuSubOther', 'Trials', 'DataSource', 'Layout_alt', 'use_alt_layout', 'toggle_layout',
174 'show_charts', 'show_version', 'check_version', 'require_version', 'can_not_quit', 'try_to_quit',
175 'new_table', 'open_table', 'write_log', 'pause', 'resume', 'quit']
176
177 - def __init__(self, appname, has_modeling=True, adjust_layout=lambda cube:None):
178 self.appname = appname
179 self.has_modeling = has_modeling
180 MapSettings()
181 gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
182 self.set_title(appname)
183 self.connect('delete_event', self._onDelete)
184 self.connect('destroy', self._onDestroy)
185 self.ref = Reffer()
186 self._profile = SettingsMgr['Cube'].active
187 SettingsMgr['Cube'].OnSet = self.ref(self._onPreSet)
188 self.__initial_layout = self._profile['Layout'].clone()
189 self._keepName = ''
190 self.connect('configure_event', self._onConfigure)
191
192
193
194 qubx.pyenv.env.globals['QubX'] = self
195 qubx.pyenv.env.globals['SettingsMgr'] = SettingsMgr
196 gobject.idle_add(qubx.pyenv.env.after_initialize)
197
198 self.OnInit = WeakEvent()
199 self.OnQuitting = WeakEvent()
200 self.OnQuit = WeakEvent()
201 gobject.idle_add(self.OnInit)
202
203 Settings = SettingsFace(global_name='QubX.Admin.Settings')
204
205 self.vbox = gtk.VBox()
206 self.vbox.show()
207 self.add(self.vbox)
208
209
210
211
212
213
214 self.left_right = pack_item(gtk.HPaned(), self.vbox, expand=True)
215 self.left_right.connect('notify::position', self._on_left_right)
216
217 self.Layout = qubx.faces.ToolsToggleFace('Layout', self._profile['Layout'], global_name='QubX.Layout')
218 self.Layout.add_events(gdk.KEY_PRESS_MASK)
219 self.Layout.connect('key_press_event', self._onLayoutKeyPress)
220 self.Layout.show()
221 self.left_right.pack1(self.Layout, True, True)
222 self.subVersion = qubx.toolspace.SubLayer_Label('', 0, 1, x=0, w=2, h=qubx.faces.TOOLTOGGLE_NAME_EM,
223 color=COLOR_VERSIONSTAMP, rotate=pi/2,
224 action=self.ref(bind(self.__onClickTool, ['Tools', 'About'])))
225 self.Layout.nameLayer.add_sublayer(self.subVersion)
226 self.Layout.parent_window = self
227
228 self.tasks_info_log = gtk.VBox(False)
229 self.tasks_info_log.show()
230 self.left_right.pack2(self.tasks_info_log, True, True)
231 self.tasks_ds = pack_item(gtk.VBox(False), self.tasks_info_log)
232 self.Tasks = pack_item(TasksFace(global_name='QubX.Tasks'), self.tasks_ds)
233 pack_hsep(11, self.tasks_info_log)
234
235 self.info_log = pack_item(gtk.VPaned(), self.tasks_info_log, expand=True)
236 self.About = qubx.faces.ToolsFace("About", pos=gtk.POS_TOP, global_name='QubX.About')
237 self.About.set_size_request(120, 120)
238 self.About.show()
239 self.info_log.pack1(self.About, True, False)
240 self.boxNotebook = gtk.VBox()
241 self.boxNotebook.show()
242 self.info_log.pack2(self.boxNotebook, True, False)
243 pan = pack_item(qubx.notebookGTK.NbEntryFace(), self.boxNotebook, expand=True)
244
245
246 self.btnBugReport = pack_button('Send bug report...', self.tasks_info_log, on_click=self.__onClickBugReport)
247
248 self.Panels = qubx.faces.ToolsFace(' Other', global_name='QubX.Panels')
249 self.Panels.show()
250 self.mnuOther = gtk.Menu()
251 self.mnuSubOther = qubx.toolspace.SubLayer_Popup(self.mnuOther, COLOR_MENU_OTHER, on_popup=self.ref(self.__onPopupOther),
252 w=qubx.faces.TOOLTOGGLE_WIDTH_EM, h=qubx.faces.TOOLTOGGLE_WIDTH_EM,
253 tooltip="Menu of panels, scripts, and layout options",
254 border=qubx.faces.TOOLTOGGLE_TAB_BORDER)
255 self.Panels.tab_sublayers.append(self.mnuSubOther)
256 self.Tables = TablesFace(global_name='QubX.Tables')
257 self.Tables.show()
258
259 self.Data = DataFace(self.Tables, has_modeling, global_name='QubX.Data')
260 self.Data.show()
261 if has_modeling:
262 self.Models = ModelsFace(self.Tables, global_name='QubX.Models')
263 self.Models.show()
264 self.Trials = qubx.trials.Trials(self.Data, self.Models.views[0])
265 else:
266 self.Models = self.Trials = None
267
268 self.Layout.append_face(self.Panels)
269 self.Layout.append_face(self.Data)
270 self.Layout.append_face(self.Tables)
271 if has_modeling:
272 self.Layout.append_face(self.Models)
273
274 self.DataSource = qubx.dataGTK.DataSource(self)
275 self.DataSourceFace = pack_item(DataSourceFace(self.DataSource, global_name='QubX.DataSourceFace'), self.tasks_ds)
276
277 self.Data.init_fitting()
278
279 self.Panels.append_face(qubx.faces.ToolsFace('Tools', global_name='QubX.Tools'))
280 self.Tools = self.Panels.Tools
281 self.Tools.append_face(AboutFace(global_name='QubX.Tools.About'))
282 self.Tools.append_face(qubx.extract.ExtractFace(global_name='QubX.Tools.Extract'))
283 self.Tools.append_face(qubx.kalman.KalmanFace(global_name='QubX.Tools.Kalman'))
284 if has_modeling:
285 self.Tools.append_face(qubx.ideal_tools.IdlToolsFace(global_name='QubX.Tools.Idealization'))
286 self.Panels.append_face(qubx.simulate.SimulationFace(global_name='QubX.Simulation'))
287 self.Simulation = self.Panels.Simulation
288 self.Panels.append_face(ModelingFace(global_name='QubX.Modeling'))
289 self.Modeling = self.Panels.Modeling
290 self.Modeling.append_face(qubx.stimulus.StimulusFace(self, global_name='QubX.Modeling.Stimulus'))
291 self.Modeling.append_face(qubx.modeling_utils.ModelingUtilsFace())
292 self.Modeling.append_face(qubx.idealize.IdlFace())
293 skm = qubx.idealize.SKMIdealizer()
294 self.Modeling.Idealize.register_method('Viterbi', skm)
295 self.Modeling.Idealize.register_method('SKM', skm)
296 self.Modeling.Idealize.register_method('Baum-Welch', qubx.idealize.BaumWelchIdealizer())
297 self.Modeling.Idealize.register_method('By Delta (forward)', qubx.stimulus.ByDeltaIdealizer())
298 self.Modeling.Idealize.register_method('By Delta (binary)', qubx.stimulus.ByDeltaARIdealizer())
299 self.Panels.append_face(qubx.faces.ToolsFace('Figures', global_name='QubX.Figures'))
300 self.Figures = self.Panels.Figures
301 self.Figures.append_face(qubx.select_charts.SelectFace(global_name='QubX.Figures.Charts'))
302 self.Charts = self.Figures.Charts
303 self.Panels.Figures.append_face(qubx.hist.AmpHistFace(global_name='QubX.Figures.AmpHist'))
304 self.Figures.append_face(qubx.list_average.ListAverageFace('Average', 'QubX.Figures.Average'))
305 self.Figures.append_face(qubx.list_figure.ListFigureFace('ListFigure', 'QubX.Figures.ListFigure'))
306 self.Panels.Figures.append_face(qubx.spectrum.SpectrumFace(global_name='QubX.Figures.Spectrum'))
307 if has_modeling:
308 self.Panels.Figures.append_face(qubx.hill.HillFace(global_name='QubX.Figures.Hill'))
309 self.Panels.append_face(qubx.faces.ToolsFace('Workflows', global_name='QubX.Workflows', pos=qubx.faces.POS_DROPDOWN, dropdown_label="Select a workflow:"))
310 self.Workflows = self.Panels.Workflows
311 self.Panels.append_face(qubx.faces.ToolsFace('Admin', global_name='QubX.Admin'))
312 self.Admin = self.Panels.Admin
313 self.Panels.Admin.append_face(Settings)
314 self.Admin.append_face(qubx.notebookGTK.NotebookFace(global_name='QubX.Admin.Notebook'))
315 self.Panels.Admin.append_face(ScriptsFace(global_name='QubX.Admin.Scripts'))
316 self.Panels.Admin.append_face(PluginsFace(global_name='QubX.Admin.Plugins'))
317 self.Panels.Admin.append_face(AltKeysFace(global_name='QubX.Admin.AltKeys'))
318 self.Panels.Admin.append_face(qubx.script_seq.SeqFace(global_name='QubX.Admin.Seq'))
319
320 self.Data.pop_info.OnWindow += self.ref(self.__connect_drag)
321 self.Tables.pop_info.OnWindow += self.ref(self.__connect_drag)
322 if has_modeling:
323 self.Models.pop_info.OnWindow += self.ref(self.__connect_drag)
324
325 self.Panels.OnSwitchFace += self.ref(self.__onSwitchPanel)
326 try:
327 self.Panels.show_face(str(self._profile.find('Panel').data))
328 except:
329 self.Panels.show_face('Tools')
330 self.Tools.show_face('About')
331 adjust_layout(self)
332 gobject.idle_add(self.__restore_faces)
333
334 try:
335 x, y, w, h = self._profile['alloc'].data[:]
336 self.resize(w, h)
337 gobject.idle_add(self.move, x, y)
338 except:
339 w, h = gdk.screen_width()-10, gdk.screen_height()-70
340 self.resize(w, h)
341 gobject.idle_add(self.move, 0, 0)
342 try:
343 self.left_right.set_position(int(round(w * self._profile['left_right'].data[0])))
344 except:
345 self.left_right.set_position(w - max(150, min(300, int(round(w*15.0/80.0)))))
346 try:
347 self.info_log.set_position(int(round(h * self._profile['info_log'].data[0])))
348 except:
349 self.info_log.set_position(h-120)
350
351
352 vis = self.Layout.profile['Showing']
353 frac = self.Layout.profile['Fraction']
354 for face in self.Layout.faces:
355 if not vis.find(face.face_name).data:
356 vis[face.face_name].data = 1
357 if not frac.find(face.face_name).data:
358 if has_modeling:
359 frac[face.face_name].data = {' Other' : .18,
360 ' Data' : .35,
361 ' Tables' : .15,
362 ' Models' : .32}[face.face_name]
363 else:
364 frac[face.face_name].data = {' Other' : .2,
365 ' Data' : .6,
366 ' Tables' : .2}[face.face_name]
367 gobject.idle_add(self.__show_faces)
368
369 self.Layout_alt = gtk.Window(gtk.WINDOW_TOPLEVEL)
370 self.Layout_alt.connect('delete_event', self._onDelete)
371 self.Layout_alt.connect('destroy', self._onDestroy)
372 self.Layout_alt.connect('configure_event', self._onConfigureAlt)
373 self.Layout_alt.add_events(gdk.KEY_PRESS_MASK)
374 self.Layout_alt.connect('key_press_event', self._onLayoutKeyPress)
375 self.Layout_alt.set_size_request(200, 480)
376 self.Layout_alt.set_title(self.appname)
377 try:
378 x, y, w, h = self._profile['alloc_alt'].data[:]
379 self.Layout_alt.resize(w, h)
380 gobject.idle_add(self.Layout_alt.move, x, y)
381 except:
382 pass
383 v = gtk.VBox()
384 v.show()
385
386 self.__use_alt_layout = False
387 self.Layout_alt.add(v)
388 self.Layout_alt.menubar = pack_item(gtk.MenuBar(), v)
389 self.Layout_alt.mnuWindows = gtk.Menu()
390 self.Layout_alt.menubar.append(build_menuitem('Windows', self.ref(self.__onPopupWindows), submenu=self.Layout_alt.mnuWindows))
391 self.Layout_alt.mnuLayouts = gtk.Menu()
392 self.Layout_alt.menubar.append(build_menuitem('Layouts', self.ref(self.__onPopupLayouts), submenu=self.Layout_alt.mnuLayouts))
393 self.Layout_alt.mnuScripts = gtk.Menu()
394 self.Layout_alt.menubar.append(build_menuitem('Scripts', self.ref(self.__onPopupScripts), submenu=self.Layout_alt.mnuScripts))
395 self.Layout_alt.mnuTools = gtk.Menu()
396 self.Layout_alt.main_pane = pack_item(gtk.VBox(), v, expand=True)
397 self.Layout_alt.nameLayer = qubx.toolspace.Layer(x=-qubx.faces.TOOLTOGGLE_NAME_EM, w=-.01, h=2)
398 self.Layout_alt.subVersion = self.Layout_alt.nameLayer.add_sublayer(qubx.toolspace.SubLayer_Label(self.appname, 0, 1, x=0, w=-.01, h=2,
399 color=COLOR_VERSIONSTAMP,
400 action=self.ref(bind(self.Tools.About.pop_info.set_state, 1))))
401 self.Layout_alt.logo = pack_item(qubx.toolspace.ToolSpace(), v, at_end=True)
402 self.Layout_alt.logo.add_layer(self.Layout_alt.nameLayer)
403 self.Layout_alt.logo.appearance.OnSetFontSize += self.ref(self.__onSetFontSize)
404 self.__onSetFontSize(self.Layout_alt.logo.appearance.font_size)
405
406 self.__connect_drag_win(self)
407 ual = False if self._profile.find('use_alt_layout').isNull else self._profile['use_alt_layout'].data[0]
408 gobject.idle_add(self.set_use_alt_layout, ual)
409
410 use_alt_layout = property(lambda self: self.__use_alt_layout, lambda self, x: self.set_use_alt_layout(x))
412 self.Layout_alt.logo.set_size_request(-1, int(round(2*self.Layout_alt.logo.appearance.emsize)))
414 win.connect('drag_data_received', self.on_drag_data_received)
415 win.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
416 gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP,
417 dnd_list, gtk.gdk.ACTION_COPY)
456 menu = self.Layout_alt.mnuWindows
457 menu.foreach(lambda item: menu.remove(item))
458 menu.ref = Reffer()
459 build_menuitem('Data', menu.ref(lambda item: self.Data.pop_info.set_state(1) or self.Data.pop_info.window.present()), menu=menu)
460 if 'Models' in self.__dict__:
461 build_menuitem('Models', menu.ref(lambda item: self.Models.pop_info.set_state(1) or self.Models.pop_info.window.present()), menu=menu)
462 if 'Charts' in self.__dict__:
463 build_menuitem('Charts', menu.ref(lambda item: self.Charts.pop_info.set_state(1) or self.Charts.pop_info.window.present()), menu=menu)
464 build_menuitem('Tables', menu.ref(lambda item: self.Tables.pop_info.set_state(1) or self.Tables.pop_info.window.present()), menu=menu)
465 for face in self.Panels.faces:
466 menu.append(nest_faces(face))
467
468 build_menuitem('Go to QUB Web Site...', self.ref(bind(webbrowser.open, 'https://qub.mandelics.com')), menu=menu)
482 def nest_scripts(script_menu, path):
483 for base, dirs, files in os.walk(path):
484 for d in dirs:
485 sub = gtk.Menu()
486 build_menuitem(d, submenu=sub, menu=script_menu)
487 nest_scripts(sub, os.path.join(path, d))
488 dirs[:] = []
489 for f in files:
490 name, ext = os.path.splitext(f)
491 if ext.lower() == '.py':
492 build_menuitem(name, script_menu.ref(bind(self.__onClickScript, os.path.join(path, f))), menu=script_menu)
493 scripts_menu = self.Layout_alt.mnuScripts
494 scripts_menu.foreach(lambda item: scripts_menu.remove(item))
495 scripts_menu.ref = Reffer()
496 build_menuitem('Scripts Window', scripts_menu.ref(lambda item: self.Admin.Scripts.pop_info.set_state(1) or self.Admin.Scripts.pop_info.window.present()), menu=scripts_menu)
497 build_menuitem('Sequencer', scripts_menu.ref(lambda item: self.Admin.Seq.pop_info.set_state(1) or self.Admin.Seq.pop_info.window.present()), menu=scripts_menu)
498 build_menuitem('-', menu=scripts_menu)
499 nest_scripts(scripts_menu, os.path.join(qubx.pyenv.env.globals['app_path'], 'Scripts'))
500 nest_scripts(scripts_menu, os.path.join(qubx.pyenv.env.folder, 'Scripts'))
504 if self.__use_alt_layout == bool(x):
505 return
506 self.__use_alt_layout = bool(x)
507 self._profile['use_alt_layout'].data = bool(x)
508 if x:
509 self.left_right.remove(self.tasks_info_log)
510 self.Layout_alt.main_pane.pack_start(self.tasks_info_log)
511 qubx.faces.REQUEST_SHOW_AS_WINDOW = True
512 self.Layout.showing = False
513 gobject.idle_add(self.hide)
514 gobject.idle_add(self.Layout_alt.show)
515 else:
516 self.Layout_alt.main_pane.remove(self.tasks_info_log)
517 self.left_right.pack2(self.tasks_info_log, True, True)
518 self.Layout.unpop_all()
519 qubx.faces.REQUEST_SHOW_AS_WINDOW = False
520 self.Layout.showing = True
521 gobject.idle_add(self.Layout_alt.hide)
522 gobject.idle_add(self.show)
541 qubx_version = qubx.pyenv.parse_version_str(qubx.pyenv.env.globals['QUBX_VERSION'])
542 n_common = min(len(version), len(qubx_version))
543 for q, v in izip(qubx_version[:n_common], version[:n_common]):
544 if q < v:
545 raise Exception('Plugin requires QUB Express %s, but this is version %s. Please download a newer version of QUB Express.' %
546 ('.'.join(str(x) for x in version), '.'.join(str(x) for x in qubx_version)))
547 elif q > v:
548 return
571 self._profile['Panel'].data = face_name
575 self._profile['ModelingFace'].data = face_name
579 self._profile['AdminFace'].data = face_name
583 self._cancelDelete = False
584 self.OnQuitting(self._do_cancelDelete)
585 return self._cancelDelete
587 if not self.can_not_quit():
588 self.OnQuit()
589 gtk.main_quit()
591 self._cancelDelete = True
593 self.OnQuit()
594 gtk.main_quit()
602 try:
603 p = self._profile['left_right'].data[0]
604 self.left_right.set_position(int(round(w * p)))
605 self._profile['left_right'].data = p
606 except:
607 pass
608 try:
609 p = self._profile['info_log'].data[0]
610 self.info_log.set_position(int(round(h * p)))
611 self._profile['info_log'].data = p
612 except:
613 pass
614 if updates.find('use_alt_layout').data:
615 self.use_alt_layout = updates['use_alt_layout'].data[0]
616 if self.__updateLayout(settings, updates['Layout']) and not self.use_alt_layout:
617 x, y, w, h = updates['alloc'].data[:]
618 self.resize(w, h)
619 gobject.idle_add(self.move, x, y)
620 if self.use_alt_layout:
621 x, y, w, h = updates['alloc_alt'].data[:]
622 self.Layout_alt.resize(w, h)
623 gobject.idle_add(self.Layout_alt.move, x, y)
627 def nest_scripts(script_menu, path):
628 for base, dirs, files in os.walk(path):
629 for d in dirs:
630 sub = gtk.Menu()
631 build_menuitem(d, submenu=sub, menu=script_menu)
632 nest_scripts(sub, os.path.join(path, d))
633 dirs[:] = []
634 for f in files:
635 name, ext = os.path.splitext(f)
636 if ext.lower() == '.py':
637 build_menuitem(name, self.ref(bind(self.__onClickScript, os.path.join(path, f))), menu=script_menu)
638 def nest_faces(face, path=[]):
639 path2 = path+[face.face_name]
640 submenu = None
641 try:
642 if face.faces:
643 submenu = gtk.Menu()
644 for subface in face.faces:
645 submenu.append(nest_faces(subface, path2))
646 except:
647 pass
648 if submenu:
649 item = build_menuitem(face.face_name, submenu=submenu)
650 else:
651 item = build_menuitem(face.face_name, self.ref(bind(self.__onClickTool, path2)))
652 return item
653 menu = self.mnuOther
654 menu.foreach(lambda item: menu.remove(item))
655 panel_menu = gtk.Menu()
656 item = build_menuitem('Show Panel', submenu=panel_menu, menu=menu)
657 for face in self.Panels.faces:
658 panel_menu.append(nest_faces(face, [' Other']))
659 scripts_menu = gtk.Menu()
660 item = build_menuitem('Scripts', submenu=scripts_menu, menu=menu)
661 nest_scripts(scripts_menu, os.path.join(qubx.pyenv.env.globals['app_path'], 'Scripts'))
662 nest_scripts(scripts_menu, os.path.join(qubx.pyenv.env.folder, 'Scripts'))
663 layout_menu = gtk.Menu()
664 item = build_menuitem('Layout', submenu=layout_menu, menu=menu)
665 layout_menu.append(build_menuitem('Show All', self.ref(bind(self.__onClickShowAll))))
666 layout_menu.append(build_menuitem('Hide All', self.ref(bind(self.__onClickHideAll))))
667 layout_menu.append(build_menuitem('Equal Sizes', self.ref(bind(self.__onClickEqualSizes))))
668 for name in SettingsMgr['Cube'].listNames():
669 layout_menu.append(build_menuitem(name, self.ref(bind(self.__onClickPreset, name))))
670 layout_menu.append(build_menuitem('Manage Layouts...', self.ref(bind(self.__onClickManageLayouts))))
671 layout_menu.append(build_menuitem('Add Layout to Menu...', self.ref(bind(self.__onClickAddToMenu))))
672 menu.append(build_menuitem('Switch to multi-window layout', self.ref(bind(self.toggle_layout))))
673 chk = build_menuitem('Reset all settings (upon exiting)', self.ref(bind(self.__onClickResetAll)), menu=menu, item_class=gtk.CheckMenuItem, active=qubx.global_namespace.RESET_ALL_SETTINGS)
674 menu.append(build_menuitem('QUB Web Site...', self.ref(bind(webbrowser.open, 'https://qub.mandelics.com'))))
675 return True
686 if qubx.pyenv.env.globals['global_key_press'](w, evt):
687 return True
688
689 return False
690 - def new_table(self, name=None, initial_row=True):
724 x,y,w,h = self.get_allocation()
725 if w <= 1: return
726 p = paned.get_position()
727 self._profile['left_right'].data = min(1.0, max(0.0, p * 1.0 / w))
729 x,y,w,h = self.get_allocation()
730 if h <= 1: return
731 p = paned.get_position()
732 self._profile['info_log'].data = min(1.0, max(0.0, p * 1.0 / h))
736 """Appends msg to the scrolling text at lower right; trailing newline optional."""
737 end = len(msg)
738 if len(msg) and (msg[-1] == '\n'):
739 end -= 1
740 clipped = msg[:end]
741
742
743
744 print clipped
750 - def quit(self, message='Quitting from script'):
751 """Call only from a script; raises KeyboardInterrupt."""
752 self.destroy()
753 raise KeyboardInterrupt(message)
754
755
763
764
765
771
772
773
775 for i in xrange(max_events):
776 if not gtk.events_pending():
777 break
778 gtk.main_iteration(False)
779
780
781
783 """Sets up the main window (L{Cube}) and calls gtk.main."""
784 __explore_featured = ['cube', 'setup_about', 'setup_paths', 'setup_globals', 'setup_altmap', 'global_key_press', 'main']
785 - def __init__(self, appname, version, user_dir, has_modeling=True, DEBUG=False, codename='qubx', adjust_layout=lambda cube:None):
786 self.__ref = Reffer()
787
788 global app_path, home, documents_path
789 app_path, home, documents_path = self.setup_paths()
790 user_path = os.path.join(home, user_dir)
791 if os.path.exists(os.path.join(app_path, user_dir)):
792 user_path = os.path.join(app_path, user_dir)
793 else:
794 oneup, leaf = os.path.split(app_path)
795 if (leaf == 'dist') and os.path.exists(os.path.join(oneup, user_dir)):
796 user_path = os.path.join(oneup, user_dir)
797
798 qubx.pyenv.Init(user_path, gobject.idle_add, gobject.timeout_add, gobject.MainLoop, process_events, app_path)
799 qubx.pyenv.env.globals['DEBUG'] = DEBUG
800 qubx.pyenv.env.globals['home'] = home
801 qubx.pyenv.env.globals['app_path'] = app_path
802 qubx.pyenv.env.globals['documents_path'] = documents_path
803 qubx.pyenv.env.globals['global_key_press'] = self.global_key_press
804 codename_ext = '64' if ((platform.system() == 'Linux') and ('64' in platform.architecture()[0])) else ''
805 qubx.pyenv.env.globals['QUBX_CODENAME'] = '%s%s' % (codename, codename_ext)
806
807 qubx.settings.InitSettings(os.path.join(app_path, 'Presets'), os.path.join(user_path, "Presets"))
808
809 qubx.fit_robots.InitFitRobots(self.__ref(lambda: qubx.task.Tasks.add_task(qubx.fit_robots.robots)),
810 self.__ref(lambda: qubx.task.Tasks.remove_task(qubx.fit_robots.robots)))
811
812 qubx.notebookGTK.Init()
813 qubx.notebook_qtiplot.Init()
814 qubx.notebook_scidavis.Init()
815
816 self.setup_altmap()
817
818 if DEBUG:
819 qubx.util_types.ShowDropped = True
820
821 self.cube = Cube(appname, has_modeling, adjust_layout)
822 self.cube.OnQuitting += self.__ref(self._onQuitting)
823 self.cube.show()
824
825 if has_modeling:
826 self.cube.Models.new()
827
828 self.cube.show_version('%s %s' % (appname, version), 'https://qub.mandelics.com')
829 print '%s %s' % (appname, version)
830 print 'app_path: ',app_path
831 self.setup_about()
832
833 qubx.pyenv.Plugins.initialize(os.path.join(app_path, 'Plugins'),
834 os.path.join(user_path, 'Plugins'))
837
839 home = os.path.expanduser('~')
840 documents_path = home
841 if home.find(':') >= 0:
842
843 documents_path = os.path.join(home, 'My Documents')
844 app_path = os.path.split(sys.argv[0])[0]
845 stem, leaf = os.path.split(app_path)
846 if leaf == 'qubx':
847 app_path = stem
848 else:
849 app_path = os.environ.get('QUBX_PATH') or '/usr/share/qub-express'
850 app_path = os.path.abspath(app_path)
851 return app_path, home, documents_path
852
856
858 env = qubx.pyenv.env
859 if not env.altmap['c']:
860 env.set_alt('c', 'Chop(silent=False)')
861 if not env.altmap['r']:
862 env.set_alt('r', 'QubX.Admin.Scripts.scripts.run()')
863 if not env.altmap['t']:
864 env.set_alt('t', "QubX.Tables.request_show(); QubX.Tables.grab_focus()")
865 if not env.altmap['`']:
866 env.set_alt('`', 'QubX.mnuSubOther.do_popup()')
867
885
886 - def main(self, startup_script=None):
887 script_path = os.path.abspath(startup_script) if startup_script else None
888 self.setup_globals()
889 qubx.notebookGTK.InitAfter()
890 mark_qubx_ready()
891 if script_path:
892 if script_path == '-':
893 qubx.pyenv.env.exec_file(script_path)
894 elif os.path.exists(script_path):
895 self.cube.Admin.Scripts.scripts.open(script_path)
896 gobject.idle_add(self.cube.Admin.Scripts.scripts.run)
897 elif qubx.pyenv.env.folder == os.path.split(script_path)[0]:
898 try:
899 open(script_path, 'w').write("""# This script is run each time QUB Express starts. If you click the same ten things each time the program starts,
900 # try recording them in this script:
901 # * click "record" above (the red circle)
902 # * do your repetitive setup, e.g. open some files
903 # * click "record" or "stop" above to finish the script
904 # * click "save" above
905 # To reset the startup script, delete this file or its contents at any time.
906 # Tip: While recording, click "pause" above to insert a break into the script.
907 # The script will wait at that point until you click "play."
908
909 """)
910 except:
911 traceback.print_exc()
912 gobject.idle_add(qubx.crash_rep.Init)
913 if qubx.splash_main.Splash:
914 gobject.idle_add(lambda: gobject.idle_add(qubx.splash_main.Splash.destroy) and None)
915 gtk.main()
916 qubx.crash_rep.Fini()
917
926
929
930
933
934
935
942