0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2006 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.ui.texteditor;
0011:
0012: import java.lang.reflect.InvocationTargetException;
0013: import java.util.ArrayList;
0014: import java.util.HashMap;
0015: import java.util.HashSet;
0016: import java.util.Iterator;
0017: import java.util.List;
0018: import java.util.Map;
0019: import java.util.Set;
0020:
0021: import org.eclipse.core.runtime.Assert;
0022: import org.eclipse.core.runtime.CoreException;
0023: import org.eclipse.core.runtime.IProgressMonitor;
0024: import org.eclipse.core.runtime.IStatus;
0025: import org.eclipse.core.runtime.NullProgressMonitor;
0026: import org.eclipse.core.runtime.Status;
0027: import org.eclipse.core.runtime.content.IContentType;
0028: import org.eclipse.core.runtime.jobs.ISchedulingRule;
0029:
0030: import org.eclipse.jface.operation.IRunnableContext;
0031: import org.eclipse.jface.operation.IRunnableWithProgress;
0032:
0033: import org.eclipse.jface.text.DocumentEvent;
0034: import org.eclipse.jface.text.IDocument;
0035: import org.eclipse.jface.text.IDocumentListener;
0036: import org.eclipse.jface.text.source.IAnnotationModel;
0037:
0038: import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
0039:
0040: /**
0041: * An abstract implementation of a sharable document provider.
0042: * <p>
0043: * Subclasses must implement <code>createDocument</code>,
0044: * <code>createAnnotationModel</code>, and <code>doSaveDocument</code>.
0045: * </p>
0046: */
0047: public abstract class AbstractDocumentProvider implements
0048: IDocumentProvider, IDocumentProviderExtension,
0049: IDocumentProviderExtension2, IDocumentProviderExtension3,
0050: IDocumentProviderExtension4, IDocumentProviderExtension5 {
0051:
0052: /**
0053: * Operation created by the document provider and to be executed by the providers runnable context.
0054: *
0055: * @since 3.0
0056: */
0057: protected static abstract class DocumentProviderOperation implements
0058: IRunnableWithProgress {
0059:
0060: /**
0061: * The actual functionality of this operation.
0062: *
0063: * @param monitor a progress monitor to track execution
0064: * @throws CoreException
0065: */
0066: protected abstract void execute(IProgressMonitor monitor)
0067: throws CoreException;
0068:
0069: /*
0070: * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
0071: */
0072: public void run(IProgressMonitor monitor)
0073: throws InvocationTargetException, InterruptedException {
0074: try {
0075: execute(monitor);
0076: } catch (CoreException x) {
0077: throw new InvocationTargetException(x);
0078: }
0079: }
0080: }
0081:
0082: /**
0083: * Collection of all information managed for a connected element.
0084: */
0085: protected class ElementInfo implements IDocumentListener {
0086:
0087: /** The element for which the info is stored */
0088: public Object fElement;
0089: /** How often the element has been connected */
0090: public int fCount;
0091: /** Can the element be saved */
0092: public boolean fCanBeSaved;
0093: /** The element's document */
0094: public IDocument fDocument;
0095: /** The element's annotation model */
0096: public IAnnotationModel fModel;
0097: /**
0098: * Has element state been validated
0099: * @since 2.0
0100: */
0101: public boolean fIsStateValidated;
0102: /**
0103: * The status of this element
0104: * @since 2.0
0105: */
0106: public IStatus fStatus;
0107:
0108: /**
0109: * Creates a new element info, initialized with the given
0110: * document and annotation model.
0111: *
0112: * @param document the document
0113: * @param model the annotation model
0114: */
0115: public ElementInfo(IDocument document, IAnnotationModel model) {
0116: fDocument = document;
0117: fModel = model;
0118: fCount = 0;
0119: fCanBeSaved = false;
0120: fIsStateValidated = false;
0121: }
0122:
0123: /**
0124: * An element info equals another object if this object is an element info
0125: * and if the documents of the two element infos are equal.
0126: * @see Object#equals(java.lang.Object)
0127: */
0128: public boolean equals(Object o) {
0129: if (o instanceof ElementInfo) {
0130: ElementInfo e = (ElementInfo) o;
0131: return fDocument.equals(e.fDocument);
0132: }
0133: return false;
0134: }
0135:
0136: /*
0137: * @see Object#hashCode()
0138: */
0139: public int hashCode() {
0140: return fDocument.hashCode();
0141: }
0142:
0143: /*
0144: * @see IDocumentListener#documentChanged(DocumentEvent)
0145: */
0146: public void documentChanged(DocumentEvent event) {
0147: fCanBeSaved = true;
0148: removeUnchangedElementListeners(fElement, this );
0149: fireElementDirtyStateChanged(fElement, fCanBeSaved);
0150: }
0151:
0152: /*
0153: * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
0154: */
0155: public void documentAboutToBeChanged(DocumentEvent event) {
0156: }
0157: }
0158:
0159: /**
0160: * Enables a certain behavior.
0161: * Indicates whether this provider should behave as described in
0162: * use case 5 of http://bugs.eclipse.org/bugs/show_bug.cgi?id=10806.
0163: * Current value: <code>true</code> since 3.0
0164: * @since 2.0
0165: */
0166: static final protected boolean PR10806_UC5_ENABLED = true;
0167:
0168: /**
0169: * Enables a certain behavior.
0170: * Indicates whether this provider should behave as described in
0171: * http://bugs.eclipse.org/bugs/show_bug.cgi?id=14469
0172: * Notes: This contradicts <code>PR10806_UC5_ENABLED</code>.
0173: * Current value: <code>false</code> since 3.0
0174: * @since 2.0
0175: */
0176: static final protected boolean PR14469_ENABLED = false;
0177:
0178: /**
0179: * Constant for representing the OK status. This is considered a value object.
0180: * @since 2.0
0181: */
0182: static final protected IStatus STATUS_OK = new Status(IStatus.OK,
0183: TextEditorPlugin.PLUGIN_ID, IStatus.OK,
0184: EditorMessages.AbstractDocumentProvider_ok, null);
0185:
0186: /**
0187: * Constant for representing the error status. This is considered a value object.
0188: * @since 2.0
0189: */
0190: static final protected IStatus STATUS_ERROR = new Status(
0191: IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.INFO,
0192: EditorMessages.AbstractDocumentProvider_error, null);
0193:
0194: /** Element information of all connected elements */
0195: private Map fElementInfoMap = new HashMap();
0196: /** The element state listeners */
0197: private List fElementStateListeners = new ArrayList();
0198: /**
0199: * The current progress monitor
0200: * @since 2.1
0201: */
0202: private IProgressMonitor fProgressMonitor;
0203:
0204: /**
0205: * Creates a new document provider.
0206: */
0207: protected AbstractDocumentProvider() {
0208: }
0209:
0210: /**
0211: * Creates the document for the given element.
0212: * <p>
0213: * Subclasses must implement this method.</p>
0214: *
0215: * @param element the element
0216: * @return the document
0217: * @exception CoreException if the document could not be created
0218: */
0219: protected abstract IDocument createDocument(Object element)
0220: throws CoreException;
0221:
0222: /**
0223: * Creates an annotation model for the given element.
0224: * <p>
0225: * Subclasses must implement this method.</p>
0226: *
0227: * @param element the element
0228: * @return the annotation model or <code>null</code> if none
0229: * @exception CoreException if the annotation model could not be created
0230: */
0231: protected abstract IAnnotationModel createAnnotationModel(
0232: Object element) throws CoreException;
0233:
0234: /**
0235: * Performs the actual work of saving the given document provided for the
0236: * given element.
0237: * <p>
0238: * Subclasses must implement this method.</p>
0239: *
0240: * @param monitor a progress monitor to report progress and request cancelation
0241: * @param element the element
0242: * @param document the document
0243: * @param overwrite indicates whether an overwrite should happen if necessary
0244: * @exception CoreException if document could not be stored to the given element
0245: */
0246: protected abstract void doSaveDocument(IProgressMonitor monitor,
0247: Object element, IDocument document, boolean overwrite)
0248: throws CoreException;
0249:
0250: /**
0251: * Returns the runnable context for this document provider.
0252: *
0253: * @param monitor a progress monitor to track the operation
0254: * @return the runnable context for this document provider
0255: * @since 3.0
0256: */
0257: protected abstract IRunnableContext getOperationRunner(
0258: IProgressMonitor monitor);
0259:
0260: /**
0261: * Returns the scheduling rule required for executing
0262: * <code>synchronize</code> on the given element. This default
0263: * implementation returns <code>null</code>.
0264: *
0265: * @param element the element
0266: * @return the scheduling rule for <code>synchronize</code>
0267: * @since 3.0
0268: */
0269: protected ISchedulingRule getSynchronizeRule(Object element) {
0270: return null;
0271: }
0272:
0273: /**
0274: * Returns the scheduling rule required for executing
0275: * <code>validateState</code> on the given element. This default
0276: * implementation returns <code>null</code>.
0277: *
0278: * @param element the element
0279: * @return the scheduling rule for <code>validateState</code>
0280: * @since 3.0
0281: */
0282: protected ISchedulingRule getValidateStateRule(Object element) {
0283: return null;
0284: }
0285:
0286: /**
0287: * Returns the scheduling rule required for executing
0288: * <code>save</code> on the given element. This default
0289: * implementation returns <code>null</code>.
0290: *
0291: * @param element the element
0292: * @return the scheduling rule for <code>save</code>
0293: * @since 3.0
0294: */
0295: protected ISchedulingRule getSaveRule(Object element) {
0296: return null;
0297: }
0298:
0299: /**
0300: * Returns the scheduling rule required for executing
0301: * <code>reset</code> on the given element. This default
0302: * implementation returns <code>null</code>.
0303: *
0304: * @param element the element
0305: * @return the scheduling rule for <code>reset</code>
0306: * @since 3.0
0307: */
0308: protected ISchedulingRule getResetRule(Object element) {
0309: return null;
0310: }
0311:
0312: /**
0313: * Returns the element info object for the given element.
0314: *
0315: * @param element the element
0316: * @return the element info object, or <code>null</code> if none
0317: */
0318: protected ElementInfo getElementInfo(Object element) {
0319: return (ElementInfo) fElementInfoMap.get(element);
0320: }
0321:
0322: /**
0323: * Creates a new element info object for the given element.
0324: * <p>
0325: * This method is called from <code>connect</code> when an element info needs
0326: * to be created. The <code>AbstractDocumentProvider</code> implementation
0327: * of this method returns a new element info object whose document and
0328: * annotation model are the values of <code>createDocument(element)</code>
0329: * and <code>createAnnotationModel(element)</code>, respectively. Subclasses
0330: * may override.</p>
0331: *
0332: * @param element the element
0333: * @return a new element info object
0334: * @exception CoreException if the document or annotation model could not be created
0335: */
0336: protected ElementInfo createElementInfo(Object element)
0337: throws CoreException {
0338: return new ElementInfo(createDocument(element),
0339: createAnnotationModel(element));
0340: }
0341:
0342: /**
0343: * Disposes of the given element info object.
0344: * <p>
0345: * This method is called when an element info is disposed. The
0346: * <code>AbstractDocumentProvider</code> implementation of this
0347: * method does nothing. Subclasses may reimplement.</p>
0348: *
0349: * @param element the element
0350: * @param info the element info object
0351: */
0352: protected void disposeElementInfo(Object element, ElementInfo info) {
0353: }
0354:
0355: /**
0356: * Called on initial creation and when the dirty state of the element
0357: * changes to <code>false</code>. Adds all listeners which must be
0358: * active as long as the element is not dirty. This method is called
0359: * before <code>fireElementDirtyStateChanged</code> or <code>
0360: * fireElementContentReplaced</code> is called.
0361: * Subclasses may extend.
0362: *
0363: * @param element the element
0364: * @param info the element info object
0365: */
0366: protected void addUnchangedElementListeners(Object element,
0367: ElementInfo info) {
0368: if (info.fDocument != null)
0369: info.fDocument.addDocumentListener(info);
0370: }
0371:
0372: /**
0373: * Called when the given element gets dirty. Removes all listeners
0374: * which must be active only when the element is not dirty. This
0375: * method is called before <code>fireElementDirtyStateChanged</code>
0376: * or <code>fireElementContentReplaced</code> is called.
0377: * Subclasses may extend.
0378: *
0379: * @param element the element
0380: * @param info the element info object
0381: */
0382: protected void removeUnchangedElementListeners(Object element,
0383: ElementInfo info) {
0384: if (info.fDocument != null)
0385: info.fDocument.removeDocumentListener(info);
0386: }
0387:
0388: /**
0389: * Enumerates the elements connected via this document provider.
0390: *
0391: * @return the list of elements (element type: <code>Object</code>)
0392: */
0393: protected Iterator getConnectedElements() {
0394: Set s = new HashSet();
0395: Set keys = fElementInfoMap.keySet();
0396: if (keys != null)
0397: s.addAll(keys);
0398: return s.iterator();
0399: }
0400:
0401: /*
0402: * @see IDocumentProvider#connect(Object)
0403: */
0404: public final void connect(Object element) throws CoreException {
0405: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0406: if (info == null) {
0407:
0408: info = createElementInfo(element);
0409: if (info == null)
0410: info = new ElementInfo(null, null);
0411:
0412: info.fElement = element;
0413:
0414: addUnchangedElementListeners(element, info);
0415:
0416: fElementInfoMap.put(element, info);
0417: if (fElementInfoMap.size() == 1)
0418: connected();
0419: }
0420: ++info.fCount;
0421: }
0422:
0423: /**
0424: * This hook method is called when this provider starts managing documents for
0425: * elements. I.e. it is called when the first element gets connected to this provider.
0426: * Subclasses may extend.
0427: * @since 2.0
0428: */
0429: protected void connected() {
0430: }
0431:
0432: /*
0433: * @see IDocumentProvider#disconnect
0434: */
0435: public final void disconnect(Object element) {
0436: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0437:
0438: if (info == null)
0439: return;
0440:
0441: if (info.fCount == 1) {
0442:
0443: fElementInfoMap.remove(element);
0444: removeUnchangedElementListeners(element, info);
0445: disposeElementInfo(element, info);
0446:
0447: if (fElementInfoMap.size() == 0)
0448: disconnected();
0449:
0450: } else
0451: --info.fCount;
0452: }
0453:
0454: /**
0455: * This hook method is called when this provider stops managing documents for
0456: * element. I.e. it is called when the last element gets disconnected from this provider.
0457: * Subclasses may extend.
0458: * @since 2.0
0459: */
0460: protected void disconnected() {
0461: }
0462:
0463: /*
0464: * @see IDocumentProvider#getDocument(Object)
0465: */
0466: public IDocument getDocument(Object element) {
0467:
0468: if (element == null)
0469: return null;
0470:
0471: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0472: return (info != null ? info.fDocument : null);
0473: }
0474:
0475: /*
0476: * @see IDocumentProvider#mustSaveDocument(Object)
0477: */
0478: public boolean mustSaveDocument(Object element) {
0479:
0480: if (element == null)
0481: return false;
0482:
0483: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0484: return (info != null ? info.fCount == 1 && info.fCanBeSaved
0485: : false);
0486: }
0487:
0488: /*
0489: * @see IDocumentProvider#getAnnotationModel(Object)
0490: */
0491: public IAnnotationModel getAnnotationModel(Object element) {
0492:
0493: if (element == null)
0494: return null;
0495:
0496: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0497: return (info != null ? info.fModel : null);
0498: }
0499:
0500: /*
0501: * @see IDocumentProvider#canSaveDocument(Object)
0502: */
0503: public boolean canSaveDocument(Object element) {
0504:
0505: if (element == null)
0506: return false;
0507:
0508: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0509: return (info != null ? info.fCanBeSaved : false);
0510: }
0511:
0512: /**
0513: * Executes the actual work of reseting the given elements document.
0514: *
0515: * @param element the element
0516: * @param monitor the progress monitor
0517: * @throws CoreException
0518: * @since 3.0
0519: */
0520: protected void doResetDocument(Object element,
0521: IProgressMonitor monitor) throws CoreException {
0522: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0523: if (info != null) {
0524:
0525: IDocument original = null;
0526: IStatus status = null;
0527:
0528: try {
0529: original = createDocument(element);
0530: } catch (CoreException x) {
0531: status = x.getStatus();
0532: }
0533:
0534: info.fStatus = status;
0535:
0536: if (original != null) {
0537: fireElementContentAboutToBeReplaced(element);
0538: info.fDocument.set(original.get());
0539: if (info.fCanBeSaved) {
0540: info.fCanBeSaved = false;
0541: addUnchangedElementListeners(element, info);
0542: }
0543: fireElementContentReplaced(element);
0544: fireElementDirtyStateChanged(element, false);
0545: }
0546: }
0547: }
0548:
0549: /**
0550: * Executes the given operation in the providers runnable context.
0551: *
0552: * @param operation the operation to be executes
0553: * @param monitor the progress monitor
0554: * @exception CoreException the operation's core exception
0555: * @since 3.0
0556: */
0557: protected void executeOperation(
0558: DocumentProviderOperation operation,
0559: IProgressMonitor monitor) throws CoreException {
0560: try {
0561: IRunnableContext runner = getOperationRunner(monitor);
0562: if (runner != null)
0563: runner.run(false, false, operation);
0564: else
0565: operation.run(monitor);
0566: } catch (InvocationTargetException x) {
0567: Throwable e = x.getTargetException();
0568: if (e instanceof CoreException)
0569: throw (CoreException) e;
0570: String message = (e.getMessage() != null ? e.getMessage()
0571: : ""); //$NON-NLS-1$
0572: throw new CoreException(new Status(IStatus.ERROR,
0573: TextEditorPlugin.PLUGIN_ID, IStatus.ERROR, message,
0574: e));
0575: } catch (InterruptedException x) {
0576: String message = (x.getMessage() != null ? x.getMessage()
0577: : ""); //$NON-NLS-1$
0578: throw new CoreException(new Status(IStatus.CANCEL,
0579: TextEditorPlugin.PLUGIN_ID, IStatus.OK, message, x));
0580: }
0581: }
0582:
0583: /*
0584: * @see IDocumentProvider#resetDocument(Object)
0585: */
0586: public final void resetDocument(final Object element)
0587: throws CoreException {
0588:
0589: if (element == null)
0590: return;
0591:
0592: class ResetOperation extends DocumentProviderOperation
0593: implements ISchedulingRuleProvider {
0594:
0595: protected void execute(IProgressMonitor monitor)
0596: throws CoreException {
0597: doResetDocument(element, monitor);
0598: }
0599:
0600: public ISchedulingRule getSchedulingRule() {
0601: return getResetRule(element);
0602: }
0603: }
0604:
0605: executeOperation(new ResetOperation(), getProgressMonitor());
0606: }
0607:
0608: /*
0609: * @see IDocumentProvider#saveDocument(IProgressMonitor, Object, IDocument, boolean)
0610: */
0611: public final void saveDocument(IProgressMonitor monitor,
0612: final Object element, final IDocument document,
0613: final boolean overwrite) throws CoreException {
0614:
0615: if (element == null)
0616: return;
0617:
0618: class SaveOperation extends DocumentProviderOperation implements
0619: ISchedulingRuleProvider {
0620:
0621: /*
0622: * @see org.eclipse.ui.texteditor.AbstractDocumentProvider.DocumentProviderOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
0623: */
0624: protected void execute(IProgressMonitor pm)
0625: throws CoreException {
0626: ElementInfo info = (ElementInfo) fElementInfoMap
0627: .get(element);
0628: if (info != null) {
0629: if (info.fDocument != document) {
0630: Status status = new Status(
0631: IStatus.WARNING,
0632: TextEditorPlugin.PLUGIN_ID,
0633: IStatus.ERROR,
0634: EditorMessages.AbstractDocumentProvider_error_save_inuse,
0635: null);
0636: throw new CoreException(status);
0637: }
0638:
0639: doSaveDocument(pm, element, document, overwrite);
0640:
0641: if (pm != null && pm.isCanceled())
0642: return;
0643:
0644: info.fCanBeSaved = false;
0645: addUnchangedElementListeners(element, info);
0646: fireElementDirtyStateChanged(element, false);
0647:
0648: } else {
0649: doSaveDocument(pm, element, document, overwrite);
0650: }
0651: }
0652:
0653: public ISchedulingRule getSchedulingRule() {
0654: return getSaveRule(element);
0655: }
0656: }
0657:
0658: executeOperation(new SaveOperation(), monitor);
0659: }
0660:
0661: /**
0662: * The <code>AbstractDocumentProvider</code> implementation of this
0663: * <code>IDocumentProvider</code> method does nothing. Subclasses may
0664: * reimplement.
0665: *
0666: * @param element the element
0667: */
0668: public void aboutToChange(Object element) {
0669: }
0670:
0671: /**
0672: * The <code>AbstractDocumentProvider</code> implementation of this
0673: * <code>IDocumentProvider</code> method does nothing. Subclasses may
0674: * reimplement.
0675: *
0676: * @param element the element
0677: */
0678: public void changed(Object element) {
0679: }
0680:
0681: /*
0682: * @see IDocumentProvider#addElementStateListener(IElementStateListener)
0683: */
0684: public void addElementStateListener(IElementStateListener listener) {
0685: Assert.isNotNull(listener);
0686: if (!fElementStateListeners.contains(listener))
0687: fElementStateListeners.add(listener);
0688: }
0689:
0690: /*
0691: * @see IDocumentProvider#removeElementStateListener(IElementStateListener)
0692: */
0693: public void removeElementStateListener(
0694: IElementStateListener listener) {
0695: Assert.isNotNull(listener);
0696: fElementStateListeners.remove(listener);
0697: }
0698:
0699: /**
0700: * Informs all registered element state listeners about a change in the
0701: * dirty state of the given element.
0702: *
0703: * @param element the element
0704: * @param isDirty the new dirty state
0705: * @see IElementStateListener#elementDirtyStateChanged(Object, boolean)
0706: */
0707: protected void fireElementDirtyStateChanged(Object element,
0708: boolean isDirty) {
0709: Iterator e = new ArrayList(fElementStateListeners).iterator();
0710: while (e.hasNext()) {
0711: IElementStateListener l = (IElementStateListener) e.next();
0712: l.elementDirtyStateChanged(element, isDirty);
0713: }
0714: }
0715:
0716: /**
0717: * Informs all registered element state listeners about an impending
0718: * replace of the given element's content.
0719: *
0720: * @param element the element
0721: * @see IElementStateListener#elementContentAboutToBeReplaced(Object)
0722: */
0723: protected void fireElementContentAboutToBeReplaced(Object element) {
0724: Iterator e = new ArrayList(fElementStateListeners).iterator();
0725: while (e.hasNext()) {
0726: IElementStateListener l = (IElementStateListener) e.next();
0727: l.elementContentAboutToBeReplaced(element);
0728: }
0729: }
0730:
0731: /**
0732: * Informs all registered element state listeners about the just-completed
0733: * replace of the given element's content.
0734: *
0735: * @param element the element
0736: * @see IElementStateListener#elementContentReplaced(Object)
0737: */
0738: protected void fireElementContentReplaced(Object element) {
0739: Iterator e = new ArrayList(fElementStateListeners).iterator();
0740: while (e.hasNext()) {
0741: IElementStateListener l = (IElementStateListener) e.next();
0742: l.elementContentReplaced(element);
0743: }
0744: }
0745:
0746: /**
0747: * Informs all registered element state listeners about the deletion
0748: * of the given element.
0749: *
0750: * @param element the element
0751: * @see IElementStateListener#elementDeleted(Object)
0752: */
0753: protected void fireElementDeleted(Object element) {
0754: Iterator e = new ArrayList(fElementStateListeners).iterator();
0755: while (e.hasNext()) {
0756: IElementStateListener l = (IElementStateListener) e.next();
0757: l.elementDeleted(element);
0758: }
0759: }
0760:
0761: /**
0762: * Informs all registered element state listeners about a move.
0763: *
0764: * @param originalElement the element before the move
0765: * @param movedElement the element after the move
0766: * @see IElementStateListener#elementMoved(Object, Object)
0767: */
0768: protected void fireElementMoved(Object originalElement,
0769: Object movedElement) {
0770: Iterator e = new ArrayList(fElementStateListeners).iterator();
0771: while (e.hasNext()) {
0772: IElementStateListener l = (IElementStateListener) e.next();
0773: l.elementMoved(originalElement, movedElement);
0774: }
0775: }
0776:
0777: /*
0778: * @see IDocumentProvider#getModificationStamp(Object)
0779: * @since 2.0
0780: */
0781: public long getModificationStamp(Object element) {
0782: return 0;
0783: }
0784:
0785: /*
0786: * @see IDocumentProvider#getSynchronizationStamp(Object)
0787: * @since 2.0
0788: */
0789: public long getSynchronizationStamp(Object element) {
0790: return 0;
0791: }
0792:
0793: /*
0794: * @see IDocumentProvider#isDeleted(Object)
0795: * @since 2.0
0796: */
0797: public boolean isDeleted(Object element) {
0798: return false;
0799: }
0800:
0801: /*
0802: * @see IDocumentProviderExtension#isReadOnly(Object)
0803: * @since 2.0
0804: */
0805: public boolean isReadOnly(Object element) {
0806: return true;
0807: }
0808:
0809: /*
0810: * @see IDocumentProviderExtension#isModifiable(Object)
0811: * @since 2.0
0812: */
0813: public boolean isModifiable(Object element) {
0814: return false;
0815: }
0816:
0817: /**
0818: * Returns whether <code>validateState</code> has been called for the given element
0819: * since the element's state has potentially been invalidated.
0820: *
0821: * @param element the element
0822: * @return whether <code>validateState</code> has been called for the given element
0823: * @since 2.0
0824: */
0825: public boolean isStateValidated(Object element) {
0826: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0827: if (info != null)
0828: return info.fIsStateValidated;
0829: return false;
0830: }
0831:
0832: /**
0833: * Hook method for validating the state of the given element. Must not take care of cache updating etc.
0834: * Default implementation is empty.
0835: *
0836: * @param element the element
0837: * @param computationContext the context in which validation happens
0838: * @exception CoreException in case validation fails
0839: * @since 2.0
0840: */
0841: protected void doValidateState(Object element,
0842: Object computationContext) throws CoreException {
0843: }
0844:
0845: /*
0846: * @see IDocumentProviderExtension#validateState(Object, Object)
0847: * @since 2.0
0848: */
0849: public void validateState(final Object element,
0850: final Object computationContext) throws CoreException {
0851: if (element == null)
0852: return;
0853:
0854: class ValidateStateOperation extends DocumentProviderOperation
0855: implements ISchedulingRuleProvider {
0856:
0857: protected void execute(IProgressMonitor monitor)
0858: throws CoreException {
0859: ElementInfo info = (ElementInfo) fElementInfoMap
0860: .get(element);
0861: if (info == null)
0862: return;
0863:
0864: doValidateState(element, computationContext);
0865:
0866: doUpdateStateCache(element);
0867: info.fIsStateValidated = true;
0868: fireElementStateValidationChanged(element, true);
0869: }
0870:
0871: public ISchedulingRule getSchedulingRule() {
0872: return getValidateStateRule(element);
0873: }
0874: }
0875:
0876: executeOperation(new ValidateStateOperation(),
0877: getProgressMonitor());
0878: }
0879:
0880: /**
0881: * Hook method for updating the state of the given element.
0882: * Default implementation is empty.
0883: *
0884: * @param element the element
0885: * @exception CoreException in case state cache updating fails
0886: * @since 2.0
0887: */
0888: protected void doUpdateStateCache(Object element)
0889: throws CoreException {
0890: }
0891:
0892: /**
0893: * Returns whether the state of the element must be invalidated given its
0894: * previous read-only state.
0895: *
0896: * @param element the element
0897: * @param wasReadOnly the previous read-only state
0898: * @return <code>true</code> if the state of the given element must be invalidated
0899: * @since 2.0
0900: */
0901: protected boolean invalidatesState(Object element,
0902: boolean wasReadOnly) {
0903: Assert.isTrue(PR10806_UC5_ENABLED != PR14469_ENABLED);
0904: boolean readOnlyChanged = (isReadOnly(element) != wasReadOnly && !wasReadOnly);
0905: if (PR14469_ENABLED)
0906: return readOnlyChanged && !canSaveDocument(element);
0907: return readOnlyChanged;
0908: }
0909:
0910: /*
0911: * @see IDocumentProviderExtension#updateStateCache(Object)
0912: * @since 2.0
0913: */
0914: final public void updateStateCache(Object element)
0915: throws CoreException {
0916: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
0917: if (info != null) {
0918: boolean wasReadOnly = isReadOnly(element);
0919: doUpdateStateCache(element);
0920: if (invalidatesState(element, wasReadOnly)) {
0921: info.fIsStateValidated = false;
0922: fireElementStateValidationChanged(element, false);
0923: }
0924: }
0925: }
0926:
0927: /*
0928: * @see IDocumentProviderExtension#setCanSaveDocument(Object)
0929: * @since 2.0
0930: */
0931: public void setCanSaveDocument(Object element) {
0932: if (element != null) {
0933: ElementInfo info = (ElementInfo) fElementInfoMap
0934: .get(element);
0935: if (info != null) {
0936: info.fCanBeSaved = true;
0937: removeUnchangedElementListeners(element, info);
0938: fireElementDirtyStateChanged(element, info.fCanBeSaved);
0939: }
0940: }
0941: }
0942:
0943: /**
0944: * Informs all registered element state listeners about a change in the
0945: * state validation of the given element.
0946: *
0947: * @param element the element
0948: * @param isStateValidated
0949: * @see IElementStateListenerExtension#elementStateValidationChanged(Object, boolean)
0950: * @since 2.0
0951: */
0952: protected void fireElementStateValidationChanged(Object element,
0953: boolean isStateValidated) {
0954: Iterator e = new ArrayList(fElementStateListeners).iterator();
0955: while (e.hasNext()) {
0956: Object o = e.next();
0957: if (o instanceof IElementStateListenerExtension) {
0958: IElementStateListenerExtension l = (IElementStateListenerExtension) o;
0959: l.elementStateValidationChanged(element,
0960: isStateValidated);
0961: }
0962: }
0963: }
0964:
0965: /**
0966: * Informs all registered element state listeners about the current state
0967: * change of the element
0968: *
0969: * @param element the element
0970: * @see IElementStateListenerExtension#elementStateChanging(Object)
0971: * @since 2.0
0972: */
0973: protected void fireElementStateChanging(Object element) {
0974: Iterator e = new ArrayList(fElementStateListeners).iterator();
0975: while (e.hasNext()) {
0976: Object o = e.next();
0977: if (o instanceof IElementStateListenerExtension) {
0978: IElementStateListenerExtension l = (IElementStateListenerExtension) o;
0979: l.elementStateChanging(element);
0980: }
0981: }
0982: }
0983:
0984: /**
0985: * Informs all registered element state listeners about the failed
0986: * state change of the element
0987: *
0988: * @param element the element
0989: * @see IElementStateListenerExtension#elementStateChangeFailed(Object)
0990: * @since 2.0
0991: */
0992: protected void fireElementStateChangeFailed(Object element) {
0993: Iterator e = new ArrayList(fElementStateListeners).iterator();
0994: while (e.hasNext()) {
0995: Object o = e.next();
0996: if (o instanceof IElementStateListenerExtension) {
0997: IElementStateListenerExtension l = (IElementStateListenerExtension) o;
0998: l.elementStateChangeFailed(element);
0999: }
1000: }
1001: }
1002:
1003: /*
1004: * @see IDocumentProviderExtension#getStatus(Object)
1005: * @since 2.0
1006: */
1007: public IStatus getStatus(Object element) {
1008: ElementInfo info = (ElementInfo) fElementInfoMap.get(element);
1009: if (info != null) {
1010: if (info.fStatus != null)
1011: return info.fStatus;
1012: return (info.fDocument == null ? STATUS_ERROR : STATUS_OK);
1013: }
1014:
1015: return STATUS_ERROR;
1016: }
1017:
1018: /**
1019: * Performs the actual work of synchronizing the given element.
1020: *
1021: * @param element the element
1022: * @param monitor the progress monitor
1023: * @exception CoreException in the case that synchronization fails
1024: * @since 3.0
1025: */
1026: protected void doSynchronize(Object element,
1027: IProgressMonitor monitor) throws CoreException {
1028: }
1029:
1030: /*
1031: * @see org.eclipse.ui.texteditor.IDocumentProviderExtension#synchronize(Object)
1032: * @since 2.0
1033: */
1034: public final void synchronize(final Object element)
1035: throws CoreException {
1036:
1037: if (element == null)
1038: return;
1039:
1040: class SynchronizeOperation extends DocumentProviderOperation
1041: implements ISchedulingRuleProvider {
1042:
1043: protected void execute(IProgressMonitor monitor)
1044: throws CoreException {
1045: doSynchronize(element, monitor);
1046: }
1047:
1048: public ISchedulingRule getSchedulingRule() {
1049: return getSynchronizeRule(element);
1050: }
1051: }
1052:
1053: executeOperation(new SynchronizeOperation(),
1054: getProgressMonitor());
1055: }
1056:
1057: /*
1058: * @see org.eclipse.ui.texteditor.IDocumentProviderExtension2#getProgressMonitor()
1059: * @since 2.1
1060: */
1061: public IProgressMonitor getProgressMonitor() {
1062: return fProgressMonitor == null ? new NullProgressMonitor()
1063: : fProgressMonitor;
1064: }
1065:
1066: /*
1067: * @see org.eclipse.ui.texteditor.IDocumentProviderExtension2#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
1068: * @since 2.1
1069: */
1070: public void setProgressMonitor(IProgressMonitor progressMonitor) {
1071: fProgressMonitor = progressMonitor;
1072: }
1073:
1074: /*
1075: * @see org.eclipse.ui.texteditor.IDocumentProviderExtension3#isSynchronized(java.lang.Object)
1076: * @since 3.0
1077: */
1078: public boolean isSynchronized(Object element) {
1079: return true;
1080: }
1081:
1082: /*
1083: * @see org.eclipse.ui.texteditor.IDocumentProviderExtension5#isNotSynchronizedException(Object, CoreException)
1084: * @since 3.2
1085: */
1086: public boolean isNotSynchronizedException(Object element,
1087: CoreException ex) {
1088: return false;
1089: }
1090:
1091: /*
1092: * @see org.eclipse.ui.texteditor.IDocumentProviderExtension4#getContentType(java.lang.Object)
1093: * @since 3.1
1094: */
1095: public IContentType getContentType(Object element)
1096: throws CoreException {
1097: return null;
1098: }
1099: }
|