source: sasview/src/sas/sasgui/guiframe/data_processor.py @ a67c494

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since a67c494 was 7432acb, checked in by andyfaff, 8 years ago

MAINT: search+replace '!= None' by 'is not None'

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