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

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 cf8e119 was fce0139, checked in by smk78, 9 years ago

Changed relative path to BatchGridClassLayout?.png to resolve Sphinx
build error

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