1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package yExport-1.0.
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2007 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  
15  package demo.yext.export;
16  
17  
18  import yext.export.datatransfer.VisualTransferable;
19  
20  import java.awt.AlphaComposite;
21  import java.awt.Color;
22  import java.awt.Composite;
23  import java.awt.Dimension;
24  import java.awt.Graphics2D;
25  import java.awt.Rectangle;
26  import java.awt.Toolkit;
27  import java.awt.datatransfer.Clipboard;
28  import java.awt.event.ActionEvent;
29  import java.net.URL;
30  import javax.swing.AbstractAction;
31  import javax.swing.Action;
32  import javax.swing.JButton;
33  import javax.swing.JToggleButton;
34  import javax.swing.JToolBar;
35  
36  import y.view.AbstractSelectionBoxMode;
37  import y.view.Drawable;
38  import y.view.Graph2D;
39  import y.view.Graph2DView;
40  
41  
42  /**
43   * Demonstrates how to copy a graph in EMF format to the system clipboard.
44   * Copying to the system clipboard is enabled by creating a to-be-copied
45   * selection using a custom view mode.
46   * 
47   */
48  public class SystemClipboardDemo extends ViewActionDemo
49  {
50    private final CopySelectionMarker copySelectionMarker;
51    private CopyToClipboardAction copyToClipboardAction;
52  
53    public SystemClipboardDemo() {
54      copySelectionMarker = new CopySelectionMarker();
55      if (copyToClipboardAction == null) {
56        copyToClipboardAction = new CopyToClipboardAction();
57      }
58      view.addDrawable(copySelectionMarker);
59    }
60  
61    /**
62     * Creates a toolbar for this demo.
63     */
64    protected JToolBar createToolBar() {
65      JToolBar jtb = super.createToolBar();
66      jtb.addSeparator();
67      jtb.add(new JToggleButton(new ToggleSelectionModeAction()));
68      if (copyToClipboardAction == null) {
69        copyToClipboardAction = new CopyToClipboardAction();
70      }
71      jtb.add(new JButton(copyToClipboardAction));
72      return jtb;
73    }
74  
75    protected Action createLoadResourceAction( final URL resource ) {
76      return new LoadResourceAction(resource) {
77        public void actionPerformed( final ActionEvent e ) {
78          setCopySelectionBounds(new Rectangle());
79          super.actionPerformed(e);
80        }
81      };
82    }
83  
84    private void setCopySelectionBounds( final Rectangle r ) {
85      copySelectionMarker.setBounds(r);
86      copyToClipboardAction.setEnabled(!copySelectionMarker.isEmpty());
87    }
88  
89  
90    /**
91     * Action that copies a graph in EMF format to the system clipboard.
92     */
93    class CopyToClipboardAction extends AbstractAction {
94      CopyToClipboardAction() {
95        final String name = "Copy To Clipboard";
96        putValue(Action.NAME, name);
97        putValue(Action.SMALL_ICON, createIcon("resource/Copy16.gif"));
98        putValue(Action.SHORT_DESCRIPTION, name);
99        setEnabled(false);
100     }
101 
102     public void actionPerformed( final ActionEvent e ) {
103       // setting up a Graph2DView for data transfer
104       final Rectangle cpSlctnBnds = copySelectionMarker.getBounds();
105       final Graph2D graph = (Graph2D) view.getGraph2D().createCopy();
106       final double z = view.getZoom();
107       final Dimension s = new Dimension(
108               (int)(cpSlctnBnds.width * z),
109               (int)(cpSlctnBnds.height * z));
110       final Graph2DView transferView = new Graph2DView(graph);
111       transferView.setZoom(z);
112       transferView.setPaintDetailThreshold(0);
113       transferView.setSize(s);
114       transferView.setPreferredSize(s);
115       transferView.setViewPoint(cpSlctnBnds.x, cpSlctnBnds.y);
116       transferView.setWorldRect(cpSlctnBnds.x, cpSlctnBnds.y,
117                                 cpSlctnBnds.width, cpSlctnBnds.height);
118 
119       // copy the contents of the previously set up view to the system clipboard
120       // note: the transferable is configured to provide some image format based
121       // fallback data flavors that will allow EMF unaware applications to
122       // import our data as image content
123       VisualTransferable transferable = new VisualTransferable(transferView, true);
124       Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
125       cb.setContents(transferable, transferable);
126     }
127   }
128 
129   /**
130    * Action that switches between regular graph edit mode and a mode to create
131    * a selection to be copied to the system clipboard.
132    */
133   class ToggleSelectionModeAction extends AbstractAction {
134     private final CreateCopySelectionMode mode;
135     private boolean active;
136 
137     ToggleSelectionModeAction() {
138       final String name = "Select Copy Region";
139       putValue(Action.NAME, name);
140       putValue(Action.SMALL_ICON, createIcon("resource/SelectRectangle16.gif"));
141       putValue(Action.SHORT_DESCRIPTION, name);
142       mode = new CreateCopySelectionMode();
143       active = false;
144     }
145 
146     public void actionPerformed( final ActionEvent e ) {
147       if(!active) {
148         view.removeViewMode(editMode);
149         view.addViewMode(mode);
150         active = true;
151       } else {
152         setCopySelectionBounds(new Rectangle());
153         view.removeViewMode(mode);
154         view.addViewMode(editMode);
155         active = false;
156       }
157     }
158   }
159 
160   /**
161    * An <code>AbstractSelectionBoxMode</code> that creates a rectangular
162    * selection to be copied to the system clipboard.
163    */
164   class CreateCopySelectionMode extends AbstractSelectionBoxMode {
165     protected void selectionBoxAction(
166             final Rectangle sb, final boolean shiftMode
167     ) {
168       setCopySelectionBounds(sb);
169       view.updateView();
170     }
171   }
172 
173   /**
174    * A drawable implementation that provides a shaded overlay for all of the
175    * currently visible portion of a <code>Graph2DView</code> but its current
176    * <code>bounds</code>.
177    */
178   static final class CopySelectionMarker implements Drawable {
179     private final Rectangle bounds;
180     private final Rectangle clip;
181 
182     private final Color fill;
183     private final Color draw;
184 
185     CopySelectionMarker() {
186       this.bounds = new Rectangle(0, 0, -1, -1);
187       this.clip = new Rectangle();
188       this.fill = Color.LIGHT_GRAY;
189       this.draw = Color.DARK_GRAY;
190     }
191 
192     public void paint( final Graphics2D gfx ) {
193       if (isEmpty()) {
194         return;
195       }
196 
197       final Composite oldComp = gfx.getComposite();
198       final Color oldColor = gfx.getColor();
199 
200       gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.35f));
201 
202       gfx.getClipBounds(clip);
203       gfx.setColor(fill);
204       // top
205       if (clip.y < bounds.y) {
206         gfx.fillRect(clip.x, clip.y, clip.width, bounds.y - clip.y);
207       }
208       // left
209       if (clip.x < bounds.x) {
210         gfx.fillRect(clip.x, bounds.y, bounds.x - clip.x, bounds.height);
211       }
212       // bottom
213       final int bndsMxY = bounds.y + bounds.height;
214       final int cbMxY = clip.y + clip.height;
215       if (cbMxY > bndsMxY) {
216         gfx.fillRect(clip.x, bndsMxY, clip.width, cbMxY - bndsMxY);
217       }
218       // right
219       final int bndsMxX = bounds.x + bounds.width;
220       final int cbMxX = clip.x + clip.width;
221       if (cbMxX > bndsMxX) {
222         gfx.fillRect(bndsMxX, bounds.y, cbMxX - bndsMxX, bounds.height);
223       }
224 
225       gfx.setColor(draw);
226       gfx.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
227 
228       gfx.setColor(oldColor);
229       gfx.setComposite(oldComp);
230     }
231 
232     public Rectangle getBounds() {
233       return bounds.getBounds();
234     }
235 
236     void setBounds( final Rectangle r ) {
237       if (r == null) {
238         throw new IllegalArgumentException("null");
239       }
240       bounds.setBounds(r);
241     }
242 
243     boolean isEmpty() {
244       return bounds.width < 1 || bounds.height < 1;
245     }
246   }
247 
248   /**
249    * Launches this demo.
250    */
251   public static void main(String[] args) {
252     initLnF();
253     (new SystemClipboardDemo()).start();
254   }
255 }