/******************************************************************************* * Copyright (c) 2006-2013 The RCP Company and others. * 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: * The RCP Company - initial API and implementation *******************************************************************************/ package com.rcpcompany.uibindings.internal.handlers; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.IHandler; import org.eclipse.core.databinding.observable.IObserving; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.emf.common.command.CommandStack; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.graphics.Point; import org.eclipse.ui.handlers.HandlerUtil; import com.rcpcompany.uibindings.Constants; import com.rcpcompany.uibindings.IBindingContext; import com.rcpcompany.uibindings.IBindingContext.FinishOption; import com.rcpcompany.uibindings.IChildCreationSpecification; import com.rcpcompany.uibindings.IManager; import com.rcpcompany.uibindings.IUIAttribute; import com.rcpcompany.uibindings.IUIBindingsPackage; import com.rcpcompany.uibindings.IValueBinding; import com.rcpcompany.uibindings.IValueBindingCell; import com.rcpcompany.uibindings.IViewerBinding; import com.rcpcompany.uibindings.internal.Activator; import com.rcpcompany.uibindings.model.utils.ICommandStackWithCollect; import com.rcpcompany.uibindings.participants.ISuperCreateParticipant; import com.rcpcompany.uibindings.participants.ISuperCreateParticipantContext; import com.rcpcompany.uibindings.uiAttributes.SimpleUIAttribute; import com.rcpcompany.uibindings.utils.IBindingHighlightContext; import com.rcpcompany.uibindings.utils.IBindingHighlightContext.STAGE; import com.rcpcompany.uibindings.utils.IClipboardConverterManager; import com.rcpcompany.uibindings.utils.IClipboardConverterManager.IResult; import com.rcpcompany.utils.logging.LogUtils; /** * Handler for <code>com.rcpcompany.uibindings.commands.SuperCreate</code> for within * {@link IViewerBinding}... * * @author Tonny Madsen, The RCP Company */ public class ViewerSuperCreateHandler extends AbstractHandler implements IHandler { @Override public Object execute(ExecutionEvent event) { if (Activator.getDefault().TRACE_HANDLERS) { LogUtils.debug(this, ""); } final Object bb = HandlerUtil.getVariable(event, Constants.SOURCES_ACTIVE_CONTAINER_BINDING); if (!(bb instanceof IViewerBinding)) return null; final IViewerBinding container = (IViewerBinding) bb; final IBindingContext context = container.getContext(); final IValueBinding binding = (IValueBinding) HandlerUtil.getVariable(event, Constants.SOURCES_ACTIVE_BINDING); if (binding == null) return null; final List<IResult> conversions = IClipboardConverterManager.Factory.getManager().getClipboardConversions(); if (conversions.size() == 0) { MessageDialog.openError(HandlerUtil.getActiveShell(event), "Cannot create data", "Data format of the created data is not supported"); return null; } /* * Just select the first */ final IResult result = conversions.get(0); final int rows = result.getRows(); final int columns = result.getColumns(); final String[][] table = result.getTable(); /* * Check that we have room for the create... */ final Point p = binding.getCell().getPosition(true); if (p == null) { MessageDialog.openError(HandlerUtil.getActiveShell(event), "Cannot create data", "Can only create into a viewer"); return null; } /* * Create the needed rows in the viewer */ final ISuperCreateParticipantContext pcontext = new ISuperCreateParticipantContext() { @Override public IViewerBinding getViewer() { return container; } @Override public EReference getReference() { final IObservableList l = getViewer().getList(); if (l.getElementType() instanceof EReference) return (EReference) l.getElementType(); return null; } @Override public EObject getParent() { final IObservableList l = getViewer().getList(); if (l instanceof IObserving) return (EObject) ((IObserving) l).getObserved(); return null; } @Override public EObject getElement() { final Point position = getPosition(); if (position == null) return null; final IObservableList list = getViewer().getList(); if (position.y >= list.size()) return null; return (EObject) list.get(position.y); } private final Point myP = new Point(p.x, p.y); @Override public Point getPosition() { return myP; } @Override public EditingDomain getEditingDomain() { return context.getEditingDomain(); } @Override public IResult getClipboardContent() { return result; } }; final ISuperCreateParticipant participant = container.getArgument(Constants.ARG_SUPER_CREATE_PARTICIPANT, ISuperCreateParticipant.class, myDefaultParticipant); final IBindingHighlightContext successHighlightContext = IBindingHighlightContext.Factory.createContext(); final Map<IValueBinding, String> assignmentMap = new HashMap<IValueBinding, String>(); final CommandStack commandStack = IManager.Factory.getManager().getEditingDomain().getCommandStack(); try { if (commandStack instanceof ICommandStackWithCollect) { ((ICommandStackWithCollect) commandStack).setCollectCommandMode(true); } boolean success = false; try { success = participant.createNeededRows(pcontext); } catch (final Exception ex) { LogUtils.error(participant, ex); } if (!success) { MessageDialog.openError(HandlerUtil.getActiveShell(event), "Cannot create data", "Can not create rows"); return null; } for (int r = 0; r < rows; r++) { /* * The index of the column to copy into - needed as some columns can be zero width * and must be ignored */ int ci = p.x; for (int c = 0; c < columns; c++) { final String data = table[r][c]; IValueBindingCell cell; do { cell = container.getCell(ci, p.y + r, true); if (cell == null) { MessageDialog.openError(HandlerUtil.getActiveShell(event), "Cannot create data", "No room for data"); return null; } ci++; } while (cell.getColumnBinding() != null && cell.getColumnBinding().getColumnAdapter().getWidth() == 0); final IValueBinding b = cell.getLabelBinding(); if (!b.isChangeable()) { cell.setFocus(); MessageDialog.openError(HandlerUtil.getActiveShell(event), "Cannot create data", "Target cell is not changeable"); return null; } successHighlightContext.add(b); /* * Make a new create binding and add this to the assignmentMap... */ final WritableValue ov = new WritableValue("", String.class); final IUIAttribute attribute = new SimpleUIAttribute(null, "", ov, true); // TODO: Why are we sure about this being a value? final IValueBinding createBinding = context.addBinding().model(b.getModelObservableValue()) .ui(attribute); if (b.hasArguments()) { createBinding.getExtraArgumentProviders().add(b); } if (b.getParentBinding() != null) { createBinding.getExtraArgumentProviders().add(b.getParentBinding()); } if (b.eIsSet(IUIBindingsPackage.Literals.BINDING__EXTRA_ARGUMENT_PROVIDERS)) { createBinding.getExtraArgumentProviders().addAll(b.getExtraArgumentProviders()); } createBinding.setCell(cell); assignmentMap.put(createBinding, data); } } /* * Assign all values */ context.finish(FinishOption.FORCE); for (final Entry<IValueBinding, String> d : assignmentMap.entrySet()) { final IValueBinding b = d.getKey(); final String value = d.getValue(); b.getUIAttribute().getCurrentValue().setValue(value); /* * Check for errors in the binding */ final List<String> errors = b.getErrors(); if (errors != null && errors.size() > 0) { b.getCell().setFocus(); // TODO Should concat to get all errors // TODO highlight error bindings /* * Not really correct... Will allow the first set of changes... */ MessageDialog.openError(HandlerUtil.getActiveShell(event), "Cannot paste data", "Setting value '" + value + "' : " + errors.get(0)); return null; } } successHighlightContext.activate(); } finally { if (commandStack instanceof ICommandStackWithCollect) { ((ICommandStackWithCollect) commandStack).setCollectCommandMode(false); } /* * If we did not succeed, the dispose the highlight context... */ if (successHighlightContext.getStage() == STAGE.INIT) { successHighlightContext.dispose(); } /* * Dispose all the created bindings */ for (final Entry<IValueBinding, String> d : assignmentMap.entrySet()) { d.getKey().dispose(); } } return null; } /** * The default {@link ISuperCreateParticipant} based on new information... */ private static ISuperCreateParticipant myDefaultParticipant = new ISuperCreateParticipant() { @Override public boolean createNeededRows(ISuperCreateParticipantContext context) { final List<IChildCreationSpecification> specs = context.getViewer().getPossibleChildObjects(null, null); if (specs == null || specs.size() != 1) { LogUtils.debug(this, "Cannot creete rows. Specs=" + specs); return false; } final IChildCreationSpecification s = specs.get(0); final List<EObject> rows = new ArrayList<EObject>(); final EditingDomain ed = context.getEditingDomain(); final CompoundCommand cc = new CompoundCommand(); for (int r = 0; r < context.getClipboardContent().getRows(); r++) { /* * Create a new row */ final EObject row = EcoreUtil.create(s.getChildType()); /* * Initialize the row */ cc.append(IManager.Factory.getManager().initializeObject(context.getEditingDomain(), s.getParent(), s.getReference(), row, false)); rows.add(row); } /* * Add the created rows to the list */ cc.append(AddCommand.create(ed, context.getParent(), context.getReference(), rows, context.getPosition().y)); /* * Execute the created command */ ed.getCommandStack().execute(cc); return true; } }; }