Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: gnu/java/awt/peer/gtk/GtkClipboard.java


1   /* GtkClipboard.java
2      Copyright (C) 1999, 2005  Free Software Foundation, Inc.
3   
4   This file is part of GNU Classpath.
5   
6   GNU Classpath is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10  
11  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with GNU Classpath; see the file COPYING.  If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301 USA.
20  
21  Linking this library statically or dynamically with other modules is
22  making a combined work based on this library.  Thus, the terms and
23  conditions of the GNU General Public License cover the whole
24  combination.
25  
26  As a special exception, the copyright holders of this library give you
27  permission to link this library with independent modules to produce an
28  executable, regardless of the license terms of these independent
29  modules, and to copy and distribute the resulting executable under
30  terms of your choice, provided that you also meet, for each linked
31  independent module, the terms and conditions of the license of that
32  module.  An independent module is a module which is not derived from
33  or based on this library.  If you modify this library, you may extend
34  this exception to your version of the library, but you are not
35  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version. */
37  
38  
39  package gnu.java.awt.peer.gtk;
40  
41  import java.awt.Image;
42  import java.awt.datatransfer.*;
43  
44  import java.io.*;
45  
46  import java.util.List;
47  import java.util.Iterator;
48  
49  public class GtkClipboard extends Clipboard
50  {
51  
52    // Given to the native side so it can signal special targets that
53    // can be converted to one of the special predefined DataFlavors.
54    static final String stringMimeType;
55    static final String imageMimeType;
56    static final String filesMimeType;
57  
58    // Indicates whether the results of the clipboard selection can be
59    // cached by GtkSelection. True if
60    // gdk_display_supports_selection_notification.
61    static final boolean canCache;
62  
63    static
64    {
65      stringMimeType = DataFlavor.stringFlavor.getMimeType();
66      imageMimeType = DataFlavor.imageFlavor.getMimeType();
67      filesMimeType = DataFlavor.javaFileListFlavor.getMimeType();
68  
69      canCache = initNativeState(stringMimeType, imageMimeType, filesMimeType);
70    }
71  
72    /**
73     * The one and only gtk+ clipboard instance.
74     */
75    private static GtkClipboard instance = new GtkClipboard();
76  
77    /**
78     * Creates the clipboard and sets the initial contents to the
79     * current gtk+ selection.
80     */
81    private GtkClipboard()
82    {
83      super("System Clipboard");
84      setContents(new GtkSelection(), null);
85    }
86  
87    /**
88     * Returns the one and only GtkClipboard instance.
89     */
90  
91    static GtkClipboard getInstance()
92    {
93      return instance;
94    }
95  
96    /**
97     * Sets the GtkSelection facade as new contents of the clipboard.
98     * Called from gtk+ when another application grabs the clipboard and
99     * we loose ownership.
100    */
101   private static void setSystemContents()
102   {
103     GtkClipboardNotifier.announce();
104   }
105 
106   /**
107    * Sets the new contents and advertises the available flavors to the
108    * gtk+ clipboard.
109    */
110   public synchronized void setContents(Transferable contents,
111                ClipboardOwner owner)
112   {
113     super.setContents(contents, owner);
114 
115     if (contents == null)
116       {
117   advertiseContent(null, false, false, false);
118   return;
119       }
120 
121     // We don't need to do anything for a GtkSelection facade.
122     if (contents instanceof GtkSelection)
123       return;
124 
125     boolean text = false;
126     boolean images = false;
127     boolean files = false;
128 
129     if (contents instanceof StringSelection
130   || contents.isDataFlavorSupported(DataFlavor.stringFlavor)
131   || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor)
132   || contents.isDataFlavorSupported(DataFlavor
133             .getTextPlainUnicodeFlavor()))
134       text = true;
135 
136     DataFlavor[] flavors = contents.getTransferDataFlavors();
137     String[] mimeTargets = new String[flavors.length];
138     for (int i = 0; i < flavors.length; i++)
139       {
140   DataFlavor flavor = flavors[i];
141   String mimeType = flavor.getMimeType();
142   mimeTargets[i] = mimeType;
143 
144   if (! text)
145     if ("text".equals(flavor.getPrimaryType())
146         || flavor.isRepresentationClassReader())
147       text = true;
148 
149   // XXX - We only support automatic image conversion for
150   // GtkImages at the moment. So explicitly check that we have
151   // one.
152   if (! images && flavors[i].equals(DataFlavor.imageFlavor))
153     {
154       try
155         {
156     Object o = contents.getTransferData(DataFlavor.imageFlavor);
157     if (o instanceof GtkImage)
158       images = true;
159         }
160       catch (UnsupportedFlavorException ufe)
161         {
162         }
163       catch (IOException ioe)
164         {
165         }
166       catch (ClassCastException cce)
167         {
168         }
169     }
170 
171   if (flavors[i].equals(DataFlavor.javaFileListFlavor))
172     files = true;
173       }
174 
175     advertiseContent(mimeTargets, text, images, files);
176   }
177 
178   /**
179    * Advertises new contents to the gtk+ clipboard given a string
180    * array of (mime-type) targets. When the boolean flags text, images
181    * and/or files are set then gtk+ is asked to also advertise the
182    * availability of any text, image or uri/file content types it
183    * supports. If targets is null (and all flags false) then the
184    * selection has explicitly been erased.
185    */
186   private native void advertiseContent(String[] targets,
187                boolean text,
188                boolean images,
189                boolean files);
190   
191   /**
192    * Called by the gtk+ clipboard when an application has requested
193    * text.  Return a string representing the current clipboard
194    * contents or null when no text can be provided.
195    */
196   private String provideText()
197   {
198     Transferable contents = this.contents;
199     if (contents == null || contents instanceof GtkSelection)
200       return null;
201 
202     // Handle StringSelection special since that is just pure text.
203     if (contents instanceof StringSelection)
204       {
205         try
206           {
207             return (String) contents.getTransferData(DataFlavor.stringFlavor);
208     }
209         catch (UnsupportedFlavorException ufe)
210           {
211           }
212         catch (IOException ioe)
213           {
214           }
215         catch (ClassCastException cce)
216           {
217           }
218       }
219 
220     // Try to get a plain text reader for the current contents and
221     // turn the result into a string.
222     try
223       {
224   DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor();
225   Reader r = plainText.getReaderForText(contents);
226   if (r != null)
227     {
228       StringBuffer sb = new StringBuffer();
229       char[] cs = new char[1024];
230       int l = r.read(cs);
231       while (l != -1)
232         {
233     sb.append(cs, 0, l);
234     l = r.read(cs);
235         }
236       return sb.toString();
237     }
238       }
239     catch (IllegalArgumentException iae)
240       {
241       }
242     catch (UnsupportedEncodingException iee)
243       {
244       }
245     catch (UnsupportedFlavorException ufe)
246       {
247       }
248     catch (IOException ioe)
249       {
250       }
251 
252     return null;
253   }
254 
255   /**
256    * Called by the gtk+ clipboard when an application has requested an
257    * image.  Returns a GtkImage representing the current clipboard
258    * contents or null when no image can be provided.
259    */
260   private GtkImage provideImage()
261   {
262     Transferable contents = this.contents;
263     if (contents == null || contents instanceof GtkSelection)
264       return null;
265 
266     try
267       {
268   return (GtkImage) contents.getTransferData(DataFlavor.imageFlavor);
269       }
270     catch (UnsupportedFlavorException ufe)
271       {
272       }
273     catch (IOException ioe)
274       {
275       }
276     catch (ClassCastException cce)
277       {
278       }
279 
280     return null;
281   }
282 
283   /**
284    * Called by the gtk+ clipboard when an application has requested a
285    * uri-list.  Return a string array containing the URIs representing
286    * the current clipboard contents or null when no URIs can be
287    * provided.
288    */
289   private String[] provideURIs()
290   {
291     Transferable contents = this.contents;
292     if (contents == null || contents instanceof GtkSelection)
293       return null;
294 
295     try
296       {
297   List list = (List) contents.getTransferData
298     (DataFlavor.javaFileListFlavor);
299   String[] uris = new String[list.size()];
300   int u = 0;
301   Iterator it = list.iterator();
302   while (it.hasNext())
303     uris[u++] = ((File) it.next()).toURI().toString();
304   return uris;
305       }
306     catch (UnsupportedFlavorException ufe)
307       {
308       }
309     catch (IOException ioe)
310       {
311       }
312     catch (ClassCastException cce)
313       {
314       }
315 
316     return null;
317   }
318 
319   /**
320    * Called by gtk+ clipboard when an application requests the given
321    * target mime-type. Returns a byte array containing the requested
322    * data, or null when the contents cannot be provided in the
323    * requested target mime-type. Only called after any explicit text,
324    * image or file/uri requests have been handled earlier and failed.
325    */
326   private byte[] provideContent(String target)
327   {
328     // Sanity check. The callback could be triggered just after we
329     // changed the clipboard.
330     Transferable contents = this.contents;
331     if (contents == null || contents instanceof GtkSelection)
332       return null;
333 
334     // XXX - We are being called from a gtk+ callback. Which means we
335     // should return as soon as possible and not call arbitrary code
336     // that could deadlock or go bonkers. But we don't really know
337     // what DataTransfer contents object we are dealing with. Same for
338     // the other provideXXX() methods.
339     try
340       {
341   DataFlavor flavor = new DataFlavor(target);
342   Object o = contents.getTransferData(flavor);
343 
344   if (o instanceof byte[])
345     return (byte[]) o;
346 
347   if (o instanceof InputStream)
348     {
349       InputStream is = (InputStream) o;
350       ByteArrayOutputStream baos = new ByteArrayOutputStream();
351       byte[] bs = new byte[1024];
352       int l = is.read(bs);
353       while (l != -1)
354         {
355     baos.write(bs, 0, l);
356     l = is.read(bs);
357         }
358       return baos.toByteArray();
359     }
360 
361   if (o instanceof Serializable)
362     {
363       ByteArrayOutputStream baos = new ByteArrayOutputStream();
364       ObjectOutputStream oos = new ObjectOutputStream(baos);
365       oos.writeObject(o);
366       oos.close();
367       return baos.toByteArray();
368     }
369       }
370     catch (ClassNotFoundException cnfe)
371       {
372       }
373     catch (UnsupportedFlavorException ufe)
374       {
375       }
376     catch (IOException ioe)
377       {
378       }
379     catch (ClassCastException cce)
380       {
381       }
382 
383     return null;
384   }
385 
386   /**
387    * Initializes the gtk+ clipboard and caches any native side
388    * structures needed. Returns whether or not the contents of the
389    * Clipboard can be cached (gdk_display_supports_selection_notification).
390    */
391   private static native boolean initNativeState(String stringTarget,
392             String imageTarget,
393             String filesTarget);
394 }