/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.components.browser.view; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.util.Enumeration; import java.util.List; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.event.MenuKeyEvent; import javax.swing.event.MenuKeyListener; import org.openflexo.FlexoCst; import org.openflexo.ch.FCH; import org.openflexo.components.browser.BrowserElement; import org.openflexo.components.browser.CustomBrowserFilter; import org.openflexo.components.browser.ElementTypeBrowserFilter; import org.openflexo.foundation.FlexoEditor; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.action.FlexoAction; import org.openflexo.foundation.action.FlexoActionType; import org.openflexo.icon.IconLibrary; import org.openflexo.selection.ContextualMenuManager; import org.openflexo.swing.ImageButton; public class BrowserFooter extends JPanel implements MouseListener, WindowListener { protected static final Logger logger = Logger.getLogger(BrowserFooter.class.getPackage().getName()); protected BrowserView _browserView; protected JButton plusButton; protected JButton minusButton; protected JButton optionsButton; protected JPopupMenu popupMenu = null; public BrowserFooter(BrowserView browserView) { super(); _browserView = browserView; setBorder(BorderFactory.createEmptyBorder()); setLayout(new BorderLayout()); // setPreferredSize(new // Dimension(FlexoCst.MINIMUM_BROWSER_VIEW_WIDTH,FlexoCst.MINIMUM_BROWSER_CONTROL_PANEL_HEIGHT)); setPreferredSize(new Dimension(FlexoCst.MINIMUM_BROWSER_VIEW_WIDTH, 20)); JPanel plusMinusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); plusMinusPanel.setBorder(BorderFactory.createEmptyBorder()); plusButton = new ImageButton(IconLibrary.BROWSER_PLUS_ICON); plusButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!hasMultiplePlusActions()) { BrowserFooter.this.<FlexoAction, FlexoModelObject, FlexoModelObject> plusPressed(e); plusButton.setIcon(IconLibrary.BROWSER_PLUS_ICON); } } }); plusButton.setDisabledIcon(IconLibrary.BROWSER_PLUS_DISABLED_ICON); // plusButton.setSelectedIcon(FlexoCst.BROWSER_PLUS_SELECTED_ICON); plusButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent mouseEvent) { if (plusButton.isEnabled()) { plusButton.setIcon(IconLibrary.BROWSER_PLUS_SELECTED_ICON); } if (hasMultiplePlusActions()) { BrowserFooter.this.<FlexoAction, FlexoModelObject, FlexoModelObject> getPlusActionMenu().show( mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); plusButton.setIcon(IconLibrary.BROWSER_PLUS_ICON); } } @Override public void mouseReleased(MouseEvent mouseEvent) { if (plusButton.isEnabled()) { plusButton.setIcon(IconLibrary.BROWSER_PLUS_ICON); } if (hasMultiplePlusActions()) { BrowserFooter.this.<FlexoAction, FlexoModelObject, FlexoModelObject> getPlusActionMenu().show( mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); } } }); FCH.setHelpItem(plusButton, "plus"); minusButton = new ImageButton(IconLibrary.BROWSER_MINUS_ICON); minusButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Multiple DELETE ACTION popup menu not implemented yet // If you need it, do the same as for ADD ACTION BrowserFooter.this.<FlexoAction, FlexoModelObject, FlexoModelObject> minusPressed(e); minusButton.setIcon(IconLibrary.BROWSER_MINUS_ICON); } }); minusButton.setDisabledIcon(IconLibrary.BROWSER_MINUS_DISABLED_ICON); // minusButton.setSelectedIcon(FlexoCst.BROWSER_MINUS_SELECTED_ICON); minusButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent mouseEvent) { if (minusButton.isEnabled()) { minusButton.setIcon(IconLibrary.BROWSER_MINUS_SELECTED_ICON); } } @Override public void mouseReleased(MouseEvent mouseEvent) { if (minusButton.isEnabled()) { minusButton.setIcon(IconLibrary.BROWSER_MINUS_ICON); } } }); FCH.setHelpItem(minusButton, "minus"); plusMinusPanel.add(plusButton); plusMinusPanel.add(minusButton); add(plusMinusPanel, BorderLayout.WEST); optionsButton = new ImageButton(IconLibrary.BROWSER_OPTIONS_ICON); if (browserView.getBrowser().showOptionsButton()) { optionsButton.setDisabledIcon(IconLibrary.BROWSER_OPTIONS_DISABLED_ICON); add(optionsButton, BorderLayout.EAST); optionsButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent mouseEvent) { if (hasFilters()) { optionsButton.setIcon(IconLibrary.BROWSER_OPTIONS_SELECTED_ICON); getPopupMenu().show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); } } @Override public void mouseReleased(MouseEvent mouseEvent) { if (hasFilters() && (popupMenu == null || !popupMenu.isVisible())) { getPopupMenu().show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); getPopupMenu().grabFocus(); } } }); // if (browserView.getBrowser().getOptionalFilters().size() == 0) optionsButton.setEnabled(hasFilters()); FCH.setHelpItem(optionsButton, "options"); if (logger.isLoggable(Level.FINE)) { logger.fine("Browser " + browserView.getBrowser() + " has " + browserView.getBrowser().getConfigurableElementTypeFilters().size() + " filters"); } } handleSelectionCleared(); validate(); } public void handleOptionalFilterAdded() { optionsButton.setEnabled(hasFilters()); closePopup(); } protected boolean hasFilters() { return _browserView.getBrowser().getConfigurableElementTypeFilters().size() + _browserView.getBrowser().getCustomFilters().size() > 0; } /* protected void elementTypeFilterChanged() { if (popupMenu != null) { popupMenu.setVisible(false); } popupMenu = null; optionsButton.setEnabled(hasFilters()); }*/ protected JPopupMenu getPopupMenu() { if (popupMenu == null) { popupMenu = makePopupMenu(); } for (Component menuItem : popupMenu.getComponents()) { if (menuItem instanceof BrowserFilterMenuItem) { ((BrowserFilterMenuItem) menuItem).update(); } } return popupMenu; } private JPopupMenu makePopupMenu() { if (logger.isLoggable(Level.FINE)) { logger.fine("Browser " + _browserView.getBrowser() + " has now " + (_browserView.getBrowser().getConfigurableElementTypeFilters().size() + _browserView.getBrowser().getCustomFilters() .size()) + " filters"); } JPopupMenu returned = new JPopupMenu() { @Override public void setVisible(boolean b) { if (b && !isVisible()) { addPopupClosers(getWindow(BrowserFooter.this)); } else if (!b && isVisible()) { removePopupClosers(getWindow(BrowserFooter.this)); } super.setVisible(b); if (!b) { optionsButton.setIcon(IconLibrary.BROWSER_OPTIONS_ICON); } } @Override public void menuSelectionChanged(boolean isIncluded) { super.menuSelectionChanged(true); } }; if (_browserView.getBrowser().getCustomFilters().size() > 0) { for (CustomBrowserFilter filter : _browserView.getBrowser().getCustomFilters()) { returned.add(new BrowserFilterMenuItem(_browserView.getBrowser(), filter)); } } if (_browserView.getBrowser().getConfigurableElementTypeFilters().size() > 0) { if (_browserView.getBrowser().getCustomFilters().size() > 0) { returned.addSeparator(); } for (ElementTypeBrowserFilter filter : _browserView.getBrowser().getConfigurableElementTypeFilters()) { returned.add(new BrowserFilterMenuItem(_browserView.getBrowser(), filter)); } } returned.addMenuKeyListener(new MenuKeyListener() { @Override public void menuKeyPressed(MenuKeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE && popupMenu != null && popupMenu.isVisible()) { closePopup(); } } @Override public void menuKeyReleased(MenuKeyEvent e) { } @Override public void menuKeyTyped(MenuKeyEvent e) { } }); return returned; } protected void closePopup() { if (popupMenu != null && popupMenu.isVisible()) { popupMenu.setVisible(false); } popupMenu = null; } /** * Added mouselistners to each component of the root container c, exept this button, and the calendar popup, because mouseclicks in them * are not supposed to clsoe the popup. * * @param c * the root container */ protected void addPopupClosers(Container c) { if (c == getWindow(this) && c != null) { if (logger.isLoggable(Level.FINE)) { logger.finer("addPopupClosers"); } ((Window) c).addWindowListener(this); } if (c != popupMenu && c != null) { c.addMouseListener(this); for (int i = 0; i < c.getComponents().length; i++) { addPopupClosers((Container) c.getComponents()[i]); } } } /** * Added mouselistners to each component of the root container c, exept this button, and the calendar popup, because mouseclicks in them * are not supposed to clsoe the popup. * * @param c * the root container */ protected void removePopupClosers(Container c) { if (c instanceof Window) { if (logger.isLoggable(Level.FINE)) { logger.finer("removePopupClosers"); } ((Window) c).removeWindowListener(this); } if (c != popupMenu && c != null) { c.removeMouseListener(this); for (int i = 0; i < c.getComponents().length; i++) { removePopupClosers((Container) c.getComponents()[i]); } } } /** * Copied directly from BasicPopupMenuUI - PK 06-08-04 * * @param c * componenet of which we want to find the owning window * @return the window that is contins after plenty of leves the component c */ protected Window getWindow(Component c) { Component w = c; while (!(w instanceof Window) && w != null) { w = w.getParent(); } return (Window) w; } protected void handleSelectionChanged() { FlexoModelObject focusedObject = getFocusedObject(); Vector globalSelection = buildGlobalSelection(); plusButton.setEnabled(_browserView.getController() != null && focusedObject != null && getActionTypesWithAddType(focusedObject, (Vector) null).size() > 0); minusButton.setEnabled(_browserView.getController() != null && focusedObject != null && getActionTypesWithDeleteType(focusedObject, globalSelection).size() > 0); plusActionMenuNeedsRecomputed = true; } private <A2 extends FlexoAction<A2, T1, T2>, T1 extends FlexoModelObject, T2 extends FlexoModelObject> List<FlexoActionType<A2, T1, T2>> getActionTypesWithAddType( FlexoModelObject focusedObject, Vector<? extends FlexoModelObject> globalSelection) { return _browserView.getContextualMenuManager().getActionTypesWithAddType(focusedObject, globalSelection); } private <A extends FlexoAction<A, T1, T2>, T1 extends FlexoModelObject, T2 extends FlexoModelObject> List<FlexoActionType<A, T1, T2>> getActionTypesWithDeleteType( FlexoModelObject focusedObject, Vector<? extends FlexoModelObject> globalSelection) { return _browserView.getContextualMenuManager().getActionTypesWithDeleteType(focusedObject, globalSelection); } protected void handleSelectionCleared() { plusButton.setEnabled(false); minusButton.setEnabled(false); plusActionMenuNeedsRecomputed = true; } <A extends FlexoAction<A, T1, T2>, T1 extends FlexoModelObject, T2 extends FlexoModelObject> void plusPressed(ActionEvent e) { if (logger.isLoggable(Level.FINE)) { logger.fine("Pressed on plus"); } FlexoActionType<A, T1, T2> actionType = this.<A, T1, T2> getActionTypesWithAddType(getFocusedObject(), (Vector<FlexoModelObject>) null).get(0); if (getEditor() != null) { getEditor().performActionType(actionType, (T1) getFocusedObject(), (Vector<T2>) getGlobalSelection(), e); } else if (logger.isLoggable(Level.WARNING)) { logger.warning("No editor available. Ignoring action " + actionType); } } protected FlexoEditor getEditor() { return _browserView.getEditor(); } boolean hasMultiplePlusActions() { if (getFocusedObject() == null) { return false; } return getActionTypesWithAddType(getFocusedObject(), (Vector) null).size() > 1; } private JPopupMenu plusActionMenu = null; private boolean plusActionMenuNeedsRecomputed = true; <A extends FlexoAction<A, T1, T2>, T1 extends FlexoModelObject, T2 extends FlexoModelObject> JPopupMenu getPlusActionMenu() { if (_browserView.getContextualMenuManager() != null) { return _browserView.getContextualMenuManager().makePopupMenu(getFocusedObject(), new ContextualMenuManager.MenuFilter() { @Override public boolean acceptActionType(FlexoActionType<?, ?, ?> actionType) { return actionType.getActionCategory() == FlexoActionType.ADD_ACTION_TYPE; } }); } if (plusActionMenuNeedsRecomputed) { plusActionMenu = new JPopupMenu(); if (logger.isLoggable(Level.FINE)) { logger.fine("Build plus menu"); } for (final FlexoActionType<A, T1, T2> action : this.<A, T1, T2> getActionTypesWithAddType(getFocusedObject(), getGlobalSelection())) { JMenuItem menuItem = new JMenuItem(action.getLocalizedName()); if (getEditor().getEnabledIconFor(action) != null) { menuItem.setIcon(getEditor().getEnabledIconFor(action)); } if (getEditor().getDisabledIconFor(action) != null) { menuItem.setDisabledIcon(getEditor().getDisabledIconFor(action)); } menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { getEditor().performActionType(action, (T1) getFocusedObject(), (Vector<T2>) getGlobalSelection(), e); } }); plusActionMenu.add(menuItem); } plusActionMenuNeedsRecomputed = false; } return plusActionMenu; } <A extends FlexoAction<A, T1, T2>, T1 extends FlexoModelObject, T2 extends FlexoModelObject> void minusPressed(ActionEvent e) { if (logger.isLoggable(Level.FINE)) { logger.fine("Pressed on plus"); } Vector globalSelection = buildGlobalSelection(); FlexoActionType<A, T1, T2> actionType = this.<A, T1, T2> getActionTypesWithDeleteType(getFocusedObject(), globalSelection).get(0); if (getEditor() != null) { getEditor().performActionType(actionType, (T1) getFocusedObject(), (Vector<T2>) getGlobalSelection(), e); } else if (logger.isLoggable(Level.WARNING)) { logger.warning("No editor available. Ignoring action " + actionType); } } /* * private boolean hasMultipleMinusActions() { Vector globalSelection = * buildGlobalSelection(); return * getActionTypesWithDeleteType(getFocusedObject(),globalSelection).size() > * 1; } */ /** * Returns focused object, considering focused object is the last selected object. If none object are selected, return null. */ public FlexoModelObject getFocusedObject() { return _browserView.getFocusedObject(); } public Vector<FlexoModelObject> getGlobalSelection() { return buildGlobalSelection(); } private Vector<FlexoModelObject> buildGlobalSelection() { Vector<FlexoModelObject> returned = new Vector<FlexoModelObject>(); Vector<BrowserElement> elements = _browserView.getSelectedElements(); for (Enumeration<BrowserElement> en = elements.elements(); en.hasMoreElements();) { BrowserElement next = en.nextElement(); returned.add(next.getObject()); } return returned; } @Override public void mouseClicked(MouseEvent e) { if (e.getSource() != popupMenu && e.getSource() != optionsButton) { closePopup(); } } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void windowActivated(WindowEvent e) { } @Override public void windowClosed(WindowEvent e) { } @Override public void windowClosing(WindowEvent e) { closePopup(); } @Override public void windowDeactivated(WindowEvent e) { closePopup(); } @Override public void windowDeiconified(WindowEvent e) { } @Override public void windowIconified(WindowEvent e) { closePopup(); } @Override public void windowOpened(WindowEvent e) { } }