| /*=============================================================================# |
| # Copyright (c) 2009, 2019 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.objectbrowser; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.viewers.IElementComparer; |
| import org.eclipse.jface.viewers.ITreeSelection; |
| import org.eclipse.jface.viewers.TreePath; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.ui.ISharedImages; |
| import org.eclipse.ui.PlatformUI; |
| |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.status.ProgressMonitor; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| import org.eclipse.statet.jcommons.ts.core.Tool; |
| |
| import org.eclipse.statet.ecommons.models.core.util.ElementPartition; |
| import org.eclipse.statet.ecommons.ts.ui.ToolRunnableDecorator; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| |
| import org.eclipse.statet.ltk.core.ElementName; |
| import org.eclipse.statet.nico.core.runtime.ToolProcess; |
| import org.eclipse.statet.nico.ui.util.ToolMessageDialog; |
| import org.eclipse.statet.r.console.core.AbstractRDataRunnable; |
| import org.eclipse.statet.r.console.core.IRDataAdapter; |
| import org.eclipse.statet.r.core.data.CombinedRElement; |
| import org.eclipse.statet.r.core.model.RElementName; |
| import org.eclipse.statet.r.ui.util.RElementInputContentProvider; |
| import org.eclipse.statet.rj.data.RObject; |
| |
| |
| class DeleteHandler extends AbstractHandler { |
| |
| |
| private static class DeleteRunnable extends AbstractRDataRunnable implements ToolRunnableDecorator { |
| |
| private final List<String> names; |
| private final List<String> commands; |
| private final Set<ElementName> topEnvirs; |
| |
| public DeleteRunnable(final List<String> names, final List<String> commands, |
| final Set<ElementName> topEnvirs) { |
| super("r/objectbrowser/delete", "Delete Elements"); //$NON-NLS-1$ |
| this.names = names; |
| this.commands = commands; |
| this.topEnvirs = topEnvirs; |
| } |
| |
| @Override |
| public Image getImage() { |
| return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); |
| } |
| |
| @Override |
| public boolean changed(final int event, final Tool tool) { |
| if (event == MOVING_FROM) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| protected void run(final IRDataAdapter r, |
| final ProgressMonitor m) throws StatusException { |
| r.briefAboutToChange(); |
| try { |
| for (int i = 0; i < this.names.size(); i++) { |
| r.evalVoid(this.commands.get(i), m); |
| } |
| } |
| finally { |
| r.briefChanged(this.topEnvirs, 0); |
| } |
| } |
| |
| } |
| |
| |
| private final ObjectBrowserView view; |
| |
| |
| public DeleteHandler(final ObjectBrowserView view) { |
| this.view = view; |
| } |
| |
| |
| private boolean isValidSelection(final ITreeSelection selection) { |
| if (selection == null || selection.isEmpty()) { |
| return false; |
| } |
| for (final Iterator<?> iter = selection.iterator(); iter.hasNext(); ) { |
| final Object element = iter.next(); |
| if (element instanceof ElementPartition) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public void setEnabled(final @Nullable Object evaluationContext) { |
| final ToolProcess process = this.view.getTool(); |
| setBaseEnabled(process != null && !process.isTerminated() |
| && isValidSelection(this.view.getSelection()) ); |
| } |
| |
| @Override |
| public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException { |
| if (!UIAccess.isOkToUse(this.view.getViewer())) { |
| return null; |
| } |
| final ITreeSelection selection = this.view.getSelection(); |
| if (!isValidSelection(selection)) { |
| return null; |
| } |
| final TreePath[] treePaths = selection.getPaths(); |
| Arrays.sort(treePaths, new Comparator<TreePath>() { |
| @Override |
| public int compare(final TreePath o1, final TreePath o2) { |
| return o1.getSegmentCount()-o2.getSegmentCount(); |
| } |
| }); |
| final IElementComparer comparer = new IElementComparer() { |
| @Override |
| public int hashCode(final Object e) { |
| return e.hashCode(); |
| } |
| @Override |
| public boolean equals(final Object e1, final Object e2) { |
| return (e1 == e2); |
| } |
| }; |
| final List<String> commands= new ArrayList<>(treePaths.length); |
| final List<String> names= new ArrayList<>(treePaths.length); |
| final Set<ElementName> topEnvirs= new HashSet<>(treePaths.length); |
| ITER_ELEMENTS: for (int i = 0; i < treePaths.length; i++) { |
| for (int j = 0; j < i; j++) { |
| if (treePaths[j] != null && treePaths[i].startsWith(treePaths[j], comparer)) { |
| treePaths[i] = null; |
| continue ITER_ELEMENTS; |
| } |
| } |
| |
| final TreePath treePath = treePaths[i]; |
| final CombinedRElement element= RElementInputContentProvider.getCombinedRElement(treePath.getLastSegment()); |
| final CombinedRElement parent= element.getModelParent(); |
| |
| final RElementName elementName = this.view.getFQElementName(treePath); |
| if (parent != null && elementName != null) { |
| final RElementName topName; |
| switch (parent.getRObjectType()) { |
| case RObject.TYPE_ENVIRONMENT: { |
| final RElementName envirName = (treePath.getSegmentCount() > 1) ? this.view.getFQElementName(treePath.getParentPath()) : parent.getElementName(); |
| final ElementName itemName = element.getElementName(); |
| topName = elementName.getScope(); |
| if (envirName != null) { // elementName ok => segmentName ok |
| commands.add("rm(`"+itemName.getSegmentName()+"`,"+ //$NON-NLS-1$ //$NON-NLS-2$ |
| "pos="+RElementName.createDisplayName(envirName, RElementName.DISPLAY_FQN | RElementName.DISPLAY_EXACT)+ //$NON-NLS-1$ |
| ")"); //$NON-NLS-1$ |
| names.add(elementName.getDisplayName()); |
| topEnvirs.add(topName); |
| continue ITER_ELEMENTS; |
| } |
| break; } |
| case RObject.TYPE_LIST: |
| case RObject.TYPE_DATAFRAME: |
| case RObject.TYPE_S4OBJECT: |
| topName = elementName.getScope(); |
| final String name = RElementName.createDisplayName(elementName, RElementName.DISPLAY_EXACT); |
| commands.add("with("+RElementName.createDisplayName(topName, RElementName.DISPLAY_FQN)+","+ //$NON-NLS-1$ //$NON-NLS-2$ |
| name+"<-NULL"+ //$NON-NLS-1$ |
| ")"); //$NON-NLS-1$ |
| names.add(elementName.getDisplayName()); |
| topEnvirs.add(topName); |
| continue ITER_ELEMENTS; |
| } |
| } |
| |
| final StringBuilder message = new StringBuilder("Selection contains unsupported object"); |
| if (elementName != null) { |
| message.append("\n\t"); //$NON-NLS-1$ |
| message.append(elementName.getDisplayName()); |
| } |
| else { |
| message.append("."); //$NON-NLS-1$ |
| } |
| MessageDialog.openError(this.view.getSite().getShell(), "Delete", message.toString()); |
| return null; |
| } |
| |
| final StringBuilder message = new StringBuilder(names.size() == 1 ? |
| "Delete this object?" : |
| NLS.bind("Delete these {0} objects?", names.size())); |
| final int show = (names.size() > 5) ? 3 : names.size(); |
| for (int i = 0; i < show; i++) { |
| message.append("\n\t"); //$NON-NLS-1$ |
| message.append(names.get(i)); |
| } |
| if (show < names.size()) { |
| message.append("\n\t..."); //$NON-NLS-1$ |
| } |
| |
| final ToolProcess process = this.view.getTool(); |
| if (ToolMessageDialog.openConfirm(process, this.view.getSite().getShell(), "Delete R Objects", |
| message.toString(), "Delete")) { |
| process.getQueue().add(new DeleteRunnable(names, commands, topEnvirs)); |
| } |
| |
| return null; |
| } |
| |
| } |