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

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

more fix in grid/output display

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