/**
* 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.controls;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import tern.eclipse.ide.core.IIDETernProject;
import tern.eclipse.ide.core.TernCorePlugin;
import tern.eclipse.ide.internal.ui.TernUIMessages;
import tern.eclipse.ide.ui.TernUIPlugin;
import tern.eclipse.ide.ui.dialogs.MultipleFolderSelectionDialog;
import tern.eclipse.ide.ui.dialogs.OpenResourceDialog;
import tern.eclipse.ide.ui.viewers.TernScriptPathContentProvider;
import tern.eclipse.ide.ui.viewers.TernScriptPathLabelProvider;
import tern.scriptpath.ITernScriptPath;
import tern.scriptpath.ITernScriptPath.ScriptPathsType;
/**
* Block which hosts the Tree of the Tern scripts path.
*
*/
public class TernScriptPathsBlock extends AbstractTreeBlock {
private Composite fControl;
private final List<ITernScriptPath> ternScriptPaths = new ArrayList<ITernScriptPath>();
private TreeViewer treeViewer;
private Button addFileButton;
private Button addFolderButton;
private Button addProjectButton;
private Button removeButton;
private final IIDETernProject ternProject;
public TernScriptPathsBlock(IIDETernProject project) {
this.ternProject = project;
}
public void createControl(Composite ancestor) {
Composite parent = new Composite(ancestor, SWT.NULL);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginHeight = 0;
layout.marginWidth = 0;
parent.setLayout(layout);
Font font = ancestor.getFont();
parent.setFont(font);
fControl = parent;
// Description
Label treeLabel = new Label(parent, SWT.NONE);
treeLabel.setText(TernUIMessages.TernScriptPathsBlock_desc);
GridData data = new GridData();
data.horizontalSpan = 2;
treeLabel.setLayoutData(data);
treeLabel.setFont(font);
// Tree
Tree tree = new Tree(parent, SWT.BORDER | SWT.FULL_SELECTION
| SWT.V_SCROLL | SWT.MULTI);
data = new GridData(GridData.FILL_BOTH);
data.widthHint = 450;
tree.setLayoutData(data);
tree.setFont(font);
tree.setHeaderVisible(false);
tree.setLinesVisible(false);
treeViewer = new TreeViewer(tree);
treeViewer.setLabelProvider(TernScriptPathLabelProvider.getInstance());
treeViewer.setContentProvider(TernScriptPathContentProvider
.getInstance());
// Add tree selection listener to enable "Remove" button when a script
// path is selected.
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event
.getSelection();
boolean enabled = false;
if (!selection.isEmpty()) {
for (Iterator iterator = selection.iterator(); iterator
.hasNext();) {
Object element = iterator.next();
if (element instanceof ITernScriptPath
&& !((ITernScriptPath) element).isExternal()) {
enabled = true;
break;
}
}
}
removeButton.setEnabled(enabled);
}
});
// Add tree listener to remove selected script path with del key.
tree.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent event) {
if (event.character == SWT.DEL && event.stateMask == 0) {
removeScriptPaths();
}
}
});
Composite buttons = new Composite(parent, SWT.NULL);
buttons.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
buttons.setLayout(layout);
buttons.setFont(font);
// Add "File" button
addFileButton = createPushButton(buttons, TernUIMessages.Button_addFile);
addFileButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
addScriptPath(ScriptPathsType.FILE);
}
});
addFileButton.setEnabled(true);
// "Add Folder" button
addFolderButton = createPushButton(buttons,
TernUIMessages.Button_addFolder);
addFolderButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
addScriptPath(ScriptPathsType.FOLDER);
}
});
addFolderButton.setEnabled(true);
// "Add Project" button
addProjectButton = createPushButton(buttons,
TernUIMessages.Button_addProject);
addProjectButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
addScriptPath(ScriptPathsType.PROJECT);
}
});
addProjectButton.setEnabled(true);
// Remove button
removeButton = createPushButton(buttons, TernUIMessages.Button_remove);
removeButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event evt) {
removeScriptPaths();
}
});
removeButton.setEnabled(false);
// copied from ListDialogField.CreateSeparator()
Label separator = new Label(buttons, SWT.NONE);
separator.setVisible(false);
GridData gd = new GridData();
gd.horizontalAlignment = GridData.FILL;
gd.verticalAlignment = GridData.BEGINNING;
gd.heightHint = 4;
separator.setLayoutData(gd);
restoreColumnSettings();
}
/**
* Add script path page type.
*/
protected void addScriptPath(ScriptPathsType type) {
// Select the resource which contains scripts to load.
SelectionDialog dialog = createDialog(type);
if (dialog.open() != Window.OK) {
return;
}
ITernScriptPath firstExistingScriptPath = null;
Object[] results = dialog.getResult();
if (results != null && results.length > 0) {
// Add selected file as script path page type.
IResource resource = null;
ITernScriptPath scriptPath = null;
for (Object result : results) {
resource = (IResource) result;
scriptPath = getScriptPath(resource);
if (scriptPath != null) {
// The current resource to add already exists as script
// path.
if (firstExistingScriptPath == null)
firstExistingScriptPath = scriptPath;
} else {
// Create a script path and add it.
String[] includesPattern = null;
String[] excludesPattern = null;
ternScriptPaths.add(ternProject.createScriptPath(resource,
type, includesPattern, excludesPattern));
}
}
treeViewer.refresh();
if (firstExistingScriptPath != null) {
treeViewer.setSelection(new StructuredSelection(
firstExistingScriptPath));
}
}
}
public SelectionDialog createDialog(ScriptPathsType type) {
final IProject project = ternProject.getProject();
switch (type) {
case FOLDER:
return createFolderDialog(project, false);
case FILE:
return new OpenResourceDialog(getShell(), true, project,
IResource.FILE);
case PROJECT:
return createFolderDialog(project, true);
default:
return null;
}
}
public SelectionDialog createFolderDialog(final IProject project,
final boolean showAllProjects) {
ILabelProvider lp = new WorkbenchLabelProvider();
ITreeContentProvider cp = new WorkbenchContentProvider();
MultipleFolderSelectionDialog dialog = new MultipleFolderSelectionDialog(
getShell(), lp, cp, !showAllProjects);
if (showAllProjects) {
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
} else {
dialog.setInput(project.getParent());
}
dialog.setInitialFocus(project);
ViewerFilter filter = new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement,
Object element) {
if (showAllProjects) {
if (element instanceof IProject) {
IProject p = (IProject) element;
return (!p.equals(project) && TernCorePlugin
.hasTernNature(p));
}
} else {
if (element instanceof IContainer) {
IContainer container = (IContainer) element;
if (container.getType() == IResource.FOLDER) {
return true;
}
if (container.getType() == IResource.PROJECT) {
return project.equals(container);
}
return false;
}
}
return false;
}
};
dialog.addFilter(filter);
return dialog;
}
/**
* Returns the script path of the given resource and null otherwise.
*
* @param resource
* @return
*/
private ITernScriptPath getScriptPath(IResource resource) {
for (ITernScriptPath scriptPath : ternScriptPaths) {
if (resource.equals(scriptPath.getAdapter(IResource.class))) {
return scriptPath;
}
}
return null;
}
/**
* Remove selected script paths.
*/
protected void removeScriptPaths() {
IStructuredSelection selection = (IStructuredSelection) treeViewer
.getSelection();
if (!selection.isEmpty()) {
this.ternScriptPaths.removeAll(selection.toList());
treeViewer.refresh();
}
}
private Shell getShell() {
return fControl.getShell();
}
public Control getControl() {
return fControl;
}
public void setTernScriptPaths(Collection<ITernScriptPath> ternScriptPaths) {
this.ternScriptPaths.clear();
this.ternScriptPaths.addAll(ternScriptPaths);
treeViewer.setInput(this.ternScriptPaths);
}
public List<ITernScriptPath> getTernScriptPaths() {
return ternScriptPaths;
}
@Override
protected Tree getTree() {
return treeViewer.getTree();
}
@Override
protected IDialogSettings getDialogSettings() {
return TernUIPlugin.getDefault().getDialogSettings();
}
@Override
protected String getQualifier() {
return TernUIPlugin.PLUGIN_ID;
}
protected Button createPushButton(Composite parent, String label) {
Button button = new Button(parent, SWT.PUSH);
button.setText(label);
button.setLayoutData(GridDataFactory.fillDefaults().create());
return button;
}
}