1 19 20 package org.netbeans.core; 21 22 import java.awt.AWTEvent ; 23 import java.awt.Toolkit ; 24 import java.awt.datatransfer.Clipboard ; 25 import java.awt.datatransfer.ClipboardOwner ; 26 import java.awt.datatransfer.DataFlavor ; 27 import java.awt.datatransfer.FlavorEvent ; 28 import java.awt.datatransfer.FlavorListener ; 29 import java.awt.datatransfer.Transferable ; 30 import java.awt.datatransfer.UnsupportedFlavorException ; 31 import java.awt.event.AWTEventListener ; 32 import java.awt.event.WindowEvent ; 33 import java.lang.ref.Reference ; 34 import java.lang.ref.WeakReference ; 35 import java.util.Collection ; 36 import java.util.logging.Level ; 37 import java.util.logging.Logger ; 38 import org.openide.util.Exceptions; 39 import org.openide.util.Lookup; 40 import org.openide.util.LookupEvent; 41 import org.openide.util.LookupListener; 42 import org.openide.util.RequestProcessor; 43 import org.openide.util.datatransfer.ExClipboard; 44 45 public final class NbClipboard extends ExClipboard 46 implements LookupListener, Runnable , FlavorListener , AWTEventListener 47 { 48 private Logger log; 49 private Clipboard systemClipboard; 50 private ExClipboard.Convertor[] convertors; 51 private Lookup.Result<ExClipboard.Convertor> result; 52 final boolean slowSystemClipboard; 53 private Transferable last; 54 private long lastWindowActivated; 55 private long lastWindowDeactivated; 56 private Reference <Object > lastWindowDeactivatedSource = new WeakReference <Object >(null); 57 58 public NbClipboard() { 59 super("NBClipboard"); systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 61 log = Logger.getLogger("org.netbeans.core.NbClipboard"); 63 result = Lookup.getDefault().lookupResult(ExClipboard.Convertor.class); 64 result.addLookupListener(this); 65 66 systemClipboard.addFlavorListener(this); 67 68 resultChanged(null); 69 70 if (System.getProperty("netbeans.slow.system.clipboard.hack") != null) slowSystemClipboard = Boolean.getBoolean("netbeans.slow.system.clipboard.hack"); else 73 slowSystemClipboard = true; 74 75 76 77 78 if (!slowSystemClipboard) { 79 if (System.getProperty("sun.awt.datatransfer.timeout") == null) { System.setProperty("sun.awt.datatransfer.timeout", "1000"); } 82 } else { 83 Toolkit.getDefaultToolkit().addAWTEventListener( 84 this, AWTEvent.WINDOW_EVENT_MASK); 85 } 86 } 87 88 protected synchronized ExClipboard.Convertor[] getConvertors () { 89 return convertors; 90 } 91 92 public synchronized void resultChanged(LookupEvent ev) { 93 Collection <? extends ExClipboard.Convertor> c = result.allInstances(); 94 ExClipboard.Convertor[] temp = new ExClipboard.Convertor[c.size()]; 95 convertors = c.toArray(temp); 96 } 97 98 120 private RequestProcessor.Task syncTask = 121 new RequestProcessor("System clipboard synchronizer").create(this, true); 123 private Transferable data; 124 private ClipboardOwner dataOwner; 125 126 public void setContents(Transferable contents, ClipboardOwner owner) { 127 synchronized (this) { 128 if (log.isLoggable (Level.FINER)) { 131 log.log (Level.FINER, "setContents called with: "); logFlavors (contents, Level.FINER); 133 } 134 contents = convert(contents); 135 if (log.isLoggable (Level.FINER)) { 136 log.log (Level.FINER, "After conversion:"); logFlavors (contents, Level.FINER); 138 } 139 140 if (slowSystemClipboard) { 141 super.setContents(contents, owner); 142 } else { 143 if (last != null) transferableOwnershipLost(last); 144 last = contents; 145 } 146 147 data = contents; 148 dataOwner = owner; 149 syncTask.schedule(0); 150 } 151 fireClipboardChange(); 152 } 153 154 public Transferable getContents(Object requestor) { 155 Transferable prev; 156 157 try { 158 if (slowSystemClipboard) { 159 if (lastWindowActivated != 0 && lastWindowActivated+100 < System.currentTimeMillis()) { 163 lastWindowActivated = 0; 164 165 syncTask.schedule(0); 166 syncTask.waitFinished (100); 167 } 168 169 170 prev = super.getContents (requestor); 171 } else { 172 syncTask.waitFinished (); 173 prev = systemClipboard.getContents (requestor); 174 } 175 176 synchronized (this) { 177 if (log.isLoggable (Level.FINE)) { 178 log.log (Level.FINE, "getContents by " + requestor); logFlavors (prev, Level.FINE); 180 } 181 if (prev == null) return null; 183 184 Transferable res = convert (prev); 185 if (log.isLoggable (Level.FINE)) { 186 log.log (Level.FINE, "getContents by " + requestor); logFlavors (res, Level.FINE); 188 189 res = new LoggableTransferable (res); 190 } 191 return res; 192 } 193 } catch (ThreadDeath ex) { 194 throw ex; 195 } catch (InterruptedException ex) { 196 Logger.getLogger(NbClipboard.class.getName()).log(Level.WARNING, null, ex); 197 return null; 198 } catch (Throwable ex) { 199 Exceptions.printStackTrace(ex); 200 return null; 201 } 202 } 203 204 public void run() { 205 Transferable contents = null; 206 ClipboardOwner owner = null; 207 208 synchronized (this) { 209 if (data != null) { 210 contents = data; 211 owner = dataOwner; 212 } 213 data = null; 214 dataOwner = null; 215 } 216 if (contents != null) { 217 if (log.isLoggable (Level.FINE)) { 218 log.log (Level.FINE, "systemClipboard updated:"); logFlavors (contents, Level.FINE); 220 } 221 systemClipboard.setContents(contents, owner); 222 return; 223 } 224 225 try { 226 Transferable transferable = systemClipboard.getContents(this); 227 super.setContents(transferable, null); 228 if (log.isLoggable (Level.FINE)) { 229 log.log (Level.FINE, "internal clipboard updated:"); logFlavors (transferable, Level.FINE); 231 } 232 fireClipboardChange(); 233 } 234 catch (ThreadDeath ex) { 235 throw ex; 236 } 237 catch (Throwable ignore) { 238 } 239 } 240 241 243 final void waitFinished () { 244 syncTask.waitFinished (); 245 } 246 247 final void activateWindowHack (boolean reschedule) { 248 lastWindowActivated = System.currentTimeMillis(); 252 if (reschedule) { 253 syncTask.schedule (0); 254 } 255 } 256 257 private void logFlavors (Transferable trans, Level level) { 258 if (trans == null) 259 log.log (level, " no clipboard contents"); 260 else { 261 java.awt.datatransfer.DataFlavor [] arr = trans.getTransferDataFlavors(); 262 for (int i = 0; i < arr.length; i++) { 263 log.log (level, " " + i + " = " + arr[i]); 264 } 265 } 266 } 267 268 public void flavorsChanged(FlavorEvent e) { 269 fireClipboardChange(); 270 } 271 272 public void eventDispatched(AWTEvent ev) { 273 if (!(ev instanceof WindowEvent )) 274 return; 275 276 if (ev.getID() == WindowEvent.WINDOW_DEACTIVATED) { 277 lastWindowDeactivated = System.currentTimeMillis(); 278 lastWindowDeactivatedSource = new WeakReference <Object >(ev.getSource()); 279 } 280 if (ev.getID() == WindowEvent.WINDOW_ACTIVATED) { 281 if (System.currentTimeMillis() - lastWindowDeactivated < 100 && 282 ev.getSource() == lastWindowDeactivatedSource.get()) { 283 activateWindowHack (false); 284 } 285 if (log.isLoggable (Level.FINE)) { 286 log.log (Level.FINE, "window activated scheduling update"); } 288 syncTask.schedule(0); 289 } 290 } 291 292 294 private final class LoggableTransferable implements Transferable { 295 private Transferable delegate; 296 297 public LoggableTransferable (Transferable delegate) { 298 this.delegate = delegate; 299 } 300 public Object getTransferData (DataFlavor flavor) throws UnsupportedFlavorException , java.io.IOException { 301 log.log (Level.FINE, "Request for flavor: " + flavor); Object res = delegate.getTransferData (flavor); 303 log.log (Level.FINE, "Returning value: " + res); return res; 305 } 306 307 public DataFlavor [] getTransferDataFlavors () { 308 return delegate.getTransferDataFlavors (); 309 } 310 311 public boolean isDataFlavorSupported (DataFlavor flavor) { 312 boolean res = delegate.isDataFlavorSupported (flavor); 313 log.log (Level.FINE, "isDataFlavorSupported: " + flavor + " result: " + res); return res; 315 } 316 317 } 318 } 319 | Popular Tags |