# GNU Solfege - ear training for GNOME
# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005  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 __builtin__
import types
try:
    basestring
except:
    basestring = (types.StringType, types.UnicodeType)
    __builtin__.basestring = basestring

__builtin__.app_running = True
__builtin__.__exdata__ = []

import sys, os, time, random

if sys.version_info < (2, 2):
    print "********************************************************************"
    print "Solfege need Python 2.2 or newer. The configure script told you so!"
    print "********************************************************************"
    sys.exit(-1)

# i18n should be imported very early in program init because it setup
# the _ and _i functions for the whole program.
import i18n
i18n.setup()

import configureoutput

def do_some_cmdline_options(argv):
    if '-h' in argv or '--help' in argv:
        print """
GNU Solfege %s
Type "man solfege" for more details.
Options:
  --no-sound             Do not play any sounds. Useful when porting.
  --verbose-sound-init   display more info about the sound setup
  -v, --version
  -w, --warranty         show warranty and copyright
  -h, --help             Display this message
  --gtk-help             Display the usual gtk/gnome commandline options.
    """ % configureoutput.VERSION_STRING
        sys.exit()

    if '-v' in argv or '--version' in argv:
        print """GNU Solfege %s
This is free software. It is covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions. Invoke as `solfege --warranty` for more information.

Copyright (C) 2000, 2001, 2002, 2003, 2004  Tom Cato Amundsen <tca@gnu.org>
        """ % configureoutput.VERSION_STRING
        sys.exit()

    if '-w' in argv or '--warranty' in argv:
        print """GNU Solfege %s
Copyright (C) 2000, 2001, 2002, 2003, 2004  Tom Cato Amundsen <tca@gnu.org>

    This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

    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 (refer to the file COPYING) of the
GNU General Public License along with this program; if not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA.
        """ % configureoutput.VERSION_STRING
        sys.exit()


do_some_cmdline_options(sys.argv)

if '--gtk-help' in sys.argv:
    del sys.argv[sys.argv.index('--gtk-help')]
    sys.argv.append('--help')

# silent, GNOME, be silent!
sys.argv.append('--disable-sound')

import pygtk
# this is needed for py2exe
if sys.platform == 'win32':
    os.environ['PATH'] += ";lib;bin;"
else:
    pygtk.require("2.0")

if not configureoutput.WITH_GNOME:
    sys.path.insert(0, "gnomeemu")

import gtk

if gtk.pygtk_version < (1, 99, 11):
    print "-"*55
    print " GNU Solfege requires pygtk version 1.99.11 or newer."
    print " The version installed appears to be", gtk.pygtk_version, "."
    print " Exiting program."
    print "-"*55+"\n"
    sys.exit(-1)

gtk.rc_parse("solfege.gtkrc")

class SplashWin(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self, gtk.WINDOW_POPUP)
        self.set_position(gtk.WIN_POS_CENTER)
        self.set_resizable(True)
        frame = gtk.Frame()
        frame.set_shadow_type(gtk.SHADOW_OUT)
        self.add(frame)
        vbox = gtk.VBox()
        vbox.set_border_width(20)
        frame.add(vbox)
        l = gtk.Label(_("Starting GNU Solfege %s") % configureoutput.VERSION_STRING)
        l.set_name("Heading1")
        vbox.pack_start(l)
        l = gtk.Label("http://www.solfege.org")
        vbox.pack_start(l)
        self.g_infolabel = gtk.Label('')
        vbox.pack_start(self.g_infolabel)
        self.show_all()
    def show_progress(self, txt):
        self.g_infolabel.set_text(txt)
        while gtk.events_pending():
            gtk.main_iteration(0)

if not filter(lambda a: a in sys.argv, ['--no-splash', '--usage', '-?', '--gtk-help']):
    splash_win = SplashWin()
    time.sleep(0.1)
    gtk.gdk.flush()
    while gtk.events_pending():
        gtk.main_iteration(0)
else:
    splash_win = None
    if '--no-splash' in sys.argv:
        del sys.argv[sys.argv.index('--no-splash')]

