#!/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/>.
# --------------------------------------------------------------------

"""
_dialogs
========

Provides:
---------
  1. CsvImportDialog: Dialog for CSV parameter choice
  2. MacroDialog: Dialog for macro management
  3. DimensionsEntryDialog
  4. AboutDialog
  
"""

import csv

import wx
import wx.lib.mixins.listctrl  as  listmix

from _widgets import IndexGrid, SortedListCtrl, MacroEditPanel
from _interfaces import CsvImport
from _datastructures import Macros
from config import DEBUG, VERSION, LIBPREFIX, icon_size, icons

class CsvImportDialog(wx.Dialog):
    """Dialog for CSV parameter choicewith preview grid
    
    Parameters:
    -----------
    csvfilepath: string, defaults to '.'
    \tPath and Filename of CSV input file
    
    """
    def __init__(self, *args, **kwds):
        try:
            self.csvfilepath = kwds.pop("csvfilepath")
        except KeyError:
            self.csvfilepath = '.'
        # begin wxGlade: CsvImportDialog.__init__
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.THICK_FRAME
        wx.Dialog.__init__(self, *args, **kwds)
        self.label_delimiter = wx.StaticText(self, -1, "Delimiter")
        self.text_ctrl_delimiter = wx.TextCtrl(self, -1, "")
        self.label_skipinitialspace = wx.StaticText(self, -1, "Skip initial space")
        self.checkbox_skipinitialspace = wx.CheckBox(self, -1, "")
        self.label_escapechar = wx.StaticText(self, -1, "Escape character")
        self.text_ctrl_escapechar = wx.TextCtrl(self, -1, "")
        self.label_doublequote = wx.StaticText(self, -1, "Doublequote")
        self.checkbox_doublequote = wx.CheckBox(self, -1, "")
        self.label_quotechar = wx.StaticText(self, -1, "Quote character")
        self.text_ctrl_quotechar = wx.TextCtrl(self, -1, "")
        self.panel_1 = wx.Panel(self, -1)
        self.panel_2 = wx.Panel(self, -1)
        self.csv_test_grid = IndexGrid(self, -1, size=(1, 1))
        self.button_cancel = wx.Button(self, wx.ID_CANCEL, "")
        self.button_apply = wx.Button(self, wx.ID_APPLY, "")
        self.button_ok = wx.Button(self, wx.ID_OK, "")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_BUTTON, self.OnButtonApply, self.button_apply)
        # end wxGlade
        self.griddimension = (10, 10) 
        self.csv_test_grid.CreateGrid(self.griddimension[0], self.griddimension[1])
        self.csv_test_grid.SetRowLabelSize(0)
        self.csv_test_grid.SetColLabelSize(0)
        self.csv_test_grid.EnableEditing(0)
        self.csv_test_grid.EnableDragGridSize(0)
        self.dlgwidgets = {'delimiter': self.text_ctrl_delimiter, \
                           'skipinitialspace': self.checkbox_skipinitialspace, \
                           'escapechar': self.text_ctrl_escapechar, \
                           'doublequote': self.checkbox_doublequote, \
                           'quotechar': self.text_ctrl_quotechar}

    def __set_properties(self):
        # begin wxGlade: CsvImportDialog.__set_properties
        self.SetTitle("CSV Import")
        self.SetSize((410, 598))
        self.SetToolTipString("When True, whitespace immediately following the delimiter is ignored. The default is False.")
        self.label_delimiter.SetToolTipString("A one-character string used to separate fields. It defaults to ','.")
        self.text_ctrl_delimiter.SetMinSize((25, 25))
        self.text_ctrl_delimiter.SetToolTipString("A one-character string used to separate fields. It defaults to ','.")
        self.text_ctrl_delimiter.SetFocus()
        self.checkbox_skipinitialspace.SetToolTipString("When True, whitespace immediately following the delimiter is ignored. The default is False.")
        self.label_escapechar.SetToolTipString("A one-character string used by the writer to escape the delimiter if quoting is set to QUOTE_NONE and the quotechar if doublequote is False. On reading, the escapechar removes any special meaning from the following character. It defaults to None, which disables escaping.")
        self.text_ctrl_escapechar.SetMinSize((25, 25))
        self.text_ctrl_escapechar.SetToolTipString("A one-character string used by the writer to escape the delimiter if quoting is set to QUOTE_NONE and the quotechar if doublequote is False. On reading, the escapechar removes any special meaning from the following character. It defaults to None, which disables escaping.")
        self.label_doublequote.SetToolTipString("Controls how instances of quotechar appearing inside a field should be themselves be quoted. When True, the character is doubled. When False, the escapechar is used as a prefix to the quotechar. It defaults to True.")
        self.checkbox_doublequote.SetToolTipString("Controls how instances of quotechar appearing inside a field should be themselves be quoted. When True, the character is doubled. When False, the escapechar is used as a prefix to the quotechar. It defaults to True.")
        self.checkbox_doublequote.SetValue(1)
        self.label_quotechar.SetToolTipString("A one-character string used to quote fields containing special characters, such as the delimiter or quotechar, or which contain new-line characters. It defaults to '\"'.")
        self.text_ctrl_quotechar.SetMinSize((25, 25))
        self.text_ctrl_quotechar.SetToolTipString("A one-character string used to quote fields containing special characters, such as the delimiter or quotechar, or which contain new-line characters. It defaults to '\"'.")
        self.button_cancel.SetMinSize((80, 28))
        self.button_apply.SetMinSize((80, 28))
        self.button_ok.SetMinSize((80, 28))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: CsvImportDialog.__do_layout
        grid_sizer_1 = wx.FlexGridSizer(2, 1, 0, 0)
        sizer_1 = wx.FlexGridSizer(1, 3, 5, 5)
        grid_sizer_2 = wx.FlexGridSizer(3, 4, 5, 5)
        grid_sizer_2.Add(self.label_delimiter, 0, wx.ADJUST_MINSIZE, 0)
        grid_sizer_2.Add(self.text_ctrl_delimiter, 0, wx.RIGHT|wx.ADJUST_MINSIZE, 3)
        grid_sizer_2.Add(self.label_skipinitialspace, 0, wx.LEFT|wx.ADJUST_MINSIZE, 15)
        grid_sizer_2.Add(self.checkbox_skipinitialspace, 0, wx.RIGHT|wx.ADJUST_MINSIZE, 3)
        grid_sizer_2.Add(self.label_escapechar, 0, wx.ADJUST_MINSIZE, 0)
        grid_sizer_2.Add(self.text_ctrl_escapechar, 0, wx.RIGHT|wx.ADJUST_MINSIZE, 3)
        grid_sizer_2.Add(self.label_doublequote, 0, wx.LEFT|wx.ADJUST_MINSIZE, 15)
        grid_sizer_2.Add(self.checkbox_doublequote, 0, wx.RIGHT|wx.ADJUST_MINSIZE, 3)
        grid_sizer_2.Add(self.label_quotechar, 0, wx.ADJUST_MINSIZE, 0)
        grid_sizer_2.Add(self.text_ctrl_quotechar, 0, wx.RIGHT|wx.ADJUST_MINSIZE, 3)
        grid_sizer_2.Add(self.panel_1, 1, wx.LEFT|wx.EXPAND, 15)
        grid_sizer_2.Add(self.panel_2, 1, wx.EXPAND, 0)
        grid_sizer_2.AddGrowableCol(3)
        grid_sizer_1.Add(grid_sizer_2, 1, wx.ALL|wx.EXPAND, 10)
        grid_sizer_1.Add(self.csv_test_grid, 1, wx.EXPAND, 0)
        sizer_1.Add(self.button_cancel, 0, wx.ALL|wx.EXPAND, 5)
        sizer_1.Add(self.button_apply, 0, wx.ALL|wx.EXPAND, 5)
        sizer_1.Add(self.button_ok, 0, wx.ALL|wx.EXPAND, 5)
        sizer_1.AddGrowableRow(0)
        sizer_1.AddGrowableCol(0)
        sizer_1.AddGrowableCol(1)
        sizer_1.AddGrowableCol(2)
        grid_sizer_1.Add(sizer_1, 1, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(grid_sizer_1)
        grid_sizer_1.AddGrowableRow(1)
        grid_sizer_1.AddGrowableCol(0)
        self.Layout()
        self.Centre()
        # end wxGlade

    def OnButtonApply(self, event): # wxGlade: CsvImportDialog.<event_handler>
        if DEBUG: 
            print "Event handler 'OnButtonApply'"
        self.csv_test_grid.ClearGrid()
        csvimport = CsvImport(self.csvfilepath, self.get_csvargs())
        csvimport.fill_target(self.csv_test_grid)
        event.Skip()

    def get_csvargs(self):
        """Returns dict with csv import parameters from dialog."""
        replacements = {'\\t':'\t', '\\n':'\n', '\\b':'\b'}
        csvargs = {}
        for param in self.dlgwidgets:
            widget_value = self.dlgwidgets[param].GetValue()
            if widget_value != '':
                for char in replacements:
                    try: 
                        widget_value = widget_value.replace(char, replacements[char])
                        widget_value = widget_value.encode("utf-8")
                    except AttributeError:
                        pass
                csvargs[param] = widget_value
        csvargs['quoting'] = csv.QUOTE_NONNUMERIC
        return csvargs

# end of class CsvImportDialog


class MacroDialog(wx.Dialog, listmix.ColumnSorterMixin):
    """Macro management dialog"""
    def __init__(self, *args, **kwds):
        try:
            self.macros = Macros(kwds.pop("macros")) # Maps all macros names to the respective functions
        except KeyError:
            self.macros = Macros()

        # begin wxGlade: MacroDialog.__init__
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.THICK_FRAME
        wx.Dialog.__init__(self, *args, **kwds)
        self.window_1 = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_BORDER)
        self.panel_3 = wx.Panel(self.window_1, -1)
        self.button_1 = wx.Button(self.panel_3, wx.ID_ADD, "")
        self.button_2 = wx.Button(self.panel_3, wx.ID_APPLY, "")
        self.button_3 = wx.Button(self.panel_3, wx.ID_REMOVE, "")
        self.macro_list_ctrl = SortedListCtrl(self.panel_3, -1, style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_SORT_ASCENDING|wx.SUNKEN_BORDER)
        self.MacroEditPanel = MacroEditPanel(self.window_1, -1)

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_BUTTON, self.OnAddMacro, self.button_1)
        self.Bind(wx.EVT_BUTTON, self.OnApplyChange, self.button_2)
        self.Bind(wx.EVT_BUTTON, self.OnRemoveMacro, self.button_3)
        self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.OnMacroFocused, self.macro_list_ctrl)
        # end wxGlade
        self.macro_list_ctrl.InsertColumn(0, "Function")
        self.macro_list_ctrl.InsertColumn(1, "Description")
