1 11 package org.eclipse.core.internal.filebuffers; 12 13 import java.net.URI ; 14 15 import org.eclipse.core.filesystem.EFS; 16 import org.eclipse.core.filesystem.IFileInfo; 17 18 import org.eclipse.core.runtime.CoreException; 19 import org.eclipse.core.runtime.ILog; 20 import org.eclipse.core.runtime.IPath; 21 import org.eclipse.core.runtime.IProgressMonitor; 22 import org.eclipse.core.runtime.IStatus; 23 import org.eclipse.core.runtime.MultiStatus; 24 import org.eclipse.core.runtime.OperationCanceledException; 25 import org.eclipse.core.runtime.Status; 26 import org.eclipse.core.runtime.SubProgressMonitor; 27 import org.eclipse.core.runtime.jobs.ISchedulingRule; 28 29 import org.eclipse.core.resources.IFile; 30 import org.eclipse.core.resources.IResource; 31 import org.eclipse.core.resources.IResourceChangeEvent; 32 import org.eclipse.core.resources.IResourceChangeListener; 33 import org.eclipse.core.resources.IResourceDelta; 34 import org.eclipse.core.resources.IResourceRuleFactory; 35 import org.eclipse.core.resources.IWorkspace; 36 import org.eclipse.core.resources.IWorkspaceRoot; 37 import org.eclipse.core.resources.ResourcesPlugin; 38 39 import org.eclipse.core.filebuffers.IFileBufferStatusCodes; 40 41 import org.eclipse.jface.text.IDocumentExtension4; 42 43 44 public abstract class ResourceFileBuffer extends AbstractFileBuffer { 45 46 51 private class SafeFileChange implements Runnable { 52 53 56 public SafeFileChange() { 57 } 58 59 65 protected void execute() throws Exception { 66 } 67 68 71 public void preRun() { 72 fManager.fireStateChanging(ResourceFileBuffer.this); 73 } 74 75 78 public void run() { 79 80 if (isDisconnected()) { 81 fManager.fireStateChangeFailed(ResourceFileBuffer.this); 82 return; 83 } 84 85 try { 86 execute(); 87 } catch (Exception x) { 88 FileBuffersPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, "Exception when synchronizing", x)); fManager.fireStateChangeFailed(ResourceFileBuffer.this); 90 } 91 } 92 } 93 94 97 private class FileSynchronizer implements IResourceChangeListener { 98 99 100 private boolean fIsInstalled= false; 101 102 105 public FileSynchronizer() { 106 } 107 108 111 public void install() { 112 fFile.getWorkspace().addResourceChangeListener(this); 113 fIsInstalled= true; 114 } 115 116 119 public void uninstall() { 120 fFile.getWorkspace().removeResourceChangeListener(this); 121 fIsInstalled= false; 122 } 123 124 127 public void resourceChanged(IResourceChangeEvent e) { 128 IResourceDelta delta= e.getDelta(); 129 if (delta != null) 130 delta= delta.findMember(fFile.getFullPath()); 131 132 if (delta != null && fIsInstalled) { 133 SafeFileChange fileChange= null; 134 135 final int flags= delta.getFlags(); 136 switch (delta.getKind()) { 137 case IResourceDelta.CHANGED: 138 if ((IResourceDelta.ENCODING & flags) != 0) { 139 if (!isDisconnected() && !fCanBeSaved && isSynchronized()) { 140 fileChange= new SafeFileChange() { 141 protected void execute() throws Exception { 142 handleFileContentChanged(false); 143 } 144 }; 145 } 146 } 147 if (fileChange == null && (IResourceDelta.CONTENT & flags) != 0) { 148 if (!isDisconnected() && !fCanBeSaved && (!isSynchronized() || (IResourceDelta.REPLACED & flags) != 0)) { 149 fileChange= new SafeFileChange() { 150 protected void execute() throws Exception { 151 handleFileContentChanged(false); 152 } 153 }; 154 } 155 } 156 break; 157 case IResourceDelta.REMOVED: 158 if ((IResourceDelta.MOVED_TO & flags) != 0) { 159 final IPath path= delta.getMovedToPath(); 160 fileChange= new SafeFileChange() { 161 protected void execute() throws Exception { 162 handleFileMoved(path); 163 } 164 }; 165 } else { 166 if (!isDisconnected() && !fCanBeSaved) { 167 fileChange= new SafeFileChange() { 168 protected void execute() throws Exception { 169 handleFileDeleted(); 170 } 171 }; 172 } 173 } 174 break; 175 } 176 177 if (fileChange != null) { 178 fileChange.preRun(); 179 fManager.execute(fileChange, isSynchronizationContextRequested()); 180 } 181 } 182 } 183 } 184 185 186 187 188 protected IPath fLocation; 189 190 protected IFile fFile; 191 192 protected int fReferenceCount; 193 194 protected boolean fCanBeSaved= false; 195 196 protected boolean fIsStateValidated= false; 197 198 protected IStatus fStatus; 199 200 protected FileSynchronizer fFileSynchronizer; 201 202 protected long fSynchronizationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 203 204 protected int fSynchronizationContextCount; 205 206 protected ResourceTextFileBufferManager fManager; 207 208 209 public ResourceFileBuffer(ResourceTextFileBufferManager manager) { 210 super(); 211 fManager= manager; 212 } 213 214 215 abstract protected void addFileBufferContentListeners(); 216 217 abstract protected void removeFileBufferContentListeners(); 218 219 abstract protected void initializeFileBufferContent(IProgressMonitor monitor) throws CoreException; 220 221 abstract protected void commitFileBufferContent(IProgressMonitor monitor, boolean overwrite) throws CoreException; 222 223 abstract protected void handleFileContentChanged(boolean revert) throws CoreException; 224 225 226 public void create(IPath location, IProgressMonitor monitor) throws CoreException { 227 monitor= Progress.getMonitor(monitor); 228 monitor.beginTask(FileBuffersMessages.ResourceFileBuffer_task_creatingFileBuffer, 2); 229 230 try { 231 IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot(); 232 IFile file= workspaceRoot.getFile(location); 233 if (file == null) 234 throw new CoreException(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.ResourceFileBuffer_error_fileDoesNotExist, null)); 235 URI uri= file.getLocationURI(); 236 if (uri == null) 237 throw new CoreException(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.ResourceFileBuffer_error_fileDoesNotExist, null)); 238 239 fLocation= location; 240 fFile= file; 241 fFileStore= EFS.getStore(uri); 242 fFileSynchronizer= new FileSynchronizer(); 243 244 SubProgressMonitor subMonitor= new SubProgressMonitor(monitor, 1); 245 initializeFileBufferContent(subMonitor); 246 subMonitor.done(); 247 248 fSynchronizationStamp= fFile.getModificationStamp(); 249 250 addFileBufferContentListeners(); 251 252 } finally { 253 monitor.done(); 254 } 255 } 256 257 public void connect() { 258 ++fReferenceCount; 259 if (fReferenceCount == 1) 260 connected(); 261 } 262 263 269 protected void connected() { 270 fFileSynchronizer.install(); 271 } 272 273 public void disconnect() throws CoreException { 274 --fReferenceCount; 275 if (fReferenceCount <= 0) 276 disconnected(); 277 } 278 279 285 protected void disconnected() { 286 if (fFileSynchronizer != null) { 287 fFileSynchronizer.uninstall(); 288 fFileSynchronizer= null; 289 } 290 removeFileBufferContentListeners(); 291 } 292 293 297 public boolean isDisconnected() { 298 return fFileSynchronizer == null; 299 } 300 301 304 public IPath getLocation() { 305 return fLocation; 306 } 307 308 311 public ISchedulingRule computeCommitRule() { 312 IResourceRuleFactory factory= ResourcesPlugin.getWorkspace().getRuleFactory(); 313 return factory.modifyRule(fFile); 314 } 315 316 319 public void commit(IProgressMonitor monitor, boolean overwrite) throws CoreException { 320 if (!isDisconnected() && fCanBeSaved) { 321 322 fManager.fireStateChanging(this); 323 324 try { 325 commitFileBufferContent(monitor, overwrite); 326 } catch (CoreException x) { 327 fManager.fireStateChangeFailed(this); 328 throw x; 329 } catch (RuntimeException x) { 330 fManager.fireStateChangeFailed(this); 331 throw x; 332 } 333 334 fCanBeSaved= false; 335 fManager.fireDirtyStateChanged(this, fCanBeSaved); 336 } 337 } 338 339 342 public void revert(IProgressMonitor monitor) throws CoreException { 343 if (isDisconnected()) 344 return; 345 346 if (!fFile.isSynchronized(IResource.DEPTH_INFINITE)) { 347 fCanBeSaved= false; 348 refreshFile(monitor); 349 return; 350 } 351 352 try { 353 fManager.fireStateChanging(this); 354 handleFileContentChanged(true); 355 } catch (RuntimeException x) { 356 fManager.fireStateChangeFailed(this); 357 throw x; 358 } 359 } 360 361 364 public boolean isDirty() { 365 return fCanBeSaved; 366 } 367 368 371 public void setDirty(boolean isDirty) { 372 fCanBeSaved= isDirty; 373 } 374 375 378 public boolean isShared() { 379 return fReferenceCount > 1; 380 } 381 382 385 public ISchedulingRule computeValidateStateRule() { 386 IResourceRuleFactory factory= ResourcesPlugin.getWorkspace().getRuleFactory(); 387 return factory.validateEditRule(new IResource[] { fFile }); 388 } 389 390 393 public void validateState(IProgressMonitor monitor, Object computationContext) throws CoreException { 394 if (!isDisconnected() && !fIsStateValidated) { 395 396 fStatus= null; 397 398 fManager.fireStateChanging(this); 399 400 try { 401 if (fFile.isReadOnly()) { 402 IWorkspace workspace= fFile.getWorkspace(); 403 fStatus= workspace.validateEdit(new IFile[] { fFile }, computationContext); 404 if (fStatus.isOK()) 405 handleFileContentChanged(false); 406 } 407 408 if (isDerived(fFile)) { 409 IStatus status= new Status(IStatus.WARNING, FileBuffersPlugin.PLUGIN_ID, IFileBufferStatusCodes.DERIVED_FILE, FileBuffersMessages.ResourceFileBuffer_warning_fileIsDerived, null); 410 if (fStatus == null || fStatus.isOK()) 411 fStatus= status; 412 else 413 fStatus= new MultiStatus(FileBuffersPlugin.PLUGIN_ID, IFileBufferStatusCodes.STATE_VALIDATION_FAILED, new IStatus[] {fStatus, status}, FileBuffersMessages.ResourceFileBuffer_stateValidationFailed, null); 414 } 415 416 } catch (RuntimeException x) { 417 fManager.fireStateChangeFailed(this); 418 throw x; 419 } 420 421 fIsStateValidated= fStatus == null || fStatus.getSeverity() != IStatus.CANCEL; 422 fManager.fireStateValidationChanged(this, fIsStateValidated); 423 } 424 } 425 426 431 private boolean isDerived(IResource resource) { 432 while (resource != null) { 433 if (resource.isDerived()) 434 return true; 435 resource= resource.getParent(); 436 } 437 return false; 438 } 439 440 443 public boolean isStateValidated() { 444 return fIsStateValidated; 445 } 446 447 450 public void resetStateValidation() { 451 if (fIsStateValidated) { 452 fIsStateValidated= false; 453 fManager.fireStateValidationChanged(this, fIsStateValidated); 454 } 455 } 456 457 462 protected void handleFileMoved(IPath newLocation) { 463 fManager.fireUnderlyingFileMoved(this, newLocation); 464 } 465 466 469 protected void handleFileDeleted() { 470 fManager.fireUnderlyingFileDeleted(this); 471 } 472 473 478 protected void refreshFile(IProgressMonitor monitor) { 479 try { 480 fFile.refreshLocal(IResource.DEPTH_INFINITE, monitor); 481 } catch (OperationCanceledException x) { 482 } catch (CoreException x) { 483 handleCoreException(x); 484 } 485 } 486 487 493 protected void handleCoreException(CoreException exception) { 494 ILog log= FileBuffersPlugin.getDefault().getLog(); 495 log.log(exception.getStatus()); 496 } 497 498 501 public boolean isSynchronized() { 502 if (fSynchronizationStamp == fFile.getModificationStamp() && fFile.isSynchronized(IResource.DEPTH_ZERO)) 503 return true; 504 505 fSynchronizationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 506 return false; 507 } 508 509 512 public void requestSynchronizationContext() { 513 ++ fSynchronizationContextCount; 514 } 515 516 519 public void releaseSynchronizationContext() { 520 -- fSynchronizationContextCount; 521 } 522 523 526 public boolean isSynchronizationContextRequested() { 527 return fSynchronizationContextCount > 0; 528 } 529 530 533 public boolean isCommitable() { 534 IFileInfo info= fFileStore.fetchInfo(); 535 return info.exists() && !info.getAttribute(EFS.ATTRIBUTE_READ_ONLY); 536 } 537 538 541 public void validationStateChanged(boolean validationState, IStatus status) { 542 fIsStateValidated= validationState; 543 fStatus= status; 544 } 545 } 546 | Popular Tags |