# GNU Solfege - eartraining for GNOME
# Copyright (C) 2000, 2001, 2002  Tom Cato Amundsen
#
# 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

import sys
import gtk, gnome, gnome.ui
import gu, mpd
import configureoutput
import widgets
from instrumentselector import ReadOnlyInstrumentSelector
from i18n import _
import cfg
import soundcard

class ConfigWindow(gnome.ui.GnomePropertyBox, cfg.ConfigUtils):
    def on_destroy(self, widget):
        self.m_app.m_ui.g_config_window.destroy()
        self.m_app.m_ui.g_config_window = None
    def __init__(self, app):
        gnome.ui.GnomePropertyBox.__init__(self)
        cfg.ConfigUtils.__init__(self, 'configwindow')
        self.m_app = app
        self._is_alive = 0
        self.__apply_tag = self.connect('apply', self.on_apply)
        self.connect('help', self.on_help)
        self.connect('destroy', self.on_destroy)
        ########
        # midi #
        ########
        vbox = gtk.GtkVBox()
        self.append_page(vbox, gtk.GtkLabel(_("Midi stuff")))
        hbox = gu.bHBox(vbox, gtk.FALSE)
        hbox.set_border_width(gnome.uiconsts.PAD)

        table = gtk.GtkTable(1, 1, gtk.FALSE)
        hbox.pack_start(table, gtk.FALSE)

        gu.tLabel(table, 0, 1, 0, 1, _("Slow bpm:"), 1.0,
                  xoptions=gtk.FILL, xpadding=gnome.uiconsts.PAD)
        gu.tLabel(table, 0, 1, 1, 2, _("Default bpm:"), 1.0, 0.5,
                  xoptions=gtk.FILL, xpadding=gnome.uiconsts.PAD)
        gu.tLabel(table, 0, 1, 2, 3, _("Arpeggio bpm:"), 1.0, 0.5,
                  xoptions=gtk.FILL, xpadding=gnome.uiconsts.PAD)
        self.g_slow_bpm = gu.tSpinButton(table, 1, 2, 0, 1,
                                         self.get_int('config/slow_bpm'),
                                         10, 500, 1, 10,
                                         self.on_changed)
        self.g_default_bpm = gu.tSpinButton(table, 1, 2, 1, 2,
                                            self.get_int('config/default_bpm'),
                                            10, 500, 1, 10,
                                            self.on_changed)
        self.g_arpeggio_bpm = gu.tSpinButton(table, 1, 2, 2, 3,
                                           self.get_int('config/arpeggio_bpm'),
                                             10, 500, 1, 10, self.on_changed)
        self.g_instrsel = ReadOnlyInstrumentSelector(_("Preferred instrument"),
               'config', 'preferred_instrument', self.on_changed)
        self.g_instrsel.set_border_width(gnome.uiconsts.PAD)
        hbox.pack_start(self.g_instrsel, gtk.FALSE)
        ########
        # user #
        ########
        box = gtk.GtkVBox()
        box.set_border_width(gnome.uiconsts.PAD)
        self.append_page(box, gtk.GtkLabel(_("User")))
        hbox = gu.bHBox(box, gtk.FALSE)

        table = gtk.GtkTable(2, 3, gtk.FALSE)
        hbox.pack_start(table, gtk.FALSE)
        gu.tLabel(table, 0, 1, 0, 1, _("Highest note user can sing:"), 1.0,
                  xoptions=gtk.FILL, xpadding=gnome.uiconsts.PAD_SMALL)
        gu.tLabel(table, 0, 1, 1, 2, _("Lowest note user can sing:"), 1.0,
                  xoptions=gtk.FILL, xpadding=gnome.uiconsts.PAD_SMALL)

        self.g_highest_singable = widgets.SimplestNotenameSpinButton(
            self.get_string('user/highest_pitch'))
        self.g_highest_singable.g_entry.connect('changed', self.on_changed)
        table.attach(self.g_highest_singable, 1, 2 , 0, 1)
        self.g_lowest_singable = widgets.SimplestNotenameSpinButton(
            self.get_string('user/lowest_pitch'))
        self.g_lowest_singable.g_entry.connect('changed', self.on_changed)
        table.attach(self.g_lowest_singable, 1, 2, 1, 2)
        widgets.NotenameRangeController(
                  self.g_lowest_singable, self.g_highest_singable,
                  mpd.LOWEST_NOTENAME, mpd.HIGHEST_NOTENAME)

        hbox = gu.bHBox(box, gtk.FALSE)
        self.g_sex_male = gtk.GtkRadioButton(None, _("Male"))
        self.g_sex_male.connect('clicked', self.on_changed)
        hbox.pack_start(self.g_sex_male, gtk.FALSE)
        self.g_sex_female = gtk.GtkRadioButton(self.g_sex_male, _("Female"))
        self.g_sex_female.connect('clicked', self.on_changed)
        hbox.pack_start(self.g_sex_female, gtk.FALSE)
        if self.get_string('user/sex') == 'female':
            self.g_sex_female.set_active(gtk.TRUE)
        #######
        # gui #
        #######
        vbox = gtk.GtkVBox()
        vbox.set_border_width(gnome.uiconsts.PAD)
        self.append_page(vbox, gtk.GtkLabel(_("Gui")))

        hbox = gu.bHBox(vbox, gtk.FALSE)
        hbox.set_spacing(gnome.uiconsts.PAD)

        frame = gtk.GtkFrame(_("Main toolbar"))
        frame.set_border_width(gnome.uiconsts.PAD)
        hbox.pack_start(frame, gtk.FALSE)
        frame_vbox = gtk.GtkVBox()
        frame_vbox.set_border_width(gnome.uiconsts.PAD)
        frame.add(frame_vbox)
        frame_hbox = gu.bHBox(frame_vbox)

        self.g_toolbar_icons = gu.RadioButton(None, _("Icons"), self.on_changed)
        frame_hbox.pack_start(self.g_toolbar_icons, gtk.FALSE)
        self.g_toolbar_text = gu.RadioButton(self.g_toolbar_icons, _("Text"), self.on_changed)
        frame_hbox.pack_start(self.g_toolbar_text, gtk.FALSE)
        self.g_toolbar_both = gu.RadioButton(self.g_toolbar_icons, _("Both"), self.on_changed)
        frame_hbox.pack_start(self.g_toolbar_both, gtk.FALSE)
        sep = gtk.GtkHSeparator()
        frame_vbox.pack_start(sep)
        self.__dict__['g_toolbar_'+self.get_string('gui/toolbar_style=icons')].set_active(gtk.TRUE)
        frame_hbox = gu.bHBox(frame_vbox, gtk.FALSE)
        self.g_toolbar_show = gu.RadioButton(None, _("Show"), self.on_changed)
        frame_hbox.pack_start(self.g_toolbar_show, gtk.FALSE)
        self.g_toolbar_hide = gu.RadioButton(self.g_toolbar_show, _("Hide"), self.on_changed)
        frame_hbox.pack_start(self.g_toolbar_hide, gtk.FALSE)
        if self.get_bool('gui/toolbar_visible'):
            self.g_toolbar_show.set_active(gtk.TRUE)
        else:
            self.g_toolbar_hide.set_active(gtk.TRUE)

        frame = gtk.GtkFrame(_("Navigation toolbar"))
        frame.set_border_width(gnome.uiconsts.PAD)
        hbox.pack_start(frame, gtk.FALSE)
        frame_vbox = gtk.GtkVBox()
        frame_vbox.set_border_width(gnome.uiconsts.PAD)
        frame.add(frame_vbox)
        frame_hbox = gu.bHBox(frame_vbox)
        sep = gtk.GtkHSeparator()
        frame_vbox.pack_start(sep)

        self.g_navbar_icons = gu.RadioButton(None, _("Icons"), self.on_changed)
        frame_hbox.pack_start(self.g_navbar_icons, gtk.FALSE)
        self.g_navbar_text = gu.RadioButton(self.g_navbar_icons, _("Text"), self.on_changed)
        frame_hbox.pack_start(self.g_navbar_text, gtk.FALSE)
        self.g_navbar_both = gu.RadioButton(self.g_navbar_icons, _("Both"), self.on_changed)
        frame_hbox.pack_start(self.g_navbar_both, gtk.FALSE)
        self.__dict__['g_navbar_'+self.get_string('gui/navbar_style=icons')].set_active(gtk.TRUE)
        frame_hbox = gu.bHBox(frame_vbox, gtk.FALSE)
        self.g_navbar_show = gu.RadioButton(None, _("Show"), self.on_changed)
        frame_hbox.pack_start(self.g_navbar_show, gtk.FALSE)
        self.g_navbar_hide = gu.RadioButton(self.g_navbar_show, _("Hide"), self.on_changed)
        frame_hbox.pack_start(self.g_navbar_hide, gtk.FALSE)
        if self.get_bool('gui/navbar_visible'):
            self.g_navbar_show.set_active(gtk.TRUE)
        else:
            self.g_navbar_hide.set_active(gtk.TRUE)

        self.g_mainwin_user_resizeable = gtk.GtkCheckButton(
              _("User resizeable main window"))
        self.g_mainwin_user_resizeable.connect('clicked', self.on_changed)
        self.g_mainwin_user_resizeable.set_active(
                        self.get_bool('gui/mainwin_user_resizeable'))
        vbox.pack_start(self.g_mainwin_user_resizeable, gtk.FALSE)

        self.g_development_menu_visible = gtk.GtkCheckButton(
            _("Show development menu"))
        self.g_development_menu_visible.connect('clicked', self.on_changed)
        self.g_development_menu_visible.set_active(
                       self.get_bool('gui/development_menu_visible'))
        vbox.pack_start(self.g_development_menu_visible, gtk.FALSE)
        self._is_alive = 1

        hbox = gu.bHBox(vbox)
        hbox.set_spacing(gnome.uiconsts.PAD_SMALL)
        hbox.pack_start(gtk.GtkLabel(_("Web browser:")), gtk.FALSE)
        self.g_web_browser = gtk.GtkEntry()
        self.g_web_browser.set_text(self.get_string("config/web_browser"))
        self.g_web_browser.connect('changed', self.on_changed)
        hbox.pack_start(self.g_web_browser)

        hbox = gu.bHBox(vbox)
        hbox.set_spacing(gnome.uiconsts.PAD_SMALL)
        hbox.pack_start(gtk.GtkLabel(_("Mail program:")), gtk.FALSE)
        self.g_mail_program = gtk.GtkEntry()
        self.g_mail_program.set_text(self.get_string("config/mua"))
        self.g_mail_program.connect('changed', self.on_changed)
        hbox.pack_start(self.g_mail_program)

        ############
        # Practise #
        ############
        vbox = gtk.GtkVBox()
        vbox.set_border_width(gnome.uiconsts.PAD)
        self.append_page(vbox, gtk.GtkLabel(_("Practise")))

        self.g_picky_on_new_question = gtk.GtkCheckButton(_("Not allow new question before the old is solved"))
        self.g_picky_on_new_question.set_active(self.get_bool('config/picky_on_new_question'))
        vbox.pack_start(self.g_picky_on_new_question, gtk.FALSE)

        self.g_autorepeat_if_wrong = gtk.GtkCheckButton(_("Repeat question if the answer was wrong"))
        self.g_autorepeat_if_wrong.set_active(self.get_bool('config/auto_repeat_question_if_wrong_answer'))
        vbox.pack_start(self.g_autorepeat_if_wrong, gtk.FALSE)

        self.g_picky_on_new_question.connect('clicked', self.on_changed)
        self.g_autorepeat_if_wrong.connect('clicked', self.on_changed)

        #########
        # sound #
        #########
        if sys.platform == 'win32':
            self.create_win32_sound_page()
        else:
            self.create_linux_sound_page()
        self.show_all()
    def create_linux_sound_page(self):
        vbox = gtk.GtkVBox()
        vbox.set_border_width(gnome.uiconsts.PAD)
        self.append_page(vbox, gtk.GtkLabel(_("Sound setup")))
        txt = gtk.GtkLabel(_("""Solfege has two ways to play music. It can use /dev/music or an external midi player program. The preferred way is to use /dev/music since this offers features that will be utilized more in later versions of this program."""))
        txt.set_line_wrap(1)
        txt.set_justify(gtk.JUSTIFY_FILL)
        txt.set_alignment(0.0, 0.0)
        vbox.pack_start(txt, gtk.FALSE)
        self.g_fakesynth_radio = gu.RadioButton(None, _("No sound"), None)
        vbox.pack_start(self.g_fakesynth_radio, gtk.FALSE)
        hbox = gu.bHBox(vbox, gtk.FALSE)
        self.g_device_radio = gu.RadioButton(self.g_fakesynth_radio,
              _("Use device"), None)
        hbox.pack_start(self.g_device_radio, gtk.FALSE)
        combo = gtk.GtkCombo()
        combo.set_popdown_strings(('/dev/sequencer', '/dev/sequencer2',
                                   '/dev/music'))
        self.g_device_entry = combo.entry
        self.g_device_entry.set_text(self.get_string('sound/device_file'))
        self.g_synth_num = gtk.GtkSpinButton(gtk.GtkAdjustment(0, 0, 100, 1, 1),
                             digits=0)
        self.g_synth_num.set_value(self.get_int('sound/synth_number'))
        hbox.pack_start(combo, gtk.FALSE)
        hbox.pack_start(self.g_synth_num, gtk.FALSE)

        hbox = gu.bHBox(vbox, gtk.FALSE)
        self.g_midiplayer_radio = gu.RadioButton(self.g_fakesynth_radio,
             _("Use external midiplayer"), None)
        hbox.pack_start(self.g_midiplayer_radio, gtk.FALSE)
        combo = gtk.GtkCombo()
        combo.set_popdown_strings(('drvmidi -i d %s',
                                   'timidity -idqq %s',
                                   'playmidi -f %s'))
        self.g_midiplayer_entry = combo.entry
        hbox.pack_start(combo, gtk.FALSE)
        self.g_midiplayer_entry.set_text(self.get_string("sound/commandline"))
        if self.get_string("sound/type") == "external-midiplayer":
            self.g_midiplayer_radio.set_active(gtk.TRUE)
        elif self.get_string("sound/type") == "sequencer-device":
            self.g_device_radio.set_active(gtk.TRUE)
        else:
            self.g_fakesynth_radio.set_active(gtk.TRUE)

        # checkbox to enable awe support
        self.g_awe_checkbutton = gtk.GtkCheckButton(_("My sound card is Sound Blaster AWE32, AWE64 or pnp32"))
        self.g_awe_checkbutton.set_active(self.get_string('sound/card_info') == 'awe')
        if not configureoutput.HAVE_LINUX_AWE_VOICE_H:
            self.g_awe_checkbutton.set_sensitive(gtk.FALSE)
        vbox.pack_start(self.g_awe_checkbutton)

        gu.bButton(vbox, _("Sound test. Hit 'Apply' before testing."), self.on_sound_test)

        self.g_fakesynth_radio.connect('clicked', self.on_changed)
        self.g_midiplayer_radio.connect('clicked', self.on_changed)
        self.g_device_radio.connect('clicked', self.on_changed)
        self.g_midiplayer_entry.connect('changed', self.on_changed)
        self.g_device_entry.connect('changed', self.on_changed)
        self.g_synth_num.connect('changed', self.on_changed)
        self.g_awe_checkbutton.connect('clicked', self.on_changed)
    def create_win32_sound_page(self):
        vbox = gtk.GtkVBox()
        vbox.set_border_width(gnome.uiconsts.PAD)
        self.append_page(vbox, gtk.GtkLabel(_("Sound setup")))
        txt = gtk.GtkLabel(_("""Solfege has two ways to play music. It is recommended to use Windows multimedia output. Support for external midiplayer is only available because this was the only way to get sound on Windows in earlier versions of this program."""))
        txt.set_line_wrap(1)
        txt.set_justify(gtk.JUSTIFY_FILL)
        txt.set_alignment(0.0, 0.0)
        vbox.pack_start(txt, gtk.FALSE)
        self.g_fakesynth_radio = gu.RadioButton(None, _("No sound"), None)
        vbox.pack_start(self.g_fakesynth_radio, gtk.FALSE)
        hbox = gu.bHBox(vbox, gtk.FALSE)
        self.g_device_radio = gu.RadioButton(self.g_fakesynth_radio,
              _("Windows multimedia output, synth number:"), None)
        self.g_synth_num = gtk.GtkSpinButton(gtk.GtkAdjustment(0, 0, 100, 1, 1),
                             digits=0)
        self.g_synth_num.set_value(self.get_int('sound/synth_number'))
        hbox.pack_start(self.g_device_radio, gtk.FALSE)
        hbox.pack_start(self.g_synth_num, gtk.FALSE)

        hbox = gu.bHBox(vbox, gtk.FALSE)
        self.g_midiplayer_radio = gu.RadioButton(self.g_fakesynth_radio,
             _("Use external midiplayer"), None)
        hbox.pack_start(self.g_midiplayer_radio, gtk.FALSE)
        combo = gtk.GtkCombo()
        combo.set_popdown_strings(('midiplayer.exe %s',
                                   'timidity -idqq %s',
                                   'playmidi -f %s'))
        self.g_midiplayer_entry = combo.entry
        hbox.pack_start(combo, gtk.FALSE)
        self.g_midiplayer_entry.set_text(self.get_string("sound/commandline"))
        if self.get_string("sound/type") == "external-midiplayer":
            self.g_midiplayer_radio.set_active(gtk.TRUE)
        elif self.get_string("sound/type") == "winsynth":
            self.g_device_radio.set_active(gtk.TRUE)
        else:
            self.g_fakesynth_radio.set_active(gtk.TRUE)

        gu.bButton(vbox, _("Sound test. Hit 'Apply' before testing."), self.on_sound_test)

        self.g_fakesynth_radio.connect('clicked', self.on_changed)
        self.g_midiplayer_radio.connect('clicked', self.on_changed)
        self.g_synth_num.connect('changed', self.on_changed)
        self.g_device_radio.connect('clicked', self.on_changed)
        self.g_midiplayer_entry.connect('changed', self.on_changed)
    def on_sound_test(self, w):
        mpd.play_music(r"""
        \staff\relative c{
          c16 e g c e, g c e g, c e g c4
        }
        \staff{
          c4 e g8 e c4
        }
        """, 130, 0, 100)
    def on_help(self, *v):
        #FIXME It is stupid to display this help in the main window.
        self.m_app.handle_href("preferences-window.html")
    def on_changed(self, _o=None):
        if self._is_alive:
            self.set_modified(gtk.TRUE)
    def on_apply(self, _o, pagenum):
        card_info = ""
        if pagenum == 0:
            self.set_int('config/slow_bpm', int(self.g_slow_bpm.get_text()))
            self.set_int('config/default_bpm',
                         int(self.g_default_bpm.get_text()))
            self.set_int('config/arpeggio_bpm',
                         int(self.g_arpeggio_bpm.get_text()))
            self.set_int('config/preferred_instrument',
                         self.g_instrsel.m_instrument)
            self.set_int('config/preferred_instrument_velocity',
                         self.g_instrsel.g_velocity.get_value_as_int())
        if pagenum == 1:
            self.set_string('user/lowest_pitch',
                            self.g_lowest_singable.get_value())
            self.set_string('user/highest_pitch',
                            self.g_highest_singable.get_value())
            if self.g_sex_male.active:
                self.set_string('user/sex', 'male')
            else:
                self.set_string('user/sex', 'female')
        if pagenum == 2:
            if self.g_toolbar_text.active:
                self.m_app.m_ui.g_toolbar.set_style(gtk.TOOLBAR_TEXT)
                self.set_string('gui/toolbar_style', 'text')
            elif self.g_toolbar_icons.active:
                self.m_app.m_ui.g_toolbar.set_style(gtk.TOOLBAR_ICONS)
                self.set_string('gui/toolbar_style', 'icons')
            elif self.g_toolbar_both.active:
                self.m_app.m_ui.g_toolbar.set_style(gtk.TOOLBAR_BOTH)
                self.set_string('gui/toolbar_style', 'both')
            if self.g_toolbar_show.active:
                self.m_app.m_ui.get_dock_item_by_name('main-toolbar').show()
                self.set_bool('gui/toolbar_visible', 1)
            else:
                self.set_bool('gui/toolbar_visible', 0)
                self.m_app.m_ui.get_dock_item_by_name('main-toolbar').hide()

            if self.g_navbar_text.active:
                self.m_app.m_ui.g_navbar.set_style(gtk.TOOLBAR_TEXT)
                self.set_string('gui/navbar_style', 'text')
            elif self.g_navbar_icons.active:
                self.m_app.m_ui.g_navbar.set_style(gtk.TOOLBAR_ICONS)
                self.set_string('gui/navbar_style', 'icons')
            elif self.g_navbar_both.active:
                self.m_app.m_ui.g_navbar.set_style(gtk.TOOLBAR_BOTH)
                self.set_string('gui/navbar_style', 'both')
            if self.g_navbar_show.active:
                self.m_app.m_ui.get_dock_item_by_name('backandforward').show()
                self.set_bool('gui/navbar_visible', 1)
            else:
                self.m_app.m_ui.get_dock_item_by_name('backandforward').hide()
                self.set_bool('gui/navbar_visible', 0)
            self.set_bool('gui/mainwin_user_resizeable',
                          self.g_mainwin_user_resizeable.active)
            if self.get_bool('gui/mainwin_user_resizeable'):
                self.m_app.m_ui.set_policy(0, 1, 0)
            else:
                self.m_app.m_ui.set_policy(0, 0, 1)
            self.set_string("config/web_browser", self.g_web_browser.get_text())
            self.set_string("config/mua", self.g_mail_program.get_text())
            self.set_bool('gui/development_menu_visible',
                          self.g_development_menu_visible.active)
            if self.get_bool('gui/development_menu_visible'):
                self.m_app.m_ui.get_dock_item_by_name("Menubar").children()[0].children()[1].show()
            else:
                self.m_app.m_ui.get_dock_item_by_name("Menubar").children()[0].children()[1].hide()
        if pagenum == 3:
            self.set_bool('config/picky_on_new_question',
                          self.g_picky_on_new_question.active)
            self.set_bool('config/auto_repeat_question_if_wrong_answer',
                          self.g_autorepeat_if_wrong.active)
        if pagenum == 4:
            if soundcard.synth:
                soundcard.synth.close()
            if self.g_midiplayer_radio.active:
                soundcard.initialise_external_midiplayer(
                      self.g_midiplayer_entry.get_text())
            elif self.g_device_radio.active:
                if sys.platform != 'win32' and configureoutput.HAVE_LINUX_AWE_VOICE_H and \
                    self.g_awe_checkbutton.active:
                      card_info = "awe"
                else:
                     card_info = ""
                try:
                    if sys.platform == 'win32':
                        soundcard.initialise_winsynth(self.g_synth_num.get_value_as_int())
                    else:
                        soundcard.initialise_devicefile(
                            self.g_device_entry.get_text(),
                            self.g_synth_num.get_value_as_int(),
                            card_info)
                except (soundcard.SoundInitException, OSError), e:
                    self.m_app.display_sound_init_error_message(e)
		    return
            elif self.g_fakesynth_radio.active:
                soundcard.initialise_using_fake_synth(0)
            else:
                raise "Shit"
            if self.g_midiplayer_radio.active:
                self.set_string("sound/type", "external-midiplayer")
            elif self.g_device_radio.active:
                self.set_string("sound/type", "sequencer-device")
            else:
                assert self.g_fakesynth_radio.active
                self.set_string("sound/type", "fake-synth")
            if sys.platform != 'win32':
                self.set_string("sound/device_file", self.g_device_entry.get_text())
                self.set_string("sound/card_info", card_info)
                if soundcard.synth.m_type_major == "OSS":
                    self.set_int("sound/synth_number", soundcard.synth.m_devnum)
                    # we set the spin just in case m_devnum was changed by the
                    # soundcard setup code, if it was out of range
                    self.g_synth_num.set_value(soundcard.synth.m_devnum)
            self.set_string("sound/commandline",
                            self.g_midiplayer_entry.get_text())
        if pagenum == -1:
            pass


