1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package yExport-1.3.
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-2012 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   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/export_usage.html#export_clipboard">Using the yExport Extension Package</a> in the yFiles for Java Developer's Guide
47   */
48  public class SystemClipboardDemo extends AbstractExportDemo
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 void loadGraph(URL resource, boolean updateView) {
76      setCopySelectionBounds(new Rectangle());
77      super.loadGraph(resource, updateView);
78    }
79  
80    private void setCopySelectionBounds( final Rectangle r ) {
81      copySelectionMarker.setBounds(r);
82      copyToClipboardAction.setEnabled(!copySelectionMarker.isEmpty());
83    }
84  
85  
86    /**
87     * Action that copies a graph in EMF format to the system clipboard.
88     */
89    class CopyToClipboardAction extends AbstractAction {
90      CopyToClipboardAction() {
91        final String name = "Copy To Clipboard";
92        putValue(Action.NAME, name);
93        putValue(Action.SMALL_ICON, createIcon("resource/copy.png"));
94        putValue(Action.SHORT_DESCRIPTION, name);
95        setEnabled(false);
96      }
97  
98      public void actionPerformed( final ActionEvent e ) {
99        // setting up a Graph2DView for data transfer
100       final Rectangle cpSlctnBnds = copySelectionMarker.getBounds();
101       final Graph2D graph = (Graph2D) view.getGraph2D().createCopy();
102       final double z = view.getZoom();
103       final Dimension s = new Dimension(
104               (int)(cpSlctnBnds.width * z),
105               (int)(cpSlctnBnds.height * z));
106       final Graph2DView transferView = new Graph2DView(graph);
107       transferView.setZoom(z);
108       transferView.setPaintDetailThreshold(0.0);
109       transferView.setSize(s);
110       transferView.setPreferredSize(s);
111       transferView.setViewPoint(cpSlctnBnds.x, cpSlctnBnds.y);
112       transferView.setWorldRect(cpSlctnBnds.x, cpSlctnBnds.y,
113                                 cpSlctnBnds.width, cpSlctnBnds.height);
114 
115       // copy the contents of the previously set up view to the system clipboard
116       // note: the transferable is configured to provide some image format based
117       // fallback data flavors that will allow EMF unaware applications to
118       // import our data as image content
119       VisualTransferable transferable = new VisualTransferable(transferView, true);
120       Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
121       cb.setContents(transferable, transferable);
122     }
123   }
124 
125   /**
126    * Action that switches between regular graph edit mode and a mode to create
127    * a selection to be copied to the system clipboard.
128    */
129   class ToggleSelectionModeAction extends AbstractAction {
130     private final CreateCopySelectionMode mode;
131     private boolean active;
132 
133     ToggleSelectionModeAction() {
134       final String name = "Select Copy Region";
135       putValue(Action.NAME, name);
136       putValue(Action.SMALL_ICON, createIcon("resource/SelectRectangle16.gif"));
137       putValue(Action.SHORT_DESCRIPTION, name);
138       mode = new CreateCopySelectionMode();
139       active = false;
140     }
141 
142     public void actionPerformed( final ActionEvent e ) {
143       if(!active) {
144         view.removeViewMode(editMode);
145         view.addViewMode(mode);
146         active = true;
147       } else {
148         setCopySelectionBounds(new Rectangle());
149         view.removeViewMode(mode);
150         view.addViewMode(editMode);
151         active = false;
152       }
153     }
154   }
155 
156   /**
157    * An <code>AbstractSelectionBoxMode</code> that creates a rectangular
158    * selection to be copied to the system clipboard.
159    */
160   class CreateCopySelectionMode extends AbstractSelectionBoxMode {
161     protected void selectionBoxAction(
162             final Rectangle sb, final boolean shiftMode
163     ) {
164       setCopySelectionBounds(sb);
165       view.updateView();
166     }
167   }
168 
169   /**
170    * A drawable implementation that provides a shaded overlay for all of the
171    * currently visible portion of a <code>Graph2DView</code> but its current
172    * <code>bounds</code>.
173    */
174   static final class CopySelectionMarker implements Drawable {
175     private final Rectangle bounds;
176     private final Rectangle clip;
177 
178     private final Color fill;
179     private final Color draw;
180 
181     CopySelectionMarker() {
182       this.bounds = new Rectangle(0, 0, -1, -1);
183       this.clip = new Rectangle();
184       this.fill = Color.LIGHT_GRAY;
185       this.draw = Color.DARK_GRAY;
186     }
187 
188     public void paint( final Graphics2D gfx ) {
189       if (isEmpty()) {
190         return;
191       }
192 
193       final Composite oldComp = gfx.getComposite();
194       final Color oldColor = gfx.getColor();
195 
196       gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.35f));
197 
198       gfx.getClipBounds(clip);
199       gfx.setColor(fill);
200       // top
201       if (clip.y < bounds.y) {
202         gfx.fillRect(clip.x, clip.y, clip.width, bounds.y - clip.y);
203       }
204       // left
205       if (clip.x < bounds.x) {
206         gfx.fillRect(clip.x, bounds.y, bounds.x - clip.x, bounds.height);
207       }
208       // bottom
209       final int bndsMxY = bounds.y + bounds.height;
210       final int cbMxY = clip.y + clip.height;
211       if (cbMxY > bndsMxY) {
212         gfx.fillRect(clip.x, bndsMxY, clip.width, cbMxY - bndsMxY);
213       }
214       // right
215       final int bndsMxX = bounds.x + bounds.width;
216       final int cbMxX = clip.x + clip.width;
217       if (cbMxX > bndsMxX) {
218         gfx.fillRect(bndsMxX, bounds.y, cbMxX - bndsMxX, bounds.height);
219       }
220 
221       gfx.setColor(draw);
222       gfx.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
223 
224       gfx.setColor(oldColor);
225       gfx.setComposite(oldComp);
226     }
227 
228     public Rectangle getBounds() {
229       return bounds.getBounds();
230     }
231 
232     void setBounds( final Rectangle r ) {
233       if (r == null) {
234         throw new IllegalArgumentException("null");
235       }
236       bounds.setBounds(r);
237     }
238 
239     boolean isEmpty() {
240       return bounds.width < 1 || bounds.height < 1;
241     }
242   }
243 
244   /**
245    * Launches this demo.
246    */
247   public static void main(String[] args) {
248     initLnF();
249     (new SystemClipboardDemo()).start();
250   }
251 }