| /*=============================================================================# |
| # Copyright (c) 2011, 2018 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.rj.eclient.graphics.util; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| import org.eclipse.statet.jcommons.status.ProgressMonitor; |
| import org.eclipse.statet.jcommons.status.Status; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| import org.eclipse.statet.jcommons.ts.core.SystemRunnable; |
| import org.eclipse.statet.jcommons.ts.core.Tool; |
| import org.eclipse.statet.jcommons.ts.core.ToolService; |
| |
| import org.eclipse.statet.rj.eclient.graphics.ERGraphic; |
| import org.eclipse.statet.rj.eclient.graphics.LocatorCallback; |
| |
| |
| /** |
| * Basic implementation for a local locator for R graphics. |
| * <p> |
| * Requests the user to locate point and converts the graphic coordinates to user coordinates. |
| * It uses the tool service API (org.eclipse.statet.jcommons.ts.core) to schedule the R job.</p> |
| */ |
| public abstract class AbstractLocalLocator extends LocatorCallback implements SystemRunnable { |
| |
| protected static final ImList<String> OK_CANCEL_STOP_TYPES= ImCollections.newList( |
| ERGraphic.LOCATOR_DONE, ERGraphic.LOCATOR_CANCEL ); |
| |
| |
| private final ERGraphic graphic; |
| private final Tool tool; |
| |
| private boolean started; |
| private boolean graphicLocatorStarted; |
| private boolean runnableScheduled; |
| |
| private final List<double[]> toConvert= new ArrayList<>(); |
| |
| private final List<double[]> locatedGraphic= new ArrayList<>(); |
| private final List<double[]> locatedUser= new ArrayList<>(); |
| |
| private volatile int counter; |
| |
| |
| public AbstractLocalLocator(final ERGraphic graphic) { |
| this.graphic= graphic; |
| this.tool= graphic.getRHandle(); |
| } |
| |
| |
| @Override |
| public Collection<String> getStopTypes() { |
| return OK_CANCEL_STOP_TYPES; |
| } |
| |
| @Override |
| public String getMessage() { |
| return super.getMessage() + " (" + this.counter + " selected)"; |
| } |
| |
| @Override |
| public int located(final double x, final double y) { |
| synchronized (this) { |
| this.counter++; |
| this.toConvert.add(new double[] { x, y }); |
| if (!internalScheduleConversion()) { |
| internalStop(null); |
| return STOP; |
| } |
| } |
| return NEXT; |
| } |
| |
| @Override |
| public void stopped(final String type) { |
| synchronized (this) { |
| this.graphicLocatorStarted= false; |
| if (type == ERGraphic.LOCATOR_DONE) { |
| if (this.toConvert.isEmpty()) { |
| internalStop(ERGraphic.LOCATOR_DONE); |
| return; |
| } |
| else if (internalScheduleConversion()) { |
| return; |
| } |
| // scheduling failed |
| } |
| internalStop(null); |
| return; |
| } |
| } |
| |
| @Override |
| public String getTypeId() { |
| return "r/rjgd/locallocator"; //$NON-NLS-1$ |
| } |
| |
| @Override |
| public String getLabel() { |
| return "Resolve Graphic Points"; |
| } |
| |
| @Override |
| public boolean canRunIn(final Tool tool) { |
| return (tool == this.tool); |
| } |
| |
| @Override |
| public boolean changed(final int event, final Tool tool) { |
| switch (event) { |
| case REMOVING_FROM: |
| return false; |
| case BEING_ABANDONED: |
| case FINISHING_CANCEL: |
| case FINISHING_ERROR: |
| synchronized (this) { |
| this.runnableScheduled= false; |
| if (!this.graphicLocatorStarted) { |
| internalStop(null); |
| break; |
| } |
| } |
| this.graphic.stopLocator(null); |
| break; |
| case FINISHING_OK: |
| synchronized (this) { |
| if (!this.graphicLocatorStarted && this.toConvert.isEmpty()) { |
| internalStop(ERGraphic.LOCATOR_DONE); |
| break; |
| } |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public void run(final ToolService service, final ProgressMonitor m) throws StatusException { |
| double[] graphic= null; |
| double[] user= null; |
| while (true) { |
| synchronized (this) { |
| if (graphic != null) { |
| if (user != null) { |
| this.locatedGraphic.add(graphic); |
| this.locatedUser.add(user); |
| } |
| else { |
| // invalid point? |
| } |
| } |
| if (this.toConvert.isEmpty()) { |
| this.counter= this.locatedGraphic.size(); |
| this.runnableScheduled= false; |
| return; |
| } |
| graphic= this.toConvert.remove(0); |
| user= null; |
| } |
| user= this.graphic.convertGraphic2User(graphic, m); |
| } |
| } |
| |
| /** |
| * synchronized |
| */ |
| protected boolean internalScheduleConversion() { |
| if (!this.runnableScheduled) { |
| if (this.tool.getQueue().addHot(this).getSeverity() == Status.OK) { |
| this.runnableScheduled= true; |
| return true; |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * synchronized |
| * |
| * @param type the stop type |
| */ |
| protected void internalStop(final String type) { |
| assert (!this.graphicLocatorStarted); |
| if (this.runnableScheduled) { |
| this.tool.getQueue().removeHot(this); |
| this.runnableScheduled= false; |
| } |
| this.started= false; |
| if (type == ERGraphic.LOCATOR_DONE) { |
| finished(new ArrayList<>(this.locatedGraphic), new ArrayList<>(this.locatedUser)); |
| } |
| else { |
| canceled(); |
| } |
| } |
| |
| |
| public boolean start() { |
| synchronized (this) { |
| if (this.started) { |
| return false; |
| } |
| this.toConvert.clear(); |
| this.locatedGraphic.clear(); |
| this.locatedUser.clear(); |
| this.started= this.graphicLocatorStarted= true; |
| this.counter= 0; |
| if (this.graphic.startLocalLocator(this).getSeverity() == Status.OK) { |
| return true; |
| } |
| else { |
| this.started= this.graphicLocatorStarted= false; |
| return false; |
| } |
| } |
| } |
| |
| /** |
| * Is called if the locator and conversion is finished. |
| * |
| * @param graphic the graphic coordinates |
| * @param user the user coordinates |
| */ |
| protected abstract void finished(final List<double[]> graphic, final List<double[]> user); |
| |
| /** |
| * Is called if the locator was canceled |
| */ |
| protected abstract void canceled(); |
| |
| } |