001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * PreviewPaneUtilities.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.gui.base.internal;
030:
031: import java.awt.Component;
032: import java.awt.FlowLayout;
033: import java.awt.Insets;
034: import java.awt.event.ActionEvent;
035: import java.beans.PropertyChangeEvent;
036: import java.beans.PropertyChangeListener;
037: import java.util.ArrayList;
038: import java.util.Arrays;
039: import java.util.HashMap;
040: import java.util.Iterator;
041: import javax.swing.AbstractAction;
042: import javax.swing.Action;
043: import javax.swing.Icon;
044: import javax.swing.JButton;
045: import javax.swing.JComboBox;
046: import javax.swing.JComponent;
047: import javax.swing.JMenu;
048: import javax.swing.JPanel;
049: import javax.swing.JToolBar;
050:
051: import org.jfree.report.modules.gui.base.PreviewPane;
052: import org.jfree.report.modules.gui.base.actions.ControlAction;
053: import org.jfree.report.modules.gui.base.actions.ControlActionPlugin;
054: import org.jfree.report.modules.gui.base.actions.ExportAction;
055: import org.jfree.report.modules.gui.base.actions.ZoomAction;
056: import org.jfree.report.modules.gui.base.actions.ZoomListActionPlugin;
057: import org.jfree.report.modules.gui.common.DefaultIconTheme;
058: import org.jfree.report.modules.gui.common.IconTheme;
059: import org.jfree.report.modules.gui.commonswing.ActionFactory;
060: import org.jfree.report.modules.gui.commonswing.ActionPlugin;
061: import org.jfree.report.modules.gui.commonswing.ActionPluginMenuComparator;
062: import org.jfree.report.modules.gui.commonswing.DefaultActionFactory;
063: import org.jfree.report.modules.gui.commonswing.ExportActionPlugin;
064: import org.jfree.report.modules.gui.commonswing.SwingCommonModule;
065: import org.jfree.report.modules.gui.commonswing.SwingGuiContext;
066: import org.jfree.report.util.StringUtil;
067: import org.jfree.ui.FloatingButtonEnabler;
068: import org.jfree.ui.KeyedComboBoxModel;
069: import org.jfree.ui.action.ActionButton;
070: import org.jfree.ui.action.ActionMenuItem;
071: import org.jfree.util.Configuration;
072: import org.jfree.util.ObjectUtilities;
073:
074: /**
075: * Creation-Date: 17.11.2006, 15:06:51
076: *
077: * @author Thomas Morgner
078: */
079: public class PreviewPaneUtilities {
080: private static class ReportJobListener implements
081: PropertyChangeListener {
082: private JComponent component;
083: private PreviewPane previewPane;
084:
085: protected ReportJobListener(final JComponent component,
086: final PreviewPane previewPane) {
087: this .previewPane = previewPane;
088: this .component = component;
089: this .component
090: .setEnabled(previewPane.getReportJob() != null);
091: }
092:
093: public void propertyChange(final PropertyChangeEvent evt) {
094: component.setEnabled(previewPane.getReportJob() != null);
095: }
096: }
097:
098: /**
099: * A zoom select action.
100: */
101: private static class ZoomSelectAction extends AbstractAction {
102: private KeyedComboBoxModel source;
103: private PreviewPane pane;
104:
105: /**
106: * Creates a new action.
107: */
108: protected ZoomSelectAction(final KeyedComboBoxModel source,
109: final PreviewPane pane) {
110: this .source = source;
111: this .pane = pane;
112: }
113:
114: /**
115: * Invoked when an action occurs.
116: *
117: * @param e the event.
118: */
119: public void actionPerformed(final ActionEvent e) {
120: final Double selected = (Double) source.getSelectedKey();
121: if (selected != null) {
122: pane.setZoom(selected.doubleValue());
123: }
124: // else
125: // {
126: // Log.warn ("No selected key! : " + pane.getZoom());
127: // }
128: }
129: }
130:
131: private static final String ICON_THEME_CONFIG_KEY = "org.jfree.report.modules.gui.common.IconTheme"; //$NON-NLS-1$
132: private static final String ACTION_FACTORY_CONFIG_KEY = "org.jfree.report.modules.gui.base.ActionFactory"; //$NON-NLS-1$
133: private static final String CATEGORY_PREFIX = "org.jfree.report.modules.gui.swing.category."; //$NON-NLS-1$
134:
135: private PreviewPaneUtilities() {
136: }
137:
138: public static JMenu createMenu(final ActionCategory cat) {
139: final JMenu menu = new JMenu();
140: menu.setText(cat.getDisplayName());
141: final Integer mnemonicKey = cat.getMnemonicKey();
142: if (mnemonicKey != null) {
143: menu.setMnemonic(mnemonicKey.intValue());
144: }
145: final String toolTip = cat.getShortDescription();
146: if (toolTip != null && toolTip.length() > 0) {
147: menu.setToolTipText(toolTip);
148: }
149: return menu;
150: }
151:
152: public static int buildMenu(final JMenu menu,
153: final ActionPlugin[] actions, final PreviewPane pane) {
154: if (actions.length == 0) {
155: return 0;
156: }
157:
158: Arrays.sort(actions, new ActionPluginMenuComparator());
159: boolean separatorPending = false;
160: int count = 0;
161: for (int i = 0; i < actions.length; i++) {
162: final ActionPlugin actionPlugin = actions[i];
163: if (actionPlugin.isAddToMenu() == false) {
164: continue;
165: }
166:
167: if (count > 0 && separatorPending) {
168: menu.addSeparator();
169: separatorPending = false;
170: }
171:
172: if (actionPlugin instanceof ExportActionPlugin) {
173: final ExportActionPlugin exportPlugin = (ExportActionPlugin) actionPlugin;
174: final ExportAction action = new ExportAction(
175: exportPlugin, pane);
176: menu.add(new ActionMenuItem(action));
177: count += 1;
178: } else if (actionPlugin instanceof ControlActionPlugin) {
179: final ControlActionPlugin controlPlugin = (ControlActionPlugin) actionPlugin;
180: final ControlAction action = new ControlAction(
181: controlPlugin, pane);
182: menu.add(new ActionMenuItem(action));
183: count += 1;
184: } else if (actionPlugin instanceof ZoomListActionPlugin) {
185: buildViewMenu(menu, pane);
186: }
187:
188: if (actionPlugin.isSeparated()) {
189: separatorPending = true;
190: }
191:
192: }
193: return count;
194: }
195:
196: private static void buildViewMenu(final JMenu zoom,
197: final PreviewPane pane) {
198: final double[] zoomFactors = pane.getZoomFactors();
199: for (int i = 0; i < zoomFactors.length; i++) {
200: final double factor = zoomFactors[i];
201: zoom.add(new ActionMenuItem(new ZoomAction(factor, pane)));
202: }
203: }
204:
205: public static void addActionsToToolBar(final JToolBar toolBar,
206: final ActionPlugin[] reportActions, final PreviewPane pane) {
207: if (reportActions == null) {
208: return;
209: }
210:
211: boolean separatorPending = false;
212: int count = 0;
213:
214: for (int i = 0; i < reportActions.length; i++) {
215: final ActionPlugin actionPlugin = reportActions[i];
216: if (actionPlugin.isAddToToolbar() == false) {
217: continue;
218: }
219:
220: if (count > 0 && separatorPending) {
221: toolBar.addSeparator();
222: separatorPending = false;
223: }
224:
225: if (actionPlugin instanceof ExportActionPlugin) {
226: final ExportActionPlugin exportPlugin = (ExportActionPlugin) actionPlugin;
227: final ExportAction action = new ExportAction(
228: exportPlugin, pane);
229: toolBar.add(createButton(action, pane
230: .getSwingGuiContext()));
231: count += 1;
232: } else if (actionPlugin instanceof ControlActionPlugin) {
233: final ControlActionPlugin controlPlugin = (ControlActionPlugin) actionPlugin;
234: final ControlAction action = new ControlAction(
235: controlPlugin, pane);
236: toolBar.add(createButton(action, pane
237: .getSwingGuiContext()));
238: count += 1;
239: } else if (actionPlugin instanceof ZoomListActionPlugin) {
240: final JPanel zoomPane = new JPanel();
241: zoomPane.setLayout(new FlowLayout(FlowLayout.LEFT));
242: zoomPane.add(createZoomSelector(pane));
243: toolBar.add(zoomPane);
244: count += 1;
245: }
246:
247: if (actionPlugin.isSeparated()) {
248: separatorPending = true;
249: }
250: }
251: }
252:
253: private static JComboBox createZoomSelector(final PreviewPane pane) {
254: final JComboBox zoomSelect = new JComboBox(pane.getZoomModel());
255: zoomSelect.addActionListener(new ZoomSelectAction(pane
256: .getZoomModel(), pane));
257: zoomSelect.setAlignmentX(Component.RIGHT_ALIGNMENT);
258: pane.addPropertyChangeListener(PreviewPane.PAGINATED_PROPERTY,
259: new ReportJobListener(zoomSelect, pane));
260: return zoomSelect;
261: }
262:
263: /**
264: * Creates a button using the given action properties for the button's
265: * initialisation.
266: *
267: * @param action the action used to set up the button.
268: * @return a button based on the supplied action.
269: */
270: private static JButton createButton(final Action action,
271: final SwingGuiContext swingGuiContext) {
272: final JButton button = new ActionButton(action);
273: boolean needText = true;
274: if (isLargeButtonsEnabled(swingGuiContext)) {
275: final Icon icon = (Icon) action
276: .getValue(SwingCommonModule.LARGE_ICON_PROPERTY);
277: if (icon != null
278: && (icon.getIconHeight() > 1 && icon
279: .getIconHeight() > 1)) {
280: button.setIcon(icon);
281: needText = false;
282: }
283: } else {
284: final Icon icon = (Icon) action.getValue(Action.SMALL_ICON);
285: if (icon != null
286: && (icon.getIconHeight() > 1 && icon
287: .getIconHeight() > 1)) {
288: button.setIcon(icon);
289: needText = false;
290: }
291: }
292:
293: if (needText) {
294: final Object value = action.getValue(Action.NAME);
295: if (value != null) {
296: button.setText(String.valueOf(value));
297: }
298: } else {
299: button.setText(null);
300: button.setMargin(new Insets(0, 0, 0, 0));
301: }
302:
303: FloatingButtonEnabler.getInstance().addButton(button);
304: return button;
305: }
306:
307: private static boolean isLargeButtonsEnabled(
308: final SwingGuiContext swingGuiContext) {
309: final Configuration configuration = swingGuiContext
310: .getConfiguration();
311: if ("true".equals(configuration.getConfigProperty //$NON-NLS-1$
312: ("org.jfree.report.modules.gui.swing.preview.LargeIcons"))) //$NON-NLS-1$
313: {
314: return true;
315: }
316: return false;
317: }
318:
319: public static double getNextZoomOut(final double zoom,
320: final double[] zoomFactors) {
321: if (zoom <= zoomFactors[0]) {
322: return (zoom * 2.0) / 3.0;
323: }
324:
325: final double largestZoom = zoomFactors[zoomFactors.length - 1];
326: if (zoom > largestZoom) {
327: final double linear = (zoom * 2.0) / 3.0;
328: if (linear < largestZoom) {
329: return largestZoom;
330: }
331: return linear;
332: }
333:
334: for (int i = zoomFactors.length - 1; i >= 0; i--) {
335: final double factor = zoomFactors[i];
336: if (factor < zoom) {
337: return factor;
338: }
339: }
340:
341: return (zoom * 2.0) / 3.0;
342: }
343:
344: public static double getNextZoomIn(final double zoom,
345: final double[] zoomFactors) {
346: final double largestZoom = zoomFactors[zoomFactors.length - 1];
347: if (zoom >= largestZoom) {
348: return (zoom * 1.5);
349: }
350:
351: final double smallestZoom = zoomFactors[0];
352: if (zoom < smallestZoom) {
353: final double linear = (zoom * 1.5);
354: if (linear > smallestZoom) {
355: return smallestZoom;
356: }
357: return linear;
358: }
359:
360: for (int i = 0; i < zoomFactors.length; i++) {
361: final double factor = zoomFactors[i];
362: if (factor > zoom) {
363: return factor;
364: }
365: }
366: return (zoom * 1.5);
367: }
368:
369: public static IconTheme createIconTheme(final Configuration config) {
370: final String themeClass = config
371: .getConfigProperty(ICON_THEME_CONFIG_KEY);
372: final Object maybeTheme = ObjectUtilities.loadAndInstantiate(
373: themeClass, PreviewPane.class, IconTheme.class);
374: final IconTheme iconTheme;
375: if (maybeTheme != null) {
376: iconTheme = (IconTheme) maybeTheme;
377: } else {
378: iconTheme = new DefaultIconTheme();
379: }
380: iconTheme.initialize(config);
381: return iconTheme;
382: }
383:
384: public static ActionFactory createActionFactory(
385: final Configuration config) {
386: final String factoryClass = config
387: .getConfigProperty(ACTION_FACTORY_CONFIG_KEY);
388: final Object maybeFactory = ObjectUtilities.loadAndInstantiate(
389: factoryClass, PreviewPane.class, ActionFactory.class);
390: final ActionFactory actionFactory;
391: if (maybeFactory != null) {
392: actionFactory = (ActionFactory) maybeFactory;
393: } else {
394: actionFactory = new DefaultActionFactory();
395: }
396: return actionFactory;
397: }
398:
399: public static CategoryTreeItem[] buildMenuTree(
400: final ActionCategory[] categories) {
401: final CategoryTreeItem[] tree = new CategoryTreeItem[categories.length];
402: for (int i = 0; i < categories.length; i++) {
403: final ActionCategory category = categories[i];
404: tree[i] = new CategoryTreeItem(category);
405: }
406:
407: for (int j = 0; j < tree.length; j++) {
408: final CategoryTreeItem item = tree[j];
409: final String itemName = item.getName();
410: int parentWeight = 0;
411: CategoryTreeItem parent = null;
412: // now for each item, find the best parent item.
413: for (int k = 0; k < tree.length; k++) {
414: if (k == j) {
415: // never add yourself ..
416: continue;
417: }
418: final CategoryTreeItem treeItem = tree[k];
419: final String parentName = treeItem.getName();
420: if (itemName.startsWith(parentName) == false) {
421: continue;
422: }
423: if (parentName.length() > parentWeight) {
424: parent = treeItem;
425: parentWeight = parentName.length();
426: }
427: }
428:
429: item.setParent(parent);
430: }
431:
432: for (int j = 0; j < tree.length; j++) {
433: final CategoryTreeItem item = tree[j];
434: final CategoryTreeItem parent = item.getParent();
435: if (parent != null) {
436: parent.add(item);
437: }
438: }
439: return tree;
440: }
441:
442: public static HashMap loadActions(
443: final SwingGuiContext swingGuiContext) {
444: final HashMap actions = new HashMap();
445:
446: final Configuration configuration = swingGuiContext
447: .getConfiguration();
448: final ActionCategory[] categories = loadCategories(swingGuiContext);
449: final ActionFactory factory = PreviewPaneUtilities
450: .createActionFactory(configuration);
451:
452: for (int i = 0; i < categories.length; i++) {
453: final ActionCategory category = categories[i];
454: actions.put(category, factory.getActions(swingGuiContext,
455: category.getName()));
456: }
457: return actions;
458: }
459:
460: public static ActionCategory[] loadCategories(
461: final SwingGuiContext swingGuiContext) {
462: final ArrayList categories = new ArrayList();
463: final Configuration configuration = swingGuiContext
464: .getConfiguration();
465: final Iterator keys = configuration
466: .findPropertyKeys(CATEGORY_PREFIX);
467: while (keys.hasNext()) {
468: final String enableKey = (String) keys.next();
469: if (enableKey.endsWith(".enabled") == false) //$NON-NLS-1$
470: {
471: continue;
472: }
473:
474: if ("true".equals(configuration.getConfigProperty(enableKey)) == false) //$NON-NLS-1$
475: {
476: continue;
477: }
478:
479: final String base = enableKey.substring(0, enableKey
480: .length()
481: - ".enabled".length()); //$NON-NLS-1$
482: if (base.length() == 0) {
483: continue;
484: }
485:
486: final String categoryKey = base.substring(CATEGORY_PREFIX
487: .length());
488: final String className = configuration
489: .getConfigProperty(base + ".class"); //$NON-NLS-1$
490: ActionCategory actionCategory;
491: if (className == null) {
492: actionCategory = new ActionCategory();
493: } else {
494: actionCategory = (ActionCategory) ObjectUtilities
495: .loadAndInstantiate(className,
496: PreviewPane.class, ActionCategory.class);
497: if (actionCategory == null) {
498: actionCategory = new ActionCategory();
499: }
500: }
501:
502: final String positionText = configuration
503: .getConfigProperty(base + ".position"); //$NON-NLS-1$
504: actionCategory.setPosition(StringUtil.parseInt(
505: positionText, 0));
506: actionCategory.setName(categoryKey);
507: actionCategory.setResourceBase(configuration
508: .getConfigProperty(base + ".resource-base")); //$NON-NLS-1$
509: actionCategory.setResourcePrefix(configuration
510: .getConfigProperty(base + ".resource-prefix")); //$NON-NLS-1$
511: actionCategory.initialize(swingGuiContext);
512: categories.add(actionCategory);
513: }
514:
515: return (ActionCategory[]) categories
516: .toArray(new ActionCategory[categories.size()]);
517: }
518: }
|