blob: 635fdf88b1294c9b79e3badd52c8cc6c107e61a6 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.ui.datafilterview;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler2;
import org.eclipse.core.databinding.UpdateSetStrategy;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.databinding.viewers.typed.ViewerProperties;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckable;
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.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.menus.UIElement;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport;
import org.eclipse.statet.ecommons.ui.actions.ControlServicesUtil;
import org.eclipse.statet.ecommons.ui.actions.HandlerCollection;
import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem;
import org.eclipse.statet.ecommons.ui.components.DropDownButton;
import org.eclipse.statet.ecommons.ui.components.SearchText;
import org.eclipse.statet.ecommons.ui.util.AutoCheckController;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
import org.eclipse.statet.ecommons.ui.viewers.ViewerUtils;
import org.eclipse.statet.ecommons.ui.workbench.WorkbenchUIUtils;
import org.eclipse.statet.internal.r.ui.datafilter.TextSearchType;
import org.eclipse.statet.internal.r.ui.datafilter.TextVariableFilter;
import org.eclipse.statet.rj.data.RCharacterStore;
public class TextClient extends FilterClient {
private class RemoveHandler extends AbstractHandler implements IElementUpdater {
@Override
public void setEnabled(final Object evaluationContext) {
setBaseEnabled(!TextClient.this.valueListViewer.getSelection().isEmpty());
}
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
final IStructuredSelection selection= (IStructuredSelection) TextClient.this.valueListViewer.getSelection();
TextClient.this.filter.removeValues(selection.toList());
updateInput();
return null;
}
@Override
public void updateElement(final UIElement element, final Map parameters) {
WorkbenchUIUtils.aboutToUpdateCommandsElements(this, element);
try {
element.setText(Messages.Items_Remove_label);
element.setTooltip(Messages.Items_RemoveSelected_label);
}
finally {
WorkbenchUIUtils.finalizeUpdateCommandsElements(this);
}
}
}
private class RemoveUncheckedHandler extends AbstractHandler {
@Override
public void setEnabled(final Object evaluationContext) {
setBaseEnabled(TextClient.this.availableValues.getLength() > TextClient.this.selectedValueSet.size());
}
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
final List<String> values= new ArrayList<>((int) TextClient.this.availableValues.getLength() - TextClient.this.selectedValueSet.size());
for (int i= 0; i < TextClient.this.availableValues.getLength(); i++) {
final String value= TextClient.this.availableValues.get(i);
if (!TextClient.this.selectedValueSet.contains(value)) {
values.add(value);
}
}
TextClient.this.filter.removeValues(values);
updateInput();
return null;
}
}
private class RemoveAllHandler extends AbstractHandler {
@Override
public void setEnabled(final Object evaluationContext) {
setBaseEnabled(TextClient.this.availableValues.getLength() > 0);
}
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
TextClient.this.filter.removeAllValues();
updateInput();
return null;
}
}
private SearchText searchTextControl;
private DropDownButton searchButtonControl;
private MenuItem[] searchMenuItems;
private TextSearchType searchType;
private CheckboxTableViewer valueListViewer;
private RCharacterStore availableValues;
private final IObservableSet<@Nullable String> selectedValueSet;
private final HandlerCollection valueListHandlers= new HandlerCollection();
private MenuManager valueListMenuManager;
private final TextVariableFilter filter;
public TextClient(final VariableComposite parent, final TextVariableFilter filter) {
super(parent);
this.filter= filter;
filter.setListener(this);
this.availableValues= filter.getAvailableValues();
this.selectedValueSet= filter.getSelectedValues();
this.searchType= TextSearchType.ECLIPSE;
init(2);
}
@Override
public TextVariableFilter getFilter() {
return this.filter;
}
@Override
protected void addWidgets() {
this.searchTextControl= new SearchText(this, "", SWT.FLAT | SWT.BORDER); //$NON-NLS-1$
this.searchTextControl.addListener(new SearchText.Listener() {
@Override
public void textChanged(final boolean user) {
}
@Override
public void okPressed() {
search(null);
}
@Override
public void downPressed() {
}
});
this.searchTextControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
this.searchButtonControl= new DropDownButton(this, SWT.FLAT);
this.searchButtonControl.setText(Messages.Items_Search_label);
{ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, false, false);
gd.heightHint= this.searchButtonControl.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
final int textHeight= this.searchTextControl.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
if (gd.heightHint - textHeight > 2) {
gd.heightHint= textHeight + 2;
}
this.searchButtonControl.setLayoutData(gd);
}
this.searchButtonControl.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
search(null);
}
});
{ final Menu searchMenu= this.searchButtonControl.getDropDownMenu();
final List<TextSearchType> searchTypes= TextSearchType.TYPES;
this.searchMenuItems= new MenuItem[searchTypes.size()];
final Listener searchTypeListener= new Listener() {
@Override
public void handleEvent(final Event event) {
search((TextSearchType) event.widget.getData());
}
};
for (int id= 0; id < searchTypes.size(); id++) {
final TextSearchType type= searchTypes.get(id);
final MenuItem item= new MenuItem(searchMenu, SWT.RADIO);
item.setText(type.getLabel());
item.setData(type);
item.addListener(SWT.Selection, searchTypeListener);
this.searchMenuItems[id]= item;
}
}
setSearchType(this.searchType);
this.valueListViewer= CheckboxTableViewer.newCheckList(this, SWT.MULTI | SWT.FLAT | SWT.FULL_SELECTION);
this.valueListViewer.setContentProvider(new RStoreContentProvider());
this.valueListViewer.setLabelProvider(new ColumnLabelProvider(this.filter.getColumn()));
}
@Override
protected void initActions(final IServiceLocator serviceLocator) {
final ControlServicesUtil servicesUtil= new ControlServicesUtil(serviceLocator,
getClass().getName()+"/ValueList#"+hashCode(), this ); //$NON-NLS-1$
servicesUtil.addControl(this.valueListViewer.getTable());
final AutoCheckController<?> autoCheckController= new AutoCheckController<>(
this.valueListViewer, this.selectedValueSet );
{ final IHandler2 handler= autoCheckController.createSelectAllHandler();
this.valueListHandlers.add(SELECT_ALL_COMMAND_ID, handler);
servicesUtil.activateHandler(SELECT_ALL_COMMAND_ID, handler);
}
{ final IHandler2 handler= new RemoveHandler();
this.valueListHandlers.add(REMOVE_COMMAND_ID, handler);
servicesUtil.activateHandler(IWorkbenchCommandConstants.EDIT_DELETE, handler);
}
{ final IHandler2 handler= new RemoveUncheckedHandler();
this.valueListHandlers.add(REMOVE_UNCHECKED_HANDLER_ID, handler);
}
{ final IHandler2 handler= new RemoveAllHandler();
this.valueListHandlers.add(REMOVE_ALL_HANDLER_COMMAND_ID, handler);
}
ViewerUtils.installSearchTextNavigation(this.valueListViewer, this.searchTextControl, true);
this.valueListMenuManager= new MenuManager();
this.valueListMenuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
null, SELECT_ALL_COMMAND_ID, HandlerContributionItem.STYLE_PUSH),
this.valueListHandlers.get(SELECT_ALL_COMMAND_ID) ));
this.valueListMenuManager.add(new Separator());
this.valueListMenuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
null, REMOVE_COMMAND_ID, HandlerContributionItem.STYLE_PUSH),
this.valueListHandlers.get(REMOVE_COMMAND_ID) ));
this.valueListMenuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
null, HandlerContributionItem.NO_COMMAND_ID, null,
null, null, null,
Messages.Items_RemoveUnchecked_label, null, "Remove unchecked items",
HandlerContributionItem.STYLE_PUSH, null, false),
this.valueListHandlers.get(REMOVE_UNCHECKED_HANDLER_ID) ));
this.valueListMenuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
null, HandlerContributionItem.NO_COMMAND_ID, null,
null, null, null,
Messages.Items_RemoveAll_label, null, "Remove all items",
HandlerContributionItem.STYLE_PUSH, null, false),
this.valueListHandlers.get(REMOVE_ALL_HANDLER_COMMAND_ID) ));
this.valueListViewer.getTable().setMenu(this.valueListMenuManager.createContextMenu(this.valueListViewer.getControl()));
this.valueListViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
updateActions();
}
});
updateActions();
}
@Override
protected void addBindings(final DataBindingSupport db) {
db.getContext().bindSet(
ViewerProperties.checkedElements(Object.class)
.observe((ICheckable)this.valueListViewer),
this.selectedValueSet,
new UpdateSetStrategy<Object, @Nullable String>()
.setConverter(new UI2RStoreConverter<String>()),
new UpdateSetStrategy<@Nullable String, Object>()
.setConverter(new RStore2UIConverter<String>()) );
}
@Override
protected void updateInput() {
this.availableValues= this.filter.getAvailableValues();
this.valueListViewer.setInput(this.availableValues);
updateActions();
if (updateLayout()) {
getParent().layout(new Control[] { this });
}
}
protected void updateActions() {
this.valueListHandlers.get(REMOVE_COMMAND_ID).setEnabled(null);
}
@Override
protected boolean updateLayout() {
return updateLayout(this.valueListViewer, (int) this.availableValues.getLength());
}
@Override
protected int getMinHeightPadding() {
return this.searchTextControl.getSize().y + 20 + 10 * LayoutUtils.defaultVSpacing();
}
protected void setSearchType(final TextSearchType type) {
this.searchType= type;
for (int id= 0; id < this.searchMenuItems.length; id++) {
this.searchMenuItems[id].setSelection(type.getId() == id);
}
this.searchButtonControl.setToolTipText(type.getLabel());
}
private void search(TextSearchType type) {
if (type != null) {
if (this.searchType != type) {
setSearchType(type);
}
}
else {
type= this.searchType;
}
final String text= this.searchTextControl.getText();
this.filter.search(type, text);
}
@Override
protected void onDispose() {
if (this.valueListMenuManager != null) {
this.valueListMenuManager.dispose();
this.valueListMenuManager= null;
}
}
}