src/share/classes/sun/awt/datatransfer/SunClipboard.java

Print this page




  23  * questions.
  24  */
  25 
  26 package sun.awt.datatransfer;
  27 
  28 import java.awt.EventQueue;
  29 
  30 import java.awt.datatransfer.Clipboard;
  31 import java.awt.datatransfer.FlavorTable;
  32 import java.awt.datatransfer.SystemFlavorMap;
  33 import java.awt.datatransfer.Transferable;
  34 import java.awt.datatransfer.ClipboardOwner;
  35 import java.awt.datatransfer.DataFlavor;
  36 import java.awt.datatransfer.FlavorListener;
  37 import java.awt.datatransfer.FlavorEvent;
  38 import java.awt.datatransfer.UnsupportedFlavorException;
  39 
  40 import java.beans.PropertyChangeEvent;
  41 import java.beans.PropertyChangeListener;
  42 
  43 import java.util.Objects;
  44 import java.util.Set;
  45 import java.util.HashSet;
  46 
  47 import java.io.IOException;
  48 
  49 import sun.awt.AppContext;
  50 import sun.awt.PeerEvent;
  51 import sun.awt.SunToolkit;
  52 
  53 
  54 /**
  55  * Serves as a common, helper superclass for the Win32 and X11 system
  56  * Clipboards.
  57  *
  58  * @author Danila Sinopalnikov
  59  * @author Alexander Gerasimov
  60  *
  61  * @since 1.3
  62  */
  63 public abstract class SunClipboard extends Clipboard
  64     implements PropertyChangeListener {
  65 
  66     private AppContext contentsContext = null;
  67 
  68     private final Object CLIPBOARD_FLAVOR_LISTENER_KEY;
  69 
  70     /**
  71      * A number of <code>FlavorListener</code>s currently registered
  72      * on this clipboard across all <code>AppContext</code>s.
  73      */
  74     private volatile int numberOfFlavorListeners = 0;
  75 
  76     /**
  77      * A set of <code>DataFlavor</code>s that is available on
  78      * this clipboard. It is used for tracking changes
  79      * of <code>DataFlavor</code>s available on this clipboard.
  80      */
  81     private volatile Set<DataFlavor> currentDataFlavors;
  82 
  83 
  84     public SunClipboard(String name) {
  85         super(name);
  86         CLIPBOARD_FLAVOR_LISTENER_KEY = new StringBuffer(name + "_CLIPBOARD_FLAVOR_LISTENER_KEY");
  87     }
  88 
  89     public synchronized void setContents(Transferable contents,
  90                                          ClipboardOwner owner) {
  91         // 4378007 : Toolkit.getSystemClipboard().setContents(null, null)
  92         // should throw NPE
  93         if (contents == null) {
  94             throw new NullPointerException("contents");
  95         }
  96 
  97         initContext();
  98 
  99         final ClipboardOwner oldOwner = this.owner;
 100         final Transferable oldContents = this.contents;
 101 


 341     private static Set<DataFlavor> formatArrayAsDataFlavorSet(long[] formats) {
 342         return (formats == null) ? null :
 343                 DataTransferer.getInstance().
 344                 getFlavorsForFormatsAsSet(formats, getDefaultFlavorTable());
 345     }
 346 
 347 
 348     public synchronized void addFlavorListener(FlavorListener listener) {
 349         if (listener == null) {
 350             return;
 351         }
 352         AppContext appContext = AppContext.getAppContext();
 353         Set<FlavorListener> flavorListeners = getFlavorListeners(appContext);
 354         if (flavorListeners == null) {
 355             flavorListeners = new HashSet<>();
 356             appContext.put(CLIPBOARD_FLAVOR_LISTENER_KEY, flavorListeners);
 357         }
 358         flavorListeners.add(listener);
 359 
 360         if (numberOfFlavorListeners++ == 0) {
 361             long[] currentFormats = null;
 362             try {
 363                 openClipboard(null);
 364                 currentFormats = getClipboardFormats();
 365             } catch (IllegalStateException exc) {
 366             } finally {
 367                 closeClipboard();
 368             }
 369             currentDataFlavors = formatArrayAsDataFlavorSet(currentFormats);
 370 
 371             registerClipboardViewerChecked();
 372         }
 373     }
 374 
 375     public synchronized void removeFlavorListener(FlavorListener listener) {
 376         if (listener == null) {
 377             return;
 378         }
 379         Set<FlavorListener> flavorListeners = getFlavorListeners(AppContext.getAppContext());
 380         if (flavorListeners == null){
 381             //else we throw NullPointerException, but it is forbidden
 382             return;
 383         }
 384         if (flavorListeners.remove(listener) && --numberOfFlavorListeners == 0) {
 385             unregisterClipboardViewerChecked();
 386             currentDataFlavors = null;
 387         }
 388     }
 389 
 390     @SuppressWarnings("unchecked")
 391     private Set<FlavorListener> getFlavorListeners(AppContext appContext) {
 392         return (Set<FlavorListener>)appContext.get(CLIPBOARD_FLAVOR_LISTENER_KEY);
 393     }
 394 
 395     public synchronized FlavorListener[] getFlavorListeners() {
 396         Set<FlavorListener> flavorListeners = getFlavorListeners(AppContext.getAppContext());
 397         return flavorListeners == null ? new FlavorListener[0]
 398                 : flavorListeners.toArray(new FlavorListener[flavorListeners.size()]);
 399     }
 400 
 401     public boolean areFlavorListenersRegistered() {
 402         return (numberOfFlavorListeners > 0);
 403     }
 404 
 405     protected abstract void registerClipboardViewerChecked();
 406 
 407     protected abstract void unregisterClipboardViewerChecked();
 408 
 409     /**
 410      * Checks change of the <code>DataFlavor</code>s and, if necessary,
 411      * posts notifications on <code>FlavorEvent</code>s to the
 412      * AppContexts' EDTs.
 413      * The parameter <code>formats</code> is null iff we have just
 414      * failed to get formats available on the clipboard.
 415      *
 416      * @param formats data formats that have just been retrieved from
 417      *        this clipboard
 418      */
 419     public void checkChange(long[] formats) {
 420         Set<DataFlavor> prevDataFlavors = currentDataFlavors;
 421         currentDataFlavors = formatArrayAsDataFlavorSet(formats);
 422 
 423         if (Objects.equals(prevDataFlavors, currentDataFlavors)) {
 424             // we've been able to successfully get available on the clipboard
 425             // DataFlavors this and previous time and they are coincident;
 426             // don't notify
 427             return;
 428         }
 429 
 430         for (AppContext appContext : AppContext.getAppContexts()) {
 431             if (appContext == null || appContext.isDisposed()) {
 432                 continue;
 433             }
 434             Set<FlavorListener> flavorListeners = getFlavorListeners(appContext);
 435             if (flavorListeners != null) {
 436                 for (FlavorListener listener : flavorListeners) {
 437                     if (listener != null) {
 438                         PeerEvent peerEvent = new PeerEvent(this,
 439                                 () -> listener.flavorsChanged(new FlavorEvent(SunClipboard.this)),
 440                                 PeerEvent.PRIORITY_EVENT);
 441                         SunToolkit.postEvent(appContext, peerEvent);
 442                     }
 443                 }


  23  * questions.
  24  */
  25 
  26 package sun.awt.datatransfer;
  27 
  28 import java.awt.EventQueue;
  29 
  30 import java.awt.datatransfer.Clipboard;
  31 import java.awt.datatransfer.FlavorTable;
  32 import java.awt.datatransfer.SystemFlavorMap;
  33 import java.awt.datatransfer.Transferable;
  34 import java.awt.datatransfer.ClipboardOwner;
  35 import java.awt.datatransfer.DataFlavor;
  36 import java.awt.datatransfer.FlavorListener;
  37 import java.awt.datatransfer.FlavorEvent;
  38 import java.awt.datatransfer.UnsupportedFlavorException;
  39 
  40 import java.beans.PropertyChangeEvent;
  41 import java.beans.PropertyChangeListener;
  42 
  43 import java.util.Arrays;
  44 import java.util.Set;
  45 import java.util.HashSet;
  46 
  47 import java.io.IOException;
  48 
  49 import sun.awt.AppContext;
  50 import sun.awt.PeerEvent;
  51 import sun.awt.SunToolkit;
  52 
  53 
  54 /**
  55  * Serves as a common, helper superclass for the Win32 and X11 system
  56  * Clipboards.
  57  *
  58  * @author Danila Sinopalnikov
  59  * @author Alexander Gerasimov
  60  *
  61  * @since 1.3
  62  */
  63 public abstract class SunClipboard extends Clipboard
  64     implements PropertyChangeListener {
  65 
  66     private AppContext contentsContext = null;
  67 
  68     private final Object CLIPBOARD_FLAVOR_LISTENER_KEY;
  69 
  70     /**
  71      * A number of <code>FlavorListener</code>s currently registered
  72      * on this clipboard across all <code>AppContext</code>s.
  73      */
  74     private volatile int numberOfFlavorListeners = 0;
  75 
  76     /**
  77      * A set of formats that is available on
  78      * this clipboard. It is used for tracking changes
  79      * of <code>DataFlavor</code>s available on this clipboard.
  80      */
  81     private volatile long[] currentDataFormats;
  82 
  83 
  84     public SunClipboard(String name) {
  85         super(name);
  86         CLIPBOARD_FLAVOR_LISTENER_KEY = new StringBuffer(name + "_CLIPBOARD_FLAVOR_LISTENER_KEY");
  87     }
  88 
  89     public synchronized void setContents(Transferable contents,
  90                                          ClipboardOwner owner) {
  91         // 4378007 : Toolkit.getSystemClipboard().setContents(null, null)
  92         // should throw NPE
  93         if (contents == null) {
  94             throw new NullPointerException("contents");
  95         }
  96 
  97         initContext();
  98 
  99         final ClipboardOwner oldOwner = this.owner;
 100         final Transferable oldContents = this.contents;
 101 


 341     private static Set<DataFlavor> formatArrayAsDataFlavorSet(long[] formats) {
 342         return (formats == null) ? null :
 343                 DataTransferer.getInstance().
 344                 getFlavorsForFormatsAsSet(formats, getDefaultFlavorTable());
 345     }
 346 
 347 
 348     public synchronized void addFlavorListener(FlavorListener listener) {
 349         if (listener == null) {
 350             return;
 351         }
 352         AppContext appContext = AppContext.getAppContext();
 353         Set<FlavorListener> flavorListeners = getFlavorListeners(appContext);
 354         if (flavorListeners == null) {
 355             flavorListeners = new HashSet<>();
 356             appContext.put(CLIPBOARD_FLAVOR_LISTENER_KEY, flavorListeners);
 357         }
 358         flavorListeners.add(listener);
 359 
 360         if (numberOfFlavorListeners++ == 0) {
 361             currentDataFormats = getClipboardFormatsOpenClose();









 362             registerClipboardViewerChecked();
 363         }
 364     }
 365 
 366     public synchronized void removeFlavorListener(FlavorListener listener) {
 367         if (listener == null) {
 368             return;
 369         }
 370         Set<FlavorListener> flavorListeners = getFlavorListeners(AppContext.getAppContext());
 371         if (flavorListeners == null){
 372             //else we throw NullPointerException, but it is forbidden
 373             return;
 374         }
 375         if (flavorListeners.remove(listener) && --numberOfFlavorListeners == 0) {
 376             unregisterClipboardViewerChecked();
 377             currentDataFormats = null;
 378         }
 379     }
 380 
 381     @SuppressWarnings("unchecked")
 382     private Set<FlavorListener> getFlavorListeners(AppContext appContext) {
 383         return (Set<FlavorListener>)appContext.get(CLIPBOARD_FLAVOR_LISTENER_KEY);
 384     }
 385 
 386     public synchronized FlavorListener[] getFlavorListeners() {
 387         Set<FlavorListener> flavorListeners = getFlavorListeners(AppContext.getAppContext());
 388         return flavorListeners == null ? new FlavorListener[0]
 389                 : flavorListeners.toArray(new FlavorListener[flavorListeners.size()]);
 390     }
 391 
 392     public boolean areFlavorListenersRegistered() {
 393         return (numberOfFlavorListeners > 0);
 394     }
 395 
 396     protected abstract void registerClipboardViewerChecked();
 397 
 398     protected abstract void unregisterClipboardViewerChecked();
 399 
 400     /**
 401      * Checks change of the <code>DataFlavor</code>s and, if necessary,
 402      * posts notifications on <code>FlavorEvent</code>s to the
 403      * AppContexts' EDTs.
 404      * The parameter <code>formats</code> is null iff we have just
 405      * failed to get formats available on the clipboard.
 406      *
 407      * @param formats data formats that have just been retrieved from
 408      *        this clipboard
 409      */
 410     public void checkChange(long[] formats) {
 411         long[] prevDataFlavors = currentDataFormats;
 412         currentDataFormats = formats;
 413 
 414         if (Arrays.equals(prevDataFlavors, currentDataFormats)) {
 415             // we've been able to successfully get available on the clipboard
 416             // DataFlavors this and previous time and they are coincident;
 417             // don't notify
 418             return;
 419         }
 420 
 421         for (AppContext appContext : AppContext.getAppContexts()) {
 422             if (appContext == null || appContext.isDisposed()) {
 423                 continue;
 424             }
 425             Set<FlavorListener> flavorListeners = getFlavorListeners(appContext);
 426             if (flavorListeners != null) {
 427                 for (FlavorListener listener : flavorListeners) {
 428                     if (listener != null) {
 429                         PeerEvent peerEvent = new PeerEvent(this,
 430                                 () -> listener.flavorsChanged(new FlavorEvent(SunClipboard.this)),
 431                                 PeerEvent.PRIORITY_EVENT);
 432                         SunToolkit.postEvent(appContext, peerEvent);
 433                     }
 434                 }