/*
* (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.fib.view.widget.browser;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.Icon;
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.fib.controller.FIBController;
import org.openflexo.fib.model.FIBBrowserAction;
import org.openflexo.fib.model.FIBBrowserElement;
import org.openflexo.fib.utils.FIBIconLibrary;
import org.openflexo.fib.view.widget.FIBBrowserWidget;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.swing.ImageButton;
public class FIBBrowserWidgetFooter extends JPanel implements MouseListener, WindowListener {
protected static final Logger logger = Logger.getLogger(FIBBrowserWidgetFooter.class.getPackage().getName());
public static final int MINIMUM_BROWSER_VIEW_WIDTH = 200;
protected FIBBrowserWidget _widget;
// protected JPopupMenu popupMenu = null;
private Map<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>> _addActions;
private Map<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>> _removeActions;
private Map<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>> _otherActions;
private class BrowserButton implements ActionListener {
private Map<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>> actions;
private JButton button;
public BrowserButton(Map<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>> actions, Icon icon, Icon disabledIcon,
Icon pressedIcon) {
super();
this.actions = actions;
button = new ImageButton(icon);
button.setDisabledIcon(disabledIcon);
button.setPressedIcon(pressedIcon);
button.addActionListener(this);
}
public JButton getButton() {
return button;
}
public void handleSelectionChanged(Object selection) {
boolean active = true;
if (selection != null) {
FIBBrowserElement element = elementForObject(selection);
if (element != null) {
Map<FIBBrowserAction, FIBBrowserActionListener> browserActions = actions.get(element);
int activeActionCount = 0;
if (browserActions != null && browserActions.size() > 0) {
for (Entry<FIBBrowserAction, FIBBrowserActionListener> e : browserActions.entrySet()) {
if (e.getValue().isActive(selection)) {
activeActionCount++;
}
}
}
active = activeActionCount > 0;
} else {
active = false;
}
} else {
active = false;
}
button.setEnabled(active);
}
private FIBBrowserElement elementForObject(Object object) {
if (object == null) {
return null;
} else {
return _widget.getComponent().elementForClass(object.getClass());
}
}
@Override
public void actionPerformed(ActionEvent e) {
FIBBrowserElement element = elementForObject(_widget.getSelectedObject());
if (element != null) {
List<FIBBrowserActionListener> listeners = new ArrayList<FIBBrowserActionListener>();
Map<FIBBrowserAction, FIBBrowserActionListener> browserActions = actions.get(element);
if (browserActions != null && browserActions.size() > 0) {
for (Entry<FIBBrowserAction, FIBBrowserActionListener> entry : browserActions.entrySet()) {
if (entry.getValue().isActive(_widget.getSelectedObject())) {
listeners.add(entry.getValue());
}
}
}
if (listeners.size() == 1) {
listeners.get(0).setSelectedObject(_widget.getSelectedObject());
listeners.get(0).actionPerformed(e);
} else if (listeners.size() > 1) {
JPopupMenu popupMenu = new JPopupMenu();
for (FIBBrowserActionListener actionListener : listeners) {
actionListener.setSelectedObject(_widget.getSelectedObject());
JMenuItem menuItem = new JMenuItem(getLocalized(actionListener.getBrowserAction().getName()));
menuItem.addActionListener(actionListener);
popupMenu.add(menuItem);
}
popupMenu.setInvoker(button);
Point location = button.getLocationOnScreen();
location.y -= popupMenu.getPreferredSize().getHeight();
popupMenu.setLocation(location);
popupMenu.setVisible(true);
}
}
}
}
private BrowserButton plusButton;
private BrowserButton minusButton;
private BrowserButton optionsButton;
private JButton filtersButton;
/**
* Stores controls: key is the JButton and value the FIBTableActionListener
*/
// private Hashtable<JButton,FIBTableActionListener> _controls;
public FIBBrowserWidgetFooter(FIBBrowserWidget widget) {
super();
setOpaque(false);
_widget = widget;
initializeActions(widget);
setBorder(BorderFactory.createEmptyBorder());
setLayout(new BorderLayout());
plusButton = new BrowserButton(_addActions, FIBIconLibrary.BROWSER_PLUS_ICON, FIBIconLibrary.BROWSER_PLUS_DISABLED_ICON,
FIBIconLibrary.BROWSER_PLUS_SELECTED_ICON);
minusButton = new BrowserButton(_removeActions, FIBIconLibrary.BROWSER_MINUS_ICON, FIBIconLibrary.BROWSER_MINUS_DISABLED_ICON,
FIBIconLibrary.BROWSER_MINUS_SELECTED_ICON);
optionsButton = new BrowserButton(_otherActions, FIBIconLibrary.BROWSER_OPTIONS_ICON, FIBIconLibrary.BROWSER_OPTIONS_DISABLED_ICON,
FIBIconLibrary.BROWSER_OPTIONS_SELECTED_ICON);
filtersButton = new ImageButton(FIBIconLibrary.BROWSER_FILTERS_ICON);
filtersButton.setDisabledIcon(FIBIconLibrary.BROWSER_FILTERS_DISABLED_ICON);
filtersButton.setPressedIcon(FIBIconLibrary.BROWSER_FILTERS_SELECTED_ICON);
filtersButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Point point = filtersButton.getLocationOnScreen();
JPopupMenu popupMenu = getFiltersPopupMenu();
popupMenu.pack();
point.y -= popupMenu.getHeight();
popupMenu.setInvoker(filtersButton);
popupMenu.setLocation(point);
popupMenu.setVisible(true);
}
});
JPanel plusMinusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
plusMinusPanel.add(plusButton.getButton());
plusMinusPanel.add(minusButton.getButton());
plusMinusPanel.setOpaque(false);
JPanel optionsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
optionsPanel.add(optionsButton.getButton());
optionsPanel.setOpaque(false);
if (hasFilters()) {
optionsPanel.add(filtersButton);
}
add(plusMinusPanel, BorderLayout.WEST);
add(optionsPanel, BorderLayout.EAST);
revalidate();
}
private void initializeActions(FIBBrowserWidget widget) {
_addActions = new LinkedHashMap<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>>();
_removeActions = new LinkedHashMap<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>>();
_otherActions = new LinkedHashMap<FIBBrowserElement, Map<FIBBrowserAction, FIBBrowserActionListener>>();
for (FIBBrowserElement element : widget.getComponent().getElements()) {
Map<FIBBrowserAction, FIBBrowserActionListener> addActions = new LinkedHashMap<FIBBrowserAction, FIBBrowserActionListener>();
Map<FIBBrowserAction, FIBBrowserActionListener> removeActions = new LinkedHashMap<FIBBrowserAction, FIBBrowserActionListener>();
Map<FIBBrowserAction, FIBBrowserActionListener> otherActions = new LinkedHashMap<FIBBrowserAction, FIBBrowserActionListener>();
for (FIBBrowserAction plAction : element.getActions()) {
FIBBrowserActionListener plActionListener = new FIBBrowserActionListener(_widget, plAction);
if (plActionListener.isAddAction()) {
addActions.put(plAction, plActionListener);
} else if (plActionListener.isRemoveAction()) {
removeActions.put(plAction, plActionListener);
} else if (plActionListener.isCustomAction()) {
otherActions.put(plAction, plActionListener);
}
}
_addActions.put(element, addActions);
_removeActions.put(element, removeActions);
_otherActions.put(element, otherActions);
}
}
public void delete() {
if (_widget.getComponent() != null) {
for (FIBBrowserElement element : _widget.getComponent().getElements()) {
Map<FIBBrowserAction, FIBBrowserActionListener> hashtable = _addActions != null ? _addActions.get(element) : null;
if (hashtable != null) {
for (Map.Entry<FIBBrowserAction, FIBBrowserActionListener> e : hashtable.entrySet()) {
e.getValue().delete();
}
}
hashtable = _removeActions != null ? _removeActions.get(element) : null;
if (hashtable != null) {
for (Map.Entry<FIBBrowserAction, FIBBrowserActionListener> e : hashtable.entrySet()) {
e.getValue().delete();
}
}
hashtable = _otherActions != null ? _otherActions.get(element) : null;
if (hashtable != null) {
for (Map.Entry<FIBBrowserAction, FIBBrowserActionListener> e : hashtable.entrySet()) {
e.getValue().delete();
}
}
}
}
_widget = null;
}
public void setFocusedObject(Object object) {
plusButton.handleSelectionChanged(object);
minusButton.handleSelectionChanged(object);
optionsButton.handleSelectionChanged(object);
}
public FIBController getController() {
return _widget.getController();
}
public String getLocalized(String key) {
return FlexoLocalization.localizedForKey(getController().getLocalizerForComponent(_widget.getComponent()), key);
}
private JPopupMenu filtersPopupMenu;
protected JPopupMenu getFiltersPopupMenu() {
if (filtersPopupMenu == null) {
filtersPopupMenu = makeFiltersPopupMenu();
}
for (Component menuItem : filtersPopupMenu.getComponents()) {
if (menuItem instanceof FIBBrowserFilterMenuItem) {
((FIBBrowserFilterMenuItem) menuItem).update();
}
}
return filtersPopupMenu;
}
private boolean hasFilters() {
for (FIBBrowserElement el : _widget.getComponent().getElements()) {
if (el.getFiltered()) {
return true;
}
}
return false;
}
private JPopupMenu makeFiltersPopupMenu() {
JPopupMenu returned = new JPopupMenu() {
@Override
public void setVisible(boolean b) {
if (b && !isVisible()) {
addPopupClosers(getWindow(FIBBrowserWidgetFooter.this));
} else if (!b && isVisible()) {
removePopupClosers(getWindow(FIBBrowserWidgetFooter.this));
}
super.setVisible(b);
if (!b) {
filtersButton.setIcon(FIBIconLibrary.BROWSER_FILTERS_ICON);
}
}
@Override
public void menuSelectionChanged(boolean isIncluded) {
super.menuSelectionChanged(true);
}
};
for (Map.Entry<FIBBrowserElement, FIBBrowserElementType> e : _widget.getBrowserModel().getElementTypes().entrySet()) {
if (e.getKey().getFiltered()) {
returned.add(new FIBBrowserFilterMenuItem(e.getValue()));
}
}
returned.addMenuKeyListener(new MenuKeyListener() {
@Override
public void menuKeyPressed(MenuKeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE && filtersPopupMenu != null && filtersPopupMenu.isVisible()) {
closeFiltersPopupMenu();
}
}
@Override
public void menuKeyReleased(MenuKeyEvent e) {
}
@Override
public void menuKeyTyped(MenuKeyEvent e) {
}
});
return returned;
}
protected void closeFiltersPopupMenu() {
logger.info("closeFiltersPopupMenu()");
if (filtersPopupMenu != null && filtersPopupMenu.isVisible()) {
filtersPopupMenu.setVisible(false);
}
filtersPopupMenu = null;
}
/**
* 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;
}
/**
* 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 != filtersPopupMenu && 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 != filtersPopupMenu && c != null) {
c.removeMouseListener(this);
for (int i = 0; i < c.getComponents().length; i++) {
removePopupClosers((Container) c.getComponents()[i]);
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() != filtersPopupMenu && e.getSource() != filtersButton) {
closeFiltersPopupMenu();
}
}
@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) {
closeFiltersPopupMenu();
}
@Override
public void windowDeactivated(WindowEvent e) {
closeFiltersPopupMenu();
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
closeFiltersPopupMenu();
}
@Override
public void windowOpened(WindowEvent e) {
}
}