blob: 8917530db18784746b90c10deb22b0007bcd0617 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Iterator;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.team.internal.ccvs.core.CVSAnnotateBlock;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteFile;
import org.eclipse.team.internal.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.internal.IWorkbenchConstants;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.registry.EditorDescriptor;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* A view showing the results of the CVS Annotate Command. A linked
* combination of a View of annotations, a source editor and the
* Resource History View
*/
public class AnnotateView extends ViewPart implements ISelectionChangedListener {
ITextEditor editor;
HistoryView historyView;
IWorkbenchPage page;
ListViewer viewer;
IDocument document;
Collection cvsAnnotateBlocks;
ICVSResource cvsResource;
InputStream contents;
IStructuredSelection previousListSelection;
ITextSelection previousTextSelection;
boolean lastSelectionWasText = false;
public static final String VIEW_ID = "org.eclipse.team.ccvs.ui.AnnotateView"; //$NON-NLS-1$
private Composite top;
public AnnotateView() {
super();
}
public void createPartControl(Composite parent) {
this.top = parent;
// Create default contents
Label label = new Label(top, SWT.WRAP);
label.setText(Policy.bind("CVSAnnotateView.viewInstructions")); //$NON-NLS-1$
label.setLayoutData(new GridData(GridData.FILL_BOTH));
top.layout();
}
/**
* Show the annotation view.
* @param cvsResource
* @param cvsAnnotateBlocks
* @param contents
* @throws InvocationTargetException
*/
public void showAnnotations(ICVSResource cvsResource, Collection cvsAnnotateBlocks, InputStream contents) throws InvocationTargetException {
showAnnotations(cvsResource, cvsAnnotateBlocks, contents, true);
}
/**
* Show the annotation view.
* @param cvsResource
* @param cvsAnnotateBlocks
* @param contents
* @param useHistoryView
* @throws InvocationTargetException
*/
public void showAnnotations(ICVSResource cvsResource, Collection cvsAnnotateBlocks, InputStream contents, boolean useHistoryView) throws InvocationTargetException {
// Remove old viewer
Control[] oldChildren = top.getChildren();
if (oldChildren != null) {
for (int i = 0; i < oldChildren.length; i++) {
oldChildren[i].dispose();
}
}
viewer = new ListViewer(top, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ArrayContentProvider());
viewer.setLabelProvider(new LabelProvider());
viewer.addSelectionChangedListener(this);
viewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
WorkbenchHelp.setHelp(viewer.getControl(), IHelpContextIds.ANNOTATE_VIEW);
top.layout();
this.cvsResource = cvsResource;
this.contents = contents;
this.cvsAnnotateBlocks = cvsAnnotateBlocks;
page = CVSUIPlugin.getActivePage();
viewer.setInput(cvsAnnotateBlocks);
editor = (ITextEditor) openEditor();
IDocumentProvider provider = editor.getDocumentProvider();
document = provider.getDocument(editor.getEditorInput());
setTitle(Policy.bind("CVSAnnotateView.showFileAnnotation", new Object[] {cvsResource.getName()})); //$NON-NLS-1$
try {
IResource localResource = cvsResource.getIResource();
if (localResource != null) {
setTitleToolTip(localResource.getFullPath().toString());
} else {
setTitleToolTip(cvsResource.getName());
}
} catch (CVSException e) {
setTitleToolTip(cvsResource.getName());
}
if (!useHistoryView) {
return;
}
// Get hook to the HistoryView
try {
historyView = (HistoryView) page.showView(HistoryView.VIEW_ID);
historyView.showHistory((ICVSRemoteFile) CVSWorkspaceRoot.getRemoteResourceFor(cvsResource));
} catch (PartInitException e) {
throw new InvocationTargetException(e);
} catch (CVSException e) {
throw new InvocationTargetException(e);
}
}
/**
* Makes the view visible in the active perspective. If there
* isn't a view registered <code>null</code> is returned.
* Otherwise the opened view part is returned.
*/
public static AnnotateView openInActivePerspective() throws PartInitException {
return (AnnotateView) CVSUIPlugin.getActivePage().showView(VIEW_ID);
}
/**
* Selection changed in either the Annotate List View or the
* Source editor.
*/
public void selectionChanged(SelectionChangedEvent event) {
if (event.getSelection() instanceof IStructuredSelection) {
listSelectionChanged((IStructuredSelection) event.getSelection());
} else if (event.getSelection() instanceof ITextSelection) {
textSelectionChanged((ITextSelection) event.getSelection());
}
}
/**
* A selection event in the Annotate Source Editor
* @param event
*/
private void textSelectionChanged(ITextSelection selection) {
// Track where the last selection event came from to avoid
// a selection event loop.
lastSelectionWasText = true;
// Locate the annotate block containing the selected line number.
CVSAnnotateBlock match = null;
for (Iterator iterator = cvsAnnotateBlocks.iterator(); iterator.hasNext();) {
CVSAnnotateBlock block = (CVSAnnotateBlock) iterator.next();
if (block.contains(selection.getStartLine())) {
match = block;
break;
}
}
// Select the annotate block in the List View.
if (match == null) {
return;
}
StructuredSelection listSelection = new StructuredSelection(match);
viewer.setSelection(listSelection, true);
}
/**
* A selection event in the Annotate List View
* @param selection
*/
private void listSelectionChanged(IStructuredSelection selection) {
// If the editor was closed, reopen it.
if (editor == null || editor.getSelectionProvider() == null) {
try {
contents.reset();
showAnnotations(cvsResource, cvsAnnotateBlocks, contents, false);
} catch (InvocationTargetException e) {
return;
} catch (IOException e) {
return;
}
}
ISelectionProvider selectionProvider = editor.getSelectionProvider();
if (selectionProvider == null) {
// Failed to open the editor but what else can we do.
return;
}
ITextSelection textSelection = (ITextSelection) selectionProvider.getSelection();
CVSAnnotateBlock listSelection = (CVSAnnotateBlock) selection.getFirstElement();
/**
* Ignore event if the current text selection is already equal to the corresponding
* list selection. Nothing to do. This prevents infinite event looping.
*
* Extra check to handle single line deltas
*/
if (textSelection.getStartLine() == listSelection.getStartLine() && textSelection.getEndLine() == listSelection.getEndLine() && selection.equals(previousListSelection)) {
return;
}
// If the last selection was a text selection then bale to prevent a selection loop.
if (!lastSelectionWasText) {
try {
int start = document.getLineOffset(listSelection.getStartLine());
int end = document.getLineOffset(listSelection.getEndLine() + 1);
editor.selectAndReveal(start, end - start);
if (editor != null && !page.isPartVisible(editor)) {
page.activate(editor);
}
} catch (BadLocationException e) {
// Ignore - nothing we can do.
}
}
// Select the revision in the history view.
if(historyView != null) {
historyView.selectRevision(listSelection.getRevision());
}
lastSelectionWasText = false;
}
/**
* Try and open the correct registered editor type for the file. If the registered
* editor is *not* an ITextEditor then open the source in a default text editor.
* @return
* @throws InvocationTargetException
*/
private IEditorPart openEditor() throws InvocationTargetException {
// Open the editor
IEditorPart part;
IEditorRegistry registry = CVSUIPlugin.getPlugin().getWorkbench().getEditorRegistry();
ICVSRemoteFile file;
try {
file = (ICVSRemoteFile) CVSWorkspaceRoot.getRemoteResourceFor(cvsResource);
} catch (CVSException e1) {
throw new InvocationTargetException(e1);
}
IEditorDescriptor descriptor = registry.getDefaultEditor(file.getName());
// Determine if the registered editor is an ITextEditor.
String id;
if (descriptor == null || !(descriptor instanceof EditorDescriptor) || !(((EditorDescriptor)descriptor).isInternal())) {
id = IWorkbenchConstants.DEFAULT_EDITOR_ID; //$NON-NLS-1$
} else {
try {
Object obj = WorkbenchPlugin.createExtension(((EditorDescriptor) descriptor).getConfigurationElement(), "class"); //$NON-NLS-1$
if (obj instanceof ITextEditor) {
id = descriptor.getId();
} else {
id = IWorkbenchConstants.DEFAULT_EDITOR_ID;
}
} catch (CoreException e) {
id = IWorkbenchConstants.DEFAULT_EDITOR_ID;
}
}
// Either reuse an existing editor or open a new editor of the correct type.
try {
try {
if (editor != null && editor instanceof IReusableEditor && page.isPartVisible(editor) && editor.getSite().getId().equals(id)) {
// We can reuse the editor
((IReusableEditor) editor).setInput(new RemoteAnnotationEditorInput(file, contents));
part = editor;
} else {
// We can not reuse the editor so close the existing one and open a new one.
if (editor != null) {
page.closeEditor(editor, false);
editor = null;
}
part = page.openEditor(new RemoteAnnotationEditorInput(file, contents), id);
}
} catch (PartInitException e) {
if (id.equals(IWorkbenchConstants.DEFAULT_EDITOR_ID)) {
throw e;
} else {
// Could not open desired editor, try a default text editor.
part = page.openEditor(new RemoteAnnotationEditorInput(file, contents), IWorkbenchConstants.DEFAULT_EDITOR_ID); //$NON-NLS-1$
}
}
} catch (PartInitException e) {
// Total failure.
throw new InvocationTargetException(e);
}
// Hook Editor post selection listener.
ITextEditor editor = (ITextEditor) part;
if (editor.getSelectionProvider() instanceof IPostSelectionProvider) {
((IPostSelectionProvider) editor.getSelectionProvider()).addPostSelectionChangedListener(this);
}
return part;
}
// This method implemented to be an ISelectionChangeListener but we
// don't really care when the List or Editor get focus.
public void setFocus() {
return;
}
}