Coverage Report - org.argouml.uml.ui.SaveGraphicsManager
 
Classes in this File Line Coverage Branch Coverage Complexity
SaveGIFAction2
0%
0/6
N/A
2.138
SaveGraphicsManager
60%
47/78
38%
13/34
2.138
SaveGraphicsManager$1
0%
0/2
N/A
2.138
SaveGraphicsManager$FileFilterChangedListener
44%
4/9
N/A
2.138
SaveGraphicsManager$FileFilterChangedListener$Anonymous1
0%
0/5
N/A
2.138
SavePNGAction2
78%
15/19
25%
1/4
2.138
SaveSVGAction2
0%
0/40
0%
0/16
2.138
SaveScaledEPSAction
0%
0/13
N/A
2.138
 
 1  
 /* $Id: SaveGraphicsManager.java 17881 2010-01-12 21:09:28Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    bobtarling
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2005-2008 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.uml.ui;
 40  
 
 41  
 import java.awt.Rectangle;
 42  
 import java.awt.event.ActionEvent;
 43  
 import java.awt.image.BufferedImage;
 44  
 import java.awt.image.RenderedImage;
 45  
 import java.beans.PropertyChangeEvent;
 46  
 import java.beans.PropertyChangeListener;
 47  
 import java.io.File;
 48  
 import java.io.IOException;
 49  
 import java.io.OutputStream;
 50  
 import java.util.ArrayList;
 51  
 import java.util.Collections;
 52  
 import java.util.Comparator;
 53  
 import java.util.Iterator;
 54  
 import java.util.List;
 55  
 
 56  
 import javax.imageio.ImageIO;
 57  
 import javax.swing.Icon;
 58  
 import javax.swing.JFileChooser;
 59  
 import javax.swing.SwingUtilities;
 60  
 import javax.xml.parsers.ParserConfigurationException;
 61  
 
 62  
 import org.apache.log4j.Logger;
 63  
 import org.argouml.configuration.Configuration;
 64  
 import org.argouml.configuration.ConfigurationKey;
 65  
 import org.argouml.gefext.DeferredBufferedImage;
 66  
 import org.argouml.i18n.Translator;
 67  
 import org.argouml.model.Model;
 68  
 import org.argouml.util.FileFilters;
 69  
 import org.argouml.util.SuffixFilter;
 70  
 import org.tigris.gef.base.Editor;
 71  
 import org.tigris.gef.base.Globals;
 72  
 import org.tigris.gef.base.Layer;
 73  
 import org.tigris.gef.base.SaveEPSAction;
 74  
 import org.tigris.gef.base.SaveGIFAction;
 75  
 import org.tigris.gef.base.SaveGraphicsAction;
 76  
 import org.tigris.gef.base.SavePNGAction;
 77  
 import org.tigris.gef.base.SavePSAction;
 78  
 import org.tigris.gef.base.SaveSVGAction;
 79  
 import org.tigris.gef.persistence.SvgWriter2D;
 80  
 import org.tigris.gef.persistence.export.PostscriptWriter;
 81  
 import org.tigris.gef.presentation.Fig;
 82  
 import org.tigris.gef.util.Localizer;
 83  
 
 84  
 
 85  
 /**
 86  
  * This class has some similar functions like PersistenceManager. <p>
 87  
  *
 88  
  * It centralizes all knowledge about the different graphical formats.
 89  
  * This class is the only one that is supposed to know
 90  
  * the complete list of supported graphics formats.
 91  
  *
 92  
  * @author mvw@tigris.org
 93  
  */
 94  
 public final class SaveGraphicsManager {
 95  
 
 96  
     private static final int MIN_MARGIN = 15;
 97  
     
 98  
     /**
 99  
      * The configuration key for the preferred graphics format.
 100  
      */
 101  85
     public static final ConfigurationKey KEY_DEFAULT_GRAPHICS_FILTER =
 102  
         Configuration.makeKey("graphics", "default", "filter");
 103  
 
 104  
     /**
 105  
      * The configuration key for the "save graphics" file location.
 106  
      */
 107  85
     public static final ConfigurationKey KEY_SAVE_GRAPHICS_PATH =
 108  
         Configuration.makeKey("graphics", "save", "path");
 109  
 
 110  
     /**
 111  
      * The configuration key for the "save all graphics" file location.
 112  
      */
 113  85
     public static final ConfigurationKey KEY_SAVEALL_GRAPHICS_PATH =
 114  
         Configuration.makeKey("graphics", "save-all", "path");
 115  
 
 116  
     /**
 117  
      * The configuration key for the export graphics resolution.
 118  
      */
 119  85
     public static final ConfigurationKey KEY_GRAPHICS_RESOLUTION =
 120  
         Configuration.makeKey("graphics", "export", "resolution");
 121  
 
 122  
     /**
 123  
      * The default file format.
 124  
      */
 125  
     private SuffixFilter defaultFilter;
 126  
 
 127  
     /**
 128  
      * The list of other file formats.
 129  
      */
 130  75
     private List<SuffixFilter> otherFilters = new ArrayList<SuffixFilter>();
 131  
 
 132  
     /**
 133  
      * The singleton instance.
 134  
      */
 135  
     private static SaveGraphicsManager instance;
 136  
 
 137  
     /**
 138  
      * The constructor.
 139  
      */
 140  75
     private SaveGraphicsManager() {
 141  75
         defaultFilter = FileFilters.PNG_FILTER;
 142  75
         otherFilters.add(FileFilters.GIF_FILTER);
 143  75
         otherFilters.add(FileFilters.SVG_FILTER);
 144  75
         otherFilters.add(FileFilters.PS_FILTER);
 145  75
         otherFilters.add(FileFilters.EPS_FILTER);
 146  75
         setDefaultFilterBySuffix(Configuration.getString(
 147  
                 KEY_DEFAULT_GRAPHICS_FILTER,
 148  
                 defaultFilter.getSuffix()));
 149  75
     }
 150  
 
 151  
     /**
 152  
      * @param suffix the extension of the new default file-format
 153  
      */
 154  
     public void setDefaultFilterBySuffix(String suffix) {
 155  75
         for (SuffixFilter sf : otherFilters) {
 156  300
             if (sf.getSuffix().equalsIgnoreCase(suffix)) {
 157  0
                 setDefaultFilter(sf);
 158  0
                 break;
 159  
             }
 160  
         }
 161  75
     }
 162  
 
 163  
     /**
 164  
      * @param f the new default file-format
 165  
      */
 166  
     public void setDefaultFilter(SuffixFilter f) {
 167  0
         otherFilters.remove(f);
 168  0
         if (!otherFilters.contains(defaultFilter)) {
 169  0
             otherFilters.add(defaultFilter);
 170  
         }
 171  0
         defaultFilter = f;
 172  0
         Configuration.setString(
 173  
                 KEY_DEFAULT_GRAPHICS_FILTER,
 174  
                 f.getSuffix());
 175  
 
 176  0
         Collections.sort(otherFilters, new Comparator<SuffixFilter>() {
 177  
             public int compare(SuffixFilter arg0, SuffixFilter arg1) {
 178  0
                 return arg0.getSuffix().compareToIgnoreCase(
 179  
                         arg1.getSuffix());
 180  
             }
 181  
         });
 182  0
     }
 183  
 
 184  
     /**
 185  
      * @return returns the singleton
 186  
      */
 187  
     public static SaveGraphicsManager getInstance() {
 188  80
         if (instance == null) {
 189  75
             instance  = new SaveGraphicsManager();
 190  
         }
 191  80
         return instance;
 192  
     }
 193  
 
 194  
     /**
 195  
      * This function allows to add new filters. This can be done e.g.
 196  
      * by modules.<p>
 197  
      *
 198  
      * @param f the filter
 199  
      */
 200  
     public void register(SuffixFilter f) {
 201  0
         otherFilters.add(f);
 202  0
     }
 203  
 
 204  
     /**
 205  
      * @param chooser the filechooser of which the filters will be set
 206  
      * @param defaultName default filename to show when chooser is displayed
 207  
      */
 208  
     public void setFileChooserFilters(
 209  
             JFileChooser chooser, String defaultName) {
 210  55
         chooser.addChoosableFileFilter(defaultFilter);
 211  55
         Iterator iter = otherFilters.iterator();
 212  275
         while (iter.hasNext()) {
 213  220
             chooser.addChoosableFileFilter((SuffixFilter) iter.next());
 214  
         }
 215  55
         chooser.setFileFilter(defaultFilter);
 216  55
         String fileName = defaultName + "." + defaultFilter.getSuffix();
 217  55
         chooser.setSelectedFile(new File(fileName));
 218  55
         chooser.addPropertyChangeListener(
 219  
                 JFileChooser.FILE_FILTER_CHANGED_PROPERTY,
 220  
                 new FileFilterChangedListener(chooser, defaultName));
 221  55
     }
 222  
 
 223  
     /**
 224  
      * This class listens to changes in the selected filefilter.
 225  
      * If the user changes the filefilter
 226  
      * (e.g. he changes from *.gif to *.png),
 227  
      * then the filename field got emptied before I introduced this class.
 228  
      * Now, a new filename is made up, based on
 229  
      * the diagram name + the new extension (suffix).
 230  
      *
 231  
      * @author mvw@tigris.org
 232  
      */
 233  0
     static class FileFilterChangedListener implements PropertyChangeListener {
 234  
         private JFileChooser chooser;
 235  
         private String defaultName;
 236  
 
 237  
         /**
 238  
          * Constructor.
 239  
          * @param c
 240  
          * @param name
 241  
          */
 242  55
         public FileFilterChangedListener(JFileChooser c, String name) {
 243  55
             chooser = c;
 244  55
             defaultName = name;
 245  55
         }
 246  
 
 247  
         /*
 248  
          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
 249  
          */
 250  
         public void propertyChange(PropertyChangeEvent evt) {
 251  0
             SuffixFilter filter = (SuffixFilter) evt.getNewValue();
 252  0
             String fileName = defaultName + "." + filter.getSuffix();
 253  
             /* The next line does not work: */
 254  
             // chooser.setSelectedFile(new File(fileName));
 255  
             /* So, let's do it the hard way: */
 256  0
             SwingUtilities.invokeLater(new Anonymous1(fileName));
 257  0
         }
 258  
 
 259  
         class Anonymous1 implements Runnable {
 260  
             private String fileName;
 261  
             /**
 262  
              * Constructor.
 263  
              *
 264  
              * @param fn The filename.
 265  
              */
 266  0
             Anonymous1(String fn) {
 267  0
                 fileName = fn;
 268  0
             }
 269  
 
 270  
             /*
 271  
              * @see java.lang.Runnable#run()
 272  
              */
 273  
             public void run() {
 274  0
                 chooser.setSelectedFile(new File(fileName));
 275  0
             }
 276  
         }
 277  
     }
 278  
 
 279  
     /**
 280  
      * @param name the filename
 281  
      * @return the filter
 282  
      */
 283  
     public SuffixFilter getFilterFromFileName(String name) {
 284  0
         if (name.toLowerCase()
 285  
             .endsWith("." + defaultFilter.getSuffix())) {
 286  0
             return defaultFilter;
 287  
         }
 288  0
         Iterator iter = otherFilters.iterator();
 289  0
         while (iter.hasNext()) {
 290  0
             SuffixFilter filter = (SuffixFilter) iter.next();
 291  0
             if (name.toLowerCase().endsWith("." + filter.getSuffix())) {
 292  0
                 return filter;
 293  
             }
 294  0
         }
 295  0
         return null;
 296  
     }
 297  
 
 298  
     /**
 299  
      * @return the extension of the default filter
 300  
      *         (just the text, not the ".")
 301  
      */
 302  
     public String getDefaultSuffix() {
 303  4
         return defaultFilter.getSuffix();
 304  
     }
 305  
 
 306  
     /**
 307  
      * @param in the input file or path name which may or may not
 308  
      *           have a recognised extension
 309  
      * @return the amended file or pathname, guaranteed to have
 310  
      *         a recognised extension
 311  
      */
 312  
     public String fixExtension(String in) {
 313  0
         if (getFilterFromFileName(in) == null) {
 314  0
             in += "." + getDefaultSuffix();
 315  
         }
 316  0
         return in;
 317  
     }
 318  
 
 319  
 
 320  
     /**
 321  
      * @param suffix the suffix (extension) of the filename,
 322  
      *               which corresponds to the graphics format to be used
 323  
      * @return the action that will do the save
 324  
      */
 325  
     public SaveGraphicsAction getSaveActionBySuffix(String suffix) {
 326  2
         SaveGraphicsAction cmd = null;
 327  2
         if (FileFilters.PS_FILTER.getSuffix().equals(suffix)) {
 328  0
             cmd = new SavePSAction(Translator.localize("action.save-ps"));
 329  2
         } else if (FileFilters.EPS_FILTER.getSuffix().equals(suffix)) {
 330  0
             cmd = new SaveScaledEPSAction(
 331  
                     Translator.localize("action.save-eps"));
 332  2
         } else if (FileFilters.PNG_FILTER.getSuffix().equals(suffix)) {
 333  2
             cmd = new SavePNGAction2(Translator.localize("action.save-png"));
 334  0
         } else if (FileFilters.GIF_FILTER.getSuffix().equals(suffix)) {
 335  0
             cmd = new SaveGIFAction(Translator.localize("action.save-gif"));
 336  
             // TODO: The following can be used when we drop Java 5 support or
 337  
             // when an ImageIO GIF writer plugin is bundled
 338  
 //            cmd = new SaveGIFAction2(Translator.localize("action.save-gif"));
 339  0
         } else if (FileFilters.SVG_FILTER.getSuffix().equals(suffix)) {
 340  
             // TODO: Use the SVGWriter2D implementation
 341  
 //            cmd = new SaveSVGAction2(Translator.localize("action.save-svg"));
 342  0
             cmd = new SaveSVGAction(Translator.localize("action.save-svg"));
 343  
         }
 344  2
         return cmd;
 345  
     }
 346  
     
 347  
 
 348  
     /**
 349  
      * @return the complete collection of SuffixFilters,
 350  
      *         the first one is the default one
 351  
      */
 352  
     public List<SuffixFilter> getSettingsList() {
 353  19
         List<SuffixFilter> c = new ArrayList<SuffixFilter>();
 354  19
         c.add(defaultFilter);
 355  19
         c.addAll(otherFilters);
 356  19
         return c;
 357  
     }
 358  
     
 359  
     /**
 360  
      * Adjust the drawing area so that instead of a tight bounding box, it
 361  
      * includes the canvas origin and some space around the lower and right
 362  
      * sides so that the elements will be roughly centered. Elements which are
 363  
      * off the top or left side of the canvas may still be clipped (ie if the
 364  
      * original drawing area had a negative x or y coordinate).
 365  
      * 
 366  
      * @param area rectangle representing original drawing area
 367  
      * @return an expanded rectangle
 368  
      */
 369  
     static Rectangle adjustDrawingArea(Rectangle area) {
 370  2
         int xMargin = area.x;
 371  2
         if (xMargin < 0) {
 372  0
             xMargin = 0;
 373  
         }
 374  2
         int yMargin = area.y;
 375  2
         if (yMargin < 0) {
 376  0
             yMargin = 0;
 377  
         }
 378  2
         int margin = Math.max(xMargin, yMargin);
 379  2
         if (margin < MIN_MARGIN) {
 380  2
             margin = MIN_MARGIN;
 381  
         }
 382  2
         return new Rectangle(0, 0, 
 383  
                 area.width + (2 * margin), 
 384  
                 area.height + (2 * margin));
 385  
     }
 386  
 }
 387  
 
 388  
 
 389  
 class SaveScaledEPSAction extends SaveEPSAction {
 390  
     
 391  
     SaveScaledEPSAction(String name) {
 392  0
         super(name);
 393  0
     }
 394  
 
 395  
     @Override
 396  
     protected void saveGraphics(OutputStream s, Editor ce,
 397  
                                 Rectangle drawingArea)
 398  
         throws IOException {
 399  
 
 400  0
         double editorScale = ce.getScale();
 401  0
         int x = (int) (drawingArea.x * editorScale);
 402  0
         int y = (int) (drawingArea.y * editorScale);
 403  0
         int h = (int) (drawingArea.height * editorScale);
 404  0
         int w = (int) (drawingArea.width * editorScale);
 405  0
         drawingArea = new Rectangle(x, y, w, h);
 406  
 
 407  0
         PostscriptWriter ps = new PostscriptWriter(s, drawingArea);
 408  
 
 409  0
         ps.scale(editorScale, editorScale);
 410  
 
 411  0
         ce.print(ps);
 412  0
         ps.dispose();
 413  0
     }
 414  
 
 415  
 }
 416  
 
 417  
 /**
 418  
  * Write out a PNG image of the current diagram using a more memory efficient
 419  
  * scheme than GEF uses.
 420  
  * 
 421  
  * @author Tom Morris <tfmorris@gmail.com>
 422  
  */
 423  
 class SavePNGAction2 extends SavePNGAction {
 424  
     
 425  1
     private static final Logger LOG = Logger.getLogger(SavePNGAction2.class);
 426  
     
 427  
     SavePNGAction2(String name) {
 428  2
         super(name);
 429  2
     }
 430  
 
 431  
     @Override
 432  
     public void actionPerformed(ActionEvent ae) {
 433  2
         Editor ce = Globals.curEditor();
 434  2
         Rectangle drawingArea = 
 435  
             ce.getLayerManager().getActiveLayer().calcDrawingArea();
 436  
         // If the diagram is empty, GEF won't write anything, leaving us with
 437  
         // an empty (and invalid) file.  Handle this case ourselves to prevent
 438  
         // this from happening.
 439  2
         if (drawingArea.width <= 0 || drawingArea.height <= 0) {
 440  2
             Rectangle dummyArea = new Rectangle(0, 0, 50, 50);
 441  
             try {
 442  2
                 saveGraphics(outputStream, ce, dummyArea);
 443  0
             } catch (java.io.IOException e) {
 444  0
                 LOG.error("Error while exporting Graphics:", e);
 445  2
             }
 446  2
             return;
 447  
         }
 448  
         
 449  
         // Anything else is handled the normal way
 450  0
         super.actionPerformed(ae);
 451  0
     }
 452  
 
 453  
     /**
 454  
      * Write the diagram contained by the current editor into an OutputStream as
 455  
      * a PNG image.
 456  
      */
 457  
     @Override
 458  
     protected void saveGraphics(OutputStream s, Editor ce, 
 459  
             Rectangle drawingArea)
 460  
         throws IOException {
 461  
 
 462  2
         Rectangle canvasArea = 
 463  
             SaveGraphicsManager.adjustDrawingArea(drawingArea);
 464  
         
 465  
         // Create an image which will do deferred rendering of the GEF
 466  
         // diagram on demand as data is pulled from it 
 467  2
         RenderedImage i = new DeferredBufferedImage(canvasArea,
 468  
                 BufferedImage.TYPE_INT_ARGB, ce, scale);
 469  
 
 470  2
         LOG.debug("Created DeferredBufferedImage - drawingArea = "
 471  
                 + canvasArea + " , scale = " + scale);
 472  
         
 473  2
         ImageIO.write(i, "png", s);
 474  
 
 475  2
     }
 476  
     
 477  
 
 478  
 }
 479  
 
 480  
 /**
 481  
  * Action to save a diagram as a GIF image in a supplied OutputStream. 
 482  
  * 
 483  
  * TODO: This requires Java 6 in its current state, so don't use.
 484  
  * 
 485  
  * @author Tom Morris <tfmorris@gmail.com>
 486  
  */
 487  
 class SaveGIFAction2 extends SaveGIFAction {
 488  
 
 489  
     /**
 490  
      * Creates a new SaveGIFAction
 491  
      * 
 492  
      * @param name The name of the action
 493  
      */
 494  
     SaveGIFAction2(String name) {
 495  0
         super(name);
 496  0
     }
 497  
 
 498  
 
 499  
     /**
 500  
      * Write the diagram contained by the current editor into an OutputStream as
 501  
      * a GIF image.
 502  
      */
 503  
     @Override
 504  
     protected void saveGraphics(OutputStream s, Editor ce, 
 505  
             Rectangle drawingArea) throws IOException {
 506  
 
 507  0
         Rectangle canvasArea = 
 508  
             SaveGraphicsManager.adjustDrawingArea(drawingArea);
 509  
         
 510  0
         RenderedImage i = new DeferredBufferedImage(canvasArea,
 511  
                 BufferedImage.TYPE_INT_ARGB, ce, scale);
 512  
 
 513  
         // NOTE: GEF's GIF writer uses Jeff Poskanzer's GIF encoder, but that
 514  
         // saves a copy of the entire image in an internal buffer before
 515  
         // starting work, defeating the whole purpose of our incremental 
 516  
         // rendering.
 517  
         
 518  
         // Java SE 6 has a native GIF writer, but it's not in Java 5.  One
 519  
         // is available in the JAI-ImageIO library, but we don't currently
 520  
         // bundle that and at 6+ MB it seems like a heavyweight solution, but
 521  
         // I don't have time to produce a stripped down version right now - tfm
 522  
         // https://jai-imageio.dev.java.net/
 523  
 
 524  0
         ImageIO.write(i, "gif", s);
 525  
 
 526  0
     }
 527  
 
 528  
 }
 529  
 
 530  
 class SaveSVGAction2 extends SaveGraphicsAction {
 531  
 
 532  
     /**
 533  
      * Creates a new SaveSVGAction
 534  
      * 
 535  
      * @param name
 536  
      *                The name of the action
 537  
      */
 538  
     public SaveSVGAction2(String name) {
 539  0
         this(name, false);
 540  0
     }
 541  
 
 542  
     /**
 543  
      * Creates a new SaveSVGAction
 544  
      * 
 545  
      * @param name
 546  
      *                The name of the action
 547  
      * @param icon
 548  
      *                The icon of the action
 549  
      */
 550  
     public SaveSVGAction2(String name, Icon icon) {
 551  0
         this(name, icon, false);
 552  0
     }
 553  
 
 554  
     /**
 555  
      * Creates a new SaveSVGAction
 556  
      * 
 557  
      * @param name
 558  
      *                The name of the action
 559  
      * @param localize
 560  
      *                Whether to localize the name or not
 561  
      */
 562  
     public SaveSVGAction2(String name, boolean localize) {
 563  0
         super(localize ? Localizer.localize("GefBase", name) : name);
 564  0
     }
 565  
 
 566  
     /**
 567  
      * Creates a new SaveSVGAction
 568  
      * 
 569  
      * @param name
 570  
      *                The name of the action
 571  
      * @param icon
 572  
      *                The icon of the action
 573  
      * @param localize
 574  
      *                Whether to localize the name or not
 575  
      */
 576  
     public SaveSVGAction2(String name, Icon icon, boolean localize) {
 577  0
         super(localize ? Localizer.localize("GefBase", name) : name, icon);
 578  0
     }
 579  
 
 580  
     protected void saveGraphics(OutputStream s, Editor ce, 
 581  
                     Rectangle drawingArea)
 582  
         throws IOException {
 583  
 
 584  
 //        LayerPerspective layer = DiagramUtils.getActiveDiagram().getLayer();
 585  0
         Layer layer = ce.getLayerManager().getActiveLayer();
 586  
 
 587  0
         Rectangle bounds = new Rectangle();
 588  0
         for (Fig fig : layer.getContents()) {
 589  0
             bounds.x = Math.min(bounds.x, fig.getX());
 590  0
             bounds.y = Math.min(bounds.y, fig.getY());
 591  
             // we actually are computing max x & max y, not width & height
 592  0
             bounds.width = Math.max(bounds.width, fig.getX() + fig.getWidth());
 593  0
             bounds.height = Math.max(bounds.height, 
 594  
                     fig.getY() + fig.getHeight());
 595  
         }
 596  
         
 597  
         // Convert max x/y to width/height
 598  0
         bounds.width -= bounds.x;
 599  0
         bounds.height -= bounds.y;
 600  
         
 601  0
             SvgWriter2D writer = null;
 602  
             try {
 603  
             // TODO: Do we want the current view or the entire diagram?
 604  
 //                drawingArea.width /= ce.getScale();
 605  
 //            drawingArea.height /= ce.getScale();
 606  
 //            writer = new SvgWriter2D(s, drawingArea);
 607  0
             writer = new SvgWriter2D(s, bounds);
 608  0
         } catch (ParserConfigurationException e) {
 609  
 //            LOG.error("Exception creating SVG writer", e);
 610  
             // Not really kosher, but we are constrained by the method signature
 611  0
             throw new IOException("Error creating SVGwriter " + e);
 612  0
         }
 613  
 
 614  0
         if (writer != null) {
 615  
             // We'll do the equivalent of the following ourselves
 616  
 //            ce.print(writer);
 617  
 
 618  0
             for (Fig f : layer.getContents()) {
 619  
                 // ignore clipping
 620  0
                 String url = null;
 621  0
                 String clazz = null;
 622  0
                 Object owner = f.getOwner();
 623  0
                 if (Model.getFacade().isAUMLElement(owner)) {
 624  0
                     clazz = Model.getMetaTypes().getName(owner);
 625  
                     // TODO: toLower?
 626  0
                     if (Model.getFacade().isAModelElement(owner)) {
 627  0
                         String name = Model.getFacade().getName(owner);
 628  0
                         if (name == null) {
 629  0
                             name = "";
 630  
                         }
 631  0
                         url = "http://argoeclipse.tigris.org" + "#" + name;
 632  
                     }
 633  
                 }
 634  0
                 writer.beginFig(f, clazz, url);
 635  0
                 f.paint(writer);
 636  0
                 writer.endFig();
 637  0
             }
 638  0
             writer.dispose();
 639  
         }
 640  0
     }
 641  
 }