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

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

fixed a problem with batch fit result display from project file

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