1 11 package org.eclipse.ui.internal.editors.quickdiff; 12 13 import java.io.BufferedReader ; 14 import java.io.IOException ; 15 import java.io.InputStream ; 16 import java.io.InputStreamReader ; 17 import java.io.Reader ; 18 19 import org.eclipse.core.resources.IEncodedStorage; 20 import org.eclipse.core.resources.IFile; 21 import org.eclipse.core.resources.IStorage; 22 import org.eclipse.core.runtime.CoreException; 23 import org.eclipse.core.runtime.IProgressMonitor; 24 import org.eclipse.core.runtime.IStatus; 25 import org.eclipse.core.runtime.OperationCanceledException; 26 import org.eclipse.core.runtime.Platform; 27 import org.eclipse.core.runtime.Status; 28 import org.eclipse.core.runtime.content.IContentDescription; 29 import org.eclipse.core.runtime.jobs.IJobManager; 30 import org.eclipse.core.runtime.jobs.ISchedulingRule; 31 import org.eclipse.core.runtime.jobs.Job; 32 33 import org.eclipse.swt.widgets.Display; 34 import org.eclipse.swt.widgets.Shell; 35 36 import org.eclipse.jface.text.Document; 37 import org.eclipse.jface.text.IDocument; 38 39 import org.eclipse.ui.IEditorInput; 40 import org.eclipse.ui.IStorageEditorInput; 41 import org.eclipse.ui.editors.text.EditorsUI; 42 import org.eclipse.ui.editors.text.IStorageDocumentProvider; 43 import org.eclipse.ui.IWorkbenchPartSite; 44 import org.eclipse.ui.IWorkbenchWindow; 45 import org.eclipse.ui.texteditor.IDocumentProvider; 46 import org.eclipse.ui.texteditor.IElementStateListener; 47 import org.eclipse.ui.texteditor.ITextEditor; 48 import org.eclipse.ui.texteditor.quickdiff.IQuickDiffReferenceProvider; 49 50 56 public class LastSaveReferenceProvider implements IQuickDiffReferenceProvider, IElementStateListener { 57 58 59 private boolean fDocumentRead= false; 60 64 private IDocument fReference= null; 65 69 private String fId; 70 71 private IDocumentProvider fDocumentProvider; 72 73 private IEditorInput fEditorInput; 74 75 private final Object fLock= new Object (); 76 77 private final Object fDocumentAccessorLock= new Object (); 78 79 private boolean fDocumentLocked; 80 84 private IProgressMonitor fProgressMonitor; 85 86 private ITextEditor fEditor; 87 88 91 private final class ReadJob extends Job { 92 93 96 public ReadJob() { 97 super(QuickDiffMessages.getString("LastSaveReferenceProvider.LastSaveReferenceProvider.readJob.label")); setSystem(true); 99 setPriority(SHORT); 100 } 101 102 112 protected IStatus run(IProgressMonitor monitor) { 113 readDocument(monitor, false); 114 return Status.OK_STATUS; 115 } 116 } 117 118 121 public IDocument getReference(IProgressMonitor monitor) { 122 if (!fDocumentRead) 123 readDocument(monitor, true); return fReference; 125 } 126 127 130 public void dispose() { 131 IProgressMonitor monitor= fProgressMonitor; 132 if (monitor != null) { 133 monitor.setCanceled(true); 134 } 135 136 IDocumentProvider provider= fDocumentProvider; 137 138 synchronized (fLock) { 139 if (provider != null) 140 provider.removeElementStateListener(this); 141 fEditorInput= null; 142 fDocumentProvider= null; 143 fReference= null; 144 fDocumentRead= false; 145 fProgressMonitor= null; 146 fEditor= null; 147 } 148 } 149 150 153 public String getId() { 154 return fId; 155 } 156 157 160 public void setActiveEditor(ITextEditor targetEditor) { 161 IDocumentProvider provider= null; 162 IEditorInput input= null; 163 if (targetEditor != null) { 164 provider= targetEditor.getDocumentProvider(); 165 input= targetEditor.getEditorInput(); 166 } 167 168 169 if (provider != fDocumentProvider || input != fEditorInput) { 172 dispose(); 173 synchronized (fLock) { 174 fEditor= targetEditor; 175 fDocumentProvider= provider; 176 fEditorInput= input; 177 } 178 } 179 } 180 181 184 public boolean isEnabled() { 185 return fEditorInput != null && fDocumentProvider != null; 186 } 187 188 191 public void setId(String id) { 192 fId= id; 193 } 194 195 203 private void readDocument(IProgressMonitor monitor, boolean force) { 204 205 IDocumentProvider prov= fDocumentProvider; 207 IEditorInput inp= fEditorInput; 208 IDocument doc= fReference; 209 ITextEditor editor= fEditor; 210 211 if (prov instanceof IStorageDocumentProvider && inp instanceof IStorageEditorInput) { 212 213 IStorageEditorInput input= (IStorageEditorInput) inp; 214 IStorageDocumentProvider provider= (IStorageDocumentProvider) prov; 215 216 if (doc == null) 217 if (force || fDocumentRead) 218 doc= new Document(); 219 else 220 return; 221 222 IJobManager jobMgr= Platform.getJobManager(); 223 224 try { 225 IStorage storage= input.getStorage(); 226 if (storage == null) 228 return; 229 fProgressMonitor= monitor; 230 ISchedulingRule rule= getSchedulingRule(storage); 231 232 236 try { 242 lockDocument(monitor, jobMgr, rule); 243 244 String encoding; 245 if (storage instanceof IEncodedStorage) 246 encoding= ((IEncodedStorage) storage).getCharset(); 247 else 248 encoding= null; 249 250 boolean skipUTF8BOM= isUTF8BOM(encoding, storage); 251 252 setDocumentContent(doc, storage, encoding, monitor, skipUTF8BOM); 253 } finally { 254 unlockDocument(jobMgr, rule); 255 fProgressMonitor= null; 256 } 257 258 } catch (CoreException e) { 259 return; 260 } 261 262 if (monitor != null && monitor.isCanceled()) 263 return; 264 265 synchronized (fLock) { 267 if (fDocumentProvider == provider && fEditorInput == input) { 268 fReference= doc; 271 fDocumentRead= true; 272 addElementStateListener(editor, prov); 273 } 274 } 275 } 276 } 277 278 private ISchedulingRule getSchedulingRule(IStorage storage) { 279 if (storage instanceof ISchedulingRule) 280 return (ISchedulingRule) storage; 281 else if (storage != null) 282 return (ISchedulingRule) storage.getAdapter(ISchedulingRule.class); 283 return null; 284 } 285 286 287 288 private void lockDocument(IProgressMonitor monitor, IJobManager jobMgr, ISchedulingRule rule) { 289 if (rule != null) { 290 jobMgr.beginRule(rule, monitor); 291 } else synchronized (fDocumentAccessorLock) { 292 while (fDocumentLocked) { 293 try { 294 fDocumentAccessorLock.wait(); 295 } catch (InterruptedException e) { 296 throw new OperationCanceledException(); 298 } 299 } 300 fDocumentLocked= true; 301 } 302 } 303 304 private void unlockDocument(IJobManager jobMgr, ISchedulingRule rule) { 305 if (rule != null) { 306 jobMgr.endRule(rule); 307 } else synchronized (fDocumentAccessorLock) { 308 fDocumentLocked= false; 309 fDocumentAccessorLock.notifyAll(); 310 } 311 } 312 313 321 private void addElementStateListener(ITextEditor editor, final IDocumentProvider provider) { 322 325 Runnable runnable= new Runnable () { 326 public void run() { 327 synchronized (fLock) { 328 if (fDocumentProvider == provider) 329 provider.addElementStateListener(LastSaveReferenceProvider.this); 331 } 332 } 333 }; 334 335 Display display= null; 336 if (editor != null) { 337 IWorkbenchPartSite site= editor.getSite(); 338 if (site != null) { 339 IWorkbenchWindow window= site.getWorkbenchWindow(); 340 if (window != null) { 341 Shell shell= window.getShell(); 342 if (shell != null) 343 display= shell.getDisplay(); 344 } 345 } 346 } 347 348 if (display != null && !display.isDisposed()) 349 display.asyncExec(runnable); 350 else 351 runnable.run(); 352 } 353 354 365 private static void setDocumentContent(IDocument document, IStorage storage, String encoding, IProgressMonitor monitor, boolean skipUTF8BOM) throws CoreException { 366 Reader in= null; 367 InputStream contentStream= storage.getContents(); 368 try { 369 370 if (skipUTF8BOM) { 371 for (int i= 0; i < 3; i++) 372 if (contentStream.read() == -1) { 373 throw new IOException (QuickDiffMessages.getString("LastSaveReferenceProvider.LastSaveReferenceProvider.error.notEnoughBytesForBOM")); } 375 } 376 377 final int DEFAULT_FILE_SIZE= 15 * 1024; 378 379 if (encoding == null) 380 in= new BufferedReader (new InputStreamReader (contentStream), DEFAULT_FILE_SIZE); 381 else 382 in= new BufferedReader (new InputStreamReader (contentStream, encoding), DEFAULT_FILE_SIZE); 383 StringBuffer buffer= new StringBuffer (DEFAULT_FILE_SIZE); 384 char[] readBuffer= new char[2048]; 385 int n= in.read(readBuffer); 386 while (n > 0) { 387 if (monitor != null && monitor.isCanceled()) 388 return; 389 390 buffer.append(readBuffer, 0, n); 391 n= in.read(readBuffer); 392 } 393 394 document.set(buffer.toString()); 395 396 } catch (IOException x) { 397 throw new CoreException(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, "Failed to access or read underlying storage", x)); } finally { 399 try { 400 if (in != null) 401 in.close(); 402 else 403 contentStream.close(); 404 } catch (IOException x) { 405 } 407 } 408 } 409 410 427 private static boolean isUTF8BOM(String encoding, IStorage storage) throws CoreException { 428 if (storage instanceof IFile && "UTF-8".equals(encoding)) { IFile file= (IFile) storage; 430 IContentDescription description= file.getContentDescription(); 431 if (description != null) { 432 byte[] bom= (byte[]) description.getProperty(IContentDescription.BYTE_ORDER_MARK); 433 if (bom != null) { 434 if (bom != IContentDescription.BOM_UTF_8) 435 throw new CoreException(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, QuickDiffMessages.getString("LastSaveReferenceProvider.LastSaveReferenceProvider.error.wrongByteOrderMark"), null)); return true; 437 } 438 } 439 } 440 return false; 441 } 442 443 444 445 448 public void elementDirtyStateChanged(Object element, boolean isDirty) { 449 if (!isDirty && element == fEditorInput) { 450 new ReadJob().schedule(); 452 } 453 } 454 455 458 public void elementContentAboutToBeReplaced(Object element) { 459 } 460 461 464 public void elementContentReplaced(Object element) { 465 if (element == fEditorInput) { 466 new ReadJob().schedule(); 468 } 469 } 470 471 474 public void elementDeleted(Object element) { 475 } 476 477 480 public void elementMoved(Object originalElement, Object movedElement) { 481 } 482 } 483 | Popular Tags |