#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007  Donald N. Allingham
# Copyright (C) 2008  Raphael Ackermann
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

# $Id: GrampsCfg.py 10208 2008-03-07 14:09:33Z ldnp $

#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import random
from gettext import gettext as _
import os
from xml.sax.saxutils import escape

#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
from gtk import glade
import gobject

#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import Config
import const
import DateHandler
from BasicUtils import name_displayer as _nd
import Utils
from gen.lib import Name
import ManagedWindow
from GrampsWidgets import MarkupLabel, BasicLabel
from QuestionDialog import ErrorDialog, QuestionDialog2
from Errors import NameDisplayError

#-------------------------------------------------------------------------
#
# Constants 
#
#-------------------------------------------------------------------------

_surname_styles = [
    _("Father's surname"), 
    _("None"), 
    _("Combination of mother's and father's surname"), 
    _("Icelandic style"), 
    ]

# column numbers for the 'name format' model
COL_NUM  = 0
COL_NAME = 1
COL_FMT  = 2
COL_EXPL = 3

def set_calendar_date_format():
    format_list = DateHandler.get_date_formats()
    DateHandler.set_format(Config.get_date_format(format_list))

def get_researcher():
    import gen.lib
    
    n  = Config.get(Config.RESEARCHER_NAME)
    a  = Config.get(Config.RESEARCHER_ADDR)
    c  = Config.get(Config.RESEARCHER_CITY)
    s  = Config.get(Config.RESEARCHER_STATE)
    ct = Config.get(Config.RESEARCHER_COUNTRY)
    p  = Config.get(Config.RESEARCHER_POSTAL)
    ph = Config.get(Config.RESEARCHER_PHONE)
    e  = Config.get(Config.RESEARCHER_EMAIL)

    owner = gen.lib.Researcher()
    owner.set_name(n)
    owner.set_address(a)
    owner.set_city(c)
    owner.set_state(s)
    owner.set_country(ct)
    owner.set_postal_code(p)
    owner.set_phone(ph)
    owner.set_email(e)

    return owner

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
class DisplayNameEditor(ManagedWindow.ManagedWindow):
    def __init__(self, uistate, dbstate, track, dialog):
        # Assumes that there are two methods: dialog.name_changed_check(), 
        # and dialog._build_custom_name_ui() 
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], DisplayNameEditor)
        self.dialog = dialog
        self.dbstate = dbstate
        self.set_window(
            gtk.Dialog(_('Display Name Editor'), 
                       flags=gtk.DIALOG_NO_SEPARATOR, 
                       buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)), 
            None, _('Display Name Editor'), None)
        table = self.dialog._build_custom_name_ui()
        self.window.vbox.add(table)
        self.window.set_default_size(600, 300)
        self.window.connect('response', self.close)
        self.show()
    def close(self, *obj):
        self.dialog.name_changed_check()
        ManagedWindow.ManagedWindow.close(self, *obj)
        
    def build_menu_names(self, obj):
        return (_(" Name Editor"), _("Preferences"))

