/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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 Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.gui.base.internal;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import org.pentaho.reporting.engine.classic.core.modules.gui.base.PreviewPane;
import org.pentaho.reporting.engine.classic.core.modules.gui.base.actions.ControlAction;
import org.pentaho.reporting.engine.classic.core.modules.gui.base.actions.ControlActionPlugin;
import org.pentaho.reporting.engine.classic.core.modules.gui.base.actions.ExportAction;
import org.pentaho.reporting.engine.classic.core.modules.gui.base.actions.ZoomAction;
import org.pentaho.reporting.engine.classic.core.modules.gui.base.actions.ZoomListActionPlugin;
import org.pentaho.reporting.engine.classic.core.modules.gui.common.DefaultIconTheme;
import org.pentaho.reporting.engine.classic.core.modules.gui.common.IconTheme;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.ActionFactory;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.ActionPlugin;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.ActionPluginMenuComparator;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.DefaultActionFactory;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.ExportActionPlugin;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.KeyedComboBoxModel;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.SwingCommonModule;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.SwingGuiContext;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.action.ActionButton;
import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.action.ActionMenuItem;
import org.pentaho.reporting.engine.classic.core.util.StringUtil;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
/**
* Creation-Date: 17.11.2006, 15:06:51
*
* @author Thomas Morgner
*/
public class PreviewPaneUtilities
{
private static final String ICON_THEME_CONFIG_KEY = "org.pentaho.reporting.engine.classic.core.modules.gui.common.IconTheme"; //$NON-NLS-1$
private static final String ACTION_FACTORY_CONFIG_KEY = "org.pentaho.reporting.engine.classic.core.modules.gui.base.ActionFactory"; //$NON-NLS-1$
private static final String CATEGORY_PREFIX = "org.pentaho.reporting.engine.classic.core.modules.gui.swing.category."; //$NON-NLS-1$
private static final ZoomAction[] EMPTY_ZOOM_ACTION = new ZoomAction[0];
private PreviewPaneUtilities()
{
}
public static JMenu createMenu(final ActionCategory cat)
{
final JMenu menu = new JMenu();
menu.setText(cat.getDisplayName());
final Integer mnemonicKey = cat.getMnemonicKey();
if (mnemonicKey != null)
{
menu.setMnemonic(mnemonicKey.intValue());
}
final String toolTip = cat.getShortDescription();
if (toolTip != null && toolTip.length() > 0)
{
menu.setToolTipText(toolTip);
}
return menu;
}
public static ZoomAction[] buildMenu(final JMenu menu,
final ActionPlugin[] actions,
final PreviewPane pane)
{
if (actions.length == 0)
{
return EMPTY_ZOOM_ACTION;
}
ZoomAction[] retval = EMPTY_ZOOM_ACTION;
Arrays.sort(actions, new ActionPluginMenuComparator());
boolean separatorPending = false;
int count = 0;
for (int i = 0; i < actions.length; i++)
{
final ActionPlugin actionPlugin = actions[i];
if (actionPlugin.isAddToMenu() == false)
{
continue;
}
if (count > 0 && separatorPending)
{
menu.addSeparator();
separatorPending = false;
}
if (actionPlugin instanceof ExportActionPlugin)
{
final ExportActionPlugin exportPlugin = (ExportActionPlugin) actionPlugin;
final ExportAction action = new ExportAction(exportPlugin, pane);
menu.add(new ActionMenuItem(action));
count += 1;
}
else if (actionPlugin instanceof ControlActionPlugin)
{
final ControlActionPlugin controlPlugin = (ControlActionPlugin) actionPlugin;
final ControlAction action = new ControlAction(controlPlugin, pane);
menu.add(new ActionMenuItem(action));
count += 1;
}
else if (actionPlugin instanceof ZoomListActionPlugin)
{
// todo: This is a memleak source ..
retval = buildViewMenu(menu, pane);
}
if (actionPlugin.isSeparated())
{
separatorPending = true;
}
}
return retval;
}
private static ZoomAction[] buildViewMenu(final JMenu zoom, final PreviewPane pane)
{
final double[] zoomFactors = pane.getZoomFactors();
final ZoomAction[] zoomActions = new ZoomAction[zoomFactors.length];
for (int i = 0; i < zoomFactors.length; i++)
{
final double factor = zoomFactors[i];
zoomActions[i] = new ZoomAction(factor, pane);
zoom.add(new ActionMenuItem(zoomActions[i]));
}
return zoomActions;
}
public static void addActionsToToolBar(final JToolBar toolBar,
final ActionPlugin[] reportActions,
final JComboBox zoomSelector,
final PreviewPane pane)
{
if (reportActions == null)
{
return;
}
boolean separatorPending = false;
int count = 0;
for (int i = 0; i < reportActions.length; i++)
{
final ActionPlugin actionPlugin = reportActions[i];
if (actionPlugin.isAddToToolbar() == false)
{
continue;
}
if (count > 0 && separatorPending)
{
toolBar.addSeparator();
separatorPending = false;
}
if (actionPlugin instanceof ExportActionPlugin)
{
final ExportActionPlugin exportPlugin = (ExportActionPlugin) actionPlugin;
final ExportAction action = new ExportAction(exportPlugin, pane);
toolBar.add(createButton(action, pane.getSwingGuiContext()));
count += 1;
}
else if (actionPlugin instanceof ControlActionPlugin)
{
final ControlActionPlugin controlPlugin = (ControlActionPlugin) actionPlugin;
final ControlAction action = new ControlAction(controlPlugin, pane);
toolBar.add(createButton(action, pane.getSwingGuiContext()));
count += 1;
}
else if (actionPlugin instanceof ZoomListActionPlugin)
{
final ZoomListActionPlugin zoomListActionPlugin = (ZoomListActionPlugin) actionPlugin;
zoomListActionPlugin.setComponent(zoomSelector);
final JPanel zoomPane = new JPanel();
zoomPane.setLayout(new FlowLayout(FlowLayout.LEFT));
zoomPane.add(zoomSelector);
toolBar.add(zoomPane);
count += 1;
}
if (actionPlugin.isSeparated())
{
separatorPending = true;
}
}
}
/**
* Creates a button using the given action properties for the button's initialisation.
*
* @param action the action used to set up the button.
* @return a button based on the supplied action.
*/
private static JButton createButton(final Action action,
final SwingGuiContext swingGuiContext)
{
final JButton button = new ActionButton(action);
boolean needText = true;
if (isLargeButtonsEnabled(swingGuiContext))
{
final Icon icon = (Icon) action.getValue(SwingCommonModule.LARGE_ICON_PROPERTY);
if (icon != null && (icon.getIconHeight() > 1 && icon.getIconHeight() > 1))
{
button.setIcon(icon);
needText = false;
}
}
else
{
final Icon icon = (Icon) action.getValue(Action.SMALL_ICON);
if (icon != null && (icon.getIconHeight() > 1 && icon.getIconHeight() > 1))
{
button.setIcon(icon);
needText = false;
}
}
if (needText)
{
final Object value = action.getValue(Action.NAME);
if (value != null)
{
button.setText(String.valueOf(value));
}
}
else
{
button.setText(null);
}
final Object value = button.getAction().getValue(Action.ACCELERATOR_KEY);
if (value instanceof KeyStroke)
{
button.unregisterKeyboardAction((KeyStroke) value);
}
return button;
}
private static boolean isLargeButtonsEnabled(final SwingGuiContext swingGuiContext)
{
final Configuration configuration = swingGuiContext.getConfiguration();
if ("true".equals(configuration.getConfigProperty //$NON-NLS-1$
("org.pentaho.reporting.engine.classic.core.modules.gui.base.LargeIcons"))) //$NON-NLS-1$
{
return true;
}
return false;
}
public static double getNextZoomOut(final double zoom,
final double[] zoomFactors)
{
if (zoom <= zoomFactors[0])
{
return (zoom * 2.0) / 3.0;
}
final double largestZoom = zoomFactors[zoomFactors.length - 1];
if (zoom > largestZoom)
{
final double linear = (zoom * 2.0) / 3.0;
if (linear < largestZoom)
{
return largestZoom;
}
return linear;
}
for (int i = zoomFactors.length - 1; i >= 0; i--)
{
final double factor = zoomFactors[i];
if (factor < zoom)
{
return factor;
}
}
return (zoom * 2.0) / 3.0;
}
public static double getNextZoomIn(final double zoom,
final double[] zoomFactors)
{
final double largestZoom = zoomFactors[zoomFactors.length - 1];
if (zoom >= largestZoom)
{
return (zoom * 1.5);
}
final double smallestZoom = zoomFactors[0];
if (zoom < smallestZoom)
{
final double linear = (zoom * 1.5);
if (linear > smallestZoom)
{
return smallestZoom;
}
return linear;
}
for (int i = 0; i < zoomFactors.length; i++)
{
final double factor = zoomFactors[i];
if (factor > zoom)
{
return factor;
}
}
return (zoom * 1.5);
}
public static IconTheme createIconTheme(final Configuration config)
{
final String themeClass = config.getConfigProperty(ICON_THEME_CONFIG_KEY);
final Object maybeTheme = ObjectUtilities.loadAndInstantiate(themeClass, PreviewPane.class, IconTheme.class);
final IconTheme iconTheme;
if (maybeTheme != null)
{
iconTheme = (IconTheme) maybeTheme;
}
else
{
iconTheme = new DefaultIconTheme();
}
iconTheme.initialize(config);
return iconTheme;
}
public static ActionFactory createActionFactory(final Configuration config)
{
final String factoryClass = config.getConfigProperty(ACTION_FACTORY_CONFIG_KEY);
final Object maybeFactory = ObjectUtilities.loadAndInstantiate
(factoryClass, PreviewPane.class, ActionFactory.class);
final ActionFactory actionFactory;
if (maybeFactory != null)
{
actionFactory = (ActionFactory) maybeFactory;
}
else
{
actionFactory = new DefaultActionFactory();
}
return actionFactory;
}
public static CategoryTreeItem[] buildMenuTree(final ActionCategory[] categories)
{
final CategoryTreeItem[] tree = new CategoryTreeItem[categories.length];
for (int i = 0; i < categories.length; i++)
{
final ActionCategory category = categories[i];
tree[i] = new CategoryTreeItem(category);
}
for (int j = 0; j < tree.length; j++)
{
final CategoryTreeItem item = tree[j];
final String itemName = item.getName();
int parentWeight = 0;
CategoryTreeItem parent = null;
// now for each item, find the best parent item.
for (int k = 0; k < tree.length; k++)
{
if (k == j)
{
// never add yourself ..
continue;
}
final CategoryTreeItem treeItem = tree[k];
final String parentName = treeItem.getName();
if (itemName.startsWith(parentName) == false)
{
continue;
}
if (parentName.length() > parentWeight)
{
parent = treeItem;
parentWeight = parentName.length();
}
}
item.setParent(parent);
}
for (int j = 0; j < tree.length; j++)
{
final CategoryTreeItem item = tree[j];
final CategoryTreeItem parent = item.getParent();
if (parent != null)
{
parent.add(item);
}
}
return tree;
}
public static HashMap loadActions(final SwingGuiContext swingGuiContext)
{
final HashMap actions = new HashMap();
final Configuration configuration = swingGuiContext.getConfiguration();
final ActionCategory[] categories = loadCategories(swingGuiContext);
final ActionFactory factory = PreviewPaneUtilities.createActionFactory(configuration);
for (int i = 0; i < categories.length; i++)
{
final ActionCategory category = categories[i];
actions.put(category, factory.getActions(swingGuiContext, category.getName()));
}
return actions;
}
public static ActionCategory[] loadCategories(final SwingGuiContext swingGuiContext)
{
final ArrayList categories = new ArrayList();
final Configuration configuration = swingGuiContext.getConfiguration();
final Iterator keys = configuration.findPropertyKeys(CATEGORY_PREFIX);
while (keys.hasNext())
{
final String enableKey = (String) keys.next();
if (enableKey.endsWith(".enabled") == false) //$NON-NLS-1$
{
continue;
}
if ("true".equals(configuration.getConfigProperty(enableKey)) == false) //$NON-NLS-1$
{
continue;
}
final String base = enableKey.substring(0, enableKey.length() - ".enabled".length()); //$NON-NLS-1$
if (base.length() == 0)
{
continue;
}
final String categoryKey = base.substring(CATEGORY_PREFIX.length());
final String className = configuration.getConfigProperty(base + ".class"); //$NON-NLS-1$
ActionCategory actionCategory;
if (className == null)
{
actionCategory = new ActionCategory();
}
else
{
actionCategory = (ActionCategory) ObjectUtilities.loadAndInstantiate
(className, PreviewPane.class, ActionCategory.class);
if (actionCategory == null)
{
actionCategory = new ActionCategory();
}
}
final String positionText = configuration.getConfigProperty(base + ".position"); //$NON-NLS-1$
actionCategory.setPosition(StringUtil.parseInt(positionText, 0));
actionCategory.setName(categoryKey);
actionCategory.setResourceBase(configuration.getConfigProperty(base + ".resource-base")); //$NON-NLS-1$
actionCategory.setResourcePrefix(configuration.getConfigProperty(base + ".resource-prefix")); //$NON-NLS-1$
actionCategory.initialize(swingGuiContext);
categories.add(actionCategory);
}
return (ActionCategory[]) categories.toArray
(new ActionCategory[categories.size()]);
}
}