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

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

batch window: distinguishes non-numeric/empty cells in hightlighed cells

  • Property mode set to 100644
File size: 66.5 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(True)
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, is_number=True):
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 and not is_number:
703                    continue
704                # empty cell
705                if not grid.GetCellValue(row, col).lstrip().rstrip():
706                    if cel in grid.selected_cells:
707                        grid.selected_cells.remove(cel)
708                    continue
709                if is_number:
710                    try: 
711                        float(grid.GetCellValue(row, col))
712                    except:
713                        # non numeric cell
714                        if cel in grid.selected_cells:
715                            grid.selected_cells.remove(cel)
716                        continue
717                if cel not in grid.selected_cells:
718                    grid.selected_cells.append(cel)
719                       
720    def get_column_labels(self):
721        """
722        return dictionary of columns labels of the current page
723        """
724        pos = self.GetSelection()
725        grid = self.GetPage(pos)
726        labels = {}
727        row = 0
728        for col in range(grid.GetNumberCols()):
729            label = grid.GetColLabelValue(int(col))
730            #label = grid.GetCellValue(row, col)
731            if label.strip() != "" :
732                labels[label.strip()] = col
733        return labels
734       
735    def create_axis_label(self, cell_list):
736        """
737        Receive a list of cells and  create a string presenting the selected
738        cells.
739        :param cell_list: list of tuple
740       
741        """
742        pos = self.GetSelection()
743        grid = self.GetPage(pos)
744        label = ""
745        col_name = ""
746        def create_label(col_name,  row_min=None, row_max=None):
747            """
748            """
749            result = " "
750            if row_min is not  None or row_max is not None:
751                if row_min is None:
752                    result = str(row_max) + "]"
753                elif row_max is None:
754                     result = str(col_name) + "[" + str(row_min) + ":"
755                else:
756                    result = str(col_name) +  "[" + str(row_min) + ":"
757                    result += str(row_max) + "]"
758            return str(result)
759           
760        if len(cell_list) > 0:
761            if len(cell_list) == 1:
762                row_min, col  = cell_list[0]   
763                col_name =  grid.GetColLabelValue(int(col))
764                 
765                col_title = grid.GetCellValue(0, col)
766                label = create_label(col_name, row_min+1 , row_min+1)
767                return  label,  col_title
768            else:
769                temp_list = copy.deepcopy(cell_list)
770                temp_list.sort()
771                length = len(temp_list)
772                row_min, col  = temp_list[0]   
773                row_max, _  = temp_list[length-1]
774                col_name = grid.GetColLabelValue(int(col))
775                col_title = grid.GetCellValue(0, col)
776
777                index = 0
778                for row in xrange(row_min, row_max + 1):
779                    if index > 0 and index < len(temp_list):
780                        new_row, _ = temp_list[index]
781                        if row != new_row:
782                            temp_list.insert(index, (None, None))
783                            if index -1 >= 0:
784                                new_row, _ = temp_list[index-1]
785                                if not new_row == None and new_row != ' ' :
786                                    label += create_label(col_name, None, 
787                                                          int(new_row) +1)
788                                else:
789                                    label += "]"
790                                label += ","
791                            if index + 1 < len(temp_list):
792                                new_row, _ = temp_list[index + 1]
793                                if not new_row==None:
794                                    label += create_label(col_name, 
795                                                          int(new_row)+1, None)
796                    if row_min != None and row_max != None:
797                        if index == 0:
798                            label += create_label(col_name, 
799                                                  int(row_min)+1, None)
800                        elif index == len(temp_list)-1:
801                            label += create_label(col_name, None, 
802                                                  int(row_max)+1)
803                    index += 1
804                # clean up the list
805                label_out = ''
806                for item in label.split(','):
807                    if item.split(":")[1] == "]":
808                        continue
809                    else:
810                        label_out += item + ","
811
812                return label_out, col_title
813   
814    def on_close_page(self, event):
815        """
816        close the page
817        """
818        if self.GetPageCount() == 1:
819            event.Veto()
820        wx.CallAfter(self.enable_close_button)
821       
822    def set_data(self, data_inputs, data_outputs, details="", file_name=None):
823        if data_outputs is None or data_outputs == {}:
824            return
825        inputs, outputs = self.get_odered_results(data_inputs, data_outputs)
826        for pos in range(self.GetPageCount()):
827            grid = self.GetPage(pos)
828            if grid.data is None:
829                #Found empty page
830                grid.set_data(data_inputs=inputs, 
831                              data_outputs=outputs,
832                              details=details,
833                              file_name=file_name) 
834                self.SetSelection(pos) 
835                return
836               
837        grid, pos = self.add_empty_page()
838        grid.set_data(data_inputs=inputs, 
839                      data_outputs=outputs,
840                      file_name=file_name,
841                      details=details)
842       
843    def get_odered_results(self, inputs, outputs=None):
844        """
845        Get ordered the results
846        """
847        # Let's re-order the data from the keys in 'Data' name.
848        if outputs == None:
849            return
850        try:
851            # For outputs from batch
852            to_be_sort = [str(item.label) for item in outputs['Data']]
853        except:
854            # When inputs are from an external file
855            return inputs, outputs
856        inds = numpy.lexsort((to_be_sort, to_be_sort))
857        for key in outputs.keys():
858            key_list = outputs[key]
859            temp_key = [item for item in key_list]
860            for ind in inds:
861                temp_key[ind] = key_list[inds[ind]]
862            outputs[key] = temp_key
863        for key in inputs.keys():
864            key_list = inputs[key]
865            if len(key_list) > 0:
866                temp_key = [item for item in key_list]
867                for ind in inds:
868                    temp_key[ind] = key_list[inds[ind]]
869                inputs[key] = temp_key
870        return inputs, outputs
871   
872    def add_column(self):
873        """
874        Append a new column to the grid
875        """
876        pos = self.GetSelection()
877        grid = self.GetPage(pos)
878        grid.AppendCols(1, True)
879       
880    def on_remove_column(self):
881        """
882        Remove the selected column from the grid
883        """
884        pos = self.GetSelection()
885        grid = self.GetPage(pos)
886        grid.on_remove_column(event=None)
887       
888class GridPanel(SPanel):
889    def __init__(self, parent, data_inputs=None,
890                 data_outputs=None, *args, **kwds):
891        SPanel.__init__(self, parent , *args, **kwds)
892       
893        self.vbox = wx.BoxSizer(wx.VERTICAL)
894       
895        self.plotting_sizer = wx.FlexGridSizer(3, 7, 10, 5)
896        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
897        self.grid_sizer = wx.BoxSizer(wx.HORIZONTAL)
898        self.vbox.AddMany([(self.grid_sizer, 1, wx.EXPAND, 0),
899                           (wx.StaticLine(self, -1), 0, wx.EXPAND, 0),
900                           (self.plotting_sizer),
901                           (self.button_sizer, 0, wx.BOTTOM, 10)])
902        self.parent = parent
903        self._data_inputs = data_inputs
904        self._data_outputs = data_outputs
905        self.x = []
906        self.= []
907        self.dy  = []
908        self.x_axis_label = None
909        self.y_axis_label = None
910        self.dy_axis_label = None
911        self.x_axis_title = None
912        self.y_axis_title = None
913        self.x_axis_unit = None
914        self.y_axis_unit = None
915        self.view_button = None
916        self.plot_button = None
917        self.notebook = None
918        self.plot_num = 1
919       
920        self.layout_grid()
921        self.layout_plotting_area()
922        self.SetSizer(self.vbox)
923
924    def set_xaxis(self, label="", x=None):
925        """
926        """
927        if x is None:
928            x = []
929        self.x = x
930        self.x_axis_label.SetValue("%s[:]" % str(label))
931        self.x_axis_title.SetValue(str(label))
932       
933    def set_yaxis(self, label="", y=None):
934        """
935        """
936        if y is None:
937            y = []
938        self.y = y
939        self.y_axis_label.SetValue("%s[:]" % str(label))
940        self.y_axis_title.SetValue(str(label))
941       
942    def set_dyaxis(self, label="", dy=None):
943        """
944        """
945        if dy is None:
946            dy = []
947        self.dy = dy
948        self.dy_axis_label.SetValue("%s[:]" % str(label))
949               
950    def get_plot_axis(self, col, list):
951        """
952       
953        """
954        axis = []
955        pos = self.notebook.GetSelection()
956        grid = self.notebook.GetPage(pos)
957        for row in list:
958            label = grid.GetCellValue(0, col)
959            value = grid.GetCellValue(row - 1, col).strip()
960            if value != "":
961                if label.lower().strip() == "data":
962                    axis.append(float(row - 1))
963                else:
964                    try:
965                        axis.append(float(value))
966                    except:
967                        msg = "Invalid data in row %s column %s" % (str(row),
968                                                                    str(col))
969                        wx.PostEvent(self.parent.parent, 
970                             StatusEvent(status=msg, info="error"))
971                        return None
972            else:
973                axis.append(None) 
974        return axis
975   
976    def on_view(self, event):
977        """
978        Get object represented buy the given cell and plot them.
979        """
980        pos = self.notebook.GetSelection()
981        grid = self.notebook.GetPage(pos)
982        title = self.notebook.GetPageText(pos)
983        self.notebook.get_highlighted_row(False)
984        if len(grid.selected_cells) == 0:
985            msg = "Highlight a Data or Chi2 column first..."
986            wx.PostEvent(self.parent.parent, 
987                             StatusEvent(status=msg, info="error")) 
988            return
989        elif len(grid.selected_cells) > 20:
990            msg = "Too many data (> 20) to plot..."
991            msg += "\n Please select no more than 20 data."
992            dial = wx.MessageDialog(self, msg, 'Plotting', wx.OK)
993            wx.PostEvent(self.parent.parent, 
994                             StatusEvent(status=msg, info="error")) 
995            return
996
997        for cell in grid.selected_cells:
998            row, col = cell
999            label_row = 0
1000            label = grid.GetCellValue(label_row, col)
1001            if label in grid.data:
1002                values = grid.data[label]
1003                if row > len(values) or row < 1:
1004                    msg = "Invalid cell was chosen." 
1005                    wx.PostEvent(self.parent.parent, StatusEvent(status=msg, 
1006                                                                info="error"))
1007                    continue
1008                else:
1009                     value = values[row -1]
1010                if issubclass(value.__class__, BatchCell):
1011                    if value.object is None or len(value.object) == 0:
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, StatusEvent(status=msg, 
1017                                                                info="error")) 
1018                        return
1019                    for new_plot in value.object:
1020                        if new_plot is None or \
1021                         not issubclass(new_plot.__class__, 
1022                                        plottables.Plottable):
1023                            msg = "Row %s , " % str(row)
1024                            msg += "Column %s is NOT " % str(label)
1025                            msg += "the results of fits to view..."
1026                            #raise ValueError, msg
1027                            wx.PostEvent(self.parent.parent, 
1028                                 StatusEvent(status=msg, info="error")) 
1029                            return
1030                            #continue
1031                        #new_plot.name =  title + ': ' + new_plot.title
1032                        if issubclass(new_plot.__class__, Data1D):
1033                            if label in grid.list_plot_panels.keys():
1034                                group_id = grid.list_plot_panels[label]
1035                            else:
1036                                group_id = str(new_plot.group_id) + str(grid.uid)
1037                                grid.list_plot_panels[label] = group_id
1038                            if group_id not in new_plot.list_group_id:
1039                                new_plot.group_id = group_id
1040                                new_plot.list_group_id.append(group_id)
1041                        else:
1042                            if label.lower() in ["data", "chi2"]:
1043                                if len(grid.selected_cells) != 1:
1044                                    msg = "2D View: Please select one data set"
1045                                    msg += " at a time for View Fit Results."
1046                                    wx.PostEvent(self.parent.parent, 
1047                                                 StatusEvent(status=msg,
1048                                                              info="error"))
1049                                    #time.sleep(0.5)
1050                                    return
1051
1052                        wx.PostEvent(self.parent.parent, 
1053                                     NewPlotEvent(plot=new_plot, 
1054                                                group_id=str(new_plot.group_id),
1055                                                title=title)) 
1056                        msg = "Plotting the View Fit Results  completed!"
1057                        wx.PostEvent( self.parent.parent, 
1058                                      StatusEvent(status=msg)) 
1059                else:
1060                   
1061                    msg = "Row %s , " % str(row)
1062                    msg += "Column %s is NOT " % str(label)
1063                    msg += "the results of fits to view..."
1064                    #raise ValueError, msg
1065                    wx.PostEvent(self.parent.parent, 
1066                         StatusEvent(status=msg, info="error")) 
1067                    #time.sleep(0.5)
1068                    return
1069                    #continue
1070   
1071    def on_plot(self, event):
1072        """
1073        Evaluate the contains of textcrtl and plot result
1074        """ 
1075        pos = self.notebook.GetSelection()
1076        grid = self.notebook.GetPage(pos)
1077        column_names = {}
1078        if grid is not None:
1079            column_names = self.notebook.get_column_labels()
1080        #evaluate x
1081        sentence = self.x_axis_label.GetValue()
1082        try:
1083            if sentence.strip() == "":
1084                msg = "Select column values for x axis"
1085                raise ValueError, msg
1086        except:
1087            msg = "X axis value error."
1088            wx.PostEvent(self.parent.parent, 
1089                            StatusEvent(status=msg, info="error")) 
1090            return
1091        dict = parse_string(sentence, column_names.keys())
1092       
1093        try:
1094            sentence = self.get_sentence(dict, sentence, column_names)
1095            x = eval(sentence)
1096        except:
1097            msg = "Need a proper x-range."
1098            wx.PostEvent(self.parent.parent, 
1099                             StatusEvent(status=msg, info="error")) 
1100            return
1101        #evaluate y
1102        sentence = self.y_axis_label.GetValue()
1103        try:
1104            if sentence.strip() == "":
1105                msg = "select value for y axis"
1106                raise ValueError, msg
1107        except:
1108            msg = "Y axis value error."
1109            wx.PostEvent(self.parent.parent, 
1110                            StatusEvent(status=msg, info="error")) 
1111            return
1112        dict = parse_string(sentence, column_names.keys())
1113        try:
1114            sentence = self.get_sentence(dict, sentence, column_names)
1115            y = eval(sentence)
1116        except:
1117            msg = "Need a proper y-range."
1118            wx.PostEvent(self.parent.parent, 
1119                             StatusEvent(status=msg, info="error")) 
1120            return
1121        #evaluate y
1122        sentence = self.dy_axis_label.GetValue()
1123        dy = None
1124        if sentence.strip() != "":
1125            dict = parse_string(sentence, column_names.keys())
1126            sentence = self.get_sentence(dict, sentence, column_names)
1127            try:
1128                dy = eval(sentence)
1129            except:
1130                msg = "Need a proper dy-range."
1131                wx.PostEvent(self.parent.parent, 
1132                                 StatusEvent(status=msg, info="error")) 
1133                return
1134        if len(x) != len(y) or (len(x) == 0 or len(y) == 0):
1135            msg = "Need same length for X and Y axis and both greater than 0"
1136            msg += " to plot.\n"
1137            msg += "Got X length = %s, Y length = %s" % (str(len(x)),
1138                                                          str(len(y)))
1139            wx.PostEvent(self.parent.parent, 
1140                             StatusEvent(status=msg, info="error")) 
1141            return
1142        if dy != None and (len(y) != len(dy)): 
1143            msg = "Need same length for Y and dY axis and both greater than 0"
1144            msg += " to plot.\n"
1145            msg += "Got Y length = %s, dY length = %s" % (str(len(y)),
1146                                                          str(len(dy)))
1147            wx.PostEvent(self.parent.parent, 
1148                             StatusEvent(status=msg, info="error")) 
1149            return
1150        if dy == None:
1151            dy = numpy.zeros(len(y))
1152        #plotting
1153        new_plot = Data1D(x=x, y=y, dy=dy)
1154        new_plot.id =  wx.NewId()
1155        new_plot.is_data = False
1156        new_plot.group_id = wx.NewId()
1157        y_title = self.y_axis_title.GetValue()
1158        x_title = self.x_axis_title.GetValue()
1159        title = "%s_vs_%s" % (y_title, 
1160                              x_title)
1161        new_plot.xaxis(x_title, 
1162                       self.x_axis_unit.GetValue())
1163        new_plot.yaxis(y_title, 
1164                       self.y_axis_unit.GetValue())
1165        try:
1166            title = y_title.strip()
1167           
1168            title += "_" + self.notebook.GetPageText(pos)
1169            title += "_" + str(self.plot_num)
1170            self.plot_num += 1
1171            new_plot.name = title
1172            new_plot.xtransform = "x"
1173            new_plot.ytransform  = "y" 
1174            #new_plot.is_data = False
1175            wx.PostEvent(self.parent.parent, 
1176                        NewPlotEvent(plot=new_plot, 
1177                        group_id=str(new_plot.group_id), title =title)) 
1178            msg = "Plotting completed!"
1179            wx.PostEvent( self.parent.parent, 
1180                                      StatusEvent(status=msg)) 
1181            self.parent.parent.update_theory(data_id=new_plot.id, 
1182                                              theory=new_plot) 
1183        except:
1184             wx.PostEvent(self.parent.parent, 
1185                             StatusEvent(status=msg, info="error")) 
1186   
1187    def get_sentence(self, dict, sentence, column_names):
1188        """
1189        Get sentence from dict
1190        """
1191        for tok, (col_name, list) in dict.iteritems():
1192            col = column_names[col_name]
1193            axis = self.get_plot_axis(col, list)
1194            if axis == None:
1195                return None
1196            sentence = sentence.replace(tok, 
1197                                        "numpy.array(%s)" % str(axis))
1198        for key, value in FUNC_DICT.iteritems():
1199            sentence = sentence.replace(key.lower(), value)
1200        return sentence
1201           
1202    def layout_grid(self):
1203        """
1204        Draw the area related to the grid
1205        """
1206        self.notebook = Notebook(parent=self)
1207        self.notebook.set_data(self._data_inputs, self._data_outputs)
1208        self.grid_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
1209       
1210    def layout_plotting_area(self):
1211        """
1212        Draw area containing options to plot
1213        """
1214        view_description = wx.StaticBox(self, -1, 'Plot Fits/Residuals')
1215        note = "To plot the fits (or residuals), click the 'View Fits' button"
1216        note += "\n after highlighting the Data names (or Chi2 values)."
1217        note_text = wx.StaticText(self, -1, note)
1218        boxsizer1 = wx.StaticBoxSizer(view_description, wx.HORIZONTAL)
1219        self.x_axis_title = wx.TextCtrl(self, -1)
1220        self.y_axis_title = wx.TextCtrl(self, -1)
1221        self.x_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1222        self.y_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1223        self.dy_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
1224        self.x_axis_add = wx.Button(self, -1, "Add")
1225        self.x_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
1226                            id=self.x_axis_add.GetId())
1227        self.y_axis_add = wx.Button(self, -1, "Add")
1228        self.y_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
1229                            id=self.y_axis_add.GetId())
1230        self.dy_axis_add = wx.Button(self, -1, "Add")
1231        self.dy_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
1232                            id=self.dy_axis_add.GetId())
1233        self.x_axis_unit = wx.TextCtrl(self, -1)
1234        self.y_axis_unit = wx.TextCtrl(self, -1)
1235        self.view_button = wx.Button(self, -1, "View Fits")
1236        view_tip = "Highlight the data set or the Chi2 column first."
1237        self.view_button.SetToolTipString(view_tip)
1238        wx.EVT_BUTTON(self, self.view_button.GetId(), self.on_view)
1239        self.plot_button = wx.Button(self, -1, "Plot")
1240        plot_tip = "Highlight a column for each axis and \n"
1241        plot_tip += "click the Add buttons first."
1242       
1243        self.plot_button.SetToolTipString(plot_tip)
1244        boxsizer1.AddMany([(note_text, 0, wx.LEFT, 10),
1245                           (self.view_button, 0, wx.LEFT|wx.RIGHT, 10)])
1246        self.button_sizer.AddMany([(boxsizer1, 0, 
1247                                    wx.LEFT|wx.RIGHT|wx.BOTTOM, 10), 
1248                                   (self.plot_button, 0, 
1249                                    wx.LEFT|wx.TOP|wx.BOTTOM|wx.EXPAND, 12)])
1250       
1251        wx.EVT_BUTTON(self, self.plot_button.GetId(), self.on_plot)
1252        self.plotting_sizer.AddMany([
1253                    (wx.StaticText(self, -1, 
1254                                   "X-axis Label\nSelection Range"), 1,
1255                      wx.TOP|wx.BOTTOM|wx.LEFT, 10),
1256                    (self.x_axis_label, 1, wx.TOP|wx.BOTTOM, 10),
1257                    (self.x_axis_add, 1, wx.TOP|wx.BOTTOM|wx.RIGHT, 10),
1258                    (wx.StaticText(self, -1, "X-axis Label"), 1, 
1259                     wx.TOP|wx.BOTTOM|wx.LEFT, 10),
1260                    (self.x_axis_title, 1, wx.TOP|wx.BOTTOM, 10),
1261                    (wx.StaticText(self, -1 , "X-axis Unit"), 1, 
1262                     wx.TOP|wx.BOTTOM, 10),
1263                    (self.x_axis_unit, 1, wx.TOP|wx.BOTTOM, 10),
1264                    (wx.StaticText(self, -1, 
1265                                   "Y-axis Label\nSelection Range"), 1, 
1266                     wx.BOTTOM|wx.LEFT, 10),
1267                    (self.y_axis_label, wx.BOTTOM, 10),
1268                    (self.y_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
1269                    (wx.StaticText(self, -1, "Y-axis Label"), 1, 
1270                     wx.BOTTOM|wx.LEFT, 10),
1271                    (self.y_axis_title,  wx.BOTTOM, 10),
1272                    (wx.StaticText(self, -1 , "Y-axis Unit"), 1, wx.BOTTOM, 10),
1273                    (self.y_axis_unit, 1, wx.BOTTOM, 10),
1274                    (wx.StaticText(self, -1, 
1275                                   "dY-Bar (Optional)\nSelection Range"), 
1276                                   1, wx.BOTTOM|wx.LEFT, 10),
1277                    (self.dy_axis_label, wx.BOTTOM, 10),
1278                    (self.dy_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
1279                      (-1, -1),
1280                      (-1, -1),
1281                      (-1, -1),
1282                      (-1, -1),
1283                      (-1, -1),
1284                      (-1, -1),
1285                      (-1, 1)])
1286   
1287    def on_edit_axis(self, event):
1288        """
1289        Get the selected column on  the visible grid and set values for axis
1290        """
1291        try:
1292            cell_list = self.notebook.on_edit_axis()
1293            label, title = self.create_axis_label(cell_list)
1294        except:
1295            msg = str(sys.exc_value)
1296            wx.PostEvent(self.parent.parent, 
1297                             StatusEvent(status=msg, info="error")) 
1298            return 
1299        tcrtl = event.GetEventObject()
1300        if tcrtl == self.x_axis_add:
1301            self.edit_axis_helper(self.x_axis_label, self.x_axis_title,
1302                                   label, title)
1303        elif tcrtl == self.y_axis_add:
1304            self.edit_axis_helper(self.y_axis_label, self.y_axis_title,
1305                                   label, title)
1306        elif tcrtl == self.dy_axis_add:
1307            self.edit_axis_helper(self.dy_axis_label, None,
1308                                   label, None)
1309           
1310    def create_axis_label(self, cell_list):
1311        """
1312        Receive a list of cells and  create a string presenting the selected
1313        cells.
1314        :param cell_list: list of tuple
1315       
1316        """
1317        if self.notebook is not None:
1318            return self.notebook.create_axis_label(cell_list)
1319   
1320    def edit_axis_helper(self, tcrtl_label, tcrtl_title, label, title):
1321        """
1322        get controls to modify
1323        """
1324        if label != None:
1325            tcrtl_label.SetValue(str(label))
1326        if title != None:
1327            tcrtl_title.SetValue(str(title))
1328       
1329    def add_column(self):
1330        """
1331        """
1332        if self.notebook is not None:
1333            self.notebook.add_column()
1334       
1335    def on_remove_column(self):
1336        """
1337        """
1338        if self.notebook is not None:
1339            self.notebook.on_remove_column()
1340       
1341       
1342class GridFrame(wx.Frame):
1343    def __init__(self, parent=None, data_inputs=None, data_outputs=None, id=-1, 
1344                 title="Grid Window", size=(800, 500)):
1345        wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
1346        self.parent = parent
1347        self.panel = GridPanel(self, data_inputs, data_outputs)
1348        menubar = wx.MenuBar()
1349        self.SetMenuBar(menubar)
1350       
1351        self.curr_col = None
1352        self.curr_grid = None
1353        self.curr_col_name = ""
1354        self.file = wx.Menu()
1355        menubar.Append(self.file, "&File")
1356       
1357        hint = "Open file containing batch results"
1358        open_menu = self.file.Append(wx.NewId(), 'Open ', hint)
1359        wx.EVT_MENU(self, open_menu.GetId(), self.on_open)
1360       
1361        hint = "Open the the current grid into excel"
1362        self.open_excel_menu = self.file.Append(wx.NewId(), 'Open with Excel', hint)
1363        wx.EVT_MENU(self, self.open_excel_menu.GetId(), self.open_with_excel)
1364        self.file.AppendSeparator()
1365        self.save_menu = self.file.Append(wx.NewId(), 'Save As', 'Save into File')
1366        wx.EVT_MENU(self, self.save_menu.GetId(), self.on_save_page)
1367       
1368        self.edit = wx.Menu()
1369       
1370        add_table_menu = self.edit.Append(-1, 'New Table', 
1371                                          'Add a New Table')
1372        self.edit.AppendSeparator()
1373        wx.EVT_MENU(self, add_table_menu.GetId(), self.add_table)
1374       
1375        self.copy_menu = self.edit.Append(-1, 'Copy', 
1376                                          'Copy the selected cells')
1377        wx.EVT_MENU(self, self.copy_menu.GetId(), self.on_copy)
1378        self.paste_menu = self.edit.Append(-1, 'Paste', 
1379                                           'Paste the selected Cells')
1380        wx.EVT_MENU(self, self.paste_menu.GetId(), self.on_paste)
1381        self.clear_menu = self.edit.Append(-1, 'Clear', 
1382                                           'Clear the selected Cells')
1383        wx.EVT_MENU(self, self.clear_menu.GetId(), self.on_clear)
1384
1385        self.edit.AppendSeparator()
1386        hint = "Insert column before the selected column"
1387        self.insert_before_menu = wx.Menu()
1388        self.insertb_sub_menu = self.edit.AppendSubMenu(self.insert_before_menu, 
1389                                                      'Insert Before', hint)
1390        hint = "Insert column after the selected column"
1391        self.insert_after_menu = wx.Menu()
1392        self.inserta_sub_menu = self.edit.AppendSubMenu(self.insert_after_menu, 
1393                                                      'Insert After', hint)
1394        hint = "Remove the selected column"
1395        self.remove_menu = self.edit.Append(-1, 'Remove Column', hint)
1396        wx.EVT_MENU(self, self.remove_menu.GetId(), self.on_remove_column)
1397       
1398        self.Bind(wx.EVT_MENU_OPEN, self.on_menu_open)
1399        menubar.Append(self.edit, "&Edit")
1400        self.Bind(wx.EVT_CLOSE, self.on_close)
1401   
1402    def on_copy(self, event):
1403        """
1404        On Copy
1405        """
1406        if event != None:
1407            event.Skip()
1408        pos = self.panel.notebook.GetSelection()
1409        grid = self.panel.notebook.GetPage(pos)
1410        grid.Copy()
1411       
1412    def on_paste(self, event):
1413        """
1414        On Paste
1415        """
1416        if event != None:
1417            event.Skip()
1418        pos = self.panel.notebook.GetSelection()
1419        grid = self.panel.notebook.GetPage(pos)
1420        grid.on_paste(None)
1421
1422    def on_clear(self, event):
1423        """
1424        On Clear
1425        """
1426        pos = self.panel.notebook.GetSelection()
1427        grid = self.panel.notebook.GetPage(pos)
1428        grid.Clear()
1429     
1430    def GetLabelText(self, id):
1431        """
1432        Get Label Text
1433        """
1434        for item in self.insert_before_menu.GetMenuItems():
1435            m_id = item.GetId() 
1436            if m_id == id:
1437                return item.GetLabel() 
1438   
1439    def on_remove_column(self, event):
1440        """
1441        On remove column
1442        """
1443        pos = self.panel.notebook.GetSelection()
1444        grid = self.panel.notebook.GetPage(pos)
1445        grid.on_remove_column(event=None)
1446       
1447    def on_menu_open(self, event):
1448        """
1449        On menu open
1450        """
1451        if self.file == event.GetMenu():
1452            pos = self.panel.notebook.GetSelection()
1453            grid = self.panel.notebook.GetPage(pos)
1454            has_data = (grid.data != None and grid.data != {})
1455            self.open_excel_menu.Enable(has_data) 
1456            self.save_menu.Enable(has_data) 
1457           
1458        if self.edit == event.GetMenu():
1459            #get the selected column
1460            pos = self.panel.notebook.GetSelection()
1461            grid = self.panel.notebook.GetPage(pos)
1462            col_list = grid.GetSelectedCols()
1463            has_selection = False
1464            selected_cel = grid.selected_cells
1465            if len(selected_cel) > 0:
1466                _row, _col = selected_cel[0]
1467                has_selection = grid.IsInSelection(_row, _col)
1468            if len(grid.selected_cols) > 0:
1469                has_selection = True
1470            if len(grid.selected_rows) > 0:
1471                has_selection = True
1472            self.copy_menu.Enable(has_selection)
1473            self.clear_menu.Enable(has_selection)
1474       
1475            if len(col_list) > 0:
1476                self.remove_menu.Enable(True)
1477            else:
1478                self.remove_menu.Enable(False)
1479            if len(col_list) == 0 or len(col_list) > 1:
1480                self.insertb_sub_menu.Enable(False)
1481                self.inserta_sub_menu.Enable(False)
1482                label = "Insert Column Before"
1483                self.insertb_sub_menu.SetText(label)
1484                label = "Insert Column After"
1485                self.inserta_sub_menu.SetText(label)
1486            else:
1487                self.insertb_sub_menu.Enable(True)
1488                self.inserta_sub_menu.Enable(True)
1489               
1490                col = col_list[0]
1491                col_name = grid.GetCellValue(row=0, col=col)
1492                label = "Insert Column Before " + str(col_name)
1493                self.insertb_sub_menu.SetText(label)
1494                for item in self.insert_before_menu.GetMenuItems():
1495                    self.insert_before_menu.DeleteItem(item)
1496                grid.insert_col_menu(menu=self.insert_before_menu, 
1497                                     label=col_name, window=self)
1498                label = "Insert Column After " + str(col_name)
1499                self.inserta_sub_menu.SetText(label)
1500                for item in self.insert_after_menu.GetMenuItems():
1501                    self.insert_after_menu.DeleteItem(item)
1502                grid.insert_after_col_menu(menu=self.insert_after_menu, 
1503                                     label=col_name, window=self)
1504        event.Skip()
1505       
1506 
1507       
1508    def on_save_page(self, event):
1509        """
1510        """
1511        if self.parent is not None:
1512            pos = self.panel.notebook.GetSelection()
1513            grid = self.panel.notebook.GetPage(pos)
1514            if grid.file_name is None or grid.file_name.strip() == "" or \
1515                grid.data is None or len(grid.data) == 0:
1516                name = self.panel.notebook.GetPageText(pos)
1517                msg = " %s has not data to save" % str(name)
1518                wx.PostEvent(self.parent, 
1519                             StatusEvent(status=msg, info="error")) 
1520           
1521                return
1522            reader, ext = os.path.splitext(grid.file_name)
1523            path = None
1524            if self.parent is not None: 
1525                location = os.path.dirname(grid.file_name)
1526                dlg = wx.FileDialog(self, "Save Project file",
1527                            location, grid.file_name, ext, wx.SAVE)
1528                path = None
1529                if dlg.ShowModal() == wx.ID_OK:
1530                    path = dlg.GetPath()
1531                dlg.Destroy()
1532                if path != None:
1533                    if self.parent is not None:
1534                        data = grid.get_grid_view()
1535                        self.parent.write_batch_tofile(data=data, 
1536                                               file_name=path,
1537                                               details=grid.details)
1538   
1539    def on_open(self, event):
1540        """
1541        Open file containg batch result
1542        """
1543        if self.parent is not None:
1544            self.parent.on_read_batch_tofile(self)
1545           
1546    def open_with_excel(self, event):
1547        """
1548        open excel and display batch result in Excel
1549        """
1550        if self.parent is not None:
1551            pos = self.panel.notebook.GetSelection()
1552            grid = self.panel.notebook.GetPage(pos)
1553            data = grid.get_grid_view()
1554            if grid.file_name is None or grid.file_name.strip() == "" or \
1555                grid.data is None or len(grid.data) == 0:
1556                name = self.panel.notebook.GetPageText(pos)
1557                msg = " %s has not data to open on excel" % str(name)
1558                wx.PostEvent(self.parent, 
1559                             StatusEvent(status=msg, info="error")) 
1560           
1561                return
1562            self.parent.open_with_externalapp(data=data,
1563                                              file_name=grid.file_name, 
1564                                              details=grid.details)
1565           
1566    def on_close(self, event):
1567        """
1568        """
1569        self.Hide()
1570       
1571    def on_append_column(self, event):
1572        """
1573        Append a new column to the grid
1574        """
1575        self.panel.add_column()
1576       
1577    def set_data(self, data_inputs, data_outputs, details="", file_name=None):
1578        """
1579        Set data
1580        """
1581        self.panel.notebook.set_data(data_inputs=data_inputs, 
1582                            file_name=file_name,
1583                            details=details,
1584                            data_outputs=data_outputs)
1585
1586    def add_table(self, event):
1587        """
1588        Add a new table
1589        """
1590        # DO not event.Skip(): it will make 2 pages
1591        self.panel.notebook.add_empty_page()     
1592     
1593class BatchOutputFrame(wx.Frame):
1594    """
1595    Allow to select where the result of batch will be displayed or stored
1596    """
1597    def __init__(self, parent, data_inputs, data_outputs, file_name="",
1598                 details="", *args, **kwds):
1599        """
1600        :param parent: Window instantiating this dialog
1601        :param result: result to display in a grid or export to an external
1602                application.
1603        """
1604        #kwds['style'] = wx.CAPTION|wx.SYSTEM_MENU
1605        wx.Frame.__init__(self, parent, *args, **kwds)
1606        self.parent = parent
1607        self.panel = wx.Panel(self)
1608        self.file_name = file_name
1609        self.details = details
1610        self.data_inputs = data_inputs
1611        self.data_outputs = data_outputs
1612        self.data = {}
1613        for item in (self.data_outputs, self.data_inputs):
1614            self.data.update(item)
1615        self.flag = 1
1616        self.SetSize((300, 200))
1617        self.local_app_selected = None
1618        self.external_app_selected = None
1619        self.save_to_file = None
1620        self._do_layout()
1621   
1622    def _do_layout(self):
1623        """
1624        Draw the content of the current dialog window
1625        """
1626        vbox = wx.BoxSizer(wx.VERTICAL)
1627        box_description = wx.StaticBox(self.panel, -1, str("Batch Outputs"))
1628        hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1629        selection_sizer = wx.GridBagSizer(5, 5)
1630        button_sizer = wx.BoxSizer(wx.HORIZONTAL)
1631        text = "Open with %s" % self.parent.application_name
1632        self.local_app_selected = wx.RadioButton(self.panel, -1, text,
1633                                                style=wx.RB_GROUP)
1634        self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
1635                    id=self.local_app_selected.GetId())
1636        text = "Open with Excel"
1637        self.external_app_selected  = wx.RadioButton(self.panel, -1, text)
1638        self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
1639                    id=self.external_app_selected.GetId())
1640        text = "Save to File"
1641        self.save_to_file = wx.CheckBox(self.panel, -1, text)
1642        self.Bind(wx.EVT_CHECKBOX, self.onselect,
1643                    id=self.save_to_file.GetId())
1644        self.local_app_selected.SetValue(True)
1645        self.external_app_selected.SetValue(False)
1646        self.save_to_file.SetValue(False)
1647        button_close = wx.Button(self.panel, -1, "Close")
1648        button_close.Bind(wx.EVT_BUTTON, id=button_close.GetId(),
1649                           handler=self.on_close)
1650        button_apply = wx.Button(self.panel, -1, "Apply")
1651        button_apply.Bind(wx.EVT_BUTTON, id=button_apply.GetId(),
1652                        handler=self.on_apply)
1653        button_apply.SetFocus()
1654        hint = ""
1655        hint_sizer.Add(wx.StaticText(self.panel, -1, hint))
1656        hint_sizer.Add(selection_sizer)
1657        #draw area containing radio buttons
1658        ix = 0
1659        iy = 0
1660        selection_sizer.Add(self.local_app_selected, (iy, ix),
1661                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1662        iy += 1
1663        selection_sizer.Add(self.external_app_selected, (iy, ix),
1664                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1665        iy += 1
1666        selection_sizer.Add(self.save_to_file, (iy, ix),
1667                           (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1668        #contruction the sizer contaning button
1669        button_sizer.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1670
1671        button_sizer.Add(button_close, 0,
1672                        wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1673        button_sizer.Add(button_apply, 0,
1674                                wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
1675        vbox.Add(hint_sizer, 0, wx.EXPAND|wx.ALL, 10)
1676        vbox.Add(wx.StaticLine(self.panel, -1),  0, wx.EXPAND, 0)
1677        vbox.Add(button_sizer, 0, wx.TOP|wx.BOTTOM, 10)
1678        self.SetSizer(vbox)
1679       
1680    def on_apply(self, event):
1681        """
1682        Get the user selection and display output to the selected application
1683        """
1684        if self.flag == 1:
1685            self.parent.open_with_localapp(data_inputs=self.data_inputs,
1686                                           data_outputs=self.data_outputs)
1687        elif self.flag == 2:
1688            self.parent.open_with_externalapp(data=self.data, 
1689                                              file_name=self.file_name,
1690                                              details=self.details)
1691    def on_close(self, event):
1692        """
1693        close the Window
1694        """
1695        self.Close()
1696       
1697    def onselect(self, event=None):
1698        """
1699        Receive event and display data into third party application
1700        or save data to file.
1701       
1702        """
1703        if self.save_to_file.GetValue():
1704            reader, ext = os.path.splitext(self.file_name)
1705            path = None
1706            location = os.getcwd()
1707            if self.parent is not None: 
1708                location = os.path.dirname(self.file_name)
1709                dlg = wx.FileDialog(self, "Save Project file",
1710                            location, self.file_name, ext, wx.SAVE)
1711                path = None
1712                if dlg.ShowModal() == wx.ID_OK:
1713                    path = dlg.GetPath()
1714                dlg.Destroy()
1715                if path != None:
1716                    if self.parent is not None and  self.data is not None:
1717                        self.parent.write_batch_tofile(data=self.data, 
1718                                                       file_name=path,
1719                                                       details=self.details)
1720        if self.local_app_selected.GetValue():
1721            self.flag = 1
1722        else:
1723            self.flag = 2
1724        return self.flag
1725   
1726 
1727       
1728if __name__ == "__main__":
1729    app = wx.App()
1730   
1731    try:
1732        data = {}
1733        j = 0
1734        for i in range(4):
1735            j += 1
1736            data["index"+str(i)] = [i/j, i*j, i, i+j]
1737       
1738        data_input =  copy.deepcopy(data)   
1739        data_input["index5"] = [10, 20, 40, 50]
1740        frame = GridFrame(data_outputs=data, data_inputs=data_input)
1741        frame.Show(True)
1742    except:
1743        print sys.exc_value
1744       
1745    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.