[jsword-devel] i18n and Actions

Aleksander Rozman - Andy jsword-devel@crosswire.org
Fri, 02 Apr 2004 12:04:05 +0200


--=====================_761973078==_
Content-Type: text/plain; charset="iso-8859-1"; format=flowed
Content-Transfer-Encoding: quoted-printable

At 2.4.2004, you wrote:
>The EirAbstractActions derived classes all have hard coded strings. This=20
>makes internationalization a little bit of a chore as the "Java way" of=20
>getting international strings is via a ResourceBundle per class.
>
>In an effort to do Internationalization and Localization (i18n and l10n) I=
=20
>used a pattern for actions that was in a tutorial on actions on the Sun=20
>web site and it served well.
>
>The basic idea is this, Actions don't have behavior but just fire actions=
=20
>to listeners. The listeners have the behavior for the actions that they=20
>care about. To facilitate this an ActionManager singelton class is=20
>responsible for creating Actions and for listening to Actions. The=20
>ActionManager is responsible for forwarding ActionEvents to its=20
>ActionListeners. The ActionEvents are manipulated so they seem like they=20
>come from the button, menu item, check box or whatever that triggered the=
=20
>action event.
>
>The advantage in the extra layer of the ActionManager, is that it is=20
>responsible for creating actions and supplying actions by simple names=20
>(createAction(...) and getAction(String simpleName). The action=20
>characteristics are held in a ActionManager.properties file that is part=20
>of the initialization of the singleton ActionManager, using ResourceBundle=
=20
>(or more likely an extended ResourceUtil) to get the proper localization=20
>of the action.
>
>In the properties file each action would be of the form:
>simpleName.LargeIcon=3D...
>simpleName.SmallIcon=3D...
>simpleName.MnemonicKey=3D...
>Where the first element is the simple name (duh!!) and the second follows=
=20
>the spelling of the key used in Action.putValue.
>The file can have as many actions as it likes and each will be built. It=20
>can have more than the applicatoin needs (i.e proceed it in development)
>
>Listeners will distinguish Actions by simple name and act when one of=20
>interest appears.
>The primary impact of this is that the actionPerformed of each action=20
>needs to be moved into the "actor" rather than actionPerformed being a=20
>delagate for that actor.
>
>Let me know what you think and whether this would be a worthy change to=
 make.
>

I have already told that this way of creating Actions is not good... When=20
you create application you should use as little as possible action classes,=
=20
but instead implement one ActionListener for more actions. Here is sample=20
how I did it (I started makeing changes on JSword some time ago). Also=20
included is my file for I18N..., which is used by this class.

I also mentioned about I18N, but I couldn't convince the boss that my way=20
is better even if it's used by almost all other java programmers...

Andy





>_________________________________________________________________
>MSN Toolbar provides one-click access to Hotmail from any Web page =AD FREE=
=20
>download! http://toolbar.msn.com/go/onm00200413ave/direct/01/
>
>_______________________________________________
>jsword-devel mailing list
>jsword-devel@crosswire.org
>http://www.crosswire.org/mailman/listinfo/jsword-devel

**************************************************************************
*  Aleksander Rozman - Andy  * Fandoms:  E2:EA, SAABer, Trekkie, Earthie *
*     andy@kksonline.com     * Sentinel, BH 90210, True's Trooper,       *
*    andy@atechnet.dhs.org   * Heller's Angel, Questie, Legacy, PO5,     *
* Maribor, Slovenia (Europe) * Profiler, Buffy (Slayerete), Pretender    *
*     ICQ-UIC: 4911125       *********************************************
*     PGP key available      *    http://www.atechnet.dhs.org/~andy/     *
**************************************************************************

--=====================_761973078==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="JSwordGUI.java"

package org.crosswire.jsword.view.swing.desktop;


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


//

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Event;
import javax.swing.ImageIcon;

import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import java.awt.event.InputEvent;
import javax.swing.JButton;

import org.crosswire.common.config.swing.SwingConfig;
import org.crosswire.jsword.view.swing.book.OuterDisplayPane;
import org.crosswire.common.swing.TextViewPanel;
import org.crosswire.jsword.passage.Key; 
import org.crosswire.common.xml.SAXEventProvider;
import org.crosswire.common.xml.StringSAXEventProvider;
import org.crosswire.common.xml.XMLUtil;
import org.crosswire.common.xml.Converter;
import org.crosswire.jsword.view.swing.util.SimpleSwingConverter; 
//import javax.swing.SwingUtilities;



import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.FocusManager;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

import org.crosswire.common.progress.Job;
import org.crosswire.common.progress.JobManager;
import org.crosswire.common.swing.BackportUtil;
import org.crosswire.common.swing.CustomAWTExceptionHandler;
import org.crosswire.common.swing.ExceptionPane;
import org.crosswire.common.swing.GuiUtil;
import org.crosswire.common.swing.LookAndFeelUtil;
import org.crosswire.common.util.Logger;
import org.crosswire.common.util.Reporter;
import org.crosswire.jsword.passage.NoSuchVerseException;
import org.crosswire.jsword.passage.Passage;
import org.crosswire.jsword.passage.PassageConstants;
import org.crosswire.jsword.passage.PassageFactory;
import org.crosswire.jsword.util.Project;
import org.crosswire.jsword.view.swing.book.BibleViewPane;
import org.crosswire.jsword.view.swing.book.DisplayArea;
import org.crosswire.jsword.view.swing.book.InnerDisplayPane;
import org.crosswire.jsword.view.swing.book.SidebarPane;
import org.crosswire.jsword.view.swing.book.SitesPane;
import org.crosswire.jsword.view.swing.book.TitleChangedEvent;
import org.crosswire.jsword.view.swing.book.TitleChangedListener;
import org.jdom.JDOMException;


import org.crosswire.common.resource.I18nControl;

/**
 * A container for various tools, particularly the BibleGenerator and
 * the Tester. These tools are generally only of use to developers, and
 * not to end users.
 *
 * <p>2 Things to think about, if you change the LaF when you have run
 * some tests already, then the window can grow quite a lot. Also do we
 * want to disable the Exit button if work is going on?</p>
 *
 * <p><table border='1' cellPadding='3' cellSpacing='0'>
 * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
 *
 * Distribution Licence:<br />
 * JSword 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.<br />
 * 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.<br />
 * The License is available on the internet
 * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA<br />
 * The copyright to this program is held by it's authors.
 * </font></td></tr></table>
 * @see gnu.gpl.Licence
 * @author Joe Walker [joe at eireneh dot com]
 * @author Mark Goodwin [mark at thorubio dot org]
 * @version $Id: Desktop.java,v 1.36 2003/11/30 19:58:26 joe Exp $
 */
public class JSwordGUI implements TitleChangedListener, HyperlinkListener
{
    
    private I18nControl ic = I18nControl.getInstance();
    private JSwordActionListener jswal = new JSwordActionListener();


    private JMenuItem mi_cut, mi_paste, mi_copy;












    /**
     * Central start point.
     * @param args The command line arguments
     */
    public static void main(String[] args)
    {
        try
        {
            
            JSwordGUI desktop = new JSwordGUI();
            desktop.getJFrame().pack();
            GuiUtil.centerWindow(desktop.getJFrame());
            desktop.getJFrame().toFront();
            desktop.getJFrame().setVisible(true);

            log.debug("desktop main exiting.");
        }
        catch (Throwable ex)
        {
            // Something went wrong before we've managed to get on our feet.
            // so we want the best possible shot at working out what failed.
            ex.printStackTrace();
            ExceptionPane.showExceptionDialog(null, ex);
        }
    }

    /**
     * Construct a Desktop.
     */
    public JSwordGUI() throws IOException, JDOMException
    {
        URL predicturl = Project.instance().getWritablePropertiesURL("splash");
        Splash splash = new Splash(frame, 60000);
        startjob = JobManager.createJob("Startup", predicturl, true);
        splash.pack();

        // Initial setup
        frame = new JFrame();
        CustomAWTExceptionHandler.setParentComponent(frame);

        startjob.setProgress("Setting-up config");
        act_tools_options = new OptionsAction(frame);

        startjob.setProgress("Loading Configuration System");
        act_tools_options.createConfig();

        startjob.setProgress("Loading Stored Settings");
        act_tools_options.loadConfig();

        startjob.setProgress("Generating Components");
        createComponents();


        startjob.setProgress("Generating Menus");
        createMenus();
        
        
        //startjob.setProgress("Generating Toolbar");
        //createToolbar();


        startjob.setProgress("Generating Main Window");
        createFrame();


        //createComponents();



        // GUI setup
        debug();
        //init();

        
        //createMenus();


        //accelerateMenu(bar_menu);

        if (initial == LAYOUT_TYPE_MDI)
        {
            rdo_view_mdi.setSelected(true);
        }
        if (initial == LAYOUT_TYPE_TDI)
        {
            rdo_view_tdi.setSelected(true);
        }

        // Sort out the current ViewLayout. We need to reset current to be
        // initial because the config system may well have changed initial
        current = initial;
        ensureAvailableBibleViewPane();

        // Configuration
        startjob.setProgress("General configuration");
        LookAndFeelUtil.addComponentToUpdate(frame);

        // Keep track of the selected DisplayArea
        FocusManager.getCurrentManager().addPropertyChangeListener(new PropertyChangeListener()
        {
            public void propertyChange(PropertyChangeEvent ev)
            {
                DisplayArea da = recurseDisplayArea();
                if (da != null)
                {
                    last = da;
                }
            }
        });

        // And setup the initial display area, by getting the first
        // BibleViewPane and asking it for a PassagePane.
        last = ((BibleViewPane) iterateBibleViewPanes().next()).getPassagePane();

        // Preload the PassageInnerPane for faster initial view
        InnerDisplayPane.preload();

        startjob.done();
        splash.close();

// X       frame.pack();
    }

    /**
     * Sometimes we need to make some changes to debug the GUI.
     */
    private void debug()
    {
        //this.getContentPane().addContainerListener(new DebugContainerListener());

        //javax.swing.RepaintManager.currentManager(this).setDoubleBufferingEnabled(false);
        //((javax.swing.JComponent) getContentPane()).setDebugGraphicsOptions(javax.swing.DebugGraphics.LOG_OPTION);
    }

    /**
     * Call all the constructors
     */
    private void createComponents()
    {

        layouts = new ViewLayout[2];
        layouts[LAYOUT_TYPE_TDI] = new TDIViewLayout();
        layouts[LAYOUT_TYPE_MDI] = new MDIViewLayout();

/*
        act_edit_cut = new EditCutAction(this);
        act_edit_copy = new EditCopyAction(this);
        act_edit_paste = new EditPasteAction(this);
        act_edit_blur1 = new BlurAction(this, 1, PassageConstants.RESTRICT_CHAPTER);
        act_edit_blur5 = new BlurAction(this, 5, PassageConstants.RESTRICT_CHAPTER);
*/
/*        
        act_file_new = new FileNewAction(this);
        act_file_open = new FileOpenAction(this);
        act_file_save = new FileSaveAction(this);
        act_file_saveas = new FileSaveAsAction(this);
        act_file_saveall = new FileSaveAllAction(this);
        act_file_close = new FileCloseAction(this);
        act_file_closeall = new FileCloseAllAction(this);
        //act_file_print = new FilePrintAction(this);
        act_file_exit = new ExitAction(this);
        
        act_edit_cut = new EditCutAction(this);
        act_edit_copy = new EditCopyAction(this);
        act_edit_paste = new EditPasteAction(this);
        act_edit_blur1 = new BlurAction(this, 1, PassageConstants.RESTRICT_CHAPTER);
        act_edit_blur5 = new BlurAction(this, 5, PassageConstants.RESTRICT_CHAPTER);
        
        act_view_tdi = new ViewTDIAction(this);
        act_view_mdi = new ViewMDIAction(this);
        //act_view_tbar = new ViewToolBarAction(this);
        act_view_ghtml = new ViewSourceGHTMLAction(this);
        act_view_vhtml = new ViewSourceHTMLAction(this);
        act_view_osis = new ViewSourceOSISAction(this);

        act_list_delete = new ListDeleteAction(this);

        //act_tools_generate = GeneratorPane.createOpenAction(this);
        //act_tools_diff = ComparePane.createOpenAction(this);
        act_tools_sites = SitesPane.createOpenAction(frame);

        act_help_contents = new HelpContentsAction(this);
        act_help_about = AboutPane.createOpenAction(this);
*/
        /*
        rdo_view_tdi = new JRadioButtonMenuItem(act_view_tdi);
        rdo_view_mdi = new JRadioButtonMenuItem(act_view_mdi);
        */
        
        //chk_view_tbar = new JCheckBoxMenuItem(act_view_tbar);

        /*
        bar_menu = new JMenuBar();
        menu_file = new JMenu();
        menu_edit = new JMenu();
        menu_view = new JMenu();
        menu_tools = new JMenu();
        menu_help = new JMenu();
        */

        //grp_views = new ButtonGroup();
        pnl_tbar = new JToolBar();
        bar_status = new StatusBar();
        bar_side = new SidebarPane();
        //bar_book = new ReferencedPane();
        spt_books = new JSplitPane();
    }






    private JMenuItem getMenuItem(String entry, String icon, KeyStroke accel)
    {
        String menuString = ic.getMessageWithoutMnemonic(entry);

        JMenuItem mi = new JMenuItem();

        if (icon!=null) 
            mi.setIcon(new ImageIcon(icon));
        
        mi.setActionCommand(entry);
        mi.setText(menuString);
        mi.setName(menuString);
        mi.setToolTipText(ic.getMessage(entry+"_TIP"));
        mi.addActionListener(jswal);

        char m = ic.getMnemonic(entry);

        if (m!=0) 
            mi.setMnemonic(m);

        if (accel!=null) 
            mi.setAccelerator(accel);

        return mi;

    }



    private JRadioButtonMenuItem getRadioMenuItem(String entry, String icon, boolean selected, KeyStroke accel)
    {
        String menuString = ic.getMessageWithoutMnemonic(entry);

        JRadioButtonMenuItem mi = new JRadioButtonMenuItem();

        if (icon!=null) 
            mi.setIcon(new ImageIcon(icon));
        
        mi.setActionCommand(entry);
        mi.setText(menuString);
        mi.setName(menuString);
        mi.setToolTipText(ic.getMessage(entry+"_TIP"));
        mi.addActionListener(jswal);

        char m = ic.getMnemonic(entry);

        if (m!=0) 
            mi.setMnemonic(m);

        if (accel!=null) 
            mi.setAccelerator(accel);

        return mi;

    }



    /**
     * Initialize the GUI, and display it.
     */
    private void createMenus()
    {
        
        layouts = new ViewLayout[2];
        layouts[LAYOUT_TYPE_TDI] = new TDIViewLayout();
        layouts[LAYOUT_TYPE_MDI] = new MDIViewLayout();

        bar_menu = new JMenuBar();
        JMenu menu; 


        menu = new JMenu(ic.getMessageWithoutMnemonic("FILE"));
        menu.setMnemonic(ic.getMnemonic("FILE"));
        menu.add(getMenuItem("FILE_NEW", "../resource/toolbarButtonGraphics/general/New16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.add(getMenuItem("FILE_OPEN", "../resource/toolbarButtonGraphics/general/Open16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.addSeparator();
        menu.add(getMenuItem("FILE_CLOSE", null, KeyStroke.getKeyStroke(KeyEvent.VK_F4, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.add(getMenuItem("FILE_CLOSE_ALL", null, null));
        menu.addSeparator();
        menu.add(getMenuItem("FILE_PRINT", "../resource/toolbarButtonGraphics/general/Print16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.addSeparator();
        menu.add(getMenuItem("FILE_SAVE", "../resource/toolbarButtonGraphics/general/Save16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.add(getMenuItem("FILE_SAVE_AS", "../resource/toolbarButtonGraphics/general/SaveAs16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.add(getMenuItem("FILE_SAVE_ALL", "../resource/toolbarButtonGraphics/general/SaveAll16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.SHIFT_MASK + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)));
        menu.addSeparator();
        menu.add(getMenuItem("FILE_EXIT", null, KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_MASK, false)));
        bar_menu.add(menu);

        
        menu = new JMenu(ic.getMessageWithoutMnemonic("EDIT"));
        menu.setMnemonic(ic.getMnemonic("EDIT"));

        mi_cut = getMenuItem("EDIT_CUT", "../resource/toolbarButtonGraphics/general/Cut16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK, false));
        mi_cut.setEnabled(false);
        menu.add(mi_cut);

        mi_copy = getMenuItem("EDIT_COPY", "../resource/toolbarButtonGraphics/general/Copy16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK, false));
        menu.add(mi_copy);

        mi_paste = getMenuItem("EDIT_PASTE", "../resource/toolbarButtonGraphics/general/Paste16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.ALT_MASK, false));
        mi_paste.setEnabled(false);
        menu.add(mi_paste);

        bar_menu.add(menu);


        menu = new JMenu(ic.getMessageWithoutMnemonic("VIEW"));
        menu.setMnemonic(ic.getMnemonic("VIEW"));

        rdo_view_tdi = getRadioMenuItem("VIEW_TABBED", null, true, null);
        rdo_view_mdi = getRadioMenuItem("VIEW_SUBWINDOW", null, true, null);

        menu.add(rdo_view_tdi);
        menu.add(rdo_view_mdi);

        menu.addSeparator();
        menu.add(getMenuItem("VIEW_GHTML", null, null));
        menu.add(getMenuItem("VIEW_HTML", null, null));
        menu.add(getMenuItem("VIEW_OSIS", null, null));
        bar_menu.add(menu);


        /*
        menu_view = new JMenu();
        menu_view.setText("View");
        menu_view.setMnemonic('V');
        menu_view.add(rdo_view_tdi);
        menu_view.add(rdo_view_mdi);
        //menu_view.add(chk_view_tbar);
        menu_view.addSeparator();
        menu_view.add(act_view_ghtml).addMouseListener(bar_status);
        menu_view.add(act_view_vhtml).addMouseListener(bar_status);
        menu_view.add(act_view_osis).addMouseListener(bar_status);
        */


        menu = new JMenu(ic.getMessageWithoutMnemonic("TOOLS"));
        menu.setMnemonic(ic.getMnemonic("TOOLS"));
        menu.add(getMenuItem("TOOLS_BLUR1", null, null));
        menu.add(getMenuItem("TOOLS_BLUR5", null, null));
        menu.add(getMenuItem("TOOLS_LISTDELETE", "../resource/toolbarButtonGraphics/general/Remove16.gif", null));
        menu.addSeparator();
        menu.add(getMenuItem("TOOLS_SITES", "../resource/toolbarButtonGraphics/general/Import16.gif", null));
        menu.add(getMenuItem("TOOLS_OPTIONS", "../resource/toolbarButtonGraphics/general/Properties16.gif", null));
        bar_menu.add(menu);


        menu = new JMenu(ic.getMessageWithoutMnemonic("HELP"));
        menu.setMnemonic(ic.getMnemonic("HELP"));
        menu.add(getMenuItem("HELP_CONTENTS", "../resource/toolbarButtonGraphics/general/Help16.gif", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, false)));
        menu.addSeparator();
        menu.add(getMenuItem("HELP_ABOUT", "../resource/ztoolbarButtonGraphics/general/About16.gif", null));
        bar_menu.add(menu);
        





        /*
        rdo_view_tdi.addMouseListener(bar_status);
        rdo_view_mdi.addMouseListener(bar_status);
        //chk_view_tbar.addMouseListener(bar_status);
        //chk_view_tbar.setSelected(view_tool);
        grp_views.add(rdo_view_mdi);
        grp_views.add(rdo_view_tdi);



        //bar_menu.add(menu_file);
        bar_menu.add(menu_edit);
        bar_menu.add(menu_view);
        bar_menu.add(menu_tools);
        bar_menu.add(menu_tools);
        bar_menu.add(menu_help);


        */

        //bar_menu.add(menu_edit);

    }



    public void createFrame()
    {
        BackportUtil.setRollover(pnl_tbar, true);

/*
        pnl_tbar.add(act_file_new).addMouseListener(bar_status);
        pnl_tbar.add(act_file_open).addMouseListener(bar_status);
        pnl_tbar.add(act_file_save).addMouseListener(bar_status);
        pnl_tbar.addSeparator();
        pnl_tbar.add(act_edit_cut).addMouseListener(bar_status);
        pnl_tbar.add(act_edit_copy).addMouseListener(bar_status);
        pnl_tbar.add(act_edit_paste).addMouseListener(bar_status);
        pnl_tbar.addSeparator();
        //pnl_tbar.add(act_tools_generate).addMouseListener(bar_status);
        //pnl_tbar.add(act_tools_diff).addMouseListener(bar_status);
        //pnl_tbar.addSeparator();
        pnl_tbar.add(act_help_contents).addMouseListener(bar_status);
        pnl_tbar.add(act_help_about).addMouseListener(bar_status);
*/
        //bar_book.addHyperlinkListener(this);
        bar_side.addHyperlinkListener(this);

        spt_books.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
        spt_books.setOneTouchExpandable(true);
        spt_books.setDividerLocation(0.9D);
        //spt_books.add(bar_book, JSplitPane.RIGHT);
        spt_books.add(bar_side, JSplitPane.RIGHT);
        spt_books.add(new JPanel(), JSplitPane.LEFT);
        spt_books.setResizeWeight(0.9D);

        frame.addWindowListener(new WindowAdapter()
        {
            public void windowClosed(WindowEvent ev)
            {
                cmdFileExit();
                
                //act_file_exit.actionPerformed(null);
            }
        });
        
        

        //frame.setJMenuBar(this.bar_menu);

        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(pnl_tbar, BorderLayout.NORTH);
        frame.getContentPane().add(bar_status, BorderLayout.SOUTH);
        frame.getContentPane().add(spt_books, BorderLayout.CENTER);
        
        frame.setJMenuBar(bar_menu);

        frame.setSize(800,600);
        frame.setEnabled(true);
        frame.setTitle(Project.instance().getName());

    }



    /**
     * Adds BibleViewPane to the list in this Desktop.
     */
    public void addBibleViewPane(BibleViewPane view)
    {
        view.addTitleChangedListener(this);
        view.addHyperlinkListener(this);
        views.add(view);

        getViewLayout().add(view);

        setLayoutComponent(getViewLayout().getRootComponent());
        getViewLayout().getSelected().adjustFocus(); 
    }

    /**
     * Removes BibleViewPane from the list in this Desktop.
     */
    public void removeBibleViewPane(BibleViewPane view)
    {
        view.removeTitleChangedListener(this);
        view.removeHyperlinkListener(this);
        views.remove(view);

        getViewLayout().remove(view);

        // Just in case that was the last one
        ensureAvailableBibleViewPane();

        setLayoutComponent(getViewLayout().getRootComponent());
        //getViewLayout().getSelected().adjustFocus(); 
    }

    /**
     * Iterate through the list of views
     */
    public Iterator iterateBibleViewPanes()
    {
        return views.iterator();
    }

    /**
     * How many BibleViewPanes are there currently?
     */
    public int countBibleViewPanes()
    {
        return views.size();
    }

    /**
     * Find the selected BibleViewPane.
     * @return BibleViewPane
     */
    public BibleViewPane getSelectedBibleViewPane()
    {
        return getViewLayout().getSelected();
    }

    /**
     * Find the currently highlighted DisplayArea
     */
    public DisplayArea getDisplayArea()
    {
        DisplayArea da = recurseDisplayArea();
        if (da != null)
        {
            return da;
        }

        return last;
    }

    /**
     * Get the currently selected component and the walk up the component tree
     * trying to find a component that implements DisplayArea
     */
    protected DisplayArea recurseDisplayArea()
    {
        Component comp = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();

        // So we've got the current component, we now need to walk up the tree
        // to find something that we recognize.
        while (comp != null)
        {
            if (comp instanceof DisplayArea)
            {
                return (DisplayArea) comp;
            }
        
            comp = comp.getParent();
        }

        return null;
    }

    /**
     * What is the current layout?
     */
    private final ViewLayout getViewLayout()
    {
        return layouts[current];
    }

    /**
     * Setup the current view
     */
    public void setLayoutType(int next)
    {
        // Check this is a change
        if (current == next)
        {
            return;
        }

        // Go through the views removing them from the layout
        Iterator it = iterateBibleViewPanes();
        while (it.hasNext())
        {
            BibleViewPane view = (BibleViewPane) it.next();
            getViewLayout().remove(view);
        }

        current = next;

        // Go through the views adding them to the layout SDIViewLayout may well add
        // a view, in which case the view needs to be set already so this must come
        // last.
        it = iterateBibleViewPanes();
        while (it.hasNext())
        {
            BibleViewPane view = (BibleViewPane) it.next();
            getViewLayout().add(view);
        }

        // Allow the current BibleViewPane to set the focus in the right place
        setLayoutComponent(getViewLayout().getRootComponent());
        getViewLayout().getSelected().adjustFocus();
    }

    /**
     * For the use of the various Layout components to update the UI with
     * their Layout component.
     */
    private void setLayoutComponent(Component next)
    {
        Component leftcurr = spt_books.getLeftComponent();
        if (leftcurr == next)
        {
            return;
        }

        if (leftcurr != null)
        {
            // Not sure why we have to use a number in place of
            // the JSplitPane.LEFT string constant.
            
            // And not sure that we need to do this at all.
            //spt_books.remove(1/*JSplitPane.LEFT*/);
        }

        spt_books.add(next, JSplitPane.LEFT);
    }

    /**
     * If there are no current BibleViewPanes then add one in.
     * final because the ctor calls this method
     */
    private final void ensureAvailableBibleViewPane()
    {
        // If there are no views in the pool, create one
        if (!iterateBibleViewPanes().hasNext())
        {
            BibleViewPane view = new BibleViewPane();
            addBibleViewPane(view);
        }
    }

    /**
     * What is the initial layout state?
     */
    public static int getInitialLayoutType()
    {
        return initial;
    }

    /**
     * What should the initial layout state be?
     */
    public static void setInitialLayoutType(int initial)
    {
        if (initial != LAYOUT_TYPE_TDI && initial != LAYOUT_TYPE_MDI)
        {
            throw new IllegalArgumentException();
        }

        JSwordGUI.initial = initial;
    }

    /* (non-Javadoc)
     * @see javax.swing.event.HyperlinkListener#hyperlinkUpdate(javax.swing.event.HyperlinkEvent)
     */
    public void hyperlinkUpdate(HyperlinkEvent ev)
    {
        try
        {
            bar_status.hyperlinkUpdate(ev);

            HyperlinkEvent.EventType type = ev.getEventType();
            if (type == HyperlinkEvent.EventType.ACTIVATED)
            {
                String url = ev.getDescription();
                if (url.indexOf(':') == -1)
                {
                    // So there is no protocol, this must be relative to the current
                    // in which case we assume that it is an in page reference.
                    // We ignore the frame case (example code within JEditorPane
                    // JavaDoc).
                    if (url.startsWith("#"))
                    {
                        url = url.substring(1);
                    }
                    log.debug("scrolling to: "+url);
                    JEditorPane pane = (JEditorPane) ev.getSource();
                    BackportUtil.scrollToReference(url, pane);
                }
                else
                {
                    // Fully formed, so we open a new window
                    openHyperlink(ev.getDescription());
                }
            }
        }
        catch (MalformedURLException ex)
        {
            Reporter.informUser(this, ex);
        }
    }

    /**
     * Create a new view showing the contents of the given hyperlink
     */
    public void openHyperlink(String url) throws MalformedURLException
    {
        int match = url.indexOf(":");
        if (match == -1)
        {
            throw new MalformedURLException("missing : in "+url);
        }

        String protocol = url.substring(0, match);
        String data = url.substring(match+1);
        if (data.startsWith("//"))
        {
            data = data.substring(2);
        }

        if (protocol.equals("bible"))
        {
            try
            {
                Passage ref = PassageFactory.createPassage(data);
                BibleViewPane view = new BibleViewPane();

                addBibleViewPane(view);

                view.addHyperlinkListener(this);
                view.setPassage(ref);
            }
            catch (NoSuchVerseException ex)
            {
                Reporter.informUser(this, ex);
            }
        }
        else if (protocol.equals("comment"))
        {
            try
            {
                Passage ref = PassageFactory.createPassage(data);    
                bar_side.getCommentaryPane().setPassage(ref);
            }
            catch (NoSuchVerseException ex)
            {
                Reporter.informUser(this, ex);
            }
        }
        else if (protocol.equals("dict"))
        {
            bar_side.getDictionaryPane().setWord(data);
        }
        else
        {
            throw new MalformedURLException("unknown protocol "+protocol);
        }
    }

    /**
     * Returns the view_status.
     * @return boolean
     */
    public boolean isStatusBarVisible()
    {
        return view_status;
    }

    /**
     * Sets the view_status.
     * @param view_status The view_status to set
     */
    public void setStatusBarVisible(boolean view_status)
    {
        bar_status.setVisible(true);
        this.view_status = view_status;
    }

    /**
     * Returns the view_tool.
     * @return boolean
     */
/*    public boolean isToolbarVisible()
    {
        return view_tool;
    }
*/
    /**
     * Sets the view_tool.
     * @param view_tool The view_tool to set
     */
/*    public void setToolbarVisible(boolean view_tool)
    {
        pnl_tbar.setVisible(true);
        this.view_tool = view_tool;
    }
*/
    /**
     * Are the close buttons enabled?
     * @param enabled The enabled state
     */
    public void setCloseEnabled(boolean enabled)
    {
/*        act_file_close.setEnabled(enabled);
        act_file_closeall.setEnabled(enabled);
        */
    }

    /* (non-Javadoc)
     * @see org.crosswire.jsword.view.swing.book.TitleChangedListener#titleChanged(org.crosswire.jsword.view.swing.book.TitleChangedEvent)
     */
    public void titleChanged(TitleChangedEvent ev)
    {
        BibleViewPane bvp = (BibleViewPane) ev.getSource();
        getViewLayout().updateTitle(bvp);
    }

    /**
     * Accessor for the main desktop Frame
     */
    public JFrame getJFrame()
    {
        return frame;
    }

    /**
     * Run down the menus adding the accelerators
     */
    private void accelerateMenu(JMenuBar menubar)
    {
        for (int i = 0; i < menubar.getMenuCount(); i++)
        {
            JMenu menu = menubar.getMenu(i);
            for (int j = 0; j < menu.getMenuComponentCount(); j++)
            {
                Component comp = menu.getMenuComponent(j);
                if (comp instanceof JMenuItem)
                {
                    JMenuItem item = (JMenuItem) comp;
                    Action action = item.getAction();
                    if (action != null)
                    {
                        KeyStroke accel = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY);
                        if (accel != null)
                        {
                            item.setAccelerator(accel);
                        }
                    }
                }
                else
                {
                    // Just in case we start getting things we could do something with
                    if (!(comp instanceof JPopupMenu.Separator))
                    {
                        log.warn("Non JMenuItem, class="+comp.getClass().getName());
                    }
                }
            }
        }
    }

    /**
     * Tabbed document interface
     */
    protected static final int LAYOUT_TYPE_TDI = 0;

    /**
     * Multiple document interface
     */
    protected static final int LAYOUT_TYPE_MDI = 1;

    /**
     * The initial layout state
     */
    private static int initial = LAYOUT_TYPE_TDI;

    /**
     * The array of valid layouts
     */
    protected ViewLayout[] layouts; 

    /**
     * The current way the views are laid out
     */
    private int current = initial;

    /**
     * The list of BibleViewPanes being viewed in tdi and mdi workspaces
     */
    private List views = new ArrayList();

    /**
     * is the status bar visible
     */
    private boolean view_status = true;

    /**
     * is the toolbar visible
     */
    private boolean view_tool = true;

    /**
     * The last selected DisplayArea
     */
    protected DisplayArea last = null;

    /**
     * The log stream
     */
    private static final Logger log = Logger.getLogger(Desktop.class);

    private Job startjob = null;
    /*
    private Action act_file_new = null;
    private Action act_file_open = null;
    private Action act_file_save = null;
    private Action act_file_saveas = null;
    private Action act_file_saveall = null;
    private Action act_file_close = null;
    private Action act_file_closeall = null;
    //private Action act_file_print = null;
    protected Action act_file_exit = null;

    private Action act_edit_cut = null;
    private Action act_edit_copy = null;
    private Action act_edit_paste = null;
    private Action act_edit_blur1 = null;
    private Action act_edit_blur5 = null;

    private Action act_view_tdi = null;
    private Action act_view_mdi = null;
    //private Action act_view_tbar = null;

    private Action act_view_ghtml = null;
    private Action act_view_vhtml = null;
    private Action act_view_osis = null;

    private Action act_list_delete = null;

    //private Action act_tools_generate = null;
    //private Action act_tools_diff = null;
    private OptionsAction act_tools_options = null;
    private Action act_tools_sites = null;

    private Action act_help_contents = null;
    private Action act_help_about = null;
    //private Action act_help_debug = null;
    */
    
    private OptionsAction act_tools_options = null;

    private JRadioButtonMenuItem rdo_view_tdi = null;
    private JRadioButtonMenuItem rdo_view_mdi = null;
    //private JCheckBoxMenuItem chk_view_tbar = null;

    private JMenuBar bar_menu = null;
    
    /*
    private JMenu menu_file = null;
    private JMenu menu_edit = null;
    private JMenu menu_view = null;
    private JMenu menu_tools = null;
    private JMenu menu_help = null;
    */
    private JFrame frame = null;
    //private ButtonGroup grp_views = null;
    private JToolBar pnl_tbar = null;
    private StatusBar bar_status = null;
    private SidebarPane bar_side = null;
    //private ReferencedPane bar_book = null;
    private JSplitPane spt_books = null;


    public void cmdFileNew()
    {
        BibleViewPane view = new BibleViewPane();
        addBibleViewPane(view);
        view.addHyperlinkListener(this);
    }



    public void cmdFileOpen()
    {
        try
        {
            BibleViewPane view = getSelectedBibleViewPane();
            view.open();
        }
        catch (Exception ex)
        {
            Reporter.informUser(this, ex);
        }
    }




    private void cmdFileClose()
    {
        BibleViewPane view = getSelectedBibleViewPane();
        removeBibleViewPane(view);
    }


    private void cmdFileCloseAll()
    {
        Iterator it = iterateBibleViewPanes();
        while (it.hasNext())
        {
            BibleViewPane view = (BibleViewPane) it.next();
            removeBibleViewPane(view);
        }
    }


    public void cmdFilePrint()
    {
        JOptionPane.showMessageDialog(frame, "Not implemented");
    }



    public void cmdFileSave()
    {
        try
        {
            BibleViewPane view = getSelectedBibleViewPane();
            view.save();
        }
        catch (IOException ex)
        {
            Reporter.informUser(this, ex);
        }
    }



    public void cmdFileSaveAs()
    {
        try
        {
            BibleViewPane view = getSelectedBibleViewPane();
            view.saveAs();
        }
        catch (IOException ex)
        {
            Reporter.informUser(this, ex);
        }
    }



    public void cmdFileSaveAll()
    {
        Iterator it = iterateBibleViewPanes();
        while (it.hasNext())
        {
            try
            {
                BibleViewPane view = (BibleViewPane) it.next();
                view.save();
            }
            catch (IOException ex)
            {
                Reporter.informUser(this, ex);
            }
        }
    }


    public void cmdFileExit()
    {
        System.exit(0);
    }



    public void cmdEditCopy()
    {
        DisplayArea da = getDisplayArea();
        da.copy();
    }



    public void cmdEditPaste()
    {
        DisplayArea da = getDisplayArea();
        da.paste();
    }


    public void cmdEditCut()
    {
        DisplayArea da = getDisplayArea();
        da.cut();
    }



    public void cmdViewLayout(int layout)
    {
        setLayoutType(layout);
    }



    public void cmdViewGHTML()
    {
        try
        {
            DisplayArea da = getDisplayArea();
            String osis = da.getOSISSource();
            Key ref = da.getKey();

            Converter style = new SimpleSwingConverter();
            SAXEventProvider osissep = new StringSAXEventProvider(osis);
            SAXEventProvider htmlsep = style.convert(osissep);
            String html = XMLUtil.writeToString(htmlsep);

            TextViewPanel viewer = new TextViewPanel(html, "Generated source to " + ref.getName());
            viewer.setEditable(true);
            viewer.showInFrame(frame);
        }
        catch (Exception ex)
        {
            Reporter.informUser(this, ex);
        }
    }



    public void cmdViewHTML()
    {
        DisplayArea da = getDisplayArea();
        String html = da.getHTMLSource();
        Key ref = da.getKey();

        TextViewPanel viewer = new TextViewPanel(html, "HTML source to "+ref.getName());
        viewer.setEditable(true);
        viewer.showInFrame(frame);
    }



    public void cmdViewOSIS()
    {
        try
        {
            DisplayArea da = getDisplayArea();
            String html = da.getOSISSource();
            Key key = da.getKey();

            TextViewPanel viewer = new TextViewPanel(html, "OSIS source to "+key.getName());
            viewer.setEditable(true);
            viewer.showInFrame(frame);
        }
        catch (Exception ex)
        {
            Reporter.informUser(this, ex);
        }
    }



    public void cmdToolsBlurBy(int blurFact)
    {
        BibleViewPane view = getSelectedBibleViewPane();
        
        if (view != null)
        {
            Passage ref = view.getPassage();
            ref.blur(blurFact, PassageConstants.RESTRICT_CHAPTER);
            view.setPassage(ref);
        }
    }

    

    public void cmdToolsListDelete()
    {
        BibleViewPane view = getSelectedBibleViewPane();
        if (view != null)
        {
            OuterDisplayPane odp = view.getPassagePane();
            odp.deleteSelected(view);
        }
    }



    public void cmdToolsBooks()
    {
        SitesPane sites = new SitesPane();
        sites.showInDialog(frame);
    }



    public void cmdToolsOptions()
    {

        act_tools_options.configAction();

    }





    public void cmdHelpContents()
    {
        JOptionPane.showMessageDialog(frame, "Um. Help, yes that would require me to write some.\nErrr. Sorry.");
    } 



    public void cmdHelpAbout()
    {
        AboutPane atp = new AboutPane(this);
        atp.showInDialog(getJFrame());
    }





    private class JSwordActionListener implements ActionListener
    {
        
        /**
         * Invoked when an action occurs.
         */
        public void actionPerformed(ActionEvent e) 
        {

            boolean correct = false;
            String command=null;

            if (e.getSource() instanceof JMenuItem) 
            {
                command = ((JMenuItem)e.getSource()).getActionCommand();
            }
            else if (e.getSource() instanceof JButton) 
            {
                command = ((JButton)e.getSource()).getActionCommand();
            }


            if (command==null) 
                return;


            if (command.equals("FILE_OPEN")) 
            {
                cmdFileOpen();
            }
            else if (command.equals("FILE_NEW")) 
            {
                cmdFileNew();
            }
            else if (command.equals("FILE_CLOSE")) 
            {
                cmdFileClose();
            }
            else if (command.equals("FILE_CLOSE_ALL")) 
            {
                cmdFileCloseAll();
            }
            else if (command.equals("FILE_PRINT")) 
            {
                cmdFilePrint();
            }
            else if (command.equals("FILE_SAVE")) 
            {
                cmdFileSave();
            }
            else if (command.equals("FILE_SAVE_AS")) 
            {
                cmdFileSaveAs();
            }
            else if (command.equals("FILE_SAVE_ALL")) 
            {
                cmdFileSaveAll();
            }
            else if (command.equals("FILE_EXIT")) 
            {
                cmdFileExit();
            }
            else if (command.equals("EDIT_CUT")) 
            {
                cmdEditCut();
            }
            else if (command.equals("EDIT_COPY")) 
            {
                cmdEditCopy();
            }
            else if (command.equals("EDIT_PASTE")) 
            {
                cmdEditPaste();
            }
            else if (command.equals("VIEW_TABBED")) 
            {
                rdo_view_tdi.setSelected(true);
                rdo_view_mdi.setSelected(false);
                cmdViewLayout(Desktop.LAYOUT_TYPE_TDI);
            }
            else if (command.equals("VIEW_SUBWINDOW")) 
            {
                rdo_view_tdi.setSelected(false);
                rdo_view_mdi.setSelected(true);
                cmdViewLayout(Desktop.LAYOUT_TYPE_MDI);
            }
            else if (command.equals("VIEW_GHTML")) 
            {
                cmdViewGHTML();
            }
            else if (command.equals("VIEW_HTML")) 
            {
                cmdViewHTML();
            }
            else if (command.equals("VIEW_OSIS")) 
            {
                cmdViewOSIS();
            }
            else if (command.equals("TOOLS_BLUR1")) 
            {
                cmdToolsBlurBy(1);
            }
            else if (command.equals("TOOLS_BLUR5")) 
            {
                cmdToolsBlurBy(5);
            }
            else if (command.equals("TOOLS_LISTDELETE")) 
            {
                cmdToolsListDelete();
            }
            else if (command.equals("TOOLS_SITES")) 
            {
                cmdToolsBooks();
            }
            else if (command.equals("TOOLS_OPTIONS")) 
            {
                cmdToolsOptions();
            }
            else if (command.equals("HELP_CONTENTS")) 
            {
                cmdHelpContents();
            }
            else if (command.equals("HELP_ABOUT")) 
            {
                cmdHelpAbout();
            }

        }

        
        public void handleEvent(Event evt) { }

    };








}

--=====================_761973078==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="I18nControl.java"

package org.crosswire.common.resource;

import java.util.Locale;
import java.util.ResourceBundle;
import java.util.MissingResourceException;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

import java.util.*;
import java.text.DateFormat;


import java.io.*;


public class I18nControl
{

    /**
     *  Resource bundle identificator
     */
    ResourceBundle res;


    static private I18nControl m_i18n = null;   // This is handle to unique 
                                                    // singelton instance
                                               

    //   Constructor:  OmniI18nControl
    /**
     *
     *  This is OmniI18nControl constructor; Since classes use Singleton Pattern,
     *  constructor is protected and can be accessed only with getInstance() 
     *  method.<br><br>
     *
     */ 
    private I18nControl()
    {

        setLanguage("EN");
            
    } 
    


    
    //  Method:       getInstance
    //  Author:       Andy
    /**
     *
     *  This method returns reference to OmniI18nControl object created, or if no 
     *  object was created yet, it creates one.<br><br>
     *
     *  @return Reference to OmniI18nControl object
     * 
     */ 
    static public I18nControl getInstance()
    {
        if (m_i18n == null)
            m_i18n = new I18nControl();
        return m_i18n;
    }






    //  Method:       deleteInstance
    /**
     *
     *  This method sets handle to OmniI18NControl to null and deletes the instance. <br><br>
     *
     */ 
    public void deleteInstance()
    {
        
        m_i18n=null;

    }



    //  Method:       setLanguage (String language)
    /**
     *
     *  This is helper method for setting language.<br><br>
     *
     *  @param language language which we want to use
     */ 
    public void setLanguage(String language)
    {
        
        Locale l = new Locale(language);
        setLanguage(l);

    }



    //  Method:       setLanguage (String language, String country)
    /**
     *
     *  This is helper method for setting language.<br><br>
     *
     *  @param language language which we want to use
     *  @param country country that uses this language
     */ 
    public void setLanguage(String language, String country)
    {
        
        Locale l = new Locale(language, country);
        setLanguage(l);
    
    }



    //  Method:       setLanguage (Locale)
    /**
     *
     *  This method sets language for control instance. If none is found, english is defaulted.
     *  if none is found, application will exit.<br><br>
     *
     *  @param lcl locale that will choose which language will be set
     */ 
    public void setLanguage(Locale lcl)
    {

        try
        {

            //ResourceBundle.get

            try
            {
                File d = new File(".");

                System.out.println(d.getCanonicalPath());
            }
            catch(Exception ex){
                
            }

            res = ResourceBundle.getBundle("JSword", lcl);
        }
        catch (MissingResourceException mre)
        {
            System.out.println("Couldn't find resource file(1): JSword_EN.properties");
            try
            {
                res = ResourceBundle.getBundle("JSword", new Locale("EN"));
            }
            catch(Exception ex)
            {
                System.out.println("Exception on reading resource file. Exiting application.");
                System.exit(2);
            }
        }

    }









    //  Method: hmmlize
    /**
     *  
     * Converts text from bundle into HTML. This must be used if we have control, which has
     * formated text in HTML or is multilined (some of basic java swing components don't 
     * support \n). 
     * 
     * @param input input text we wish to HTMLize
     * @return HTMLized text
     * 
     */
    private String htmlize(String input)
    {
        
        StringBuffer buffer = new StringBuffer("<HTML>");

        input = input.replaceAll("\n", "<BR>");
        input = input.replaceAll("&", "&amp;");

        buffer.append(input);
        buffer.append("</HTML>");

        return buffer.toString();
        
    }



    //  Method: getMessageHTML(String)
    /**
     * 
     *  Helper method to get HTMLized message from Bundle
     * 
     * @param msg non-htmlized (or partitialy HTMLized tekst)
     * @return fully HTMLized message 
     * 
     */
    public String getMessageHTML(String msg)
    {

        String mm = this.getMessage(msg);

        return htmlize(mm);

    }





    //  Method:       getString
    /**
     * 
     *  This helper method calls getMessage(String) and returns message that is
     *  associated with inserted code. It is implemented mainly, because some 
     *  programmers are used that resource nsg is returned with this command.
     * 
     *  @param msg id of message we want
     *  @return value for code, or same code back
     */
    public String getString(String msg)
    {
        return this.getMessage(msg);
    }



    //  Method:       returnSameValue (String)
    /**
     * 
     *  Returns same value as it was sent to catalog in case that catalog entry was not
     *  found. This message has inserted spaces so that is easier readable.
     * 
     *  @param msg id of message we want
     *  @return same code back (formated)
     */
    private String returnSameValue(String msg)
    {
        // If we return same msg back, without beeing resolved, we put spaces before %, so
        // that it is much easier readable.
        if (msg.indexOf("%")==-1)
            return msg;

        StringBuffer out=new StringBuffer();
        int idx;
        while ((idx=msg.indexOf("%"))!=-1)
        {
            out.append(msg.substring(0, idx));
            out.append("|%");
            
            msg = msg.substring(idx+1);
                
        }

        out.append(msg);

        return out.toString();

    }



    // Method: resolveMnemonic(String)
    /**
     *  This method extracts mnemonics from message string. Each such string can
     *  contain several & characters, even double &. Last & in String is mnemonic
     *  while other are discarded. Double && is resolved to single & in text. We 
     *  return array of Object. First entry contains mnemonic if this is null, we 
     *  didn't find any mnemonic. Second entry is text without mnemonic and changed 
     *  && substrings. If whole object is returned as null, then String didn't 
     *  contain any & signs.
     * 
     *  @param msg message from message catalog
     *  @return array of Object, containg max. two elements, null can also be returned
     *
     */
    private Object[] resolveMnemonics(String msg)
    {

        if (msg.indexOf("&")==-1)
            return null;


        Object back[] = new Object[2];
        int msg_length = msg.length();
        int code[] = new int[msg_length];
        boolean foundDouble=false;
        boolean foundMnemonic=false;


        for (int i=0;i<msg_length;i++)
        {
            if (msg.charAt(i)=='&')
            {
                // we found mnemonic sign   
                code[i]=1;  // 1 if & sign
                if (i!=0)
                {
                    // check for double &
                    if (code[i-1]==1)  // double & are marked 2
                    {
                        code[i-1]=2;
                        code[i]=2;
                        foundDouble=true;
                    }
                }
            }
            else
                code[i]=0;
        }


        // now we find real menmonic
        for (int i=msg_length-1; i>-1; i--)
        {
            if (code[i]==1)
            {
                code[i]=3;
                if (i==msg_length-1)  // if & is last char we ignore it
                {
                    code[i]=1;
                }
                else
                {
                    foundMnemonic=true;
                    break;
                }
            }
        }


        StringBuffer returnStr = new StringBuffer();

        int lastChange=0;

        for (int i=0; i<msg_length;i++)
        {
            
            if (code[i]==1)  // all & (tagged 1) are removed
            {
                returnStr.append(msg.substring(lastChange, i));
                lastChange=i+1;
                
            } 
            else if (code[i]==2) // all && are replaced with one &
            {
                returnStr.append(msg.substring(lastChange, i));
                returnStr.append("&");
                lastChange=i+2; // was 2
                i=i+1;
            }
            else if (code[i]==3) // this is mnemonic
            {
                back[0]=new Character(msg.charAt(i+1)); 
                returnStr.append(msg.substring(lastChange, i));
                lastChange=i+1;
            }
        }

        returnStr.append(msg.substring(lastChange));

        back[1] = returnStr.toString();

        if (!foundMnemonic)
            back[0]=null;

        return back;
    
    }



    // Method: getMnemonic
    /**
     *  Returns mnemonic of String that is stored in bundle as msg_id. If mnemonic is
     *  not found 0 is returned. Calls private method resolveMnemonics.
     * 
     *  @see resolveMnemonic
     *  @param msg_id id of message in bundle
     *  @return int representation of char that is mnemonic, 0 if none found
     */
    public char getMnemonic(String msg_id)
    {
        try
        {
            Object[] back = resolveMnemonics(getMessageFromCatalog(msg_id));

            if ((back==null) || (back[0]==null))
               return 0;
        
            return ((Character)back[0]).charValue();
        }
        catch (Exception e)
        {
            return 0;
        }

    }



    // Method: getMessageWithoutMnemonic
    /**
     *  Returns String that is stored in bundle as msg_id. It also removes  
     *  mnemonic signs and removed double &. Calls private method resolveMnemonics.
     * 
     *  @see resolveMnemonic
     *  @param msg_id id of message in bundle
     *  @return String message from catalog, woithout mnemonic and double &
     */
    public String getMessageWithoutMnemonic(String msg_id)
    {
        try
        {

            String ret = getMessageFromCatalog(msg_id);

            Object[] back = resolveMnemonics(ret);

            if (back==null)
                return ret;
            else
                return (String)back[1];
        }
        catch(Exception ex)
        {
            return returnSameValue(msg_id);
        }
    }



    // Method: getMessageFromCatalog
    /**
     *  Looks into bundle and returns correct message. This method is syncronized, so only one
     *  message at the time can be returned.
     * 
     *  @param msg id of message in bundle
     *  @return String message from catalog.
     */
    private synchronized String getMessageFromCatalog(String msg)
    {

        try
        {
            
            if (msg==null)
                return "null";
            
            String ret = res.getString(msg);

            if (ret==null)
            {
                System.out.println("Couldn't find message: ");
                return returnSameValue(msg);
            }
            else
                return ret;

        }
        catch(Exception ex)
        {
            return returnSameValue(msg);
        }

    }



    //  Method:       getMessage (String)
    /**
     * 
     *  Helper method to get message from Bundle.
     * 
     *  @param msg id of message we want
     *  @return value for code, or same code back
     */    
    public String getMessage(String msg)
    {

        return getMessageFromCatalog(msg);

    }





    


    public static void main(String args[])
    {

        I18nControl oc = I18nControl.getInstance();

//        System.out.println(oc.getMessage(12, 1));


    }






}



--=====================_761973078==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="JSword_EN.properties"





# [Blur]
BLUR_BY=Blur by
VERSE=verse
BLUR_PASAGE_BY=Blur passage by
BLUR_THE_CURRENT_PASSAGE_BY=Blur the current passage by




# [Main]

VERSION=Version
RUNNING_TASKS=Running Tasks
ERRORS=Errors
SYSTEM_PROPERTIES=System Properties
DEBUG=Debug
OK=&Ok


# [JSwordGUI.Main GUI]

FILE=&File
FILE_NEW=&New Window
FILE_NEW_TIP=New Window
FILE_NEW_DESC=Open a new Bible View window
FILE_OPEN=&Open ...
FILE_OPEN_TIP=Open Passage
FILE_OPEN_DESC=Open a saved passage.
FILE_CLOSE=&Close
FILE_CLOSE_TIP=Close Passages
FILE_CLOSE_DESC=Close the current passage
FILE_CLOSE_ALL=C&lose All
FILE_CLOSE_ALL_TIP=Close All Passages
FILE_CLOSE_ALL_DESC=Close all the passages
FILE_PRINT=Print ...
FILE_PRINT_TIP=Print Passage
FILE_PRINT_DESC=Print the current passage.
FILE_SAVE=Save ...
FILE_SAVE_TIP=Save Passage
FILE_SAVE_DESC=Save the current passage.
FILE_SAVE_AS=Save As ...
FILE_SAVE_AS_TIP=Save Passage As
FILE_SAVE_AS_DESC=Save the current passage under a different name.
FILE_SAVE_ALL=Save All
FILE_SAVE_ALL_TIP=Save All Passages
FILE_SAVE_ALL_DESC=Save all the passages.
FILE_EXIT=Exit
FILE_EXIT_TIP=Exit
FILE_EXIT_DESC=Exit the Desktop application.

EDIT=&Edit
EDIT_CUT=C&ut
EDIT_CUT_TIP=Cut
EDIT_CUT_DESC=Cut the selection.
EDIT_COPY=&Copy
EDIT_COPY_TIP=Copy
EDIT_COPY_DESC=Copy the selection.
EDIT_PASTE=&Paste
EDIT_PASTE_TIP=Paste
EDIT_PASTE_DESC=Paste the selection.

VIEW=&View
VIEW_TABBED=&Tabbed Mode
VIEW_TABBED_TIP=View passages using tabs", 
VIEW_TABBED_DESC=View passages using a tab based layout
VIEW_SUBWINDOW=Sub-Window &Mode
VIEW_SUBWINDOW_TIP=View passages using sub-windows
VIEW_SUBWINDOW_DESC=View passages using a MDI based windows layout
VIEW_GHTML=View &G-HTML Source
VIEW_GHTML_TIP=View Generated HTML Source
VIEW_GHTML_DESC=View the generated HTML source to the current window
VIEW_HTML=View &HTML Source
VIEW_HTML_TIP=View HTML Source
VIEW_HTML_DESC=View the HTML source to the current window
VIEW_OSIS=View &OSIS Source
VIEW_OSIS_TIP=View OSIS Source
VIEW_OSIS_DESC=View the OSIS source to the current window

TOOLS=&Tools
TOOLS_BLUR1=Blur by 1 Verse
TOOLS_BLUR1_TIP=Blur passage by 1 Verse
TOOLS_BLUR1_DESC=Blur the current passage by 1 Verse
TOOLS_BLUR5=Blur by 5 Verse
TOOLS_BLUR5_TIP=Blur passage by 5 Verse
TOOLS_BLUR5_DESC=Blur the current passage by 5 Verse
TOOLS_LISTDELETE=&Delete Selected
TOOLS_LISTDELETE_TIP=Delete selected verses
TOOLS_LISTDELETE_DESC=Deleted the selected verses in the current verse list.
TOOLS_SITES=Boo&ks ...
TOOLS_SITES_TIP=Display/Install Books
TOOLS_SITES_DESC=Investigate Books and link to sites that allow new downloads
TOOLS_OPTIONS=&Options ...
TOOLS_OPTIONS_TIP=Options
TOOLS_OPTIONS_DESC=Alter system settings.

HELP=&Help
HELP_ABOUT=&About
HELP_ABOUT_TIP=About
HELP_ABOUT_DESC=The more information about Investigate tasks, errors and logs
HELP_CONTENTS=&Contents ...
HELP_CONTENTS_TIP=Help
HELP_CONTENTS_DESC=Help file contents.




TEST=/join #7th_Heaven_Episodes


# [common.config]

CONFIG_NOCLASS=Specified class not found: %s
CONFIG_MISSINGELE=Missing %s element in config.xml
CONFIG_NOSETTER=Specified method not found %s.set%s(%s arg0)
CONFIG_NOGETTER=Specified method not found %s.get%s()
CONFIG_NORETURN=Mismatch of return types, found: %s required: %s
CONFIG_NOMAP=Missing <map> element.

--=====================_761973078==_--