--- /dev/null
+/*
+ * Copyright (c) 2009, Takeyuki Nagao
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+package jp.sourceforge.dvibrowser.dvicore.gui.swing;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.Logger;
+
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+
+import jp.sourceforge.dvibrowser.dvicore.DviException;
+import jp.sourceforge.dvibrowser.dvicore.DviRect;
+import jp.sourceforge.dvibrowser.dvicore.api.DviContext;
+import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport;
+import jp.sourceforge.dvibrowser.dvicore.api.DviPage;
+import jp.sourceforge.dvibrowser.dvicore.ctx.DviToolkit;
+import jp.sourceforge.dvibrowser.dvicore.util.DaemonThreadFactory;
+
+
+public class TDviPage extends JPanel implements DviContextSupport, ChangeListener
+{
+ private static final Logger LOGGER = Logger.getLogger(TDviPage.class.getName());
+ private static final long serialVersionUID = -7167678585159838308L;
+
+ private boolean busy = false;
+
+ private final DviContextSupport dcs;
+ public DviContext getDviContext() { return dcs.getDviContext(); }
+
+ public TDviPage(DviContextSupport dcs, DviPage page) {
+ super();
+ this.dcs = dcs;
+ this.viewSpec = new ViewSpec(this);
+ this.viewSpec.setResolution(viewSpec.getResolution().approximate(200));
+ setPage(page);
+ }
+
+ public TDviPage(DviContextSupport dcs) {
+ this(dcs, null);
+ }
+
+ private DviPage page = null;
+
+ public void setPage(DviPage page)
+ {
+ this.page = page;
+ determineSize();
+ }
+
+ public DviPage getPage() { return page; }
+
+ private ViewSpec viewSpec;
+
+ public void setViewSpec(ViewSpec viewSpec)
+ {
+ LOGGER.fine("page=" + page + ",viewSpec=" + viewSpec);
+ this.viewSpec = viewSpec;
+ determineSize();
+ }
+
+ public ViewSpec getViewSpec() { return viewSpec; }
+
+// private DviRect bbox;
+//
+// public void setBoundingBox(DviRect bbox)
+// {
+// this.bbox = bbox;
+// determineSize();
+// }
+//
+// public DviRect getBoundingBox()
+// {
+// return bbox;
+// }
+
+// private Anchor.Href myHref = null;
+// private DviRect saveBBOX = null;
+//
+// public ByteRange getByteRangeFor(DviRect rect)
+// {
+// try {
+// DviResolution res = viewSpec.getResolution();
+//
+// rect = rect.intersect(displayRect);
+// if (rect.isEmpty())
+// return null;
+// rect = rect.magnify(res.shrinkFactor());
+//
+// Geometer geometer = new BasicGeometer(this);
+// ByteRangeComputer brc = new ByteRangeComputer(this, res, rect);
+// geometer.setPainter(brc);
+// getDviContext().execute(page, geometer);
+// AnchorSet anchors = (AnchorSet) rsc.getDataSource().find(AnchorSet.class,
+// page);
+// if (myHref != null) {
+// anchors.remove(myHref);
+// }
+// ByteRange br = brc.getByteRange();
+// anchors.add(myHref = new Anchor.Href(br.begin(), br.end(), "none"));
+// if (saveBBOX != null) {
+// DviRect r = saveBBOX;
+// repaint(r.x(), r.y(), r.width(), r.height());
+// }
+// DviRect r = brc.getBounds().shrink(res.shrinkFactor());
+// repaint(r.x(), r.y(), r.width(), r.height());
+// saveBBOX = r;
+// return br;
+// } catch (DviException ex) {
+// Logger.trace(ex);
+// return null;
+// }
+// }
+
+ private DviRect displayRect = null;
+
+ public void determineSize()
+ {
+ final DviToolkit utils = getDviContext().getDviToolkit();
+ displayRect = null;
+ try {
+ if (layout != null)
+ displayRect = layout.determinePageSize(this);
+ } catch (Exception e) {
+ LOGGER.severe(e.toString());
+ e.printStackTrace();
+ }
+ if (displayRect == null) {
+ displayRect = utils.computePageBoundingBox
+ (viewSpec.getPaperSize(), viewSpec.getResolution());
+ }
+
+ setPreferredSize(new Dimension(displayRect.width(), displayRect.height()));
+ setSize(new Dimension(displayRect.width(), displayRect.height()));
+ revalidate();
+ }
+
+ private static ExecutorService exe = Executors.newFixedThreadPool(3, new DaemonThreadFactory());
+
+ protected ExecutorService getExecutorService()
+ {
+ return exe;
+ }
+
+ protected void startPagePreparation(Graphics g, final Rectangle rect, final DviPage page, final ViewSpec viewSpec)
+ {
+ final DviToolkit utils = getDviContext().getDviToolkit();
+
+ LOGGER.finer("Preparing page for paint: " + page);
+ getExecutorService().submit(new Runnable() {
+ public void run()
+ {
+ try {
+ utils.prepareForRendering(page, viewSpec);
+ } catch (Exception e) {
+ LOGGER.warning(e.toString());
+ }
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run()
+ {
+ setBusy(false);
+ repaint();
+ }
+ });
+ }
+ });
+ setBusy(true);
+ paintDummyContents(g, rect, viewSpec);
+ }
+
+ private void paintDummyContents(Graphics g, final Rectangle rect,
+ final ViewSpec viewSpec)
+ {
+ g.setColor(viewSpec.getBackgroundColor().toColor());
+ g.fillRect(rect.x, rect.y, rect.width, rect.height);
+ }
+
+ protected void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ final DviToolkit utils = getDviContext().getDviToolkit();
+
+ if (page == null) return;
+
+ final Rectangle rect = g.getClipBounds();
+ g.fillRect(rect.x, rect.y, rect.width, rect.height);
+
+ boolean enableDelayedRendering = true;
+
+ try {
+ enableDelayedRendering = getEnableDelayedRendering();
+ } catch (DviException e1) {
+ LOGGER.warning(e1.toString());
+ }
+
+ if (enableDelayedRendering) {
+ if (!utils.canRenderPageImmediately(page, viewSpec)) {
+ LOGGER.finest("delayed rendering");
+ startPagePreparation(g, rect, page, viewSpec);
+ return;
+ }
+ }
+
+ try {
+ LOGGER.finest("rendering page=" + page.getPageNumber() + " rect=" + rect + " viewSpec=" + viewSpec);
+// DviRect targetArea = new DviRect
+// (rect.x + displayRect.x(), rect.y + displayRect.y(), rect.width+1, rect.height+1);
+ DviRect targetArea = DviRect.fromRectangle(rect).translate(displayRect.topLeft());
+ if (!targetArea.isEmpty()) {
+ BufferedImage img = utils.renderToBufferedImage(page, targetArea, viewSpec);
+ g.drawImage(img, rect.x, rect.y, null);
+ }
+ } catch (DviException e) {
+ LOGGER.warning(e.toString());
+ e.printStackTrace();
+ paintDummyContents(g, rect, viewSpec);
+ }
+ }
+
+ public void stateChanged(ChangeEvent e)
+ {
+ LOGGER.fine("stateChanged called: EDT=" + SwingUtilities.isEventDispatchThread());
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run()
+ {
+ determineSize();
+ revalidate();
+ repaint();
+ }
+ });
+ }
+
+ private DviLayoutManager layout = new DefaultDviLayoutManager(this, 1);
+
+ public boolean getEnableDelayedRendering()
+ throws DviException
+ {
+ if (layout == null) return true;
+ return layout.getEnableDelayedRendering(this);
+ }
+
+ public DviLayoutManager getDviLayout()
+ {
+ return layout;
+ }
+
+ public void setDviLayout(DviLayoutManager layout)
+ {
+ if (layout == null)
+ throw new NullPointerException("layout");
+ this.layout = layout;
+ }
+
+ protected void setBusy(boolean busy) {
+ this.busy = busy;
+ fireChangeEvent();
+ }
+
+ public boolean isBusy() {
+ return busy;
+ }
+
+ protected EventListenerList listenerList = new EventListenerList();
+
+ public void addChangeListener(ChangeListener l)
+ {
+ listenerList.add(ChangeListener.class, l);
+ }
+
+ public void removeChangeListener(ChangeListener l)
+ {
+ listenerList.remove(ChangeListener.class, l);
+ }
+
+ protected void fireChangeEvent()
+ {
+ ChangeEvent event = null;
+
+ Object[] listeners = listenerList.getListenerList();
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i] == ChangeListener.class) {
+ if (event == null)
+ event = new ChangeEvent(this);
+ ((ChangeListener)listeners[i+1]).stateChanged(event);
+ }
+ }
+ }
+
+}