/*******************************************************************************
* Copyright (c) 2015 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.views;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.springframework.ide.eclipse.boot.dash.BootDashActivator;
import org.springframework.ide.eclipse.boot.dash.livexp.MultiSelection;
import org.springframework.ide.eclipse.boot.dash.livexp.MultiSelectionSource;
import org.springframework.ide.eclipse.boot.dash.model.BootDashElement;
import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel;
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
import org.springframework.ide.eclipse.boot.dash.util.ToolbarPulldownContributionItem;
import org.springframework.ide.eclipse.boot.dash.views.sections.BootDashUnifiedTreeSection;
import org.springframework.ide.eclipse.boot.dash.views.sections.TagSearchSection;
import org.springframework.ide.eclipse.boot.dash.views.sections.ViewPartWithSections;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
import org.springsource.ide.eclipse.commons.livexp.ui.IPageSection;
import com.google.common.collect.ImmutableSet;
/**
* @author Kris De Volder
*/
public class BootDashTreeView extends ViewPartWithSections implements ITabbedPropertySheetPageContributor, ISelectionProvider {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "org.springframework.ide.eclipse.boot.dash.views.BootDashView";
/**
* Adds scroll support to the whole view. You probably want to disable this
* if view is broken into pieces that have their own scrollbars
*/
private static final boolean ENABLE_SCROLLING = false;
private BootDashViewModel model = BootDashActivator.getDefault().getModel();
// private Action refreshAction;
// private Action doubleClickAction;
private BootDashActions actions;
private UserInteractions ui = new DefaultUserInteractions(this);
private MultiSelection<BootDashElement> selection = null; // lazy init
private List<ISelectionChangedListener> selectionListeners = new ArrayList<>();
/*
* The content provider class is responsible for providing objects to the
* view. It can wrap existing objects in adapters or simply return objects
* as-is. These objects may be sensitive to the current input of the view,
* or ignore it and always show the same content (like Task List, for
* example).
*/
/**
* The constructor.
*/
public BootDashTreeView() {
super(ENABLE_SCROLLING);
}
@Override
public void dispose() {
super.dispose();
if (actions != null) {
actions.dispose();
}
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
super.createPartControl(parent);
getSite().setSelectionProvider(this);
// Create the help context id for the viewer's control
// PlatformUI.getWorkbench().getHelpSystem().setHelp(tv.getControl(),
// "org.springframework.ide.eclipse.boot.dash.viewer");
actions = new BootDashActions(model, getRawSelection(), ui);
// hookContextMenu();
// hookDoubleClickAction();
contributeToActionBars();
}
public synchronized MultiSelection<BootDashElement> getRawSelection() {
if (this.selection == null) {
MultiSelection<BootDashElement> selection = MultiSelection.empty(BootDashElement.class);
for (IPageSection section : getSections()) {
if (section instanceof MultiSelectionSource) {
MultiSelectionSource source = (MultiSelectionSource) section;
MultiSelection<BootDashElement> subSelection = source.getSelection().filter(BootDashElement.class);
selection = MultiSelection.union(selection, subSelection);
}
}
this.selection = selection;
selection.getElements().addListener(new ValueListener<ImmutableSet<BootDashElement>>() {
@Override
public void gotValue(LiveExpression<ImmutableSet<BootDashElement>> exp, ImmutableSet<BootDashElement> value) {
ISelection selection = getSelection();
for (ISelectionChangedListener selectionListener : selectionListeners) {
selectionListener.selectionChanged(new SelectionChangedEvent(BootDashTreeView.this, selection));
}
}
});
}
return this.selection;
}
public List<BootDashElement> getSelectedElements() {
ArrayList<BootDashElement> elements = new ArrayList<>();
for (Object e : getRawSelection().getValue()) {
if (e instanceof BootDashElement) {
elements.add((BootDashElement) e);
}
}
return Collections.unmodifiableList(elements);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
/**
* Fills the pull-down menu for this view (accessible from the toolbar)
*/
private void fillLocalPullDown(IMenuManager manager) {
for (RunStateAction a : actions.getRunStateActions()) {
manager.add(a);
}
manager.add(actions.getOpenBrowserAction());
manager.add(actions.getOpenNgrokAdminUi());
manager.add(actions.getOpenConsoleAction());
manager.add(actions.getOpenInPackageExplorerAction());
manager.add(actions.getOpenConfigAction());
manager.add(actions.getShowPropertiesViewAction());
manager.add(new Separator());
manager.add(actions.getExposeRunAppAction());
manager.add(actions.getExposeDebugAppAction());
manager.add(new Separator());
addAddRunTargetMenuActions(manager);
manager.add(new Separator());
//manager.add(actions.getToggleFiltersDialogAction());
for (ToggleFilterAction a : actions.getToggleFilterActions()) {
manager.add(a);
}
manager.add(new Separator());
manager.add(actions.getOpenFilterPreferencesAction());
// manager.add(refreshAction);
// manager.add(new Separator());
// manager.add(action2);
}
private void fillLocalToolBar(IToolBarManager manager) {
for (RunStateAction a : actions.getRunStateActions()) {
manager.add(a);
}
manager.add(actions.getOpenBrowserAction());
manager.add(actions.getOpenConsoleAction());
manager.add(actions.getOpenConfigAction());
manager.add(actions.getShowPropertiesViewAction());
manager.add(actions.getToggleFiltersDialogAction());
// This ought to work, but it doesn't.
// manager.add(createAddRunTargetMenuManager());
// Must write specific code to create toolbar pull-down button / menu:
createAddRunTargetPulldown(manager);
// manager.add(refreshAction);
// manager.add(action2);
}
private void addAddRunTargetMenuActions(IMenuManager manager) {
if (actions.getAddRunTargetActions().length==1) {
//Special case. Creationg a pulldown for just one item isn't very logical.
AddRunTargetAction action = actions.getAddRunTargetActions()[0];
manager.add(action);
} else {
MenuManager menu = createAddRunTargetMenuManager();
manager.add(menu);
}
}
private MenuManager createAddRunTargetMenuManager() {
final MenuManager menu = new MenuManager("Add Run Target...", BootDashActivator.getImageDescriptor("icons/add_target.png"), null);
for (AddRunTargetAction a : actions.getAddRunTargetActions()) {
menu.add(a);
}
return menu;
}
public void createAddRunTargetPulldown(IToolBarManager toolbar) {
if (actions.getAddRunTargetActions().length==1) {
//Special case. Creationg a pulldown for just one item isn't very logical.
AddRunTargetAction action = actions.getAddRunTargetActions()[0];
toolbar.add(action);
} else {
Action dropdownAction=new Action("Create Target",SWT.DROP_DOWN){};
dropdownAction.setImageDescriptor(BootDashActivator.getImageDescriptor("icons/add_target.png"));
dropdownAction.setMenuCreator(new IMenuCreator() {
Menu theMenu;
@Override
public Menu getMenu(Menu parent) {
return null;
}
@Override
public Menu getMenu(Control parent) {
if (theMenu==null) {
final MenuManager menu = createAddRunTargetMenuManager();
theMenu = menu.createContextMenu(parent);
theMenu.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
menu.dispose();
}
});
}
return theMenu;
}
@Override
public void dispose() {
}
});
toolbar.add(new ToolbarPulldownContributionItem(dropdownAction));
}
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
if (page != null) {
page.setFocus();
}
}
public UserInteractions getUserInteractions() {
return ui;
}
@Override
public Shell getShell() {
return getSite().getShell();
}
@Override
protected List<IPageSection> createSections() throws CoreException {
List<IPageSection> sections = new ArrayList<>();
sections.add(new TagSearchSection(BootDashTreeView.this, model.getFilterBox().getText(), model));
sections.add(new BootDashUnifiedTreeSection(this, model, ui));
return sections;
}
@Override
public String getContributorId() {
return "org.springframework.ide.eclipse.boot.dash.propertyContributor";
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object getAdapter(Class adapter) {
if (adapter == IPropertySheetPage.class) {
return new TabbedPropertySheetPage(this);
}
return super.getAdapter(adapter);
}
@Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
selectionListeners.add(listener);
}
@Override
public ISelection getSelection() {
return new StructuredSelection(getRawSelection().getValue().toArray());
}
@Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
selectionListeners.remove(listener);
}
@Override
public void setSelection(ISelection selection) {
//This method isn't implemented. Probably this is okay, nobody needs to set our selection.
// If the need arises to do this in the future, then the 'setSelection' needs to be distributed to
// our subsections so each subsection can select whichever elements in the selection apply to them.
}
}