source: sasview/src/sas/guiframe/data_processor.py @ 49ab5d7

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 49ab5d7 was 76aed53, checked in by Doucet, Mathieu <doucetm@…>, 9 years ago

pylint fixes

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