source: sasview/src/sas/qtgui/MainWindow/GuiManager.py @ 2d0e0c1

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 2d0e0c1 was 2d0e0c1, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Initial version of the Fitting Options dialog SASVIEW-276

  • Property mode set to 100644
File size: 24.7 KB
Line 
1import sys
2import os
3import subprocess
4import logging
5import json
6import webbrowser
7
8from PyQt4 import QtCore
9from PyQt4 import QtGui
10from PyQt4 import QtWebKit
11
12from twisted.internet import reactor
13
14# General SAS imports
15from sas.qtgui.Utilities.ConnectionProxy import ConnectionProxy
16from sas.qtgui.Utilities.SasviewLogger import XStream
17from sas.qtgui.Utilities.IPythonWidget import IPythonWidget
18import sas.qtgui.Utilities.LocalConfig as LocalConfig
19import sas.qtgui.Utilities.GuiUtils as GuiUtils
20import sas.qtgui.Utilities.ObjectLibrary as ObjectLibrary
21
22from sas.qtgui.MainWindow.UI.AcknowledgementsUI import Ui_Acknowledgements
23from sas.qtgui.MainWindow.AboutBox import AboutBox
24from sas.qtgui.MainWindow.WelcomePanel import WelcomePanel
25from sas.qtgui.MainWindow.DataManager import DataManager
26
27from sas.qtgui.Calculators.SldPanel import SldPanel
28from sas.qtgui.Calculators.DensityPanel import DensityPanel
29from sas.qtgui.Calculators.KiessigPanel import KiessigPanel
30from sas.qtgui.Calculators.SlitSizeCalculator import SlitSizeCalculator
31from sas.qtgui.Calculators.GenericScatteringCalculator import GenericScatteringCalculator
32
33# Perspectives
34import sas.qtgui.Perspectives as Perspectives
35from sas.qtgui.Perspectives.Fitting.FittingPerspective import FittingWindow
36from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
37
38class Acknowledgements(QtGui.QDialog, Ui_Acknowledgements):
39    def __init__(self, parent=None):
40        QtGui.QDialog.__init__(self, parent)
41        self.setupUi(self)
42
43class GuiManager(object):
44    """
45    Main SasView window functionality
46    """
47    ## TODO: CHANGE FOR SHIPPED PATH IN RELEASE
48    HELP_DIRECTORY_LOCATION = "docs/sphinx-docs/build/html"
49
50    def __init__(self, parent=None):
51        """
52        Initialize the manager as a child of MainWindow.
53        """
54        self._workspace = parent
55        self._parent = parent
56
57        # Add signal callbacks
58        self.addCallbacks()
59
60        # Create the data manager
61        # TODO: pull out all required methods from DataManager and reimplement
62        self._data_manager = DataManager()
63
64        # Create action triggers
65        self.addTriggers()
66
67        # Populate menus with dynamic data
68        #
69        # Analysis/Perspectives - potentially
70        # Window/current windows
71        #
72        # Widgets
73        #
74        # Current displayed perspective
75        self._current_perspective = None
76
77        # Invoke the initial perspective
78        self.perspectiveChanged("Fitting")
79
80        self.addWidgets()
81
82        # Fork off logging messages to the Log Window
83        XStream.stdout().messageWritten.connect(self.listWidget.insertPlainText)
84        XStream.stderr().messageWritten.connect(self.listWidget.insertPlainText)
85
86        # Log the start of the session
87        logging.info(" --- SasView session started ---")
88        # Log the python version
89        logging.info("Python: %s" % sys.version)
90
91        # Set up the status bar
92        self.statusBarSetup()
93
94        # Show the Welcome panel
95        self.welcomePanel = WelcomePanel()
96        self._workspace.workspace.addWindow(self.welcomePanel)
97
98        # Current help file
99        self._helpView = QtWebKit.QWebView()
100        # Needs URL like path, so no path.join() here
101        self._helpLocation = self.HELP_DIRECTORY_LOCATION + "/index.html"
102
103        # Current tutorial location
104        self._tutorialLocation = os.path.abspath(os.path.join(self.HELP_DIRECTORY_LOCATION,
105                                              "_downloads",
106                                              "Tutorial.pdf"))
107    def addWidgets(self):
108        """
109        Populate the main window with widgets
110
111        TODO: overwrite close() on Log and DR widgets so they can be hidden/shown
112        on request
113        """
114        # Add FileDialog widget as docked
115        self.filesWidget = DataExplorerWindow(self._parent, self, manager=self._data_manager)
116        ObjectLibrary.addObject('DataExplorer', self.filesWidget)
117
118        self.dockedFilesWidget = QtGui.QDockWidget("Data Explorer", self._workspace)
119        self.dockedFilesWidget.setWidget(self.filesWidget)
120
121        # Disable maximize/minimize and close buttons
122        self.dockedFilesWidget.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
123        self._workspace.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
124                                      self.dockedFilesWidget)
125
126        # Add the console window as another docked widget
127        self.logDockWidget = QtGui.QDockWidget("Log Explorer", self._workspace)
128        self.logDockWidget.setObjectName("LogDockWidget")
129        self.listWidget = QtGui.QTextBrowser()
130        self.logDockWidget.setWidget(self.listWidget)
131        self._workspace.addDockWidget(QtCore.Qt.BottomDockWidgetArea,
132                                      self.logDockWidget)
133
134        # Add other, minor widgets
135        self.ackWidget = Acknowledgements()
136        self.aboutWidget = AboutBox()
137
138        # Add calculators - floating for usability
139        self.SLDCalculator = SldPanel(self)
140        self.DVCalculator = DensityPanel(self)
141        #self.KIESSIGCalculator = DensityPanel(self)#KiessigPanel(self)
142        self.KIESSIGCalculator = KiessigPanel(self)
143        self.SlitSizeCalculator = SlitSizeCalculator(self)
144        self.GENSASCalculator = GenericScatteringCalculator(self)
145
146    def statusBarSetup(self):
147        """
148        Define the status bar.
149        | <message label> .... | Progress Bar |
150
151        Progress bar invisible until explicitly shown
152        """
153        self.progress = QtGui.QProgressBar()
154        self._workspace.statusbar.setSizeGripEnabled(False)
155
156        self.statusLabel = QtGui.QLabel()
157        self.statusLabel.setText("Welcome to SasView")
158        self._workspace.statusbar.addPermanentWidget(self.statusLabel, 1)
159        self._workspace.statusbar.addPermanentWidget(self.progress, stretch=0)
160        self.progress.setRange(0, 100)
161        self.progress.setValue(0)
162        self.progress.setTextVisible(True)
163        self.progress.setVisible(False)
164
165    def fileWasRead(self, data):
166        """
167        Callback for fileDataReceivedSignal
168        """
169        pass
170
171    def workspace(self):
172        """
173        Accessor for the main window workspace
174        """
175        return self._workspace.workspace
176
177    def perspectiveChanged(self, perspective_name):
178        """
179        Respond to change of the perspective signal
180        """
181        # Close the previous perspective
182        if self._current_perspective:
183            self._current_perspective.setClosable()
184            self._current_perspective.close()
185        # Default perspective
186        self._current_perspective = Perspectives.PERSPECTIVES[str(perspective_name)](parent=self)
187
188        self._workspace.workspace.addWindow(self._current_perspective)
189        # Resize to the workspace height
190        workspace_height = self._workspace.workspace.sizeHint().height()
191        perspective_size = self._current_perspective.sizeHint()
192        if workspace_height < perspective_size.height:
193            perspective_width = perspective_size.width()
194            self._current_perspective.resize(perspective_width, workspace_height-10)
195        self._current_perspective.show()
196
197    def updatePerspective(self, data):
198        """
199        Update perspective with data sent.
200        """
201        assert isinstance(data, list)
202        if self._current_perspective is not None:
203            self._current_perspective.setData(data.values())
204        else:
205            msg = "No perspective is currently active."
206            logging.info(msg)
207
208    def communicator(self):
209        """ Accessor for the communicator """
210        return self.communicate
211
212    def perspective(self):
213        """ Accessor for the perspective """
214        return self._current_perspective
215
216    def updateProgressBar(self, value):
217        """
218        Update progress bar with the required value (0-100)
219        """
220        assert -1 <= value <= 100
221        if value == -1:
222            self.progress.setVisible(False)
223            return
224        if not self.progress.isVisible():
225            self.progress.setTextVisible(True)
226            self.progress.setVisible(True)
227
228        self.progress.setValue(value)
229
230    def updateStatusBar(self, text):
231        """
232        Set the status bar text
233        """
234        self.statusLabel.setText(text)
235
236    def createGuiData(self, item, p_file=None):
237        """
238        Access the Data1D -> plottable Data1D conversion
239        """
240        return self._data_manager.create_gui_data(item, p_file)
241
242    def setData(self, data):
243        """
244        Sends data to current perspective
245        """
246        if self._current_perspective is not None:
247            self._current_perspective.setData(data.values())
248        else:
249            msg = "Guiframe does not have a current perspective"
250            logging.info(msg)
251
252    def quitApplication(self):
253        """
254        Close the reactor and exit nicely.
255        """
256        # Display confirmation messagebox
257        quit_msg = "Are you sure you want to exit the application?"
258        reply = QtGui.QMessageBox.question(
259            self._parent,
260            'Information',
261            quit_msg,
262            QtGui.QMessageBox.Yes,
263            QtGui.QMessageBox.No)
264
265        # Exit if yes
266        if reply == QtGui.QMessageBox.Yes:
267            reactor.callFromThread(reactor.stop)
268            return True
269
270        return False
271
272    def checkUpdate(self):
273        """
274        Check with the deployment server whether a new version
275        of the application is available.
276        A thread is started for the connecting with the server. The thread calls
277        a call-back method when the current version number has been obtained.
278        """
279        version_info = {"version": "0.0.0"}
280        c = ConnectionProxy(LocalConfig.__update_URL__, LocalConfig.UPDATE_TIMEOUT)
281        response = c.connect()
282        if response is None:
283            return
284        try:
285            content = response.read().strip()
286            logging.info("Connected to www.sasview.org. Latest version: %s"
287                            % (content))
288            version_info = json.loads(content)
289            self.processVersion(version_info)
290        except ValueError, ex:
291            logging.info("Failed to connect to www.sasview.org:", ex)
292
293    def processVersion(self, version_info):
294        """
295        Call-back method for the process of checking for updates.
296        This methods is called by a VersionThread object once the current
297        version number has been obtained. If the check is being done in the
298        background, the user will not be notified unless there's an update.
299
300        :param version: version string
301        """
302        try:
303            version = version_info["version"]
304            if version == "0.0.0":
305                msg = "Could not connect to the application server."
306                msg += " Please try again later."
307                self.communicate.statusBarUpdateSignal.emit(msg)
308
309            elif cmp(version, LocalConfig.__version__) > 0:
310                msg = "Version %s is available! " % str(version)
311                if "download_url" in version_info:
312                    webbrowser.open(version_info["download_url"])
313                else:
314                    webbrowser.open(LocalConfig.__download_page__)
315                self.communicate.statusBarUpdateSignal.emit(msg)
316            else:
317                msg = "You have the latest version"
318                msg += " of %s" % str(LocalConfig.__appname__)
319                self.communicate.statusBarUpdateSignal.emit(msg)
320        except:
321            msg = "guiframe: could not get latest application"
322            msg += " version number\n  %s" % sys.exc_value
323            logging.error(msg)
324            msg = "Could not connect to the application server."
325            msg += " Please try again later."
326            self.communicate.statusBarUpdateSignal.emit(msg)
327
328    def addCallbacks(self):
329        """
330        Method defining all signal connections for the gui manager
331        """
332        self.communicate = GuiUtils.Communicate()
333        self.communicate.fileDataReceivedSignal.connect(self.fileWasRead)
334        self.communicate.statusBarUpdateSignal.connect(self.updateStatusBar)
335        self.communicate.updatePerspectiveWithDataSignal.connect(self.updatePerspective)
336        self.communicate.progressBarUpdateSignal.connect(self.updateProgressBar)
337        self.communicate.perspectiveChangedSignal.connect(self.perspectiveChanged)
338        self.communicate.updateTheoryFromPerspectiveSignal.connect(self.updateTheoryFromPerspective)
339        self.communicate.plotRequestedSignal.connect(self.showPlot)
340
341    def addTriggers(self):
342        """
343        Trigger definitions for all menu/toolbar actions.
344        """
345        # File
346        self._workspace.actionLoadData.triggered.connect(self.actionLoadData)
347        self._workspace.actionLoad_Data_Folder.triggered.connect(self.actionLoad_Data_Folder)
348        self._workspace.actionOpen_Project.triggered.connect(self.actionOpen_Project)
349        self._workspace.actionOpen_Analysis.triggered.connect(self.actionOpen_Analysis)
350        self._workspace.actionSave.triggered.connect(self.actionSave)
351        self._workspace.actionSave_Analysis.triggered.connect(self.actionSave_Analysis)
352        self._workspace.actionQuit.triggered.connect(self.actionQuit)
353        # Edit
354        self._workspace.actionUndo.triggered.connect(self.actionUndo)
355        self._workspace.actionRedo.triggered.connect(self.actionRedo)
356        self._workspace.actionCopy.triggered.connect(self.actionCopy)
357        self._workspace.actionPaste.triggered.connect(self.actionPaste)
358        self._workspace.actionReport.triggered.connect(self.actionReport)
359        self._workspace.actionReset.triggered.connect(self.actionReset)
360        self._workspace.actionExcel.triggered.connect(self.actionExcel)
361        self._workspace.actionLatex.triggered.connect(self.actionLatex)
362
363        # View
364        self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window)
365        self._workspace.actionHide_Toolbar.triggered.connect(self.actionHide_Toolbar)
366        self._workspace.actionStartup_Settings.triggered.connect(self.actionStartup_Settings)
367        self._workspace.actionCategry_Manager.triggered.connect(self.actionCategry_Manager)
368        # Tools
369        self._workspace.actionData_Operation.triggered.connect(self.actionData_Operation)
370        self._workspace.actionSLD_Calculator.triggered.connect(self.actionSLD_Calculator)
371        self._workspace.actionDensity_Volume_Calculator.triggered.connect(self.actionDensity_Volume_Calculator)
372        self._workspace.actionKeissig_Calculator.triggered.connect(self.actionKiessig_Calculator)
373        #self._workspace.actionKIESSING_Calculator.triggered.connect(self.actionKIESSING_Calculator)
374        self._workspace.actionSlit_Size_Calculator.triggered.connect(self.actionSlit_Size_Calculator)
375        self._workspace.actionSAS_Resolution_Estimator.triggered.connect(self.actionSAS_Resolution_Estimator)
376        self._workspace.actionGeneric_Scattering_Calculator.triggered.connect(self.actionGeneric_Scattering_Calculator)
377        self._workspace.actionPython_Shell_Editor.triggered.connect(self.actionPython_Shell_Editor)
378        self._workspace.actionImage_Viewer.triggered.connect(self.actionImage_Viewer)
379        # Fitting
380        self._workspace.actionNew_Fit_Page.triggered.connect(self.actionNew_Fit_Page)
381        self._workspace.actionConstrained_Fit.triggered.connect(self.actionConstrained_Fit)
382        self._workspace.actionCombine_Batch_Fit.triggered.connect(self.actionCombine_Batch_Fit)
383        self._workspace.actionFit_Options.triggered.connect(self.actionFit_Options)
384        self._workspace.actionFit_Results.triggered.connect(self.actionFit_Results)
385        self._workspace.actionChain_Fitting.triggered.connect(self.actionChain_Fitting)
386        self._workspace.actionEdit_Custom_Model.triggered.connect(self.actionEdit_Custom_Model)
387        # Window
388        self._workspace.actionCascade.triggered.connect(self.actionCascade)
389        self._workspace.actionTile.triggered.connect(self.actionTile)
390        self._workspace.actionArrange_Icons.triggered.connect(self.actionArrange_Icons)
391        self._workspace.actionNext.triggered.connect(self.actionNext)
392        self._workspace.actionPrevious.triggered.connect(self.actionPrevious)
393        # Analysis
394        self._workspace.actionFitting.triggered.connect(self.actionFitting)
395        self._workspace.actionInversion.triggered.connect(self.actionInversion)
396        self._workspace.actionInvariant.triggered.connect(self.actionInvariant)
397        # Help
398        self._workspace.actionDocumentation.triggered.connect(self.actionDocumentation)
399        self._workspace.actionTutorial.triggered.connect(self.actionTutorial)
400        self._workspace.actionAcknowledge.triggered.connect(self.actionAcknowledge)
401        self._workspace.actionAbout.triggered.connect(self.actionAbout)
402        self._workspace.actionCheck_for_update.triggered.connect(self.actionCheck_for_update)
403
404    #============ FILE =================
405    def actionLoadData(self):
406        """
407        Menu File/Load Data File(s)
408        """
409        self.filesWidget.loadFile()
410
411    def actionLoad_Data_Folder(self):
412        """
413        Menu File/Load Data Folder
414        """
415        self.filesWidget.loadFolder()
416
417    def actionOpen_Project(self):
418        """
419        Menu Open Project
420        """
421        self.filesWidget.loadProject()
422
423    def actionOpen_Analysis(self):
424        """
425        """
426        print("actionOpen_Analysis TRIGGERED")
427        pass
428
429    def actionSave(self):
430        """
431        Menu Save Project
432        """
433        self.filesWidget.saveProject()
434
435    def actionSave_Analysis(self):
436        """
437        """
438        print("actionSave_Analysis TRIGGERED")
439
440        pass
441
442    def actionQuit(self):
443        """
444        Close the reactor, exit the application.
445        """
446        self.quitApplication()
447
448    #============ EDIT =================
449    def actionUndo(self):
450        """
451        """
452        print("actionUndo TRIGGERED")
453        pass
454
455    def actionRedo(self):
456        """
457        """
458        print("actionRedo TRIGGERED")
459        pass
460
461    def actionCopy(self):
462        """
463        """
464        print("actionCopy TRIGGERED")
465        pass
466
467    def actionPaste(self):
468        """
469        """
470        print("actionPaste TRIGGERED")
471        pass
472
473    def actionReport(self):
474        """
475        """
476        print("actionReport TRIGGERED")
477        pass
478
479    def actionReset(self):
480        """
481        """
482        logging.warning(" *** actionOpen_Analysis logging *******")
483        print("actionReset print TRIGGERED")
484        sys.stderr.write("STDERR - TRIGGERED")
485        pass
486
487    def actionExcel(self):
488        """
489        """
490        print("actionExcel TRIGGERED")
491        pass
492
493    def actionLatex(self):
494        """
495        """
496        print("actionLatex TRIGGERED")
497        pass
498
499    #============ VIEW =================
500    def actionShow_Grid_Window(self):
501        """
502        """
503        print("actionShow_Grid_Window TRIGGERED")
504        pass
505
506    def actionHide_Toolbar(self):
507        """
508        Toggle toolbar vsibility
509        """
510        if self._workspace.toolBar.isVisible():
511            self._workspace.actionHide_Toolbar.setText("Show Toolbar")
512            self._workspace.toolBar.setVisible(False)
513        else:
514            self._workspace.actionHide_Toolbar.setText("Hide Toolbar")
515            self._workspace.toolBar.setVisible(True)
516        pass
517
518    def actionStartup_Settings(self):
519        """
520        """
521        print("actionStartup_Settings TRIGGERED")
522        pass
523
524    def actionCategry_Manager(self):
525        """
526        """
527        print("actionCategry_Manager TRIGGERED")
528        pass
529
530    #============ TOOLS =================
531    def actionData_Operation(self):
532        """
533        """
534        print("actionData_Operation TRIGGERED")
535        pass
536
537    def actionSLD_Calculator(self):
538        """
539        """
540        self.SLDCalculator.show()
541
542    def actionDensity_Volume_Calculator(self):
543        """
544        """
545        self.DVCalculator.show()
546
547    def actionKiessig_Calculator(self):
548        """
549        """
550        #self.DVCalculator.show()
551        self.KIESSIGCalculator.show()
552
553    def actionSlit_Size_Calculator(self):
554        """
555        """
556        self.SlitSizeCalculator.show()
557
558    def actionSAS_Resolution_Estimator(self):
559        """
560        """
561        print("actionSAS_Resolution_Estimator TRIGGERED")
562        pass
563
564    def actionGeneric_Scattering_Calculator(self):
565        """
566        """
567        self.GENSASCalculator.show()
568
569    def actionPython_Shell_Editor(self):
570        """
571        Display the Jupyter console as a docked widget.
572        """
573        terminal = IPythonWidget()
574
575        # Add the console window as another docked widget
576        self.ipDockWidget = QtGui.QDockWidget("IPython", self._workspace)
577        self.ipDockWidget.setObjectName("IPythonDockWidget")
578        self.ipDockWidget.setWidget(terminal)
579        self._workspace.addDockWidget(QtCore.Qt.RightDockWidgetArea,
580                                      self.ipDockWidget)
581
582    def actionImage_Viewer(self):
583        """
584        """
585        print("actionImage_Viewer TRIGGERED")
586        pass
587
588    #============ FITTING =================
589    def actionNew_Fit_Page(self):
590        """
591        Add a new, empty Fit page in the fitting perspective.
592        """
593        # Make sure the perspective is correct
594        per = self.perspective()
595        if not isinstance(per, FittingWindow):
596            return
597        per.addFit(None)
598
599    def actionConstrained_Fit(self):
600        """
601        """
602        print("actionConstrained_Fit TRIGGERED")
603        pass
604
605    def actionCombine_Batch_Fit(self):
606        """
607        """
608        print("actionCombine_Batch_Fit TRIGGERED")
609        pass
610
611    def actionFit_Options(self):
612        """
613        """
614        if getattr(self._current_perspective, "fit_options_widget"):
615            self._current_perspective.fit_options_widget.show()
616        pass
617
618    def actionFit_Results(self):
619        """
620        """
621        print("actionFit_Results TRIGGERED")
622        pass
623
624    def actionChain_Fitting(self):
625        """
626        """
627        print("actionChain_Fitting TRIGGERED")
628        pass
629
630    def actionEdit_Custom_Model(self):
631        """
632        """
633        print("actionEdit_Custom_Model TRIGGERED")
634        pass
635
636    #============ ANALYSIS =================
637    def actionFitting(self):
638        """
639        """
640        print("actionFitting TRIGGERED")
641        pass
642
643    def actionInversion(self):
644        """
645        """
646        print("actionInversion TRIGGERED")
647        pass
648
649    def actionInvariant(self):
650        """
651        """
652        print("actionInvariant TRIGGERED")
653        pass
654
655    #============ WINDOW =================
656    def actionCascade(self):
657        """
658        Arranges all the child windows in a cascade pattern.
659        """
660        self._workspace.workspace.cascade()
661
662    def actionTile(self):
663        """
664        Tile workspace windows
665        """
666        self._workspace.workspace.tile()
667
668    def actionArrange_Icons(self):
669        """
670        Arranges all iconified windows at the bottom of the workspace
671        """
672        self._workspace.workspace.arrangeIcons()
673
674    def actionNext(self):
675        """
676        Gives the input focus to the next window in the list of child windows.
677        """
678        self._workspace.workspace.activateNextWindow()
679
680    def actionPrevious(self):
681        """
682        Gives the input focus to the previous window in the list of child windows.
683        """
684        self._workspace.workspace.activatePreviousWindow()
685
686    #============ HELP =================
687    def actionDocumentation(self):
688        """
689        Display the documentation
690
691        TODO: use QNetworkAccessManager to assure _helpLocation is valid
692        """
693        self._helpView.load(QtCore.QUrl(self._helpLocation))
694        self._helpView.show()
695
696    def actionTutorial(self):
697        """
698        Open the tutorial PDF file with default PDF renderer
699        """
700        # Not terribly safe here. Shell injection warning.
701        # isfile() helps but this probably needs a better solution.
702        if os.path.isfile(self._tutorialLocation):
703            result = subprocess.Popen([self._tutorialLocation], shell=True)
704
705    def actionAcknowledge(self):
706        """
707        Open the Acknowledgements widget
708        """
709        self.ackWidget.show()
710
711    def actionAbout(self):
712        """
713        Open the About box
714        """
715        # Update the about box with current version and stuff
716
717        # TODO: proper sizing
718        self.aboutWidget.show()
719
720    def actionCheck_for_update(self):
721        """
722        Menu Help/Check for Update
723        """
724        self.checkUpdate()
725
726    def updateTheoryFromPerspective(self, index):
727        """
728        Catch the theory update signal from a perspective
729        Send the request to the DataExplorer for updating the theory model.
730        """
731        self.filesWidget.updateTheoryFromPerspective(index)
732
733    def showPlot(self, plot):
734        """
735        Pass the show plot request to the data explorer
736        """
737        if hasattr(self, "filesWidget"):
738            self.filesWidget.displayData(plot)
739
Note: See TracBrowser for help on using the repository browser.