content: /**
  - *  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.core.runtime.CoreException;
  import org.eclipse.jface.action.IToolBarManager;
  import org.eclipse.jface.text.DocumentEvent;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.jface.text.IDocumentListener;
  import org.eclipse.jface.viewers.DoubleClickEvent;
  import org.eclipse.jface.viewers.IDoubleClickListener;
  import org.eclipse.jface.viewers.ISelection;
  import org.eclipse.jface.viewers.ISelectionChangedListener;
  import org.eclipse.jface.viewers.IStructuredSelection;
  import org.eclipse.jface.viewers.SelectionChangedEvent;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Control;
  import org.eclipse.ui.navigator.CommonViewer;
  import org.eclipse.ui.part.Page;
  import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
  
  import tern.eclipse.ide.core.TernCorePlugin;
  import tern.eclipse.ide.internal.ui.Trace;
  import tern.eclipse.ide.internal.ui.views.actions.LinkEditorAction;
  import tern.eclipse.ide.internal.ui.views.actions.TerminateTernServerAction;
  import tern.eclipse.ide.ui.utils.EditorUtils;
  import tern.server.ITernServer;
  import tern.server.ITernServerListener;
  import tern.server.protocol.outline.IJSNode;
  
  /**
   * Abstract class for tern outline page.
   *
   */
  public abstract class AbstractTernContentOutlinePage extends Page
  		implements IContentOutlinePage, ITernServerListener, IDocumentListener {
  
  	private final AbstractTernOutlineView view;
  	private CommonViewer viewer;
  
  	// Commons actions
  	private LinkEditorAction toggleLinkingAction;
  	private TerminateTernServerAction terminateAction;
  
  	private final IProject project;
  	private IDocument currentDocument;
  	private IFile currentFile;
  
  	public AbstractTernContentOutlinePage(IProject project, AbstractTernOutlineView view) {
  		this.project = project;
  		this.view = view;
  	}
  
  	@Override
  	public void addSelectionChangedListener(ISelectionChangedListener listener) {
  		this.viewer.addSelectionChangedListener(listener);
  	}
  
  	@Override
  	public ISelection getSelection() {
  		return this.viewer.getSelection();
  	}
  
  	@Override
  	public void removeSelectionChangedListener(ISelectionChangedListener listener) {
  		this.viewer.removePostSelectionChangedListener(listener);
  	}
  
  	@Override
  	public void setSelection(ISelection selection) {
  		this.viewer.setSelection(selection);
  	}
  
  	@Override
  	public Control getControl() {
  		return this.viewer != null ? this.viewer.getControl() : null;
  	}
  
  	@Override
  	public void setFocus() {
  		getControl().setFocus();
  	}
  
  	@Override
  	public void createControl(Composite parent) {
  		viewer = new CommonViewer(getViewerId(), parent, SWT.MULTI);
  		viewer.addDoubleClickListener(new IDoubleClickListener() {
  			@Override
  			public void doubleClick(DoubleClickEvent event) {
  				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
  				if (!selection.isEmpty()) {
  					if (selection.getFirstElement() instanceof IJSNode) {
  						IJSNode node = (IJSNode) selection.getFirstElement();
  						view.openInEditor(node, true);
  					}
  				}
  			}
  
  		});
  		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
  
  			@Override
  			public void selectionChanged(SelectionChangedEvent event) {
  				updateEnabledActions();
  				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
  				if (!selection.isEmpty()) {
  					if (selection.getFirstElement() instanceof IJSNode) {
  						IJSNode node = (IJSNode) selection.getFirstElement();
  						IFile nodeFile = EditorUtils.getFile(node);
  						if (nodeFile == null || nodeFile.equals(getCurrentFile())) {
  							view.openInEditor(node, false);
  						}
  					}
  				}
  			}
  
  		});
  		// viewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
  
  		// Actions
  		registerActions(getSite().getActionBars().getToolBarManager());
  		registerContextMenu(viewer.getControl());
  
  		try {
  			IProject project = getProject();
  			TernCorePlugin.getTernProject(project).addServerListener(this);
  		} catch (CoreException e) {
  			Trace.trace(Trace.SEVERE, "error while getting tern project", e);
  		}
  
  		updateEnabledActions();
  	}
  
  	protected void registerActions(IToolBarManager manager) {
  		this.toggleLinkingAction = new LinkEditorAction(view, getViewer());
  		manager.add(toggleLinkingAction);
  		this.terminateAction = new TerminateTernServerAction(this);
  		manager.add(terminateAction);
  	}
  
  	protected void registerContextMenu(Control control) {
  	}
  
  	public CommonViewer getViewer() {
  		return viewer;
  	}
  
  	protected void updateEnabledActions() {
  
  	}
  
  	@Override
  	public void onStart(ITernServer server) {
  		refreshOutline();
  		terminateAction.setEnabled(true);
  	}
  
  	@Override
  	public void onStop(ITernServer server) {
  		terminateAction.setEnabled(false);
  	}
  
  	@Override
  	public void dispose() {
  		super.dispose();
  		if (this.currentDocument != null) {
  			currentDocument.removeDocumentListener(this);
  		}
  		try {
  			IProject project = getProject();
  			TernCorePlugin.getTernProject(project).removeServerListener(this);
  		} catch (CoreException e) {
  			Trace.trace(Trace.SEVERE, "error while getting tern project", e);
  		}
  	}
  
  	public void setCurrentFile(IFile currentFile) {
  		// Old file/document
  		IFile oldFile = this.currentFile;
  		IDocument oldDocument = this.currentDocument;
  		if (oldDocument != null) {
  			oldDocument.removeDocumentListener(this);
  		}
  		// new file/document
  		this.currentFile = currentFile;
  		this.currentDocument = EditorUtils.getDocument(currentFile);
  		if (currentDocument != null) {
  			currentDocument.addDocumentListener(this);
  		}
  		if (isRefreshOutline(oldFile, currentFile)) {
  			refreshOutline();
  		}
  	}
  
  	protected abstract boolean isRefreshOutline(IFile oldFile, IFile newFile);
  
  	protected abstract String getViewerId();
  
  	public final IFile getCurrentFile() {
  		return currentFile;
  	}
  
  	public IDocument getCurrentDocument() {
  		return currentDocument;
  	}
  
  	public final IProject getProject() {
  		return project;
  	}
  
  	public abstract IFile getFile();
  
  	/**
  	 * Refresh the outline tree in a job.
  	 */
  	public void refreshOutline() {
  		view.refreshOutline();
  	}
  
  	@Override
  	public void documentChanged(DocumentEvent event) {
  		refreshOutline();
  	}
  
  	@Override
  	public void documentAboutToBeChanged(DocumentEvent event) {
  	}
  }
  