CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Application.py
Go to the documentation of this file.
1 import os
2 import sys
3 import string
4 import commands
5 import platform
6 import logging
7 import logging.handlers
8 import ConfigParser
9 import optparse
10 import webbrowser
11 import subprocess
12 
13 from PyQt4.QtCore import SIGNAL,qVersion,QString,QVariant, Qt
14 from PyQt4.QtGui import QApplication,QMenu,QPixmap,QAction,QFileDialog,QIcon,QMessageBox
15 
16 from Vispa.Main.Directories import logDirectory,pluginDirectory,baseDirectory,homeDirectory,iniFileName,applicationName,docDirectory,websiteUrl
17 from Vispa.Main.MainWindow import MainWindow
18 from Vispa.Main.AbstractTab import AbstractTab
19 from Vispa.Main.Filetype import Filetype
20 from Vispa.Main.Exceptions import *
21 from Vispa.Main.AboutDialog import AboutDialog
22 from Vispa.Main.RotatingIcon import RotatingIcon
23 #from PreferencesEditor import PreferencesEditor
24 import Vispa.__init__
25 
26 import Resources
27 
28 class Application(QApplication):
29 
30  MAX_RECENT_FILES = 30
31  MAX_VISIBLE_RECENT_FILES = 10
32  MAX_VISIBLE_UNDO_EVENTS = 10
33  FAILED_LOADING_PLUGINS_ERROR = "Errors while loading plugins. For details see error output or log file.\n\nThe following plugins won't work correctly:\n\n"
34  TAB_PREMATURELY_CLOSED_WARNING = "Tab was closed before user request could be handled."
35  NO_PROCESS_EVENTS = False
36 
37  def __init__(self, argv):
38  QApplication.__init__(self, argv)
39  self._version = None
40  self._plugins = []
41  self._closeAllFlag = False
44  self._pluginMenus = []
45  self._pluginToolBars = []
46  self._recentFiles = []
47  self._ini = None
48  self._iniFileName = iniFileName
49  self._zoomToolBar = None
50  self._undoToolBar = None
51  self._messageId=0
52  self._loadablePlugins = {}
53  self._logFile = None
54 
55  self._initLogging()
56 
57  logging.debug('Running with Qt-Version ' + str(qVersion()))
58 
60 
61  self._loadIni()
62 
63  self.setVersion(Vispa.__init__.__version__)
64 
65  self._window = MainWindow(self, applicationName)
66  self._window.show()
67 
68  self._loadPlugins()
69 
70  self._fillFileMenu()
71  self._fillEditMenu()
72  self._fillHelpMenu()
73 
74  self.createUndoToolBar()
75  self.createZoomToolBar()
76  self.hidePluginMenus()
77  self.hidePluginToolBars()
78  self.createStatusBar()
79  self.updateMenu()
80 
82  self._connectSignals()
83 
84  def commandLineParser(self):
85  return self._commandLineParser
86 
87  def commandLineOptions(self):
88  return self._commandLineOptions
89 
90  def setVersion(self, version):
91  self._version = version
92 
93  def version(self):
94  """ Returns version string.
95  """
96  return self._version
97 
98  def atLeastQtVersion(self, versionString):
99  """ Returns True if given versionString is newer than current used version of Qt.
100  """
101  [majorV, minorV, revisionV] = versionString.split(".")
102  [majorQ, minorQ, revisionQ] = str(qVersion()).split(".")
103  if majorV > majorQ:
104  return True
105  elif majorV < majorQ:
106  return False
107  elif majorV == majorQ:
108  if minorV > minorQ:
109  return True
110  elif minorV < minorQ:
111  return False
112  elif minorV == minorQ:
113  if revisionV > revisionQ:
114  return True
115  elif revisionV < revisionQ:
116  return False
117  elif revisionV == revisionQ:
118  return True
119  return False
120 
122  """ Set the available command line options.
123  """
124  self._commandLineParser.add_option("-f", "--file", dest="filename", help="open a FILE", metavar="FILE")
125  self._commandLineParser.add_option("-l", "--loglevel", dest="loglevel", help="set LOGLEVEL to 10=DEBUG, 20=INFO, 30=WARNING, 40=ERROR, 50=CRITICAL", metavar="LOGLEVEL", type="int")
126 
128  """ Initialize command line parser.
129 
130  After calling this function, plugins may add options.
131  """
132  class QuiteOptionParser(optparse.OptionParser):
133  def __init__(self):
134  optparse.OptionParser.__init__(self,add_help_option=False)
135  def error(self,message=""):
136  pass
137  self._commandLineParser = QuiteOptionParser()
138  self._setCommandLineOptions()
139  (self._commandLineOptions, self._args) = self._commandLineParser.parse_args()
140  if self._commandLineOptions.loglevel:
141  logging.root.setLevel(self._commandLineOptions.loglevel)
142  self._commandLineParser = optparse.OptionParser()
143  self._setCommandLineOptions()
144 
146  """ Analyzes the command line attributes and print usage summary if required.
147  """
148  (self._commandLineOptions, self._args) = self._commandLineParser.parse_args()
149  if self._commandLineOptions.filename:
150  self.mainWindow().setStartupScreenVisible(False)
151  self.openFile(self._commandLineOptions.filename)
152  if len(self._args) > 0:
153  self.mainWindow().setStartupScreenVisible(False)
154  self.openFile(self._args[0])
155 
156  def _checkFile(self, filename):
157  """ Check if logfile is closed correctly
158  """
159  finished = True
160  file = open(filename, "r")
161  for line in file.readlines():
162  if "INFO Start logging" in line:
163  finished = False
164  if "INFO Stop logging" in line:
165  finished = True
166  return finished
167 
168  def _initLogging(self):
169  """ Add logging handlers for a log file as well as stderr.
170  """
171  instance = 0
172  done = False
173  while not done:
174  # iterate name of log file for several instances of vispa
175  instance += 1
176  logfile = os.path.join(logDirectory, "log" + str(instance) + ".txt")
177  # do not create more than 10 files
178  if instance > 10:
179  instance = 1
180  logfile = os.path.join(logDirectory, "log" + str(instance) + ".txt")
181  done = True
182  break
183  if not os.path.exists(logfile):
184  done = True
185  break
186  done = self._checkFile(logfile)
187 
188  # clean up old logs
189  nextlogfile = os.path.join(logDirectory, "log" + str(instance + 1) + ".txt")
190  if os.path.exists(nextlogfile):
191  if not self._checkFile(nextlogfile):
192  file = open(nextlogfile, "a")
193  file.write("Cleaning up logfile after abnormal termination: INFO Stop logging\n")
194 
195  if os.path.exists(logDirectory):
196  handler1 = logging.handlers.RotatingFileHandler(logfile, maxBytes=100000, backupCount=1)
197  formatter1 = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
198  handler1.setFormatter(formatter1)
199  self._logFile = logfile
200 
201  handler2 = logging.StreamHandler(sys.stderr)
202  formatter2 = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
203  handler2.setFormatter(formatter2)
204 
205  logging.root.handlers = []
206  if os.path.exists(logDirectory):
207  logging.root.addHandler(handler1)
208  logging.root.addHandler(handler2)
209  #logging.root.setLevel(logging.INFO)
210 
211  self._infologger = logging.getLogger("info")
212  self._infologger.setLevel(logging.INFO)
213  self._infologger.handlers = []
214  if self._logFile:
215  self._infologger.info("Start logging to " + self._logFile)
216 
217  def run(self):
218  """ Show the MainWindow and run the application.
219  """
220  #logging.debug('Application: run()')
221 
222  self.exec_()
223  if self._logFile:
224  self._infologger.info("Stop logging to " + self._logFile)
225 
226  def _connectSignals(self):
227  """ Connect signal to observe the TabWidget in the MainWindow.
228  """
229  logging.debug('Application: _connectSignals()')
230  self.connect(self._window.tabWidget(), SIGNAL("currentChanged(int)"), self.tabChanged)
231  self.connect(self._window, SIGNAL("windowActivated()"), self.tabChanged)
232  self.connect(self._window.tabWidget(), SIGNAL("tabCloseRequested(int)"), self.tabCloseRequest)
233 
234  def _loadPlugins(self):
235  """ Search all subfolders of the plugin directory for vispa plugins and registers them.
236  """
237  logging.debug('Application: _loadPlugins()')
238  dirs = ["Vispa.Plugins." + str(f) for f in os.listdir(pluginDirectory)
239  if os.path.isdir(os.path.join(pluginDirectory, f)) and not f.startswith(".") and not f.startswith("CVS")]
240  failedToLoad = []
241  for di in dirs:
242  try:
243  module = __import__(di, globals(), locals(), "Vispa.Plugins")
244  self._loadablePlugins[module.plugin.__name__] = module.plugin
245  except ImportError:
246  logging.warning('Application: cannot load plugin ' + di + ': ' + exception_traceback())
247  failedToLoad.append(di)
248  except PluginIgnoredException,e:
249  logging.info('Application: plugin ' + di + ' cannot be loaded and is ignored: ' + str(e))
250  except AttributeError,e:
251  logging.info('Application: plugin ' + di + ' is deactivated (define plugin in __init__.py to activate): ' + str(e))
252 
253  for pluginName in self._loadablePlugins.keys():
254  # loop over all loadable plugins
255  # this mechanism enables plugins to call initializePlugin() for plugins they depend on
256  if not self.initializePlugin(pluginName):
257  failedToLoad.append(pluginName)
258 
259  if len(failedToLoad) > 0:
260  self.errorMessage(self.FAILED_LOADING_PLUGINS_ERROR + "\n".join(failedToLoad))
261 
263 
264  def initializePlugin(self, name):
265  if name in [plugin.__class__.__name__ for plugin in self._plugins]:
266  logging.info("%s: initalizePlugin(): Plugin '%s' already loaded. Aborting..." % (self.__class__.__name__, name))
267  return True
268  if not name in self._loadablePlugins.keys():
269  logging.error("%s: initalizePlugin(): Unknown plugin '%s'. Aborting..." % (self.__class__.__name__, name))
270  return False
271 
272  try:
273  pluginObject = self._loadablePlugins[name](self)
274  self._plugins.append(pluginObject)
275  logging.debug('Application: added plugin ' + name)
276  return True
277  except ValueError:
278  logging.warning('Application: ' + name + ' is not a plugin: ' + exception_traceback())
279  return False
280 
281 
282  def plugins(self):
283  return self._plugins
284 
285  def plugin(self, name):
286  """ Returns plugin with given name or None if there is no such one.
287  """
288  if not name.endswith("Plugin"):
289  name += "Plugin"
290 
291  for plugin in self._plugins:
292  if name == plugin.__class__.__name__:
293  return plugin
294  return None
295 
296  def tabControllers(self):
297  controllers=[self._window.tabWidget().widget(i).controller() for i in range(0, self._window.tabWidget().count())]
298  controllers+=[tab.controller() for tab in self.mainWindow().tabWidgets()]
299  return controllers
300 
301  def setCurrentTabController(self, controller):
302  if controller.tab().tabWidget():
303  self._window.activateWindow()
304  self._window.tabWidget().setCurrentIndex(self.tabControllers().index(controller))
305  else:
306  controller.tab().activateWindow()
307 
309  """ Return the TabController that belongs to the tab selected in the MainWindow.
310  """
311  #logging.debug('Application: currentTabController()')
312  if isinstance(self.activeWindow(),AbstractTab):
313  return self.activeWindow().controller()
314  else:
315  currentWidget = self._window.tabWidget().currentWidget()
316  if isinstance(currentWidget, AbstractTab):
317  return currentWidget.controller()
318  raise NoCurrentTabControllerException
319 
320  def mainWindow(self):
321  return self._window
322 
323  #def editPreferences(self):
324  # self.preferencesEditor = PreferencesEditor()
325  # self.preferencesEditor.show()
326 
327  def createAction(self, name, slot=None, shortcut=None, image=None, enabled=True):
328  """ create an action with name and icon and connect it to a slot.
329  """
330  #logging.debug('Application: createAction() - ' + name)
331  if image:
332  image0 = QPixmap()
333  image0.load(":/resources/" + image + ".svg")
334  action = QAction(QIcon(image0), name, self._window)
335  else:
336  action = QAction(name, self._window)
337  action.setEnabled(enabled)
338  if slot:
339  self.connect(action, SIGNAL("triggered()"), slot)
340  if shortcut:
341  if isinstance(shortcut, list):
342  action.setShortcuts(shortcut)
343  else:
344  action.setShortcut(shortcut)
345  return action
346 
347  def _fillFileMenu(self):
348  """Called for the first time this function creates the file menu and fill it.
349 
350  The function is written in a way that it recreates the whole menu, if it
351  is called again later during execution. So it is possible to aad new
352  plugins and use them (which means they appear in the menus) without
353  restarting the program.
354  """
355  logging.debug('Application: _fillFileMenu()')
356  self._fileMenuItems = {}
357  if not self._window.fileMenu().isEmpty():
358  self._window.fileMenu().clear()
359 
360  # New
361  newFileActions = []
362  for plugin in self._plugins:
363  newFileActions += plugin.getNewFileActions()
364 
365  if len(newFileActions) == 1:
366  newFileActions[0].setShortcut('Ctrl+N')
367 
368  self._window.fileMenu().addActions(newFileActions)
369 
370  # Open
371  openFileAction = self.createAction('&Open File', self.openFileDialog, 'Ctrl+O', "fileopen")
372  self._window.fileMenu().addAction(openFileAction)
373  self._window.fileToolBar().addAction(openFileAction)
374 
375  # Reload
376  self._fileMenuItems['reloadFileAction'] = self.createAction('&Reload File', self.reloadFile, ['Ctrl+R', 'F5'], "reload")
377  self._window.fileMenu().addAction(self._fileMenuItems['reloadFileAction'])
378  #self._window.fileToolBar().addAction(self._fileMenuItems['reloadFileAction'])
379 
380  # Recent files
381  if not hasattr(self, 'recentFilesMenu'):
382  self._recentFilesMenu = QMenu('&Recent Files', self._window)
384  for i in range(0, self.MAX_VISIBLE_RECENT_FILES):
385  action = self.createAction("recent file " + str(i), self.openRecentFileSlot)
386  action.setVisible(False)
387  self._recentFilesMenu.addAction(action)
388  self._recentFilesMenuActions.append(action)
389  self._recentFilesMenu.addSeparator()
390  self._fileMenuItems['clearMissingRecentFilesAction'] = self.createAction("Clear missing files", self.clearMissingRecentFiles)
391  self._recentFilesMenu.addAction(self._fileMenuItems['clearMissingRecentFilesAction'])
392  self._fileMenuItems['clearRecentFilesAction'] = self.createAction("Clear list", self.clearRecentFiles)
393  self._recentFilesMenu.addAction(self._fileMenuItems['clearRecentFilesAction'])
394 
395  self._window.fileMenu().addMenu(self._recentFilesMenu)
396 
397  self._window.fileMenu().addSeparator()
398 
399  # Close
400  self._fileMenuItems['closeFileAction'] = self.createAction('&Close', self.closeFile, 'Ctrl+W', "closefile")
401  self._window.fileMenu().addAction(self._fileMenuItems['closeFileAction'])
402 
403  # Close all
404  self._fileMenuItems['closeAllAction'] = self.createAction('Close All', self.closeAllFiles, 'Ctrl+Shift+W', "closefileall")
405  self._window.fileMenu().addAction(self._fileMenuItems['closeAllAction'])
406 
407  self._window.fileMenu().addSeparator()
408 
409  # Save
410  self._fileMenuItems['saveFileAction'] = self.createAction('&Save', self.saveFile, 'Ctrl+S', "filesave")
411  self._window.fileMenu().addAction(self._fileMenuItems['saveFileAction'])
412  self._window.fileToolBar().addAction(self._fileMenuItems['saveFileAction'])
413 
414  # Save as
415  self._fileMenuItems['saveFileAsAction'] = self.createAction('Save As...', self.saveFileAsDialog, 'Ctrl+Shift+S', image="filesaveas")
416  self._window.fileMenu().addAction(self._fileMenuItems['saveFileAsAction'])
417 
418  # Save all
419  self._fileMenuItems['saveAllFilesAction'] = self.createAction('Save &All', self.saveAllFiles, "Ctrl+Alt+S", "filesaveall")
420  self._window.fileMenu().addAction(self._fileMenuItems['saveAllFilesAction'])
421 
422  self._window.fileMenu().addSeparator()
423 
424  #editPreferencesAction = self.createAction('Preferences',self.editPreferences)
425  #self._window.fileMenu().addAction(editPreferencesAction)
426  # Exit
427  exit = self.createAction('&Exit', self.exit, "Ctrl+Q", "exit")
428  self._window.fileMenu().addAction(exit)
429 
430  def _fillEditMenu(self):
431  """Called for the first time this function creates the edit menu and fills it.
432 
433  The function is written in a way that it recreates the whole menu, if it
434  is called again later during execution. So it is possible to aad new
435  plugins and use them (which means they appear in the menus) without
436  restarting the program.
437  """
438  logging.debug('Application: _fillEditMenu()')
439  self._editMenuItems = {}
440  if not self._window.editMenu().isEmpty():
441  self._window.editMenu().clear()
442 
443  # Undo / Redo
444  self._editMenuItems["undoAction"] = self.createAction("Undo", self.undoEvent, "Ctrl+Z", "edit-undo")
445  self._editMenuItems["redoAction"] = self.createAction("Redo", self.redoEvent, "Ctrl+Y", "edit-redo")
446  self._editMenuItems["undoAction"].setData(QVariant(1))
447  self._editMenuItems["redoAction"].setData(QVariant(1))
448  self._editMenuItems["undoAction"].setEnabled(False)
449  self._editMenuItems["redoAction"].setEnabled(False)
450  self._window.editMenu().addAction(self._editMenuItems["undoAction"])
451  self._window.editMenu().addAction(self._editMenuItems["redoAction"])
452  #self._editMenuItems["undoAction"].menu().addAction(self.createAction("test"))
453  #self._editMenuItems["undoAction"].menu().setEnabled(False)
454  #self._editMenuItems["undoAction"].menu().setVisible(False)
455 
456  self._undoActionsMenu = QMenu(self._window)
458  for i in range(0, self.MAX_VISIBLE_UNDO_EVENTS):
459  action = self.createAction("undo " + str(i), self.undoEvent)
460  action.setVisible(False)
461  self._undoActionsMenu.addAction(action)
462  self._undoMenuActions.append(action)
463 
464  self._redoActionsMenu = QMenu(self._window)
466  for i in range(0, self.MAX_VISIBLE_UNDO_EVENTS):
467  action = self.createAction("redo " + str(i), self.redoEvent)
468  action.setVisible(False)
469  self._redoActionsMenu.addAction(action)
470  self._redoMenuActions.append(action)
471 
472  # Cut
473  self._editMenuItems['cutAction'] = self.createAction('&Cut', self.cutEvent, 'Ctrl+X', 'editcut')
474  self._window.editMenu().addAction(self._editMenuItems['cutAction'])
475  self._editMenuItems['cutAction'].setEnabled(False)
476 
477  # Copy
478  self._editMenuItems['copyAction'] = self.createAction('C&opy', self.copyEvent, 'Ctrl+C', 'editcopy')
479  self._window.editMenu().addAction(self._editMenuItems['copyAction'])
480  self._editMenuItems['copyAction'].setEnabled(False)
481 
482  # Paste
483  self._editMenuItems['pasteAction'] = self.createAction('&Paste', self.pasteEvent, 'Ctrl+V', 'editpaste')
484  self._window.editMenu().addAction(self._editMenuItems['pasteAction'])
485  self._editMenuItems['pasteAction'].setEnabled(False)
486 
487  # Select all
488  self._editMenuItems['selectAllAction'] = self.createAction("Select &all", self.selectAllEvent, "Ctrl+A", "selectall")
489  self._window.editMenu().addAction(self._editMenuItems['selectAllAction'])
490  self._editMenuItems['selectAllAction'].setVisible(False)
491 
492  self._window.editMenu().addSeparator()
493 
494  # Find
495  self._editMenuItems['findAction'] = self.createAction('&Find', self.findEvent, 'Ctrl+F', "edit-find")
496  self._window.editMenu().addAction(self._editMenuItems['findAction'])
497  self._editMenuItems['findAction'].setEnabled(False)
498 
499  def _fillHelpMenu(self):
500  logging.debug('Application: _fillHelpMenu()')
501  self._helpMenuItems = {}
502 
503  # About
504  self._helpMenuItems['aboutAction'] = self.createAction('&About', self.aboutBoxSlot, 'F1')
505  self._window.helpMenu().addAction(self._helpMenuItems['aboutAction'])
506 
507  # open log file
508  if self._logFile:
509  self._helpMenuItems['openLogFile'] = self.createAction("Open log file", self.openLogFileSlot)
510  self._window.helpMenu().addAction(self._helpMenuItems['openLogFile'])
511 
512  # Offline Documentation
513  if os.path.exists(os.path.join(docDirectory,"index.html")):
514  self._window.helpMenu().addAction(self.createAction('Offline Documentation', self._openDocumentation, "CTRL+F1"))
515 
516  # Vispa Website
517  self._window.helpMenu().addAction(self.createAction('Website', self._openWebsite, "Shift+F1"))
518 
519  def updateMenu(self):
520  """ Update recent files and enable disable menu entries in file and edit menu.
521  """
522  #logging.debug('Application: updateMenu()')
523  if self.mainWindow().startupScreen():
524  self.updateStartupScreen()
525  # Recent files
526  num_recent_files = min(len(self._recentFiles), self.MAX_VISIBLE_RECENT_FILES)
527  for i in range(0, num_recent_files):
528  filename = self._recentFiles[i]
529  self._recentFilesMenuActions[i].setText(os.path.basename(filename))
530  self._recentFilesMenuActions[i].setToolTip(filename)
531  self._recentFilesMenuActions[i].setStatusTip(filename)
532  self._recentFilesMenuActions[i].setData(QVariant(filename))
533  self._recentFilesMenuActions[i].setVisible(True)
534 
535  for i in range(num_recent_files, self.MAX_VISIBLE_RECENT_FILES):
536  self._recentFilesMenuActions[i].setVisible(False)
537 
538  if num_recent_files == 0:
539  self._fileMenuItems['clearRecentFilesAction'].setEnabled(False)
540  self._fileMenuItems['clearMissingRecentFilesAction'].setEnabled(False)
541  else:
542  self._fileMenuItems['clearRecentFilesAction'].setEnabled(True)
543  self._fileMenuItems['clearMissingRecentFilesAction'].setEnabled(True)
544 
545  # Enabled / disable menu entries depending on number of open files
546  at_least_one_flag = False
547  at_least_two_flag = False
548  if len(self.tabControllers()) > 1:
549  at_least_one_flag = True
550  at_least_two_flag = True
551  elif len(self.tabControllers()) > 0:
552  at_least_one_flag = True
553 
554  self._fileMenuItems['saveFileAction'].setEnabled(at_least_one_flag)
555  self._fileMenuItems['saveFileAsAction'].setEnabled(at_least_one_flag)
556  self._fileMenuItems['reloadFileAction'].setEnabled(at_least_one_flag)
557  self._fileMenuItems['closeFileAction'].setEnabled(at_least_one_flag)
558 
559  self._fileMenuItems['saveAllFilesAction'].setEnabled(at_least_two_flag)
560  self._fileMenuItems['closeAllAction'].setEnabled(at_least_two_flag)
561 
562  try:
563  if at_least_one_flag:
564  if not self.currentTabController().isEditable():
565  self._fileMenuItems['saveFileAction'].setEnabled(False)
566  self._fileMenuItems['saveFileAsAction'].setEnabled(False)
567  if not self.currentTabController().isModified():
568  self._fileMenuItems['saveFileAction'].setEnabled(False)
569 
570  # Copy / Cut / Paste
571  copy_paste_enabled_flag = at_least_one_flag and self.currentTabController().isCopyPasteEnabled()
572  self._editMenuItems['cutAction'].setEnabled(copy_paste_enabled_flag)
573  self._editMenuItems['copyAction'].setEnabled(copy_paste_enabled_flag)
574  self._editMenuItems['pasteAction'].setEnabled(copy_paste_enabled_flag)
575 
576  self._editMenuItems['selectAllAction'].setVisible(self.currentTabController().allowSelectAll())
577 
578  self._editMenuItems['findAction'].setEnabled(at_least_one_flag and self.currentTabController().isFindEnabled())
579 
580  # Undo / Redo
581  undo_supported_flag = at_least_one_flag and self.currentTabController().supportsUndo()
582  self._editMenuItems["undoAction"].setEnabled(undo_supported_flag)
583  self._editMenuItems["undoAction"].setVisible(undo_supported_flag)
584  self._editMenuItems["redoAction"].setEnabled(undo_supported_flag)
585  self._editMenuItems["redoAction"].setVisible(undo_supported_flag)
586  self.showPluginToolBar(self._undoToolBar, undo_supported_flag)
587 
588  if undo_supported_flag:
589  undo_events = self.currentTabController().undoEvents()
590  num_undo_events = min(len(undo_events), self.MAX_VISIBLE_UNDO_EVENTS)
591  self._editMenuItems["undoAction"].setEnabled(num_undo_events > 0)
592  if num_undo_events > 1:
593  self._editMenuItems["undoAction"].setMenu(self._undoActionsMenu)
594  else:
595  self._editMenuItems["undoAction"].setMenu(None)
596  for i in range(0, num_undo_events):
597  undo_event = undo_events[num_undo_events - i - 1] # iterate backwards
598  self._undoMenuActions[i].setText(undo_event.LABEL)
599  self._undoMenuActions[i].setToolTip(undo_event.description())
600  self._undoMenuActions[i].setStatusTip(undo_event.description())
601  self._undoMenuActions[i].setData(QVariant(i+1))
602  self._undoMenuActions[i].setVisible(True)
603  for i in range(num_undo_events, self.MAX_VISIBLE_UNDO_EVENTS):
604  self._undoMenuActions[i].setVisible(False)
605 
606  redo_events = self.currentTabController().redoEvents()
607  num_redo_events = min(len(redo_events), self.MAX_VISIBLE_UNDO_EVENTS)
608  self._editMenuItems["redoAction"].setEnabled(num_redo_events > 0)
609  if num_redo_events > 1:
610  self._editMenuItems["redoAction"].setMenu(self._redoActionsMenu)
611  else:
612  self._editMenuItems["redoAction"].setMenu(None)
613  for i in range(0, num_redo_events):
614  redo_event = redo_events[num_redo_events - i - 1] # iterate backwards
615  self._redoMenuActions[i].setText(redo_event.LABEL)
616  self._redoMenuActions[i].setToolTip(redo_event.description())
617  self._redoMenuActions[i].setStatusTip(redo_event.description())
618  self._redoMenuActions[i].setData(QVariant(i+1))
619  self._redoMenuActions[i].setVisible(True)
620  for i in range(num_redo_events, self.MAX_VISIBLE_UNDO_EVENTS):
621  self._redoMenuActions[i].setVisible(False)
622 
623  except NoCurrentTabControllerException:
624  pass
625 
627  """ Opens Vispa Offline Documentation
628  """
629  webbrowser.open(os.path.join(docDirectory,"index.html"), 2, True)
630 
631  def _openWebsite(self):
632  """ Open new browser tab and opens Vispa Project Website.
633  """
634  webbrowser.open(websiteUrl, 2, True)
635 
636  def createPluginMenu(self, name):
637  """ Creates menu in main window's menu bar before help menu and adds it to _pluginMenus list.
638  """
639  menu = QMenu(name)
640  self._window.menuBar().insertMenu(self._window.helpMenu().menuAction(), menu)
641  self._pluginMenus.append(menu)
642  return menu
643 
644  def showPluginMenu(self, menuObject, show=True):
645  """ Shows given menu if it is in _pluginMenus list.
646  """
647  #logging.debug(self.__class__.__name__ +": showPluginMenu()")
648  if menuObject in self._pluginMenus:
649  # show all actions and activate their shortcuts
650  if show:
651  for action in menuObject.actions():
652  if hasattr(action,"_wasVisible") and action._wasVisible!=None:
653  action.setVisible(action._wasVisible)
654  action._wasVisible=None
655  else:
656  action.setVisible(True) # has to be after actions() loop to prevent permanant invisibility on Mac OS X
657  menuObject.menuAction().setVisible(show)
658 
659  def hidePluginMenu(self, menuObject):
660  """ Hides given menu object if it it in _pluginMenus list.
661  """
662  self.showPluginMenu(menuObject, False)
663 
664  def hidePluginMenus(self):
665  """ Hides all menus in _pluginMenus list.
666  """
667  for menuObject in self._pluginMenus:
668  # hide all actions and deactivate their shortcuts
669  menuObject.menuAction().setVisible(False)
670  for action in menuObject.actions():
671  if not hasattr(action,"_wasVisible") or action._wasVisible==None:
672  action._wasVisible=action.isVisible()
673  action.setVisible(False) # setVisible() here hides plugin menu forever on Mac OS X (10.5.7), Qt 4.5.
674 
675  def createPluginToolBar(self, name):
676  """ Creates tool bar in main window and adds it to _pluginToolBars list.
677  """
678  toolBar = self._window.addToolBar(name)
679  self._pluginToolBars.append(toolBar)
680  return toolBar
681 
682  def showPluginToolBar(self, toolBarObject, show=True):
683  """ Shows given toolbar if it is in _pluginToolBars list.
684  """
685  if toolBarObject in self._pluginToolBars:
686  toolBarObject.setVisible(show)
687 
688  def hidePluginMenu(self, toolBarObject):
689  """ Hides given toolbar object if it it in _pluginToolBars list.
690  """
691  self.showPluginToolBar(toolBarObject, False)
692  #if toolBarObject in self._pluginToolBars:
693  # toolBarObject.menuAction().setVisible(False)
694 
696  """ Hides all toolbars in _toolBarMenus list.
697  """
698  for toolBar in self._pluginToolBars:
699  toolBar.hide()
700 
701  def createZoomToolBar(self):
702  """ Creates tool bar with three buttons "user", "100 %" and "all".
703 
704  See TabController's documentation of zoomUser(), zoomHundred() and zoomAll() to find out more on the different zoom levels.
705  """
706  self._zoomToolBar = self.createPluginToolBar('Zoom ToolBar')
707  self._zoomToolBar.addAction(self.createAction('Revert Zoom', self.zoomUserEvent, image='zoomuser'))
708  self._zoomToolBar.addAction(self.createAction('Zoom to 100 %', self.zoomHundredEvent, image='zoom100'))
709  self._zoomToolBar.addAction(self.createAction('Zoom to all', self.zoomAllEvent, image='zoomall'))
710 
711  def showZoomToolBar(self):
712  """ Makes zoom tool bar visible.
713 
714  Should be called from TabController's selected() function, if the controller wants to use the tool bar.
715  """
717 
718  def hideZoomToolBar(self):
719  """ Makes zoom tool bar invisible.
720  """
721  self._zoomToolBar.hide()
722 
723  def createUndoToolBar(self):
724  """ Creates tool bar with buttons to invoke undo and redo events.
725 
726  Needs to be called after _fillEditMenu() as actions are defined there.
727  """
728  self._undoToolBar = self.createPluginToolBar("Undo ToolBar")
729  self._undoToolBar.addAction(self._editMenuItems["undoAction"])
730  self._undoToolBar.addAction(self._editMenuItems["redoAction"])
731 
732  def showUndoToolBar(self):
733  """ Makes undo tool bar visible.
734  """
736 
737  def hideUndoToolBar(self):
738  """ Hides undo tool bar.
739  """
740  self._undoToolBar.hide()
741 
742  def clearRecentFiles(self):
743  """ Empties list of recent files and updates main menu.
744  """
745  self._recentFiles = []
746  self._saveIni()
747  self.updateMenu()
748 
750  """ Removes entries from recent files menu if file does no longer exist.
751  """
752  newList = []
753  for file in self._recentFiles:
754  if os.path.exists(file):
755  newList.append(file)
756  self._recentFiles = newList
757  self._saveIni()
758  self.updateMenu()
759 
760  def addRecentFile(self, filename):
761  """ Adds given filename to list of recent files.
762  """
763  logging.debug('Application: addRecentFile() - ' + filename)
764  if isinstance(filename, QString):
765  filename = str(filename) # Make sure filename is a python string not a QString
766  leftCount = self.MAX_RECENT_FILES - 1
767  if filename in self._recentFiles:
768  del self._recentFiles[self._recentFiles.index(filename)]
769  self._recentFiles = [filename] + self._recentFiles[:leftCount]
770  self._saveIni()
771 
772  def recentFiles(self):
773  """ Returns list of recently opened files.
774  """
775  return self._recentFiles
776 
778  """ Returns directory name of first entry of recent files list.
779  """
780  # if current working dir is vispa directory use recentfile or home
781  if os.path.abspath(os.getcwd()) in [os.path.abspath(baseDirectory),os.path.abspath(os.path.join(baseDirectory,"bin"))] or platform.system() == "Darwin":
782  if len(self._recentFiles) > 0:
783  return os.path.dirname(self._recentFiles[0])
784  elif platform.system() == "Darwin":
785  # Mac OS X
786  return homeDirectory + "/Documents"
787  else:
788  return homeDirectory
789  # if user navigated to another directory use this
790  else:
791  return os.getcwd()
792 
793  def recentFilesFromPlugin(self,plugin):
794  files=[]
795  filetypes = plugin.filetypes()
796  extension=None
797  if len(filetypes) > 0:
798  extension=filetypes[0].extension().lower()
799  for file in self._recentFiles:
800  if os.path.splitext(os.path.basename(file))[1][1:].lower()==extension:
801  files+=[file]
802  return files
803 
805  screen=self.mainWindow().startupScreen()
806  screen.analysisDesignerRecentFilesList().clear()
807  screen.analysisDesignerRecentFilesList().addItem("...")
808  screen.analysisDesignerRecentFilesList().setCurrentRow(0)
809  plugin=self.plugin("AnalysisDesignerPlugin")
810  if plugin:
811  files = self.recentFilesFromPlugin(plugin)
812  for file in files:
813  screen.analysisDesignerRecentFilesList().addItem(os.path.basename(file))
814 
815  screen.pxlEditorRecentFilesList().clear()
816  screen.pxlEditorRecentFilesList().addItem("...")
817  screen.pxlEditorRecentFilesList().setCurrentRow(0)
818  plugin=self.plugin("PxlPlugin")
819  if plugin:
820  files = self.recentFilesFromPlugin(plugin)
821  for file in files:
822  screen.pxlEditorRecentFilesList().addItem(os.path.basename(file))
823 
824  def exit(self):
825  self._window.close()
826 
827  def shutdownPlugins(self):
828  logging.debug('Application: shutting down plugins' )
829  for plugin in self._plugins:
830  plugin.shutdown()
831 
832 
834  """ Loop over all plugins and remember their file extensions.
835  """
837  self._knownFiltersList = []
838  self._knownFiltersList.append('All files (*.*)')
839  for plugin in self.plugins():
840  for ft in plugin.filetypes():
841  self._knownExtensionsDictionary[ft.extension()] = plugin
842  self._knownFiltersList.append(ft.fileDialogFilter())
843  if len(self._knownFiltersList) > 0:
844  allKnownFilter = 'All known files (*.' + " *.".join(self._knownExtensionsDictionary.keys()) + ')'
845  self._knownFiltersList.insert(1, allKnownFilter)
846  logging.debug('Application: _collectFileExtensions() - ' + allKnownFilter)
847  else:
848  logging.debug('Application: _collectFileExtensions()')
849 
850 
851  def openFileDialog(self, defaultFileFilter=None):
852  """Displays a common open dialog for all known file types.
853  """
854  logging.debug('Application: openFileDialog()')
855 
856  if not defaultFileFilter:
857  if len(self._knownFiltersList) > 1:
858  # Set defaultFileFilter to all known files
859  defaultFileFilter = self._knownFiltersList[1]
860  else:
861  # Set dfaultFileFilter to any file type
862  defaultFileFilter = self._knownFiltersList[0]
863 
864  # Dialog
865  filename = QFileDialog.getOpenFileName(
866  self._window,
867  'Select a file',
868  self.getLastOpenLocation(),
869  ";;".join(self._knownFiltersList),
870  defaultFileFilter)
871  if not filename.isEmpty():
872  self.openFile(filename)
873 
874  def openFile(self, filename):
875  """ Decides which plugin should handle opening of the given file name.
876  """
877  logging.debug('Application: openFile()')
878  statusMessage = self.startWorking("Opening file " + filename)
879  if isinstance(filename, QString):
880  filename = str(filename) # convert QString to Python String
881 
882  # Check whether file is already opened
883  for controller in self.tabControllers():
884  if filename == controller.filename():
885  self.setCurrentTabController(controller)
886  self.stopWorking(statusMessage, "already open")
887  return
888 
889  baseName = os.path.basename(filename)
890  ext = os.path.splitext(baseName)[1].lower().strip(".")
891  errormsg = None
892 
893  if self._knownExtensionsDictionary == {}:
895 
896  foundCorrectPlugin = False
897  if os.path.exists(filename):
898  if ext in self._knownExtensionsDictionary:
899  foundCorrectPlugin = True
900  try:
901  if self._knownExtensionsDictionary[ext].openFile(filename):
902  self.addRecentFile(filename)
903  else:
904  logging.error(self.__class__.__name__ + ": openFile() - Error while opening '" + str(filename) + "'.")
905  self.errorMessage("Failed to open file.")
906  except Exception:
907  logging.error(self.__class__.__name__ + ": openFile() - Error while opening '" + str(filename) + "' : " + exception_traceback())
908  self.errorMessage("Exception while opening file. See log for details.")
909 
910  if not foundCorrectPlugin:
911  errormsg = 'Unknown file type (.' + ext + '). Aborting.'
912  else:
913  errormsg = 'File does not exist: ' + filename
914 
915  self.updateMenu()
916 
917  # Error messages
918  if not errormsg:
919  self.stopWorking(statusMessage)
920  else:
921  logging.error(errormsg)
922  self.stopWorking(statusMessage, "failed")
923  self.warningMessage(errormsg)
924 
925  def reloadFile(self):
926  """ Tells current tab controller to refresh.
927  """
928  logging.debug('Application: reloadFile()')
929  try:
930  if self.currentTabController().filename() and self.currentTabController().allowClose():
931  self.currentTabController().refresh()
932  self.currentTabController().setModified(False)
933  except NoCurrentTabControllerException:
934  pass
935  # call tabChanged instead of updateMenu to be qt 4.3 compatible
936  self.tabChanged()
937 
938  def closeFile(self):
939  """ Tells current tab controller to close.
940  """
941  logging.debug('Application: closeCurrentFile()')
942  try:
943  self.currentTabController().close()
944  except NoCurrentTabControllerException:
945  pass
946  # call tabChanged instead of updateMenu to be qt 4.3 compatible
947  self.tabChanged()
948 
949  def closeAllFiles(self):
950  """ Closes all open tabs unless user aborts closing.
951  """
952  logging.debug('Application: closeAllFiles()')
953  # to prevent unneeded updates set flag
954  self._closeAllFlag = True
955  while len(self.tabControllers())>0:
956  controller=self.tabControllers()[0]
957  if controller.close() == False:
958  break
959  self._closeAllFlag = False
960 
961  # call tabChanged instead of updateMenu to be qt 4.3 compatible
962  self.tabChanged()
963 
964  def saveFile(self):
965  """ Tells current tab controller to save its file.
966  """
967  logging.debug('Application: saveFile()')
968  try:
969  self.currentTabController().save()
970  except NoCurrentTabControllerException:
971  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
972 
973  def saveFileAsDialog(self):
974  """This functions asks the user for a file name.
975  """
976  logging.debug('Application: saveFileAsDialog()')
977  try:
978  currentTabController = self.currentTabController()
979  except NoCurrentTabControllerException:
980  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
981  return
982 
983  if currentTabController.filename():
984  startDirectory = currentTabController.filename()
985  else:
986  startDirectory = self.getLastOpenLocation()
987 
988  filetypesList = []
989  for filetype in currentTabController.supportedFileTypes():
990  filetypesList.append(Filetype(filetype[0], filetype[1]).fileDialogFilter())
991  filetypesList.append('Any (*.*)')
992 
993  selectedFilter = QString("")
994  filename = str(QFileDialog.getSaveFileName(
995  self._window,
996  'Select a file',
997  startDirectory,
998  ";;".join(filetypesList), selectedFilter))
999  if filename != "":
1000  # add extension if necessary
1001  if os.path.splitext(filename)[1].strip(".") == "" and str(selectedFilter) != 'Any (*.*)':
1002  ext = currentTabController.supportedFileTypes()[filetypesList.index(str(selectedFilter))][0]
1003  filename = os.path.splitext(filename)[0] + "." + ext
1004  return currentTabController.save(filename)
1005  return False
1006 
1007  def saveAllFiles(self):
1008  """ Tells tab controllers of all tabs to save.
1009  """
1010  logging.debug('Application: saveAllFiles()')
1011 
1012  for controller in self.tabControllers():
1013  if controller.filename() or controller == self.currentTabController():
1014  controller.save()
1015 
1016  def cutEvent(self):
1017  """ Called when cut action is triggered (e.g. from menu entry) and forwards it to current tab controller.
1018  """
1019  try:
1020  self.currentTabController().cut()
1021  except NoCurrentTabControllerException:
1022  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1023 
1024  def copyEvent(self):
1025  """ Called when copy action is triggered (e.g. from menu entry) and forwards it to current tab controller.
1026  """
1027  try:
1028  self.currentTabController().copy()
1029  except NoCurrentTabControllerException:
1030  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1031 
1032  def pasteEvent(self):
1033  """ Called when paste action is triggered (e.g. from menu entry) and forwards it to current tab controller.
1034  """
1035  try:
1036  self.currentTabController().paste()
1037  except NoCurrentTabControllerException:
1038  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1039 
1040  def selectAllEvent(self):
1041  """ Called when selectAll action is triggered (e.g. from menu entry) and forwards it to current tab controller.
1042  """
1043  try:
1044  self.currentTabController().selectAll()
1045  except NoCurrentTabControllerException:
1046  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1047 
1048  def findEvent(self):
1049  """ Called when find action is triggered (e.g. from menu entry) and forwards it to current tab controller.
1050  """
1051  try:
1052  self.currentTabController().find()
1053  except NoCurrentTabControllerException:
1054  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1055 
1056  def zoomUserEvent(self):
1057  """ Handles button pressed event from zoom tool bar and forwards it to current tab controller.
1058  """
1059  try:
1060  self.currentTabController().zoomUser()
1061  except NoCurrentTabControllerException:
1062  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1063 
1064  def zoomHundredEvent(self):
1065  """ Handles button pressed event from zoom tool bar and forwards it to current tab controller.
1066  """
1067  try:
1068  self.currentTabController().zoomHundred()
1069  except NoCurrentTabControllerException:
1070  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1071 
1072  def zoomAllEvent(self):
1073  """ Handles button pressed event from zoom tool bar and forwards it to current tab controller.
1074  """
1075  try:
1076  self.currentTabController().zoomAll()
1077  except NoCurrentTabControllerException:
1078  logging.warning(self.__class__.__name__ + ": " + self.TAB_PREMATURELY_CLOSED_WARNING)
1079 
1080  def undoEvent(self):
1081  """ Handles undo action for buttons in undo tool bar and edit menu.
1082  """
1083  try:
1084  num = 1
1085  sender = self.sender()
1086  if sender:
1087  num = sender.data().toInt()
1088  if len(num) > 1:
1089  # strange: toInt returns tuple like (1, True), QT 4.6.0, Mac OS X 10.6.4, 2010-06-28
1090  num = num[0]
1091  self.currentTabController().undo(num)
1092  except NoCurrentTabControllerException:
1093  logging.warning(self.__class__.__name__ + ": "+ self.TAB_PREMATURELY_CLOSED_WARNING)
1094 
1095  def redoEvent(self):
1096  """ Handles redo action for buttons in undo tool bar and edit menu.
1097  """
1098  try:
1099  num = 1
1100  sender = self.sender()
1101  if sender:
1102  num = sender.data().toInt()
1103  if len(num) > 1:
1104  # strange: toInt returns tuple like (1, True), QT 4.6.0, Mac OS X 10.6.4, 2010-06-28
1105  num = num[0]
1106  self.currentTabController().redo(num)
1107  except NoCurrentTabControllerException:
1108  logging.warning(self.__class__.__name__ + ": "+ self.TAB_PREMATURELY_CLOSED_WARNING)
1109 
1110  def aboutBoxSlot(self):
1111  """ Displays about box.
1112  """
1113  logging.debug('Application: aboutBoxSlot()')
1114  about = AboutDialog(self)
1115  about.onScreen()
1116 
1117  def openLogFileSlot(self):
1118  if self._logFile:
1119  self.doubleClickOnFile(self._logFile)
1120  else:
1121  logging.warning("%s: openLogFileSlot(): _logFile not set. Aborting..." % self.__class__.__name__)
1122 
1124  """ Slot for opening recent file.
1125 
1126  Called from recent file menu action. Filename is set as data object (QVariant) of action.
1127  """
1128  filename = self.sender().data().toString()
1129  logging.debug('Application: openRecentFileSlot() - ' + filename)
1130  self.openFile(filename)
1131 
1132  def tabChanged(self, tab=None):
1133  """ when a different tab is activated update menu
1134  """
1135  logging.debug('Application: tabChanged()')
1136  # only update once when closing all files at once
1137  if not self._closeAllFlag:
1138  self.hidePluginMenus()
1139  self.hidePluginToolBars()
1140  self.updateWindowTitle()
1141  self.updateMenu()
1142  try:
1143  self.currentTabController().activated()
1144  self.currentTabController().checkModificationTimestamp()
1145  except NoCurrentTabControllerException:
1146  pass
1147 
1148  self.mainWindow().setStartupScreenVisible(self.mainWindow().tabWidget().count() == 0)
1149 
1151  """ Update menu and window title.
1152  """
1153  self.updateMenu()
1154  self.updateWindowTitle()
1155 
1156  def windowTitle(self):
1157  return str(self._window.windowTitle()).split("-")[0].strip()
1158 
1160  """ update window caption
1161  """
1162  #logging.debug('Application: updateWindowTitle()')
1163  name = self.windowTitle()
1164 
1165  try:
1166  filename = self.currentTabController().filename()
1167  except NoCurrentTabControllerException:
1168  filename = None
1169 
1170  if filename:
1171  dirName = os.path.dirname(sys.argv[0])
1172  if os.path.abspath(dirName) in filename:
1173  filename = filename[len(os.path.abspath(dirName)) + 1:]
1174  name = name + " - " + filename
1175  self._window.setWindowTitle(name)
1176 
1177  def ini(self):
1178  if not self._ini:
1179  self._ini = ConfigParser.ConfigParser()
1180  self._ini.read(self._iniFileName)
1181  return self._ini
1182 
1183  def writeIni(self):
1184  try:
1185  configfile = open(self._iniFileName, "w")
1186  self._ini.write(configfile)
1187  configfile.close()
1188  except IOError:
1189  pass
1190  self._ini = None
1191 
1192  def _loadIni(self):
1193  """ Save the list of recent files.
1194  """
1195  logging.debug('Application: _loadIni()')
1196  ini = self.ini()
1197  self._recentFiles = []
1198  if ini.has_section("history"):
1199  for i in range(0, self.MAX_RECENT_FILES):
1200  if ini.has_option("history", str(i)):
1201  self._recentFiles+=[ini.get("history", str(i))]
1202 
1203  def _saveIni(self):
1204  """ Load the list of recent files.
1205  """
1206  logging.debug('Application: _saveIni()')
1207  ini = self.ini()
1208  if ini.has_section("history"):
1209  ini.remove_section("history")
1210  ini.add_section("history")
1211  for i in range(len(self._recentFiles)):
1212  ini.set("history", str(i), self._recentFiles[i])
1213 
1214  self.writeIni()
1215 
1216  def errorMessage(self, message):
1217  """ Displays error message.
1218  """
1219  QMessageBox.critical(self.mainWindow(), 'Error', message)
1220 
1221  def warningMessage(self, message):
1222  """ Displays warning message.
1223  """
1224  QMessageBox.warning(self.mainWindow(), 'Warning', message)
1225 
1226  def infoMessage(self, message):
1227  """ Displays info message.
1228  """
1229  QMessageBox.about(self.mainWindow(), 'Info', message)
1230 
1231  def showMessageBox(self, text, informativeText="", standardButtons=QMessageBox.Ok | QMessageBox.Cancel | QMessageBox.Ignore, defaultButton=QMessageBox.Ok, extraButtons=None):
1232  """ Shows a standardized message box and returns the pressed button.
1233 
1234  See documentation on Qt's QMessageBox for a list of possible standard buttons.
1235  """
1236 
1237  msgBox = QMessageBox(self.mainWindow())
1238  msgBox.setParent(self.mainWindow(), Qt.Sheet) # Qt.Sheet: Indicates that the widget is a Macintosh sheet.
1239  msgBox.setText(text)
1240  msgBox.setInformativeText(informativeText)
1241  msgBox.setStandardButtons(standardButtons)
1242  if extraButtons!=None:
1243  for button,role in extraButtons:
1244  msgBox.addButton(button,role)
1245  msgBox.setDefaultButton(defaultButton)
1246  return msgBox.exec_()
1247 
1248  def doubleClickOnFile(self, filename):
1249  """ Opens file given as argument if possible in Vispa.
1250 
1251  If Vispa cannot handle the file type the file will be opened in it's default application.
1252  """
1253  logging.debug(self.__class__.__name__ + ": doubleClickOnFile() - " + str(filename))
1254 
1255  if filename == "":
1256  return
1257 
1258  baseName = os.path.basename(filename)
1259  ext = os.path.splitext(baseName)[1].lower().strip(".")
1260  if self._knownExtensionsDictionary == {}:
1261  self._collectFileExtensions()
1262  if os.path.exists(filename):
1263  if ext in self._knownExtensionsDictionary:
1264  return self.openFile(filename)
1265 
1266  # open file in default application
1267  try:
1268  if 'Windows' in platform.system():
1269  os.startfile(filename)
1270  elif 'Darwin' in platform.system():
1271  if os.access(filename, os.X_OK):
1272  logging.warning("It seems that executing the python program is the default action on this system, which is processed when double clicking a file. Please change that to open the file witrh your favourite editor, to use this feature.")
1273  else:
1274  subprocess.call(("open", filename))
1275  elif 'Linux' in platform.system():
1276  # Linux comes with many Desktop Enviroments
1277  if os.access(filename, os.X_OK):
1278  logging.warning("It seems that executing the python program is the default action on this system, which is processed when double clicking a file. Please change that to open the file witrh your favourite editor, to use this feature.")
1279  else:
1280  try:
1281  #Freedesktop Standard
1282  subprocess.call(("xdg-open", filename))
1283  except:
1284  try:
1285  subprocess.call(("gnome-open", filename))
1286  except:
1287  logging.error(self.__class__.__name__ + ": doubleClickOnFile() - Platform '" + platform.platform() + "'. Cannot open file. I Don't know how!")
1288  except:
1289  logging.error(self.__class__.__name__ + ": doubleClickOnFile() - Platform '" + platform.platform() + "'. Error while opening file: " + str(filename))
1290 
1291  def createStatusBar(self):
1293 
1294  self._progressWidget = RotatingIcon(":/resources/vispabutton.png")
1295  self._window.statusBar().addPermanentWidget(self._progressWidget)
1296 
1297  def startWorking(self, message=""):
1298  if len(self._workingMessages.keys()) == 0:
1299  self._progressWidget.start()
1300  self._window.statusBar().showMessage(message + "...")
1301  self._messageId+=1
1302  self._workingMessages[self._messageId] = message
1303  self._progressWidget.setToolTip(message)
1304  return self._messageId
1305 
1306  def stopWorking(self, id, end="done"):
1307  if not id in self._workingMessages.keys():
1308  logging.error(self.__class__.__name__ +": stopWorking() - Unknown id %s. Aborting..." % str(id))
1309  return
1310  if len(self._workingMessages.keys()) > 1:
1311  self._window.statusBar().showMessage(self._workingMessages[self._workingMessages.keys()[0]] + "...")
1312  self._progressWidget.setToolTip(self._workingMessages[self._workingMessages.keys()[0]])
1313  else:
1314  self._progressWidget.stop()
1315  self._progressWidget.setToolTip("")
1316  self._window.statusBar().showMessage(self._workingMessages[id] + "... " + end + ".")
1317  del self._workingMessages[id]
1318 
1319  def tabCloseRequest(self, i):
1320  self.mainWindow().tabWidget().setCurrentIndex(i)
1321  self.closeFile()
1322 
1323  def showStatusMessage(self, message, timeout=0):
1324  self._window.statusBar().showMessage(message, timeout)
1325 
1326  def cancel(self):
1327  """ Cancel operations in current tab.
1328  """
1329  logging.debug(__name__ + ": cancel")
1330  try:
1331  self.currentTabController().cancel()
1332  except NoCurrentTabControllerException:
1333  pass
void strip(std::string &input, const std::string &blanks=" \n\t")
Definition: stringTools.cc:16
#define min(a, b)
Definition: mlp_lapack.h:161
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:7
void clear(CLHEP::HepGenMatrix &m)
Helper function: Reset all elements of a matrix to 0.
Definition: matutil.cc:168
std::string toString(const std::pair< T, T > &aT)
Definition: CaloEllipse.h:72
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
tuple filename
Definition: lut2db_cfg.py:20
double split
Definition: MVATrainer.cc:139