All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.rtext.RTextMenuBar Maven / Gradle / Ivy

Go to download

RText is a powerful, cross-platform programmer's text editor written in Java. It is designed to be easy to use, highly customizable and flexible. Part of RText's design is for the source code to be simple, easy to understand, and well documented, so that other programmers can look into its inner-workings and figure out how RText ticks with ease. A good place to start (besides the source code) is the Javadoc for all classes used in the project.

There is a newer version: 2.0.7
Show newest version
/*
 * 11/14/2003
 *
 * RTextMenuBar.java - Menu bar used by RText.
 * Copyright (C) 2003 Robert Futrell
 * robert_futrell at users.sourceforge.net
 * http://rtext.fifesoft.com
 *
 * This file is a part of RText.
 *
 * RText 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 any later version.
 *
 * RText 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.
 */
package org.fife.rtext;

import java.awt.FontMetrics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import javax.swing.AbstractAction;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.Action;

import org.fife.rtext.actions.ViewTasksAction;
import org.fife.ui.UIUtil;
import org.fife.ui.app.MenuBar;
import org.fife.ui.app.PluginMenu;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextAreaEditorKit;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;


/**
 * The menu bar used by rtext.  The menu bar includes a "file history" feature,
 * where it can remember any number of recent files and display them as options
 * in the File menu.
 *
 * @author Robert Futrell
 * @version 0.5
 */
