CMS 3D CMS Logo

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