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

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

the data in the grid copied from datainfo can now be in data operation

  • Property mode set to 100644
File size: 66.0 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 = 3001
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        if dy == None:
1140            dy = numpy.zeros(len(y))
1141        #plotting
1142        new_plot = Data1D(x=x, y=y, dy=dy)
1143        new_plot.id =  wx.NewId()
1144        new_plot.is_data = False
1145        new_plot.group_id = wx.NewId()
1146        y_title = self.y_axis_title.GetValue()
1147        x_title = self.x_axis_title.GetValue()
1148        title = "%s_vs_%s" % (y_title, 
1149                              x_title)
1150        new_plot.xaxis(x_title, 
1151                       self.x_axis_unit.GetValue())
1152        new_plot.yaxis(y_title, 
1153                       self.y_axis_unit.GetValue())
1154        try:
1155            title = y_title.strip()
1156           
1157            title += "_" + self.notebook.GetPageText(pos)
1158            title += "_" + str(self.plot_num)
1159            self.plot_num += 1
1160            new_plot.name = title
1161            new_plot.xtransform = "x"
1162            new_plot.ytransform  = "y" 
1163            #new_plot.is_data = False
1164            wx.PostEvent(self.parent.parent, 
1165                        NewPlotEvent(plot=new_plot, 
1166                        group_id=str(new_plot.group_id), title =title)) 
1167            msg = "Plotting completed!"
1168            wx.PostEvent( self.parent.parent, 
1169                                      StatusEvent(status=msg)) 
1170            self.parent.parent.update_theory(data_id=new_plot.id, 
1171                                              theory=new_plot) 
1172        except:
1173             wx.PostEvent(self.parent.parent, 
1174                             StatusEvent(status=msg, info="error")) 
1175   
1176    def get_sentence(self, dict, sentence, column_names):
1177        """
1178        Get sentence from dict
1179        """
1180        for tok, (col_name, list) in dict.iteritems():
1181            col = column_names[col_name]
1182            axis = self.get_plot_axis(col, list)
1183            if axis == None:
1184                return None
1185            sentence = sentence.replace(tok, 
1186                                        "numpy.array(%s)" % str(axis))
1187        for key, value in FUNC_DICT.iteritems():
1188            sentence = sentence.replace(key.lower(), value)
1189        return sentence
1190           
1191    def layout_grid(self):
1192        """
1193        Draw the area related to the grid
1194        """
1195        self.notebook = Notebook(parent=self)
1196        self.notebook.set_data(self._data_inputs, self._data_outputs)
1197        self.grid_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
1198       
1199    def layout_plotting_area(self):
1200        """
1201        Draw area containing options to plot
1202        """
1203        view_description = wx.StaticBox(self, -1, 'Plot Fits/Residuals')
1204        note = "To plot the fits (or residuals), click the 'View Fits' button"
1205        note += "\n after highlighting the Data names (or Chi2 values)."
1206        note_text = wx.StaticText(self, -1, note)
1207        boxsizer1 = wx.StaticBoxSizer(view_description, wx.HORIZONTAL)
1208        self.x_axis_title = wx.TextCtrl(self, -1)
1209        self.y_axis_title = wx.TextCtrl(self, -1)
1210        self.x_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1211        self.y_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1212        self.dy_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1213        self.x_axis_add = wx.Button(self, -1, "Add")
1214        self.x_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
1215                            id=self.x_axis_add.GetId())
1216        self.y_axis_add = wx.Button(self, -1, "Add")
1217        self.y_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
1218                            id=self.y_axis_add.GetId())
1219        self.dy_axis_add = wx.Button(self, -1, "Add")
1220        self.dy_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
1221                            id=self.dy_axis_add.GetId())
1222        self.x_axis_unit = wx.TextCtrl(self, -1)
1223        self.y_axis_unit = wx.TextCtrl(self, -1)
1224        self.view_button = wx.Button(self, -1, "View Fits")
1225        view_tip = "Highlight the data set or the Chi2 column first."
1226        self.view_button.SetToolTipString(view_tip)
1227        wx.EVT_BUTTON(self, self.view_button.GetId(), self.on_view)
1228        self.plot_button = wx.Button(self, -1, "Plot")
1229        plot_tip = "Highlight a column for each axis and \n"
1230        plot_tip += "click the Add buttons first."
1231       
1232        self.plot_button.SetToolTipString(plot_tip)
1233        boxsizer1.AddMany([(note_text, 0, wx.LEFT, 10),
1234                           (self.view_button, 0, wx.LEFT|wx.RIGHT, 10)])
1235        self.button_sizer.AddMany([(boxsizer1, 0, 
1236                                    wx.LEFT|wx.RIGHT|wx.BOTTOM, 10), 
1237                                   (self.plot_button, 0, 
1238                                    wx.LEFT|wx.TOP|wx.BOTTOM|wx.EXPAND, 12)])
1239       
1240        wx.EVT_BUTTON(self, self.plot_button.GetId(), self.on_plot)
1241        self.plotting_sizer.AddMany([
1242                    (wx.StaticText(self, -1, 
1243                                   "X-axis Label\nSelection Range"), 1,
1244                      wx.TOP|wx.BOTTOM|wx.LEFT, 10),
1245                    (self.x_axis_label, 1, wx.TOP|wx.BOTTOM, 10),
1246                    (self.x_axis_add, 1, wx.TOP|wx.BOTTOM|wx.RIGHT, 10),
1247                    (wx.StaticText(self, -1, "X-axis Label"), 1, 
1248                     wx.TOP|wx.BOTTOM|wx.LEFT, 10),
1249                    (self.x_axis_title, 1, wx.TOP|wx.BOTTOM, 10),
1250                    (wx.StaticText(self, -1 , "X-axis Unit"), 1, 
1251                     wx.TOP|wx.BOTTOM, 10),
1252                    (self.x_axis_unit, 1, wx.TOP|wx.BOTTOM, 10),
1253                    (wx.StaticText(self, -1, 
1254                                   "Y-axis Label\nSelection Range"), 1, 
1255                     wx.BOTTOM|wx.LEFT, 10),
1256                    (self.y_axis_label, wx.BOTTOM, 10),
1257                    (self.y_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
1258                    (wx.StaticText(self, -1, "Y-axis Label"), 1, 
1259                     wx.BOTTOM|wx.LEFT, 10),
1260                    (self.y_axis_title,  wx.BOTTOM, 10),
1261                    (wx.StaticText(self, -1 , "Y-axis Unit"), 1, wx.BOTTOM, 10),
1262                    (self.y_axis_unit, 1, wx.BOTTOM, 10),
1263                    (wx.StaticText(self, -1, 
1264                                   "dY-Bar (Optional)\nSelection Range"), 
1265                                   1, wx.BOTTOM|wx.LEFT, 10),
1266                    (self.dy_axis_label, wx.BOTTOM, 10),
1267                    (self.dy_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
1268                      (-1, -1),
1269                      (-1, -1),
1270                      (-1, -1),
1271                      (-1, -1),
1272                      (-1, -1),
1273                      (-1, -1),
1274                      (-1, 1)])
1275   
1276    def on_edit_axis(self, event):
1277        """
1278        Get the selected column on  the visible grid and set values for axis
1279        """
1280        try:
1281            cell_list = self.notebook.on_edit_axis()
1282        except:
1283            msg = str(sys.exc_value)
1284            wx.PostEvent(self.parent.parent, 
1285                             StatusEvent(status=msg, info="error")) 
1286            return 
1287        label, title = self.create_axis_label(cell_list)
1288        tcrtl = event.GetEventObject()
1289        if tcrtl == self.x_axis_add:
1290            self.edit_axis_helper(self.x_axis_label, self.x_axis_title,
1291                                   label, title)
1292        elif tcrtl == self.y_axis_add:
1293            self.edit_axis_helper(self.y_axis_label, self.y_axis_title,
1294                                   label, title)
1295        elif tcrtl == self.dy_axis_add:
1296            self.edit_axis_helper(self.dy_axis_label, None,
1297                                   label, None)
1298           
1299    def create_axis_label(self, cell_list):
1300        """
1301        Receive a list of cells and  create a string presenting the selected
1302        cells.
1303        :param cell_list: list of tuple
1304       
1305        """
1306        if self.notebook is not None:
1307            return self.notebook.create_axis_label(cell_list)
1308   
1309    def edit_axis_helper(self, tcrtl_label, tcrtl_title, label, title):
1310        """
1311        get controls to modify
1312        """
1313        if label != None:
1314            tcrtl_label.SetValue(str(label))
1315        if title != None:
1316            tcrtl_title.SetValue(str(title))
1317       
1318    def add_column(self):
1319        """
1320        """
1321        if self.notebook is not None:
1322            self.notebook.add_column()
1323       
1324    def on_remove_column(self):
1325        """
1326        """
1327        if self.notebook is not None:
1328            self.notebook.on_remove_column()
1329       
1330       
1331class GridFrame(wx.Frame):
1332    def __init__(self, parent=None, data_inputs=None, data_outputs=None, id=-1, 
1333                 title="Grid Window", size=(800, 500)):
1334        wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
1335        self.parent = parent
1336        self.panel = GridPanel(self, data_inputs, data_outputs)
1337        menubar = wx.MenuBar()
1338        self.SetMenuBar(menubar)
1339       
1340        self.curr_col = None
1341        self.curr_grid = None
1342        self.curr_col_name = ""
1343        self.file = wx.Menu()
1344        menubar.Append(self.file, "&File")
1345       
1346        hint = "Open file containing batch results"
1347        open_menu = self.file.Append(wx.NewId(), 'Open ', hint)
1348        wx.EVT_MENU(self, open_menu.GetId(), self.on_open)
1349       
1350        hint = "Open the the current grid into excel"
1351        self.open_excel_menu = self.file.Append(wx.NewId(), 'Open with Excel', hint)
1352        wx.EVT_MENU(self, self.open_excel_menu.GetId(), self.open_with_excel)
1353        self.file.AppendSeparator()
1354        self.save_menu = self.file.Append(wx.NewId(), 'Save As', 'Save into File')
1355        wx.EVT_MENU(self, self.save_menu.GetId(), self.on_save_page)
1356       
1357        self.edit = wx.Menu()
1358       
1359        add_table_menu = self.edit.Append(-1, 'New Table', 
1360                                          'Add a New Table')
1361        self.edit.AppendSeparator()
1362        wx.EVT_MENU(self, add_table_menu.GetId(), self.add_table)
1363       
1364        self.copy_menu = self.edit.Append(-1, 'Copy', 
1365                                          'Copy the selected cells')
1366        wx.EVT_MENU(self, self.copy_menu.GetId(), self.on_copy)
1367        self.paste_menu = self.edit.Append(-1, 'Paste', 
1368                                           'Paste the selected Cells')
1369        wx.EVT_MENU(self, self.paste_menu.GetId(), self.on_paste)
1370        self.clear_menu = self.edit.Append(-1, 'Clear', 
1371                                           'Clear the selected Cells')
1372        wx.EVT_MENU(self, self.clear_menu.GetId(), self.on_clear)
1373
1374        self.edit.AppendSeparator()
1375        hint = "Insert column before the selected column"
1376        self.insert_before_menu = wx.Menu()
1377        self.insertb_sub_menu = self.edit.AppendSubMenu(self.insert_before_menu, 
1378                                                      'Insert Before', hint)
1379        hint = "Insert column after the selected column"
1380        self.insert_after_menu = wx.Menu()
1381        self.inserta_sub_menu = self.edit.AppendSubMenu(self.insert_after_menu, 
1382                                                      'Insert After', hint)
1383        hint = "Remove the selected column"
1384        self.remove_menu = self.edit.Append(-1, 'Remove Column', hint)
1385        wx.EVT_MENU(self, self.remove_menu.GetId(), self.on_remove_column)
1386       
1387        self.Bind(wx.EVT_MENU_OPEN, self.on_menu_open)
1388        menubar.Append(self.edit, "&Edit")
1389        self.Bind(wx.EVT_CLOSE, self.on_close)
1390   
1391    def on_copy(self, event):
1392        """
1393        On Copy
1394        """
1395        if event != None:
1396            event.Skip()
1397        pos = self.panel.notebook.GetSelection()
1398        grid = self.panel.notebook.GetPage(pos)
1399        grid.Copy()
1400       
1401    def on_paste(self, event):
1402        """
1403        On Paste
1404        """
1405        if event != None:
1406            event.Skip()
1407        pos = self.panel.notebook.GetSelection()
1408        grid = self.panel.notebook.GetPage(pos)
1409        grid.on_paste(None)
1410
1411    def on_clear(self, event):
1412        """
1413        On Clear
1414        """
1415        pos = self.panel.notebook.GetSelection()
1416        grid = self.panel.notebook.GetPage(pos)
1417        grid.Clear()
1418     
1419    def GetLabelText(self, id):
1420        """
1421        Get Label Text
1422        """
1423        for item in self.insert_before_menu.GetMenuItems():
1424            m_id = item.GetId() 
1425            if m_id == id:
1426                return item.GetLabel() 
1427   
1428    def on_remove_column(self, event):
1429        """
1430        On remove column
1431        """
1432        pos = self.panel.notebook.GetSelection()
1433        grid = self.panel.notebook.GetPage(pos)
1434        grid.on_remove_column(event=None)
1435       
1436    def on_menu_open(self, event):
1437        """
1438        On menu open
1439        """
1440        if self.file == event.GetMenu():
1441            pos = self.panel.notebook.GetSelection()
1442            grid = self.panel.notebook.GetPage(pos)
1443            has_data = (grid.data != None and grid.data != {})
1444            self.open_excel_menu.Enable(has_data) 
1445            self.save_menu.Enable(has_data) 
1446           
1447        if self.edit == event.GetMenu():
1448            #get the selected column
1449            pos = self.panel.notebook.GetSelection()
1450            grid = self.panel.notebook.GetPage(pos)
1451            col_list = grid.GetSelectedCols()
1452            has_selection = False
1453            selected_cel = grid.selected_cells
1454            if len(selected_cel) > 0:
1455                _row, _col = selected_cel[0]
1456                has_selection = grid.IsInSelection(_row, _col)
1457            if len(grid.selected_cols) > 0:
1458                has_selection = True
1459            if len(grid.selected_rows) > 0:
1460                has_selection = True
1461            self.copy_menu.Enable(has_selection)
1462            self.clear_menu.Enable(has_selection)
1463       
1464            if len(col_list) > 0:
1465                self.remove_menu.Enable(True)
1466            else:
1467                self.remove_menu.Enable(False)
1468            if len(col_list) == 0 or len(col_list) > 1:
1469                self.insertb_sub_menu.Enable(False)
1470                self.inserta_sub_menu.Enable(False)
1471                label = "Insert Column Before"
1472                self.insertb_sub_menu.SetText(label)
1473                label = "Insert Column After"
1474                self.inserta_sub_menu.SetText(label)
1475            else:
1476                self.insertb_sub_menu.Enable(True)
1477                self.inserta_sub_menu.Enable(True)
1478               
1479                col = col_list[0]
1480                col_name = grid.GetCellValue(row=0, col=col)
1481                label = "Insert Column Before " + str(col_name)
1482                self.insertb_sub_menu.SetText(label)
1483                for item in self.insert_before_menu.GetMenuItems():
1484                    self.insert_before_menu.DeleteItem(item)
1485                grid.insert_col_menu(menu=self.insert_before_menu, 
1486                                     label=col_name, window=self)
1487                label = "Insert Column After " + str(col_name)
1488                self.inserta_sub_menu.SetText(label)
1489                for item in self.insert_after_menu.GetMenuItems():
1490                    self.insert_after_menu.DeleteItem(item)
1491                grid.insert_after_col_menu(menu=self.insert_after_menu, 
1492                                     label=col_name, window=self)
1493        event.Skip()
1494       
1495 
1496       
1497    def on_save_page(self, event):
1498        """
1499        """
1500        if self.parent is not None:
1501            pos = self.panel.notebook.GetSelection()
1502            grid = self.panel.notebook.GetPage(pos)
1503            if grid.file_name is None or grid.file_name.strip() == "" or \
1504                grid.data is None or len(grid.data) == 0:
1505                name = self.panel.notebook.GetPageText(pos)
1506                msg = " %s has not data to save" % str(name)
1507                wx.PostEvent(self.parent, 
1508                             StatusEvent(status=msg, info="error")) 
1509           
1510                return
1511            reader, ext = os.path.splitext(grid.file_name)
1512            path = None
1513            if self.parent is not None: 
1514                location = os.path.dirname(grid.file_name)
1515                dlg = wx.FileDialog(self, "Save Project file",
1516                            location, grid.file_name, ext, wx.SAVE)
1517                path = None
1518                if dlg.ShowModal() == wx.ID_OK:
1519                    path = dlg.GetPath()
1520                dlg.Destroy()
1521                if path != None:
1522                    if self.parent is not None:
1523                        data = grid.get_grid_view()
1524                        self.parent.write_batch_tofile(data=data, 
1525                                               file_name=path,
1526                                               details=grid.details)
1527   
1528    def on_open(self, event):
1529        """
1530        Open file containg batch result
1531        """
1532        if self.parent is not None:
1533            self.parent.on_read_batch_tofile(self)
1534           
1535    def open_with_excel(self, event):
1536        """
1537        open excel and display batch result in Excel
1538        """
1539        if self.parent is not None:
1540            pos = self.panel.notebook.GetSelection()
1541            grid = self.panel.notebook.GetPage(pos)
1542            data = grid.get_grid_view()
1543            if grid.file_name is None or grid.file_name.strip() == "" or \
1544                grid.data is None or len(grid.data) == 0:
1545                name = self.panel.notebook.GetPageText(pos)
1546                msg = " %s has not data to open on excel" % str(name)
1547                wx.PostEvent(self.parent, 
1548                             StatusEvent(status=msg, info="error")) 
1549           
1550                return
1551            self.parent.open_with_externalapp(data=data,
1552                                              file_name=grid.file_name, 
1553                                              details=grid.details)
1554           
1555    def on_close(self, event):
1556        """
1557        """
1558        self.Hide()
1559       
1560    def on_append_column(self, event):
1561        """
1562        Append a new column to the grid
1563        """
1564        self.panel.add_column()
1565       
1566    def set_data(self, data_inputs, data_outputs, details="", file_name=None):
1567        """
1568        Set data
1569        """
1570        self.panel.notebook.set_data(data_inputs=data_inputs, 
1571                            file_name=file_name,
1572                            details=details,
1573                            data_outputs=data_outputs)
1574
1575    def add_table(self, event):
1576        """
1577        Add a new table
1578        """
1579        # DO not event.Skip(): it will make 2 pages
1580        self.panel.notebook.add_empty_page()     
1581     
1582class BatchOutputFrame(wx.Frame):
1583    """
1584    Allow to select where the result of batch will be displayed or stored
1585    """
1586    def __init__(self, parent, data_inputs, data_outputs, file_name="",
1587                 details="", *args, **kwds):
1588        """
1589        :param parent: Window instantiating this dialog
1590        :param result: result to display in a grid or export to an external
1591                application.
1592        """
1593        #kwds['style'] = wx.CAPTION|wx.SYSTEM_MENU
1594        wx.Frame.__init__(self, parent, *args, **kwds)
1595        self.parent = parent
1596        self.panel = wx.Panel(self)
1597        self.file_name = file_name
1598        self.details = details
1599        self.data_inputs = data_inputs
1600        self.data_outputs = data_outputs
1601        self.data = {}
1602        for item in (self.data_outputs, self.data_inputs):
1603            self.data.update(item)
1604        self.flag = 1
1605        self.SetSize((300, 200))
1606        self.local_app_selected = None
1607        self.external_app_selected = None
1608        self.save_to_file = None
1609        self._do_layout()
1610   
1611    def _do_layout(self):
1612        """
1613        Draw the content of the current dialog window
1614        """
1615        vbox = wx.BoxSizer(wx.VERTICAL)
1616        box_description = wx.StaticBox(self.panel, -1, str("Batch Outputs"))
1617        hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1618        selection_sizer = wx.GridBagSizer(5, 5)
1619        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
1620        text = "Open with %s" % self.parent.application_name
1621        self.local_app_selected = wx.RadioButton(self.panel, -1, text,
1622                                                style=wx.RB_GROUP)
1623        self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
1624                    id=self.local_app_selected.GetId())
1625        text = "Open with Excel"
1626        self.external_app_selected  = wx.RadioButton(self.panel, -1, text)
1627        self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
1628                    id=self.external_app_selected.GetId())
1629        text = "Save to File"
1630        self.save_to_file = wx.CheckBox(self.panel, -1, text)
1631        self.Bind(wx.EVT_CHECKBOX, self.onselect,
1632                    id=self.save_to_file.GetId())
1633        self.local_app_selected.SetValue(True)
1634        self.external_app_selected.SetValue(False)
1635        self.save_to_file.SetValue(False)
1636        button_close = wx.Button(self.panel, -1, "Close")
1637        button_close.Bind(wx.EVT_BUTTON, id=button_close.GetId(),
1638                           handler=self.on_close)
1639        button_apply = wx.Button(self.panel, -1, "Apply")
1640        button_apply.Bind(wx.EVT_BUTTON, id=button_apply.GetId(),
1641                        handler=self.on_apply)
1642        button_apply.SetFocus()
1643        hint = ""
1644        hint_sizer.Add(wx.StaticText(self.panel, -1, hint))
1645        hint_sizer.Add(selection_sizer)
1646        #draw area containing radio buttons
1647        ix = 0
1648        iy = 0
1649        selection_sizer.Add(self.local_app_selected, (iy, ix),
1650                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1651        iy += 1
1652        selection_sizer.Add(self.external_app_selected, (iy, ix),
1653                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1654        iy += 1
1655        selection_sizer.Add(self.save_to_file, (iy, ix),
1656                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1657        #contruction the sizer contaning button
1658        button_sizer.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1659
1660        button_sizer.Add(button_close, 0,
1661                        wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1662        button_sizer.Add(button_apply, 0,
1663                                wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
1664        vbox.Add(hint_sizer, 0, wx.EXPAND|wx.ALL, 10)
1665        vbox.Add(wx.StaticLine(self.panel, -1),  0, wx.EXPAND, 0)
1666        vbox.Add(button_sizer, 0, wx.TOP|wx.BOTTOM, 10)
1667        self.SetSizer(vbox)
1668       
1669    def on_apply(self, event):
1670        """
1671        Get the user selection and display output to the selected application
1672        """
1673        if self.flag == 1:
1674            self.parent.open_with_localapp(data_inputs=self.data_inputs,
1675                                           data_outputs=self.data_outputs)
1676        elif self.flag == 2:
1677            self.parent.open_with_externalapp(data=self.data, 
1678                                              file_name=self.file_name,
1679                                              details=self.details)
1680    def on_close(self, event):
1681        """
1682        close the Window
1683        """
1684        self.Close()
1685       
1686    def onselect(self, event=None):
1687        """
1688        Receive event and display data into third party application
1689        or save data to file.
1690       
1691        """
1692        if self.save_to_file.GetValue():
1693            reader, ext = os.path.splitext(self.file_name)
1694            path = None
1695            location = os.getcwd()
1696            if self.parent is not None: 
1697                location = os.path.dirname(self.file_name)
1698                dlg = wx.FileDialog(self, "Save Project file",
1699                            location, self.file_name, ext, wx.SAVE)
1700                path = None
1701                if dlg.ShowModal() == wx.ID_OK:
1702                    path = dlg.GetPath()
1703                dlg.Destroy()
1704                if path != None:
1705                    if self.parent is not None and  self.data is not None:
1706                        self.parent.write_batch_tofile(data=self.data, 
1707                                                       file_name=path,
1708                                                       details=self.details)
1709        if self.local_app_selected.GetValue():
1710            self.flag = 1
1711        else:
1712            self.flag = 2
1713        return self.flag
1714   
1715 
1716       
1717if __name__ == "__main__":
1718    app = wx.App()
1719   
1720    try:
1721        data = {}
1722        j = 0
1723        for i in range(4):
1724            j += 1
1725            data["index"+str(i)] = [i/j, i*j, i, i+j]
1726       
1727        data_input =  copy.deepcopy(data)   
1728        data_input["index5"] = [10, 20, 40, 50]
1729        frame = GridFrame(data_outputs=data, data_inputs=data_input)
1730        frame.Show(True)
1731    except:
1732        print sys.exc_value
1733       
1734    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.