source: sasview/src/sas/guiframe/data_processor.py @ 56e99f9

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 56e99f9 was 56e99f9, checked in by butler, 9 years ago

add help button to batch Grid Panel

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