KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > RemoteRevisionQuickDiffProvider


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.internal.ccvs.ui;
12
13 import java.io.*;
14
15 import org.eclipse.core.resources.IFile;
16 import org.eclipse.core.resources.IResource;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.core.runtime.jobs.Job;
19 import org.eclipse.jface.text.Document;
20 import org.eclipse.jface.text.IDocument;
21 import org.eclipse.team.core.TeamException;
22 import org.eclipse.team.core.subscribers.ISubscriberChangeEvent;
23 import org.eclipse.team.core.subscribers.ISubscriberChangeListener;
24 import org.eclipse.team.core.synchronize.SyncInfo;
25 import org.eclipse.team.internal.ccvs.core.*;
26 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
27 import org.eclipse.ui.IEditorInput;
28 import org.eclipse.ui.editors.text.IStorageDocumentProvider;
29 import org.eclipse.ui.ide.ResourceUtil;
30 import org.eclipse.ui.texteditor.*;
31 import org.eclipse.ui.texteditor.quickdiff.IQuickDiffReferenceProvider;
32
33 /**
34  * A QuickDiff provider that provides a reference to the latest revision of a file
35  * in the CVS repository. The provider notifies when the file's sync state changes
36  * and the diff should be recalculated (e.g. commit, update...) or when the file
37  * is changed (e.g. replace with).
38  *
39  * Here are the file states and what this provider does for each:
40  *
41  * 1. File is unmanaged : reference == empty document
42  * 2. Unmanaged file transitions to managed : empty reference updated with new remote revision
43  * 3. A managed file has new remote (commit, refresh remote) : reference updated with new
44  * remote revision
45  * 4. A managed file cleaned, remote is the same (replace with, update) : refresh diff bar
46  * with existing reference
47  *
48  * [Note: Currently an empty document must be returned for an unmanaged file. This
49  * results in the entire document appearing as outgoing changes in the quickdiff bar.
50  * This is required because the quickdiff support relies on IDocument change events
51  * to update the quickdiff, and returning null for the reference document doesn't
52  * allow the transition to later return a IDocument.]
53  *
54  * @since 3.0
55  */

