source: sasview/src/sans/guiframe/data_processor.py @ f468791

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 f468791 was f468791, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Move plottools under sans

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