Java tutorial
/******************************************************************************* * Copyright (c) 2005, 2006 Subclipse project and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Subclipse project committers - initial API and implementation ******************************************************************************/ package org.tigris.subversion.subclipse.ui.operations; import java.lang.reflect.Method; import java.text.DateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.revisions.Revision; import org.eclipse.jface.text.revisions.RevisionInformation; import org.eclipse.jface.text.source.LineRange; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Shell; import org.eclipse.team.internal.ui.Utils; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor; import org.eclipse.ui.texteditor.ITextEditorExtension4; import org.tigris.subversion.subclipse.core.ISVNRemoteFile; import org.tigris.subversion.subclipse.core.SVNException; import org.tigris.subversion.subclipse.core.SVNTeamProvider; import org.tigris.subversion.subclipse.core.commands.GetAnnotationsCommand; import org.tigris.subversion.subclipse.core.commands.GetLogsCommand; import org.tigris.subversion.subclipse.core.history.ILogEntry; import org.tigris.subversion.subclipse.core.history.LogEntry; import org.tigris.subversion.subclipse.ui.ISVNUIConstants; import org.tigris.subversion.subclipse.ui.Policy; import org.tigris.subversion.subclipse.ui.SVNUIPlugin; import org.tigris.subversion.subclipse.ui.annotations.AnnotateBlock; import org.tigris.subversion.subclipse.ui.annotations.AnnotateBlocks; import org.tigris.subversion.subclipse.ui.annotations.AnnotateView; import org.tigris.subversion.svnclientadapter.ISVNAnnotations; import org.tigris.subversion.svnclientadapter.ISVNClientAdapter; import org.tigris.subversion.svnclientadapter.ISVNLogMessage; import org.tigris.subversion.svnclientadapter.SVNRevision; /** * @author Brock Janiczak */ public class ShowAnnotationOperation extends SVNOperation { private final SVNRevision fromRevision; private final SVNRevision toRevision; private final ISVNRemoteFile remoteFile; private final boolean includeMergedRevisions; private final boolean ignoreMimeType; public ShowAnnotationOperation(IWorkbenchPart part, ISVNRemoteFile remoteFile, SVNRevision fromRevision, boolean includeMergedRevisions, boolean ignoreMimeType) { super(part); this.remoteFile = remoteFile; this.fromRevision = fromRevision; this.toRevision = remoteFile.getLastChangedRevision(); this.includeMergedRevisions = includeMergedRevisions; this.ignoreMimeType = ignoreMimeType; } public ShowAnnotationOperation(IWorkbenchPart part, ISVNRemoteFile remoteFile, SVNRevision fromRevision, SVNRevision toRevision, boolean includeMergedRevisions, boolean ignoreMimeType) { super(part); this.remoteFile = remoteFile; this.fromRevision = fromRevision; this.toRevision = toRevision; this.includeMergedRevisions = includeMergedRevisions; this.ignoreMimeType = ignoreMimeType; } public ShowAnnotationOperation(IWorkbenchPart part, ISVNRemoteFile remoteFile, boolean includeMergedRevisions, boolean ignoreMimeType) { this(part, remoteFile, SVNRevision.START, includeMergedRevisions, ignoreMimeType); } /* (non-Javadoc) * @see org.tigris.subversion.subclipse.ui.operations.RepositoryProviderOperation#getTaskName(org.tigris.subversion.subclipse.core.SVNTeamProvider) */ protected String getTaskName(SVNTeamProvider provider) { return Policy.bind("AnnotateOperation.0", provider.getProject().getName()); //$NON-NLS-1$ } /* (non-Javadoc) * @see org.tigris.subversion.subclipse.ui.operations.SVNOperation#getTaskName() */ protected String getTaskName() { return Policy.bind("AnnotateOperation.taskName"); //$NON-NLS-1$ } /* (non-Javadoc) * @see org.tigris.subversion.subclipse.ui.operations.SVNOperation#execute(org.eclipse.core.runtime.IProgressMonitor) */ protected void execute(final IProgressMonitor monitor) throws SVNException, InterruptedException { monitor.beginTask(null, 100); try { GetAnnotationsCommand command = new GetAnnotationsCommand(remoteFile, fromRevision, toRevision, includeMergedRevisions, ignoreMimeType); command.run(new SubProgressMonitor(monitor, 100)); final ISVNAnnotations annotations = command.getAnnotations(); final AnnotateBlocks annotateBlocks = new AnnotateBlocks(annotations); // this is not needed if there is no live annotate // final RevisionInformation information= createRevisionInformation(annotateBlocks, Policy.subMonitorFor(monitor, 20)); // We aren't running from a UI thread getShell().getDisplay().asyncExec(new Runnable() { public void run() { // is there an open editor for the given input? If yes, use live annotate final ITextEditorExtension4 editor = getEditor(); if (editor != null && promptForQuickDiffAnnotate()) { RevisionInformation information = createRevisionInformation(annotateBlocks, Policy.subMonitorFor(monitor, 20)); editor.showRevisionInformation(information, "org.tigris.subversion.subclipse.quickdiff.providers.SVNReferenceProvider"); //$NON-NLS-1$ } else { try { // Open the view IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window != null) { try { PlatformUI.getWorkbench().showPerspective( "org.tigris.subversion.subclipse.ui.svnPerspective", window); //$NON-NLS-1$ } catch (WorkbenchException e1) { // If this does not work we will just open the view in the // current perspective. } } AnnotateView view = AnnotateView.openInActivePerspective(); view.showAnnotations(remoteFile, annotateBlocks.getAnnotateBlocks(), annotations.getInputStream()); } catch (PartInitException e1) { collectStatus(e1.getStatus()); } } } }); } catch (SVNException e) { if (e.operationInterrupted()) { showCancelledMessage(); } else { collectStatus(e.getStatus()); } } finally { monitor.done(); } } /* (non-Javadoc) * @see org.eclipse.team.ui.TeamOperation#getGotoAction() */ protected IAction getGotoAction() { return super.getGotoAction(); } private ITextEditorExtension4 getEditor() { final IWorkbench workbench = PlatformUI.getWorkbench(); final IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IEditorReference[] references = window.getActivePage().getEditorReferences(); IResource resource = remoteFile.getResource(); if (resource == null) return null; for (int i = 0; i < references.length; i++) { IEditorReference reference = references[i]; try { if (resource != null && resource.equals(reference.getEditorInput().getAdapter(IFile.class))) { IEditorPart editor = reference.getEditor(false); if (editor instanceof ITextEditorExtension4) return (ITextEditorExtension4) editor; else { //editor opened is not a text editor - reopen file using the defualt text editor IEditorPart part = getPart().getSite().getPage().openEditor( new FileEditorInput((IFile) resource), IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID, true, IWorkbenchPage.MATCH_NONE); if (part != null && part instanceof AbstractDecoratedTextEditor) return (AbstractDecoratedTextEditor) part; } } } catch (PartInitException e) { // ignore } } //no existing editor references found, try to open a new editor for the file if (resource instanceof IFile) { try { IEditorDescriptor descrptr = IDE.getEditorDescriptor((IFile) resource); //try to open the associated editor only if its an internal editor if (descrptr.isInternal()) { IEditorPart part = IDE.openEditor(getPart().getSite().getPage(), (IFile) resource); if (part instanceof AbstractDecoratedTextEditor) return (AbstractDecoratedTextEditor) part; //editor opened is not a text editor - close it getPart().getSite().getPage().closeEditor(part, false); } //open file in default text editor IEditorPart part = IDE.openEditor(getPart().getSite().getPage(), (IFile) resource, IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID); if (part != null && part instanceof AbstractDecoratedTextEditor) return (AbstractDecoratedTextEditor) part; } catch (PartInitException e) { } } return null; } private RevisionInformation createRevisionInformation(final AnnotateBlocks annotateBlocks, IProgressMonitor monitor) { Map logEntriesByRevision = new HashMap(); GetLogsCommand logCommand = new GetLogsCommand(this.remoteFile, SVNRevision.HEAD, this.fromRevision, this.toRevision, false, 0, null, false); try { logCommand.run(monitor); ILogEntry[] logEntries = logCommand.getLogEntries(); for (int i = 0; i < logEntries.length; i++) { ILogEntry logEntry = logEntries[i]; logEntriesByRevision.put(new Long(logEntry.getRevision().getNumber()), logEntry); } } catch (SVNException e) { SVNUIPlugin.log(e); } RevisionInformation info = new RevisionInformation(); try { // Have to use reflection for compatibility with Eclipse 3.2 API // info.setHoverControlCreator(new AnnotationControlCreator("Press F2 for focus.")); // info.setInformationPresenterControlCreator(new AnnotationControlCreator(null)); String tooltipAffordance = "Press F2 for focus."; try { // Will either set an affordance, or null if the tooltip affordance turned is off tooltipAffordance = (String) EditorsUI.class.getMethod("getTooltipAffordanceString", null) .invoke(null, null); } catch (Exception e) { //ignore } Class infoClass = info.getClass(); Class[] paramTypes = { IInformationControlCreator.class }; Method setHoverControlCreator = infoClass.getMethod("setHoverControlCreator", paramTypes); Method setInformationPresenterControlCreator = infoClass .getMethod("setInformationPresenterControlCreator", paramTypes); final class AnnotationControlCreator implements IInformationControlCreator { private final String statusFieldText; public AnnotationControlCreator(String statusFieldText) { this.statusFieldText = statusFieldText; } public IInformationControl createInformationControl(Shell parent) { return new SourceViewerInformationControl(parent, SWT.TOOL, SWT.NONE, JFaceResources.DEFAULT_FONT, statusFieldText); } } setHoverControlCreator.invoke(info, new Object[] { new AnnotationControlCreator(tooltipAffordance) }); setInformationPresenterControlCreator.invoke(info, new Object[] { new AnnotationControlCreator(null) }); } catch (Exception e) { // ignore } final CommitterColors colors = CommitterColors.getDefault(); HashMap sets = new HashMap(); for (Iterator blocks = annotateBlocks.getAnnotateBlocks().iterator(); blocks.hasNext();) { final AnnotateBlock block = (AnnotateBlock) blocks.next(); final String revisionString = Long.toString(block.getRevision()); LogEntry logEntry = (LogEntry) logEntriesByRevision.get(new Long(block.getRevision())); final String logMessage; if (logEntry == null) { logMessage = getSingleEntry(remoteFile, new Long(block.getRevision())); } else { logMessage = logEntry.getComment(); } Revision revision = (Revision) sets.get(revisionString); if (revision == null) { revision = new Revision() { public Object getHoverInfo() { return block.getUser() + " " + revisionString + " " + DateFormat //$NON-NLS-1$//$NON-NLS-2$ .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(block.getDate()) + "\n\n" + //$NON-NLS-1$ (logMessage != null ? logMessage : ""); //$NON-NLS-1$ } public String getAuthor() { return block.getUser(); } public String getId() { return revisionString; } public Date getDate() { return block.getDate(); } public RGB getColor() { return colors.getCommitterRGB(getAuthor()); } }; sets.put(revisionString, revision); info.addRevision(revision); } revision.addRange(new LineRange(block.getStartLine(), block.getEndLine() - block.getStartLine() + 1)); } return info; } /** * Returns true if the user wishes to always use the live annotate view, false otherwise. * @return */ private boolean promptForQuickDiffAnnotate() { //check whether we should ask the user. final IPreferenceStore store = SVNUIPlugin.getPlugin().getPreferenceStore(); final String option = store.getString(ISVNUIConstants.PREF_USE_QUICKDIFFANNOTATE); if (option.equals(MessageDialogWithToggle.ALWAYS)) return true; //use live annotate else if (option.equals(MessageDialogWithToggle.NEVER)) return false; //don't use live annotate final MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(Utils.getShell(null), Policy.bind("AnnotateOperation_QDAnnotateTitle"), Policy.bind("AnnotateOperation_QDAnnotateMessage"), Policy.bind("AnnotateOperation_4"), false, store, ISVNUIConstants.PREF_USE_QUICKDIFFANNOTATE); final int result = dialog.getReturnCode(); switch (result) { //yes case IDialogConstants.YES_ID: case IDialogConstants.OK_ID: return true; } return false; } private String getSingleEntry(ISVNRemoteFile file, Long revLong) { ISVNClientAdapter client = null; try { client = file.getRepository().getSVNClient(); SVNRevision revision = SVNRevision.getRevision(revLong.toString()); ISVNLogMessage[] messages = client.getLogMessages(file.getRepository().getRepositoryRoot(), revision, revision, false); if (messages.length == 1) return messages[0].getMessage(); else return null; } catch (Exception e) { return null; } finally { file.getRepository().returnSVNClient(client); } } }