source: sasview/src/sas/qtgui/DataExplorer.py @ f721030

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 f721030 was f721030, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 8 years ago

Initial commit of the main window prototype

  • Property mode set to 100755
File size: 10.6 KB
Line 
1# global
2import sys
3import os
4import logging
5
6from PyQt4 import QtCore
7from PyQt4 import QtGui
8from PyQt4 import QtWebKit
9from twisted.internet import threads
10
11# SAS
12from GuiUtils import *
13from sas.sascalc.dataloader.loader import Loader
14from sas.sasgui.guiframe.data_manager import DataManager
15
16# UI
17#from UI.DataExplorerUI import DataExplorerUI
18from UI.TabbedFileLoadUI import DataLoadWidget
19
20class DataExplorerWindow(DataLoadWidget):
21    # The controller which is responsible for managing signal slots connections
22    # for the gui and providing an interface to the data model.
23
24    def __init__(self, parent=None, guimanager=None):
25        super(DataExplorerWindow, self).__init__(parent)
26
27        # Main model for keeping loaded data
28        self.model = QtGui.QStandardItemModel(self)
29        self._default_save_location = None
30
31        # GuiManager is the actual parent, but we needed to also pass the QMainWindow
32        # in order to set the widget parentage properly.
33        self.parent = guimanager
34        self.loader = Loader()
35        self.manager = DataManager()
36
37        # Connect the buttons
38        self.cmdLoad.clicked.connect(self.loadFile)
39        self.cmdDelete.clicked.connect(self.deleteFile)
40        self.cmdSendTo.clicked.connect(self.sendData)
41
42        # Communicator for signal definitions
43        self.communicate = self.parent.communicator()
44
45        # Proxy model for showing a subset of Data1D/Data2D content
46        self.proxy = QtGui.QSortFilterProxyModel(self)
47        self.proxy.setSourceModel(self.model)
48
49        # The Data viewer is QTreeView showing the proxy model
50        self.treeView.setModel(self.proxy)
51
52    def loadFile(self, event):
53        """
54        Called when the "Load" button pressed.
55        Opens the Qt "Open File..." dialog
56        """
57        path_str = self.chooseFiles()
58        if not path_str:
59            return
60
61        # Notify the manager of the new data available
62        self.communicate.fileReadSignal.emit(path_str)
63
64        # Read in the data from chosen file(s)
65        self.readData(path_str)
66
67        return
68
69    def deleteFile(self, event):
70        """
71        """
72        # Figure out which rows are checked
73
74        # Delete these rows from the model
75
76        # Call data_manager update with delete_data()
77
78        pass
79
80    def sendData(self, event):
81        """
82        """
83        # Figure out which rows are checked
84
85        # Dig up data from model
86        # To get the original Data1D object back use:
87        # object_item.data().toPyObject()
88
89
90        # Which perspective has been selected?
91
92        # New plot or appended?
93
94        # Notify the GuiManager about the send request
95        # updatePerspectiveWithDataSignal()
96        pass
97
98    def chooseFiles(self):
99        """
100        """
101        # List of known extensions
102        wlist = self.getWlist()
103
104        # Location is automatically saved - no need to keep track of the last dir
105        # TODO: is it really?
106        paths = QtGui.QFileDialog.getOpenFileName(self, "Choose a file", "", wlist)
107        if paths is None:
108            return
109
110        if paths.__class__.__name__ != "list":
111            paths = [paths]
112
113        path_str=[]
114        for path in paths:
115            if str(path):
116                path_str.append(str(path))
117
118        return path_str
119
120    def readData(self, path):
121        """
122        verbatim copy/paste from
123            sasgui\guiframe\local_perspectives\data_loader\data_loader.py
124        slightly modified for clarity
125        """
126        message = ""
127        log_msg = ''
128        output = {}
129        any_error = False
130        data_error = False
131        error_message = ""
132        for p_file in path:
133            info = "info"
134            basename = os.path.basename(p_file)
135            _, extension = os.path.splitext(basename)
136            if extension.lower() in EXTENSIONS:
137                any_error = True
138                log_msg = "Data Loader cannot "
139                log_msg += "load: %s\n" % str(p_file)
140                log_msg += """Please try to open that file from "open project" """
141                log_msg += """or "open analysis" menu\n"""
142                error_message = log_msg + "\n"
143                logging.info(log_msg)
144                continue
145
146            try:
147                message = "Loading Data... " + str(p_file) + "\n"
148
149                # change this to signal notification in GuiManager
150                self.communicate.statusBarUpdateSignal.emit(message)
151
152                # threaded file load
153                # load_thread = threads.deferToThread(self.loadThread, p_file)
154                # Add deferred callback for call return
155                # load_thread.addCallback(self.plotResult)
156
157                output_objects = self.loader.load(p_file)
158
159                # Some loaders return a list and some just a single Data1D object.
160                # Standardize.
161                if not isinstance(output_objects, list):
162                    output_objects = [output_objects]
163
164                for item in output_objects:
165                    # cast sascalc.dataloader.data_info.Data1D into sasgui.guiframe.dataFitting.Data1D
166                    # TODO : Fix it
167                    new_data = self.manager.create_gui_data(item, p_file)
168                    output[new_data.id] = new_data
169                    self.updateModel(new_data, p_file)
170
171                    if hasattr(item, 'errors'):
172                        for error_data in item.errors:
173                            data_error = True
174                            message += "\tError: {0}\n".format(error_data)
175                    else:
176                        logging.error("Loader returned an invalid object:\n %s" % str(item))
177                        data_error = True
178
179            except:
180                logging.error(sys.exc_value)
181                any_error = True
182            if any_error or error_message != "":
183                if error_message == "":
184                    error = "Error: " + str(sys.exc_info()[1]) + "\n"
185                    error += "while loading Data: \n%s\n" % str(basename)
186                    error_message += "The data file you selected could not be loaded.\n"
187                    error_message += "Make sure the content of your file"
188                    error_message += " is properly formatted.\n\n"
189                    error_message += "When contacting the SasView team, mention the"
190                    error_message += " following:\n%s" % str(error)
191                elif data_error:
192                    base_message = "Errors occurred while loading "
193                    base_message += "{0}\n".format(basename)
194                    base_message += "The data file loaded but with errors.\n"
195                    error_message = base_message + error_message
196                else:
197                    error_message += "%s\n" % str(p_file)
198                info = "error"
199       
200        if any_error or error_message:
201            # self.loadUpdate(output=output, message=error_message, info=info)
202            self.communicate.statusBarUpdateSignal.emit(error_message)
203
204        else:
205            message = "Loading Data Complete! "
206        message += log_msg
207        self.loadComplete(output=output, message=message)
208
209    def getWlist(self):
210        """
211        """
212        # Display the Qt Load File module
213        cards = self.loader.get_wildcards()
214
215        # get rid of the wx remnant in wildcards
216        # TODO: modify sasview loader get_wildcards method, after merge,
217        # so this kludge can be avoided
218        new_cards = []
219        for item in cards:
220            new_cards.append(item[:item.find("|")])
221        wlist = ';;'.join(new_cards)
222
223        return wlist
224           
225
226    def loadComplete(self, output, message=""):
227        """
228        Post message to status bar and update the data manager
229        """
230        # Notify the manager of the new data available
231        self.communicate.statusBarUpdateSignal.emit(message)
232        self.communicate.fileDataReceivedSignal.emit(output)
233
234        self.manager.add_data(data_list=output)
235
236    def updateModel(self, data, p_file):
237        """
238        """
239        # Structure of the model
240        # checkbox + basename
241        #     |-------> Info
242        #                 |----> Data.D object
243        #                 |----> Title:
244        #                 |----> Run:
245        #                 |----> Type:
246        #                 |----> Path:
247        #                 |----> Process
248        #                          |-----> process[0].name
249        #
250
251        # Top-level item: checkbox with label
252        checkbox_item = QtGui.QStandardItem(True)
253        checkbox_item.setCheckable(True)
254        checkbox_item.setCheckState(QtCore.Qt.Checked)
255        checkbox_item.setText(os.path.basename(p_file))
256
257        # Add "Info" item
258        info_item = QtGui.QStandardItem("Info")
259
260        # Add the actual Data1D/Data2D object
261        object_item = QtGui.QStandardItem()
262        object_item.setData(QtCore.QVariant(data))
263
264        # Add rows for display in the view
265        self.addExtraRows(info_item, data)
266
267        # Set info_item as the only child
268        checkbox_item.setChild(0, info_item)
269
270        # New row in the model
271        self.model.appendRow(checkbox_item)
272       
273        # Don't show "empty" rows with data objects
274        self.proxy.setFilterRegExp(r"[^()]")
275
276
277    def addExtraRows(self, info_item, data):
278        """
279        """
280        title_item   = QtGui.QStandardItem("Title: "      + data.title)
281        run_item     = QtGui.QStandardItem("Run: "        + str(data.run))
282        type_item    = QtGui.QStandardItem("Type: "       + str(data.__class__.__name__))
283        path_item    = QtGui.QStandardItem("Path: "       + data.path)
284        instr_item   = QtGui.QStandardItem("Instrument: " + data.instrument)
285        process_item = QtGui.QStandardItem("Process")
286        if isinstance(data.process, list) and data.process:
287            for process in data.process:
288                process_date = process.date
289                process_date_item = QtGui.QStandardItem("Date: " + process_date)
290                process_item.appendRow(process_date_item)
291
292                process_descr = process.description
293                process_descr_item = QtGui.QStandardItem("Description: " + process_descr)
294                process_item.appendRow(process_descr_item)
295
296                process_name = process.name
297                process_name_item = QtGui.QStandardItem("Name: " + process_name)
298                process_item.appendRow(process_name_item)
299
300        info_item.appendRow(title_item)
301        info_item.appendRow(run_item)
302        info_item.appendRow(type_item)
303        info_item.appendRow(path_item)
304        info_item.appendRow(instr_item)
305        info_item.appendRow(process_item)
306       
307
308if __name__ == "__main__":
309    app = QtGui.QApplication([])
310    dlg = DataExplorerWindow()
311    dlg.show()
312    sys.exit(app.exec_())
Note: See TracBrowser for help on using the repository browser.