001/*
002 * SVG Salamander
003 * Copyright (c) 2004, Mark McKay
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or 
007 * without modification, are permitted provided that the following
008 * conditions are met:
009 *
010 *   - Redistributions of source code must retain the above 
011 *     copyright notice, this list of conditions and the following
012 *     disclaimer.
013 *   - Redistributions in binary form must reproduce the above
014 *     copyright notice, this list of conditions and the following
015 *     disclaimer in the documentation and/or other materials 
016 *     provided with the distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
021 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
022 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
029 * OF THE POSSIBILITY OF SUCH DAMAGE. 
030 * 
031 * Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
032 * projects can be found at http://www.kitfox.com
033 *
034 * Created on April 3, 2004, 5:28 PM
035 */
036
037package com.kitfox.svg.app;
038
039
040import com.kitfox.svg.SVGConst;
041import com.kitfox.svg.SVGDiagram;
042import com.kitfox.svg.SVGDisplayPanel;
043import com.kitfox.svg.SVGElement;
044import com.kitfox.svg.SVGException;
045import com.kitfox.svg.SVGUniverse;
046import java.awt.Color;
047import java.awt.event.MouseAdapter;
048import java.awt.event.MouseEvent;
049import java.awt.geom.Point2D;
050import java.io.File;
051import java.io.InputStream;
052import java.net.URI;
053import java.net.URL;
054import java.net.URLEncoder;
055import java.security.AccessControlException;
056import java.util.ArrayList;
057import java.util.List;
058import java.util.logging.Level;
059import java.util.logging.Logger;
060import java.util.regex.Matcher;
061import java.util.regex.Pattern;
062import javax.swing.JFileChooser;
063import javax.swing.JOptionPane;
064
065/**
066 * @author Mark McKay
067 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
068 */
069public class SVGPlayer extends javax.swing.JFrame
070{
071    public static final long serialVersionUID = 1;
072
073    SVGDisplayPanel svgDisplayPanel = new SVGDisplayPanel();
074
075    final PlayerDialog playerDialog;
076    
077    SVGUniverse universe;
078    
079    /** FileChooser for running in trusted environments */
080    final JFileChooser fileChooser;
081    {
082//        fileChooser = new JFileChooser(new File("."));
083        JFileChooser fc = null;
084        try
085        {
086            fc = new JFileChooser();
087            fc.setFileFilter(
088                new javax.swing.filechooser.FileFilter() {
089                    final Matcher matchLevelFile = Pattern.compile(".*\\.svg[z]?").matcher("");
090
091                    @Override
092                    public boolean accept(File file)
093                    {
094                        if (file.isDirectory()) return true;
095
096                        matchLevelFile.reset(file.getName());
097                        return matchLevelFile.matches();
098                    }
099
100                    @Override
101                    public String getDescription() { return "SVG file (*.svg, *.svgz)"; }
102                }
103            );
104        }
105        catch (AccessControlException ex)
106        {
107            //Do not create file chooser if webstart refuses permissions
108        }
109        fileChooser = fc;
110    }
111
112    /** Backup file service for opening files in WebStart situations */
113    /*
114    final FileOpenService fileOpenService;
115    {
116        try 
117        { 
118            fileOpenService = (FileOpenService)ServiceManager.lookup("javax.jnlp.FileOpenService"); 
119        } 
120        catch (UnavailableServiceException e) 
121        { 
122            fileOpenService = null; 
123        } 
124    }
125     */
126    
127    /** Creates new form SVGViewer */
128    public SVGPlayer() {
129        initComponents();
130
131        setSize(800, 600);
132
133        svgDisplayPanel.setBgColor(Color.white);
134        svgDisplayPanel.addMouseListener(new MouseAdapter()
135        {
136            @Override
137            public void mouseClicked(MouseEvent evt)
138            {
139                SVGDiagram diagram = svgDisplayPanel.getDiagram();
140                if (diagram == null) return;
141                
142                System.out.println("Picking at cursor (" + evt.getX() + ", " + evt.getY() + ")");
143                try
144                {
145                    List<List<SVGElement>> paths = diagram.pick(new Point2D.Float(evt.getX(), evt.getY()), null);
146                    for (int i = 0; i < paths.size(); i++)
147                    {
148                        System.out.println(pathToString(paths.get(i)));
149                    }
150                }
151                catch (SVGException ex)
152                {
153                    Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, 
154                        "Could not pick", ex);
155                }
156            }
157        }
158        );
159        
160        svgDisplayPanel.setPreferredSize(getSize());
161        scrollPane_svgArea.setViewportView(svgDisplayPanel);
162        
163        playerDialog = new PlayerDialog(this);
164    }
165    
166    private String pathToString(List<SVGElement> path)
167    {
168        if (path.size() == 0) return "";
169        
170        StringBuffer sb = new StringBuffer();
171        sb.append(path.get(0));
172        for (int i = 1; i < path.size(); i++)
173        {
174            sb.append("/");
175            sb.append(path.get(i).getId());
176        }
177        return sb.toString();
178    }
179    
180    public void updateTime(double curTime)
181    {
182        try
183        {
184            if (universe != null)
185            {
186                universe.setCurTime(curTime);
187                universe.updateTime();
188    //            svgDisplayPanel.updateTime(curTime);
189                repaint();
190            }
191        }
192        catch (Exception e)
193        {
194            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
195        }
196    }
197
198    private void loadURL(URL url)
199    {
200        boolean verbose = cmCheck_verbose.isSelected();
201
202        universe = new SVGUniverse();
203        universe.setVerbose(verbose);
204        SVGDiagram diagram = null;
205
206        if (!CheckBoxMenuItem_anonInputStream.isSelected())
207        {
208            //Load from a disk with a valid URL
209            URI uri = universe.loadSVG(url);
210
211            if (verbose) System.err.println(uri.toString());
212
213            diagram = universe.getDiagram(uri);
214        }
215        else
216        {
217            //Load from a stream with no particular valid URL
218            try
219            {
220                InputStream is = url.openStream();
221                URI uri = universe.loadSVG(is, "defaultName");
222
223                if (verbose) System.err.println(uri.toString());
224
225                diagram = universe.getDiagram(uri);
226            }
227            catch (Exception e)
228            {
229                Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
230            }
231        }
232
233        svgDisplayPanel.setDiagram(diagram);
234        repaint();
235    }
236    
237    /** This method is called from within the constructor to
238     * initialize the form.
239     * WARNING: Do NOT modify this code. The content of this method is
240     * always regenerated by the Form Editor.
241     */
242    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
243    private void initComponents()
244    {
245        scrollPane_svgArea = new javax.swing.JScrollPane();
246        jMenuBar1 = new javax.swing.JMenuBar();
247        menu_file = new javax.swing.JMenu();
248        cm_loadFile = new javax.swing.JMenuItem();
249        cm_loadUrl = new javax.swing.JMenuItem();
250        menu_window = new javax.swing.JMenu();
251        cm_player = new javax.swing.JMenuItem();
252        jSeparator2 = new javax.swing.JSeparator();
253        cm_800x600 = new javax.swing.JMenuItem();
254        CheckBoxMenuItem_anonInputStream = new javax.swing.JCheckBoxMenuItem();
255        cmCheck_verbose = new javax.swing.JCheckBoxMenuItem();
256        menu_help = new javax.swing.JMenu();
257        cm_about = new javax.swing.JMenuItem();
258
259        setTitle("SVG Player - Salamander Project");
260        addWindowListener(new java.awt.event.WindowAdapter()
261        {
262            @Override
263            public void windowClosing(java.awt.event.WindowEvent evt)
264            {
265                exitForm(evt);
266            }
267        });
268
269        getContentPane().add(scrollPane_svgArea, java.awt.BorderLayout.CENTER);
270
271        menu_file.setMnemonic('f');
272        menu_file.setText("File");
273        cm_loadFile.setMnemonic('l');
274        cm_loadFile.setText("Load File...");
275        cm_loadFile.addActionListener(new java.awt.event.ActionListener()
276        {
277            public void actionPerformed(java.awt.event.ActionEvent evt)
278            {
279                cm_loadFileActionPerformed(evt);
280            }
281        });
282
283        menu_file.add(cm_loadFile);
284
285        cm_loadUrl.setText("Load URL...");
286        cm_loadUrl.addActionListener(new java.awt.event.ActionListener()
287        {
288            public void actionPerformed(java.awt.event.ActionEvent evt)
289            {
290                cm_loadUrlActionPerformed(evt);
291            }
292        });
293
294        menu_file.add(cm_loadUrl);
295
296        jMenuBar1.add(menu_file);
297
298        menu_window.setText("Window");
299        cm_player.setText("Player");
300        cm_player.addActionListener(new java.awt.event.ActionListener()
301        {
302            public void actionPerformed(java.awt.event.ActionEvent evt)
303            {
304                cm_playerActionPerformed(evt);
305            }
306        });
307
308        menu_window.add(cm_player);
309
310        menu_window.add(jSeparator2);
311
312        cm_800x600.setText("800 x 600");
313        cm_800x600.addActionListener(new java.awt.event.ActionListener()
314        {
315            public void actionPerformed(java.awt.event.ActionEvent evt)
316            {
317                cm_800x600ActionPerformed(evt);
318            }
319        });
320
321        menu_window.add(cm_800x600);
322
323        CheckBoxMenuItem_anonInputStream.setText("Anonymous Input Stream");
324        menu_window.add(CheckBoxMenuItem_anonInputStream);
325
326        cmCheck_verbose.setText("Verbose");
327        cmCheck_verbose.addActionListener(new java.awt.event.ActionListener()
328        {
329            public void actionPerformed(java.awt.event.ActionEvent evt)
330            {
331                cmCheck_verboseActionPerformed(evt);
332            }
333        });
334
335        menu_window.add(cmCheck_verbose);
336
337        jMenuBar1.add(menu_window);
338
339        menu_help.setText("Help");
340        cm_about.setText("About...");
341        cm_about.addActionListener(new java.awt.event.ActionListener()
342        {
343            public void actionPerformed(java.awt.event.ActionEvent evt)
344            {
345                cm_aboutActionPerformed(evt);
346            }
347        });
348
349        menu_help.add(cm_about);
350
351        jMenuBar1.add(menu_help);
352
353        setJMenuBar(jMenuBar1);
354
355        pack();
356    }// </editor-fold>//GEN-END:initComponents
357
358    private void cm_loadUrlActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadUrlActionPerformed
359    {//GEN-HEADEREND:event_cm_loadUrlActionPerformed
360        String urlStrn = JOptionPane.showInputDialog(this, "Enter URL of SVG file");
361        if (urlStrn == null) return;
362        
363        try
364        {
365            URL url = new URL(URLEncoder.encode(urlStrn, "UTF-8"));
366            loadURL(url);
367        }
368        catch (Exception e)
369        {
370            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
371        }
372
373    }//GEN-LAST:event_cm_loadUrlActionPerformed
374
375    private void cmCheck_verboseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cmCheck_verboseActionPerformed
376    {//GEN-HEADEREND:event_cmCheck_verboseActionPerformed
377// TODO add your handling code here:
378    }//GEN-LAST:event_cmCheck_verboseActionPerformed
379
380    private void cm_playerActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_playerActionPerformed
381    {//GEN-HEADEREND:event_cm_playerActionPerformed
382        playerDialog.setVisible(true);
383    }//GEN-LAST:event_cm_playerActionPerformed
384
385    private void cm_aboutActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_aboutActionPerformed
386    {//GEN-HEADEREND:event_cm_aboutActionPerformed
387        VersionDialog dia = new VersionDialog(this, true, cmCheck_verbose.isSelected());
388        dia.setVisible(true);
389//        JOptionPane.showMessageDialog(this, "Salamander SVG - Created by Mark McKay\nhttp://www.kitfox.com");
390    }//GEN-LAST:event_cm_aboutActionPerformed
391
392    private void cm_800x600ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cm_800x600ActionPerformed
393        setSize(800, 600);
394    }//GEN-LAST:event_cm_800x600ActionPerformed
395    
396    private void cm_loadFileActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadFileActionPerformed
397    {//GEN-HEADEREND:event_cm_loadFileActionPerformed
398        boolean verbose = cmCheck_verbose.isSelected();
399        
400        try
401        {
402            int retVal = fileChooser.showOpenDialog(this);
403            if (retVal == JFileChooser.APPROVE_OPTION)
404            {
405                File chosenFile = fileChooser.getSelectedFile();
406
407                URL url = chosenFile.toURI().toURL();
408
409                loadURL(url);
410            }
411        }
412        catch (Exception e)
413        {
414            Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
415        }
416
417    }//GEN-LAST:event_cm_loadFileActionPerformed
418
419    /** Exit the Application */
420    private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
421        System.exit(0);
422    }//GEN-LAST:event_exitForm
423
424    /**
425     * @param args the command line arguments
426     */
427    public static void main(String args[]) {
428        new SVGPlayer().setVisible(true);
429    }
430
431    public void updateTime(double curTime, double timeStep, int playState)
432    {
433    }
434    
435    // Variables declaration - do not modify//GEN-BEGIN:variables
436    private javax.swing.JCheckBoxMenuItem CheckBoxMenuItem_anonInputStream;
437    private javax.swing.JCheckBoxMenuItem cmCheck_verbose;
438    private javax.swing.JMenuItem cm_800x600;
439    private javax.swing.JMenuItem cm_about;
440    private javax.swing.JMenuItem cm_loadFile;
441    private javax.swing.JMenuItem cm_loadUrl;
442    private javax.swing.JMenuItem cm_player;
443    private javax.swing.JMenuBar jMenuBar1;
444    private javax.swing.JSeparator jSeparator2;
445    private javax.swing.JMenu menu_file;
446    private javax.swing.JMenu menu_help;
447    private javax.swing.JMenu menu_window;
448    private javax.swing.JScrollPane scrollPane_svgArea;
449    // End of variables declaration//GEN-END:variables
450
451}