/******************************************************************************* * Copyright (c) 2007, 2016 Association for Decentralized Information Management in * Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation * Semantum Oy - JSON plain text input support *******************************************************************************/ package org.simantics.charts.editor; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.eclipse.jface.viewers.ISelection; import org.simantics.Simantics; import org.simantics.charts.internal.JsonUtils; import org.simantics.charts.query.AddChartItem; import org.simantics.charts.query.ChartItemDescriptor; import org.simantics.charts.ui.AddVariableToChartAction; import org.simantics.charts.ui.ChartDropActionFactory; import org.simantics.charts.ui.ChartVariable; import org.simantics.databoard.util.ObjectUtils; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.SelectionHints; import org.simantics.db.layer0.request.PossibleModel; import org.simantics.db.layer0.variable.RVI; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.VariableReference; import org.simantics.db.layer0.variable.Variables; import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant; import org.simantics.g2d.dnd.DragItem; import org.simantics.g2d.dnd.IDnDContext; import org.simantics.g2d.dnd.IDragItem; import org.simantics.g2d.dnd.IDropTargetParticipant; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.PropertyVariables; import org.simantics.modeling.PropertyVariablesImpl; import org.simantics.modeling.utils.VariableReferences; import org.simantics.ui.dnd.LocalObjectTransfer; import org.simantics.ui.dnd.LocalObjectTransferable; import org.simantics.ui.selection.WorkbenchSelectionElement; import org.simantics.utils.FileUtils; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.ISelectionUtils; import org.simantics.utils.ui.dialogs.ShowMessage; /** * @author Tuukka Lehtonen */ public class SubscriptionDropParticipant extends AbstractDiagramParticipant implements IDropTargetParticipant { private static class SubscriptionItemDragItem extends DragItem { public SubscriptionItemDragItem(ChartItemDescriptor obj) { super(obj); } } private static class VariableReferenceDragItem extends DragItem { public VariableReferenceDragItem(VariableReference obj) { super(obj); } } Resource container; Resource model; public SubscriptionDropParticipant(Resource container) { this.container = container; try { model = Simantics.getSession().sync( new PossibleModel( container ) ); } catch (DatabaseException e) { } } @Override public void dragEnter(DropTargetDragEvent dtde, IDnDContext dp) { // The source cannot link, too bad if ((dtde.getSourceActions() & DnDConstants.ACTION_LINK) == 0) { dtde.rejectDrag(); return; } // Ensure the content is usable if (dtde.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) { dragEnterLocalObject(dtde, dp); } else if (dtde.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())) { dragEnterPlainText(dtde, dp); } else { dtde.rejectDrag(); } } private void dragEnterLocalObject(DropTargetDragEvent dtde, IDnDContext dp) { try { Object data = dtde.getTransferable().getTransferData(LocalObjectTransferable.FLAVOR); data = LocalObjectTransfer.getTransfer().getObject(); List items = new ArrayList<>(); Session session = Simantics.getSession(); final List resources = ISelectionUtils.getPossibleKeys(data, SelectionHints.KEY_MAIN, Resource.class); if (!resources.isEmpty()) { // Support SubscriptionItem drags items.addAll( session.syncRequest(new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { List result = new ArrayList<>(); ModelingResources MOD = ModelingResources.getInstance(graph); Resource targetModel = graph.syncRequest(new PossibleModel(container)); if (targetModel != null) { for (Resource r : resources) { if (graph.isInstanceOf(r, MOD.Subscription_Item)) { Resource model = graph.syncRequest(new PossibleModel(r)); if (ObjectUtils.objectEquals(targetModel, model)) result.add( new SubscriptionItemDragItem( AddChartItem.createDescriptor(graph, r) ) ); } } } return result; } }) ); } if(data instanceof RVI) { VariableReferenceDragItem vrdi = new VariableReferenceDragItem(session.sync(new UnaryRead((RVI)data) { @Override public VariableReference perform(ReadGraph graph) throws DatabaseException { return new VariableReference(parameter, Variables.getDatatype(graph, model, parameter), null); } })); items.add( vrdi ); } else { // Variable/PropertyVariable are mutually exclusive List varItems = null; // 1st try Variable final List vars2 = ISelectionUtils.getPossibleKeys(data, SelectionHints.KEY_MAIN, Variable.class); if (!vars2.isEmpty()) { varItems = session.syncRequest( new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { return toDragItems( graph.syncRequest(VariableReferences.variablesToReferences(model, vars2)) ); } } ); } if (varItems == null || varItems.isEmpty()) { // Try legacy PropertyVariables final List vars = ISelectionUtils.getPossibleKeys(data, SelectionHints.KEY_MAIN, PropertyVariables.class); if (!vars.isEmpty()) { varItems = session.syncRequest( new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { List vars2 = PropertyVariablesImpl.resolve(graph, vars); return toDragItems( graph.syncRequest(VariableReferences.toReferences(model, vars2)) ); } } ); } } if (varItems != null) items.addAll(varItems); // Try WorkbenchSelectionElement if (data instanceof ISelection) { final List wses = ISelectionUtils.filterSelection((ISelection)data, WorkbenchSelectionElement.class); if (!wses.isEmpty()) { items.addAll( session.syncRequest( new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { List wsevars = new ArrayList<>(); ChartVariable av = new ChartVariable(graph); for(WorkbenchSelectionElement wse : wses) { Variable v = wse.getContent(av); if(v != null) { wsevars.add(v); } } return toDragItems( graph.syncRequest(VariableReferences.variablesToReferences(model, wsevars)) ); } } ) ); } } } if (items.isEmpty()) { dtde.rejectDrag(); } else { // Accept, make sure it is Link for (IDragItem i : items) dp.add(i); dtde.acceptDrag( DnDConstants.ACTION_LINK ); } } catch (UnsupportedFlavorException e) { throw new RuntimeException(e); } catch (IOException e) { ErrorLogger.defaultLogError(e); dtde.rejectDrag(); } catch (DatabaseException e) { ErrorLogger.defaultLogError(e); dtde.rejectDrag(); } } private void dragEnterPlainText(DropTargetDragEvent dtde, IDnDContext dp) { try { DataFlavor flavor = DataFlavor.getTextPlainUnicodeFlavor(); String flavorCharset = flavor.getParameter("charset"); Transferable t = dtde.getTransferable(); InputStream in = (InputStream) t.getTransferData(flavor); String data = FileUtils.getContents(in, Charset.forName(flavorCharset)); List items = new ArrayList<>(); Session session = Simantics.getSession(); Optional v = JsonUtils.tryParseJsonPropertyVariable(session, data); if (v.isPresent()) { items.addAll( toDragItems( session.syncRequest(VariableReferences.variablesToReferences(model, Collections.singletonList(v.get()))) ) ); } if (items.isEmpty()) { dtde.rejectDrag(); } else { // Accept, make sure it is Link for (IDragItem i : items) dp.add(i); dtde.acceptDrag( DnDConstants.ACTION_LINK ); } } catch (UnsupportedFlavorException e) { throw new RuntimeException(e); } catch (IOException e) { ErrorLogger.defaultLogError(e); dtde.rejectDrag(); } catch (DatabaseException e) { ErrorLogger.defaultLogError(e); dtde.rejectDrag(); } } @Override public void dragExit(DropTargetEvent dte, IDnDContext dp) { for (IDragItem i : dp.getItemsByClass(SubscriptionItemDragItem.class)) dp.remove(i); for (IDragItem i : dp.getItemsByClass(VariableReferenceDragItem.class)) dp.remove(i); } @Override public void dragOver(DropTargetDragEvent dtde, IDnDContext dp) { } @Override public void drop(DropTargetDropEvent dtde, IDnDContext dp) { // Subscription Item Collection subs = dp.getItemsByClass(SubscriptionItemDragItem.class); if (!subs.isEmpty()) { ChartDropActionFactory.addPlots(container, subs.stream().map(DragItem::getObject).collect(Collectors.toList()), Collections.emptySet()).run(); dtde.dropComplete(true); return; } // Variable Reference Collection vrdis = dp.getItemsByClass(VariableReferenceDragItem.class); if (!vrdis.isEmpty()) { try { new AddVariableToChartAction( container, null, vrdis.stream().map(DragItem::getObject).collect(Collectors.toList()) ) .init().run(); dtde.dropComplete(true); } catch (DatabaseException e) { ShowMessage.showError(e.getClass().getName(), e.getMessage()); dtde.dropComplete(true); } return; } dtde.rejectDrop(); } @Override public void dropActionChanged(DropTargetDragEvent dtde, IDnDContext dp) { dtde.acceptDrag( DnDConstants.ACTION_LINK ); } @Override public int getAllowedOps() { return DnDConstants.ACTION_LINK; } private static List toDragItems(Collection references) { return references.stream().map(VariableReferenceDragItem::new).collect(Collectors.toList()); } @Override public double getPriority() { return 10.0; } }