blob: 16590a0092451e926267a2f72e625ab82505f7c1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui;
import java.io.IOException;
import java.io.InputStream;
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.IPartListener;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
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;
private IPartListener partListener = new IPartListener() {
public void partActivated(IWorkbenchPart part) {
}
public void partBroughtToTop(IWorkbenchPart part) {
}
public void partClosed(IWorkbenchPart part) {
if (editor != null && part == editor) {
disconnect();
}
}
public void partDeactivated(IWorkbenchPart part) {
}
public void partOpened(IWorkbenchPart part) {
}
};
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 PartInitException, CVSException
*/
public void showAnnotations(ICVSResource cvsResource, Collection cvsAnnotateBlocks, InputStream contents) throws PartInitException, CVSException {
showAnnotations(cvsResource, cvsAnnotateBlocks, contents, true);
}
/**
* Show the annotation view.
* @param cvsResource
* @param cvsAnnotateBlocks
* @param contents
* @param useHistoryView
* @throws PartInitException, CVSException
*/
public void showAnnotations(ICVSResource cvsResource, Collection cvsAnnotateBlocks, InputStream contents, boolean useHistoryView) throws PartInitException, CVSException {
// Disconnect from old annotation editor
disconnect();
// 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());
setPartName(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
historyView = (HistoryView) page.showView(HistoryView.VIEW_ID);
historyView.showHistory((ICVSRemoteFile) CVSWorkspaceRoot.getRemoteResourceFor(cvsResource), false /* don't refetch */);
}
protected void disconnect() {
if(editor != null) {
if (editor.getSelectionProvider() instanceof IPostSelectionProvider) {
((IPostSelectionProvider) editor.getSelectionProvider()).removePostSelectionChangedListener(this);
}
editor.getSite().getPage().removePartListener(partListener);
editor = null;
document = null;
}
}
/**
* 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());
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#dispose()
*/
public void dispose() {
disconnect();
}
/**
* 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 (CVSException e) {
return;
} catch (PartInitException 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.
* @throws CVSException, PartInitException
*/
private IEditorPart openEditor() throws CVSException, PartInitException {
ICVSRemoteFile file = (ICVSRemoteFile) CVSWorkspaceRoot.getRemoteResourceFor(cvsResource);
// Determine if the registered editor is an ITextEditor.
// There is currently no support from UI to determine this information. This
// problem has been logged in: https://bugs.eclipse.org/bugs/show_bug.cgi?id=47362
// For now, use internal classes.
String id = getEditorId(file);
ITextEditor editor = getEditor(id, file);
// Hook Editor post selection listener.
if (editor.getSelectionProvider() instanceof IPostSelectionProvider) {
((IPostSelectionProvider) editor.getSelectionProvider()).addPostSelectionChangedListener(this);
}
editor.getSite().getPage().addPartListener(partListener);
return editor;
}
private ITextEditor getEditor(String id, ICVSRemoteFile file) throws PartInitException {
// Either reuse an existing editor or open a new editor of the correct type.
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));
return 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;
}
IEditorPart part = page.openEditor(new RemoteAnnotationEditorInput(file, contents), id);
if (part instanceof ITextEditor) {
return (ITextEditor)part;
} else {
// We asked for a text editor but didn't get one
// so open a vanilla text editor
page.closeEditor(part, false);
part = page.openEditor(new RemoteAnnotationEditorInput(file, contents), IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID);
if (part instanceof ITextEditor) {
return (ITextEditor)part;
} else {
// There is something really wrong so just bail
throw new PartInitException(Policy.bind("AnnotateView.0")); //$NON-NLS-1$
}
}
}
}
private String getEditorId(ICVSRemoteFile file) {
String id;
IEditorRegistry registry = CVSUIPlugin.getPlugin().getWorkbench().getEditorRegistry();
IEditorDescriptor descriptor = registry.getDefaultEditor(file.getName());
if (descriptor == null || !(descriptor instanceof EditorDescriptor) || !(((EditorDescriptor)descriptor).isInternal())) {
id = IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID; //$NON-NLS-1$
} else {
try {
Object obj = IDEWorkbenchPlugin.createExtension(((EditorDescriptor) descriptor).getConfigurationElement(), "class"); //$NON-NLS-1$
if (obj instanceof ITextEditor) {
id = descriptor.getId();
} else {
id = IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID;
}
} catch (CoreException e) {
id = IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID;
}
}
return id;
}
// This method implemented to be an ISelectionChangeListener but we
// don't really care when the List or Editor get focus.
public void setFocus() {
return;
}
}