source: sasview/src/sas/guiframe/data_processor.py @ 24d3a40

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 24d3a40 was e54dbc3e, checked in by Doucet, Mathieu <doucetm@…>, 10 years ago

Fix cut/paste issue.

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