# we have to remove all options gnome/gtk don't understand
# from sys.argv
args = []
for a in ('--no-sound', '--verbose-sound-init'):
    if a in sys.argv:
        args.append(a)
        del sys.argv[sys.argv.index(a)]

if splash_win:
    splash_win.show_progress("importing GNOME modules")

import gnome, gnome.ui
# FIXME we set this because it is not yet added to PyGNOME2
gnome.ui.PAD = 8
gnome.ui.PAD_SMALL = 4
gnome.ui.PAD_BIG = 12

if splash_win:
    splash_win.show_progress("importing application modules")

import tracebackwindow
# redirect error messages to a window that will popup if
# something bad happens.

sys.stderr = tracebackwindow.TracebackWindow()

import const
import app
from htmlwidget import HtmlWidget
import utils, history
from configwindow import ConfigWindow
import soundcard
import mpd, mpd.musicdisplayer, gu, cfg
import stock


# The order the modules are imported affect the ordering in the menus.
import melodicinterval, chord, rhythm
import chordvoicing, harmonicinterval, \
       singinterval, idbyname, dictation, twelvetone, \
       idtone, compareintervals, singchord, identifybpm, \
       harmonicprogressiondictation, singanswer,\
       polyrhythm, intervals

import exercise_setup
exercise_setup.register_exercise({
    'exercise_name': 'id-by-name',
    'exercise_config': 'solfege/scales',
    'menu_path': '%s/%s' % (_("_Misc exercises"), _("_Scales")),
    'toolbar': 4.5,
    'stock-icon': 'solfege-identify-scale',
})
exercise_setup.register_exercise({
    'exercise_name': 'id-by-name',
    'exercise_config': 'solfege/scales-thirds',
    'menu_path': '%s/%s' % (_("_Misc exercises"), _("Scales in t_hirds")),
    'stock-icon': 'solfege-identify-scale',
})


class DocViewer(gtk.VBox):
    def __init__(self, activate_cb):
        gtk.VBox.__init__(self)
        self.m_htmlwidget = HtmlWidget(activate_cb, self.on_anchor_track)
        self.m_htmlwidget.show_all()
        self.pack_start(self.m_htmlwidget)
        self.set_size_request(500, 300)
        #self.read_docfile = self.m_htmlwidget.read_docfile
        self.get_vadjustment = self.m_htmlwidget.get_vadjustment
        self.on_key_press_event = self.m_htmlwidget.on_key_press_event
        self.m_statusbar = gtk.Statusbar()
        self.m_statusbar.show()
        self.pack_start(self.m_statusbar, False)
        self.source = self.m_htmlwidget.source
        self.grab_focus = self.m_htmlwidget.grab_focus
    def read_docfile(self, fn, anchor):
        """
        We reread the docfile even if we are alreado displaying this file,
        just in case it has changed on disk.
        """
        self.m_htmlwidget.read_docfile(fn)
        #if anchor:
        #    #FIXME jump_to_anchor is not implemented yet it gnome-python,
        #    # or maybe I just don't understand how to use it.
        #    #self.m_htmlwidget.g_view.jump_to_anchor(anchor)
        #else:
        a = self.m_htmlwidget.get_vadjustment()
        a.set_value(0.0)
    def on_anchor_track(self, url):
        if url:
            # remove newlines in url because it make the window resize
            s = url.replace("\n", "")
            self.m_statusbar.pop(1)
            self.m_statusbar.push(1, s)
        else:
            self.m_statusbar.pop(1)


class MusicViewerWindow(gtk.Dialog):
    def __init__(self, app):
        gtk.Dialog.__init__(self)
        self.m_app = app
        self.set_default_size(400, 200)
        self.g_music_displayer = mpd.musicdisplayer.MusicDisplayer(utils.play_tone)
        self.vbox.pack_start(self.g_music_displayer)
        b = gu.bButton(self.action_area, _("Close"), self.m_app.close_musicviewer)
        b.grab_focus()
        self.connect('destroy', self.m_app.close_musicviewer)
        self.show_all()
    def display_music(self, music):
        fontsize = cfg.get_int('config/feta_font_size=20')
        self.g_music_displayer.display(music, fontsize)

