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

   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: PreviewPane.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.BorderLayout;
  35: import java.awt.Color;
  36: import java.awt.Window;
  37: import java.beans.PropertyChangeEvent;
  38: import java.beans.PropertyChangeListener;
  39: import java.text.NumberFormat;
  40: import java.util.ArrayList;
  41: import java.util.Arrays;
  42: import java.util.Collections;
  43: import java.util.HashMap;
  44: import java.util.Iterator;
  45: import java.util.Locale;
  46: import java.util.Map;
  47: import javax.swing.BorderFactory;
  48: import javax.swing.JComponent;
  49: import javax.swing.JMenu;
  50: import javax.swing.JPanel;
  51: import javax.swing.JScrollPane;
  52: import javax.swing.JToolBar;
  53: import javax.swing.SwingUtilities;
  54: 
  55: import org.jfree.layout.CenterLayout;
  56: import org.jfree.layouting.modules.output.graphics.PageDrawable;
  57: import org.jfree.report.JFreeReportBoot;
  58: import org.jfree.report.flow.ReportJob;
  59: import org.jfree.report.flow.ReportStructureRoot;
  60: import org.jfree.report.modules.gui.common.IconTheme;
  61: import org.jfree.report.modules.gui.swing.common.ActionPlugin;
  62: import org.jfree.report.modules.gui.swing.common.SwingGuiContext;
  63: import org.jfree.report.modules.gui.swing.common.SwingUtil;
  64: import org.jfree.report.modules.gui.swing.printing.PrintReportProcessor;
  65: import org.jfree.report.util.Worker;
  66: import org.jfree.report.util.TextUtilities;
  67: import org.jfree.ui.Drawable;
  68: import org.jfree.ui.DrawablePanel;
  69: import org.jfree.ui.KeyedComboBoxModel;
  70: import org.jfree.util.Configuration;
  71: import org.jfree.util.Log;
  72: import org.jfree.util.ObjectUtilities;
  73: 
  74: /**
  75:  * Creation-Date: 11.11.2006, 19:36:13
  76:  *
  77:  * @author Thomas Morgner
  78:  */
  79: public class PreviewPane extends JPanel
  80: {
  81:   private class PreviewGuiContext implements SwingGuiContext
  82:   {
  83:     private PreviewGuiContext()
  84:     {
  85:     }
  86: 
  87:     public Window getWindow()
  88:     {
  89:       return SwingUtil.getWindowAncestor(PreviewPane.this);
  90:     }
  91: 
  92:     public Locale getLocale()
  93:     {
  94:       final ReportJob report = getReportJob();
  95:       if (report != null)
  96:       {
  97:         return report.getReportStructureRoot().getLocale();
  98:       }
  99:       return Locale.getDefault();
 100:     }
 101: 
 102:     public IconTheme getIconTheme()
 103:     {
 104:       return PreviewPane.this.getIconTheme();
 105:     }
 106: 
 107:     public Configuration getConfiguration()
 108:     {
 109:       final ReportJob report = getReportJob();
 110:       if (report != null)
 111:       {
 112:         return report.getConfiguration();
 113:       }
 114:       return JFreeReportBoot.getInstance().getGlobalConfig();
 115:     }
 116:   }
 117: 
 118:   private class RepaginationRunnable implements Runnable
 119:   {
 120:     private PrintReportProcessor processor;
 121: 
 122:     private RepaginationRunnable(final PrintReportProcessor processor)
 123:     {
 124:       this.processor = processor;
 125:     }
 126: 
 127:     /**
 128:      * When an object implementing interface <code>Runnable</code> is used to
 129:      * create a thread, starting the thread causes the object's <code>run</code>
 130:      * method to be called in that separately executing thread.
 131:      * <p/>
 132:      * The general contract of the method <code>run</code> is that it may take
 133:      * any action whatsoever.
 134:      *
 135:      * @see Thread#run()
 136:      */
 137:     public void run()
 138:     {
 139:       final UpdatePaginatingPropertyHandler startPaginationNotify =
 140:           new UpdatePaginatingPropertyHandler(processor, true, 0);
 141:       if (SwingUtilities.isEventDispatchThread())
 142:       {
 143:         startPaginationNotify.run();
 144:       }
 145:       else
 146:       {
 147:         SwingUtilities.invokeLater(startPaginationNotify);
 148:       }
 149: 
 150:       // Perform the pagination ..
 151:       final int pageCount = processor.getNumberOfPages();
 152: 
 153:       final UpdatePaginatingPropertyHandler endPaginationNotify =
 154:           new UpdatePaginatingPropertyHandler(processor, false, pageCount);
 155:       if (SwingUtilities.isEventDispatchThread())
 156:       {
 157:         endPaginationNotify.run();
 158:       }
 159:       else
 160:       {
 161:         SwingUtilities.invokeLater(endPaginationNotify);
 162:       }
 163: 
 164:     }
 165:   }
 166: 
 167:   private class UpdatePaginatingPropertyHandler implements Runnable
 168:   {
 169:     private boolean paginating;
 170:     private int pageCount;
 171:     private PrintReportProcessor processor;
 172: 
 173:     private UpdatePaginatingPropertyHandler(final PrintReportProcessor processor,
 174:                                            final boolean paginating,
 175:                                            final int pageCount)
 176:     {
 177:       this.processor = processor;
 178:       this.paginating = paginating;
 179:       this.pageCount = pageCount;
 180:     }
 181: 
 182:     /**
 183:      * When an object implementing interface <code>Runnable</code> is used to
 184:      * create a thread, starting the thread causes the object's <code>run</code>
 185:      * method to be called in that separately executing thread.
 186:      * <p/>
 187:      * The general contract of the method <code>run</code> is that it may take
 188:      * any action whatsoever.
 189:      *
 190:      * @see Thread#run()
 191:      */
 192:     public void run()
 193:     {
 194:       if (processor != getPrintReportProcessor())
 195:       {
 196:         Log.debug("No longer valid");
 197:         return;
 198:       }
 199: 
 200:       Log.debug("Pagination: " + paginating + " No. " + pageCount);
 201:       if (paginating == false)
 202:       {
 203:         setNumberOfPages(pageCount);
 204:         if (getPageNumber() < 1)
 205:         {
 206:           setPageNumber(1);
 207:         }
 208:         else if (getPageNumber() > pageCount)
 209:         {
 210:           setPageNumber(pageCount);
 211:         }
 212:       }
 213:       setPaginating(paginating);
 214:     }
 215:   }
 216: 
 217:   private class PreviewUpdateHandler implements PropertyChangeListener
 218:   {
 219:     private PreviewUpdateHandler()
 220:     {
 221:     }
 222: 
 223:     public void propertyChange(final PropertyChangeEvent evt)
 224:     {
 225:       final String propertyName = evt.getPropertyName();
 226:       if (PAGINATING_PROPERTY.equals(propertyName))
 227:       {
 228:         if (isPaginating())
 229:         {
 230:           drawablePanel.setDrawable(getPaginatingDrawable());
 231:         }
 232:         else
 233:         {
 234:           updateVisiblePage(getPageNumber());
 235:         }
 236:       }
 237:       else if (REPORT_JOB_PROPERTY.equals(propertyName))
 238:       {
 239:         if (getReportJob() == null)
 240:         {
 241:           drawablePanel.setDrawable(getNoReportDrawable());
 242:         }
 243:         // else the paginating property will be fired anyway ..
 244:       }
 245:       else if (PAGE_NUMBER_PROPERTY.equals(propertyName))
 246:       {
 247:         if (isPaginating())
 248:         {
 249:           return;
 250:         }
 251: 
 252:         updateVisiblePage(getPageNumber());
 253:       }
 254:     }
 255:   }
 256: 
 257:   private class UpdateZoomHandler implements PropertyChangeListener
 258:   {
 259:     private UpdateZoomHandler()
 260:     {
 261:     }
 262: 
 263:     /**
 264:      * This method gets called when a bound property is changed.
 265:      *
 266:      * @param evt A PropertyChangeEvent object describing the event source and
 267:      *            the property that has changed.
 268:      */
 269: 
 270:     public void propertyChange(final PropertyChangeEvent evt)
 271:     {
 272:       if ("zoom".equals(evt.getPropertyName()) == false)
 273:       {
 274:         return;
 275:       }
 276:       Log.debug ("Zooming: " + zoom);
 277:       if (zoom == 1.0)
 278:       {
 279:         Log.debug ("JERE");
 280:       }
 281:       final double zoom = getZoom();
 282:       pageDrawable.setZoom(zoom);
 283:       zoomModel.setSelectedKey(new Double(zoom));
 284:       if (zoomModel.getSelectedKey() == null)
 285:       {
 286:         Log.debug ("Zooming: (2) " + zoom);
 287:         zoomModel.setSelectedItem(formatZoomText(zoom));
 288:       }
 289:       drawablePanel.revalidate();
 290:     }
 291:   }
 292: 
 293:   private static final double[] ZOOM_FACTORS = {
 294:       0.5, 0.75, 1, 1.20, 1.50, 2.00
 295:   };
 296:   private static final int DEFAULT_ZOOM_INDEX = 2;
 297:   public static final String PAGE_NUMBER_PROPERTY = "pageNumber";
 298:   public static final String NUMBER_OF_PAGES_PROPERTY = "numberOfPages";
 299:   public static final String STATUS_TEXT_PROPERTY = "statusText";
 300:   public static final String STATUS_TYPE_PROPERTY = "statusType";
 301:   public static final String REPORT_CONTROLLER_PROPERTY = "reportController";
 302:   public static final String REPORT_JOB_PROPERTY = "reportJob";
 303:   public static final String ZOOM_PROPERTY = "zoom";
 304:   public static final String CLOSED_PROPERTY = "closed";
 305:   public static final String PAGINATING_PROPERTY = "paginating";
 306:   public static final String ICON_THEME_PROPERTY = "iconTheme";
 307:   public static final String TITLE_PROPERTY = "title";
 308:   public static final String MENU_PROPERTY = "menu";
 309: 
 310:   private Drawable paginatingDrawable;
 311:   private Drawable noReportDrawable;
 312:   private PageBackgroundDrawable pageDrawable;
 313: 
 314:   private DrawablePanel drawablePanel;
 315:   private ReportController reportController;
 316:   private JMenu[] menus;
 317:   private JToolBar toolBar;
 318:   private String statusText;
 319:   private String title;
 320:   private int statusType;
 321:   private boolean closed;
 322:   private ReportJob reportJob;
 323: 
 324:   private int numberOfPages;
 325:   private int pageNumber;
 326:   private SwingGuiContext swingGuiContext;
 327:   private IconTheme iconTheme;
 328:   private double zoom;
 329:   private boolean paginating;
 330: 
 331:   private PrintReportProcessor printReportProcessor;
 332: 
 333: 
 334:   private Worker paginationWorker;
 335:   private JPanel innerReportControllerHolder;
 336:   private JPanel toolbarHolder;
 337:   private JPanel outerReportControllerHolder;
 338:   private boolean reportControllerInner;
 339:   private String reportControllerLocation;
 340:   private JComponent reportControllerComponent;
 341:   private KeyedComboBoxModel zoomModel;
 342: 
 343: 
 344:   /**
 345:    * Creates a new <code>JPanel</code> with a double buffer and a flow layout.
 346:    */
 347:   public PreviewPane()
 348:   {
 349:     this.menus = new JMenu[0];
 350:     setLayout(new BorderLayout());
 351: 
 352:     zoomModel = new KeyedComboBoxModel();
 353:     zoomModel.setAllowOtherValue(true);
 354:     zoom = ZOOM_FACTORS[DEFAULT_ZOOM_INDEX];
 355: 
 356:     pageDrawable = new PageBackgroundDrawable();
 357: 
 358:     drawablePanel = new DrawablePanel();
 359:     drawablePanel.setOpaque(false);
 360:     drawablePanel.setBackground(Color.green);
 361: 
 362:     swingGuiContext = new PreviewGuiContext();
 363: 
 364:     final JPanel reportPaneHolder = new JPanel(new CenterLayout());
 365:     reportPaneHolder.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 366:     reportPaneHolder.add(drawablePanel);
 367: 
 368:     final JScrollPane s1 = new JScrollPane(reportPaneHolder);
 369:     s1.getVerticalScrollBar().setUnitIncrement(20);
 370: 
 371:     innerReportControllerHolder = new JPanel();
 372:     innerReportControllerHolder.setLayout(new BorderLayout());
 373:     innerReportControllerHolder.add(s1, BorderLayout.CENTER);
 374: 
 375:     toolbarHolder = new JPanel();
 376:     toolbarHolder.setLayout(new BorderLayout());
 377:     toolbarHolder.add(innerReportControllerHolder, BorderLayout.CENTER);
 378: 
 379:     outerReportControllerHolder = new JPanel();
 380:     outerReportControllerHolder.setLayout(new BorderLayout());
 381:     outerReportControllerHolder.add(toolbarHolder, BorderLayout.CENTER);
 382: 
 383:     add(outerReportControllerHolder, BorderLayout.CENTER);
 384: 
 385:     addPropertyChangeListener(new PreviewUpdateHandler());
 386:     addPropertyChangeListener("zoom", new UpdateZoomHandler());
 387:   }
 388: 
 389:   public synchronized PrintReportProcessor getPrintReportProcessor()
 390:   {
 391:     return printReportProcessor;
 392:   }
 393: 
 394:   protected synchronized void setPrintReportProcessor(final PrintReportProcessor printReportProcessor)
 395:   {
 396:     this.printReportProcessor = printReportProcessor;
 397:   }
 398: 
 399:   public JMenu[] getMenu()
 400:   {
 401:     return menus;
 402:   }
 403: 
 404:   protected void setMenu(final JMenu[] menus)
 405:   {
 406:     if (menus == null)
 407:     {
 408:       throw new NullPointerException();
 409:     }
 410:     final JMenu[] oldmenu = this.menus;
 411:     this.menus = (JMenu[]) menus.clone();
 412:     firePropertyChange(MENU_PROPERTY, oldmenu, this.menus);
 413:   }
 414: 
 415:   public JToolBar getToolBar()
 416:   {
 417:     return toolBar;
 418:   }
 419: 
 420:   public String getStatusText()
 421:   {
 422:     return statusText;
 423:   }
 424: 
 425:   public void setStatusText(final String statusText)
 426:   {
 427:     final String oldStatus = this.statusText;
 428:     this.statusText = statusText;
 429: 
 430:     firePropertyChange(STATUS_TEXT_PROPERTY, oldStatus, statusText);
 431:   }
 432: 
 433:   public int getStatusType()
 434:   {
 435:     return statusType;
 436:   }
 437: 
 438:   public void setStatusType(final int statusType)
 439:   {
 440:     final int oldType = this.statusType;
 441:     this.statusType = statusType;
 442: 
 443:     firePropertyChange(STATUS_TYPE_PROPERTY, oldType, statusType);
 444:   }
 445: 
 446:   public ReportController getReportController()
 447:   {
 448:     return reportController;
 449:   }
 450: 
 451:   public void setReportController(final ReportController reportController)
 452:   {
 453:     final ReportController oldController = this.reportController;
 454:     this.reportController = reportController;
 455:     firePropertyChange(REPORT_CONTROLLER_PROPERTY, oldController, reportController);
 456: 
 457:     // Now add the controller to the GUI ..
 458:     refreshReportController(reportController);
 459:   }
 460: 
 461:   public void refreshReportController(final ReportController newReportController)
 462:   {
 463:     if (newReportController != null)
 464:     {
 465:       final JComponent rcp = newReportController.getControlPanel();
 466:       // if either the controller component or its position (inner vs outer)
 467:       // and border-position has changed, then refresh ..
 468:       if (reportControllerComponent != rcp ||
 469:           reportControllerInner != newReportController.isInnerComponent() ||
 470:           ObjectUtilities.equal(reportControllerLocation,
 471:               newReportController.getControllerLocation()))
 472:       {
 473:         if (reportControllerComponent != null)
 474:         {
 475:           outerReportControllerHolder.remove(reportControllerComponent);
 476:           innerReportControllerHolder.remove(reportControllerComponent);
 477:         }
 478:         final String sanLocation = sanitizeLocation(
 479:             newReportController.getControllerLocation());
 480:         final boolean innerComponent = newReportController.isInnerComponent();
 481:         if (rcp != null)
 482:         {
 483:           if (innerComponent)
 484:           {
 485:             innerReportControllerHolder.add(rcp, sanLocation);
 486:           }
 487:           else
 488:           {
 489:             outerReportControllerHolder.add(rcp, sanLocation);
 490:           }
 491:         }
 492:         reportControllerComponent = rcp;
 493:         reportControllerLocation = sanLocation;
 494:         reportControllerInner = innerComponent;
 495:       }
 496:     }
 497:     else
 498:     {
 499:       if (reportControllerComponent != null)
 500:       {
 501:         outerReportControllerHolder.remove(reportControllerComponent);
 502:         innerReportControllerHolder.remove(reportControllerComponent);
 503:       }
 504:       reportControllerComponent = null;
 505:     }
 506:   }
 507: 
 508: 
 509:   private String sanitizeLocation(final String location)
 510:   {
 511:     if (BorderLayout.NORTH.equals(location))
 512:     {
 513:       return BorderLayout.NORTH;
 514:     }
 515:     if (BorderLayout.SOUTH.equals(location))
 516:     {
 517:       return BorderLayout.SOUTH;
 518:     }
 519:     if (BorderLayout.WEST.equals(location))
 520:     {
 521:       return BorderLayout.WEST;
 522:     }
 523:     if (BorderLayout.EAST.equals(location))
 524:     {
 525:       return BorderLayout.EAST;
 526:     }
 527:     return BorderLayout.NORTH;
 528:   }
 529: 
 530:   public ReportJob getReportJob()
 531:   {
 532:     return reportJob;
 533:   }
 534: 
 535:   public void setReportJob(final ReportJob reportJob)
 536:   {
 537:     final ReportJob oldJob = this.reportJob;
 538:     this.reportJob = reportJob;
 539: 
 540:     firePropertyChange(REPORT_JOB_PROPERTY, oldJob, reportJob);
 541:     if (reportJob == null)
 542:     {
 543:       initializeWithoutJob();
 544:     }
 545:     else
 546:     {
 547:       initializeFromReport();
 548:     }
 549:   }
 550: 
 551:   public double getZoom()
 552:   {
 553:     return zoom;
 554:   }
 555: 
 556:   public void setZoom(final double zoom)
 557:   {
 558:     final double oldZoom = this.zoom;
 559:     this.zoom = zoom;
 560:     firePropertyChange(ZOOM_PROPERTY, oldZoom, zoom);
 561:   }
 562: 
 563:   public boolean isClosed()
 564:   {
 565:     return closed;
 566:   }
 567: 
 568:   public void setClosed(final boolean closed)
 569:   {
 570:     final boolean oldClosed = this.closed;
 571:     this.closed = closed;
 572:     firePropertyChange(CLOSED_PROPERTY, oldClosed, closed);
 573:     if (closed)
 574:     {
 575:       prepareShutdown();
 576:     }
 577:   }
 578: 
 579:   private void prepareShutdown()
 580:   {
 581:     synchronized (this)
 582:     {
 583:       if (paginationWorker != null)
 584:       {
 585:         synchronized (paginationWorker)
 586:         {
 587:           paginationWorker.finish();
 588:         }
 589:         paginationWorker = null;
 590:       }
 591:       if (printReportProcessor != null)
 592:       {
 593:         printReportProcessor.close();
 594:         printReportProcessor = null;
 595:       }
 596:       closeToolbar();
 597:     }
 598:   }
 599: 
 600:   private int getUserDefinedCategoryPosition()
 601:   {
 602:     return TextUtilities.parseInt
 603:         (swingGuiContext.getConfiguration().getConfigProperty
 604:             ("org.jfree.report.modules.gui.swing.user-defined-category.position"), 15000);
 605:   }
 606: 
 607: 
 608:   public Locale getLocale()
 609:   {
 610:     final ReportStructureRoot report = getReportJob().getReportStructureRoot();
 611:     if (report != null)
 612:     {
 613:       return report.getLocale();
 614:     }
 615:     return super.getLocale();
 616:   }
 617: 
 618:   public int getNumberOfPages()
 619:   {
 620:     return numberOfPages;
 621:   }
 622: 
 623:   public void setNumberOfPages(final int numberOfPages)
 624:   {
 625:     final int oldPageNumber = this.numberOfPages;
 626:     this.numberOfPages = numberOfPages;
 627:     firePropertyChange(NUMBER_OF_PAGES_PROPERTY, oldPageNumber, numberOfPages);
 628:   }
 629: 
 630:   public int getPageNumber()
 631:   {
 632:     return pageNumber;
 633:   }
 634: 
 635:   public void setPageNumber(final int pageNumber)
 636:   {
 637:     final int oldPageNumber = this.pageNumber;
 638:     this.pageNumber = pageNumber;
 639:     Log.debug("Setting PageNumber: " + pageNumber);
 640:     firePropertyChange(PAGE_NUMBER_PROPERTY, oldPageNumber, pageNumber);
 641:   }
 642: 
 643:   public IconTheme getIconTheme()
 644:   {
 645:     return iconTheme;
 646:   }
 647: 
 648:   protected void setIconTheme(final IconTheme theme)
 649:   {
 650:     final IconTheme oldTheme = this.iconTheme;
 651:     this.iconTheme = theme;
 652:     firePropertyChange(ICON_THEME_PROPERTY, oldTheme, theme);
 653:   }
 654: 
 655:   protected void initializeFromReport()
 656:   {
 657:     setIconTheme(PreviewPaneUtilities.createIconTheme(reportJob.getConfiguration()));
 658: 
 659:     zoomModel.clear();
 660:     for (int i = 0; i < ZOOM_FACTORS.length; i++)
 661:     {
 662:       zoomModel.add(new Double(ZOOM_FACTORS[i]), formatZoomText(ZOOM_FACTORS[i]));
 663:     }
 664:     zoom = ZOOM_FACTORS[DEFAULT_ZOOM_INDEX];
 665:     zoomModel.setSelectedKey(new Double(ZOOM_FACTORS[DEFAULT_ZOOM_INDEX]));
 666: 
 667:     final HashMap actions = PreviewPaneUtilities.loadActions(swingGuiContext);
 668:     buildMenu(actions);
 669: 
 670: 
 671:     if (toolBar != null)
 672:     {
 673:       toolbarHolder.remove(toolBar);
 674:     }
 675:     toolBar = buildToolbar(actions);
 676:     if (toolBar != null)
 677:     {
 678:       toolbarHolder.add(toolBar, BorderLayout.NORTH);
 679:     }
 680: 
 681:     startPagination();
 682:   }
 683: 
 684:   private JToolBar buildToolbar(final HashMap actions)
 685:   {
 686:     final JToolBar toolBar = new JToolBar();
 687:     toolBar.setFloatable(false);
 688: 
 689:     final ActionCategory[] cats = (ActionCategory[])
 690:         actions.keySet().toArray(new ActionCategory[actions.size()]);
 691:     Arrays.sort(cats);
 692: 
 693:     for (int i = 0; i < cats.length; i++)
 694:     {
 695:       final ActionCategory cat = cats[i];
 696:       final ActionPlugin[] plugins = (ActionPlugin[]) actions.get(cat);
 697:       PreviewPaneUtilities.addActionsToToolBar(toolBar, plugins, this);
 698:     }
 699: 
 700:     return toolBar;
 701:   }
 702: 
 703:   private void closeToolbar()
 704:   {
 705:     if (toolBar.getParent() != toolbarHolder)
 706:     {
 707:       // ha!, we detected that the toolbar is floating ...
 708:       // Log.debug (currentToolbar.getParent());
 709:       final Window w = SwingUtilities.windowForComponent(toolBar);
 710:       if (w != null)
 711:       {
 712:         w.setVisible(false);
 713:         w.dispose();
 714:       }
 715:     }
 716:     toolBar.setVisible(false);
 717:   }
 718: 
 719:   public SwingGuiContext getSwingGuiContext()
 720:   {
 721:     return swingGuiContext;
 722:   }
 723: 
 724:   public KeyedComboBoxModel getZoomModel()
 725:   {
 726:     return zoomModel;
 727:   }
 728: 
 729:   private String formatZoomText(final double zoom)
 730:   {
 731:     final NumberFormat numberFormat =
 732:         NumberFormat.getPercentInstance(swingGuiContext.getLocale());
 733:     return (numberFormat.format(zoom));
 734:   }
 735: 
 736: 
 737:   private void buildMenu(final HashMap actions)
 738:   {
 739:     final HashMap menus = new HashMap();
 740:     final int userPos = getUserDefinedCategoryPosition();
 741: 
 742:     final ActionCategory[] categories = new ActionCategory[actions.size()];
 743:     boolean insertedUserDefinedActions = false;
 744:     int catCount = 0;
 745:     final Iterator iterator = actions.entrySet().iterator();
 746:     while (iterator.hasNext())
 747:     {
 748:       final Map.Entry entry = (Map.Entry) iterator.next();
 749:       final ActionCategory cat = (ActionCategory) entry.getKey();
 750:       categories[catCount] = cat;
 751:       catCount += 1;
 752:       final ActionPlugin[] plugins = (ActionPlugin[]) entry.getValue();
 753: 
 754:       if (insertedUserDefinedActions == false && cat.getPosition() > userPos)
 755:       {
 756:         final ReportController controller = getReportController();
 757:         if (controller != null)
 758:         {
 759:           controller.initialize(this);
 760:           final JMenu[] controlerMenus = controller.getMenus();
 761:           for (int i = 0; i < controlerMenus.length; i++)
 762:           {
 763:             final ActionCategory userCategory = new ActionCategory();
 764:             userCategory.setName("X-User-Category-" + i);
 765:             userCategory.setPosition(userPos + i);
 766:             menus.put(userCategory, controlerMenus[i]);
 767:           }
 768:         }
 769: 
 770:         insertedUserDefinedActions = true;
 771:       }
 772: 
 773:       final JMenu menu = PreviewPaneUtilities.createMenu(cat);
 774:       final int count = PreviewPaneUtilities.buildMenu(menu, plugins, this);
 775:       menus.put(cat, menu);
 776:     }
 777: 
 778:     final CategoryTreeItem[] categoryTreeItems =
 779:         PreviewPaneUtilities.buildMenuTree(categories);
 780: 
 781:     final ArrayList menuList = new ArrayList();
 782:     for (int i = 0; i < categoryTreeItems.length; i++)
 783:     {
 784:       final CategoryTreeItem item = categoryTreeItems[i];
 785:       final JMenu menu = (JMenu) menus.get(item.getCategory());
 786:       // now connect all menus ..
 787:       final CategoryTreeItem[] childs = item.getChilds();
 788:       Arrays.sort(childs);
 789:       for (int j = 0; j < childs.length; j++)
 790:       {
 791:         final CategoryTreeItem child = childs[j];
 792:         final JMenu childMenu = (JMenu) menus.get(child.getCategory());
 793:         if (childMenu != null)
 794:         {
 795:           menu.add(childMenu);
 796:         }
 797:       }
 798: 
 799:       if (item.getParent() == null)
 800:       {
 801:         menuList.add(item);
 802:       }
 803:     }
 804: 
 805:     Collections.sort(menuList);
 806:     final ArrayList retval = new ArrayList();
 807:     for (int i = 0; i < menuList.size(); i++)
 808:     {
 809:       final CategoryTreeItem item = (CategoryTreeItem) menuList.get(i);
 810:       final JMenu menu = (JMenu) menus.get(item.getCategory());
 811:       if (menu.getItemCount() > 0)
 812:       {
 813:         retval.add(menu);
 814:       }
 815:     }
 816: 
 817:     setMenu((JMenu[]) retval.toArray(new JMenu[retval.size()]));
 818:   }
 819: 
 820: //  private JMenu createViewMenu(ActionCategory cat)
 821: //  {
 822: //    JMenu zoom = new JMenu("Zoom");
 823: //    zoom.add(new ActionMenuItem(new ZoomOutAction(this)));
 824: //    zoom.add(new ActionMenuItem(new ZoomInAction(this)));
 825: //    zoom.addSeparator();
 826: //
 827: //    for (int i = 0; i < ZOOM_FACTORS.length; i++)
 828: //    {
 829: //      double factor = ZOOM_FACTORS[i];
 830: //      zoom.add(new ActionMenuItem(new ZoomAction(factor, this)));
 831: //    }
 832: //
 833: //    zoom.addSeparator();
 834: //    zoom.add(new ActionMenuItem(new ZoomCustomAction(this)));
 835: //
 836: //    JMenu menu = new JMenu("View");
 837: //    menu.add(zoom);
 838: //    menu.addSeparator();
 839: //    menu.add(new ActionMenuItem("Paginated"));
 840: //    menu.add(new ActionMenuItem("Flow"));
 841: //    return menu;
 842: //  }
 843: 
 844:   protected void initializeWithoutJob()
 845:   {
 846:     final Configuration globalConfig =
 847:         JFreeReportBoot.getInstance().getGlobalConfig();
 848:     setIconTheme(PreviewPaneUtilities.createIconTheme(globalConfig));
 849: 
 850:     zoomModel.clear();
 851:     for (int i = 0; i < ZOOM_FACTORS.length; i++)
 852:     {
 853:       zoomModel.add(new Double(ZOOM_FACTORS[i]), formatZoomText(ZOOM_FACTORS[i]));
 854:     }
 855:     zoom = ZOOM_FACTORS[DEFAULT_ZOOM_INDEX];
 856:     zoomModel.setSelectedKey(new Double(ZOOM_FACTORS[DEFAULT_ZOOM_INDEX]));
 857: 
 858:     final HashMap actions = PreviewPaneUtilities.loadActions(swingGuiContext);
 859:     buildMenu(actions);
 860:     if (toolBar != null)
 861:     {
 862:       toolbarHolder.remove(toolBar);
 863:     }
 864:     toolBar = buildToolbar(actions);
 865:     if (toolBar != null)
 866:     {
 867:       toolbarHolder.add(toolBar, BorderLayout.NORTH);
 868:     }
 869: 
 870:   }
 871: 
 872:   public String getTitle()
 873:   {
 874:     return title;
 875:   }
 876: 
 877:   public void setTitle(final String title)
 878:   {
 879:     final String oldTitle = this.title;
 880:     this.title = title;
 881:     firePropertyChange(TITLE_PROPERTY, oldTitle, title);
 882:   }
 883: 
 884:   public double[] getZoomFactors()
 885:   {
 886:     return (double[]) ZOOM_FACTORS.clone();
 887:   }
 888: 
 889:   public boolean isPaginating()
 890:   {
 891:     return paginating;
 892:   }
 893: 
 894:   public void setPaginating(final boolean paginating)
 895:   {
 896:     final boolean oldPaginating = this.paginating;
 897:     this.paginating = paginating;
 898:     firePropertyChange(PAGINATING_PROPERTY, oldPaginating, paginating);
 899:   }
 900: 
 901:   private synchronized void startPagination()
 902:   {
 903:     if (paginationWorker != null)
 904:     {
 905:       // make sure that old pagination handler does not run longer than
 906:       // necessary..
 907:       synchronized(paginationWorker)
 908:       {
 909:         paginationWorker.finish();
 910:       }
 911:       paginationWorker = null;
 912:     }
 913: 
 914:     if (printReportProcessor != null)
 915:     {
 916:       printReportProcessor.close();
 917:       printReportProcessor = null;
 918:     }
 919: 
 920:     final ReportJob reportJob = getReportJob();
 921:     printReportProcessor = new PrintReportProcessor(reportJob.derive());
 922: 
 923:     paginationWorker = new Worker();
 924:     paginationWorker.setWorkload
 925:         (new RepaginationRunnable(printReportProcessor));
 926:   }
 927: 
 928:   public Drawable getNoReportDrawable()
 929:   {
 930:     return noReportDrawable;
 931:   }
 932: 
 933:   public void setNoReportDrawable(final Drawable noReportDrawable)
 934:   {
 935:     this.noReportDrawable = noReportDrawable;
 936:   }
 937: 
 938:   public Drawable getPaginatingDrawable()
 939:   {
 940:     return paginatingDrawable;
 941:   }
 942: 
 943:   public void setPaginatingDrawable(final Drawable paginatingDrawable)
 944:   {
 945:     this.paginatingDrawable = paginatingDrawable;
 946:   }
 947: 
 948:   protected void updateVisiblePage(final int pageNumber)
 949:   {
 950:     //
 951:     if (printReportProcessor == null)
 952:     {
 953:       throw new IllegalStateException();
 954:     }
 955: 
 956:     // todo: This can be very expensive - so we better move this off the event-dispatcher
 957:     final int pageIndex = getPageNumber() - 1;
 958:     if (pageIndex < 0 || pageIndex >= printReportProcessor.getNumberOfPages())
 959:     {
 960:       drawablePanel.setDrawable(null);
 961:       pageDrawable.setBackend(null);
 962:     }
 963:     else
 964:     {
 965:       final PageDrawable drawable = printReportProcessor.getPageDrawable(pageIndex);
 966:       Log.debug("Drawable: " + drawable);
 967:       this.pageDrawable.setBackend(drawable);
 968:       this.drawablePanel.setDrawable(pageDrawable);
 969:     }
 970:   }
 971: }