001    /**
002     * ========================================
003     * JFreeReport : a free Java report library
004     * ========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/
007     *
008     * (C) Copyright 2000-2007, by Object Refinery Limited, 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     * $Id: PreviewPane.java 3525 2007-10-16 11:43:48Z tmorgner $
027     * ------------
028     * (C) Copyright 2000-2005, by Object Refinery Limited.
029     * (C) Copyright 2005-2007, by Pentaho Corporation.
030     */
031    
032    package org.jfree.report.modules.gui.swing.preview;
033    
034    import java.awt.BorderLayout;
035    import java.awt.Color;
036    import java.awt.Window;
037    import java.beans.PropertyChangeEvent;
038    import java.beans.PropertyChangeListener;
039    import java.text.NumberFormat;
040    import java.util.ArrayList;
041    import java.util.Arrays;
042    import java.util.Collections;
043    import java.util.HashMap;
044    import java.util.Iterator;
045    import java.util.Locale;
046    import java.util.Map;
047    import javax.swing.BorderFactory;
048    import javax.swing.JComponent;
049    import javax.swing.JMenu;
050    import javax.swing.JPanel;
051    import javax.swing.JScrollPane;
052    import javax.swing.JToolBar;
053    import javax.swing.SwingUtilities;
054    
055    import org.jfree.layout.CenterLayout;
056    import org.jfree.layouting.modules.output.graphics.PageDrawable;
057    import org.jfree.report.JFreeReportBoot;
058    import org.jfree.report.flow.ReportJob;
059    import org.jfree.report.flow.ReportStructureRoot;
060    import org.jfree.report.modules.gui.common.IconTheme;
061    import org.jfree.report.modules.gui.swing.common.ActionPlugin;
062    import org.jfree.report.modules.gui.swing.common.SwingGuiContext;
063    import org.jfree.report.modules.gui.swing.common.SwingUtil;
064    import org.jfree.report.modules.gui.swing.printing.PrintReportProcessor;
065    import org.jfree.report.util.Worker;
066    import org.jfree.report.util.TextUtilities;
067    import org.jfree.ui.Drawable;
068    import org.jfree.ui.DrawablePanel;
069    import org.jfree.ui.KeyedComboBoxModel;
070    import org.jfree.util.Configuration;
071    import org.jfree.util.Log;
072    import org.jfree.util.ObjectUtilities;
073    
074    /**
075     * Creation-Date: 11.11.2006, 19:36:13
076     *
077     * @author Thomas Morgner
078     */
079    public class PreviewPane extends JPanel
080    {
081      private class PreviewGuiContext implements SwingGuiContext
082      {
083        private PreviewGuiContext()
084        {
085        }
086    
087        public Window getWindow()
088        {
089          return SwingUtil.getWindowAncestor(PreviewPane.this);
090        }
091    
092        public Locale getLocale()
093        {
094          final ReportJob report = getReportJob();
095          if (report != null)
096          {
097            return report.getReportStructureRoot().getLocale();
098          }
099          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    }