Changeset 9e426c1 in sasview for src/sas/qtgui
- Timestamp:
- Jun 21, 2016 8:07:33 AM (9 years ago)
- Branches:
- ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
- Children:
- f82ab8c
- Parents:
- 1042dba
- Location:
- src/sas/qtgui
- Files:
-
- 1 added
- 1 deleted
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/DataExplorer.py
r1042dba r9e426c1 85 85 """ 86 86 dir = QtGui.QFileDialog.getExistingDirectory(self, "Choose a directory", "", 87 QtGui.QFileDialog.ShowDirsOnly )87 QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontUseNativeDialog) 88 88 if dir is None: 89 89 return … … 171 171 """ 172 172 Create a new matplotlib chart from selected data 173 174 TODO: Add 2D-functionality 173 175 """ 174 176 … … 192 194 # Location is automatically saved - no need to keep track of the last dir 193 195 # But only with Qt built-in dialog (non-platform native) 194 paths = QtGui.QFileDialog.getOpenFileName (self, "Choose a file", "",196 paths = QtGui.QFileDialog.getOpenFileNames(self, "Choose a file", "", 195 197 wlist, None, QtGui.QFileDialog.DontUseNativeDialog) 196 198 if paths is None: 197 199 return 198 200 201 if type(paths) == QtCore.QStringList: 202 paths = [str(f) for f in paths] 203 199 204 if paths.__class__.__name__ != "list": 200 205 paths = [paths] 201 206 202 path_str=[] 203 for path in paths: 204 if str(path): 205 path_str.append(str(path)) 206 207 return path_str 207 return paths 208 208 209 209 def readData(self, path): … … 402 402 Post message to status bar and update the data manager 403 403 """ 404 # Don't show "empty" rows with data objects 405 self.proxy.setFilterRegExp(r"[^()]") 406 407 # Reset the model so the view gets updated. 404 408 self.model.reset() 405 assert (type(output), tuple)409 assert type(output)== tuple 406 410 407 411 output_data = output[0] … … 433 437 checkbox_item.setText(os.path.basename(p_file)) 434 438 435 # Add "Info" item436 # info_item = QtGui.QStandardItem("Info")437 438 439 # Add the actual Data1D/Data2D object 439 440 object_item = QtGui.QStandardItem() … … 443 444 444 445 # Add rows for display in the view 445 # self.addExtraRows(info_item, data)446 446 info_item = infoFromData(data) 447 447 … … 452 452 self.model.appendRow(checkbox_item) 453 453 454 # Don't show "empty" rows with data objects455 self.proxy.setFilterRegExp(r"[^()]")456 457 454 def updateModelFromPerspective(self, model_item): 458 455 """ -
src/sas/qtgui/GuiManager.py
r1042dba r9e426c1 1 1 import sys 2 import subprocess 3 import logging 4 import json 5 import webbrowser 2 6 3 7 from PyQt4 import QtCore … … 9 13 # General SAS imports 10 14 from sas.sasgui.guiframe.data_manager import DataManager 15 from sas.sasgui.guiframe.proxy import Connection 16 11 17 import LocalConfig 12 18 from GuiUtils import * 19 from UI.AcknowledgementsUI import Acknowledgements 13 20 14 21 # Perspectives … … 21 28 Main SasView window functionality 22 29 """ 30 HELP_DIRECTORY_LOCATION="html" 31 23 32 def __init__(self, mainWindow=None, reactor=None, parent=None): 24 33 """ … … 56 65 self.dockedFilesWidget.setWidget(self.filesWidget) 57 66 self._workspace.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockedFilesWidget) 67 68 self.ackWidget = Acknowledgements() 69 58 70 # Disable the close button (?) 71 59 72 # Show the Welcome panel 60 73 self.welcomePanel = WelcomePanel() … … 63 76 # Current help file 64 77 self._helpView = QtWebKit.QWebView() 65 self._helpLocation = "html/index.html" 78 # Needs URL like path, so no path.join() here 79 self._helpLocation = self.HELP_DIRECTORY_LOCATION + "/index.html" 80 81 # Current tutorial location 82 self._tutorialLocation = os.path.join(self.HELP_DIRECTORY_LOCATION, 83 "_downloads", 84 "Tutorial.pdf") 66 85 67 86 #========================================================== … … 77 96 """ 78 97 """ 79 print("FILE %s "%data)80 98 pass 81 99 … … 161 179 logging.info(msg) 162 180 181 def quitApplication(self): 182 """ 183 Close the reactor and exit nicely. 184 """ 185 # Display confirmation messagebox 186 quit_msg = "Are you sure you want to exit the application?" 187 reply = QtGui.QMessageBox.question( 188 self._parent, 189 'Warning', 190 quit_msg, 191 QtGui.QMessageBox.Yes, 192 QtGui.QMessageBox.No) 193 194 if reply == QtGui.QMessageBox.No: 195 return 196 197 # Exit if yes 198 reactor.callFromThread(reactor.stop) 199 reactor.stop 200 sys.exit() 201 202 def checkUpdate(self): 203 """ 204 Check with the deployment server whether a new version 205 of the application is available. 206 A thread is started for the connecting with the server. The thread calls 207 a call-back method when the current version number has been obtained. 208 """ 209 version_info = {"version": "0.0.0"} 210 c = Connection(LocalConfig.__update_URL__, LocalConfig.UPDATE_TIMEOUT) 211 response = c.connect() 212 if response is not None: 213 try: 214 content = response.read().strip() 215 logging.info("Connected to www.sasview.org. Latest version: %s" 216 % (content)) 217 version_info = json.loads(content) 218 except: 219 logging.info("Failed to connect to www.sasview.org") 220 self.processVersion(version_info) 221 222 def processVersion(self, version_info, standalone=False): 223 """ 224 Call-back method for the process of checking for updates. 225 This methods is called by a VersionThread object once the current 226 version number has been obtained. If the check is being done in the 227 background, the user will not be notified unless there's an update. 228 229 :param version: version string 230 :param standalone: True of the update is being checked in 231 the background, False otherwise. 232 233 """ 234 try: 235 version = version_info["version"] 236 if version == "0.0.0": 237 msg = "Could not connect to the application server." 238 msg += " Please try again later." 239 #self.SetStatusText(msg) 240 self.communicate.statusBarUpdateSignal.emit(msg) 241 242 elif cmp(version, LocalConfig.__version__) > 0: 243 msg = "Version %s is available! " % str(version) 244 if not standalone: 245 if "download_url" in version_info: 246 webbrowser.open(version_info["download_url"]) 247 else: 248 webbrowser.open(LocalConfig.__download_page__) 249 else: 250 msg += "See the help menu to download it." 251 self.communicate.statusBarUpdateSignal.emit(msg) 252 else: 253 msg = "You have the latest version" 254 msg += " of %s" % str(LocalConfig.__appname__) 255 self.communicate.statusBarUpdateSignal.emit(msg) 256 except: 257 msg = "guiframe: could not get latest application" 258 msg += " version number\n %s" % sys.exc_value 259 logging.error(msg) 260 if not standalone: 261 msg = "Could not connect to the application server." 262 msg += " Please try again later." 263 self.communicate.statusBarUpdateSignal.emit(msg) 264 163 265 def addCallbacks(self): 164 266 """ 267 Method defining all signal connections for the gui manager 165 268 """ 166 269 self.communicate = Communicate() … … 234 337 def actionLoadData(self): 235 338 """ 236 Load file from Data Explorer339 Menu File/Load Data File(s) 237 340 """ 238 341 self.filesWidget.loadFile() … … 240 343 def actionLoad_Data_Folder(self): 241 344 """ 345 Menu File/Load Data Folder 242 346 """ 243 347 self.filesWidget.loadFolder() … … 272 376 Close the reactor, exit the application. 273 377 """ 274 # display messagebox 275 quit_msg = "Are you sure you want to exit the application?" 276 reply = QtGui.QMessageBox.question(self._parent, 'Warning', quit_msg, 277 QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) 278 279 if reply == QtGui.QMessageBox.No: 280 return 281 282 # exit if yes 283 reactor.callFromThread(reactor.stop) 284 sys.exit() 378 self.quitApplication() 285 379 286 380 #============ EDIT ================= … … 509 603 def actionDocumentation(self): 510 604 """ 605 Display the documentation 606 607 TODO: use QNetworkAccessManager to assure _helpLocation is valid 511 608 """ 512 609 self._helpView.load(QtCore.QUrl(self._helpLocation)) … … 515 612 def actionTutorial(self): 516 613 """ 517 """ 518 print("actionTutorial TRIGGERED") 519 pass 614 Open the tutorial PDF file with default PDF renderer 615 """ 616 # Not terribly safe here. Shell injection warning. 617 # isfile() helps but this probably needs a better solution. 618 if os.path.isfile(self._tutorialLocation): 619 result = subprocess.Popen([self._tutorialLocation], shell=True) 520 620 521 621 def actionAcknowledge(self): 522 622 """ 523 """524 print("actionAcknowledge TRIGGERED")525 pass623 Open the Acknowledgements widget 624 """ 625 self.ackWidget.show() 526 626 527 627 def actionAbout(self): 528 628 """ 529 """ 629 Open the About box 630 """ 631 530 632 print("actionAbout TRIGGERED") 531 633 pass … … 533 635 def actionCheck_for_update(self): 534 636 """ 535 """ 536 print("actionCheck_for_update TRIGGERED") 537 pass 538 637 Menu Help/Check for Update 638 """ 639 self.checkUpdate() 640 641 pass 642 -
src/sas/qtgui/MainWindow.py
rf721030 r9e426c1 21 21 # Create the gui manager 22 22 from GuiManager import GuiManager 23 guiManager = GuiManager(self, reactor, self)23 self.guiManager = GuiManager(self, reactor, self) 24 24 25 def closeEvent(self, event): 26 from twisted.internet import reactor 27 reactor.stop 28 event.accept() 29 sys.exit() 25 30 26 31 def SplashScreen(): … … 60 65 reactor.run() 61 66 62 # TODO : in the VS debugger, the Qt loop doesn't seem to end - investigate -
src/sas/qtgui/UnitTesting/DataExplorerTest.py
r1042dba r9e426c1 72 72 loadButton = self.form.cmdLoad 73 73 74 # Mock the system file open method 75 QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=None) 74 filename = "cyl_400_20.txt" 75 # Initialize signal spy instances 76 spy_file_read = QtSignalSpy(self.form, self.form.communicate.fileReadSignal) 77 78 # Return no files. 79 QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=None) 76 80 77 81 # Click on the Load button … … 79 83 80 84 # Test the getOpenFileName() dialog called once 81 self.assertTrue(QtGui.QFileDialog.getOpenFileName.called) 82 QtGui.QFileDialog.getOpenFileName.assert_called_once() 85 self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called) 86 QtGui.QFileDialog.getOpenFileNames.assert_called_once() 87 88 # Make sure the signal has not been emitted 89 self.assertEqual(spy_file_read.count(), 0) 90 91 # Now, return a single file 92 QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=filename) 93 94 # Click on the Load button 95 QTest.mouseClick(loadButton, Qt.LeftButton) 96 97 # Test the getOpenFileName() dialog called once 98 self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called) 99 QtGui.QFileDialog.getOpenFileNames.assert_called_once() 100 101 # Expected one spy instance 102 self.assertEqual(spy_file_read.count(), 1) 103 self.assertIn(filename, str(spy_file_read.called()[0]['args'][0])) 83 104 84 105 def testDeleteButton(self): … … 131 152 QTest.mouseClick(deleteButton, Qt.LeftButton) 132 153 133 134 154 def testSendToButton(self): 135 155 """ … … 166 186 # Assure the message box popped up 167 187 QtGui.QMessageBox.assert_called_once() 168 169 188 170 189 def testDataSelection(self): … … 272 291 Test the callback method updating the data object 273 292 """ 274 275 293 message="Loading Data Complete" 276 294 data_dict = {"a1":Data1D()} -
src/sas/qtgui/UnitTesting/GuiManagerTest.py
r5032ea68 r9e426c1 1 1 import sys 2 import subprocess 2 3 import unittest 4 import webbrowser 5 import logging 3 6 4 7 from PyQt4.QtGui import * 5 8 from PyQt4.QtTest import QTest 6 9 from PyQt4.QtCore import * 10 from PyQt4.QtWebKit import * 7 11 from mock import MagicMock 8 12 … … 10 14 from GuiManager import GuiManager 11 15 from UI.MainWindowUI import MainWindow 16 from UnitTesting.TestUtils import QtSignalSpy 12 17 13 18 app = QApplication(sys.argv) … … 56 61 pass 57 62 63 def testQuitApplication(self): 64 """ 65 Test that the custom exit method is called on shutdown 66 """ 67 # Must mask sys.exit, otherwise the whole testing process stops. 68 sys.exit = MagicMock() 69 70 # Say No to the close dialog 71 QMessageBox.question = MagicMock(return_value=QMessageBox.No) 72 73 # Open, then close the manager 74 self.manager.quitApplication() 75 76 # See that the MessageBox method got called 77 self.assertTrue(QMessageBox.question.called) 78 # sys.exit() not called this time 79 self.assertFalse(sys.exit.called) 80 81 # Say Yes to the close dialog 82 QMessageBox.question = MagicMock(return_value=QMessageBox.Yes) 83 84 # Open, then close the manager 85 self.manager.quitApplication() 86 87 # See that the MessageBox method got called 88 self.assertTrue(QMessageBox.question.called) 89 # Also, sys.exit() called 90 self.assertTrue(sys.exit.called) 91 92 def testCheckUpdate(self): 93 """ 94 Tests the SasView website version polling 95 """ 96 self.manager.processVersion = MagicMock() 97 version = {'update_url' : 'http://www.sasview.org/sasview.latestversion', 98 'version' : '3.1.2', 99 'download_url': 'https://github.com/SasView/sasview/releases'} 100 self.manager.checkUpdate() 101 102 self.manager.processVersion.assert_called_with(version) 103 104 pass 105 106 def testProcessVersion(self): 107 """ 108 Tests the version checker logic 109 """ 110 # 1. version = 0.0.0 111 version_info = {u'version' : u'0.0.0'} 112 spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal) 113 114 self.manager.processVersion(version_info) 115 116 self.assertEqual(spy_status_update.count(), 1) 117 message = 'Could not connect to the application server. Please try again later.' 118 self.assertIn(message, str(spy_status_update.signal(index=0))) 119 120 # 2. version < LocalConfig.__version__ 121 version_info = {u'version' : u'0.0.1'} 122 spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal) 123 124 self.manager.processVersion(version_info) 125 126 self.assertEqual(spy_status_update.count(), 1) 127 message = 'You have the latest version of SasView' 128 self.assertIn(message, str(spy_status_update.signal(index=0))) 129 130 # 3. version > LocalConfig.__version__ 131 version_info = {u'version' : u'999.0.0'} 132 spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal) 133 webbrowser.open = MagicMock() 134 135 self.manager.processVersion(version_info) 136 137 self.assertEqual(spy_status_update.count(), 1) 138 message = 'Version 999.0.0 is available!' 139 self.assertIn(message, str(spy_status_update.signal(index=0))) 140 141 webbrowser.open.assert_called_with("https://github.com/SasView/sasview/releases") 142 143 # 4. version > LocalConfig.__version__ and standalone 144 version_info = {u'version' : u'999.0.0'} 145 spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal) 146 webbrowser.open = MagicMock() 147 148 self.manager.processVersion(version_info, standalone=True) 149 150 self.assertEqual(spy_status_update.count(), 1) 151 message = 'See the help menu to download it' 152 self.assertIn(message, str(spy_status_update.signal(index=0))) 153 154 self.assertFalse(webbrowser.open.called) 155 156 # 5. couldn't load version 157 version_info = {} 158 logging.error = MagicMock() 159 spy_status_update = QtSignalSpy(self.manager, self.manager.communicate.statusBarUpdateSignal) 160 161 self.manager.processVersion(version_info) 162 163 # Retrieve and compare arguments of the mocked call 164 message = "guiframe: could not get latest application version number" 165 args, _ = logging.error.call_args 166 self.assertIn(message, args[0]) 167 168 # Check the signal message 169 message = 'Could not connect to the application server.' 170 self.assertIn(message, str(spy_status_update.signal(index=0))) 171 58 172 def testActions(self): 59 173 """ … … 66 180 """ 67 181 # Mock the system file open method 68 QFileDialog.getOpenFileName = MagicMock(return_value=None)182 QFileDialog.getOpenFileNames = MagicMock(return_value=None) 69 183 70 184 # invoke the action 185 self.manager.actionLoadData() 71 186 72 187 # Test the getOpenFileName() dialog called once 73 #self.assertTrue(QtGui.QFileDialog.getOpenFileName.called) 74 #QtGui.QFileDialog.getOpenFileName.assert_called_once() 188 self.assertTrue(QFileDialog.getOpenFileNames.called) 75 189 76 77 # test each action separately 190 def testActionDocumentation(self): 191 """ 192 Menu Help/Documentation 193 """ 194 #Mock the QWebView method 195 QWebView.show = MagicMock() 196 197 # Assure the filename is correct 198 self.assertIn("index.html", self.manager._helpLocation) 199 200 # Invoke the action 201 self.manager.actionDocumentation() 202 203 # Check if show() got called 204 self.assertTrue(QWebView.show.called) 205 206 def testActionTutorial(self): 207 """ 208 Menu Help/Tutorial 209 """ 210 # Mock subprocess.Popen 211 subprocess.Popen = MagicMock() 212 213 tested_location = self.manager._tutorialLocation 214 215 # Assure the filename is correct 216 self.assertIn("Tutorial.pdf", tested_location) 217 218 # Invoke the action 219 self.manager.actionTutorial() 220 221 # Check if popen() got called 222 self.assertTrue(subprocess.Popen.called) 223 224 #Check the popen() call arguments 225 subprocess.Popen.assert_called_with([tested_location], shell=True) 226 227 def testActionAcknowledge(self): 228 """ 229 Menu Help/Acknowledge 230 """ 231 pass 232 233 def testActionCheck_for_update(self): 234 """ 235 Menu Help/Check for update 236 """ 237 # Just make sure checkUpdate is called. 238 self.manager.checkUpdate = MagicMock() 239 240 self.manager.actionCheck_for_update() 241 242 self.assertTrue(self.manager.checkUpdate.called) 243 78 244 79 245 if __name__ == "__main__": -
src/sas/qtgui/UnitTesting/MainWindowTest.py
rf721030 r9e426c1 2 2 import unittest 3 3 4 from PyQt4 .QtGui import *5 from PyQt4 .QtTest import QTest6 from PyQt4 .QtCore import *4 from PyQt4 import QtGui 5 from PyQt4 import QtTest 6 from PyQt4 import QtCore 7 7 from mock import MagicMock 8 8 … … 11 11 from MainWindow import SplashScreen 12 12 13 app = Q Application(sys.argv)13 app = QtGui.QApplication(sys.argv) 14 14 15 15 class MainWindowTest(unittest.TestCase): 16 '''Test the Main Window GUI'''16 """Test the Main Window GUI""" 17 17 def setUp(self): 18 '''Create the GUI'''18 """Create the GUI""" 19 19 20 20 self.widget = MainSasViewWindow(None) 21 21 22 22 def tearDown(self): 23 '''Destroy the GUI''' 24 self.widget.close() 23 """Destroy the GUI""" 25 24 self.widget = None 26 25 27 26 def testDefaults(self): 28 '''Test the GUI in its default state'''29 self.assertIsInstance(self.widget, Q MainWindow)30 self.assertIsInstance(self.widget.centralWidget(), Q Workspace)27 """Test the GUI in its default state""" 28 self.assertIsInstance(self.widget, QtGui.QMainWindow) 29 self.assertIsInstance(self.widget.centralWidget(), QtGui.QWorkspace) 31 30 32 31 def testSplashScreen(self): 32 """ Test the splash screen """ 33 splash = SplashScreen() 34 self.assertIsInstance(splash, QtGui.QSplashScreen) 35 36 def testExit(self): 33 37 """ 38 Test that the custom exit method is called on shutdown 34 39 """ 35 splash = SplashScreen() 36 self.assertIsInstance(splash, QSplashScreen) 40 # Must mask sys.exit, otherwise the whole testing process stops. 41 sys.exit = MagicMock() 42 QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes) 43 44 # Open, then close the main window 45 tmp_main = MainSasViewWindow(None) 46 tmp_main.close() 47 48 # See that the MessageBox method got called 49 self.assertTrue(QtGui.QMessageBox.question.called) 37 50 38 51 if __name__ == "__main__":
Note: See TracChangeset
for help on using the changeset viewer.