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

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

small fix in insert menus

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