class GrampsPreferences(ManagedWindow.ManagedWindow):

    def __init__(self, uistate, dbstate):
        self.dbstate = dbstate
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], GrampsPreferences)
        self.set_window(
            gtk.Dialog(_('Preferences'), 
                       flags=gtk.DIALOG_NO_SEPARATOR, 
                       buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)), 
            None, _('Preferences'), None)
        panel = gtk.Notebook()
        self.window.vbox.add(panel)
        self.window.connect('response', self.done)
        panel.append_page(self.add_behavior_panel(), 
                          MarkupLabel(_('General')))
        panel.append_page(self.add_database_panel(), 
                          MarkupLabel(_('Database')))
        panel.append_page(self.add_formats_panel(), 
                          MarkupLabel(_('Display')))
        panel.append_page(self.add_text_panel(), 
                          MarkupLabel(_('Text')))
        panel.append_page(self.add_prefix_panel(), 
                          MarkupLabel(_('ID Formats')))
        panel.append_page(self.add_advanced_panel(), 
                          MarkupLabel(_('Warnings')))
        panel.append_page(self.add_researcher_panel(), 
                          MarkupLabel(_('Researcher')))
        panel.append_page(self.add_color_panel(), 
                          MarkupLabel(_('Marker Colors')))
        self.window.show_all()
        self.show()

    def done(self, obj, value):
        self.close()

    def add_researcher_panel(self):
        table = gtk.Table(3, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        self.add_entry(table, _('Name'), 0, Config.RESEARCHER_NAME)
        self.add_entry(table, _('Address'), 1, Config.RESEARCHER_ADDR)
        self.add_entry(table, _('City'), 2, Config.RESEARCHER_CITY)
        self.add_entry(table, _('State/Province'), 3, Config.RESEARCHER_STATE)
        self.add_entry(table, _('Country'), 4, Config.RESEARCHER_COUNTRY)
        self.add_entry(table, _('ZIP/Postal Code'), 5, Config.RESEARCHER_POSTAL)
        self.add_entry(table, _('Phone'), 6, Config.RESEARCHER_PHONE)
        self.add_entry(table, _('Email'), 7, Config.RESEARCHER_EMAIL)
        return table

    def add_prefix_panel(self):
        """
        Add the ID prefix tab to the preferences.
        """
        table = gtk.Table(3, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        self.add_entry(table, _('Person'), 0, Config.IPREFIX, 
                       self.update_idformat_entry)
        self.add_entry(table, _('Family'), 1, Config.FPREFIX,
                       self.update_idformat_entry)
        self.add_entry(table, _('Place'), 2, Config.PPREFIX,
                       self.update_idformat_entry)
        self.add_entry(table, _('Source'), 3, Config.SPREFIX,
                       self.update_idformat_entry)
        self.add_entry(table, _('Media Object'), 4, Config.OPREFIX,
                       self.update_idformat_entry)
        self.add_entry(table, _('Event'), 5, Config.EPREFIX,
                       self.update_idformat_entry)
        self.add_entry(table, _('Repository'), 6, Config.RPREFIX,
                       self.update_idformat_entry)
        self.add_entry(table, _('Note'), 7, Config.NPREFIX,
                       self.update_idformat_entry)
        return table

    def add_advanced_panel(self):
        table = gtk.Table(4, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        self.add_checkbox(
            table, _('Suppress warning when adding parents to a child'), 
            0, Config.FAMILY_WARN)
        
        self.add_checkbox(
            table, _('Suppress warning when cancelling with changed data'), 
            1, Config.DONT_ASK)
        
        self.add_checkbox(
            table, _('Suppress warning about missing researcher when'
                     ' exporting to GEDCOM'), 
            2, Config.OWNER_WARN)

        self.add_checkbox(
            table, _('Show plugin status dialog on plugin load error'), 
            3, Config.POP_PLUGIN_STATUS)
        
        return table

    def add_color_panel(self):
        table = gtk.Table(3, 8)
        table.set_border_width(12)
        table.set_col_spacings(12)
        table.set_row_spacings(6)

        self.comp_color = self.add_color(table, _("Complete"), 0, 
                                         Config.COMPLETE_COLOR)
        self.todo_color = self.add_color(table, _("ToDo"), 1, 
                                         Config.TODO_COLOR)
        self.custom_color = self.add_color(table, _("Custom"), 2, 
                                           Config.CUSTOM_MARKER_COLOR)
        
        button = gtk.Button(stock=gtk.STOCK_REVERT_TO_SAVED)
        button.connect('clicked', self.reset_colors)
        table.attach(button, 1, 2, 3, 4, yoptions=0, xoptions=0)
        return table

    def reset_colors(self, obj):

        def_comp = Config.get_default(Config.COMPLETE_COLOR, '')
        def_todo = Config.get_default(Config.TODO_COLOR, '')
        def_cust = Config.get_default(Config.CUSTOM_MARKER_COLOR, '')
        
        Config.set(Config.COMPLETE_COLOR, def_comp)
        Config.set(Config.TODO_COLOR, def_todo)
        Config.set(Config.CUSTOM_MARKER_COLOR, def_cust)

        self.comp_color.set_color(gtk.gdk.color_parse(def_comp))
        self.todo_color.set_color(gtk.gdk.color_parse(def_todo))
        self.custom_color.set_color(gtk.gdk.color_parse(def_cust))
        for widget in [self.comp_color, self.todo_color, self.custom_color]:
            widget.emit('color-set')

    def add_name_panel(self):
        """
        Name format settings panel
        """

        # a dummy name to be used in the examples
        self.examplename = Name()
        self.examplename.set_title('Dr.')
        self.examplename.set_first_name('Edwin Jose')
        self.examplename.set_surname_prefix('Rev.')
        self.examplename.set_surname('Smith')
        self.examplename.set_suffix('Sr')
        self.examplename.set_patronymic('Wilson')
        self.examplename.set_call_name('Ed')

        table = gtk.Table(2, 2)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)

        # get the model for the combo and the treeview
        active = _nd.get_default_format()
        self.fmt_model, active = self._build_name_format_model(active)

        # set up the combo to choose the preset format
        self.fmt_obox = gtk.ComboBox()
        cell = gtk.CellRendererText()
        self.fmt_obox.pack_start(cell, True)
        self.fmt_obox.add_attribute(cell, 'text', 1)
        self.fmt_obox.set_model(self.fmt_model)
        
        # set the default value as active in the combo
        self.fmt_obox.set_active(active)
        self.fmt_obox.connect('changed', self.cb_name_changed)
        # label for the combo
        lwidget = BasicLabel("%s: " % _('_Display format'))
        lwidget.set_use_underline(True)
        lwidget.set_mnemonic_widget(self.fmt_obox)

        # build the format manager ui
        custom_ui = self._build_custom_name_ui()
        name_exp = gtk.expander_new_with_mnemonic(_('C_ustom format details'))
        name_exp.add(custom_ui)
        name_exp.set_sensitive(self.dbstate.open)
        
        # put all these together
        table.attach(lwidget, 0, 1, 0, 1, yoptions=0)
        table.attach(self.fmt_obox, 1, 2, 0, 1, yoptions=0)
        table.attach(name_exp, 0, 2, 1, 2, yoptions=gtk.FILL|gtk.EXPAND)
        
        return table

    def _build_name_format_model(self, active):
        """
        Create a common model for ComboBox and TreeView
        """
        name_format_model = gtk.ListStore(gobject.TYPE_INT, 
                                          gobject.TYPE_STRING, 
                                          gobject.TYPE_STRING, 
                                          gobject.TYPE_STRING)
        index = 0        
        the_index = 0
        for num, name, fmt_str, act in _nd.get_name_format():
            translation = fmt_str
            for key in Utils.get_keywords():
                if key in translation:
                    translation = translation.replace(key, Utils.get_translation_from_keyword(key))
            self.examplename.set_display_as(num)
            name_format_model.append(
                row=[num, translation, fmt_str, _nd.display_name(self.examplename)])
            if num == active: the_index = index
            index += 1
        return name_format_model, the_index

    def __new_name(self, obj):
        lyst = ["%s, %s %s (%s)" % (_("Surname"), _("Given"), _("Suffix"), 
                                    _("Common")),
                "%s, %s %s (%s)" % (_("Surname"), _("Given"), _("Suffix"), 
                                    _("Call")),
                "%s, %s %s (%s)" % (_("SURNAME"), _("Given"), _("Suffix"), 
                                    _("Call")),
                "%s, %s (%s)" % (_("Surname"), _("Given"), _("Common")),
                "%s, %s (%s)" % (_("Surname"), _("Given"), _("Call")),
                "%s %s" % (_("Given"), _("Surname")),
                "%s %s, %s" % (_("Given"), _("Surname"), _("Suffix")),
                "%s %s %s" % (_("Given"), _("Surname"), _("Patronymic")),
                "%s, %s %s (%s)" % (_("SURNAME"), _("Given"), _("Suffix"), 
                                    _("Common")),
                "%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Common")),
                "%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Call")),
                "%s %s" % (_("Given"), _("SURNAME")),
                "%s %s, %s" % (_("Given"), _("SURNAME"), _("Suffix")),
                "%s /%s/" % (_("Given"), _("SURNAME")),
                ]
        f = lyst[int(random.random() * len(lyst))]
        i = _nd.add_name_format(f, f.lower())
        node = self.fmt_model.append(row=[i, f, f.lower(), 
                                   _nd.format_str(self.examplename, f)])
        path = self.fmt_model.get_path(node)
        self.format_list.set_cursor(path, 
                                    focus_column=self.name_column, 
                                    start_editing=True)

    def __edit_name(self, obj):
        store, node = self.format_list.get_selection().get_selected()
        path = self.fmt_model.get_path(node)
        self.format_list.set_cursor(path, 
                                    focus_column=self.name_column, 
                                    start_editing=True)

    def __check_for_name(self, name, oldnode):
        """
        Check to see if there is another name the same as name
        in the format list. Don't compare with self (oldnode).
        """
        model = self.fmt_obox.get_model()
        iter = model.get_iter_first()
        while iter != None:
            othernum = model.get_value(iter, COL_NUM)
            oldnum = model.get_value(oldnode, COL_NUM)
            if othernum == oldnum: 
                pass# skip comparison with self
            else:
                othername = model.get_value(iter, COL_NAME)
                if othername == name:
                    return True
            iter = model.iter_next(iter)
        return False

    def __change_name(self, text, path, new_text):
        """
        If the new string is empty, do nothing. Otherwise, renaming the
        database is simply changing the contents of the name file.
        """
        if len(new_text) > 0 and text != new_text:
            # build a pattern from translated pattern:
            pattern = new_text
            for key in Utils.get_translations():
                if key in pattern:
                    pattern = pattern.replace(key, Utils.get_keyword_from_translation(key))
            # now build up a proper translation:
            translation = pattern
            for key in Utils.get_keywords():
                if key in translation:
                    translation = translation.replace(key, Utils.get_translation_from_keyword(key))
            num, name, fmt = self.selected_fmt[COL_NUM:COL_EXPL]
            node = self.fmt_model.get_iter(path)
            oldname = self.fmt_model.get_value(node, COL_NAME)
            # check to see if this pattern already exists
            if self.__check_for_name(translation, node):
                ErrorDialog(_("This format exists already"), 
                                           translation)
                self.edit_button.emit('clicked')
                return
            # else, change the name
            exmpl = _nd.format_str(self.examplename, pattern)
            self.fmt_model.set(self.iter, COL_NAME, translation, 
                               COL_FMT, pattern, 
                               COL_EXPL, exmpl)
            self.selected_fmt = (num, translation, pattern, exmpl)
            _nd.edit_name_format(num, translation, pattern)
            self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True, 
                                                               only_active=False)

    def __format_change(self, obj):
        try:
            t = (_nd.format_str(self.name, escape(obj.get_text())))
            self.valid = True
        except NameDisplayError:
            t = _("Invalid or incomplete format definition")
            self.valid = False
        self.fmt_model.set(self.iter, COL_EXPL, t)

    def _build_custom_name_ui(self):
        """
        UI to manage the custom name formats
        """

        table = gtk.Table(2, 3)
        table.set_border_width(6)
        table.set_col_spacings(6)
        table.set_row_spacings(6)

        # make a treeview for listing all the name formats
        format_tree = gtk.TreeView(self.fmt_model)
        name_renderer = gtk.CellRendererText()
        name_column = gtk.TreeViewColumn(_('Format'), 
                                         name_renderer, 
                                         text=COL_NAME)
        name_renderer.set_property('editable', False)
        name_renderer.connect('edited', self.__change_name)
        self.name_renderer = name_renderer
        format_tree.append_column(name_column)
        example_renderer = gtk.CellRendererText()
        example_column = gtk.TreeViewColumn(_('Example'), 
                                            example_renderer, 
                                            text=COL_EXPL)
        format_tree.append_column(example_column)
        format_tree.get_selection().connect('changed', 
                                            self.cb_format_tree_select)
        format_tree.set_rules_hint(True)

        # ... and put it into a scrolled win
        format_sw = gtk.ScrolledWindow()
        format_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        format_sw.add(format_tree)
        format_sw.set_shadow_type(gtk.SHADOW_IN)
        table.attach(format_sw, 0, 3, 0, 1, yoptions=gtk.FILL|gtk.EXPAND)

        # to hold the values of the selected row of the tree and the iter
        self.selected_fmt = ()
        self.iter = None

        insert_button = gtk.Button(stock=gtk.STOCK_ADD)
        insert_button.connect('clicked', self.__new_name)
                              #self.cb_insert_fmt_str)

        self.edit_button = gtk.Button(stock=gtk.STOCK_EDIT)
        self.edit_button.connect('clicked', self.__edit_name)
                                 #self.cb_edit_fmt_str)
        self.edit_button.set_sensitive(False)

        self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
        self.remove_button.connect('clicked', self.cb_del_fmt_str)
        self.remove_button.set_sensitive(False)
        
        table.attach(insert_button, 0, 1, 1, 2, yoptions=0)
        table.attach(self.remove_button, 1, 2, 1, 2, yoptions=0)
        table.attach(self.edit_button,   2, 3, 1, 2, yoptions=0)
        self.format_list = format_tree
        self.name_column = name_column
        return table

    def name_changed_check(self):
        """
        Method to check for a name change. Called by Name Edit Dialog.
        """
        obj = self.fmt_obox
        the_list = obj.get_model()
        the_iter = obj.get_active_iter()
        format = the_list.get_value(the_iter, COL_FMT)
        if format != self.old_format:
            # Yes a change; call the callback
            self.cb_name_changed(obj)

    def cb_name_changed(self, obj):
        """
        Preset name format ComboBox callback
        """
        the_list = obj.get_model()
        the_iter = obj.get_active_iter()
        new_idx = the_list.get_value(the_iter, COL_NUM)
        Config.set(Config.NAME_FORMAT, new_idx)
        _nd.set_default_format(new_idx)
        self.uistate.emit('nameformat-changed')
        
    def cb_format_tree_select(self, tree_selection):
        """
        Name format editor TreeView callback
        
        Remember the values of the selected row (self.selected_fmt, self.iter)
        and set the Remove and Edit button sensitivity
        
        """
        model, self.iter = tree_selection.get_selected()
        if self.iter == None:
            tree_selection.select_path(0)
            model, self.iter = tree_selection.get_selected()
        self.selected_fmt = model.get(self.iter, 0, 1, 2)
        idx = self.selected_fmt[COL_NUM] < 0
        self.remove_button.set_sensitive(idx)
        self.edit_button.set_sensitive(idx)
        self.name_renderer.set_property('editable', idx)


    def cb_edit_fmt_str(self, obj):
        """
        Name format editor Edit button callback
        """
        num, name, fmt = self.selected_fmt[COL_NUM:COL_EXPL]
        dlg = NameFormatEditDlg(name, fmt, self.examplename)
        dlg.dlg.set_transient_for(self.window)
        (res, name, fmt) = dlg.run()

        if res == gtk.RESPONSE_OK and (name != self.selected_fmt[COL_NAME] or 
                                       fmt != self.selected_fmt[COL_FMT]):
            exmpl = _nd.format_str(self.examplename, fmt)
            self.fmt_model.set(self.iter, COL_NAME, name, 
                               COL_FMT, fmt, 
                               COL_EXPL, exmpl)
            self.selected_fmt = (num, name, fmt, exmpl)
            _nd.edit_name_format(num, name, fmt)

            self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True, 
                                                               only_active=False)
        
    def cb_insert_fmt_str(self, obj):
        """
        Name format editor Insert button callback
        """
        dlg = NameFormatEditDlg('', '', self.examplename)
        dlg.dlg.set_transient_for(self.window)
        (res, n, f) = dlg.run()

        if res == gtk.RESPONSE_OK:
            i = _nd.add_name_format(n, f)
            self.fmt_model.append(row=[i, n, f, 
                                       _nd.format_str(self.examplename, f)])

        self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True, 
                                                           only_active=False)
        
    def cb_del_fmt_str(self, obj):
        """
        Name format editor Remove button callback
        """
        num = self.selected_fmt[COL_NUM]

        if _nd.get_default_format() == num:
            self.fmt_obox.set_active(0)

        self.fmt_model.remove(self.iter)
        _nd.set_format_inactive(num)
        self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True, 
                                                           only_active=False)

    def add_formats_panel(self):
        row = 0
        table = gtk.Table(4, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)

        # Display name:
        self.examplename = Name()
        self.examplename.set_title('Dr.')
        self.examplename.set_first_name('Edwin Jose')
        self.examplename.set_surname_prefix('Rev.')
        self.examplename.set_surname('Smith')
        self.examplename.set_suffix('Sr')
        self.examplename.set_patronymic('Wilson')
        self.examplename.set_call_name('Ed')
        # get the model for the combo and the treeview
        active = _nd.get_default_format()
        self.fmt_model, active = self._build_name_format_model(active)
        # set up the combo to choose the preset format
        self.fmt_obox = gtk.ComboBox()
        cell = gtk.CellRendererText()
        self.fmt_obox.pack_start(cell, True)
        self.fmt_obox.add_attribute(cell, 'text', 1)
        self.fmt_obox.set_model(self.fmt_model)
        # set the default value as active in the combo
        self.fmt_obox.set_active(active)
        self.fmt_obox.connect('changed', self.cb_name_changed)
        # label for the combo
        lwidget = BasicLabel("%s: " % _('Name format'))
        lwidget.set_use_underline(True)
        lwidget.set_mnemonic_widget(self.fmt_obox)
        hbox = gtk.HBox()
        btn = gtk.Button("%s..." % _('Edit') )
        btn.connect('clicked', self.cb_name_dialog)
        hbox.pack_start(self.fmt_obox, expand=True, fill=True)
        hbox.pack_start(btn, expand=False, fill=False)
        table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
        table.attach(hbox,    1, 3, row, row+1, yoptions=0)
        row += 1

        # Date format:
        obox = gtk.combo_box_new_text()
        formats = DateHandler.get_date_formats()
        for item in formats:
            obox.append_text(item)
        active = Config.get(Config.DATE_FORMAT)
        if active >= len(formats):
            active = 0
        obox.set_active(active)
        obox.connect('changed', self.date_format_changed)
        lwidget = BasicLabel("%s: " % _('Date format'))
        table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
        table.attach(obox, 1, 3, row, row+1, yoptions=0)
        row += 1

        # Surname guessing:
        obox = gtk.combo_box_new_text()
        formats = _surname_styles
        for item in formats:
            obox.append_text(item)
        obox.set_active(Config.get(Config.SURNAME_GUESSING))
        obox.connect('changed', 
                     lambda obj: Config.set(Config.SURNAME_GUESSING, 
                                            obj.get_active()))
        lwidget = BasicLabel("%s: " % _('Surname guessing'))
        table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
        table.attach(obox, 1, 3, row, row+1, yoptions=0)
        row += 1

        # Status bar:
        obox = gtk.combo_box_new_text()
        formats = [_("Active person's name and ID"), 
                   _("Relationship to home person")]
        for item in formats:
            obox.append_text(item)
        active = Config.get(Config.STATUSBAR)
        if active < 2:
            obox.set_active(0)
        else:
            obox.set_active(1)
        obox.connect('changed', 
                     lambda obj: Config.set(Config.STATUSBAR, 2*obj.get_active()))
        lwidget = BasicLabel("%s: " % _('Status bar'))
        table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
        table.attach(obox,    1, 3, row, row+1, yoptions=0)
        row += 1

        # Text in sidebar:
        self.add_checkbox(table, _("Show text in sidebar buttons (takes effect on restart)"), 
                          row, Config.SIDEBAR_TEXT)
        row += 1
        return table

    def add_text_panel(self):
        row = 0
        table = gtk.Table(6, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        self.add_entry(table, _('Missing surname'), row, 
                       Config.NO_SURNAME_TEXT)
        row += 1
        self.add_entry(table, _('Missing given name'), row, 
                       Config.NO_GIVEN_TEXT)
        row += 1
        self.add_entry(table, _('Missing record'), row, 
                       Config.NO_RECORD_TEXT)
        row += 1
        self.add_entry(table, _('Private surname'), row, 
                       Config.PRIVATE_SURNAME_TEXT)
        row += 1
        self.add_entry(table, _('Private given name'), row, 
                       Config.PRIVATE_GIVEN_TEXT)
        row += 1
        self.add_entry(table, _('Private record'), row, 
                       Config.PRIVATE_RECORD_TEXT)
        row += 1
        return table

    def cb_name_dialog(self, obj):
        the_list = self.fmt_obox.get_model()
        the_iter = self.fmt_obox.get_active_iter()
        self.old_format = the_list.get_value(the_iter, COL_FMT)
        win = DisplayNameEditor(self.uistate, self.dbstate, self.track, self)

    def date_format_changed(self, obj):
        from QuestionDialog import OkDialog

        Config.set(Config.DATE_FORMAT, obj.get_active())
        OkDialog(_('Change is not immediate'), 
                 _('Changing the data format will not take '
                   'effect until the next time GRAMPS is started.'))

    def add_behavior_panel(self):
        table = gtk.Table(3, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)

        self.add_checkbox(table, _('Add default source on import'), 
                          0, Config.DEFAULT_SOURCE)
        self.add_checkbox(table, _('Enable spelling checker'), 
                          1, Config.SPELLCHECK)
        self.add_checkbox(table, _('Display Tip of the Day'), 
                          2, Config.USE_TIPS)
        self.add_checkbox(table, _('Use shading in Relationship View'), 
                          3, Config.RELATION_SHADE)
        self.add_checkbox(table, _('Display edit buttons on Relationship View'), 
                          4, Config.RELEDITBTN)
        self.add_checkbox(table, _('Remember last view displayed'), 
                          5, Config.USE_LAST_VIEW)
        self.add_pos_int_entry(table, 
                _('Number of generations for relationship determination'),
                6, Config.GENERATION_DEPTH, self.update_gen_depth)
        self.path_entry = gtk.Entry()
        self.add_path_box(table, _('Base path for relative media paths'),
                7, self.path_entry, self.dbstate.db.get_mediapath(),
                self.set_mediapath, self.select_mediapath)

        return table

    def add_database_panel(self):
        table = gtk.Table(2, 8)
        table.set_border_width(12)
        table.set_col_spacings(6)
        table.set_row_spacings(6)

        self.add_entry(table, _('Database path'), 0, Config.DATABASE_PATH)
        self.add_checkbox(table, _('Automatically load last database'), 
                          2, Config.AUTOLOAD)
        return table

    def add_checkbox(self, table, label, index, constant):
        checkbox = gtk.CheckButton(label)
        checkbox.set_active(Config.get(constant))
        checkbox.connect('toggled', self.update_checkbox, constant)
        table.attach(checkbox, 1, 3, index, index+1, yoptions=0)

    def add_path_box(self, table, label, index, entry, path, callback_label, 
                     callback_sel):
        """ Add an entry to give in path and a select button to open a 
            dialog. 
            Changing entry calls callback_label
            Clicking open button call callback_sel
        """
        lwidget = BasicLabel("%s: " %label)
        hbox = gtk.HBox()
        if path:
            entry.set_text(path)
        entry.connect('changed', callback_label)
        btn = gtk.Button()
        btn.connect('clicked', callback_sel)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
        image.show()
        btn.add(image)
        hbox.pack_start(entry, expand=True, fill=True)
        hbox.pack_start(btn, expand=False, fill=False)
        table.attach(lwidget, 1, 2, index, index+1, yoptions=0, 
                     xoptions=gtk.FILL)
        table.attach(hbox, 2, 3, index, index+1, yoptions=0)

    def add_entry(self, table, label, index, constant, callback=None):
        if not callback:
            callback = self.update_entry
        lwidget = BasicLabel("%s: " % label)
        entry = gtk.Entry()
        entry.set_text(Config.get(constant))
        entry.connect('changed', callback, constant)
        table.attach(lwidget, 0, 1, index, index+1, yoptions=0, 
                     xoptions=gtk.FILL)
        table.attach(entry, 1, 2, index, index+1, yoptions=0)

    def add_pos_int_entry(self, table, label, index, constant, callback=None):
        """ entry field for positive integers
        """
        lwidget = BasicLabel("%s: " % label)
        entry = gtk.Entry()
        entry.set_text(str(Config.get(constant)))
        if callback:
            entry.connect('changed', callback, constant)
        table.attach(lwidget, 1, 2, index, index+1, yoptions=0, 
                     xoptions=gtk.FILL)
        table.attach(entry, 2, 3, index, index+1, yoptions=0)

    def add_color(self, table, label, index, constant):
        lwidget = BasicLabel("%s: " % label)
        hexval = Config.get(constant)
        color = gtk.gdk.color_parse(hexval)
        entry = gtk.ColorButton(color=color)
        color_hex_label = BasicLabel(hexval)
        entry.connect('color-set', self.update_color, constant, color_hex_label)
        table.attach(lwidget, 0, 1, index, index+1, yoptions=0, 
                     xoptions=gtk.FILL)
        table.attach(entry, 1, 2, index, index+1, yoptions=0, xoptions=0)
        table.attach(color_hex_label, 2, 3, index, index+1, yoptions=0)
        return entry

    def set_mediapath(self, *obj):
        if self.path_entry.get_text().strip():
            self.dbstate.db.set_mediapath(self.path_entry.get_text())
        else:
            self.dbstate.db.set_mediapath(None)

    def select_mediapath(self, *obj):
        f = gtk.FileChooserDialog(
            _("Select media directory"),
            action=gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER,
            buttons=(gtk.STOCK_CANCEL,
                     gtk.RESPONSE_CANCEL,
                     gtk.STOCK_APPLY,
                     gtk.RESPONSE_OK))
        mpath = self.dbstate.db.get_mediapath()
        if not mpath:
            mpath = const.HOME_DIR
        f.set_current_folder(os.path.dirname(mpath))

        status = f.run()
        if status == gtk.RESPONSE_OK:
            val = Utils.get_unicode_path(f.get_filename())
            if val:
                self.path_entry.set_text(val)
        f.destroy()

    def update_entry(self, obj, constant):
        Config.set(constant, unicode(obj.get_text()))

    def update_idformat_entry(self, obj, constant):
        Config.set(constant, unicode(obj.get_text()))
        self.dbstate.db.set_prefixes(
            Config.get(Config.IPREFIX),
            Config.get(Config.OPREFIX),
            Config.get(Config.FPREFIX),
            Config.get(Config.SPREFIX),
            Config.get(Config.PPREFIX),
            Config.get(Config.EPREFIX),
            Config.get(Config.RPREFIX),
            Config.get(Config.NPREFIX) )

    def update_gen_depth(self, obj, constant):
        ok = True
        if not obj.get_text():
            return
        try:
            intval = int(obj.get_text())
        except:
            intval = Config.get(constant)
            ok = False
        if intval < 0 :
            intval = Config.get(constant)
            ok = False
        if ok:
            Config.set(constant, intval)
            #immediately use this value in displaystate.
            self.uistate.set_gendepth(intval)
        else:
            obj.set_text(str(intval))

    def update_color(self, obj, constant, color_hex_label):
        color = obj.get_color()
        hexval = "#%02x%02x%02x" % (color.red/256, 
                                    color.green/256, 
                                    color.blue/256)
        color_hex_label.set_text(hexval)
        Config.set(constant, hexval)

    def update_checkbox(self, obj, constant):
        Config.set(constant, obj.get_active())

    def build_menu_names(self, obj):
        return (_('Preferences'), None)

    # FIXME: is this needed?
    def _set_button(self, stock):
        button = gtk.Button()
        image = gtk.Image()
        image.set_from_stock(stock, gtk.ICON_SIZE_BUTTON)
        image.show()
        button.add(image)
        button.show()
        return button
    
class NameFormatEditDlg:
    """
    """
    
    def __init__(self, fmt_name, fmt_str, name):
        self.fmt_name = fmt_name
        self.fmt_str = fmt_str
        self.name = name
        self.valid = True

        self.top = glade.XML(const.GLADE_FILE, 'namefmt_edit', 'gramps')
        self.dlg = self.top.get_widget('namefmt_edit')
        ManagedWindow.set_titles(self.dlg, None, _('Name Format Editor'))
        
        self.examplelabel = self.top.get_widget('example_label')
        
        self.nameentry = self.top.get_widget('name_entry')
        self.nameentry.set_text('<span weight="bold">%s</span>' % self.fmt_name)
        self.nameentry.set_use_markup(True)
        
        self.formatentry = self.top.get_widget('format_entry')
        self.formatentry.connect('changed', self.cb_format_changed)
        self.formatentry.set_text(self.fmt_str)
        
    def run(self):
        running = True
        while running:
            self.response = self.dlg.run()

            running = False
            self.fmt_name = self.nameentry.get_text()
            self.fmt_str = self.formatentry.get_text()
            
            if self.response == gtk.RESPONSE_OK:
                if not self.valid:
                    q = QuestionDialog2(
                        _('The format definition is invalid'), 
                        _('What would you like to do?'), 
                        _('_Continue anyway'), _('_Modify format'), 
                        parent=self.dlg)
                    running = not q.run()
                    self.response = gtk.RESPONSE_CANCEL
                elif self.fmt_name == '' and self.fmt_str == '':
                    self.response = gtk.RESPONSE_CANCEL
                elif (self.fmt_name == '') ^ (self.fmt_str == ''):
                    ErrorDialog(
                        _('Both Format name and definition have to be defined'), 
                        parent=self.dlg)
                    running = True
                                    
        self.dlg.destroy()
        return (self.response, self.fmt_name, self.fmt_str)

    def cb_format_changed(self, obj):
        try:
            t = (_nd.format_str(self.name, escape(obj.get_text())))
            sample = '<span weight="bold" style="italic">%s</span>' % t
            self.valid = True
        except NameDisplayError:
            t = _("Invalid or incomplete format definition")
            sample = '<span foreground="#FF0000">%s</span>' % t
            self.valid = False

        self.examplelabel.set_text(sample)
        self.examplelabel.set_use_markup(True)
        self.nameentry.set_text('<span weight="bold">%s</span>' % obj.get_text())
        self.nameentry.set_use_markup(True)