class RTextMenuBar extends MenuBar implements PropertyChangeListener,
									PopupMenuListener {

	// These items correspond to actions belonging to RTextEditorPanes, and are
	// changed in disableEditorActions() below, so we need to remember them.
	private JMenuItem newItem;
	private JMenuItem openItem;
	private JMenuItem openInNewWindowItem;
	private JMenuItem openRemoteItem;
	private JMenuItem saveItem;
	private JMenuItem saveAsItem;
	private JMenuItem saveAsRemoteItem;
	private JMenuItem saveAsWebPageItem;
	private JMenuItem saveAllItem;
	private JMenuItem closeItem;
	private JMenuItem closeAllItem;
	private JMenuItem printItem;
	private JMenuItem printPreviewItem;
	private JMenuItem exitItem;
	private JMenuItem undoItem;
	private JMenuItem redoItem;
	private JMenuItem cutItem;
	private JMenuItem copyItem;
	private JMenuItem copyAsRtfItem;
	private JMenuItem pasteItem;
	private JMenuItem deleteItem;
	private JMenuItem findItem;
	private JMenuItem findNextItem;
	private JMenuItem replaceItem;
	private JMenuItem replaceNextItem;
	private JMenuItem findInFilesItem;
	private JMenuItem replaceInFilesItem;
	private JMenuItem goToItem;
	private JMenuItem selectAllItem;
	private JMenuItem timeDateItem;
	private JMenuItem optionsItem;
	private JCheckBoxMenuItem toolbarItem;
	private JCheckBoxMenuItem searchToolbarMenuItem;
	private JCheckBoxMenuItem statusBarItem;
	private JCheckBoxMenuItem lineNumbersItem;
	private JCheckBoxMenuItem tasksItem;
	private JMenuItem increaseFontSizesItem;
	private JMenuItem decreaseFontSizesItem;
	//private JRadioButtonMenuItem ltrItem, rtlItem;
	//private JRadioButtonMenuItem splitHorizItem, splitVertItem, splitNoneItem;
	private JMenuItem helpItem;
	private JMenuItem homePageItem;
	private JMenuItem aboutItem;
	private JMenuItem filePropItem;

	private JMenu fileMenu;
	private JMenu viewMenu;
	private JMenu pluginMenu;
	private JMenu windowMenu;
	private JMenu recentFilesMenu;
	private JMenu savedMacroMenu;

	private RText rtext;

	private int maxFileHistorySize;	// Number of files to remember in the "file history."
	private int numFilesInHistory;	// Number of files currently in the file history.

	private ArrayList fileHistory;	// Strings representing full paths of file history.

	/**
	 * Approximate maximum length, in pixels, of a File History entry.
	 * Note that this is only  GUIDELINE, and some filenames
	 * can (and will) exceed this limit.
	 */
	private final int MAX_FILE_PATH_LENGTH = 250;


	/**
	 * Creates an instance of the menu bar.
	 *
	 * @param rtext The instance of the RText editor that this
	 *        menu bar belongs to.
	 * @param lnfName The name for a look and feel; should be obtained from
	 *        UIManager.getLookAndFeel().getName().
	 * @param properties The properties we'll be using to initialize the menu
	 *        bar.
	 */
	public RTextMenuBar(final RText rtext, String lnfName,
							RTextPreferences properties) {

		// Initialize some private variables.
		this.rtext = rtext;

		// Variables to create the menu.
		JMenu menu;
		JMenuItem menuItem;
		ResourceBundle msg = rtext.getResourceBundle();
		ResourceBundle menuMsg = ResourceBundle.getBundle("org.fife.rtext.MenuBar");

		// File submenu.
		fileMenu = createMenu(menuMsg, "MenuFile");
		add(fileMenu);

		// File submenu's items.
		newItem = createMenuItem(rtext.getAction(RText.NEW_ACTION));
		fileMenu.add(newItem);

		openItem = createMenuItem(rtext.getAction(RText.OPEN_ACTION));
		fileMenu.add(openItem);

		openInNewWindowItem = createMenuItem(rtext.getAction(RText.OPEN_NEWWIN_ACTION));
		fileMenu.add(openInNewWindowItem);

		openRemoteItem = createMenuItem(rtext.getAction(RText.OPEN_REMOTE_ACTION));
		fileMenu.add(openRemoteItem);

		closeItem = createMenuItem(rtext.getAction(RText.CLOSE_ACTION));
		fileMenu.add(closeItem);

		closeAllItem = createMenuItem(rtext.getAction(RText.CLOSE_ALL_ACTION));
		fileMenu.add(closeAllItem);

		fileMenu.addSeparator();

		saveItem = createMenuItem(rtext.getAction(RText.SAVE_ACTION));
		fileMenu.add(saveItem);

		saveAsItem = createMenuItem(rtext.getAction(RText.SAVE_AS_ACTION));
		fileMenu.add(saveAsItem);

		saveAsRemoteItem = createMenuItem(rtext.getAction(RText.SAVE_AS_REMOTE_ACTION));
		fileMenu.add(saveAsRemoteItem);

		saveAsWebPageItem = createMenuItem(rtext.getAction(RText.SAVE_WEBPAGE_ACTION));
		fileMenu.add(saveAsWebPageItem);

		saveAllItem = createMenuItem(rtext.getAction(RText.SAVE_ALL_ACTION));
		fileMenu.add(saveAllItem);

		fileMenu.addSeparator();

		printItem = createMenuItem(rtext.getAction(RText.PRINT_ACTION));
		fileMenu.add(printItem);

		printPreviewItem = createMenuItem(rtext.getAction(RText.PRINT_PREVIEW_ACTION));
		fileMenu.add(printPreviewItem);

		fileMenu.addSeparator();

		recentFilesMenu = new JMenu(menuMsg.getString("RecentFiles"));
		fileMenu.add(recentFilesMenu);

		// Add file history, if any.
		// FIXME:  Make this configurable from the Options dialog!!
		this.maxFileHistorySize = 20;//maxFileHistorySize;
		fileHistory = new ArrayList(maxFileHistorySize);
		if (properties.fileHistoryString != null) {
			StringTokenizer st = new StringTokenizer(properties.fileHistoryString, "<");
			String token;
			while (st.hasMoreTokens()) {
				token = st.nextToken();
				addFileToFileHistory(token);
			}
		}

		// 1.5.2004/pwy: On OS X the Exit menu item is in the standard
		// application menu and is always generated by the system. No need to
		// have an additional Exit in the menu.
		if (rtext.getOS()!=RText.OS_MAC_OSX) {
			exitItem = createMenuItem(rtext.getAction(RText.EXIT_ACTION_KEY));
			fileMenu.addSeparator();
			fileMenu.add(exitItem);
		}

		// Edit submenu.
		menu = createMenu(menuMsg, "MenuEdit");
		add(menu);

		// Edit submenu's items.
		undoItem = createMenuItem(RTextArea.getAction(RTextArea.UNDO_ACTION));
		menu.add(undoItem);

		redoItem = createMenuItem(RTextArea.getAction(RTextArea.REDO_ACTION));
		menu.add(redoItem);

		menu.addSeparator();

		cutItem = createMenuItem(RTextArea.getAction(RTextArea.CUT_ACTION));
		menu.add(cutItem);

		copyItem = createMenuItem(RTextArea.getAction(RTextArea.COPY_ACTION));
		menu.add(copyItem);

		copyAsRtfItem = createMenuItem(rtext.getAction(RText.COPY_AS_RTF_ACTION));
		menu.add(copyAsRtfItem);

		pasteItem = createMenuItem(RTextArea.getAction(RTextArea.PASTE_ACTION));
		menu.add(pasteItem);

		deleteItem = createMenuItem(RTextArea.getAction(RTextArea.DELETE_ACTION));
		menu.add(deleteItem);

		menu.addSeparator();

		selectAllItem = createMenuItem(RTextArea.getAction(RTextArea.SELECT_ALL_ACTION));
		menu.add(selectAllItem);

		timeDateItem = createMenuItem(rtext.getAction(RText.TIME_DATE_ACTION));
		menu.add(timeDateItem);

		menu.addSeparator();

		// The "text" menu.  Note that keystrokes are okay here, because
		// these actions are also owned by RSyntaxTextArea and thus we
		// do not want to be able to change them.
		JMenu textMenu = createMenu(menuMsg, "MenuText");
		int defaultModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
		menuItem = createMenuItem(
				new RSyntaxTextAreaEditorKit.ToggleCommentAction(),
				menuMsg, "ToggleComment", "ToggleCommentMnemonic",
				KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, defaultModifier));
		UIUtil.setDescription(menuItem, menuMsg, "DescToggleComment");
		textMenu.add(menuItem);
		textMenu.addSeparator();
		menuItem = createMenuItem(
				new RTextAreaEditorKit.DeleteRestOfLineAction(),
				menuMsg, "DeleteLineRemainder", "DeleteLineRemainderMnemonic",
				KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, defaultModifier));
		UIUtil.setDescription(menuItem, menuMsg, "DescDeleteLineRemainder");
		textMenu.add(menuItem);
		menuItem = createMenuItem(
				new RSyntaxTextAreaEditorKit.JoinLinesAction(),
				menuMsg, "JoinLines", "JoinLinesMnemonic",
				KeyStroke.getKeyStroke(KeyEvent.VK_J, defaultModifier));
		UIUtil.setDescription(menuItem, menuMsg, "DescJoinLines");
		textMenu.add(menuItem);
		textMenu.addSeparator();
		menuItem = createMenuItem(
				new RTextAreaEditorKit.UpperSelectionCaseAction(),
				menuMsg, "UpperCase", "UpperCaseMnemonic");
		UIUtil.setDescription(menuItem, menuMsg, "DescUpperCase");
		textMenu.add(menuItem);
		menuItem = createMenuItem(
				new RTextAreaEditorKit.LowerSelectionCaseAction(),
				menuMsg, "LowerCase", "LowerCaseMnemonic");
		UIUtil.setDescription(menuItem, menuMsg, "DescLowerCase");
		textMenu.add(menuItem);
		menuItem = createMenuItem(
				new RTextAreaEditorKit.InvertSelectionCaseAction(),
				menuMsg, "InvertCase", "InvertCaseMnemonic");
		UIUtil.setDescription(menuItem, menuMsg, "DescInvertCase");
		textMenu.add(menuItem);
		menu.add(textMenu);

		// The "indent" menu.  Note that keystrokes are okay here, because
		// these actions are also owned by the RSyntaxTextArea and thus we do
		// not want to be able to change them.
		JMenu indentMenu = createMenu(menuMsg, "MenuIndent");
		final int shift = InputEvent.SHIFT_MASK;
		menuItem = createMenuItem(
						//new RSyntaxTextAreaEditorKit.IncreaseIndentAction(),
						new RSyntaxTextAreaEditorKit.InsertTabAction(),
						menuMsg, "IncreaseIndent", "IncreaseIndentMnemonic",
						KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
		UIUtil.setDescription(menuItem, menuMsg, "DescIncreaseIndent");
		indentMenu.add(menuItem);
		menuItem = createMenuItem(
						new RSyntaxTextAreaEditorKit.DecreaseIndentAction(),
						menuMsg, "DecreaseIndent", "DecreaseIndentMnemonic",
						KeyStroke.getKeyStroke(KeyEvent.VK_TAB, shift));
		UIUtil.setDescription(menuItem, menuMsg, "DescDecreaseIndent");
		indentMenu.add(menuItem);
		menu.add(indentMenu);

		// 1.5.2004/pwy: On OS X the Options menu item is in the standard
		// application menu and is always generated by the system. No need
		// to have an additional Options in the menu.
		if (rtext.getOS()!=RText.OS_MAC_OSX) {
			menu.addSeparator();
			optionsItem = createMenuItem(rtext.getAction(RText.OPTIONS_ACTION));
			menu.add(optionsItem);
		}

		// Search menu.
		menu = createMenu(menuMsg, "MenuSearch");
		add(menu);

		// Search menu's items.
		findItem = createMenuItem(rtext.getAction(RText.FIND_ACTION));
		menu.add(findItem);

		findNextItem = createMenuItem(rtext.getAction(RText.FIND_NEXT_ACTION));
		menu.add(findNextItem);

		replaceItem = createMenuItem(rtext.getAction(RText.REPLACE_ACTION));
		menu.add(replaceItem);

		replaceNextItem = createMenuItem(rtext.getAction(RText.REPLACE_NEXT_ACTION));
		menu.add(replaceNextItem);

		menu.addSeparator();

		findInFilesItem = createMenuItem(rtext.getAction(RText.FIND_IN_FILES_ACTION));
		menu.add(findInFilesItem);

		replaceInFilesItem = createMenuItem(
				rtext.getAction(RText.REPLACE_IN_FILES_ACTION));
		menu.add(replaceInFilesItem);

		menu.addSeparator();

		goToItem = createMenuItem(rtext.getAction(RText.GOTO_ACTION));
		menu.add(goToItem);

		menuItem = createMenuItem(
			new RSyntaxTextAreaEditorKit.GoToMatchingBracketAction(),
			menuMsg, "GoToMatchingBracket", "GoToMatchingBracketMnemonic",
			KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, defaultModifier));
		UIUtil.setDescription(menuItem, menuMsg, "DescGoToMatchingBracket");
		menu.add(menuItem);

		menu.addSeparator();

		menuItem = createMenuItem(
				new RTextAreaEditorKit.NextBookmarkAction(
					RTextAreaEditorKit.rtaNextBookmarkAction, true),
				menuMsg, "NextBookmark", "NextBookmarkMnemonic",
				KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
		UIUtil.setDescription(menuItem, menuMsg, "DescNextBookmark");
		menu.add(menuItem);

		menuItem = createMenuItem(
				new RTextAreaEditorKit.NextBookmarkAction(
					RTextAreaEditorKit.rtaNextBookmarkAction, false),
				menuMsg, "PreviousBookmark", "PreviousBookmarkMnemonic",
				KeyStroke.getKeyStroke(KeyEvent.VK_F2, shift));
		UIUtil.setDescription(menuItem, menuMsg, "DescPreviousBookmark");
		menu.add(menuItem);

		menuItem = createMenuItem(
				new RTextAreaEditorKit.ToggleBookmarkAction(),
				menuMsg, "ToggleBookmark", "ToggleBookmarkMnemonic",
				KeyStroke.getKeyStroke(KeyEvent.VK_F2, defaultModifier));
		UIUtil.setDescription(menuItem, menuMsg, "DescToggleBookmark");
		menu.add(menuItem);

		// View submenu.
		viewMenu = createMenu(menuMsg, "MenuView");
		viewMenu.getPopupMenu().addPopupMenuListener(this);
		add(viewMenu);

		// View submenu's items.
		JMenu toolbarsMenu = new JMenu(menuMsg.getString("Toolbars"));
		Action a = rtext.getAction(RText.TOOL_BAR_ACTION);
		toolbarItem = new JCheckBoxMenuItem(a);
		toolbarItem.setToolTipText(null);
		toolbarItem.setSelected(properties.toolbarVisible);
		toolbarsMenu.add(toolbarItem);
		searchToolbarMenuItem = new JCheckBoxMenuItem(new SearchToolBarAction(
						rtext, menuMsg.getString("QuickSearchBar"), null,
						null, -1, null));
		searchToolbarMenuItem.setSelected(properties.searchToolBarVisible);
		UIUtil.setDescription(searchToolbarMenuItem, menuMsg,"DescQuickSearch");
		toolbarsMenu.add(searchToolbarMenuItem);
		viewMenu.add(toolbarsMenu);

		statusBarItem = new JCheckBoxMenuItem(rtext.getAction(RText.STATUS_BAR_ACTION));
		statusBarItem.setToolTipText(null);
		statusBarItem.setSelected(properties.statusBarVisible);
		viewMenu.add(statusBarItem);

		lineNumbersItem = new JCheckBoxMenuItem(rtext.getAction(RText.LINE_NUMBER_ACTION));
		lineNumbersItem.setSelected(properties.lineNumbersVisible);
		lineNumbersItem.setToolTipText(null);
//		UIUtil.setDescription(lineNumbersItem, msg, "DescLineNumbers");
		viewMenu.add(lineNumbersItem);

		final ViewTasksAction vta = (ViewTasksAction)rtext.getAction(RText.VIEW_TASKS_ACTION);
		tasksItem = new JCheckBoxMenuItem(vta);
		tasksItem.setToolTipText(null);
		// Unfortunately we must wrap this in an invokeLater, since the action
		// adds the window in an invokeLater() itself...
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				tasksItem.setState(vta.isTaskWindowVisible());
			}
		});
		viewMenu.add(tasksItem);

		// Font sizes submenu.
		JMenu fontSizesMenu = createMenu(menuMsg, "MenuFontSizes");
		a = new RSyntaxTextAreaEditorKit.DecreaseFontSizeAction();
		decreaseFontSizesItem = createMenuItem(a, menuMsg,
					"DecreaseFontSizes", "DecreaseFontSizesMnemonic",
					KeyStroke.getKeyStroke(KeyEvent.VK_F6, defaultModifier));
		UIUtil.setDescription(decreaseFontSizesItem,menuMsg,"DescDecFontSizes");
		fontSizesMenu.add(decreaseFontSizesItem);
		a = new RSyntaxTextAreaEditorKit.IncreaseFontSizeAction();
		increaseFontSizesItem = createMenuItem(a, menuMsg,
					"IncreaseFontSizes", "IncreaseFontSizesMnemonic",
					KeyStroke.getKeyStroke(KeyEvent.VK_F7, defaultModifier));
		UIUtil.setDescription(increaseFontSizesItem,menuMsg,"DescIncFontSizes");
		fontSizesMenu.add(increaseFontSizesItem);
		viewMenu.add(fontSizesMenu);