56 public class RemoteRevisionQuickDiffProvider implements IQuickDiffReferenceProvider {
57     // The editor showing this quickdiff and provides access to the editor input and
58
// ultimatly the IFile.
59
private ITextEditor fEditor = null;
60     
61     // The document containing the remote file. Can be null if the assigned editor doesn't have
62
// a CVS remote resource associated with it.
63
private IDocument fReference = null;
64     
65     // Will be true when the document has been read and initialized.
66
private boolean fReferenceInitialized = false;
67     
68     // Document provider allows us to register/deregister the element state change listener.
69
private IDocumentProvider fDocumentProvider = null;
70
71     // Unique id for this reference provider as set via setId().
72
private String JavaDoc fId;
73     
74     // A handle to the remote CVS file for this provider.
75
private SyncInfo fLastSyncState;
76
77     // Job that re-creates the reference document.
78
private Job fUpdateJob;
79     
80     private boolean DEBUG = false;
81     
82     /**
83      * Updates the document if a sync changes occurs to the associated CVS file.
84      */

85     private ISubscriberChangeListener teamChangeListener = new ISubscriberChangeListener() {
86         public void subscriberResourceChanged(ISubscriberChangeEvent[] deltas) {
87             if(fReferenceInitialized) {
88                 for (int i = 0; i < deltas.length; i++) {
89                     ISubscriberChangeEvent delta = deltas[i];
90                     IResource resource = delta.getResource();
91                     if(resource.getType() == IResource.FILE &&
92                        fLastSyncState != null && resource.equals(fLastSyncState.getLocal())) {
93                         if(delta.getFlags() == ISubscriberChangeEvent.SYNC_CHANGED) {
94                             fetchContentsInJob();
95                         }
96                     }
97                 }
98             }
99         }
100     };
101
102     /**
103      * Updates the document if the document is changed (e.g. replace with)
104      */

105     private IElementStateListener documentListener = new IElementStateListener() {
106         public void elementDirtyStateChanged(Object JavaDoc element, boolean isDirty) {
107         }
108
109         public void elementContentAboutToBeReplaced(Object JavaDoc element) {
110         }
111
112         public void elementContentReplaced(Object JavaDoc element) {
113             if(fEditor != null && fEditor.getEditorInput() == element) {
114                 fetchContentsInJob();
115             }
116         }
117
118         public void elementDeleted(Object JavaDoc element) {
119         }
120
121         public void elementMoved(Object JavaDoc originalElement, Object JavaDoc movedElement) {
122         }
123     };
124
125     /*
126      * @see org.eclipse.test.quickdiff.DocumentLineDiffer.IQuickDiffReferenceProvider#getReference()
127      */

128     public IDocument getReference(IProgressMonitor monitor) throws CoreException {
129         if(! fReferenceInitialized) return null;
130         if (fReference == null) {
131             readDocument(monitor);
132         }
133         return fReference;
134     }
135
136     /* (non-Javadoc)
137      * @see org.eclipse.ui.texteditor.quickdiff.IQuickDiffProviderImplementation#setActiveEditor(org.eclipse.ui.texteditor.ITextEditor)
138      */

139     public void setActiveEditor(ITextEditor targetEditor) {
140         IEditorInput editorInput = targetEditor.getEditorInput();
141         if (editorInput == null || ResourceUtil.getFile(editorInput) == null) return;
142         fEditor = targetEditor;
143         fDocumentProvider= fEditor.getDocumentProvider();
144         
145         if(fDocumentProvider != null) {
146             CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().addListener(teamChangeListener);
147             fDocumentProvider.addElementStateListener(documentListener);
148         }
149         fReferenceInitialized= true;
150     }
151
152     /* (non-Javadoc)
153      * @see org.eclipse.ui.texteditor.quickdiff.IQuickDiffProviderImplementation#isEnabled()
154      */

155     public boolean isEnabled() {
156         if (! fReferenceInitialized)
157             return false;
158         try {
159             return getManagedCVSFile() != null;
160         } catch (CVSException e) {
161             return false;
162         }
163     }
164
165     /*
166      * @see org.eclipse.jface.text.source.diff.DocumentLineDiffer.IQuickDiffReferenceProvider#dispose()
167      */

168     public void dispose() {
169         fReferenceInitialized = false;
170         // stop update job
171
if(fUpdateJob != null && fUpdateJob.getState() != Job.NONE) {
172             fUpdateJob.cancel();
173         }
174         
175         // remove listeners
176
if(fDocumentProvider != null) {
177             fDocumentProvider.removeElementStateListener(documentListener);
178         }
179         CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().removeListener(teamChangeListener);
180     }
181
182     /*
183      * @see org.eclipse.quickdiff.QuickDiffTestPlugin.IQuickDiffProviderImplementation#setId(java.lang.String)
184      */

185     public void setId(String JavaDoc id) {
186         fId= id;
187     }
188
189     /*
190      * @see org.eclipse.jface.text.source.diff.DocumentLineDiffer.IQuickDiffReferenceProvider#getId()
191      */

192     public String JavaDoc getId() {
193         return fId;
194     }
195     
196     /**
197      * Determine if the file represented by this quickdiff provider has changed with
198      * respect to it's remote state. Return true if the remote contents should be
199      * refreshed, and false if not.
200      */

201     private boolean computeChange(IProgressMonitor monitor) throws TeamException {
202         boolean needToUpdateReferenceDocument = false;
203         if(fReferenceInitialized) {
204             SyncInfo info = getSyncState(getFileFromEditor());
205             if(info == null && fLastSyncState != null) {
206                 return true;
207             } else if(info == null) {
208                 return false;
209             }
210                     
211             if(fLastSyncState == null) {
212                 needToUpdateReferenceDocument = true;
213             } else if(! fLastSyncState.equals(info)) {
214                 needToUpdateReferenceDocument = true;
215             }
216             if(DEBUG) debug(fLastSyncState, info);
217             fLastSyncState = info;
218         }
219         return needToUpdateReferenceDocument;
220     }
221     
222     private void debug(SyncInfo lastSyncState, SyncInfo info) {
223         String JavaDoc last = "[none]"; //$NON-NLS-1$
224
if(lastSyncState != null) {
225             last = lastSyncState.toString();
226         }
227         System.out.println("+ CVSQuickDiff: was " + last + " is " + info.toString()); //$NON-NLS-1$ //$NON-NLS-2$
228
}
229
230     private SyncInfo getSyncState(IResource resource) throws TeamException {
231         if (resource == null) return null;
232         return CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().getSyncInfo(resource);
233     }
234     
235     /**
236      * Creates a document and initializes it with the contents of a CVS remote
237      * resource.
238      * @param monitor the progress monitor
239      * @throws CoreException
240      */

241     private void readDocument(IProgressMonitor monitor) throws CoreException {
242         if(! fReferenceInitialized) return;
243         if(fReference == null)
244             fReference = new Document();
245         if(computeChange(monitor)) {
246             ICVSRemoteFile remoteFile = (ICVSRemoteFile)fLastSyncState.getRemote();
247             if (fLastSyncState.getRemote() != null && fDocumentProvider instanceof IStorageDocumentProvider) {
248                 IStorageDocumentProvider provider= (IStorageDocumentProvider) fDocumentProvider;
249                 String JavaDoc encoding= provider.getEncoding(fEditor.getEditorInput());
250                 if (encoding == null) {
251                     encoding= provider.getDefaultEncoding();
252                 }
253                 if(monitor.isCanceled()) return;
254                 InputStream stream= remoteFile.getContents(monitor);
255                 if (stream == null || monitor.isCanceled() || ! fReferenceInitialized) {
256                     return;
257                 }
258                 setDocumentContent(fReference, stream, encoding);
259             } else {
260                 // the remote is null, so ensure that the document is null
261
if(monitor.isCanceled()) return;
262                 fReference.set(""); //$NON-NLS-1$
263
}
264             if(DEBUG) System.out.println("+ CVSQuickDiff: updating document " + (fReference!=null ? "remote found" : "remote empty")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
265
}
266     }
267     
268     /**
269      * Intitializes the given document with the given stream using the given encoding.
270      *
271      * @param document the document to be initialized
272      * @param contentStream the stream which delivers the document content
273      * @param encoding the character encoding for reading the given stream
274      * @exception CoreException if the given stream can not be read
275      */

276     private static void setDocumentContent(IDocument document, InputStream contentStream, String JavaDoc encoding) throws CoreException {
277         Reader in= null;
278         try {
279             final int DEFAULT_FILE_SIZE= 15 * 1024;
280
281             in= new BufferedReader(new InputStreamReader(contentStream, encoding), DEFAULT_FILE_SIZE);
282             CharArrayWriter caw= new CharArrayWriter(DEFAULT_FILE_SIZE);
283             char[] readBuffer= new char[2048];
284             int n= in.read(readBuffer);
285             while (n > 0) {
286                 caw.write(readBuffer, 0, n);
287                 n= in.read(readBuffer);
288             }
289             document.set(caw.toString());
290             //System.out.println("+ CVSQuickDiff: updating document : " + caw.toString());
291
} catch (IOException x) {
292             IStatus status = new CVSStatus(IStatus.ERROR, CVSStatus.ERROR, CVSUIMessages.RemoteRevisionQuickDiffProvider_readingFile, x);
293             throw new CVSException(status);
294         } finally {
295             if (in != null) {
296                 try {
297                     in.close();
298                 } catch (IOException x) {
299                     IStatus status = new CVSStatus(IStatus.ERROR, CVSStatus.ERROR, CVSUIMessages.RemoteRevisionQuickDiffProvider_closingFile, x);
300                     throw new CVSException(status);
301                 }
302             }
303         }
304     }
305     
306     /**
307      * Returns the ICVSFile associated with he active editor or <code>null</code>
308      * if the provider doesn't not have access to a CVS managed file.
309      * @return the handle to a CVS file
310      */

311     private ICVSFile getManagedCVSFile() throws CVSException {
312         if(fEditor != null) {
313             IFile file = getFileFromEditor();
314                 if(file != null && CVSWorkspaceRoot.isSharedWithCVS(file)) {
315                     return CVSWorkspaceRoot.getCVSFileFor(file);
316                 }
317         }
318         return null;
319     }
320
321     private IFile getFileFromEditor() {
322         if(fEditor != null) {
323             IEditorInput input= fEditor.getEditorInput();
324             if (input != null) {
325                 IFile file = ResourceUtil.getFile(input);
326                 return file;
327             }
328         }
329         return null;
330     }
331     
332     /**
333      * Runs a job that updates the document. If a previous job is already running it
334      * is stopped before the new job can start.
335      */

336     private void fetchContentsInJob() {
337         if(! fReferenceInitialized) return;
338         if(fUpdateJob != null && fUpdateJob.getState() != Job.NONE) {
339             fUpdateJob.cancel();
340         }
341         fUpdateJob = new Job(CVSUIMessages.RemoteRevisionQuickDiffProvider_fetchingFile) {
342             protected IStatus run(IProgressMonitor monitor) {
343                 try {
344                     readDocument(monitor);
345                 } catch (CoreException e) {
346                     // continue and return ok for now. The error will be reported
347
// when the quick diff supports calls getReference() again.
348
// continue
349
}
350                 return Status.OK_STATUS;
351             }
352         };
353         fUpdateJob.schedule();
354     }
355 }
356
Popular Tags