KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > operations > ShowAnnotationOperation


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  * Eugene Kuleshov <eu@md.pp.ru> - Bug 173959 add mechanism for navigating from team annotation to corresponding task
11  *******************************************************************************/

12 package org.eclipse.team.internal.ccvs.ui.operations;
13
14 import java.io.*;
15 import java.util.*;
16
17 import org.eclipse.core.resources.*;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.jface.dialogs.IDialogConstants;
20 import org.eclipse.jface.dialogs.MessageDialogWithToggle;
21 import org.eclipse.jface.preference.IPreferenceStore;
22 import org.eclipse.jface.resource.JFaceResources;
23 import org.eclipse.jface.text.IInformationControl;
24 import org.eclipse.jface.text.IInformationControlCreator;
25 import org.eclipse.jface.text.revisions.Revision;
26 import org.eclipse.jface.text.revisions.RevisionInformation;
27 import org.eclipse.jface.text.source.LineRange;
28 import org.eclipse.osgi.util.NLS;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.graphics.RGB;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.swt.widgets.Shell;
33 import org.eclipse.team.core.TeamException;
34 import org.eclipse.team.core.variants.IResourceVariant;
35 import org.eclipse.team.internal.ccvs.core.*;
36 import org.eclipse.team.internal.ccvs.core.client.*;
37 import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption;
38 import org.eclipse.team.internal.ccvs.core.client.listeners.AnnotateListener;
39 import org.eclipse.team.internal.ccvs.core.connection.CVSServerException;
40 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
41 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
42 import org.eclipse.team.internal.ccvs.core.util.KnownRepositories;
43 import org.eclipse.team.internal.ccvs.ui.*;
44 import org.eclipse.team.internal.ccvs.ui.Policy;
45 import org.eclipse.team.internal.core.TeamPlugin;
46 import org.eclipse.team.internal.ui.Utils;
47 import org.eclipse.team.ui.TeamUI;
48 import org.eclipse.team.ui.history.*;
49 import org.eclipse.ui.*;
50 import org.eclipse.ui.editors.text.EditorsUI;
51 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
52
53 import com.ibm.icu.text.DateFormat;
54
55 /**
56  * An operation to fetch the annotations for a file from the repository and
57  * display them in the annotations view.
58  */