class MainWin(gnome.ui.App, cfg.ConfigUtils):
    def __init__(self, argv):
        gnome.ui.App.__init__(self, 'solfege', 'GNU Solfege')
        self.icons = stock.SolfegeIconFactory(self, configureoutput.datadir)
        self.set_default_size(400, 400)
        pixbuf = self.render_icon('solfege-icon', gtk.ICON_SIZE_DIALOG)
        self.set_icon(pixbuf)
        cfg.ConfigUtils.__dict__['__init__'](self, 'mainwin')
        self.set_resizable(self.get_bool('gui/mainwin_user_resizeable'))
        self.connect('destroy', self.quit_program)
        self.connect('key_press_event', self.on_key_press_event)
        self.g_about_window = None
        self.main_box = gtk.VBox()
        self.main_box.show()
        self.set_contents(self.main_box)
        self.m_exercise = None
        self.m_viewer = None
        self.box_dict = {}
        self.g_config_window = None
        self.g_musicviewer_window = None
        self.m_history = history.History()
        self.m_key_bindings = {'history_back_ak': self.history_back,
                               'history_forward_ak': self.history_forward,
                               'history_reload_ak': self.history_reload}
        self.m_app = app.SolfegeApp(argv, self)
        self.setup_toolbar()
        self.setup_menubar()
        self.m_app.handle_href('welcome.html')
    def dialog_yesno(self, text):
        """Return True if the answer is yes, False if the answer is no.
        """
        m = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION,
                gtk.BUTTONS_YES_NO, text)
        ret = m.run()
        m.destroy()
        return ret == gtk.RESPONSE_YES
    def display_exception_message(self, exception, err_file=None):
        """Call this function only inside an except clause."""
        if err_file:
            msg = _("Exception catched in %s:%i\n") % (err_file, sys.exc_info()[2].tb_lineno) + "\n"
        else:
            msg = ""
        msg += str(exception)
        m = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
                              gtk.BUTTONS_CLOSE, msg)
        m.set_title(sys.exc_info()[0].__name__)
        m.run()
        m.destroy()
    def display_error_message(self, msg, err_pos=None):
        if err_pos:
            msg = _("Error found in %s:\n") % err_pos + "\n" + msg
        m = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
                              gtk.BUTTONS_CLOSE, msg)
        m.run()
        m.destroy()
    def display_question_music_error_message(self, idx, lessonfile, exception, err_file=None):
        """Call this function only inside an except clause."""
        msg = _("Failed to parse the music for question number %(idx)i in '%(lf)s':\n%(ex)s") % {'idx': idx, 'lf': lessonfile, 'ex': exception}
        self.display_exception_message(msg, err_file)
    def show_about_window(self, widget):
        #if not self.g_about_window:
        if 1:
            trans = _("SOLFEGETRANSLATORS")
            if trans == 'SOLFEGETRANSLATORS':
                trans = ""
            pixbuf = self.render_icon('solfege-icon', gtk.ICON_SIZE_DIALOG)
            self.g_about_window = gnome.ui.About("GNU Solfege",
                  configureoutput.VERSION_STRING,
                  "Copyright (C) 2000, 2001, 2002, 2003, 2004  Tom Cato Amundsen",
                  _("GPL'ed ear training.") + "\n" + "http://www.solfege.org",
                  ["Tom Cato Amundsen",
                  'Oliver Vollmer %s' % _("(toolbar icons)"),
                  'Giovanni Chierico %s' % _("(some lessonfiles)"),
                  'Michael Becker %s' % _("(some lessonfiles)"),
                  'Joe Lee %s' % _("(sound code for the MS Windows port)"),
                  ],
                  ["Tom Cato Amundsen"],
                  trans, pixbuf)
            #self.g_about_window.connect('destroy', self.hide_about_window)
            #self.g_about_window.show()
            #FIXME this sucks.
            i = self.g_about_window.run()
            #self.g_about_window.destroy()
    def hide_about_window(self, widget):
        self.g_about_window.destroy()
        self.g_about_window = None
    def post_constructor(self):
        if not self.get_bool("gui/navbar_visible"):
            self.get_dock_item_by_name('navbar').hide()
        if not self.get_bool("gui/toolbar_visible"):
            self.get_dock_item_by_name('toolbar').hide()
        self.box_dict['docviewer'].grab_focus()
        if self.m_app.m_sound_init_exception is not None:
            self.m_app.display_sound_init_error_message(self.m_app.m_sound_init_exception)
    def activate_exercise(self, href):
        protocol, action, exname, anchor, collection, lessonfile, config = \
           utils.parse_url(href)
        assert protocol == 'solfege'
        if self.m_viewer:
            self.box_dict[self.m_viewer].hide()
        self.box_dict[exname].show()
        self.m_viewer = exname
        if action in ['practise', 'config', 'statistics']:
            # We need this test because not all exercises use a notebook.
            if self.box_dict[self.m_viewer].g_notebook:
                self.box_dict[self.m_viewer].g_notebook.set_current_page(
                   ['practise', 'config', 'statistics'].index(action))
        self.set_title("Solfege - " + self.box_dict[exname].get_pretty_name())
        self.m_history.add(href)
    def _show_docviewer(self):
        if 'docviewer' not in self.box_dict:
            self.box_dict['docviewer'] = DocViewer(self.m_app.handle_href)
            self.main_box.pack_start(self.box_dict['docviewer'])
        if self.m_viewer and (self.m_viewer != 'docviewer'):
            self.box_dict[self.m_viewer].hide()
        self.m_viewer = 'docviewer'
        self.box_dict['docviewer'].show()
    def display_docfile(self, fn, anchor):
        self._show_docviewer()
        self.box_dict['docviewer'].read_docfile(fn, anchor)
        self.set_title("Solfege - %s" % fn)
        self.m_history.add(fn)
    def display_html(self, html):
        self._show_docviewer()
        self.box_dict['docviewer'].source(html)
    def history_back(self, *v):
        if self.m_viewer == 'docviewer':
            self.m_history.set_adj_of_current(
              self.box_dict['docviewer'].get_vadjustment().get_value())
        self.m_history.back()
        self.m_history.lock()
        url, adj = self.m_history.get_current()
        self.m_app.handle_href(url, display_docfile_set_adj=0)
        if self.m_viewer == 'docviewer':
            self.box_dict['docviewer'].get_vadjustment().set_value(adj)
        self.m_history.unlock()
    def history_forward(self, *v):
        if self.m_viewer == 'docviewer':
            self.m_history.set_adj_of_current(
              self.box_dict['docviewer'].get_vadjustment().get_value())
        self.m_history.forward()
        self.m_history.lock()
        url, adj = self.m_history.get_current()
        self.m_app.handle_href(url, display_docfile_set_adj=0)
        if self.m_viewer == 'docviewer':
            self.box_dict['docviewer'].get_vadjustment().set_value(adj)
        self.m_history.unlock()
    def history_reload(self, *v):
        self.m_history.lock()
        self.m_app.handle_href(self.m_history.get_current()[0])
        self.m_history.unlock()
    def initialise_exercise(self, teacher):
        assert teacher.m_exname not in self.box_dict
        n = utils.exercise_name_to_module_name(teacher.m_exname)
        self.box_dict[teacher.m_exname] = globals()[n].Gui(teacher, self)
        self.main_box.pack_start(self.box_dict[teacher.m_exname])
    def on_key_press_event(self, widget, event):
        if event.type == gtk.gdk.KEY_PRESS:
            for s in self.m_key_bindings:
                if (event.state & (gtk.gdk.CONTROL_MASK|gtk.gdk.SHIFT_MASK), event.keyval) \
                         == utils.parse_key_string(self.get_string(s)):
                    self.m_key_bindings[s]()
                    return 1
        self.box_dict[self.m_viewer].on_key_press_event(widget, event)
    def open_preferences_window(self, widget=None):
        if not self.g_config_window:
            self.g_config_window = ConfigWindow(self.m_app)
            #self.g_config_window.set_parent(self)
            self.g_config_window.show()
        else:
            self.g_config_window.show()
    def setup_menubar(self):
        ag = gtk.AccelGroup()
        self.add_accel_group(ag)
        self.g_menubar = menubar = gtk.MenuBar()
        self.set_menus(self.g_menubar)
        for label, func in ((_("_File"), self.create_file_menu),
                            (_("_View"), self.create_view_menu),
                            (_("_Help"), self.create_help_menu)):
            menuitem = gtk.MenuItem(label)
            menubar.add(menuitem)
            menuitem.set_submenu(func(ag))
        self.g_menubar.show_all()
    def create_submenu(self, data, ag):
        """FIXME rename
        """
        menu = gtk.Menu()
        for d in data:
            menuitem = gtk.ImageMenuItem(d['menu_path'].split('/')[1])
            if 'icon' in d:
                im = gtk.Image()
                im.set_from_file(d['icon'])
                im.set_from_pixbuf(im.get_pixbuf().scale_simple(16, 16, gtk.gdk.INTERP_TILES))
                menuitem.set_image(im)
            elif 'stock-icon' in d:
                im = gtk.Image()
                im.set_from_stock(d['stock-icon'], gtk.ICON_SIZE_MENU)
                menuitem.set_image(im)
            if 'exercise_config' in d:
                s = 'solfege:practise/%s/%s' % (d['exercise_name'], d['exercise_config'])
            else:
                s = 'solfege:practise/%s' % d['exercise_name']
            menuitem.connect('activate', lambda o, self=self, s=s: self.m_app.handle_href(s))
            if 'accel_key' in d:
                menuitem.add_accelerator('activate', ag, d['accel_key'], d['accel_mods'], gtk.ACCEL_VISIBLE)
            menu.add(menuitem)
        return menu
    def create_ex_menu(self, exlist, ag):
        """
        Each item in exlist:
        (MENUTEXT, URI, graphics/FILENAME.PNG)
        The icon is optional.
        """
        menu = gtk.Menu()
        for ex in exlist:
            if ex[0] == ex[1] == 'SEP':
                item = gtk.SeparatorMenuItem()
            else:
                item = gtk.ImageMenuItem(ex[0])
                item.connect('activate', lambda o, url=ex[1]: self.m_app.handle_href(url))
                if len(ex) > 2:
                    im = gtk.Image()
                    im.set_from_file(os.path.join('graphics', ex[2]))
                    im.set_from_pixbuf(im.get_pixbuf().scale_simple(16, 16, gtk.gdk.INTERP_TILES))
                    item.set_image(im)
            menu.add(item)
        return menu
    def get_file_menu_data(self):
        menus = {}
        sections = []
        for rec in __exdata__:
            m, n = rec['menu_path'].split("/")
            if m not in menus:
                menus[m] = []
                sections.append(m)
            menus[m].append(rec)
        return sections, menus
    def create_file_menu(self, ag):
        menu = gtk.Menu()
        if self.get_bool("gui/menus_have_tearoff"):
            item = gtk.TearoffMenuItem()
            menu.add(item)
        sections, d = self.get_file_menu_data()
        for k in sections:
            menuitem = gtk.MenuItem(k)
            menu.add(menuitem)
            menuitem.set_submenu(self.create_submenu(d[k], ag))
        ##
        menuitem = gtk.MenuItem(_("_Theory"))
        menu.add(menuitem)
        menuitem.set_submenu(self.create_ex_menu(
              ( ('_Scale names', 'theory-scales.html'),
                ('_Intervals', 'theory-intervals.html'),
               ), ag))
        item = gtk.MenuItem()
        item.add(gtk.HSeparator())
        menu.add(item)
        ##############
        # Preferences
        menu.add(gu.create_stock_menu_item('gtk-preferences', _("Preferences window"), self.open_preferences_window, ag, gtk.keysyms.F12, gtk.gdk.CONTROL_MASK))
        #######
        # Exit
        menu.add(gu.create_stock_menu_item('gtk-quit', _("_Exit"), self.quit_program, ag, gtk.keysyms.Q, gtk.gdk.CONTROL_MASK))
        return menu
    def create_view_menu(self, ag):
        menu = gtk.Menu()
        if self.get_bool("gui/menus_have_tearoff"):
            item = gtk.TearoffMenuItem()
            menu.add(item)
        # toolbar visible?
        toolitem = gtk.CheckMenuItem(_("_Toolbar"))
        toolitem.connect('toggled', self.on_view_menu_toolbar_visible_toggled)
        toolitem.set_active(self.get_bool('gui/toolbar_visible'))
        self.add_watch('gui/toolbar_visible', lambda key:
          toolitem.set_active(self.get_bool('gui/toolbar_visible')))
        menu.add(toolitem)

        # navbar visible?
        navitem = gtk.CheckMenuItem(_("_Navigation buttons"))
        navitem.connect('toggled', self.on_view_menu_navbar_visible_toggled)
        navitem.set_active(self.get_bool('gui/navbar_visible'))
        self.add_watch('gui/navbar_visible', lambda key:
          navitem.set_active(self.get_bool('gui/navbar_visible')))
        menu.add(navitem)

        if configureoutput.WITH_GTKHTML:
            menu.add(gtk.SeparatorMenuItem())
            menu.add(gu.create_stock_menu_item('gtk-zoom-in', _("Help viewer zoom in"),
               lambda w: self.box_dict['docviewer'].m_htmlwidget.g_view.zoom_in(),
               ag, gtk.keysyms.plus, gtk.gdk.CONTROL_MASK))
            menu.add(gu.create_stock_menu_item('gtk-zoom-out', _("Help viewer zoom out"),
               lambda w: self.box_dict['docviewer'].m_htmlwidget.g_view.zoom_out(),
               ag, gtk.keysyms.minus, gtk.gdk.CONTROL_MASK))
            menu.add(gu.create_stock_menu_item('gtk-zoom-100', _("Help viewer zoom reset"),
               lambda w: self.box_dict['docviewer'].m_htmlwidget.g_view.zoom_reset(),
               ag, gtk.keysyms.equal, gtk.gdk.CONTROL_MASK))
        return menu
    def on_zoom_in(self, *v):
        self.box_dict['docviewer'].m_htmlwidget.g_view.zoom_in()
    def on_view_menu_toolbar_visible_toggled(self, widget):
        """
        This function is called when the user selects the View/Toolbar menu
        to change if the toolbar is visible or not.
        """
        self.set_bool('gui/toolbar_visible', widget.get_active())
        if widget.get_active():
            self.get_dock_item_by_name("toolbar").show()
        else:
            self.get_dock_item_by_name("toolbar").hide()
    def on_view_menu_navbar_visible_toggled(self, widget):
        """
        This function is called when the user selects the View/Navbar menu
        to change it the navbar is visible or not.
        """
        self.set_bool('gui/navbar_visible', widget.get_active())
        if widget.get_active():
            self.get_dock_item_by_name("navbar").show()
        else:
            self.get_dock_item_by_name("navbar").hide()
    def create_help_menu(self, ag):
        menu = gtk.Menu()
        if self.get_bool("gui/menus_have_tearoff"):
            item = gtk.TearoffMenuItem()
            menu.add(item)
        item = gu.create_stock_menu_item('gtk-help', _("_Help on current exercise"),
                            lambda o, self=self: self.m_app.please_help_me(),
                            ag, gtk.keysyms.F1, 0)
        menu.add(item)
        for txt, url in (
                     (_("_Welcome"), 'welcome.html'),
                     (_("_All help files"), 'toc.html'),
                     (_("All installed _lesson files"), 'solfege:all-lessonfiles'),
                     ('SEP', 'SEP'),
                     (_("_Copyright notice"), 'copyright.html'),
                     (_("C_redits"), 'AUTHORS.html'),
                     (_("_Mailinglists, web page etc."), 'online-resources.html'),
                     (_("Reporting _bugs"), 'bug-reporting.html'),
                     ):
            if txt == url == 'SEP':
                item = gtk.SeparatorMenuItem()
                menu.add(item)
            else:
                item = gtk.MenuItem(txt)
                item.connect('activate', lambda o, self=self, url=url: self.m_app.handle_href(url))
                menu.add(item)
        item = gtk.MenuItem(_("_About"))
        item.connect('activate', self.show_about_window)
        menu.add(item)
        return menu
    def quit_program(self, w=None):
        self.m_app.quit_program()
        gtk.main_quit()
    def setup_toolbar(self):
        ## navbar
        self.g_navbar = gtk.Toolbar()
        self.g_navbar.insert_stock('gtk-go-forward', None, None,
                                   self.history_forward, 0, 0)
        self.g_navbar.insert_stock('gtk-go-back', None, None,
                                   self.history_back, 0, 0)
        self.g_navbar.show_all()
        self.add_toolbar(self.g_navbar, "navbar", "normal", "top", 1, 0, 0)
        s = self.get_string('gui/navbar_style')
        if not (s in ('icons', 'text', 'both')):
            s = 'icons'
            self.set_string('gui/navbar_style', 'icons')
        self.g_navbar.set_style({'icons': gtk.TOOLBAR_ICONS,
                                 'text': gtk.TOOLBAR_TEXT,
                                 'both': gtk.TOOLBAR_BOTH}[s])
        if self.get_bool('gui/navbar_visible'):
            self.get_dock_item_by_name("navbar").show()
        else:
            self.get_dock_item_by_name("navbar").hide()
        # main toolbar
        self.g_toolbar =  gtk.Toolbar()
        exdict = {}
        tblist_ordered = []
        tblist_unordered = []
        for e in __exdata__:
            exdict[e['exercise_name']] = e
            if 'toolbar' in e:
                tblist_ordered.append(e)
        tblist_ordered.sort(lambda a, b: cmp(a['toolbar'], b['toolbar']))
        for ex in tblist_ordered + tblist_unordered:
            im = gtk.Image()
            if 'toolbar' not in ex:
                continue
            if ex.has_key('icon'):
                im.set_from_file(ex['icon'])
            else:
                assert ex.has_key('stock-icon')
                im.set_from_stock(ex['stock-icon'], gtk.ICON_SIZE_SMALL_TOOLBAR)
            button = self.g_toolbar.append_item(ex['exercise_pretty_name'], ex['exercise_pretty_name'], None, im, None, None)
            button.connect('clicked', lambda button, ex=ex: self.m_app.handle_href("solfege:practice/"+ex['exercise_name']+'/'+ex['exercise_config']))
        self.add_toolbar(self.g_toolbar, "toolbar", "normal", "top", 1, 0, 1)
        s = self.get_string('gui/toolbar_style')
        if not (s in ('icons', 'text', 'both')):
            s = 'icons'
            self.set_string('gui/toolbar_style', 'icons')
        self.g_toolbar.set_style({'icons': gtk.TOOLBAR_ICONS,
                                  'text': gtk.TOOLBAR_TEXT,
                                  'both': gtk.TOOLBAR_BOTH}[s])
        self.g_toolbar.show_all()
    def display_in_musicviewer(self, music):
        if not self.g_musicviewer_window:
            self.g_musicviewer_window = MusicViewerWindow(self)
            self.g_musicviewer_window.show()
        self.g_musicviewer_window.display_music(music)
    def close_musicviewer(self, widget=None):
        self.g_musicviewer_window.destroy()
        self.g_musicviewer_window = None

#UGH is this really necessary
def create_menu_item(txt, callback, ag, accel_key, accel_mod):
    item = gtk.MenuItem(txt)
    item.add_accelerator('activate', ag, accel_key, accel_mod, gtk.ACCEL_VISIBLE)
    item.connect('activate', callback)
    return item

if splash_win:
    splash_win.show_progress("running gnome.program_init")

gnome.program_init('solfege', configureoutput.VERSION_STRING)
prog = gnome.program_get()
prog.parse_args()

import locale
locale.setlocale(locale.LC_NUMERIC, "C")

if splash_win:
    splash_win.show_progress("creating MainWin")

w = MainWin(args)
w.show()
if splash_win:
    splash_win.destroy()
w.post_constructor()
gtk.main()

