Source for org.jfree.report.modules.gui.swing.preview.PreviewPaneUtilities

   1: /**
   2:  * ========================================
   3:  * JFreeReport : a free Java report library
   4:  * ========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/
   7:  *
   8:  * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  * ------------
  26:  * $Id: PreviewPaneUtilities.java 3525 2007-10-16 11:43:48Z tmorgner $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: 
  32: package org.jfree.report.modules.gui.swing.preview;
  33: 
  34: import java.awt.Component;
  35: import java.awt.FlowLayout;
  36: import java.awt.Insets;
  37: import java.awt.event.ActionEvent;
  38: import java.util.ArrayList;
  39: import java.util.Arrays;
  40: import java.util.HashMap;
  41: import java.util.Iterator;
  42: import javax.swing.AbstractAction;
  43: import javax.swing.Action;
  44: import javax.swing.Icon;
  45: import javax.swing.JButton;
  46: import javax.swing.JComboBox;
  47: import javax.swing.JMenu;
  48: import javax.swing.JPanel;
  49: import javax.swing.JToolBar;
  50: 
  51: import org.jfree.report.modules.gui.common.DefaultIconTheme;
  52: import org.jfree.report.modules.gui.common.IconTheme;
  53: import org.jfree.report.modules.gui.swing.common.ActionFactory;
  54: import org.jfree.report.modules.gui.swing.common.ActionPlugin;
  55: import org.jfree.report.modules.gui.swing.common.ActionPluginMenuComparator;
  56: import org.jfree.report.modules.gui.swing.common.DefaultActionFactory;
  57: import org.jfree.report.modules.gui.swing.common.ExportActionPlugin;
  58: import org.jfree.report.modules.gui.swing.common.SwingCommonModule;
  59: import org.jfree.report.modules.gui.swing.common.SwingGuiContext;
  60: import org.jfree.report.modules.gui.swing.preview.actions.ControlAction;
  61: import org.jfree.report.modules.gui.swing.preview.actions.ControlActionPlugin;
  62: import org.jfree.report.modules.gui.swing.preview.actions.ExportAction;
  63: import org.jfree.report.modules.gui.swing.preview.actions.ZoomAction;
  64: import org.jfree.report.modules.gui.swing.preview.actions.ZoomListActionPlugin;
  65: import org.jfree.report.util.TextUtilities;
  66: import org.jfree.ui.FloatingButtonEnabler;
  67: import org.jfree.ui.KeyedComboBoxModel;
  68: import org.jfree.ui.action.ActionButton;
  69: import org.jfree.ui.action.ActionMenuItem;
  70: import org.jfree.util.Configuration;
  71: import org.jfree.util.Log;
  72: import org.jfree.util.ObjectUtilities;
  73: 
  74: /**
  75:  * Creation-Date: 17.11.2006, 15:06:51
  76:  *
  77:  * @author Thomas Morgner
  78:  */
  79: public class PreviewPaneUtilities
  80: {
  81:   /**
  82:    * A zoom select action.
  83:    */
  84:   private static class ZoomSelectAction extends AbstractAction
  85:   {
  86:     private KeyedComboBoxModel source;
  87:     private PreviewPane pane;
  88: 
  89:     /**
  90:      * Creates a new action.
  91:      */
  92:     private ZoomSelectAction(final KeyedComboBoxModel source,
  93:                             final PreviewPane pane)
  94:     {
  95:       this.source = source;
  96:       this.pane = pane;
  97:     }
  98: 
  99:     /**
 100:      * Invoked when an action occurs.
 101:      *
 102:      * @param e the event.
 103:      */
 104:     public void actionPerformed(final ActionEvent e)
 105:     {
 106:       final Double selected = (Double) source.getSelectedKey();
 107:       if (selected != null)
 108:       {
 109:         pane.setZoom(selected.doubleValue());
 110:       }
 111:       else
 112:       {
 113:         Log.warn ("No selected key! : " + pane.getZoom());
 114:       }
 115:     }
 116:   }
 117: 
 118:   private static final String ICON_THEME_CONFIG_KEY = "org.jfree.report.modules.gui.common.IconTheme";
 119:   private static final String ACTION_FACTORY_CONFIG_KEY = "org.jfree.report.modules.gui.swing.preview.ActionFactory";
 120:   private static final String CATEGORY_PREFIX = "org.jfree.report.modules.gui.swing.category.";
 121: 
 122:   private PreviewPaneUtilities()
 123:   {
 124:   }
 125: 
 126:   public static JMenu createMenu(final ActionCategory cat)
 127:   {
 128:     final JMenu menu = new JMenu();
 129:     menu.setText(cat.getDisplayName());
 130:     final Integer mnemonicKey = cat.getMnemonicKey();
 131:     if (mnemonicKey != null)
 132:     {
 133:       menu.setMnemonic(mnemonicKey.intValue());
 134:     }
 135:     final String toolTip = cat.getShortDescription();
 136:     if (toolTip != null && toolTip.length() > 0)
 137:     {
 138:       menu.setToolTipText(toolTip);
 139:     }
 140:     return menu;
 141:   }
 142: 
 143: 
 144:   public static int buildMenu(final JMenu menu,
 145:                               final ActionPlugin[] actions,
 146:                               final PreviewPane pane)
 147:   {
 148:     if (actions.length == 0)
 149:     {
 150:       return 0;
 151:     }
 152: 
 153:     Arrays.sort(actions, new ActionPluginMenuComparator());
 154:     boolean separatorPending = false;
 155:     int count = 0;
 156:     for (int i = 0; i < actions.length; i++)
 157:     {
 158:       final ActionPlugin actionPlugin = actions[i];
 159:       if (actionPlugin.isAddToMenu() == false)
 160:       {
 161:         continue;
 162:       }
 163: 
 164:       if (count > 0 && separatorPending)
 165:       {
 166:         menu.addSeparator();
 167:         separatorPending = false;
 168:       }
 169: 
 170:       if (actionPlugin instanceof ExportActionPlugin)
 171:       {
 172:         final ExportActionPlugin exportPlugin = (ExportActionPlugin) actionPlugin;
 173:         final ExportAction action = new ExportAction(exportPlugin, pane);
 174:         menu.add(new ActionMenuItem(action));
 175:         count += 1;
 176:       }
 177:       else if (actionPlugin instanceof ControlActionPlugin)
 178:       {
 179:         final ControlActionPlugin controlPlugin = (ControlActionPlugin) actionPlugin;
 180:         final ControlAction action = new ControlAction(controlPlugin, pane);
 181:         menu.add(new ActionMenuItem(action));
 182:         count += 1;
 183:       }
 184:       else if (actionPlugin instanceof ZoomListActionPlugin)
 185:       {
 186:         buildViewMenu(menu, pane);
 187:       }
 188: 
 189:       if (actionPlugin.isSeparated())
 190:       {
 191:         separatorPending = true;
 192:       }
 193: 
 194:     }
 195:     return count;
 196:   }
 197: 
 198:   private static void buildViewMenu(final JMenu zoom, final PreviewPane pane)
 199:   {
 200:     final double[] zoomFactors = pane.getZoomFactors();
 201:     for (int i = 0; i < zoomFactors.length; i++)
 202:     {
 203:       final double factor = zoomFactors[i];
 204:       zoom.add(new ActionMenuItem(new ZoomAction(factor, pane)));
 205:     }
 206:   }
 207: 
 208:   public static void addActionsToToolBar(final JToolBar toolBar,
 209:                                          final ActionPlugin[] reportActions,
 210:                                          final PreviewPane pane)
 211:   {
 212:     if (reportActions == null)
 213:     {
 214:       return;
 215:     }
 216: 
 217:     boolean separatorPending = false;
 218:     int count = 0;
 219: 
 220:     for (int i = 0; i < reportActions.length; i++)
 221:     {
 222:       final ActionPlugin actionPlugin = reportActions[i];
 223:       if (actionPlugin.isAddToToolbar() == false)
 224:       {
 225:         continue;
 226:       }
 227: 
 228:       if (count > 0 && separatorPending)
 229:       {
 230:         toolBar.addSeparator();
 231:         separatorPending = false;
 232:       }
 233: 
 234:       if (actionPlugin instanceof ExportActionPlugin)
 235:       {
 236:         final ExportActionPlugin exportPlugin = (ExportActionPlugin) actionPlugin;
 237:         final ExportAction action = new ExportAction(exportPlugin, pane);
 238:         toolBar.add(createButton(action, pane.getSwingGuiContext()));
 239:         count += 1;
 240:       }
 241:       else if (actionPlugin instanceof ControlActionPlugin)
 242:       {
 243:         final ControlActionPlugin controlPlugin = (ControlActionPlugin) actionPlugin;
 244:         final ControlAction action = new ControlAction(controlPlugin, pane);
 245:         toolBar.add(createButton(action, pane.getSwingGuiContext()));
 246:         count += 1;
 247:       }
 248:       else if (actionPlugin instanceof ZoomListActionPlugin)
 249:       {
 250:         final JPanel zoomPane = new JPanel();
 251:         zoomPane.setLayout(new FlowLayout(FlowLayout.LEFT));
 252:         zoomPane.add(createZoomSelector(pane));
 253:         toolBar.add(zoomPane);
 254:         count += 1;
 255:       }
 256: 
 257:       if (actionPlugin.isSeparated())
 258:       {
 259:         separatorPending = true;
 260:       }
 261:     }
 262:   }
 263: 
 264: 
 265:   private static JComboBox createZoomSelector(final PreviewPane pane)
 266:   {
 267:     final JComboBox zoomSelect = new JComboBox(pane.getZoomModel());
 268:     zoomSelect.addActionListener(new ZoomSelectAction(pane.getZoomModel(), pane));
 269:     zoomSelect.setAlignmentX(Component.RIGHT_ALIGNMENT);
 270:     return zoomSelect;
 271:   }
 272: 
 273:   /**
 274:    * Creates a button using the given action properties for the button's
 275:    * initialisation.
 276:    *
 277:    * @param action the action used to set up the button.
 278:    * @return a button based on the supplied action.
 279:    */
 280:   private static JButton createButton(final Action action,
 281:                                       final SwingGuiContext swingGuiContext)
 282:   {
 283:     final JButton button = new ActionButton(action);
 284:     boolean needText = true;
 285:     if (isLargeButtonsEnabled(swingGuiContext))
 286:     {
 287:       final Icon icon = (Icon) action.getValue(SwingCommonModule.LARGE_ICON_PROPERTY);
 288:       if (icon != null && (icon.getIconHeight() > 1 && icon.getIconHeight() > 1))
 289:       {
 290:         button.setIcon(icon);
 291:         needText = false;
 292:       }
 293:     }
 294:     else
 295:     {
 296:       final Icon icon = (Icon) action.getValue(Action.SMALL_ICON);
 297:       if (icon != null && (icon.getIconHeight() > 1 && icon.getIconHeight() > 1))
 298:       {
 299:         button.setIcon(icon);
 300:         needText = false;
 301:       }
 302:     }
 303: 
 304:     if (needText)
 305:     {
 306:       final Object value = action.getValue(Action.NAME);
 307:       if (value != null)
 308:       {
 309:         button.setText(String.valueOf(value));
 310:       }
 311:     }
 312:     else
 313:     {
 314:       button.setText(null);
 315:       button.setMargin(new Insets(0, 0, 0, 0));
 316:     }
 317: 
 318:     FloatingButtonEnabler.getInstance().addButton(button);
 319:     return button;
 320:   }
 321: 
 322:   private static boolean isLargeButtonsEnabled(final SwingGuiContext swingGuiContext)
 323:   {
 324:     final Configuration configuration = swingGuiContext.getConfiguration();
 325:     if ("true".equals(configuration.getConfigProperty
 326:         ("org.jfree.report.modules.gui.swing.preview.LargeIcons")))
 327:     {
 328:       return true;
 329:     }
 330:     return false;
 331:   }
 332: 
 333: 
 334:   public static double getNextZoomOut(final double zoom,
 335:                                       final double[] zoomFactors)
 336:   {
 337:     if (zoom <= zoomFactors[0])
 338:     {
 339:       return (zoom * 2.0) / 3.0;
 340:     }
 341: 
 342:     final double largestZoom = zoomFactors[zoomFactors.length - 1];
 343:     if (zoom > largestZoom)
 344:     {
 345:       final double linear = (zoom * 2.0) / 3.0;
 346:       if (linear < largestZoom)
 347:       {
 348:         return largestZoom;
 349:       }
 350:       return linear;
 351:     }
 352: 
 353:     for (int i = zoomFactors.length - 1; i >= 0; i--)
 354:     {
 355:       final double factor = zoomFactors[i];
 356:       if (factor < zoom)
 357:       {
 358:         return factor;
 359:       }
 360:     }
 361: 
 362:     return (zoom * 2.0) / 3.0;
 363:   }
 364: 
 365:   public static double getNextZoomIn(final double zoom,
 366:                                      final double[] zoomFactors)
 367:   {
 368:     final double largestZoom = zoomFactors[zoomFactors.length - 1];
 369:     if (zoom >= largestZoom)
 370:     {
 371:       return (zoom * 1.5);
 372:     }
 373: 
 374:     final double smallestZoom = zoomFactors[0];
 375:     if (zoom < smallestZoom)
 376:     {
 377:       final double linear = (zoom * 1.5);
 378:       if (linear > smallestZoom)
 379:       {
 380:         return smallestZoom;
 381:       }
 382:       return linear;
 383:     }
 384: 
 385:     for (int i = 0; i < zoomFactors.length; i++)
 386:     {
 387:       final double factor = zoomFactors[i];
 388:       if (factor > zoom)
 389:       {
 390:         return factor;
 391:       }
 392:     }
 393:     return (zoom * 1.5);
 394:   }
 395: 
 396: 
 397:   public static IconTheme createIconTheme(final Configuration config)
 398:   {
 399:     final String themeClass = config.getConfigProperty(ICON_THEME_CONFIG_KEY);
 400:     final Object maybeTheme = ObjectUtilities.loadAndInstantiate(themeClass, PreviewPane.class, IconTheme.class);
 401:     final IconTheme iconTheme;
 402:     if (maybeTheme != null)
 403:     {
 404:       iconTheme = (IconTheme) maybeTheme;
 405:     }
 406:     else
 407:     {
 408:       iconTheme = new DefaultIconTheme();
 409:     }
 410:     iconTheme.initialize(config);
 411:     return iconTheme;
 412:   }
 413: 
 414:   public static ActionFactory createActionFactory(final Configuration config)
 415:   {
 416:     final String factoryClass = config.getConfigProperty(ACTION_FACTORY_CONFIG_KEY);
 417:     final Object maybeFactory = ObjectUtilities.loadAndInstantiate
 418:         (factoryClass, PreviewPane.class, ActionFactory.class);
 419:     final ActionFactory actionFactory;
 420:     if (maybeFactory != null)
 421:     {
 422:       actionFactory = (ActionFactory) maybeFactory;
 423:     }
 424:     else
 425:     {
 426:       actionFactory = new DefaultActionFactory();
 427:     }
 428:     return actionFactory;
 429:   }
 430: 
 431:   public static CategoryTreeItem[] buildMenuTree(final ActionCategory[] categories)
 432:   {
 433:     final CategoryTreeItem[] tree = new CategoryTreeItem[categories.length];
 434:     for (int i = 0; i < categories.length; i++)
 435:     {
 436:       final ActionCategory category = categories[i];
 437:       tree[i] = new CategoryTreeItem(category);
 438:     }
 439: 
 440:     for (int j = 0; j < tree.length; j++)
 441:     {
 442:       final CategoryTreeItem item = tree[j];
 443:       final String itemName = item.getName();
 444:       int parentWeight = 0;
 445:       CategoryTreeItem parent = null;
 446:       // now for each item, find the best parent item.
 447:       for (int k = 0; k < tree.length; k++)
 448:       {
 449:         if (k == j)
 450:         {
 451:           // never add yourself ..
 452:           continue;
 453:         }
 454:         final CategoryTreeItem treeItem = tree[k];
 455:         final String parentName = treeItem.getName();
 456:         if (itemName.startsWith(parentName) == false)
 457:         {
 458:           continue;
 459:         }
 460:         if (parentName.length() > parentWeight)
 461:         {
 462:           parent = treeItem;
 463:           parentWeight = parentName.length();
 464:         }
 465:       }
 466: 
 467:       item.setParent(parent);
 468:     }
 469: 
 470:     for (int j = 0; j < tree.length; j++)
 471:     {
 472:       final CategoryTreeItem item = tree[j];
 473:       final CategoryTreeItem parent = item.getParent();
 474:       if (parent != null)
 475:       {
 476:         parent.add(item);
 477:       }
 478:     }
 479:     return tree;
 480:   }
 481: 
 482:   public static HashMap loadActions(final SwingGuiContext swingGuiContext)
 483:   {
 484:     final HashMap actions = new HashMap();
 485: 
 486:     final Configuration configuration = swingGuiContext.getConfiguration();
 487:     final ActionCategory[] categories = loadCategories(swingGuiContext);
 488:     final ActionFactory factory = PreviewPaneUtilities.createActionFactory(configuration);
 489: 
 490:     for (int i = 0; i < categories.length; i++)
 491:     {
 492:       final ActionCategory category = categories[i];
 493:       actions.put(category,
 494:           factory.getActions(swingGuiContext, category.getName()));
 495:     }
 496:     return actions;
 497:   }
 498: 
 499: 
 500:   public static ActionCategory[] loadCategories(final SwingGuiContext swingGuiContext)
 501:   {
 502:     final ArrayList categories = new ArrayList();
 503:     final Configuration configuration = swingGuiContext.getConfiguration();
 504:     final Iterator keys = configuration.findPropertyKeys(CATEGORY_PREFIX);
 505:     while (keys.hasNext())
 506:     {
 507:       final String enableKey = (String) keys.next();
 508:       if (enableKey.endsWith(".enabled") == false)
 509:       {
 510:         continue;
 511:       }
 512: 
 513:       if ("true".equals(configuration.getConfigProperty(enableKey)) == false)
 514:       {
 515:         continue;
 516:       }
 517: 
 518:       final String base = enableKey.substring(0, enableKey.length() - ".enabled".length());
 519:       if (base.length() == 0)
 520:       {
 521:         continue;
 522:       }
 523: 
 524:       final String categoryKey = base.substring(CATEGORY_PREFIX.length());
 525:       final String className = configuration.getConfigProperty(base + ".class");
 526:       ActionCategory actionCategory;
 527:       if (className == null)
 528:       {
 529:         actionCategory = new ActionCategory();
 530:       }
 531:       else
 532:       {
 533:         actionCategory = (ActionCategory) ObjectUtilities.loadAndInstantiate
 534:             (className, PreviewPane.class, ActionCategory.class);
 535:         if (actionCategory == null)
 536:         {
 537:           actionCategory = new ActionCategory();
 538:         }
 539:       }
 540: 
 541:       final String positionText = configuration.getConfigProperty(base + ".position");
 542:       actionCategory.setPosition(TextUtilities.parseInt(positionText, 0));
 543:       actionCategory.setName(categoryKey);
 544:       actionCategory.setResourceBase(configuration.getConfigProperty(base + ".resource-base"));
 545:       actionCategory.setResourcePrefix(configuration.getConfigProperty(base + ".resource-prefix"));
 546:       actionCategory.initialize(swingGuiContext);
 547:       categories.add(actionCategory);
 548:     }
 549: 
 550:     return (ActionCategory[]) categories.toArray
 551:         (new ActionCategory[categories.size()]);
 552:   }
 553: }