/*
* Copyright (c) 2015 the original author or authors.
* 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:
* Etienne Studer & Donát Csikós (Gradle Inc.) - initial API and implementation and initial documentation
* Simon Scholz <simon.scholz@vogella.com> - Bug 479243
*/
package org.eclipse.buildship.ui.view.task;
import java.util.List;
import com.gradleware.tooling.toolingmodel.OmniEclipseProject;
import com.gradleware.tooling.toolingmodel.repository.FetchStrategy;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.wizards.IWizardDescriptor;
import org.eclipse.buildship.core.GradlePluginsRuntimeException;
import org.eclipse.buildship.ui.UiPluginConstants;
import org.eclipse.buildship.ui.external.viewer.FilteredTree;
import org.eclipse.buildship.ui.external.viewer.PatternFilter;
import org.eclipse.buildship.ui.util.nodeselection.NodeSelection;
import org.eclipse.buildship.ui.util.nodeselection.NodeSelectionProvider;
import org.eclipse.buildship.ui.util.nodeselection.SelectionHistoryManager;
/**
* A view displaying the Gradle tasks of the Gradle projects in the workspace.
*/
public final class TaskView extends ViewPart implements NodeSelectionProvider {
// view id declared in the plugin.xml
public static final String ID = "org.eclipse.buildship.ui.views.taskview"; //$NON-NLS-1$
private TaskViewState state;
private UiContributionManager uiContributionManager;
private SelectionHistoryManager selectionHistoryManager;
private PageBook pages;
private Link emptyInputPage;
private Label errorInputPage;
private Composite nonEmptyInputPage;
private TreeViewer treeViewer;
private FilteredTree filteredTree;
@Override
public void init(IViewSite site) throws PartInitException {
super.init(site);
// load the persisted state before we create any UI components that query for some state
this.state = new TaskViewState();
this.state.load();
}
@Override
public void createPartControl(Composite parent) {
// the top-level control changing its content depending on whether the content provider
// contains task data to display or not
this.pages = new PageBook(parent, SWT.NONE);
// if there is no task data to display, show only a label
this.emptyInputPage = new Link(this.pages, SWT.NONE);
this.emptyInputPage.setText(TaskViewMessages.Label_No_Gradle_Projects);
// if there is a problem loading the task data, show an error label
this.errorInputPage = new Label(this.pages, SWT.NONE);
this.errorInputPage.setText(TaskViewMessages.Label_Reload_Error);
this.errorInputPage.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_RED));
// if there is task data to display, show the task tree and the search label on the bottom
this.nonEmptyInputPage = new Composite(this.pages, SWT.NONE);
GridLayout gridLayout = new GridLayout(1, false);
gridLayout.marginWidth = gridLayout.marginHeight = gridLayout.verticalSpacing = 0;
this.nonEmptyInputPage.setLayout(gridLayout);
// add tree with two columns
this.filteredTree = new FilteredTree(this.nonEmptyInputPage, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI, new PatternFilter(true));
this.filteredTree.setShowFilterControls(false);
this.treeViewer = this.filteredTree.getViewer();
this.treeViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
// set filter, comparator, and content provider
this.treeViewer.addFilter(TaskNodeViewerFilter.createFor(getState()));
this.treeViewer.setComparator(TaskNodeViewerSorter.createFor(this.state));
this.treeViewer.setContentProvider(new TaskViewContentProvider(this));
TreeViewerColumn treeViewerNameColumn = new TreeViewerColumn(this.treeViewer, SWT.LEFT);
treeViewerNameColumn.setLabelProvider(new DelegatingStyledCellLabelProvider(new TaskNameLabelProvider()));
final TreeColumn taskNameColumn = treeViewerNameColumn.getColumn();
taskNameColumn.setText(TaskViewMessages.Tree_Column_Name_Text);
taskNameColumn.setWidth(this.state.getHeaderNameColumnWidth());
TreeViewerColumn treeViewerDescriptionColumn = new TreeViewerColumn(this.treeViewer, SWT.LEFT);
treeViewerDescriptionColumn.setLabelProvider(new TaskDescriptionLabelProvider());
final TreeColumn taskDescriptionColumn = treeViewerDescriptionColumn.getColumn();
taskDescriptionColumn.setText(TaskViewMessages.Tree_Column_Description_Text);
taskDescriptionColumn.setWidth(this.state.getHeaderDescriptionColumnWidth());
// open the import wizard if the empty input page link is selected
this.emptyInputPage.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
try {
IWizardDescriptor descriptor = PlatformUI.getWorkbench().getImportWizardRegistry().findWizard(UiPluginConstants.IMPORT_WIZARD_ID);
IWizard wizard = descriptor.createWizard();
WizardDialog dialog = new WizardDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), wizard);
dialog.open();
} catch (CoreException e) {
throw new GradlePluginsRuntimeException(e);
}
}
});
// when changed save the header width into the state
taskNameColumn.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
TaskView.this.state.setHeaderNameColumnWidth(taskNameColumn.getWidth());
}
});
taskDescriptionColumn.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
TaskView.this.state.setHeaderDescriptionColumnWidth(taskDescriptionColumn.getWidth());
}
});
// manage the selection history as required for the task execution and let the
// SelectionHistoryManager propagate the NodeSelection to the Workbench
this.selectionHistoryManager = new SelectionHistoryManager(this.treeViewer);
getSite().setSelectionProvider(this.selectionHistoryManager);
// create toolbar actions, menu items, event listeners, etc.
this.uiContributionManager = new UiContributionManager(this);
this.uiContributionManager.wire();
// set initial content (use fetch strategy LOAD_IF_NOT_CACHED since
// the model might already be available in case a project import has
// just happened)
reload(FetchStrategy.LOAD_IF_NOT_CACHED);
}
/**
* Triggers a refresh of the view.
*/
public void refresh() {
if (!this.treeViewer.getTree().isDisposed()) {
this.treeViewer.refresh(true);
}
}
/**
* Updates the view to display the given content.
* @param content the content, never null
*/
public void setContent(TaskViewContent content) {
List<OmniEclipseProject> models = content.getProjects();
List<IProject> faultyProjects = content.getFaultyProjects();
this.pages.showPage((models.isEmpty() && faultyProjects.isEmpty()) ? this.emptyInputPage : this.nonEmptyInputPage);
this.treeViewer.setInput(content);
}
/**
* Reloads the task model in the background and updates this view once the reload is complete.
* Can be safely called outside the UI thread.
* @param fetchStrategy determines how to get the model being visualized from the cache
*/
public void reload(FetchStrategy fetchStrategy) {
new ReloadTaskViewJob(this, fetchStrategy).schedule();
}
@Override
public void setFocus() {
this.pages.setFocus();
}
public TaskViewState getState() {
return this.state;
}
public TreeViewer getTreeViewer() {
return this.treeViewer;
}
public FilteredTree getFilteredTree() {
return this.filteredTree;
}
@Override
public NodeSelection getSelection() {
return this.selectionHistoryManager.getSelectionHistory();
}
@Override
public void dispose() {
if (this.state != null) {
this.state.dispose();
}
if (this.selectionHistoryManager != null) {
this.selectionHistoryManager.dispose();
}
if (this.uiContributionManager != null) {
this.uiContributionManager.dispose();
}
super.dispose();
}
}