source: sasview/sansguiframe/src/sans/guiframe/data_processor.py @ 95b513c

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 95b513c was 95b513c, checked in by Jae Cho <jhjcho@…>, 12 years ago

added clear on edit menu

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