source: sasview/src/sas/guiframe/data_processor.py @ c85b0ae

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

Trying to fix the CSheet problem

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