/* * @(#)SVGApplet.java * * Copyright (c) 2006-2010 The authors and contributors of JHotDraw. * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.samples.svg; import org.jhotdraw.draw.io.InputFormat; import org.jhotdraw.draw.io.ImageOutputFormat; import org.jhotdraw.draw.io.ImageInputFormat; import org.jhotdraw.io.BoundedRangeInputStream; import java.applet.AppletContext; import org.jhotdraw.draw.*; import org.jhotdraw.gui.*; import org.jhotdraw.util.*; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.io.*; import java.net.*; import java.util.*; import javax.swing.*; import javax.swing.border.MatteBorder; import org.jhotdraw.samples.svg.figures.SVGImageFigure; import org.jhotdraw.samples.svg.gui.MessagePanel; import org.jhotdraw.samples.svg.gui.ProgressIndicator; import org.jhotdraw.samples.svg.io.SVGOutputFormat; import org.jhotdraw.samples.svg.io.SVGZInputFormat; import org.jhotdraw.samples.svg.io.SVGZOutputFormat; /** * This is the base class for concrete implementations of SVG drawing * applets. * <p> * The base class loads and saves drawings asynchronously and handles * errors. The actual data transmission and the editing of drawings * is the responsibility of the subclasses. * <p> * FIXME - Applet must offer to save file locally, if uploading to server * failed. * <p> * FIXME - Applet must save changes locally and reload them, if the user * navigated out of the page and back again, without saving the changes. * * @author Werner Randelshofer * @version $Id$ */ public class SVGApplet extends JApplet { private static final long serialVersionUID = 1L; private SVGDrawingPanel drawingComponent; /** * Lazily initialized in method getVersion(); */ private String version; private long start; public SVGApplet() { setBackground(Color.WHITE); start = System.currentTimeMillis(); setName("JHotDraw SVG Applet " + getClass().getPackage().getImplementationVersion()); ((JComponent) getContentPane()).setBorder(new MatteBorder(new Insets(1, 1, 1, 1), new Color(0xa5a5a5))); //ResourceBundleUtil.setVerbose(true); } /** * Same as <code>Applet.getParameter()</code> but doesn't throw a * NullPointerException when used without an Applet context. */ @Override public String getParameter(String name) { try { return super.getParameter(name); } catch (NullPointerException e) { return null; } } /** * Same as <code>Applet.getParameter()</code> but doesn't throw a * NullPointerException when used without an Applet context. */ public String getParameter(String name, String defaultValue) { try { String value = super.getParameter(name); return (value == null) ? defaultValue : value; } catch (NullPointerException e) { return defaultValue; } } /** * Displays a progress indicator and then invokes <code>loadDrawing</code> * on a worker thread. Displays the drawing panel when done successfully. * Displays an error message when done unsuccessfully. * * @see #loadDrawing */ @Override public final void init() { // set the language of the applet if (getParameter("Locale") != null) { Locale.setDefault(new Locale(getParameter("Locale"))); } final ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.samples.svg.Labels"); // Set look and feel // ----------------- try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Throwable e) { // Do nothing. // If we can't set the desired look and feel, UIManager does // automaticaly the right thing for us. } // Set our own popup factory, because the one that comes with Mac OS X // creates translucent popups which is not useful for color selection // using pop menus. try { PopupFactory.setSharedInstance(new PopupFactory()); } catch (Throwable e) { // If we can't set the popup factory, we have to use what is there. } // Display a progress indicator while we are loading the drawing // ---------------------------------------------------------- Container c = getContentPane(); final ProgressIndicator progress = new ProgressIndicator( getName(), labels.getString("progressInitializing")); c.add(progress); progress.revalidate(); // Load the drawing using a worker thread // -------------------------------------- new Worker<Drawing>() { @Override protected Drawing construct() throws Exception { Thread t = new Thread() { @Override public void run() { drawingComponent = createDrawingComponent(); } }; t.start(); progress.setNote(labels.getString("progressLoading")); Drawing drawing = loadDrawing(progress); progress.setNote(labels.getString("progressOpeningEditor")); progress.setIndeterminate(true); t.join(); return drawing; } @Override protected void done(Drawing result) { Container c = getContentPane(); c.setLayout(new BorderLayout()); c.removeAll(); c.add(drawingComponent.getComponent()); initComponents(); if (result != null) { setDrawing(result); } drawingComponent.revalidate(); } @Override protected void failed(Throwable result) { Container c = getContentPane(); c.setLayout(new BorderLayout()); c.removeAll(); Throwable error = result; error.printStackTrace(); String message = (error.getMessage() == null) ? error.toString() : error.getMessage(); MessagePanel mp = new MessagePanel( UIManager.getIcon("OptionPane.errorIcon"), labels.getFormatted("messageLoadFailed", htmlencode(getParameter("DrawingURL")), htmlencode(message))); c.add(mp); mp.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { if ("close".equals(evt.getActionCommand())) { close(); } } }); mp.revalidate(); } @Override protected void finished() { long end = System.currentTimeMillis(); System.out.println("AbstractDrawingApplet startup latency:" + (end - start)); } }.start(); } /** * Sets the drawing on the drawing panel. */ private void setDrawing(Drawing d) { drawingComponent.setDrawing(d); } /** * Gets the drawing from the drawing panel. */ private Drawing getDrawing() { return drawingComponent.getDrawing(); } /** * Gets the version of the applet. */ public String getVersion() { if (version == null) { BufferedReader r = null; try { InputStream resource = SVGApplet.class.getResourceAsStream("version.txt"); r = new BufferedReader(new InputStreamReader(resource, "UTF-8")); version = r.readLine(); } catch (IOException e) { version = "unknown"; } catch (NullPointerException e) { version = "unknown"; } finally { if (r != null) { try { r.close(); } catch (IOException e) { // suppress } } } } return version; } /** * Returns information about the applet. */ @Override public String getAppletInfo() { return getName() + "\nVersion " + getVersion() + "\n\nCopyright 1996-2010 (c) by the original authors of JHotDraw and all its contributors" + "\nThis software is licensed under LGPL or" + "\nCreative Commons 2.5 BY"; } /** * Creates the drawing. */ /** * Creates the drawing. */ protected Drawing createDrawing() { DefaultDrawing drawing = new DefaultDrawing(); drawing.addInputFormat(new SVGZInputFormat()); drawing.addInputFormat(new ImageInputFormat(new SVGImageFigure())); drawing.addOutputFormat(new SVGOutputFormat()); drawing.addOutputFormat(new SVGZOutputFormat()); drawing.addOutputFormat(new ImageOutputFormat()); drawing.addOutputFormat(new ImageOutputFormat("JPG", "Joint Photographics Experts Group (JPEG)", "jpg", BufferedImage.TYPE_INT_RGB)); drawing.addOutputFormat(new ImageOutputFormat("BMP", "Windows Bitmap (BMP)", "bmp", BufferedImage.TYPE_BYTE_INDEXED)); return drawing; } /** * Creates the drawing component. */ protected SVGDrawingPanel createDrawingComponent() { SVGDrawingPanel p = new SVGDrawingPanel(); p.setEditor(new DefaultDrawingEditor()); return p; } protected SVGDrawingPanel getDrawingComponent() { return drawingComponent; } @Override public String[][] getParameterInfo() { return new String[][]{ {"data", "String", "the data to be displayed by this applet."}, {"datafile", "URL", "an URL to a file containing the data to be displayed by this applet."}}; } /** * Loads the drawing. * By convention this method is invoked on a worker thread. * * @param progress A ProgressIndicator to inform the user about the progress * of the operation. * @return The Drawing that was loaded. */ protected Drawing loadDrawing(ProgressIndicator progress) throws IOException { Drawing drawing = createDrawing(); if (getParameter("datafile") != null) { URL url = new URL(getDocumentBase(), getParameter("datafile")); URLConnection uc = url.openConnection(); // Disable caching. This ensures that we always request the // newest version of the drawing from the server. // (Note: The server still needs to set the proper HTTP caching // properties to prevent proxies from caching the drawing). if (uc instanceof HttpURLConnection) { ((HttpURLConnection) uc).setUseCaches(false); } // Read the data into a buffer int contentLength = uc.getContentLength(); InputStream in = uc.getInputStream(); try { if (contentLength != -1) { in = new BoundedRangeInputStream(in); ((BoundedRangeInputStream) in).setMaximum(contentLength + 1); progress.setProgressModel((BoundedRangeModel) in); progress.setIndeterminate(false); } BufferedInputStream bin = new BufferedInputStream(in); bin.mark(512); // Read the data using all supported input formats // until we succeed IOException formatException = null; for (InputFormat format : drawing.getInputFormats()) { try { bin.reset(); } catch (IOException e) { uc = url.openConnection(); in = uc.getInputStream(); in = new BoundedRangeInputStream(in); ((BoundedRangeInputStream) in).setMaximum(contentLength + 1); progress.setProgressModel((BoundedRangeModel) in); bin = new BufferedInputStream(in); bin.mark(512); } try { bin.reset(); format.read(bin, drawing, true); formatException = null; break; } catch (IOException e) { formatException = e; } } if (formatException != null) { throw formatException; } } finally { in.close(); } } return drawing; } /** * Closes the applet. This method can be implemented by invoking * <code>getAppletContext().showDocument(...)</code>. */ protected void close() { AppletContext appletContext; try { appletContext = getAppletContext(); } catch (Throwable e) { appletContext = null; } if (appletContext == null) { System.exit(0); } else { try { appletContext.showDocument(new URL(getDocumentBase(), getParameter("PageURL"))); } catch (MalformedURLException ex) { ex.printStackTrace(); } } } /** * Escapes all '<', '>' and '&' characters in a string. * @param str A String. * @return HTMlEncoded String. */ private static String htmlencode(String str) { if (str == null) { return ""; } else { StringBuilder buf = new StringBuilder(); for (char ch : str.toCharArray()) { switch (ch) { case '<': buf.append("<"); break; case '>': buf.append(">"); break; case '&': buf.append("&"); break; default: buf.append(ch); break; } } return buf.toString(); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame f = new JFrame("JHotDraw SVG Sample Applet"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); SVGApplet a = new SVGApplet(); f.getContentPane().add(a); a.init(); f.setSize(500, 300); f.setVisible(true); a.start(); } }); } /** This method is called from within the init() method to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables }