source: sasview/src/sas/guiframe/data_processor.py @ 1d115ef

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 1d115ef was a12c0a6, checked in by butler, 9 years ago

some docstring edits

  • Property mode set to 100644
File size: 78.1 KB
Line 
1"""
2Implement grid used to store results of a batch fit.
3
4This is in Guiframe rather than fitting which is probably where it should be.
5Actually could be a generic framework implemented in fit gui module.  At this
6point however there this grid behaves independently of the fitting panel and
7only knows about information sent to it but not about the fits or fit panel and
8thus cannot feed back to the fitting panel.  This could change in the future.
9
10The organization of the classes goes as:
11.. image::  media/BatchGridClassLayout.png
12   :align:   center
13
14"""
15import wx
16import numpy
17import math
18import re
19import os
20import sys
21import copy
22from wx.lib.scrolledpanel import ScrolledPanel
23import wx.aui
24from wx.aui import AuiNotebook as nb
25import wx.lib.sheet as sheet
26from sas.guiframe.panel_base import PanelBase
27from sas.guiframe.events import NewPlotEvent
28from sas.guiframe.events import StatusEvent
29from sas.plottools import plottables
30from sas.guiframe.dataFitting import Data1D
31
32
33FUNC_DICT = {"sqrt": "math.sqrt",
34             "pow": "math.sqrt"}
35
36class BatchCell(object):
37    """
38    Object describing a cell in  the grid.
39
40    """
41    def __init__(self):
42        """
43        Initialize attributes of class (label, value, col, row, object)
44       
45        """
46        self.label = ""
47        self.value = None
48        self.col = -1
49        self.row = -1
50        self.object = []
51
52
53def parse_string(sentence, list):
54    """
55    Return a dictionary of column label and index or row selected
56   
57    :param sentence: String to parse
58    :param list: list of columns label
59   
60    """
61
62    p2 = re.compile(r'\d+')
63    p = re.compile(r'[\+\-\*\%\/]')
64    labels = p.split(sentence)
65    col_dict = {}
66    for elt in labels:
67        rang = None
68        temp_arr = []
69        for label in  list:
70            label_pos = elt.find(label)
71            separator_pos = label_pos + len(label)
72            if label_pos != -1 and len(elt) >= separator_pos  and\
73                elt[separator_pos] == "[":
74                # the label contain , meaning the range selected is not
75                # continuous
76                if elt.count(',') > 0:
77                    new_temp = []
78                    temp = elt.split(label)
79                    for item in temp:
80                        range_pos = item.find(":")
81                        if range_pos != -1:
82                            rang = p2.findall(item)
83                            for i in xrange(int(rang[0]), int(rang[1]) + 1):
84                                new_temp.append(i)
85                    temp_arr += new_temp
86                else:
87                    # continuous range
88                    temp = elt.split(label)
89                    for item in temp:
90                        if item.strip() != "":
91                            range_pos = item.find(":")
92                            if range_pos != -1:
93                                rang = p2.findall(item)
94                                for i in xrange(int(rang[0]), int(rang[1]) + 1):
95                                    temp_arr.append(i)
96                col_dict[elt] = (label, temp_arr)
97    return col_dict
98
99
100class SPanel(ScrolledPanel):
101    """
102    ensure proper scrolling of GridPanel
103   
104    Adds a SetupScrolling call to the normal ScrolledPanel init.   
105    GridPanel then subclasses this class
106   
107    """
108    def __init__(self, parent, *args, **kwds):
109        """
110        initialize ScrolledPanel then force a call to SetupScrolling
111
112        """
113        ScrolledPanel.__init__(self, parent, *args, **kwds)
114        self.SetupScrolling()
115
116
117class GridCellEditor(sheet.CCellEditor):
118    """
119    Custom cell editor
120   
121    This subclasses the sheet.CCellEditor (itself a subclass of
122    grid.GridCellEditor) in order to override two of its methods:
123    PaintBackrgound and EndEdit.
124   
125    This is necessary as the sheet module is broken in wx 3.0.2 and
126    improperly subclasses grid.GridCellEditor
127   
128    """
129    def __init__(self, grid):
130        """
131        Override of CCellEditor init. Runs the grid.GridCellEditor init code
132
133        """
134        super(GridCellEditor, self).__init__(grid)
135
136    def PaintBackground(self, dc, rect, attr):
137        """
138        Overrides wx.sheet.CCellEditor.PaintBackground which incorrectly calls
139        the base class method.
140       
141        In wx3.0 all paint objects must explicitly
142        have a wxPaintDC (Device Context) object.  Thus the paint event which
143        generates a call to this method provides such a DC object and the
144        base class in grid expects to receive that object.  sheet was apparently
145        not updated to reflect this and hence fails.  This could thus
146        become obsolete in a future bug fix of wxPython.
147       
148        Apart from adding a dc variable in the list of arguments in the def
149        and in the call to the base class the rest of this method is copied
150        as is from sheet.CCellEditor.PaintBackground
151       
152        :param dc: the wxDC object for the paint
153        -------
154        Draws the part of the cell not occupied by the edit control.  The
155        base class version just fills it with background colour from the
156        attribute.
157
158        NOTE: There is no need to override this if you don't need
159        to do something out of the ordinary.
160
161        """
162        # Call base class method.
163        DC = dc
164        super(sheet.CCellEditor,self).PaintBackground(DC, rect, attr)
165
166    def EndEdit(self, row, col, grid, previous):
167        """
168        Commit editing the current cell. Returns True if the value has changed.
169       
170        :param previous: previous value in the cell
171       
172        """
173        changed = False                             # Assume value not changed
174        val = self._tc.GetValue()                   # Get value in edit control
175        if val != self._startValue:                 # Compare
176            changed = True                          # If different then changed is True
177            grid.GetTable().SetValue(row, col, val) # Update the table
178        self._startValue = ''                       # Clear the class' start value
179        self._tc.SetValue('')                       # Clear contents of the edit control
180        return changed
181
182
183class GridPage(sheet.CSheet):
184    """
185    Class that receives the results of a batch fit.
186   
187    GridPage displays the received results in a wx.grid using sheet.  This is
188    then used by GridPanel and GridFrame to present the full GUI.
189   
190    """
191    def __init__(self, parent, panel=None):
192        """
193        Initialize
194       
195        Initialize all the attributes of GridPage, and the events. include
196        the init stuff from sheet.CSheet as well.
197       
198        """
199        #sheet.CSheet.__init__(self, parent)
200       
201        # The following is the __init__ from CSheet. ##########################
202        # We re-write it here because the class is broken in wx 3.0,
203        # such that the cell editor is not able to receive the right
204        # number of parameters when it is called. The only way to
205        # pick a different cell editor is apparently to re-write the __init__.
206        wx.grid.Grid.__init__(self, parent, -1)
207
208        # Init variables
209        self._lastCol = -1              # Init last cell column clicked
210        self._lastRow = -1              # Init last cell row clicked
211        self._selected = None           # Init range currently selected
212                                        # Map string datatype to default renderer/editor
213        self.RegisterDataType(wx.grid.GRID_VALUE_STRING,
214                              wx.grid.GridCellStringRenderer(),
215                              GridCellEditor(self))
216
217        self.CreateGrid(4, 3)           # By default start with a 4 x 3 grid
218        self.SetColLabelSize(18)        # Default sizes and alignment
219        self.SetRowLabelSize(50)
220        self.SetRowLabelAlignment(wx.ALIGN_RIGHT, wx.ALIGN_BOTTOM)
221        self.SetColSize(0, 75)          # Default column sizes
222        self.SetColSize(1, 75)
223        self.SetColSize(2, 75)
224
225        # Sink events
226        self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)
227        self.Bind(wx.grid.EVT_GRID_ROW_SIZE, self.OnRowSize)
228        self.Bind(wx.grid.EVT_GRID_COL_SIZE, self.OnColSize)
229        self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnGridSelectCell)
230        # NOTE: the following bind to standard sheet methods that are
231        # overriden in this subclassn - actually we have currently
232        # disabled the on_context_menu that would override the OnRightClick
233        self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnCellChange)
234        self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnLeftClick)
235        self.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnRightClick)
236        #self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.OnLeftDoubleClick)
237        # This ends the __init__ section for CSheet. ##########################
238
239
240
241        # The following events must be bound even if CSheet is working
242        # properly and does not need the above re-implementation of the
243        # CSheet init method.  Basically these override any intrinsic binding
244        self.Bind(wx.grid.EVT_GRID_LABEL_RIGHT_CLICK, self.on_right_click)
245        self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_left_click)       
246
247        self.AdjustScrollbars()
248        #self.SetLabelBackgroundColour('#DBD4D4')
249        self.uid = wx.NewId()
250        self.parent = parent
251        self.panel = panel
252        self.col_names = []
253        self.data_inputs = {}
254        self.data_outputs = {}
255        self.data = None
256        self.details = ""
257        self.file_name = None
258        self._cols = 50
259        self._rows = 3001
260        self.last_selected_row = -1
261        self.last_selected_col = -1
262        self.col_width = 30
263        self.row_height = 20
264        self.max_row_touse = 0
265        self.axis_value = []
266        self.axis_label = ""
267        self.selected_cells = []
268        self.selected_cols = []
269        self.selected_rows = []
270        self.plottable_cells = []
271        self.plottable_flag = False
272        self.SetColMinimalAcceptableWidth(self.col_width)
273        self.SetRowMinimalAcceptableHeight(self.row_height)
274        self.SetNumberRows(self._rows)
275        self.SetNumberCols(self._cols)
276        color = self.parent.GetBackgroundColour()
277        for col in range(self._cols):
278            self.SetCellBackgroundColour(0, col, color)
279        self.AutoSize()
280        self.list_plot_panels = {}
281        self.default_col_width = 75
282        self.EnableEditing(True)
283        if self.GetNumberCols() > 0:
284            self.default_col_width = self.GetColSize(0)
285        # We have moved these to the top of the init section with the
286        # rest of the grid event bindings from the sheet init when
287        # appropriate
288        #self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_left_click)
289        #self.Bind(wx.grid.EVT_GRID_LABEL_RIGHT_CLICK, self.on_right_click)
290        #self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.on_selected_cell)
291        #self.Bind(wx.grid.EVT_GRID_CMD_CELL_CHANGE, self.on_edit_cell)
292        #self.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.onContextMenu)
293
294    def OnLeftClick(self, event):
295        """
296        Overrides sheet.CSheet.OnLefClick.
297       
298        Processes when a cell is selected by left clicking on that cell. First
299        process the base Sheet method then the current class specific method
300         
301        """
302        sheet.CSheet.OnLeftClick(self, event)
303        self.on_selected_cell(event)
304       
305
306    def OnCellChange(self, event):
307        """
308        Overrides sheet.CSheet.OnCellChange. 
309       
310        Processes when a cell has been edited by a cell editor. Checks for the
311        edited row being outside the max row to use attribute and if so updates
312        the last row.  Then calls the base handler using skip.
313
314        """
315        row, _ = event.GetRow(), event.GetCol()
316        if row > self.max_row_touse:
317            self.max_row_touse = row
318        if self.data == None:
319            self.data = {}
320        event.Skip()
321
322    def on_selected_cell(self, event):
323        """
324        Handler catching cell selection.
325       
326        Called after calling base 'on left click' method.
327
328        """
329
330        flag = event.CmdDown() or event.ControlDown()
331        flag_shift = event.ShiftDown()
332        row, col = event.GetRow(), event.GetCol()
333        cell = (row, col)
334        if not flag and not flag_shift:
335            self.selected_cols = []
336            self.selected_rows = []
337            self.selected_cells = []
338            self.axis_label = ""
339            self.axis_value = []
340            self.plottable_list = []
341            self.plottable_cells = []
342            self.plottable_flag = False
343        self.last_selected_col = col
344        self.last_selected_row = row
345        if col >= 0:
346            if flag:
347                label_row = row
348            else:
349                label_row = 0
350            self.axis_label = self.GetCellValue(label_row, col)
351            self.selected_cols.append(col)
352        if flag_shift:
353            if not self.selected_rows:
354                min_r = 1
355            else:
356                min_r = min(self.selected_rows)
357            for row_s in range(min_r, row + 1):
358                cel = (row_s, col)
359                if cel not in self.selected_cells:
360                    if row > 0:
361                        self.selected_cells.append(cel)
362                        self.selected_rows.append(row)
363            for row_s in self.selected_rows:
364                cel = (row_s, col)
365                if row_s > row:
366                    try:
367                        self.selected_cells.remove(cel)
368                    except:
369                        pass
370                    try:
371                        self.selected_rows.remove(row_s)
372                    except:
373                        pass
374        elif flag:
375            if cell not in self.selected_cells:
376                if row > 0:
377                    self.selected_cells.append(cell)
378                    self.selected_rows.append(row)
379            else:
380                try:
381                    self.selected_cells.remove(cell)
382                except:
383                    pass
384                try:
385                    self.selected_rows.remove(row)
386                except:
387                    pass
388        else:
389            self.selected_cells.append(cell)
390            self.selected_rows.append(row)
391        self.axis_value = []
392        for cell_row, cell_col in self.selected_cells:
393            if cell_row > 0 and cell_row < self.max_row_touse:
394                self.axis_value.append(self.GetCellValue(cell_row, cell_col))
395        event.Skip()
396
397    def on_left_click(self, event):
398        """
399        Is triggered when the left mouse button is clicked while the mouse
400        is hovering over the column 'label.'
401       
402        This processes the information on the selected column: the column name
403        (in row 0 of column) and the range of cells with a valid value to be
404        used by the GridPanel set_axis methods.
405       
406        """
407       
408        flag = event.CmdDown() or event.ControlDown()
409
410        col = event.GetCol()
411        row = event.GetRow()
412
413        if not flag:
414            self.selected_cols = []
415            self.selected_rows = []
416            self.selected_cells = []
417            self.axis_label = ""
418            self.axis_value = []
419            self.plottable_list = []
420            self.plottable_cells = []
421            self.plottable_flag = False
422
423        self.last_selected_col = col
424        self.last_selected_row = row
425        if row != -1 and row not in self.selected_rows:
426            self.selected_rows.append(row)
427
428        if col != -1:
429            for row in range(1, self.GetNumberRows() + 1):
430                cell = (row, col)
431                if row > 0 and row < self.max_row_touse:
432                    if cell not in self.selected_cells:
433                        self.selected_cells.append(cell)
434                    else:
435                        if flag:
436                            self.selected_cells.remove(cell)
437            self.selected_cols.append(col)
438            self.axis_value = []
439            for cell_row, cell_col in self.selected_cells:
440                val = self.GetCellValue(cell_row, cell_col)
441                if not val:
442                    self.axis_value.append(self.GetCellValue(cell_row, cell_col))
443            self.axis_label = self.GetCellValue(0, col)
444            if not self.axis_label:
445                self.axis_label = " "
446        event.Skip()
447
448    def on_right_click(self, event):
449        """
450        Is triggered when the right mouse button is clicked while the mouse
451        is hovering over the column 'label.'
452       
453        This brings up a context menu that allows the deletion of the column,
454        or the insertion of a new column either to the right or left of the
455        current column.  If inserting a new column can insert a blank column or
456        choose a number of hidden columns.  By default all the error parameters
457        are in hidden columns so as to save space on the grid.  Also any other
458        intrinsic variables stored with the data such as Temperature, pressure,
459        time etc can be used to populate this menu.
460       
461        """
462       
463        col = event.GetCol()
464        row = event.GetRow()
465        # Ignore the index column
466        if col < 0 or row != -1:
467            return
468        self.selected_cols = []
469        self.selected_cols.append(col)
470        # Slicer plot popup menu
471        slicerpop = wx.Menu()
472        col_label_menu = wx.Menu()
473        c_name = self.GetCellValue(0, col)
474        label = "Insert column before %s " % str(c_name)
475        slicerpop.AppendSubMenu(col_label_menu, '&%s' % str(label), str(label))
476        row = 0
477        label = self.GetCellValue(row, col)
478        self.insert_col_menu(col_label_menu, label, self)
479
480        col_after_menu = wx.Menu()
481        label = "Insert column after %s " % str(c_name)
482        slicerpop.AppendSubMenu(col_after_menu, '&%s' % str(label), str(label))
483        self.insert_after_col_menu(col_after_menu, label, self)
484
485        wx_id = wx.NewId()
486        hint = 'Remove selected column %s'
487        slicerpop.Append(wx_id, '&Remove Column', hint)
488        wx.EVT_MENU(self, wx_id, self.on_remove_column)
489
490        pos = wx.GetMousePosition()
491        pos = self.ScreenToClient(pos)
492        self.PopupMenu(slicerpop, pos)
493        event.Skip()
494
495    def insert_col_menu(self, menu, label, window):
496        """
497        method called to populate the 'insert column before current column'
498        submenu.
499       
500        """
501       
502        if self.data is None:
503            return
504        id = wx.NewId()
505        title = "Empty"
506        hint = 'Insert empty column before %s' % str(label)
507        menu.Append(id, title, hint)
508        wx.EVT_MENU(window, id, self.on_insert_column)
509        row = 0
510        col_name = [self.GetCellValue(row, col) for col in range(self.GetNumberCols())]
511        for c_name in self.data.keys():
512            if c_name not in col_name and self.data[c_name]:
513                wx_id = wx.NewId()
514                hint = "Insert %s column before the " % str(c_name)
515                hint += " %s column" % str(label)
516                menu.Append(wx_id, '&%s' % str(c_name), hint)
517                wx.EVT_MENU(window, wx_id, self.on_insert_column)
518
519    def insert_after_col_menu(self, menu, label, window):
520        """
521        Method called to populate the 'insert column after current column'
522        submenu
523       
524        """
525       
526        if self.data is None:
527            return
528        wx_id = wx.NewId()
529        title = "Empty"
530        hint = 'Insert empty column after %s' % str(label)
531        menu.Append(wx_id, title, hint)
532        wx.EVT_MENU(window, wx_id, self.on_insert_after_column)
533        row = 0
534        col_name = [self.GetCellValue(row, col)
535                        for col in range(self.GetNumberCols())]
536        for c_name in self.data.keys():
537            if c_name not in col_name and self.data[c_name]:
538                wx_id = wx.NewId()
539                hint = "Insert %s column after the " % str(c_name)
540                hint += " %s column" % str(label)
541                menu.Append(wx_id, '&%s' % str(c_name), hint)
542                wx.EVT_MENU(window, wx_id, self.on_insert_after_column)
543
544    def on_remove_column(self, event=None):
545        """
546        Called when user chooses remove from the column right click menu
547        Checks the columnn exists then calls the remove_column method
548       
549        """
550       
551        if self.selected_cols is not None or len(self.selected_cols) > 0:
552            col = self.selected_cols[0]
553            self.remove_column(col=col, numCols=1)
554
555    def remove_column(self, col, numCols=1):
556        """
557        Remove the col column from the current grid
558       
559        """
560       
561        # add data to the grid   
562        row = 0
563        col_name = self.GetCellValue(row, col)
564        self.data[col_name] = []
565        for row in range(1, self.GetNumberRows() + 1):
566            if row < self.max_row_touse:
567                value = self.GetCellValue(row, col)
568                self.data[col_name].append(value)
569                for k, value_list in self.data.iteritems():
570                    if k != col_name:
571                        length = len(value_list)
572                        if length < self.max_row_touse:
573                            diff = self.max_row_touse - length
574                            for i in range(diff):
575                                self.data[k].append("")
576        self.DeleteCols(pos=col, numCols=numCols, updateLabels=True)
577
578    def on_insert_column(self, event):
579        """
580        Called when user chooses insert 'column before' submenu
581        of the column context menu obtained when right clicking on a given
582        column header.
583       
584        Sets up to insert column into the current grid before the current
585        highlighted column location and sets up what to populate that column
586        with.  Then calls insert_column method to actually do the insertion.
587       
588        """
589       
590        if self.selected_cols is not None or len(self.selected_cols) > 0:
591            col = self.selected_cols[0]
592            # add data to the grid
593            wx_id = event.GetId()
594            col_name = event.GetEventObject().GetLabelText(wx_id)
595            self.insert_column(col=col, col_name=col_name)
596            if  not issubclass(event.GetEventObject().__class__, wx.Menu):
597                col += 1
598                self.selected_cols[0] += 1
599
600    def on_insert_after_column(self, event):
601        """
602        Called when user chooses insert 'column after' submenu
603        of the column context menu obtained when right clicking on a given
604        column header.
605       
606        Sets up to insert column into the current grid after the current
607        highlighted column location and sets up what to populate that column
608        with.  Then calls insert_column method to actually do the insertion.
609       
610        """
611       
612        if self.selected_cols is not None or len(self.selected_cols) > 0:
613            col = self.selected_cols[0] + 1
614            # add data to the grid
615            wx_id = event.GetId()
616            col_name = event.GetEventObject().GetLabelText(wx_id)
617            self.insert_column(col=col, col_name=col_name)
618            if  not issubclass(event.GetEventObject().__class__, wx.Menu):
619                self.selected_cols[0] += 1
620
621    def insert_column(self, col, col_name):
622        """
623        Insert column at position col with data[col_name] into the current
624        grid.
625       
626        """
627       
628        row = 0
629        self.InsertCols(pos=col, numCols=1, updateLabels=True)
630        if col_name.strip() != "Empty":
631            self.SetCellValue(row, col, str(col_name.strip()))
632        if col_name in self.data.keys():
633            value_list = self.data[col_name]
634            cell_row = 1
635            for value in value_list:
636                label = value#format_number(value, high=True)
637                self.SetCellValue(cell_row, col, str(label))
638                cell_row += 1
639        self.AutoSizeColumn(col, True)
640        width = self.GetColSize(col)
641        if width < self.default_col_width:
642            self.SetColSize(col, self.default_col_width)
643        color = self.parent.GetBackgroundColour()
644        self.SetCellBackgroundColour(0, col, color)
645        self.ForceRefresh()
646
647    def on_set_x_axis(self, event):
648        """
649        Just calls the panel version of the method
650       
651        """
652       
653        self.panel.set_xaxis(x=self.axis_value, label=self.axis_label)
654
655    def on_set_y_axis(self, event):
656        """
657        Just calls the panel version of the method
658       
659        """
660        self.panel.set_yaxis(y=self.axis_value, label=self.axis_label)
661
662    def set_data(self, data_inputs, data_outputs, details, file_name):
663        """
664        Add data to the grid
665       
666        :param data_inputs: data to use from the context menu of the grid
667        :param data_ouputs: default columns deplayed
668       
669        """
670       
671        self.file_name = file_name
672        self.details = details
673
674        if data_outputs is None:
675            data_outputs = {}
676        self.data_outputs = data_outputs
677        if data_inputs is None:
678            data_inputs = {}
679        self.data_inputs = data_inputs
680        self.data = {}
681        for item in (self.data_outputs, self.data_inputs):
682            self.data.update(item)
683
684        if  len(self.data_outputs) > 0:
685            self._cols = self.GetNumberCols()
686            self._rows = self.GetNumberRows()
687            self.col_names = self.data_outputs.keys()
688            self.col_names.sort()
689            nbr_user_cols = len(self.col_names)
690            #Add more columns to the grid if necessary
691            if nbr_user_cols > self._cols:
692                new_col_nbr = nbr_user_cols - self._cols + 1
693                self.AppendCols(new_col_nbr, True)
694            #Add more rows to the grid if necessary
695            nbr_user_row = len(self.data_outputs.values()[0])
696            if nbr_user_row > self._rows + 1:
697                new_row_nbr = nbr_user_row - self._rows + 1
698                self.AppendRows(new_row_nbr, True)
699            # add data to the grid
700            wx.CallAfter(self.set_grid_values)
701        self.ForceRefresh()
702
703    def set_grid_values(self):
704        """
705        Set the values in grids
706       
707        """
708       
709        # add data to the grid
710        row = 0
711        col = 0
712        cell_col = 0
713        for col_name in  self.col_names:
714            # use the first row of the grid to add user defined labels
715            self.SetCellValue(row, col, str(col_name))
716            col += 1
717            cell_row = 1
718            value_list = self.data_outputs[col_name]
719
720            for value in value_list:
721                label = value
722                if issubclass(value.__class__, BatchCell):
723                    label = value.label
724                try:
725                    float(label)
726                    label = str(label)#format_number(label, high=True)
727                except:
728                    label = str(label)
729                self.SetCellValue(cell_row, cell_col, label)
730                self.AutoSizeColumn(cell_col, True)
731                width = self.GetColSize(cell_col)
732                if width < self.default_col_width:
733                    self.SetColSize(cell_col, self.default_col_width)
734
735                cell_row += 1
736            cell_col += 1
737            if cell_row > self.max_row_touse:
738                self.max_row_touse = cell_row
739
740    def get_grid_view(self):
741        """
742        Return value contained in the grid
743       
744        """
745       
746        grid_view = {}
747        for col in xrange(self.GetNumberCols()):
748            label = self.GetCellValue(row=0, col=col)
749            label = label.strip()
750            if label != "":
751                grid_view[label] = []
752                for row in range(1, self.max_row_touse):
753                    value = self.GetCellValue(row=row, col=col)
754                    if value != "":
755                        grid_view[label].append(value)
756                    else:
757                        grid_view[label].append(None)
758        return grid_view
759
760    def get_nofrows(self):
761        """
762        Return number of total rows
763       
764        """
765        return self._rows
766
767    def onContextMenu(self, event):
768        """
769        Method to handle cell right click context menu.
770       
771        THIS METHOD IS NOT CURRENTLY USED.  It is designed to provide a
772        cell pop up context by right clicking on a cell and gives the
773        option to cut, paste, and clear. This will probably be removed in
774        future versions and is being superceded by more traditional cut and
775        paste options.
776       
777        """
778       
779        wx_id = wx.NewId()
780        c_menu = wx.Menu()
781        copy_menu = c_menu.Append(wx_id, '&Copy', 'Copy the selected cells')
782        wx.EVT_MENU(self, wx_id, self.on_copy)
783
784        wx_id = wx.NewId()
785        c_menu.Append(wx_id, '&Paste', 'Paste the selected cells')
786        wx.EVT_MENU(self, wx_id, self.on_paste)
787
788        wx_id = wx.NewId()
789        clear_menu = c_menu.Append(wx_id, '&Clear', 'Clear the selected cells')
790        wx.EVT_MENU(self, wx_id, self.on_clear)
791
792        # enable from flag
793        has_selection = False
794        selected_cel = self.selected_cells
795        if len(selected_cel) > 0:
796            _row, _col = selected_cel[0]
797            has_selection = self.IsInSelection(_row, _col)
798        if len(self.selected_cols) > 0:
799            has_selection = True
800        if len(self.selected_rows) > 0:
801            has_selection = True
802        copy_menu.Enable(has_selection)
803        clear_menu.Enable(has_selection)
804        try:
805            # mouse event pos
806            pos_evt = event.GetPosition()
807            self.PopupMenu(c_menu, pos_evt)
808        except:
809            return
810
811    def on_copy(self, event):
812        """
813        Called when copy is chosen from cell right click context menu
814
815        THIS METHOD IS NOT CURRENTLY USED.  it is part of right click cell
816        context menu which is being removed. This will probably be removed in
817        future versions and is being superceded by more traditional cut and
818        paste options
819
820        """
821
822        self.Copy()
823
824    def on_paste(self, event):
825        """
826        Called when paste is chosen from cell right click context menu
827       
828        THIS METHOD IS NOT CURRENTLY USED.  it is part of right click cell
829        context menu which is being removed. This will probably be removed in
830        future versions and is being superceded by more traditional cut and
831        paste options
832
833        """
834
835        if self.data == None:
836            self.data = {}
837        if self.file_name == None:
838            self.file_name = 'copied_data'
839        self.Paste()
840
841    def on_clear(self, event):
842        """
843        Called when clear cell is chosen from cell right click context menu
844
845        THIS METHOD IS NOT CURRENTLY USED.  it is part of right click cell
846        context menu which is being removed. This will probably be removed in
847        future versions and is being superceded by more traditional cut and
848        paste options
849
850        """
851
852        self.Clear()
853
854class Notebook(nb, PanelBase):
855    """
856    ## Internal name for the AUI manager
857    window_name = "Fit panel"
858    ## Title to appear on top of the window
859   
860    """
861   
862    window_caption = "Notebook "
863
864    def __init__(self, parent, manager=None, data=None, *args, **kwargs):
865        """
866        """
867        nb.__init__(self, parent, -1,
868                    style=wx.aui.AUI_NB_WINDOWLIST_BUTTON |
869                    wx.aui.AUI_BUTTON_DOWN |
870                    wx.aui.AUI_NB_DEFAULT_STYLE |
871                    wx.CLIP_CHILDREN)
872        PanelBase.__init__(self, parent)
873        self.gpage_num = 1
874        self.enable_close_button()
875        self.parent = parent
876        self.manager = manager
877        self.data = data
878        #add empty page
879        self.add_empty_page()
880        self.pageClosedEvent = wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE
881        self.Bind(self.pageClosedEvent, self.on_close_page)
882
883    def add_empty_page(self):
884        """
885        """
886        grid = GridPage(self, panel=self.parent)
887        self.AddPage(grid, "", True)
888        pos = self.GetPageIndex(grid)
889        title = "Table" + str(self.gpage_num)
890        self.SetPageText(pos, title)
891        self.SetSelection(pos)
892        self.enable_close_button()
893        self.gpage_num += 1
894        return grid, pos
895
896    def enable_close_button(self):
897        """
898        display the close button on the tab if more than 1 tab exits.
899        Otherwise remove the close button
900
901        """
902
903        if self.GetPageCount() <= 1:
904            style = self.GetWindowStyleFlag()
905            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
906            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB == flag:
907                style = style & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
908                self.SetWindowStyle(style)
909        else:
910            style = self.GetWindowStyleFlag()
911            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
912            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB != flag:
913                style |= wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
914                self.SetWindowStyle(style)
915
916    def on_edit_axis(self):
917        """
918        Return the select cell range from a given selected column. Checks that
919        all cells are from the same column
920
921        """
922
923        pos = self.GetSelection()
924        grid = self.GetPage(pos)
925        #grid.selected_cols = [grid.GetSelectedRows()]#
926        if len(grid.selected_cols) >= 1:
927            col = grid.selected_cols[0]
928            for c in grid.selected_cols:
929                if c != col:
930                    msg = "Edit axis doesn't understand this selection.\n"
931                    msg += "Please select only one column"
932                    raise ValueError, msg
933            for (_, cell_col) in grid.selected_cells:
934                if cell_col != col:
935                    msg = "Cannot use cells from different columns for "
936                    msg += "this operation.\n"
937                    msg += "Please select elements of the same col.\n"
938                    raise ValueError, msg
939
940            # Finally check the highlighted cell if any cells missing
941            self.get_highlighted_row(True)
942        else:
943            msg = "No item selected.\n"
944            msg += "Please select only one column or one cell"
945            raise ValueError, msg
946        return grid.selected_cells
947
948    def get_highlighted_row(self, is_number=True):
949        """
950        Add highlight rows
951
952        """
953
954        pos = self.GetSelection()
955        grid = self.GetPage(pos)
956        col = grid.selected_cols[0]
957        # Finally check the highlighted cell if any cells missing
958        for row in range(grid.get_nofrows()):
959            if grid.IsInSelection(row, col):
960                cel = (row, col)
961                if row < 1 and not is_number:
962                    continue
963                # empty cell
964                if not grid.GetCellValue(row, col).lstrip().rstrip():
965                    if cel in grid.selected_cells:
966                        grid.selected_cells.remove(cel)
967                    continue
968                if is_number:
969                    try:
970                        float(grid.GetCellValue(row, col))
971                    except:
972                        # non numeric cell
973                        if cel in grid.selected_cells:
974                            grid.selected_cells.remove(cel)
975                        continue
976                if cel not in grid.selected_cells:
977                    grid.selected_cells.append(cel)
978
979    def get_column_labels(self):
980        """
981        return dictionary of columns labels on the current page
982
983        """
984
985        pos = self.GetSelection()
986        grid = self.GetPage(pos)
987        labels = {}
988        for col in range(grid.GetNumberCols()):
989            label = grid.GetColLabelValue(int(col))
990            if label.strip() != "":
991                labels[label.strip()] = col
992        return labels
993
994    def create_axis_label(self, cell_list):
995        """
996        Receive a list of cells and  create a string presenting the selected
997        cells that can be used as data for one axis of a plot.
998       
999        :param cell_list: list of tuple
1000
1001        """
1002        pos = self.GetSelection()
1003        grid = self.GetPage(pos)
1004        label = ""
1005        col_name = ""
1006        def create_label(col_name, row_min=None, row_max=None):
1007            """
1008            """
1009            result = " "
1010            if row_min is not  None or row_max is not None:
1011                if row_min is None:
1012                    result = str(row_max) + "]"
1013                elif row_max is None:
1014                    result = str(col_name) + "[" + str(row_min) + ":"
1015                else:
1016                    result = str(col_name) + "[" + str(row_min) + ":"
1017                    result += str(row_max) + "]"
1018            return str(result)
1019
1020        if len(cell_list) > 0:
1021            if len(cell_list) == 1:
1022                row_min, col = cell_list[0]
1023                col_name = grid.GetColLabelValue(int(col))
1024
1025                col_title = grid.GetCellValue(0, col)
1026                label = create_label(col_name, row_min + 1, row_min + 1)
1027                return  label, col_title
1028            else:
1029                temp_list = copy.deepcopy(cell_list)
1030                temp_list.sort()
1031                length = len(temp_list)
1032                row_min, col = temp_list[0]
1033                row_max, _ = temp_list[length - 1]
1034                col_name = grid.GetColLabelValue(int(col))
1035                col_title = grid.GetCellValue(0, col)
1036
1037                index = 0
1038                for row in xrange(row_min, row_max + 1):
1039                    if index > 0 and index < len(temp_list):
1040                        new_row, _ = temp_list[index]
1041                        if row != new_row:
1042                            temp_list.insert(index, (None, None))
1043                            if index - 1 >= 0:
1044                                new_row, _ = temp_list[index - 1]
1045                                if not new_row == None and new_row != ' ':
1046                                    label += create_label(col_name, None,
1047                                                          int(new_row) + 1)
1048                                else:
1049                                    label += "]"
1050                                label += ","
1051                            if index + 1 < len(temp_list):
1052                                new_row, _ = temp_list[index + 1]
1053                                if not new_row == None:
1054                                    label += create_label(col_name,
1055                                                          int(new_row) + 1, None)
1056                    if row_min != None and row_max != None:
1057                        if index == 0:
1058                            label += create_label(col_name,
1059                                                  int(row_min) + 1, None)
1060                        elif index == len(temp_list) - 1:
1061                            label += create_label(col_name, None,
1062                                                  int(row_max) + 1)
1063                    index += 1
1064                # clean up the list
1065                label_out = ''
1066                for item in label.split(','):
1067                    if item.split(":")[1] == "]":
1068                        continue
1069                    else:
1070                        label_out += item + ","
1071
1072                return label_out, col_title
1073
1074    def on_close_page(self, event):
1075        """
1076        close the page
1077
1078        """
1079
1080        if self.GetPageCount() == 1:
1081            event.Veto()
1082        wx.CallAfter(self.enable_close_button)
1083
1084    def set_data(self, data_inputs, data_outputs, details="", file_name=None):
1085        """
1086        """
1087        if data_outputs is None or data_outputs == {}:
1088            return
1089        inputs, outputs = self.get_odered_results(data_inputs, data_outputs)
1090        for pos in range(self.GetPageCount()):
1091            grid = self.GetPage(pos)
1092            if grid.data is None:
1093                #Found empty page
1094                grid.set_data(data_inputs=inputs,
1095                              data_outputs=outputs,
1096                              details=details,
1097                              file_name=file_name)
1098                self.SetSelection(pos)
1099                return
1100
1101        grid, pos = self.add_empty_page()
1102        grid.set_data(data_inputs=inputs,
1103                      data_outputs=outputs,
1104                      file_name=file_name,
1105                      details=details)
1106
1107    def get_odered_results(self, inputs, outputs=None):
1108        """
1109        Order a list of 'inputs.' Used to sort rows and columns to present
1110        in batch results grid.
1111
1112        """
1113
1114        # Let's re-order the data from the keys in 'Data' name.
1115        if outputs == None:
1116            return
1117        try:
1118            # For outputs from batch
1119            to_be_sort = [str(item.label) for item in outputs['Data']]
1120        except:
1121            # When inputs are from an external file
1122            return inputs, outputs
1123        inds = numpy.lexsort((to_be_sort, to_be_sort))
1124        for key in outputs.keys():
1125            key_list = outputs[key]
1126            temp_key = [item for item in key_list]
1127            for ind in inds:
1128                temp_key[ind] = key_list[inds[ind]]
1129            outputs[key] = temp_key
1130        for key in inputs.keys():
1131            key_list = inputs[key]
1132            if len(key_list) == len(inds):
1133                temp_key = [item for item in key_list]
1134                for ind in inds:
1135                    temp_key[ind] = key_list[inds[ind]]
1136                inputs[key] = temp_key
1137            else:
1138                inputs[key] = []
1139
1140        return inputs, outputs
1141
1142    def add_column(self):
1143        """
1144        Append a new column to the grid
1145
1146        """
1147
1148        # I Believe this is no longer used now that we have removed the
1149        # edit menu from the menubar - PDB July 12, 2015
1150        pos = self.GetSelection()
1151        grid = self.GetPage(pos)
1152        grid.AppendCols(1, True)
1153
1154    def on_remove_column(self):
1155        """
1156        Remove the selected column from the grid
1157
1158        """
1159        # I Believe this is no longer used now that we have removed the
1160        # edit menu from the menubar - PDB July 12, 2015
1161        pos = self.GetSelection()
1162        grid = self.GetPage(pos)
1163        grid.on_remove_column(event=None)
1164
1165class GridPanel(SPanel):
1166    """
1167    A ScrolledPanel class that contains the grid sheet as well as a number of
1168    widgets to create interesting plots and buttons for help etc.
1169
1170    """
1171
1172    def __init__(self, parent, data_inputs=None,
1173                 data_outputs=None, *args, **kwds):
1174        """
1175        Initialize the GridPanel
1176
1177        """
1178
1179        SPanel.__init__(self, parent, *args, **kwds)
1180
1181        self.vbox = wx.BoxSizer(wx.VERTICAL)
1182
1183        self.plotting_sizer = wx.FlexGridSizer(3, 7, 10, 5)
1184        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
1185        self.grid_sizer = wx.BoxSizer(wx.HORIZONTAL)
1186        self.vbox.AddMany([(self.grid_sizer, 1, wx.EXPAND, 0),
1187                           (wx.StaticLine(self, -1), 0, wx.EXPAND, 0),
1188                           (self.plotting_sizer),
1189                           (self.button_sizer, 0, wx.BOTTOM, 10)])
1190        self.parent = parent
1191        self._data_inputs = data_inputs
1192        self._data_outputs = data_outputs
1193        self.x = []
1194        self.y = []
1195        self.dy = []
1196        self.x_axis_label = None
1197        self.y_axis_label = None
1198        self.dy_axis_label = None
1199        self.x_axis_title = None
1200        self.y_axis_title = None
1201        self.x_axis_unit = None
1202        self.y_axis_unit = None
1203        self.view_button = None
1204        self.plot_button = None
1205        self.notebook = None
1206        self.plot_num = 1
1207
1208        self.layout_grid()
1209        self.layout_plotting_area()
1210        self.SetSizer(self.vbox)
1211
1212    def set_xaxis(self, label="", x=None):
1213        """
1214        """
1215        if x is None:
1216            x = []
1217        self.x = x
1218        self.x_axis_label.SetValue("%s[:]" % str(label))
1219        self.x_axis_title.SetValue(str(label))
1220
1221    def set_yaxis(self, label="", y=None):
1222        """
1223        """
1224        if y is None:
1225            y = []
1226        self.y = y
1227        self.y_axis_label.SetValue("%s[:]" % str(label))
1228        self.y_axis_title.SetValue(str(label))
1229
1230    def set_dyaxis(self, label="", dy=None):
1231        """
1232        """
1233        if dy is None:
1234            dy = []
1235        self.dy = dy
1236        self.dy_axis_label.SetValue("%s[:]" % str(label))
1237
1238    def get_plot_axis(self, col, list):
1239        """
1240        """
1241        axis = []
1242        pos = self.notebook.GetSelection()
1243        grid = self.notebook.GetPage(pos)
1244        for row in list:
1245            label = grid.GetCellValue(0, col)
1246            value = grid.GetCellValue(row - 1, col).strip()
1247            if value != "":
1248                if label.lower().strip() == "data":
1249                    axis.append(float(row - 1))
1250                else:
1251                    try:
1252                        axis.append(float(value))
1253                    except:
1254                        msg = "Invalid data in row %s column %s" % (str(row), str(col))
1255                        wx.PostEvent(self.parent.parent,
1256                                     StatusEvent(status=msg, info="error"))
1257                        return None
1258            else:
1259                axis.append(None)
1260        return axis
1261
1262    def on_view(self, event):
1263        """
1264        Get object represented by the given cells and plot them.  Basically
1265        plot the colum in y vs the column in x.
1266
1267        """
1268
1269        pos = self.notebook.GetSelection()
1270        grid = self.notebook.GetPage(pos)
1271        title = self.notebook.GetPageText(pos)
1272        self.notebook.get_highlighted_row(False)
1273        if len(grid.selected_cells) == 0:
1274            msg = "Highlight a Data or Chi2 column first..."
1275            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1276            return
1277        elif len(grid.selected_cells) > 20:
1278            msg = "Too many data (> 20) to plot..."
1279            msg += "\n Please select no more than 20 data."
1280            wx.MessageDialog(self, msg, 'Plotting', wx.OK)
1281            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1282            return
1283
1284        for cell in grid.selected_cells:
1285            row, col = cell
1286            label_row = 0
1287            label = grid.GetCellValue(label_row, col)
1288            if label in grid.data:
1289                values = grid.data[label]
1290                if row > len(values) or row < 1:
1291                    msg = "Invalid cell was chosen."
1292                    wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1293                    continue
1294                else:
1295                    value = values[row - 1]
1296                if issubclass(value.__class__, BatchCell):
1297                    if value.object is None or len(value.object) == 0:
1298                        msg = "Row %s , " % str(row)
1299                        msg += "Column %s is NOT " % str(label)
1300                        msg += "the results of fits to view..."
1301                        wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1302                        return
1303                    for new_plot in value.object:
1304                        if new_plot is None or \
1305                         not issubclass(new_plot.__class__,
1306                                        plottables.Plottable):
1307                            msg = "Row %s , " % str(row)
1308                            msg += "Column %s is NOT " % str(label)
1309                            msg += "the results of fits to view..."
1310                            wx.PostEvent(self.parent.parent,
1311                                         StatusEvent(status=msg, info="error"))
1312                            return
1313                        if issubclass(new_plot.__class__, Data1D):
1314                            if label in grid.list_plot_panels.keys():
1315                                group_id = grid.list_plot_panels[label]
1316                            else:
1317                                group_id = str(new_plot.group_id) + str(grid.uid)
1318                                grid.list_plot_panels[label] = group_id
1319                            if group_id not in new_plot.list_group_id:
1320                                new_plot.group_id = group_id
1321                                new_plot.list_group_id.append(group_id)
1322                        else:
1323                            if label.lower() in ["data", "chi2"]:
1324                                if len(grid.selected_cells) != 1:
1325                                    msg = "2D View: Please select one data set"
1326                                    msg += " at a time for View Fit Results."
1327                                    wx.PostEvent(self.parent.parent,
1328                                                 StatusEvent(status=msg, info="error"))
1329                                    return
1330
1331                        wx.PostEvent(self.parent.parent,
1332                                     NewPlotEvent(plot=new_plot,
1333                                                  group_id=str(new_plot.group_id),
1334                                                  title=title))
1335                        msg = "Plotting the View Fit Results  completed!"
1336                        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1337                else:
1338                    msg = "Row %s , " % str(row)
1339                    msg += "Column %s is NOT " % str(label)
1340                    msg += "the results of fits to view..."
1341                    wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1342                    return
1343
1344    def on_plot(self, event):
1345        """
1346        Evaluate the contains of textcrtl and plot result
1347
1348        """
1349
1350        pos = self.notebook.GetSelection()
1351        grid = self.notebook.GetPage(pos)
1352        column_names = {}
1353        if grid is not None:
1354            column_names = self.notebook.get_column_labels()
1355        #evaluate x
1356        sentence = self.x_axis_label.GetValue()
1357        try:
1358            if sentence.strip() == "":
1359                msg = "Select column values for x axis"
1360                raise ValueError, msg
1361        except:
1362            msg = "X axis value error."
1363            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1364            return
1365        dict = parse_string(sentence, column_names.keys())
1366
1367        try:
1368            sentence = self.get_sentence(dict, sentence, column_names)
1369            x = eval(sentence)
1370        except:
1371            msg = "Need a proper x-range."
1372            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1373            return
1374        #evaluate y
1375        sentence = self.y_axis_label.GetValue()
1376        try:
1377            if sentence.strip() == "":
1378                msg = "select value for y axis"
1379                raise ValueError, msg
1380        except:
1381            msg = "Y axis value error."
1382            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1383            return
1384        dict = parse_string(sentence, column_names.keys())
1385        try:
1386            sentence = self.get_sentence(dict, sentence, column_names)
1387            y = eval(sentence)
1388        except:
1389            msg = "Need a proper y-range."
1390            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1391            return
1392        #evaluate y
1393        sentence = self.dy_axis_label.GetValue()
1394        dy = None
1395        if sentence.strip() != "":
1396            dict = parse_string(sentence, column_names.keys())
1397            sentence = self.get_sentence(dict, sentence, column_names)
1398            try:
1399                dy = eval(sentence)
1400            except:
1401                msg = "Need a proper dy-range."
1402                wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1403                return
1404        if len(x) != len(y) or (len(x) == 0 or len(y) == 0):
1405            msg = "Need same length for X and Y axis and both greater than 0"
1406            msg += " to plot.\n"
1407            msg += "Got X length = %s, Y length = %s" % (str(len(x)), str(len(y)))
1408            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1409            return
1410        if dy != None and (len(y) != len(dy)):
1411            msg = "Need same length for Y and dY axis and both greater than 0"
1412            msg += " to plot.\n"
1413            msg += "Got Y length = %s, dY length = %s" % (str(len(y)), str(len(dy)))
1414            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1415            return
1416        if dy == None:
1417            dy = numpy.zeros(len(y))
1418        #plotting
1419        new_plot = Data1D(x=x, y=y, dy=dy)
1420        new_plot.id = wx.NewId()
1421        new_plot.is_data = False
1422        new_plot.group_id = wx.NewId()
1423        y_title = self.y_axis_title.GetValue()
1424        x_title = self.x_axis_title.GetValue()
1425        title = "%s_vs_%s" % (y_title, x_title)
1426        new_plot.xaxis(x_title, self.x_axis_unit.GetValue())
1427        new_plot.yaxis(y_title, self.y_axis_unit.GetValue())
1428        try:
1429            title = y_title.strip()
1430            title += "_" + self.notebook.GetPageText(pos)
1431            title += "_" + str(self.plot_num)
1432            self.plot_num += 1
1433            new_plot.name = title
1434            new_plot.xtransform = "x"
1435            new_plot.ytransform = "y"
1436            wx.PostEvent(self.parent.parent,
1437                         NewPlotEvent(plot=new_plot,
1438                                      group_id=str(new_plot.group_id), title=title))
1439            msg = "Plotting completed!"
1440            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1441            self.parent.parent.update_theory(data_id=new_plot.id, theory=new_plot)
1442        except:
1443            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1444
1445    def on_help(self, event):
1446        """
1447        Bring up the Batch Grid Panel Usage Documentation whenever
1448        the HELP button is clicked.
1449
1450        Calls DocumentationWindow with the path of the location within the
1451        documentation tree (after /doc/ ....".  Note that when using old
1452        versions of Wx (before 2.9) and thus not the release version of
1453        installers, the help comes up at the top level of the file as
1454        webbrowser does not pass anything past the # to the browser when it is
1455        running "file:///...."
1456
1457        :param evt: Triggers on clicking the help button
1458
1459        """
1460
1461        #import documentation window here to avoid circular imports
1462        #if put at top of file with rest of imports.
1463        from documentation_window import DocumentationWindow
1464
1465        _TreeLocation = "user/perspectives/fitting/fitting_help.html"
1466        _PageAnchor = "#batch-fit-mode"
1467        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
1468                                          "Batch Mode Help")
1469
1470    def get_sentence(self, dict, sentence, column_names):
1471        """
1472        Get sentence from dict
1473
1474        """
1475
1476        for tok, (col_name, list) in dict.iteritems():
1477            col = column_names[col_name]
1478            axis = self.get_plot_axis(col, list)
1479            if axis == None:
1480                return None
1481            sentence = sentence.replace(tok, "numpy.array(%s)" % str(axis))
1482        for key, value in FUNC_DICT.iteritems():
1483            sentence = sentence.replace(key.lower(), value)
1484        return sentence
1485
1486    def layout_grid(self):
1487        """
1488        Draw the area related to the grid by adding it as the first element
1489        in the panel's grid_sizer
1490
1491        """
1492
1493        self.notebook = Notebook(parent=self)
1494        self.notebook.set_data(self._data_inputs, self._data_outputs)
1495        self.grid_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
1496
1497    def layout_plotting_area(self):
1498        """
1499        Add the area containing all the plot options, buttons etc to a plotting
1500        area sizer to later be added to the top level grid_sizer
1501
1502        """
1503
1504        view_description = wx.StaticBox(self, -1, 'Plot Fits/Residuals')
1505        note = "To plot the fits (or residuals), click the 'View Fits' button"
1506        note += "\n after highlighting the Data names (or Chi2 values)."
1507        note_text = wx.StaticText(self, -1, note)
1508        boxsizer1 = wx.StaticBoxSizer(view_description, wx.HORIZONTAL)
1509        self.x_axis_title = wx.TextCtrl(self, -1)
1510        self.y_axis_title = wx.TextCtrl(self, -1)
1511        self.x_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1512        self.y_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1513        self.dy_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1514        self.x_axis_add = wx.Button(self, -1, "Add")
1515        self.x_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis,
1516                             id=self.x_axis_add.GetId())
1517        self.y_axis_add = wx.Button(self, -1, "Add")
1518        self.y_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis,
1519                             id=self.y_axis_add.GetId())
1520        self.dy_axis_add = wx.Button(self, -1, "Add")
1521        self.dy_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis,
1522                              id=self.dy_axis_add.GetId())
1523        self.x_axis_unit = wx.TextCtrl(self, -1)
1524        self.y_axis_unit = wx.TextCtrl(self, -1)
1525        self.view_button = wx.Button(self, -1, "View Fits")
1526        view_tip = "Highlight the data set or the Chi2 column first."
1527        self.view_button.SetToolTipString(view_tip)
1528        wx.EVT_BUTTON(self, self.view_button.GetId(), self.on_view)
1529        self.plot_button = wx.Button(self, -1, "Plot")
1530        plot_tip = "Highlight a column for each axis and \n"
1531        plot_tip += "click the Add buttons first."
1532
1533        self.plot_button.SetToolTipString(plot_tip)
1534
1535        self.help_button = wx.Button(self, -1, "HELP")
1536        self.help_button.SetToolTipString("Get Help for Batch Mode")
1537        self.help_button.Bind(wx.EVT_BUTTON, self.on_help)
1538
1539        boxsizer1.AddMany([(note_text, 0, wx.LEFT, 10),
1540                           (self.view_button, 0, wx.LEFT | wx.RIGHT, 10)])
1541        self.button_sizer.AddMany([(boxsizer1, 0,
1542                                    wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
1543                                   (self.plot_button, 0,
1544                                    wx.LEFT | wx.TOP | wx.BOTTOM, 12),
1545                                   (self.help_button,0, 
1546                                    wx.LEFT | wx.TOP | wx.BOTTOM, 12)])
1547
1548        wx.EVT_BUTTON(self, self.plot_button.GetId(), self.on_plot)
1549        self.plotting_sizer.AddMany(\
1550                   [(wx.StaticText(self, -1, "X-axis Label\nSelection Range"), 1,
1551                     wx.TOP | wx.BOTTOM | wx.LEFT, 10),
1552                    (self.x_axis_label, 1, wx.TOP | wx.BOTTOM, 10),
1553                    (self.x_axis_add, 1, wx.TOP | wx.BOTTOM | wx.RIGHT, 10),
1554                    (wx.StaticText(self, -1, "X-axis Label"), 1, wx.TOP | wx.BOTTOM | wx.LEFT, 10),
1555                    (self.x_axis_title, 1, wx.TOP | wx.BOTTOM, 10),
1556                    (wx.StaticText(self, -1, "X-axis Unit"), 1, wx.TOP | wx.BOTTOM, 10),
1557                    (self.x_axis_unit, 1, wx.TOP | wx.BOTTOM, 10),
1558                    (wx.StaticText(self, -1, "Y-axis Label\nSelection Range"), 1,
1559                     wx.BOTTOM | wx.LEFT, 10),
1560                    (self.y_axis_label, wx.BOTTOM, 10),
1561                    (self.y_axis_add, 1, wx.BOTTOM | wx.RIGHT, 10),
1562                    (wx.StaticText(self, -1, "Y-axis Label"), 1,
1563                     wx.BOTTOM | wx.LEFT, 10),
1564                    (self.y_axis_title, wx.BOTTOM, 10),
1565                    (wx.StaticText(self, -1, "Y-axis Unit"), 1, wx.BOTTOM, 10),
1566                    (self.y_axis_unit, 1, wx.BOTTOM, 10),
1567                    (wx.StaticText(self, -1, "dY-Bar (Optional)\nSelection Range"),
1568                     1, wx.BOTTOM | wx.LEFT, 10),
1569                    (self.dy_axis_label, wx.BOTTOM, 10),
1570                    (self.dy_axis_add, 1, wx.BOTTOM | wx.RIGHT, 10),
1571                    (-1, -1),
1572                    (-1, -1),
1573                    (-1, -1),
1574                    (-1, 1)])
1575
1576    def on_edit_axis(self, event):
1577        """
1578        Get the selected column on  the visible grid and set values for axis
1579
1580        """
1581
1582        try:
1583            cell_list = self.notebook.on_edit_axis()
1584            label, title = self.create_axis_label(cell_list)
1585        except:
1586            msg = str(sys.exc_value)
1587            wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info="error"))
1588            return
1589        tcrtl = event.GetEventObject()
1590        if tcrtl == self.x_axis_add:
1591            self.edit_axis_helper(self.x_axis_label, self.x_axis_title, label, title)
1592        elif tcrtl == self.y_axis_add:
1593            self.edit_axis_helper(self.y_axis_label, self.y_axis_title, label, title)
1594        elif tcrtl == self.dy_axis_add:
1595            self.edit_axis_helper(self.dy_axis_label, None, label, None)
1596
1597    def create_axis_label(self, cell_list):
1598        """
1599        Receive a list of cells and  create a string presenting the selected
1600        cells.
1601
1602        :param cell_list: list of tuple
1603
1604        """
1605
1606        if self.notebook is not None:
1607            return self.notebook.create_axis_label(cell_list)
1608
1609    def edit_axis_helper(self, tcrtl_label, tcrtl_title, label, title):
1610        """
1611        get controls to modify
1612
1613        """
1614
1615        if label != None:
1616            tcrtl_label.SetValue(str(label))
1617        if title != None:
1618            tcrtl_title.SetValue(str(title))
1619
1620    def add_column(self):
1621        """
1622        """
1623        # I Believe this is no longer used now that we have removed the
1624        # edit menu from the menubar - PDB July 12, 2015
1625        if self.notebook is not None:
1626            self.notebook.add_column()
1627
1628    def on_remove_column(self):
1629        """
1630        """
1631        # I Believe this is no longer used now that we have removed the
1632        # edit menu from the menubar - PDB July 12, 2015
1633        if self.notebook is not None:
1634            self.notebook.on_remove_column()
1635
1636
1637class GridFrame(wx.Frame):
1638    """
1639    The main wx.Frame for the batch results grid
1640
1641    """
1642
1643    def __init__(self, parent=None, data_inputs=None, data_outputs=None, id=-1,
1644                 title="Batch Fitting Results Panel", size=(800, 500)):
1645        """
1646        Initialize the Frame
1647       
1648        """
1649
1650        wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
1651        self.parent = parent
1652        self.panel = GridPanel(self, data_inputs, data_outputs)
1653        menubar = wx.MenuBar()
1654        self.SetMenuBar(menubar)
1655
1656        self.curr_col = None
1657        self.curr_grid = None
1658        self.curr_col_name = ""
1659        self.file = wx.Menu()
1660        menubar.Append(self.file, "&File")
1661
1662        hint = "Open file containing batch results"
1663        open_menu = self.file.Append(wx.NewId(), 'Open ', hint)
1664        wx.EVT_MENU(self, open_menu.GetId(), self.on_open)
1665
1666        hint = "Open the the current grid into excel"
1667        self.open_excel_menu = self.file.Append(wx.NewId(), 'Open with Excel', hint)
1668        wx.EVT_MENU(self, self.open_excel_menu.GetId(), self.open_with_excel)
1669        self.file.AppendSeparator()
1670        self.save_menu = self.file.Append(wx.NewId(), 'Save As', 'Save into File')
1671        wx.EVT_MENU(self, self.save_menu.GetId(), self.on_save_page)
1672
1673        # We need to grab a WxMenu handle here, otherwise the next one to grab
1674        # the handle will be treated as the Edit Menu handle when checking in
1675        # on_menu_open event handler and thus raise an exception when it hits an
1676        # unitialized object.  Alternative is to comment out that whole section
1677        # in on_menu_open, but that would make it more difficult to undo the
1678        # hidding of the menu.   PDB  July 12, 2015.
1679        #
1680        # To enable the Edit menubar comment out next line and uncomment the
1681        # following line.
1682        self.edit = wx.Menu()
1683        #self.add_edit_menu()
1684
1685        self.Bind(wx.EVT_MENU_OPEN, self.on_menu_open)
1686        self.Bind(wx.EVT_CLOSE, self.on_close)
1687
1688    def add_edit_menu(self, menubar):
1689        """
1690        populates the edit menu on the menubar.  Not activated as of SasView
1691        3.1.0
1692
1693        """
1694        self.edit = wx.Menu()
1695
1696        add_table_menu = self.edit.Append(-1, 'New Table',
1697                                          'Add a New Table')
1698        self.edit.AppendSeparator()
1699        wx.EVT_MENU(self, add_table_menu.GetId(), self.add_table)
1700
1701        self.copy_menu = self.edit.Append(-1, 'Copy',
1702                                          'Copy the selected cells')
1703        wx.EVT_MENU(self, self.copy_menu.GetId(), self.on_copy)
1704        self.paste_menu = self.edit.Append(-1, 'Paste',
1705                                           'Paste the selected Cells')
1706        wx.EVT_MENU(self, self.paste_menu.GetId(), self.on_paste)
1707        self.clear_menu = self.edit.Append(-1, 'Clear',
1708                                           'Clear the selected Cells')
1709        wx.EVT_MENU(self, self.clear_menu.GetId(), self.on_clear)
1710
1711        self.edit.AppendSeparator()
1712        hint = "Insert column before the selected column"
1713        self.insert_before_menu = wx.Menu()
1714        self.insertb_sub_menu = self.edit.AppendSubMenu(self.insert_before_menu,
1715                                                        'Insert Before', hint)
1716        hint = "Insert column after the selected column"
1717        self.insert_after_menu = wx.Menu()
1718        self.inserta_sub_menu = self.edit.AppendSubMenu(self.insert_after_menu,
1719                                                        'Insert After', hint)
1720        hint = "Remove the selected column"
1721        self.remove_menu = self.edit.Append(-1, 'Remove Column', hint)
1722        wx.EVT_MENU(self, self.remove_menu.GetId(), self.on_remove_column)
1723        menubar.Append(self.edit, "&Edit")
1724
1725    def on_copy(self, event):
1726        """
1727        On Copy from the Edit menu item on the menubar 
1728
1729        """
1730        # I Believe this is no longer used now that we have removed the
1731        # edit menu from the menubar - PDB July 12, 2015
1732        if event != None:
1733            event.Skip()
1734        pos = self.panel.notebook.GetSelection()
1735        grid = self.panel.notebook.GetPage(pos)
1736        grid.Copy()
1737
1738    def on_paste(self, event):
1739        """
1740        On Paste from the Edit menu item on the menubar
1741
1742        """
1743        # I Believe this is no longer used now that we have removed the
1744        # edit menu from the menubar - PDB July 12, 2015
1745        if event != None:
1746            event.Skip()
1747        pos = self.panel.notebook.GetSelection()
1748        grid = self.panel.notebook.GetPage(pos)
1749        grid.on_paste(None)
1750
1751    def on_clear(self, event):
1752        """
1753        On Clear from the Edit menu item on the menubar
1754
1755        """
1756        # I Believe this is no longer used now that we have removed the
1757        # edit menu from the menubar - PDB July 12, 2015
1758        pos = self.panel.notebook.GetSelection()
1759        grid = self.panel.notebook.GetPage(pos)
1760        grid.Clear()
1761
1762    def GetLabelText(self, id):
1763        """
1764        Get Label Text
1765
1766        """
1767        for item in self.insert_before_menu.GetMenuItems():
1768            m_id = item.GetId()
1769            if m_id == id:
1770                return item.GetLabel()
1771
1772    def on_remove_column(self, event):
1773        """
1774        On remove column from the Edit menu Item on the menubar
1775
1776        """
1777        # I Believe this is no longer used now that we have removed the
1778        # edit menu from the menubar - PDB July 12, 2015
1779        pos = self.panel.notebook.GetSelection()
1780        grid = self.panel.notebook.GetPage(pos)
1781        grid.on_remove_column(event=None)
1782
1783    def on_menu_open(self, event):
1784        """
1785        On menu open
1786
1787        """
1788        if self.file == event.GetMenu():
1789            pos = self.panel.notebook.GetSelection()
1790            grid = self.panel.notebook.GetPage(pos)
1791            has_data = (grid.data != None and grid.data != {})
1792            self.open_excel_menu.Enable(has_data)
1793            self.save_menu.Enable(has_data)
1794
1795        if self.edit == event.GetMenu():
1796            #get the selected column
1797            pos = self.panel.notebook.GetSelection()
1798            grid = self.panel.notebook.GetPage(pos)
1799            col_list = grid.GetSelectedCols()
1800            has_selection = False
1801            selected_cel = grid.selected_cells
1802            if len(selected_cel) > 0:
1803                _row, _col = selected_cel[0]
1804                has_selection = grid.IsInSelection(_row, _col)
1805            if len(grid.selected_cols) > 0:
1806                has_selection = True
1807            if len(grid.selected_rows) > 0:
1808                has_selection = True
1809            self.copy_menu.Enable(has_selection)
1810            self.clear_menu.Enable(has_selection)
1811
1812            if len(col_list) > 0:
1813                self.remove_menu.Enable(True)
1814            else:
1815                self.remove_menu.Enable(False)
1816            if len(col_list) == 0 or len(col_list) > 1:
1817                self.insertb_sub_menu.Enable(False)
1818                self.inserta_sub_menu.Enable(False)
1819                label = "Insert Column Before"
1820                self.insertb_sub_menu.SetText(label)
1821                label = "Insert Column After"
1822                self.inserta_sub_menu.SetText(label)
1823            else:
1824                self.insertb_sub_menu.Enable(True)
1825                self.inserta_sub_menu.Enable(True)
1826
1827                col = col_list[0]
1828                col_name = grid.GetCellValue(row=0, col=col)
1829                label = "Insert Column Before " + str(col_name)
1830                self.insertb_sub_menu.SetText(label)
1831                for item in self.insert_before_menu.GetMenuItems():
1832                    self.insert_before_menu.DeleteItem(item)
1833                grid.insert_col_menu(menu=self.insert_before_menu,
1834                                     label=col_name, window=self)
1835                label = "Insert Column After " + str(col_name)
1836                self.inserta_sub_menu.SetText(label)
1837                for item in self.insert_after_menu.GetMenuItems():
1838                    self.insert_after_menu.DeleteItem(item)
1839                grid.insert_after_col_menu(menu=self.insert_after_menu,
1840                                           label=col_name, window=self)
1841        event.Skip()
1842
1843
1844
1845    def on_save_page(self, event):
1846        """
1847        Saves data in grid to a csv file.
1848       
1849        At this time only the columns displayed get saved.  Thus any error
1850        bars not inserted before saving will not be saved in the file
1851
1852        """
1853
1854        if self.parent is not None:
1855            pos = self.panel.notebook.GetSelection()
1856            grid = self.panel.notebook.GetPage(pos)
1857            if grid.file_name is None or grid.file_name.strip() == "" or \
1858                grid.data is None or len(grid.data) == 0:
1859                name = self.panel.notebook.GetPageText(pos)
1860                msg = " %s has not data to save" % str(name)
1861                wx.PostEvent(self.parent,
1862                             StatusEvent(status=msg, info="error"))
1863
1864                return
1865            reader, ext = os.path.splitext(grid.file_name)
1866            path = None
1867            if self.parent is not None:
1868                location = os.path.dirname(grid.file_name)
1869                dlg = wx.FileDialog(self, "Save Project file",
1870                                    location, grid.file_name, ext, wx.SAVE)
1871                path = None
1872                if dlg.ShowModal() == wx.ID_OK:
1873                    path = dlg.GetPath()
1874                dlg.Destroy()
1875                if path != None:
1876                    if self.parent is not None:
1877                        data = grid.get_grid_view()
1878                        self.parent.write_batch_tofile(data=data,
1879                                                       file_name=path,
1880                                                       details=grid.details)
1881
1882    def on_open(self, event):
1883        """
1884        Open file containing batch result
1885
1886        """
1887
1888        if self.parent is not None:
1889            self.parent.on_read_batch_tofile(self)
1890
1891    def open_with_excel(self, event):
1892        """
1893        open excel and display batch result in Excel
1894
1895        """
1896
1897        if self.parent is not None:
1898            pos = self.panel.notebook.GetSelection()
1899            grid = self.panel.notebook.GetPage(pos)
1900            data = grid.get_grid_view()
1901            if grid.file_name is None or grid.file_name.strip() == "" or \
1902                grid.data is None or len(grid.data) == 0:
1903                name = self.panel.notebook.GetPageText(pos)
1904                msg = " %s has not data to open on excel" % str(name)
1905                wx.PostEvent(self.parent,
1906                             StatusEvent(status=msg, info="error"))
1907
1908                return
1909            self.parent.open_with_externalapp(data=data,
1910                                              file_name=grid.file_name,
1911                                              details=grid.details)
1912
1913    def on_close(self, event):
1914        """
1915        """
1916        self.Hide()
1917
1918    def on_append_column(self, event):
1919        """
1920        Append a new column to the grid
1921
1922        """
1923        self.panel.add_column()
1924
1925    def set_data(self, data_inputs, data_outputs, details="", file_name=None):
1926        """
1927        Set data
1928
1929        """
1930        self.panel.notebook.set_data(data_inputs=data_inputs,
1931                                     file_name=file_name,
1932                                     details=details,
1933                                     data_outputs=data_outputs)
1934
1935    def add_table(self, event):
1936        """
1937        Add a new table
1938
1939        """
1940        # DO not event.Skip(): it will make 2 pages
1941        self.panel.notebook.add_empty_page()
1942
1943class BatchOutputFrame(wx.Frame):
1944    """
1945    Allow to select where the result of batch will be displayed or stored
1946
1947    """
1948    def __init__(self, parent, data_inputs, data_outputs, file_name="",
1949                 details="", *args, **kwds):
1950        """
1951        Initialize dialog
1952
1953        :param parent: Window instantiating this dialog
1954        :param result: result to display in a grid or export to an external
1955                application.
1956
1957        """
1958
1959        #kwds['style'] = wx.CAPTION|wx.SYSTEM_MENU
1960        wx.Frame.__init__(self, parent, *args, **kwds)
1961        self.parent = parent
1962        self.panel = wx.Panel(self)
1963        self.file_name = file_name
1964        self.details = details
1965        self.data_inputs = data_inputs
1966        self.data_outputs = data_outputs
1967        self.data = {}
1968        for item in (self.data_outputs, self.data_inputs):
1969            self.data.update(item)
1970        self.flag = 1
1971        self.SetSize((300, 200))
1972        self.local_app_selected = None
1973        self.external_app_selected = None
1974        self.save_to_file = None
1975        self._do_layout()
1976
1977    def _do_layout(self):
1978        """
1979        Draw the content of the current dialog window
1980
1981        """
1982
1983        vbox = wx.BoxSizer(wx.VERTICAL)
1984        box_description = wx.StaticBox(self.panel, -1, str("Batch Outputs"))
1985        hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1986        selection_sizer = wx.GridBagSizer(5, 5)
1987        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
1988        text = "Open with %s" % self.parent.application_name
1989        self.local_app_selected = wx.RadioButton(self.panel, -1, text, style=wx.RB_GROUP)
1990        self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
1991                  id=self.local_app_selected.GetId())
1992        text = "Open with Excel"
1993        self.external_app_selected = wx.RadioButton(self.panel, -1, text)
1994        self.Bind(wx.EVT_RADIOBUTTON, self.onselect, id=self.external_app_selected.GetId())
1995        text = "Save to File"
1996        self.save_to_file = wx.CheckBox(self.panel, -1, text)
1997        self.Bind(wx.EVT_CHECKBOX, self.onselect, id=self.save_to_file.GetId())
1998        self.local_app_selected.SetValue(True)
1999        self.external_app_selected.SetValue(False)
2000        self.save_to_file.SetValue(False)
2001        button_close = wx.Button(self.panel, -1, "Close")
2002        button_close.Bind(wx.EVT_BUTTON, id=button_close.GetId(), handler=self.on_close)
2003        button_apply = wx.Button(self.panel, -1, "Apply")
2004        button_apply.Bind(wx.EVT_BUTTON, id=button_apply.GetId(), handler=self.on_apply)
2005        button_apply.SetFocus()
2006        hint = ""
2007        hint_sizer.Add(wx.StaticText(self.panel, -1, hint))
2008        hint_sizer.Add(selection_sizer)
2009        #draw area containing radio buttons
2010        ix = 0
2011        iy = 0
2012        selection_sizer.Add(self.local_app_selected, (iy, ix),
2013                            (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2014        iy += 1
2015        selection_sizer.Add(self.external_app_selected, (iy, ix),
2016                            (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2017        iy += 1
2018        selection_sizer.Add(self.save_to_file, (iy, ix),
2019                            (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2020        #contruction the sizer contaning button
2021        button_sizer.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2022
2023        button_sizer.Add(button_close, 0,
2024                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2025        button_sizer.Add(button_apply, 0,
2026                         wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
2027        vbox.Add(hint_sizer, 0, wx.EXPAND | wx.ALL, 10)
2028        vbox.Add(wx.StaticLine(self.panel, -1), 0, wx.EXPAND, 0)
2029        vbox.Add(button_sizer, 0, wx.TOP | wx.BOTTOM, 10)
2030        self.SetSizer(vbox)
2031
2032    def on_apply(self, event):
2033        """
2034        Get the user selection and display output to the selected application
2035
2036        """
2037
2038        if self.flag == 1:
2039            self.parent.open_with_localapp(data_inputs=self.data_inputs,
2040                                           data_outputs=self.data_outputs)
2041        elif self.flag == 2:
2042            self.parent.open_with_externalapp(data=self.data,
2043                                              file_name=self.file_name,
2044                                              details=self.details)
2045    def on_close(self, event):
2046        """
2047        close the Window
2048
2049        """
2050
2051        self.Close()
2052
2053    def onselect(self, event=None):
2054        """
2055        Receive event and display data into third party application
2056        or save data to file.
2057
2058        """
2059        if self.save_to_file.GetValue():
2060            _, ext = os.path.splitext(self.file_name)
2061            path = None
2062            location = os.getcwd()
2063            if self.parent is not None:
2064                location = os.path.dirname(self.file_name)
2065                dlg = wx.FileDialog(self, "Save Project file",
2066                                    location, self.file_name, ext, wx.SAVE)
2067                path = None
2068                if dlg.ShowModal() == wx.ID_OK:
2069                    path = dlg.GetPath()
2070                dlg.Destroy()
2071                if path != None:
2072                    if self.parent is not None and  self.data is not None:
2073                        self.parent.write_batch_tofile(data=self.data,
2074                                                       file_name=path,
2075                                                       details=self.details)
2076        if self.local_app_selected.GetValue():
2077            self.flag = 1
2078        else:
2079            self.flag = 2
2080        return self.flag
2081
2082
2083
2084if __name__ == "__main__":
2085    app = wx.App()
2086
2087    try:
2088        data = {}
2089        j = 0
2090        for i in range(4):
2091            j += 1
2092            data["index" + str(i)] = [i / j, i * j, i, i + j]
2093
2094        data_input = copy.deepcopy(data)
2095        data_input["index5"] = [10, 20, 40, 50]
2096        frame = GridFrame(data_outputs=data, data_inputs=data_input)
2097        frame.Show(True)
2098    except:
2099        print sys.exc_value
2100
2101    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.