/**
* Copyright (c) 2013-2016 Angelo ZERR.
* 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:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package tern.eclipse.ide.ui.views;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.part.IPage;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.views.contentoutline.ContentOutline;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import tern.eclipse.ide.ui.utils.EditorUtils;
import tern.server.protocol.outline.IJSNode;
import tern.server.protocol.outline.TernOutlineCollector;
/**
* Abstract class for tern outline view.
*
*/
public abstract class AbstractTernOutlineView extends ContentOutline {
public static final int IS_LINKING_ENABLED_PROPERTY = 0;
private ITextEditor textEditor;
protected IMemento memento;
private String LINKING_ENABLED = "AbstractTernOutlineView.LINKING_ENABLED"; //$NON-NLS-1$
private boolean linkingEnabled = false;
boolean ignoreEditorActivation;
boolean ignoreSelectionChanged;
// ----------- Jobs
// Job which is executed when the treeview of the tern outline is clicked to
// select the well content of the active JavaScript Editor.
private ActivateEditorJob activateEditorJob = new ActivateEditorJob(this);
// Job which is executed when there is a selection inside JavaScript Editor
// to select the well node in the tern outline.
private final UpdateSelectionJob updateSelectionJob = new UpdateSelectionJob(this);
private final RefreshOutlineJob refreshJob = new RefreshOutlineJob(this);
@Override
protected PageRec doCreatePage(IWorkbenchPart part) {
IFile file = getFile(part);
if (file == null) {
// The opened file in the given editor cannot be displayed in the
// outline
return null;
}
// Try to get the shared outline for the given project (ex : for angular
// explorer)
IProject project = file.getProject();
IContentOutlinePage page = getOutlinePage(project);
if (page == null) {
// Create a new instance of the outline page
page = createOutlinePage(file.getProject());
if (page != null) {
if (page instanceof IPageBookViewPage) {
initPage((IPageBookViewPage) page);
}
page.createControl(getPageBook());
if (page instanceof AbstractTernContentOutlinePage) {
updateCurrentFile(page, part, file);
}
}
} else {
if (page instanceof AbstractTernContentOutlinePage) {
updateCurrentFile(page, part, file);
}
}
if (page != null) {
return new PageRec(part, page);
}
// There is no content outline
return null;
}
@Override
protected void showPageRec(PageRec pageRec) {
IPage page = pageRec.page;
IWorkbenchPart part = pageRec.part;
if (page instanceof AbstractTernContentOutlinePage) {
IFile file = getFile(part);
if (file != null) {
updateCurrentFile(page, part, file);
}
}
super.showPageRec(pageRec);
}
/**
* Returns the shared outline page for the given project or null if a page
* must be created for each file.
*
* @param project
* @return the shared outline page for the given project or null if a page
* must be created for each file.
*/
protected IContentOutlinePage getOutlinePage(IProject project) {
return null;
}
protected IFile getFile(IWorkbenchPart part) {
if (part != null && part instanceof IEditorPart) {
IFile file = EditorUtils.getFile((IEditorPart) part);
if (file != null && isAdaptFor(file)) {
return file;
}
}
return null;
}
@Override
public void init(IViewSite aSite, IMemento aMemento) throws PartInitException {
super.init(aSite, aMemento);
memento = aMemento;
if (memento != null) {
Integer linkingEnabledInteger = memento.getInteger(LINKING_ENABLED);
setLinkingEnabled(((linkingEnabledInteger != null) ? linkingEnabledInteger.intValue() == 1 : false));
}
}
@Override
public void saveState(IMemento aMemento) {
aMemento.putInteger(LINKING_ENABLED, (linkingEnabled) ? 1 : 0);
super.saveState(aMemento);
}
public boolean isLinkingEnabled() {
return linkingEnabled;
}
public void setLinkingEnabled(boolean linkingEnabled) {
this.linkingEnabled = linkingEnabled;
}
private void updateCurrentFile(IPage page, IWorkbenchPart part, IFile file) {
if (isEditorChanged(part)) {
((AbstractTernContentOutlinePage) page).setCurrentFile(file);
this.setCurrentPart(part);
}
}
protected boolean isEditorChanged(IWorkbenchPart part) {
return this.textEditor != part;
}
private void setCurrentPart(IWorkbenchPart part) {
if (part instanceof ITextEditor) {
this.textEditor = (ITextEditor) part;
} else {
this.textEditor = null;
}
updateSelectionJob.setCurrentPart(part);
}
public void openInEditor(IJSNode node, boolean force) {
activateEditorJob.openInEditor(node, force);
}
/**
* Returns the current tern outline page and null otherwise.
*
* @return the current tern outline page and null otherwise.
*/
AbstractTernContentOutlinePage getCurrentTernPage() {
IPage p = getCurrentPage();
if (p == null || !(p instanceof AbstractTernContentOutlinePage)) {
return null;
}
AbstractTernContentOutlinePage page = (AbstractTernContentOutlinePage) p;
return page;
}
/**
* Returns the viewer of the current tern outline page and null otherwise.
*
* @return the viewer of the current tern outline page and null otherwise.
*/
CommonViewer getCurrentViewer() {
AbstractTernContentOutlinePage page = getCurrentTernPage();
return page != null ? page.getViewer() : null;
}
@Override
public void dispose() {
super.dispose();
activateEditorJob.cancel();
updateSelectionJob.dispose();
refreshJob.cancel();
}
/**
* Refresh the outline tree in a job.
*/
public void refreshOutline() {
refreshJob.refreshOutline();
}
/**
* Returns true if the outline view is adapted for the given file and false
* otherwise.
*
* @param file
* @return true if the outline view is adapted for the given file and false
* otherwise.
*/
protected abstract boolean isAdaptFor(IFile file);
/**
* Create the outline view for the given project. It can have one page per
* file (see tern outline) or one page per project (see angular outline).
*
* @param project
* @return an instance of outline page for the given project.
*/
protected abstract IContentOutlinePage createOutlinePage(IProject project);
public abstract TernOutlineCollector loadOutline(IFile file, IDocument document) throws Exception;
public abstract boolean isOutlineAvailable(IFile file);
}