59 public class ShowAnnotationOperation extends CVSOperation {
60     
61     private final ICVSResource fCVSResource;
62     private final String JavaDoc fRevision;
63     private final boolean fBinary;
64
65     public ShowAnnotationOperation(IWorkbenchPart part, ICVSResource cvsResource, String JavaDoc revision, boolean binary) {
66         super(part);
67         fCVSResource= cvsResource;
68         fRevision= revision;
69         fBinary = binary;
70     }
71
72     /* (non-Javadoc)
73      * @see org.eclipse.team.internal.ccvs.ui.operations.CVSOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
74      */

75     protected void execute(IProgressMonitor monitor) throws CVSException, InterruptedException JavaDoc {
76
77         final boolean useLiveAnnotate= isKnownUseLiveAnnotate();
78         final boolean useView= isKnownUseView();
79         
80         monitor.beginTask(null, 80 + (useView ? 0 : 20) + (useLiveAnnotate ? 0 : 20));
81
82         // Get the annotations from the repository.
83
final AnnotateListener listener= new AnnotateListener();
84         fetchAnnotation(listener, fCVSResource, fRevision, Policy.subMonitorFor(monitor, 80));
85
86         // If we're not using live annotate or the file is a remote file,
87
// we need to fetch the contents to ensure the encoding is correct
88
// (i.e. the contents from the annotate command will only work if the file is ASCII).
89
if (!useLiveAnnotate || fCVSResource.getIResource() == null)
90             fetchContents(listener, Policy.subMonitorFor(monitor, 20));
91
92         // this is not needed if there is no live annotate
93
final RevisionInformation information;
94         if (!useView)
95             information= createRevisionInformation(listener, Policy.subMonitorFor(monitor, 20));
96         else
97             information= null;
98
99         // Open the view and display it from the UI thread.
100
final Display display= getPart().getSite().getShell().getDisplay();
101         display.asyncExec(new Runnable JavaDoc() {
102             public void run() {
103                 //If the file being annotated is not binary, check to see if we can use the quick
104
//annotate. Until we are able to show quick diff annotate on read only text editors
105
//we can't make use of it for binary files/remote files.
106
boolean useQuickDiffAnnotate = promptForQuickDiffAnnotate();
107                 if (useQuickDiffAnnotate){
108                     try {
109                         //is there an open editor for the given input? If yes, use live annotate
110
final AbstractDecoratedTextEditor editor= getEditor(listener);
111                         if (editor != null) {
112                             editor.showRevisionInformation(information, "org.eclipse.quickdiff.providers.CVSReferenceProvider"); //$NON-NLS-1$
113
final IWorkbenchPage page= getPart().getSite().getPage();
114                             showHistoryView(page, editor);
115                             page.activate(editor);
116                         }
117                     } catch (PartInitException e) {
118                         CVSException.wrapException(e);
119                     }
120                 } else
121                     showView(listener);
122             }
123         });
124         
125         monitor.done();
126     }
127     
128     /**
129      * Shows the history view, creating it if necessary, but does not give it focus.
130      *
131      * @param page the workbench page to operate in
132      * @param editor the editor that is showing the file
133      * @return the history view
134      * @throws PartInitException
135      */

136     private IHistoryView showHistoryView(IWorkbenchPage page, AbstractDecoratedTextEditor editor) throws PartInitException {
137         Object JavaDoc object = fCVSResource.getIResource();
138         if (object == null)
139             object = editor.getEditorInput();
140         IHistoryView historyView= TeamUI.showHistoryFor(page, object, null);
141         IHistoryPage historyPage = historyView.getHistoryPage();
142         if (historyPage instanceof CVSHistoryPage){
143             CVSHistoryPage cvsHistoryPage = (CVSHistoryPage) historyPage;
144             cvsHistoryPage.setMode(CVSHistoryPage.REMOTE_MODE);
145             // We need to call link to ensure that the history page gets linked
146
// even if the page input did not change
147
cvsHistoryPage.linkWithEditor();
148         }
149         return historyView;
150     }
151
152     /* (non-Javadoc)
153      * @see org.eclipse.team.internal.ccvs.ui.operations.CVSOperation#getTaskName()
154      */

155     protected String JavaDoc getTaskName() {
156         return CVSUIMessages.ShowAnnotationOperation_taskName;
157     }
158
159     protected boolean hasCharset(ICVSResource cvsResource, InputStream contents) {
160         try {
161             return TeamPlugin.getCharset(cvsResource.getName(), contents) != null;
162         } catch (IOException e) {
163             // Assume that the contents do have a charset
164
return true;
165         }
166     }
167
168     /**
169      * Shows the view once the background operation is finished. This must be called
170      * from the UI thread.
171      *
172      * @param listener The listener with the results.
173      */

174     protected void showView(final AnnotateListener listener) {
175         final IWorkbench workbench= PlatformUI.getWorkbench();
176         final IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
177         
178         final String JavaDoc defaultPerspectiveID= promptForPerspectiveSwitch();
179
180         if (defaultPerspectiveID != null) {
181             try {
182                 workbench.showPerspective(defaultPerspectiveID, window);
183             } catch (WorkbenchException e) {
184                 Utils.handleError(window.getShell(), e, CVSUIMessages.ShowAnnotationOperation_0, e.getMessage());
185             }
186         }
187        
188         try {
189             final AnnotateView view = AnnotateView.openInActivePerspective();
190             view.showAnnotations(fCVSResource, listener.getCvsAnnotateBlocks(), listener.getContents());
191         } catch (PartInitException e) {
192             CVSUIPlugin.log(e);
193         } catch (CVSException e) {
194             CVSUIPlugin.log(e);
195         }
196     }
197
198     private AbstractDecoratedTextEditor getEditor(AnnotateListener listener) throws PartInitException {
199         IResource resource= fCVSResource.getIResource();
200         if (resource instanceof IFile){
201             return RevisionAnnotationController.openEditor(getPart().getSite().getPage(), (IFile)resource);
202         }
203         if (fCVSResource instanceof ICVSRemoteResource) {
204             return RevisionAnnotationController.openEditor(getPart().getSite().getPage(), fCVSResource, new RemoteAnnotationStorage((ICVSRemoteFile)fCVSResource, listener.getContents()));
205         }
206         return null;
207     }
208
209     private void fetchAnnotation(AnnotateListener listener, ICVSResource cvsResource, String JavaDoc revision, IProgressMonitor monitor) throws CVSException {
210     
211         monitor = Policy.monitorFor(monitor);
212         monitor.beginTask(null, 100);
213         
214         final ICVSFolder folder = cvsResource.getParent();
215         final FolderSyncInfo info = folder.getFolderSyncInfo();
216         final ICVSRepositoryLocation location = KnownRepositories.getInstance().getRepository(info.getRoot());
217         
218         final Session session = new Session(location, folder, true /*output to console*/);
219         session.open(Policy.subMonitorFor(monitor, 10), false /* read-only */);
220         try {
221             final Command.QuietOption quietness = CVSProviderPlugin.getPlugin().getQuietness();
222             try {
223                 CVSProviderPlugin.getPlugin().setQuietness(Command.VERBOSE);
224                 List localOptions = new ArrayList();
225                 if (revision != null) {
226                     localOptions.add(Annotate.makeRevisionOption(revision));
227                 }
228                 if (fBinary) {
229                     localOptions.add(Annotate.FORCE_BINARY_ANNOTATE);
230                 }
231                 final IStatus status = Command.ANNOTATE.execute(session, Command.NO_GLOBAL_OPTIONS, (LocalOption[]) localOptions.toArray(new LocalOption[localOptions.size()]), new ICVSResource[]{cvsResource}, listener, Policy.subMonitorFor(monitor, 90));
232                 if (status.getCode() == CVSStatus.SERVER_ERROR) {
233                     throw new CVSServerException(status);
234                 }
235             } finally {
236                 CVSProviderPlugin.getPlugin().setQuietness(quietness);
237                 monitor.done();
238             }
239         } finally {
240             session.close();
241         }
242     }
243
244     private RevisionInformation createRevisionInformation(final AnnotateListener listener, IProgressMonitor monitor) throws CVSException {
245         Map logEntriesByRevision= new HashMap();
246         if (fCVSResource instanceof ICVSFile) {
247             try {
248                 ILogEntry[] logEntries= ((ICVSFile) fCVSResource).getLogEntries(monitor);
249                 for (int i= 0; i < logEntries.length; i++) {
250                     ILogEntry entry= logEntries[i];
251                     logEntriesByRevision.put(entry.getRevision(), entry);
252                 }
253             } catch (CVSException e) {
254                 throw e;
255             } catch (TeamException e) {
256                 // XXX why does getLogEntries throw TeamException?
257
throw CVSException.wrapException(e);
258             }
259         }
260
261         final CommitterColors colors= CommitterColors.getDefault();
262         RevisionInformation info= new RevisionInformation();
263
264     class AnnotationControlCreator implements IInformationControlCreator {
265       private final boolean showTooltipAffordance;
266
267       public AnnotationControlCreator(boolean showTooltipAffordance) {
268         this.showTooltipAffordance = showTooltipAffordance;
269       }
270
271       public IInformationControl createInformationControl(Shell parent) {
272         String JavaDoc statusFieldText = showTooltipAffordance ? EditorsUI.getTooltipAffordanceString() : null;
273         return new SourceViewerInformationControl(parent, SWT.TOOL,
274             SWT.NONE, JFaceResources.DEFAULT_FONT, statusFieldText);
275       }
276     }
277         
278     info.setHoverControlCreator(new AnnotationControlCreator(true));
279     info.setInformationPresenterControlCreator(new AnnotationControlCreator(false));
280         
281         HashMap sets= new HashMap();
282         List annotateBlocks= listener.getCvsAnnotateBlocks();
283         for (Iterator blocks= annotateBlocks.iterator(); blocks.hasNext();) {
284             final CVSAnnotateBlock block= (CVSAnnotateBlock) blocks.next();
285             final String JavaDoc revisionString= block.getRevision();
286             Revision revision= (Revision) sets.get(revisionString);
287             if (revision == null) {
288                 final ILogEntry entry= (ILogEntry) logEntriesByRevision.get(revisionString);
289                 if (entry == null)
290                     continue;
291                 
292                 revision= new Revision() {
293                     private String JavaDoc fCommitter= null;
294                     
295                     public Object JavaDoc getHoverInfo() {
296                         if (entry != null)
297                             return entry.getAuthor() + " " + entry.getRevision() + " " + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(entry.getDate()) //$NON-NLS-1$ //$NON-NLS-2$
298
+ "\n\n" + entry.getComment(); //$NON-NLS-1$
299

300                         return block.toString().substring(0, block.toString().indexOf(" (")); //$NON-NLS-1$
301
}
302                     
303                     private String JavaDoc getCommitterId() {
304                         if (fCommitter == null)
305                             fCommitter= block.toString().substring(0, block.toString().indexOf(' '));
306                         return fCommitter;
307                     }
308                     
309                     public String JavaDoc getId() {
310                         return revisionString;
311                     }
312                     
313                     public Date getDate() {
314                         return entry.getDate();
315                     }
316                     
317                     public RGB getColor() {
318                         return colors.getCommitterRGB(getCommitterId());
319                     }
320
321                     public String JavaDoc getAuthor() {
322                         return getCommitterId();
323                     }
324                 };
325                 sets.put(revisionString, revision);
326                 info.addRevision(revision);
327             }
328             revision.addRange(new LineRange(block.getStartLine(), block.getEndLine() - block.getStartLine() + 1));
329         }
330         
331         return info;
332     }
333     
334     private void fetchContents(final AnnotateListener listener, IProgressMonitor monitor) {
335         try {
336             if (hasCharset(fCVSResource, listener.getContents())) {
337                 listener.setContents(getRemoteContents(fCVSResource, monitor));
338             }
339         } catch (CoreException e) {
340             // Log and continue, using the original fetched contents
341
CVSUIPlugin.log(e);
342         }
343     }
344
345     private InputStream getRemoteContents(ICVSResource resource, IProgressMonitor monitor) throws CoreException {
346         
347         final ICVSRemoteResource remote = CVSWorkspaceRoot.getRemoteResourceFor(resource);
348         if (remote == null) {
349             return new ByteArrayInputStream(new byte[0]);
350         }
351         final IStorage storage = ((IResourceVariant)remote).getStorage(monitor);
352         if (storage == null) {
353             return new ByteArrayInputStream(new byte[0]);
354         }
355         return storage.getContents();
356     }
357     
358     /**
359      * @return The ID of the perspective if the perspective needs to be changed,
360      * null otherwise.
361      */

362     private String JavaDoc promptForPerspectiveSwitch() {
363         // check whether we should ask the user.
364
final IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
365         final String JavaDoc option = store.getString(ICVSUIConstants.PREF_CHANGE_PERSPECTIVE_ON_SHOW_ANNOTATIONS);
366         final String JavaDoc desiredID = store.getString(ICVSUIConstants.PREF_DEFAULT_PERSPECTIVE_FOR_SHOW_ANNOTATIONS);
367         
368         if (option.equals(MessageDialogWithToggle.ALWAYS))
369             return desiredID; // no, always switch
370

371         if (option.equals(MessageDialogWithToggle.NEVER))
372             return null; // no, never switch
373

374         // Check whether the desired perspective is already active.
375
final IPerspectiveRegistry registry= PlatformUI.getWorkbench().getPerspectiveRegistry();
376         final IPerspectiveDescriptor desired = registry.findPerspectiveWithId(desiredID);
377         final IWorkbenchPage page = CVSUIPlugin.getActivePage();
378         
379         if (page != null) {
380             final IPerspectiveDescriptor current = page.getPerspective();
381             if (current != null && current.getId().equals(desiredID)) {
382                 return null; // it is active, so no prompt and no switch
383
}
384         }
385         
386         if (desired != null) {
387             
388             String JavaDoc message;;
389             String JavaDoc desc = desired.getDescription();
390             if (desc == null) {
391                 message = NLS.bind(CVSUIMessages.ShowAnnotationOperation_2, new String JavaDoc[] { desired.getLabel() });
392             } else {
393                 message = NLS.bind(CVSUIMessages.ShowAnnotationOperation_3, new String JavaDoc[] { desired.getLabel(), desc });
394             }
395             // Ask the user whether to switch
396
final MessageDialogWithToggle m = MessageDialogWithToggle.openYesNoQuestion(
397                     Utils.getShell(null),
398                     CVSUIMessages.ShowAnnotationOperation_1,
399                     message,
400                     CVSUIMessages.ShowAnnotationOperation_4,
401                     false /* toggle state */,
402                     store,
403                     ICVSUIConstants.PREF_CHANGE_PERSPECTIVE_ON_SHOW_ANNOTATIONS);
404             
405             final int result = m.getReturnCode();
406             switch (result) {
407             // yes
408
case IDialogConstants.YES_ID:
409             case IDialogConstants.OK_ID :
410                 return desiredID;
411             // no
412
case IDialogConstants.NO_ID :
413                 return null;
414             }
415         }
416         return null;
417     }
418     
419     private boolean isKnownUseView() {
420         //check whether we should ask the user.
421
final IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
422         final String JavaDoc option = store.getString(ICVSUIConstants.PREF_USE_QUICKDIFFANNOTATE);
423         
424         return option.equals(MessageDialogWithToggle.NEVER);
425     }
426     
427     private boolean isKnownUseLiveAnnotate() {
428         //check whether we should ask the user.
429
final IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
430         final String JavaDoc option = store.getString(ICVSUIConstants.PREF_USE_QUICKDIFFANNOTATE);
431         
432         return option.equals(MessageDialogWithToggle.ALWAYS);
433     }
434     
435     /**
436      * Returns true if the user wishes to always use the live annotate view, false otherwise.
437      * @return
438      */

439     private boolean promptForQuickDiffAnnotate(){
440         //check whether we should ask the user.
441
final IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
442         final String JavaDoc option = store.getString(ICVSUIConstants.PREF_USE_QUICKDIFFANNOTATE);
443         
444         if (option.equals(MessageDialogWithToggle.ALWAYS))
445             return true; //use live annotate
446
else if (option.equals(MessageDialogWithToggle.NEVER))
447             return false; //don't use live annotate
448

449         final MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(Utils.getShell(null), CVSUIMessages.ShowAnnotationOperation_QDAnnotateTitle,
450                 CVSUIMessages.ShowAnnotationOperation_QDAnnotateMessage,CVSUIMessages.ShowAnnotationOperation_4, false, store, ICVSUIConstants.PREF_USE_QUICKDIFFANNOTATE);
451         
452         final int result = dialog.getReturnCode();
453         switch (result) {
454             //yes
455
case IDialogConstants.YES_ID:
456             case IDialogConstants.OK_ID :
457                 return true;
458         }
459         return false;
460     }
461 }
462
Popular Tags