#!/usr/bin/env python
# -*- coding: utf-8 -*-
# generated by wxGlade 0.6 on Sun May 25 23:31:23 2008

# Copyright 2008 Martin Manns
# Distributed under the terms of the GNU General Public License
# generated by wxGlade 0.6 on Mon Mar 17 23:22:49 2008

# --------------------------------------------------------------------
# pyspread is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyspread is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyspread.  If not, see <http://www.gnu.org/licenses/>.
# --------------------------------------------------------------------


"""
_windows
========

Provides:
---------
  1. MainWindow: Main window of the application pyspread

"""

import bz2
import os
import csv
import cPickle as pickle
import sys
import types

import wx
import wx.grid
import wx.lib.printout as printout

import pyspread._widgets as _widgets
from pyspread._choicebars import MainMenu, MainToolbar
from pyspread._dialogs import MacroDialog, CsvImportDialog, CsvExportDialog, \
                       DimensionsEntryDialog, AboutDialog
from pyspread._interfaces import CsvInterfaces, string_match, bzip_dump
from pyspread.config import ICONPREFIX, icon_size, KEYFUNCTIONS


class MainWindow(wx.Frame):
    """Main window of pyspread
    
    Parameters:
    -----------
    dimensions: 3-tuple of int, defaults to (100, 100, 1)
    \tDimensions of the grid
    
    """
    def __init__(self, *args, **kwds):
        try:
            dim = kwds.pop("dimensions")
        except:
            dim = (1000, 100, 1)
        self.wildcard = "Pyspread file (*.pys)|*.pys|"     \
                        "All files (*.*)|*.*"
        
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        
        # Menu Bar
        self.main_window_menubar = wx.MenuBar()
        self.main_menu = MainMenu(parent=self, menubar=self.main_window_menubar)
        self.SetMenuBar(self.main_window_menubar)
        
        # Status bar
        self.main_window_statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
        
        # Tool Bar
        self.main_window_toolbar = MainToolbar(self, -1)
        self.SetToolBar(self.main_window_toolbar)
        self._add_combo() # Combo box in toolbar
        
        # Main grid
        self.MainGrid = _widgets.MainGrid(self, -1, size=(1, 1), dim=dim, \
            set_statustext=self.main_window_statusbar.SetStatusText,\
            cbox_Z = self.cbox_Z)
        
        self._set_properties()
        self._do_layout()
        
        self.Bind(wx.EVT_FIND, self.OnFind)
        self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
        self.Bind(wx.EVT_FIND_REPLACE, self.OnFind)
        self.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind)
        self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
        self.Bind(wx.EVT_TEXT, self.MainGrid.OnCombo, id=self.cbID)
        self.Bind(wx.EVT_COMBOBOX, self.MainGrid.OnCombo, id=self.cbID)
        wx.EVT_KEY_DOWN(self.MainGrid, self.OnKey)
        
        # Misc
        self.MainGrid.mainwindow = self
        self.MainGrid.deletion_imminent = False
        self.filepath = None # No file loaded yet
    
    def _set_properties(self):
        self.SetTitle("pyspread")
        _icon = wx.EmptyIcon()
        _icon.CopyFromBitmap(wx.Bitmap(ICONPREFIX+'icons/pyspread.png', \
                             wx.BITMAP_TYPE_ANY))
        self.SetIcon(_icon)
        self.SetSize((1000, 700))
        self.main_window_statusbar.SetStatusWidths([-1])
        
        # statusbar fields
        main_window_statusbar_fields = [""]
        for i in range(len(main_window_statusbar_fields)):
            self.main_window_statusbar.SetStatusText( \
                            main_window_statusbar_fields[i], i)
        self.main_window_toolbar.SetToolBitmapSize(icon_size)
        self.main_window_toolbar.SetMargins((1, 1))
        self.main_window_toolbar.Realize()
        # end wxGlade
        self.MainGrid.create_rowcol()
    
    def _do_layout(self):
        # begin wxGlade: MainWindow._do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.VERTICAL)
        grid_sizer_2 = wx.FlexGridSizer(1, 1, 0, 0)
        sizer_3.Add(self.MainGrid.entry_line, 0, wx.EXPAND, 0)
        grid_sizer_2.Add(self.MainGrid, 0, wx.EXPAND, 0)
        grid_sizer_2.AddGrowableRow(0)
        grid_sizer_2.AddGrowableCol(0)
        sizer_3.Add(grid_sizer_2, 1, wx.EXPAND, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()
        # end wxGlade
    
    def _add_combo(self):
        """Choicebox for the Z choice of the worksheet"""
        self.cbID = wx.NewId()
        self.cbox_Z = wx.ComboBox(self.main_window_toolbar, self.cbID, "0", \
                      size=(icon_size[0]*2, icon_size[1]-4), \
                      style=wx.CB_DROPDOWN)
        
        self.main_window_toolbar.AddControl(self.cbox_Z)
        
        self.main_window_toolbar.Realize()
    
    def OnNotImplemented(self, event):
        """All not implemented functions point here"""
        
        self.main_window_statusbar.SetStatusText("Not implemented")
        event.Skip()
    
    def OnKey(self, event):
        """
        Additional key behavior if not already in menu
        
        The method parses the key representation and calls the respective
        function for the defined keys. It relies on the KEYFUNCTIONS dict in
        config.py and on self.key_modifier_methods. Note that menu defined keys
        are not evaluated.
        
        """
        
        # Key modifier event methods
        kmm = {'Ctrl': 'event.ControlDown()', \
               'not_Ctrl': 'not event.ControlDown()', \
               'Shift': 'event.ShiftDown()', \
               'not_Shift': 'not event.ShiftDown()'}
        
        for keystr, funcstr in KEYFUNCTIONS.iteritems():
            ks = keystr.split('+')
            actkey = ks.pop() # Actual unmodified key in KEYFUNCTIONS
            evtmeths = [kmm[modifier] for modifier in ks]
            evtmeths += [" == ".join(["event.GetKeyCode()", repr(ord(actkey))])]
            evtmeths_string = " and ".join(evtmeths)
            if eval(evtmeths_string):
                funccallstr = "".join(["self.", funcstr, "()"])
                eval(funccallstr)
        
        # Skip other Key events
        if event.GetKeyCode():
            event.Skip()
    
    def _confirm_largegrid(self, dim):
        """
        Asks on large grid dimensions
        
        Returns True if grid not large or large grid accepted.
        Returns False otherwise
        
        Parameters
        ----------
        dim: n-tuple of int > 0
        \tDimensions of an n-dim grid
        
        """
        no_gridcells = reduce(lambda x, y: x*y, dim)
        if no_gridcells > 1E6:
            dlg = wx.MessageDialog(self, 'The grid has ' + \
                unicode(no_gridcells) + ' cells.\n' + \
                'You may run out of memory.\n' + \
                'Do you want to continue?',
                'Memory alert',
                wx.OK | wx.CANCEL | wx.ICON_INFORMATION)
            
            res = dlg.ShowModal()
            dlg.Destroy()
            
            if res != wx.ID_OK:
                return False
        return True
    
    def OnFileNew(self, event):
        """Creates a new grid and destroys the old one"""
        
        dim_dialog = DimensionsEntryDialog(self)
        if dim_dialog.ShowModal() != wx.ID_OK:
            dim_dialog.Destroy()
            return False
        
        dim_dialog.Destroy()
        
        dimensions = tuple(dim_dialog.dimensions)
        
        if not self._confirm_largegrid(dimensions):
            return False
        
        self.Destroy()
        self = MainWindow(None, dimensions=dimensions)
        self.Show()
        
        self.MainGrid.pysgrid.unredo.reset()
        event.Skip()
    
    def OnFileOpen(self, event): # wxGlade: MainWindow.<event_handler>
        dlg = wx.FileDialog(
            self, message="Choose a file", defaultDir=os.getcwd(),
            defaultFile="", wildcard=self.wildcard, \
            style=wx.OPEN | wx.CHANGE_DIR)
        if dlg.ShowModal() == wx.ID_OK:
            self.filepath = dlg.GetPath()
            self.MainGrid.loadfile(self.filepath)
            self.MainGrid.OnCombo(event)
        dlg.Hide()
        dlg.Destroy()
        event.Skip()
    
    def OnFileSave(self, event):
        """Saves an existing file"""
        
        if self.filepath is None:
            self.OnFileSaveAs(event)
        else:
            bzip_dump(self.MainGrid.pysgrid.sgrid, self.filepath)
        event.Skip()
    
    def OnFileSaveAs(self, event):
        """Opens the file dialog and saves the file to the chosen location"""
        
        dlg = wx.FileDialog( \
            self, message="Save file as ...", defaultDir=os.getcwd(), \
            defaultFile="", wildcard=self.wildcard, style=wx.SAVE)
        
        if dlg.ShowModal() == wx.ID_OK:
            self.filepath = dlg.GetPath()
            bzip_dump(self.MainGrid.pysgrid.sgrid, self.filepath)
        
        dlg.Hide()
        dlg.Destroy()
        
        event.Skip()
    
    
    def OnFileImport(self, event): # wxGlade: MainWindow.<event_handler>
        """Imports files. Currently only CSV files supported"""
        
        # File choice
        try:
            path, filterindex = self._getfilename( \
                    message="Import file", \
                    defaultDir=os.getcwd(), \
                    defaultFile="", \
                    wildcard=" CSV file|*.*|Tab-delimited text file|*.*", \
                    style=wx.OPEN | wx.CHANGE_DIR)
        except TypeError:
            return 0
        
        csvfilename = os.path.split(path)[1]
        
        # CSV import option choice
        try:
            filterdlg = CsvImportDialog(self, csvfilepath=path)
        except csv.Error, err:
            dlg = wx.MessageDialog(self, \
                'The file "' + csvfilename + '" does not seem to be ' + \
                'a valid CSV file.\n \nOpening it yielded the error:\n' + \
                str(err), \
                'Error opening CSV file', \
                style=wx.ID_CANCEL)
            dlg.ShowModal()
            dlg.Destroy()
            event.Skip()
            return False
        
        # Get target types
        if filterindex == 0:
            if filterdlg.ShowModal() == wx.ID_OK:
                dialect, has_header = filterdlg.csvwidgets.get_dialect()
                digest_types = filterdlg.grid.dtypes
            else:
                filterdlg.Destroy()
                return 0
        elif filterindex == 1:
            dialect = csv.get_dialect('excel-tab')
            digest_types = [types.StringType]
            has_header = False
        
        filterdlg.Destroy()
        
        # The actual data import
        csv_interface = CsvInterfaces(path, dialect, digest_types, has_header)
        topleftcell = tuple(list(self.MainGrid.get_currentcell()) + \
                            [self.MainGrid.current_table])
        try:
            csv_interface.read(self.MainGrid.pysgrid, key=topleftcell)
        except ValueError, err:
            dlg = wx.MessageDialog(self, \
                'The file "' + csvfilename + '" has only been loaded ' + \
                'partly. \n \nError message:\n' + \
                str(err), \
                'Error reading CSV file', \
                style=wx.ID_OK)
            dlg.ShowModal()
            dlg.Destroy()
        self.MainGrid.update_grid(funceval=True, gridslice=None)
        event.Skip()
    
    def OnFileExport(self, event):
        """Exports files. Currently only CSV files supported"""
        
        # Get Selection --> iterable
        selection = self.MainGrid.get_selection()
        if len(selection) == 1:
            slice_x, slice_y = self.MainGrid.get_visiblecell_slice()[:2]
            selection = [(x, y) for x in xrange(slice_x.start, slice_x.stop)
                                for y in xrange(slice_y.start, slice_y.stop)]
        
        rowslice, colslice = self.MainGrid.get_selected_rows_cols(selection)
        data = self.MainGrid.getselectiondata(self.MainGrid.pysgrid, \
                                    rowslice, colslice, omittedfield_repr=' ')
                                    
        # Get CSV export options via dialog
        filterdlg = CsvExportDialog(self, data=data)
        
        if filterdlg.ShowModal() == wx.ID_OK:
            dialect, has_header = filterdlg.csvwidgets.get_dialect()
            digest_types = [types.StringType]
        else:
            filterdlg.Destroy()
            return 0
        
        filterdlg.Destroy()
        
        # Get target file path
        
        path = None
        try:
            path, filterindex = self._getfilename( \
                    message="Export file", \
                    defaultDir=os.getcwd(), \
                    defaultFile="", \
                    wildcard=" CSV file|*.*", \
                    style=wx.OPEN | wx.CHANGE_DIR)
        
        except TypeError:
            return 0
            
        #csvfilename = os.path.split(path)[1]
        
        # Export file
        csv_interface = CsvInterfaces(path, dialect, digest_types, has_header)
        try:
            csv_interface.write(data)
        except IOError, err:
            dlg = wx.MessageDialog(self, \
                'The file "' + csvfilename + '" could not be fully written ' + \
                '\n \nError message:\n' + \
                str(err), \
                'Error writing CSV file', \
                style=wx.ID_OK)
            dlg.ShowModal()
            dlg.Destroy()
        event.Skip()
    
    def OnFilePrint(self, event):
        """Prints the current selection or current screen if no selection"""
        
        selection = self.MainGrid.get_selection()
        if len(selection) == 1:
            slice_x, slice_y = self.MainGrid.get_visiblecell_slice()[:2]
            selection = [(x, y) for x in xrange(slice_x.start, slice_x.stop)
                                for y in xrange(slice_y.start, slice_y.stop)]
        #print selection
        rowslice, colslice = self.MainGrid.get_selected_rows_cols(selection)
        data = self.MainGrid.getselectiondata(self.MainGrid.pysgrid, \
                                              rowslice, colslice, \
                                              omittedfield_repr=' ')
        prt = printout.PrintTable(self)
        prt.data = data
        prt.Preview()
        event.Skip()
    
    def OnExit(self, event):
        """Exit program"""
        
        sys.exit()
        event.Skip()
    
    def OnCut(self, event): 
        """Cut from main grid to clipboard"""
        
        self.MainGrid.cut()
        self.MainGrid.pysgrid.unredo.mark()
        event.Skip()
    
    def OnCopy(self, event):
        """Copy from main grid to clipboard"""
        
        self.MainGrid.copy(source=self.MainGrid.pysgrid.sgrid)
        self.MainGrid.pysgrid.unredo.mark()
        event.Skip()
    
    def OnCopyResult(self, event):
        """Copy results from main grid to clipboard"""
        
        self.MainGrid.copy(source=self.MainGrid.pysgrid)
        self.MainGrid.pysgrid.unredo.mark()
        event.Skip()
    
    def OnPaste(self, event):
        """Paste from clipboard to main grid"""
        
        self.MainGrid.paste()
        self.MainGrid.pysgrid.unredo.mark()
        event.Skip()
    
    def OnAbout(self, event):
        """Launches about dialog"""
        
        about_dialog = AboutDialog(self)
        about_dialog.ShowModal()
        about_dialog.Destroy()
        event.Skip()
    
    def OnInsertRows(self, event): # wxGlade: MainWindow.<event_handler>
        """Insert the maximum of 1 and the number of selected rows"""
        self.MainGrid.insert_selected_rows()
        event.Skip()
    
    def OnInsertColumns(self, event): # wxGlade: MainWindow.<event_handler>
        """Inserts the maximum of 1 and the number of selected columns """
        self.MainGrid.insert_selected_cols()
        event.Skip()
    
    def OnInsertTable(self, event): # wxGlade: MainWindow.<event_handler>
        """Insert one table into MainGrid and pysgrid """
        self.MainGrid.insert_selected_tables()
        event.GetString = lambda x=0: unicode(self.MainGrid.current_table)
        self.MainGrid.OnCombo(event)
        event.Skip()
    
    def OnDeleteRows(self, event): # wxGlade: MainWindow.<event_handler>
        """Deletes rows from all tables of the grid"""
        
        self.MainGrid.delete_selected_rows()
        event.Skip()
    
    def OnDeleteColumns(self, event): # wxGlade: MainWindow.<event_handler>
        """Deletes columnss from all tables of the grid"""
        
        self.MainGrid.delete_selected_cols()
        event.Skip()
    
    def OnDeleteTable(self, event): # wxGlade: MainWindow.<event_handler>
        """Deletes tables"""
        
        self.MainGrid.delete_selected_tables()
        event.GetString = lambda x=0: \
              unicode(max(0, self.MainGrid.current_table, \
                         self.MainGrid.pysgrid.sgrid.shape[2]-1))
        self.MainGrid.OnCombo(event)
        event.Skip()
    
    def OnResizeGrid(self, event):
        """Resizes current grid by appending/deleting rows, cols and tables"""
        
        dim_dialog = DimensionsEntryDialog(self)
        if dim_dialog.ShowModal() != wx.ID_OK:
            dim_dialog.Destroy()
            return False
        
        dim_dialog.Destroy()
        
        dimensions = tuple(dim_dialog.dimensions)
        
        #print dimensions
        
        if not self._confirm_largegrid(dimensions):
            return False
        
        # Check for each dimension, how many items are inserted or deleted
        dim_diff = [dimensions[i] - self.MainGrid.pysgrid.shape[i] \
                        for i in xrange(3)]
                        
        #print dim_diff
        
        for dim, diff in enumerate(dim_diff):
            self.MainGrid.change_dim(dim, diff)
        
        #print self.MainGrid.pysgrid.shape
        
        self.MainGrid.pysgrid.unredo.reset()
    
    def _getfilename(self, message, defaultDir=os.getcwd(), defaultFile="", \
                     wildcard=" Any file|*.*", style=wx.OPEN | wx.CHANGE_DIR):
        """Spawns a wx.FileDialog and returns filename"""
        
        filedlg = wx.FileDialog(self, message=message, defaultDir=defaultDir, \
                       defaultFile=defaultFile, wildcard=wildcard, style=style)
        if filedlg.ShowModal() == wx.ID_OK:
            path = filedlg.GetPath()
        else:
            path = None
        filedlg.Destroy()
        
        try:
            filename = os.path.split(path)[1]
        except AttributeError:
            return None
        
        return filename, filedlg.GetFilterIndex()
    
    def OnMacroList(self, event):
        """Invokes the MacroDialog and updates the macros in the app"""
        
        dlg = MacroDialog(None, -1, "", macros = self.MainGrid.pysgrid.macros)
        if dlg.ShowModal() == wx.ID_OK:
            # Insert function string into current cell
            targetcell = self.MainGrid.get_currentcell()
            macrostring = dlg.GetMacroString()
            try:
                self.MainGrid.entry_line.SetValue(macrostring)
            except TypeError:
                self.MainGrid.entry_line.SetValue("")
            self.MainGrid.pysgrid[targetcell] = macrostring
            self.MainGrid.update_grid(funceval=True)
        self.MainGrid.pysgrid.macros = dlg.macros
        self.MainGrid.pysgrid.set_global_macros(self.MainGrid.pysgrid.macros)
        dlg.Destroy()
        self.MainGrid.update_grid()
        event.Skip()
    
    def OnMacroListLoad(self, event): # wxGlade: MainWindow.<event_handler>
        macrowildcard = " Macro file|*.*"
        # File choice
        filedlg = wx.FileDialog(
            self, message="Load a Macro-file", defaultDir=os.getcwd(),
            defaultFile="", wildcard=macrowildcard, \
            style=wx.OPEN | wx.CHANGE_DIR)
        if filedlg.ShowModal() == wx.ID_OK:
            path = filedlg.GetPath()
            filedlg.Destroy()
        macrocodes = {}
        infile = bz2.BZ2File(path, "r")
        macrocodes = pickle.load(infile)
        infile.close()
        #print macrocodes
        for macroname in macrocodes:
            self.MainGrid.pysgrid.macros.add(macrocodes[macroname])
        self.MainGrid.pysgrid.set_global_macros()
        event.Skip()
    
    def OnMacroListSave(self, event): # wxGlade: MainWindow.<event_handler>
        macrowildcard = " Macro file|*.*"
        # File choice
        filedlg = wx.FileDialog(
            self, message="Save a Macro-file", defaultDir=os.getcwd(),
            defaultFile="", wildcard=macrowildcard, \
            style=wx.OPEN | wx.CHANGE_DIR)
        if filedlg.ShowModal() == wx.ID_OK:
            path = filedlg.GetPath()
            filedlg.Destroy()
        macros = self.MainGrid.pysgrid.macros
        macrocodes = dict((m, macros[m].func_dict['macrocode']) for m in macros)
        
        bzip_dump(macrocodes, path)
        
        event.Skip()
    
    def OnFind(self, event): # wxGlade: MainWindow.<event_handler>
        """Find functionality should be in interfaces"""
        
        newstring = ""
        wx_map = { wx.wxEVT_COMMAND_FIND : "FIND",
                   wx.wxEVT_COMMAND_FIND_NEXT : "FIND_NEXT",
                   wx.wxEVT_COMMAND_FIND_REPLACE : "REPLACE",
                   wx.wxEVT_COMMAND_FIND_REPLACE_ALL : "REPLACE_ALL" }
        wx_flags = { 0: ["UP", ],
                     1: ["DOWN"],
                     2: ["UP", "WHOLE_WORD"],
                     3: ["DOWN", "WHOLE_WORD"],
                     4: ["UP", "MATCH_CASE"],
                     5: ["DOWN", "MATCH_CASE"],
                     6: ["UP", "WHOLE_WORD", "MATCH_CASE"],
                     7: ["DOWN", "WHOLE_WORD", "MATCH_CASE"] }
        et = event.GetEventType()
        ef = event.GetFlags()
        try:
            event_type = wx_map[et]
            event_flags = wx_flags[ef]
        except KeyError:
            self.main_window_statusbar.SetStatusText("Unknown event type " + \
                                       "or flag:" + unicode(et) + unicode(ef))
            return 0
        event_find_string = event.GetFindString()
        event_replace_string = event.GetReplaceString()
        
        findpos = self.MainGrid.pysgrid.findnextmatch(self.MainGrid.key, \
                                            event_find_string, event_flags)
        if event_type in ["FIND", "FIND_NEXT", "REPLACE"]:
            if findpos is not None:
                self.MainGrid.selectnewcell(findpos, event)
                self.main_window_statusbar.SetStatusText("Found '" + \
                                 event_find_string +  "' in cell " + \
                                 unicode(list(findpos)) + ".", 0)
            else:
                self.main_window_statusbar.SetStatusText("'" + \
                                 event_find_string + "' not found.", 0)
        if event_type in ["REPLACE", "REPLACE_ALL"]:
            noreplaced = 0
            while findpos is not None:
                noreplaced += 1
                cellstring = self.MainGrid.pysgrid.sgrid[findpos]
                string_position = string_match(cellstring, \
                                    event_find_string, event_flags)
                newstring = cellstring[:string_position]
                newstring += cellstring[string_position:].replace(\
                                       event_find_string, \
                                       event_replace_string, 1)
                self.MainGrid.pysgrid[findpos] = newstring
                if event_type == "REPLACE":
                    self.main_window_statusbar.SetStatusText("'" +
                                 cellstring + "' replaced by '" + \
                                 newstring + "'.", 0)
                    break
                elif event_type == "REPLACE_ALL":
                    findpos = self.MainGrid.pysgrid.findnextmatch( \
                                 findpos, event_find_string, event_flags)
                else:
                    raise ValueError, "Event type " + event_type + " unknown."
            
            self.MainGrid.update_grid(funceval=True)
            self.MainGrid.pysgrid.unredo.mark()
            
            if event_type == "REPLACE_ALL":
                self.main_window_statusbar.SetStatusText(unicode(noreplaced) + \
                                 " occurrences of '" + event_find_string + \
                                 "' replaced by '" +  event_replace_string + \
                                 "'.", 0)
            else:
                self.MainGrid.entry_line.SetValue(newstring)
        event.Skip()
    
    def OnFindClose(self, event): # wxGlade: MainWindow.<event_handler>
        event.GetDialog().Destroy()
        self.main_window_statusbar.SetStatusText("", 0)
        self.MainGrid.update_grid(funceval=True)
        event.Skip()
    
    def OnUndo(self, event): # wxGlade: MainWindow.<event_handler>
        self.MainGrid.undo()
        event.Skip()
    
    def OnRedo(self, event): # wxGlade: MainWindow.<event_handler>
        self.MainGrid.redo()
        event.Skip()
    
    def OnShowFind(self, event): # wxGlade: MainWindow.<event_handler>
        data = wx.FindReplaceData()
        dlg = wx.FindReplaceDialog(self, data, "Find")
        dlg.data = data  # save a reference to it...
        dlg.Show(True)
        event.Skip()
    
    def OnShowFindReplace(self, event): # wxGlade: MainWindow.<event_handler>
        data = wx.FindReplaceData()
        dlg = wx.FindReplaceDialog(self, data, "Find & Replace", \
                                   wx.FR_REPLACEDIALOG)
        dlg.data = data  # save a reference to it...
        dlg.Show(True)
        event.Skip()

# end of class MainWindow