#        self.Bind(wx.EVT_TEXT_ENTER, self.OnMacroTextEntered, self.MacroEditPanel.CodeTextCtrl)
        self.UpdateMacroList(func=None)

    def __set_properties(self):    
        # begin wxGlade: MacroDialog.__set_properties
        self.SetTitle("Macro list")
        self.SetSize((1122, 600))
        self.button_1.SetToolTipString("Add new macro")
        self.button_2.SetToolTipString("Apply changes to current macro")
        self.button_3.SetToolTipString("Remove current macro")
        self.MacroEditPanel.SetMinSize((-1, -1))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MacroDialog.__do_layout
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        grid_sizer_3 = wx.FlexGridSizer(2, 1, 5, 0)
        grid_sizer_4 = wx.FlexGridSizer(1, 3, 0, 5)
        grid_sizer_4.Add(self.button_1, 0, wx.ALL|wx.EXPAND, 3)
        grid_sizer_4.Add(self.button_2, 0, wx.ALL|wx.EXPAND, 3)
        grid_sizer_4.Add(self.button_3, 0, wx.ALL|wx.EXPAND, 3)
        grid_sizer_4.AddGrowableCol(0)
        grid_sizer_4.AddGrowableCol(1)
        grid_sizer_4.AddGrowableCol(2)
        grid_sizer_3.Add(grid_sizer_4, 1, wx.TOP|wx.EXPAND, 5)
        grid_sizer_3.Add(self.macro_list_ctrl, 1, wx.EXPAND, 0)
        self.panel_3.SetSizer(grid_sizer_3)
        grid_sizer_3.AddGrowableRow(1)
        grid_sizer_3.AddGrowableCol(0)
        self.window_1.SplitVertically(self.panel_3, self.MacroEditPanel, 500)
        sizer_1.Add(self.window_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()
        # end wxGlade
        
    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
    def GetListCtrl(self):
        return self.macro_list_ctrl

    def GetCurrentMacro(self, event=None):
        """ Returns the macro that is selected in the list. None if there is no such macro"""
        if event is None:
            itemno = self.macro_list_ctrl.GetFocusedItem()
            if itemno == -1:
                current_listitem = None
            else:
                current_listitem = self.macro_list_ctrl.GetItem(itemno)
        else:
            current_listitem = self.macro_list_ctrl.GetItem(event.m_itemIndex)
        #print current_listitem
        try:
            return self.macros[current_listitem.GetText()]
        except KeyError:
            return None

    def GetMacroString(self):
        """ Gets the string-formatted call for the current function with the values from the macro entry form\nFormat: Functionname + ( + var1 + , +  ... + , + varn + )"""
        macro = self.GetCurrentMacro()
        functionname = macro.__name__
        varentries = [var.GetValue() for var in self.MacroEditPanel.varentries]
        varlist = varentries[:macro.func_code.co_argcount]
        return functionname + "(" + ", ".join(varlist) + ")"

    def UpdateMacroList(self, func=None):
        """ Updates the macro list from self.macros """
        self.macro_list_ctrl.DeleteAllItems()
        for i, key in enumerate(sorted(list(self.macros))):
            listentry = (key, self.macros[key].__doc__)
            index = self.macro_list_ctrl.Append(listentry)
            self.macro_list_ctrl.SetItemData(index, i)
        if func is not None:
            self.UpdateMacroListSelection(func)

    def UpdateMacroListSelection(self, func):
        """ Updates the selection so that it focuses
            the item of the recently selected macro """
        newitempos = self.macro_list_ctrl.FindItem(-1, func.__name__)
        self.macro_list_ctrl.Select(newitempos)        

    def OnAddMacro(self, event): # wxGlade: MacroDialog.<event_handler>
        code = self.MacroEditPanel.CodeTextCtrl.GetText()
        func = self.macros.AddToMacroDict(code)
        if func != 0:
            self.UpdateMacroList(func)
        event.Skip()

    def OnApplyChange(self, event): # wxGlade: MacroDialog.<event_handler>
        """Applies change in function to macro dict"""
        code = self.MacroEditPanel.CodeTextCtrl.GetText()
        func = self.macros.GetMacro(code)
        if func.__name__ not in self.macros:
            # If the function name has changed, the old function is removed            
            selecteditem_pos = self.macro_list_ctrl.GetFirstSelected()
            if selecteditem_pos != -1:
                current_listitem = self.macro_list_ctrl.GetItem(selecteditem_pos)
                current_macro = self.macros[current_listitem.GetText()]
                self.macros.pop(current_macro.__name__)
        self.macros[func.__name__] = func
        self.UpdateMacroList(func)
        #for variable in func.func_code.co_varnames:
        #    print variable
        event.Skip()

    def OnRemoveMacro(self, event): # wxGlade: MacroDialog.<event_handler>
        if DEBUG: print "Event handler `OnRemoveMacro'"
        selecteditem_pos = self.macro_list_ctrl.GetFirstSelected()
        if selecteditem_pos != -1:
            current_listitem = self.macro_list_ctrl.GetItem(selecteditem_pos)
            current_macro = self.macros[current_listitem.GetText()]
            self.macros.pop(current_macro.__name__)
            self.UpdateMacroList()
        event.Skip()

    def OnMacroFocused(self, event): # wxGlade: MacroDialog.<event_handler>
        if DEBUG: print "Event handler `OnMacroFocused'"
        current_macro = self.GetCurrentMacro(event)
        if current_macro is None:
            event.Skip()
            return 0
        self.MacroEditPanel.CodeTextCtrl.SetText(current_macro.func_dict['macrocode'])
        try:
            self.MacroEditPanel.docstringTextCtrl.SetValue(current_macro.__doc__)
        except TypeError:
            self.MacroEditPanel.docstringTextCtrl.SetValue("")
        self.MacroEditPanel.update_macroform(self.MacroEditPanel.pane_macroform, current_macro)
        event.Skip()

# end of class MacroDialog


class DimensionsEntryDialog(wx.Dialog):
    """Input dialog for the 3 dimensions of a grid"""
    def __init__(self, *args, **kwds):
        # begin wxGlade: DimensionsEntryDialog.__init__
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.STAY_ON_TOP
        wx.Dialog.__init__(self, *args, **kwds)
        self.Rows_Label = wx.StaticText(self, -1, "Rows", style=wx.ALIGN_CENTRE)
        self.X_DimensionsEntry = wx.TextCtrl(self, -1, "")
        self.Columns_Label = wx.StaticText(self, -1, "Columns", style=wx.ALIGN_CENTRE)
        self.Y_DimensionsEntry = wx.TextCtrl(self, -1, "")
        self.Tabs_Label = wx.StaticText(self, -1, "Tabs", style=wx.ALIGN_CENTRE)
        self.Z_DimensionsEntry = wx.TextCtrl(self, -1, "")
        self.cancel_button = wx.Button(self, wx.ID_CANCEL, "")
        self.ok_button = wx.Button(self, wx.ID_OK, "")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_TEXT, self.OnXDim, self.X_DimensionsEntry)
        self.Bind(wx.EVT_TEXT, self.OnYDim, self.Y_DimensionsEntry)
        self.Bind(wx.EVT_TEXT, self.OnZDim, self.Z_DimensionsEntry)
        # end wxGlade
        self.dimensions = [100, 100, 1]

    def __set_properties(self):
        # begin wxGlade: DimensionsEntryDialog.__set_properties
        self.SetTitle("Create a new grid and discard the old one")
        self.cancel_button.SetDefault()
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: DimensionsEntryDialog.__do_layout
        grid_sizer_1 = wx.GridSizer(4, 2, 3, 3)
        grid_sizer_1.Add(self.Rows_Label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 3)
        grid_sizer_1.Add(self.X_DimensionsEntry, 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.Columns_Label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 3)
        grid_sizer_1.Add(self.Y_DimensionsEntry, 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.Tabs_Label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 3)
        grid_sizer_1.Add(self.Z_DimensionsEntry, 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.cancel_button, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 3)
        grid_sizer_1.Add(self.ok_button, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 3)
        self.SetSizer(grid_sizer_1)
        grid_sizer_1.Fit(self)
        self.Layout()
        # end wxGlade

    def OnXDim(self, event): # wxGlade: DimensionsEntryDialog.<event_handler>
        try: self.dimensions[0] = int(event.GetString())
        except ValueError: self.dimensions[0] = 0
        event.Skip()

    def OnYDim(self, event): # wxGlade: DimensionsEntryDialog.<event_handler>
        try: self.dimensions[1] = int(event.GetString())
        except ValueError: self.dimensions[1] = 0
        event.Skip()

    def OnZDim(self, event): # wxGlade: DimensionsEntryDialog.<event_handler>
        try: self.dimensions[2] = int(event.GetString())
        except ValueError: self.dimensions[2] = 0
        event.Skip()

# end of class DimensionsEntryDialog


class AboutDialog(wx.Dialog):
    """Displays information about pyspread"""
    def __init__(self, *args, **kwds):
        # begin wxGlade: AboutDialog.__init__
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
        wx.Dialog.__init__(self, *args, **kwds)
        self.bitmap_2 = wx.StaticBitmap(self, -1, wx.Bitmap(LIBPREFIX+'icons/pyspread.png', wx.BITMAP_TYPE_ANY))
        self.about_label = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)

        self.__set_properties()
        self.__do_layout()
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: AboutDialog.__set_properties
        self.SetTitle("About pyspread")
        # end wxGlade
        
        self.about_label.SetLabel("pyspread " + VERSION + \
                                  "\nCopyright Martin Manns 2008")

    def __do_layout(self):
        # begin wxGlade: AboutDialog.__do_layout
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4.Add(self.bitmap_2, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 10)
        sizer_4.Add(self.about_label, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 10)
        self.SetSizer(sizer_4)
        sizer_4.Fit(self)
        self.Layout()
        self.Centre()
        # end wxGlade

# end of class AboutDialog
