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

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

Initial changes to make SasView? run with python3

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