/*
		// Text orientation submenu
		JMenu orientMenu = createMenu(menuMsg, "TextOrientation");
		ltrItem = createRadioButtonMenuItem(
				rtext.getAction(RText.LTR_ACTION),
				null, menuMsg.getString("DescLeftToRight"));
		orientMenu.add(ltrItem);
		rtlItem = createRadioButtonMenuItem(
				rtext.getAction(RText.RTL_ACTION),
				null, menuMsg.getString("DescRightToLeft"));
		orientMenu.add(rtlItem);
		ButtonGroup bg = new ButtonGroup();
		bg.add(ltrItem);
		bg.add(rtlItem);
		viewMenu.add(orientMenu);

		viewMenu.addSeparator();

		// Split view submenu.
		JMenu splitViewMenu = createMenu(menuMsg, "MenuSplitView",
									"MenuSplitViewMnemonic");
		splitHorizItem = createRadioButtonMenuItem(
				rtext.getAction(RText.VIEW_SPLIT_HORIZ_ACTION),
				null, menuMsg.getString("DescSplitViewHoriz"));
		splitViewMenu.add(splitHorizItem);
		splitVertItem = createRadioButtonMenuItem(
				rtext.getAction(RText.VIEW_SPLIT_VERT_ACTION),
				null, menuMsg.getString("DescSplitViewVert"));
		splitViewMenu.add(splitVertItem);
		splitNoneItem = createRadioButtonMenuItem(
				rtext.getAction(RText.VIEW_SPLIT_NONE_ACTION),
				null, menuMsg.getString("DescSplitViewNone"));
		splitViewMenu.add(splitNoneItem);
		viewMenu.add(splitViewMenu);
*/
		viewMenu.addSeparator();

		filePropItem = createMenuItem(rtext.getAction(
										RText.FILE_PROPERTIES_ACTION));
		viewMenu.add(filePropItem);
