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

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 74c5521 was 74c5521, checked in by smk78, 8 years ago

Fixing docstring errors

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