/*
* org.openmicroscopy.shoola.env.ui.TaskBarImpl
*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2013 University of Dundee. All rights reserved.
*
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.env.ui;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JToolBar;
import javax.swing.event.MenuKeyListener;
import javax.swing.event.MenuListener;
import org.openmicroscopy.shoola.util.CommonsLangUtils;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
/**
* The view component of the {@link TaskBar}.
* This is just a dummy UI which is controlled by the {@link TaskBarManager}.
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author <br>Andrea Falconi
* <a href="mailto:a.falconi@dundee.ac.uk">
* a.falconi@dundee.ac.uk</a>
* @version 2.2
* @since OME2.2
*/
class TaskBarView
extends JFrame
implements TaskBar
{
//NOTE: We make no assumption on the order in which entries are added/removed
//and when this happens. We don't even impose a sort of internal order. As a
//result, the variuos menus and toolbars might look different across time.
//Moreover, even if all agents always add their entries during the linking
//phase, reordering the agent tags in the configuration file would lead to
//a different order in which agents are linked by the container, which, in
//turn, would result in a different order in which entries are added to the
//menus/toolbars.
/** Identifies the exit menu item within the file menu. */
static final int EXIT_MI = 0;
/**
* Identifies the connect to <i>OMEDS</i> menu item within the connect menu.
*/
static final int CONNECT_MI = 1;
/**
* Identifies the disconnect from <i>OMEDS</i> menu item within the
* connect menu.
*/
static final int DISCONNECT_MI = 2;
/** Identifies the welcome menu item within the help menu. */
static final int WELCOME_MI = 3;
/** Identifies the help contents menu item within the help menu. */
static final int HELP_MI = 4;
/** Identifies the how-to menu item within the help menu. */
static final int HOWTO_MI = 5;
/** Identifies the software updates menu item within the help menu. */
static final int UPDATES_MI = 6;
/** Identifies the about menu item within the help menu. */
static final int ABOUT_MI = 7;
/** Identifies the exit button within the tool bar. */
static final int EXIT_BTN = 8;
/** Identifies the connect to <i>OMEDS</i> button within the tool bar. */
static final int CONNECT_BTN = 9;
/**
* Identifies the disconnect from <i>OMEDS</i> button within the tool bar.
*/
static final int DISCONNECT_BTN = 10;
/** Identifies the help button within the tool bar. */
static final int HELP_BTN = 11;
/** Identifies the comment menu item within the help menu. */
static final int COMMENT_MI = 12;
/** Identifies the help contents menu item within the help menu. */
static final int FORUM_MI = 13;
/** Identifies the activity menu item within the windows menu. */
static final int ACTIVITY_MI = 14;
/** Identifies the log file location menu item within the windows menu. */
static final int LOG_FILE_MI = 15;
/**
* The maximum id of the buttons and menu items identifiers.
* Allows to size the {@link #buttons} array correctly.
*/
private static final int MAX_ID = 15;
/** The title of the frame. */
private static final String TITLE = "Open Microscopy Environment";
/**
* All the button-like objects used by this view.
* These are all the menu items within the various menus in the menu bar
* and all icon buttons within the tool bar.
* We do direct indexing on this array by using the constants specified by
* this class.
*/
private AbstractButton[] buttons;
/**
* The menus specified by {@link TaskBar}.
* We do direct indexing on this array by using the constants specified by
* {@link TaskBar}.
*/
private JMenu[] menus;
/** Cached reference to the {@link IconManager} singleton.*/
private IconManager iconManager;
/** Collection of the copy of the window menu. */
private Set<JMenu> windowMenus;
/** Collection of the copy of the window menu. */
private Set<JMenu> helpMenus;
/** Collection of available menu bars. */
private Set<JMenuBar> menubars;
/** The original menu bar. */
private JMenuBar originalBar;
/** Reference to the manager. */
private TaskBarManager manager;
/** The bars hosting the components to register.*/
private Map<Integer, List<JComponent>> bars;
/**
* Returns a copy of the <code>Help</code> menu.
*
* @return See above.
*/
private JMenu getHelpMenu()
{
JMenu menu = createHelpMenu();
helpMenus.add(menu);
return menu;
}
/**
* Returns a copy of the <code>Windows</code> menu.
*
* @return See above.
*/
private JMenu getWindowsMenu()
{
JMenu menu = createWindowMenu();
Component[] comps = menus[WINDOW_MENU].getPopupMenu().getComponents();
for (int i = 0; i < comps.length; i++) {
if (comps[i] instanceof JMenu)
menu.add(copyItemsFromMenu((JMenu) comps[i]));
else if (comps[i] instanceof JMenuItem)
menu.add(copyItem((JMenuItem) comps[i]));
}
windowMenus.add(menu);
return menu;
}
/**
* Helper method to create all menu items for the various menus within
* the menu bar.
*/
private void createMenuItems()
{
buttons[EXIT_MI] = new JMenuItem("Exit",
iconManager.getIcon(IconManager.EXIT));
buttons[CONNECT_MI] = new JMenuItem("Connect to OMEDS",
iconManager.getIcon(IconManager.CONNECT_DS));
buttons[DISCONNECT_MI] = new JMenuItem("Disconnect from OMEDS",
iconManager.getIcon(IconManager.DISCONNECT_DS));
buttons[WELCOME_MI] = new JMenuItem("Welcome...",
iconManager.getIcon(IconManager.WELCOME));
buttons[HELP_MI] = new JMenuItem("Help Contents",
iconManager.getIcon(IconManager.HELP));
buttons[HOWTO_MI] = new JMenuItem("How To...",
iconManager.getIcon(IconManager.HOW_TO));
String aboutName = "About "+manager.getSoftwareName()+"...";
buttons[UPDATES_MI] = new JMenuItem(aboutName,
iconManager.getIcon(IconManager.SW_UPDATES));
buttons[ABOUT_MI] = new JMenuItem("About OMERO",
IconManager.getOMEIcon());
buttons[COMMENT_MI] = new JMenuItem("Send Feedback...",
iconManager.getIcon(IconManager.COMMENT));
buttons[FORUM_MI] = new JMenuItem("Forum",
iconManager.getIcon(IconManager.FORUM));
buttons[LOG_FILE_MI] = new JMenuItem("Show Log File",
iconManager.getIcon(IconManager.LOG_FILE));
buttons[ACTIVITY_MI] = new JMenuItem("Activities...",
iconManager.getIcon(IconManager.ACTIVITY));
}
/**
* Copies the items from the specified menu and creates a new menu.
*
* @param original The menu to handle.
* @return See above.
*/
private JMenu copyItemsFromMenu(JMenu original)
{
Component[] comps = original.getPopupMenu().getComponents();
JMenu menu = new JMenu();
menu.setText(original.getText());
menu.setToolTipText(original.getToolTipText());
ActionListener[] al = original.getActionListeners();
for (int j = 0; j < al.length; j++)
menu.addActionListener(al[j]);
MenuKeyListener[] mkl = original.getMenuKeyListeners();
for (int j = 0; j < mkl.length; j++)
menu.addMenuKeyListener(mkl[j]);
MenuListener[] ml = original.getMenuListeners();
for (int j = 0; j < ml.length; j++)
menu.addMenuListener(ml[j]);
for (int i = 0; i < comps.length; i++) {
if (comps[i] instanceof JMenu) {
menu.add(copyItemsFromMenu((JMenu) comps[i]));
} else if (comps[i] instanceof JMenuItem) {
menu.add(copyItem((JMenuItem) comps[i]));
} else if (comps[i] instanceof JSeparator) {
menu.add(new JSeparator(JSeparator.HORIZONTAL));
}
}
return menu;
}
/**
* Makes and returns a copy of the specified item.
*
* @param original The item to handle.
* @return See above.
*/
private JMenuItem copyItem(JMenuItem original)
{
JMenuItem item = new JMenuItem(original.getAction());
item.setIcon(original.getIcon());
item.setText(original.getText());
item.setToolTipText(original.getToolTipText());
ActionListener[] al = original.getActionListeners();
for (int j = 0; j < al.length; j++)
item.addActionListener(al[j]);
return item;
}
/**
* Helper method to create the file menu.
*
* @return The file menu.
*/
private JMenu createFileMenu()
{
JMenu file = new JMenu("File");
file.setMnemonic(KeyEvent.VK_F);
return file;
}
/**
* Helper method to create the window menu.
*
* @return The window menu.
*/
private JMenu createWindowMenu()
{
JMenu window = new JMenu("Window");
window.setMnemonic(KeyEvent.VK_W);
window.add(buttons[ACTIVITY_MI]);
return window;
}
/**
* Helper method to create the help menu.
*
* @return The help menu.
*/
private JMenu createHelpMenu()
{
JMenu help = new JMenu("Help");
help.setMnemonic(KeyEvent.VK_H);
JMenuItem i = copyItem((JMenuItem) buttons[HELP_MI]);
if(i.getActionListeners().length==0)
i.addActionListener(manager.getHelpMenuAction(HELP_MI));
help.add(i);
i = copyItem((JMenuItem) buttons[FORUM_MI]);
if(i.getActionListeners().length==0)
i.addActionListener(manager.getHelpMenuAction(FORUM_MI));
help.add(i);
i = copyItem((JMenuItem) buttons[COMMENT_MI]);
if(i.getActionListeners().length==0)
i.addActionListener(manager.getHelpMenuAction(COMMENT_MI));
help.add(i);
help.add(new JSeparator(JSeparator.HORIZONTAL));
i = copyItem((JMenuItem) buttons[LOG_FILE_MI]);
if(i.getActionListeners().length==0)
i.addActionListener(manager.getHelpMenuAction(LOG_FILE_MI));
help.add(i);
i = copyItem((JMenuItem) buttons[UPDATES_MI]);
if(i.getActionListeners().length==0)
i.addActionListener(manager.getHelpMenuAction(UPDATES_MI));
help.add(i);
return help;
}
/**
* Helper method to create the menu bar.
*
* @return The menu bar.
*/
private JMenuBar createMenuBar()
{
createMenuItems();
menus[FILE_MENU] = createFileMenu();
menus[WINDOW_MENU] = createWindowMenu();
menus[HELP_MENU] = createHelpMenu();
JMenuBar bar = new JMenuBar();
for (int i = 0; i < menus.length; ++i)
bar.add(menus[i]);
return bar;
}
/** Helper method to create all buttons for the main toolbar. */
private void createButtons()
{
buttons[CONNECT_BTN] = new JButton(
iconManager.getIcon(IconManager.CONNECT_DS));
buttons[CONNECT_BTN].setToolTipText(
UIUtilities.formatToolTipText("Connect to OMERO."));
buttons[DISCONNECT_BTN] = new JButton(
iconManager.getIcon(IconManager.DISCONNECT_DS));
buttons[DISCONNECT_BTN].setToolTipText(
UIUtilities.formatToolTipText("Disconnect from OMERO."));
buttons[HELP_BTN] = new JButton(iconManager.getIcon(IconManager.HELP));
buttons[HELP_BTN].setToolTipText(
UIUtilities.formatToolTipText("Bring up help contents."));
buttons[EXIT_BTN] = new JButton(iconManager.getIcon(IconManager.EXIT));
buttons[EXIT_BTN].setToolTipText(
UIUtilities.formatToolTipText("Exit the application."));
}
/**
* Helper method to create an empty, floatable toolbar with rollover
* effect for the icon buttons and an etched border.
*
* @return See above.
*/
private JToolBar createToolBar()
{
JToolBar bar = new JToolBar();
bar.setBorder(BorderFactory.createEtchedBorder());
bar.setFloatable(false);
bar.putClientProperty("JToolBar.isRollover", Boolean.valueOf(true));
return bar;
}
/**
* Helper method to create the window's toolbars panel.
* This panel contains all the predefined toolbars (file, connect, and
* help) as well as those specified by {@link TaskBar}.
*
* @return The window's toolbars panel.
*/
private JPanel createToolBarsPanel()
{
createButtons();
JToolBar file = createToolBar(), connect = createToolBar(),
help = createToolBar();
file.add(buttons[EXIT_BTN]);
connect.add(buttons[CONNECT_BTN]);
connect.add(buttons[DISCONNECT_BTN]);
help.add(buttons[HELP_BTN]);
JPanel bars = new JPanel(), outerPanel = new JPanel();
bars.setBorder(null);
bars.setLayout(new BoxLayout(bars, BoxLayout.X_AXIS));
bars.add(file);
bars.add(connect);
bars.add(help);
outerPanel.setBorder(null);
outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.X_AXIS));
outerPanel.add(bars);
outerPanel.add(Box.createRigidArea(new Dimension(100, 16)));
outerPanel.add(Box.createHorizontalGlue());
return outerPanel;
}
/** Builds and lays out the UI. */
private void buildGUI()
{
setIconImage(IconManager.getOMEImageIcon());
originalBar = createMenuBar();
menubars.add(originalBar);
createToolBarsPanel();
}
/**
* Creates and returns a copy of the original menu bar.
*
* @return See above.
*/
private JMenuBar copyMenuBar()
{
JMenuBar bar = new JMenuBar();
JMenu menu, copy;
for (int i = 0; i < originalBar.getMenuCount(); i++) {
menu = originalBar.getMenu(i);
copy = copyItemsFromMenu(menu);
bar.add(copy);
if (menu == menus[WINDOW_MENU])
windowMenus.add(copy);
else if (menu == menus[HELP_MENU])
helpMenus.add(copy);
}
return bar;
}
/**
* Creates a new instance.
*
* @param manager Reference to the manager.
* @param im The {@link IconManager} singleton that we use to retrieve
* the various icons.
*/
TaskBarView(TaskBarManager manager, IconManager im)
{
super(TITLE);
this.manager = manager;
buttons = new AbstractButton[MAX_ID+1];
menus = new JMenu[3];
iconManager = im;
windowMenus = new HashSet<JMenu>();
helpMenus = new HashSet<JMenu>();
menubars = new HashSet<JMenuBar>();
bars = new HashMap<Integer, List<JComponent>>();
buildGUI();
}
/**
* Returns the specified icon button or menu item.
*
* @param id Identifies the button or menu item. Must be one of the
* constants defined by this class.
* @return See above.
*/
AbstractButton getButton(int id)
{
//Don't check this is only meant to be used by the TaskBarManager.
return buttons[id];
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#addToMenu(int, JMenuItem)
*/
public void addToToolBar(int toolBarID, JComponent entry)
{
if (entry == null) return;
//Check if tool bar id is supported
switch (toolBarID) {
case AGENTS:
case ANALYSIS:
break;
default:
return;
}
List<JComponent> list = bars.get(toolBarID);
if (list == null) {
list = new ArrayList<JComponent>();
bars.put(toolBarID, list);
}
list.add(entry);
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#getToolBarEntries(int)
*/
public List<JComponent> getToolBarEntries(int toolBarID)
{
return bars.get(toolBarID);
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#addToMenu(int, JMenuItem)
*/
public void addToMenu(int menuID, JMenuItem entry)
{
if (menuID < 0 || menus.length <= menuID)
throw new IllegalArgumentException("Invalid menu id: "+menuID+".");
if (entry == null)
throw new NullPointerException("No entry");
menus[menuID].add(entry);
Iterator<JMenu> i;
JMenu menu;
if (menuID == WINDOW_MENU) {
i = windowMenus.iterator();
while (i.hasNext()) {
menu = i.next();
if (entry instanceof JMenu)
menu.add(copyItemsFromMenu((JMenu) entry));
else
menu.add(copyItem(entry));
}
} else if (menuID == HELP_MENU) {
i = helpMenus.iterator();
while (i.hasNext()) {
menu = i.next();
if (entry instanceof JMenu)
menu.add(copyItemsFromMenu((JMenu) entry));
else
menu.add(copyItem(entry));
}
}
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#removeFromMenu(int, JMenuItem)
*/
public void removeFromMenu(int menuID, JMenuItem entry)
{
if (menuID < 0 || menus.length <= menuID)
throw new IllegalArgumentException("Invalid menu id: "+menuID+".");
Iterator<JMenu> i;
JMenu menu;
Component[] comps;
Component c;
if (menuID == WINDOW_MENU && entry instanceof JMenu) {
i = windowMenus.iterator();
//tmp solution to remove item from the copy of the windows menu.
while (i.hasNext()) {
menu = i.next();
comps = menu.getPopupMenu().getComponents();
for (int j = 0; j < comps.length; j++) {
c = comps[j];
if (c instanceof JMenu) {
if (((JMenu) c).getText().equals(entry.getText()))
menu.remove(c);
}
}
}
} else if (menuID == HELP_MENU && entry instanceof JMenu) {
i = helpMenus.iterator();
//tmp solution to remove item from the copy of the windows menu.
while (i.hasNext()) {
menu = i.next();
comps = menu.getPopupMenu().getComponents();
for (int j = 0; j < comps.length; j++) {
c = comps[j];
if (c instanceof JMenu) {
if (((JMenu) c).getText() == entry.getText()) {
menu.remove(c);
}
}
}
}
}
menus[menuID].remove(entry);
}
/**
* Overridden so that the task bar is never brought up on screen.
* @see JFrame#setVisible(boolean)
*/
public void setVisible(boolean b) { super.setVisible(false); }
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#getFrame()
*/
public JFrame getFrame() { return this; }
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#getTaskBarMenuBar()
*/
public JMenuBar getTaskBarMenuBar() { return copyMenuBar(); }
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#getMenu(int)
*/
public JMenu getMenu(int menuID)
{
switch (menuID) {
case HELP_MENU: return getHelpMenu();
case WINDOW_MENU: return getWindowsMenu();
case FILE_MENU: return menus[FILE_MENU];
}
return null;
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#getCopyMenuItem(int)
*/
public JMenuItem getCopyMenuItem(int index)
{
switch (index) {
case TaskBar.COMMENT:
return copyItem((JMenuItem) buttons[COMMENT_MI]);
case TaskBar.HELP_CONTENTS:
return copyItem((JMenuItem) buttons[HELP_MI]);
default:
return null;
}
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#login()
*/
public boolean login() { return manager.login(); }
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#openURL(String)
*/
public void openURL(String path)
{
if (CommonsLangUtils.isEmpty(path)) return;
manager.openURL(path);
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#sessionExpired(int)
*/
public void sessionExpired(int index)
{
manager.sessionExpired(index);
}
/**
* Implemented as specified by {@link TaskBar}.
* @see TaskBar#getLibFileRelative(String)
*/
public String getLibFileRelative(String file)
{
return manager.getLibFileRelative(file);
}
}