/* TODO: 1.1
		// Tools menu
		menu = createMenu(menuMsg, "MenuTools");
		add(menu);

		menu.add(createMenuItem(rtext.getAction(RTextActionInfo.NEW_TOOL_ACTION)));
*/
		// Macros menu.
		menu = createMenu(menuMsg, "MenuMacros");
		add(menu);

		int ctrlshift = InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK;

		a = new BeginRecordingMacroAction(menuMsg.getString("MacroBegin"),
						null, // icon
						null, // desc
						null, // mnemonic
						KeyStroke.getKeyStroke(KeyEvent.VK_R,ctrlshift),
						rtext,
						false); // false => NOT temporary.
		JMenuItem item = new JMenuItem(a);
		item.setToolTipText(null);
		UIUtil.setDescription(item, menuMsg, "MacroBeginDesc");
		menu.add(item);

		a = new BeginRecordingMacroAction(menuMsg.getString("MacroBeginTemp"),
						null, // icon
						null, // desc
						null, // mnemonic
						null,//KeyStroke.getKeyStroke(KeyEvent.VK_R,ctrlshift),
						rtext,
						true); // true => temporary.
		item = new JMenuItem(a);
		item.setToolTipText(null);
		UIUtil.setDescription(item, menuMsg, "MacroBeginTempDesc");
		menu.add(item);

		a = new EndRecordingMacroAction(menuMsg.getString("MacroEnd"),
						null, // icon
						null, // desc
						null, // mnemonic
						KeyStroke.getKeyStroke(KeyEvent.VK_S,ctrlshift),
						rtext);
		item = new JMenuItem(a);
		item.setToolTipText(null);
		UIUtil.setDescription(item, menuMsg, "MacroEndDesc");
		menu.add(item);

		menu.addSeparator();

		a = new RTextAreaEditorKit.PlaybackLastMacroAction(
							menuMsg.getString("MacroPlay"),
							null, // icon
							null, // desc
							null, // mnemonic
							KeyStroke.getKeyStroke(KeyEvent.VK_M,ctrlshift));
		item = new JMenuItem(a);
		item.setToolTipText(null);
		UIUtil.setDescription(item, menuMsg, "MacroPlayDesc");
		menu.add(item);

		savedMacroMenu = createMenu(menuMsg, "MenuSavedMacro");
		savedMacroMenu.getPopupMenu().addPopupMenuListener(this);
		menu.add(savedMacroMenu);

		// Window menu (only visible when in MDI mode).
		windowMenu = createMenu(menuMsg, "MenuWindow");
		add(windowMenu);

		item = new JMenuItem(menuMsg.getString("TileVertically"));
		UIUtil.setDescription(item, msg, "DescTileVertically");
		item.setActionCommand("TileVertically");
		item.addActionListener(rtext);
		windowMenu.add(item);

		item = new JMenuItem(menuMsg.getString("TileHorizontally"));
		UIUtil.setDescription(item, msg, "DescTileHorizontally");
		item.setActionCommand("TileHorizontally");
		item.addActionListener(rtext);
		windowMenu.add(item);

		item = new JMenuItem(menuMsg.getString("Cascade"));
		UIUtil.setDescription(item, msg, "DescCascade");
		item.setActionCommand("Cascade");
		item.addActionListener(rtext);
		windowMenu.add(item);

		windowMenu.addSeparator();

		// Add listener that will create open document list.
		windowMenu.getPopupMenu().addPopupMenuListener(this);

		// Plugin menu.
		pluginMenu = new PluginMenu(rtext, true);
		//createMenu(menuMsg, "MenuPlugins");
		add(pluginMenu);

		// Help submenu.
		menu = createMenu(menuMsg, "MenuHelp");
		add(menu);

		// Help submenu's items.
		helpItem = createMenuItem(rtext.getAction(RText.HELP_ACTION_KEY));
		menu.add(helpItem);

		homePageItem = createMenuItem(rtext.getAction(RText.HOME_PAGE_ACTION));
		menu.add(homePageItem);

		menu.addSeparator();

		aboutItem = createMenuItem(rtext.getAction(RText.ABOUT_ACTION_KEY));
		menu.add(aboutItem);

	}


	/**
	 * Adds the file specified to the file history.
	 *
	 * @param fileFullPath Full path to a file to add to the file history in
	 *        the File menu.
	 * @see #getFileHistoryString
	 */
	private void addFileToFileHistory(String fileFullPath) {

		// We don't remember just-created empty text files.
		// Also, due to the Preferences API needing a non-null key for all
		// values, a "-" filename means no files were found for the file
		// history.  So, we won't add this file in either.
		if (fileFullPath.endsWith(File.separatorChar + rtext.getNewFileName())
				|| fileFullPath.equals("-"))
			return;

		JMenuItem menuItem;

		// If the file history already contains this file, remove it and add
		// it back to the top of the list; this keeps the list in a "most
		// recently opened" order.
		int index = fileHistory.indexOf(fileFullPath);
		if (index>-1) {
			// Remove it physically from the menu and add it back at the
			// top, then remove it from the path history and it its path
			// to the top of that.
			menuItem = (JMenuItem)recentFilesMenu.getMenuComponent(index);
			recentFilesMenu.remove(index);
			recentFilesMenu.insert(menuItem, 0);
			Object temp = fileHistory.remove(index);
			fileHistory.add(0, temp);
			return;
		}

		// If the path name is too long, make an "abbrevriated name" to put in the menu.
		String displayPath = getDisplayPath(fileFullPath);

		// Create an action to open the file.
		OpenFileFromHistoryAction tempAction = new OpenFileFromHistoryAction(
									rtext, displayPath, null, null,
									-1, null, fileFullPath);

		// Add the new file to the top of the file history list.
		menuItem = new JMenuItem(tempAction);
		recentFilesMenu.insert(menuItem, 0);
		fileHistory.add(0, fileFullPath);		// 0th position is top of the list.

		// If there are still some spaces in the file history, just
		// remember we've added a new file.
		if (numFilesInHistory < maxFileHistorySize) {
			numFilesInHistory++;
		}

		// If there are now too many files, oust the file in history added least recently.
		else {
			recentFilesMenu.remove(recentFilesMenu.getItemCount()-1);
			fileHistory.remove(fileHistory.size()-1);	// Last item.
		}

	}


	/**
	 * Attempts to return an "attractive" shortened version of
	 * fullPath.  For example,
	 * /home/lobster/dir1/dir2/dir3/dir4/file.out could be
	 * abbreviated as /home/lobster/dir1/.../file.out.  Note that
	 * this method is still in the works, and isn't fully cooked yet.
	 */
	private String getDisplayPath(String longPath) {

		// Initialize some variables.
		FontMetrics fontMetrics = getFontMetrics(getFont());
		int textWidth = getTextWidth(longPath, fontMetrics);

		// If the text width is already short enough to fit, don't do anything to it.		
		if (textWidth <= MAX_FILE_PATH_LENGTH) {
			return longPath;
		}

		// If it's too long, we'll have to trim it down some...

		// Will be '\' for Windows, '/' for Unix and derivatives.
		String separator = System.getProperty("file.separator");

		// What we will eventually return.
		String displayString = longPath;

		// If there is no directory separator, then the string is just a file name,
		// and so we can't shorten it.  Just return the sucker.
		int lastSeparatorPos = displayString.lastIndexOf(separator);
		if (lastSeparatorPos==-1)
			return displayString;

		// Get the length of just the file name.
		String justFileName = displayString.substring(
						lastSeparatorPos+1, displayString.length());
		int justFileNameLength = getTextWidth(justFileName, fontMetrics);

		// If even just the file name is too long, return it.
		if (justFileNameLength > MAX_FILE_PATH_LENGTH)
			return "..." + separator + justFileName;

		// Otherwise, just keep adding levels in the directory hierarchy
		// until the name gets too long.
		String endPiece = "..." + separator + justFileName;
		int endPieceLength = getTextWidth(endPiece, fontMetrics);
		int separatorPos = displayString.indexOf(separator, 0);
		String firstPart = displayString.substring(0, separatorPos+1);
		int firstPartLength = getTextWidth(firstPart, fontMetrics);
		String tempFirstPart = firstPart;
		int tempFirstPartLength = firstPartLength;
		while (tempFirstPartLength+endPieceLength < MAX_FILE_PATH_LENGTH) {
			firstPart  = tempFirstPart;
			separatorPos = displayString.indexOf(separator, separatorPos+1);
			if (separatorPos==-1)
				endPieceLength = 9999999;
			else {
				tempFirstPart = displayString.substring(0, separatorPos+1);
				tempFirstPartLength = getTextWidth(tempFirstPart, fontMetrics);
			}
		}

		return firstPart+endPiece;

	}


	/**
	 * Returns a string representing all files in the file history separated by
	 * '<' characters.  This character was chosen as the separator because it
	 * is a character that cannot be used in filenames in both Windows and
	 * UNIX/Linux.
	 *
	 * @return A String representing all files in the file
	 *         history, separated by '<' characters.  If no files are in the
	 *         file history, then null is returned.
	 * @see #addFileToFileHistory
	 */
	public String getFileHistoryString() {
		String retVal = null;
		for (int i=numFilesInHistory-1; i>=0; i--) {
			if (i==numFilesInHistory-1)
				retVal = (String)fileHistory.get(i) + "<";
			else
				retVal += (String)fileHistory.get(i) + "<";
		}
		if (retVal!=null)
			retVal = retVal.substring(0, retVal.length()-1); // Remove trailing '>'.
		return retVal;
	}


	/**
	 * Returns the maximum number of files the file history in the File menu
	 * will remember.
	 *
	 * @return The maximum size of the file history.
	 */
	public int getMaximumFileHistorySize() {
		return maxFileHistorySize;
	}


	/**
	 * Determines the width of the given String containing no
	 * tabs.  Note that this is simply a trimmed-down version of
	 * javax.swing.text.getTextWidth that has been
	 * optimized for our use.
	 *
	 * @param s  the source of the text
	 * @param metrics the font metrics to use for the calculation
	 * @return  the width of the text
	 */
	private final int getTextWidth(String s, FontMetrics metrics) {

		int textWidth = 0;

		char[] txt = s.toCharArray();
		int n = txt.length;
		for (int i=0; iRText will remember
	 * for you in it's "file history" in the File menu.
	 *
	 * @param newSize The new size of the file history.
	 */
	public void setMaximumFileHistorySize(int newSize) {

		if (newSize<0)
			return;

		// If the new size is smaller than the current size, we need to remove
		// some files from the history.
		if (newSize




© 2015 - 2025 Weber Informatics LLC | Privacy Policy