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

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 6280464 was 6280464, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

More Qt5 related fixes.

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