/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.meta.action.impl.handlers; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Properties; import org.jboss.tools.common.meta.XAdoptManager; import org.jboss.tools.common.meta.XAttribute; import org.jboss.tools.common.meta.XChild; import org.jboss.tools.common.meta.XModelEntity; import org.jboss.tools.common.meta.action.XAttributeData; import org.jboss.tools.common.meta.action.XEntityData; import org.jboss.tools.common.meta.action.impl.AbstractHandler; import org.jboss.tools.common.meta.action.impl.SpecialWizardSupport; import org.jboss.tools.common.meta.action.impl.XEntityDataImpl; import org.jboss.tools.common.meta.impl.XMetaDataConstants; import org.jboss.tools.common.meta.impl.XModelMetaDataImpl; import org.jboss.tools.common.model.ServiceDialog; import org.jboss.tools.common.model.XModel; import org.jboss.tools.common.model.XModelBuffer; import org.jboss.tools.common.model.XModelException; import org.jboss.tools.common.model.XModelObjectConstants; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.event.ActionDeclinedException; import org.jboss.tools.common.model.plugin.ModelMessages; import org.jboss.tools.common.model.util.XModelObjectLoaderUtil; public class PasteHandler extends AbstractHandler { /** * When more than one object is pasted and paste of each object * invokes a wizard, to cancel paste of current object and all * subsequent objects, wizard should set this context property * to 'true'. */ public static String IS_CANCELLED = "isCancelled"; //$NON-NLS-1$ public PasteHandler() { data = new XEntityDataImpl[1]; } private static String[] attrs = {"attribute name", XModelObjectConstants.YES, //$NON-NLS-1$ "entity name", XModelObjectConstants.YES, //$NON-NLS-1$ "parameters", XModelObjectConstants.NO}; //$NON-NLS-1$ public XEntityData[] getEntityData(XModelObject object) { return getEntityData(object, 0); } protected XEntityData[] getEntityData(XModelObject object, int bi) { if(getBuffer(object).source(bi) == null) return null; ArrayList<String[]> a = new ArrayList<String[]>(); a.add(new String[]{getEntityName(object, bi), XModelObjectConstants.YES}); String an = getAttributeName(getEntityName(object, bi)); if(an != null) a.add(new String[]{an, XModelObjectConstants.YES}); for (int i = 0; i < attrs.length; i += 2) register(object, attrs[i], attrs[i + 1], a, bi); String[][] ds = new String[a.size()][]; for (int i = 0; i < ds.length; i++) ds[i] = (String[])a.get(i); data[0] = XEntityDataImpl.create(ds); setDefaultData(object, bi); return data; } private void register(XModelObject o, String attr, String mandatory, ArrayList<String[]> list, int bi) { if(hasAttribute(o.getModel(), attr, bi)) list.add(new String[]{attr, mandatory}); } public void executeHandler(XModelObject object, Properties prop) throws XModelException { if(!isEnabled(object)) return; boolean isDrop = (prop != null) && XModelObjectConstants.TRUE.equals(prop.getProperty("isDrop")); //$NON-NLS-1$ int bs = object.getModel().getModelBuffer().getSize(); for (int i = 0; i < bs; i++) { execute(object, i, isDrop, prop); if(prop != null && XModelObjectConstants.TRUE.equals(prop.getProperty(IS_CANCELLED))) return; } } protected void execute(XModelObject parent, int sourceIndex, boolean isDrop, Properties p) throws XModelException { XModelBuffer buffer = getBuffer(parent); boolean isParent = isParent(parent, buffer.copy(sourceIndex)); if(isParent) { if(!prepaste(parent, sourceIndex)) return; if(!isDrop) paste(parent, sourceIndex, p); else pasteOnDrop(parent, sourceIndex, p); } else { drop(parent, buffer.source(sourceIndex), p); } } protected final void paste(XModelObject parent, int sourceIndex, Properties p) throws XModelException { XModelObject source = getBuffer(parent).source(sourceIndex); XModelObject copy = getBuffer(parent).copy(sourceIndex); XModelObject existing = parent.getChildByPath(copy.getPathPart()); if(existing != null) { XChild c = parent.getModelEntity().getChild(existing.getModelEntity().getName()); if(c != null && c.isRequired() && c.getMaxCount() == 1) return; } String found = (existing == null) ? null : copy.getModelEntity().getRenderer().getTitle(copy); String entity = getEntityName(parent, sourceIndex); getEntityData(parent, sourceIndex); XAttributeData[] ad = ((XEntityData[])data)[0].getAttributeData(); boolean mustGenerate = (found != null && mustGenerate(entity)); if(!mustGenerate) { int i = (found == null) ? 0 : PasteEnterNewNameSupport.run(parent, source, copy, data[0]); if(i != 0) throw new ActionDeclinedException("Paste declined."); } for (int j = 0; j < ad.length; j++) copy.setAttributeValue(ad[j].getAttribute().getName(), ad[j].getValue()); if(!mustGenerate) { String an = getAttributeName(getEntityName(parent, sourceIndex)); XAttributeData a = (an == null) ? null : HUtil.find(data, 0, an); if(a != null) copy.setAttributeValue(an, a.getValue()); } else { generate(parent, copy, getAttributeName(entity)); } copy = modify(copy.copy()); DefaultCreateHandler.addCreatedObject(parent, copy, p); if(copy.isActive()) onChildPasted(copy); } private boolean prepaste(XModelObject parent, int sourceIndex) { XModelObject source = parent.getModel().getModelBuffer().source(sourceIndex); String entity = source.getModelEntity().getName(); XChild c = parent.getModelEntity().getChild(entity); if(c == null || c.getMaxCount() > 1) return true; XModelObject co = parent.getChildByPath(source.getPathPart()); if(co == null) return true; if(co == source) { if(sourceIndex == 0) showUniqueMessae(parent, source); return false; } String n = "<" + co.getModelEntity().getXMLSubPath() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ String message = MessageFormat.format("Replace existing element {0}?", n); ServiceDialog d = parent.getModel().getService(); int q = d.showDialog("Paste", message, new String[]{ModelMessages.OK, ModelMessages.Cancel}, null, ServiceDialog.QUESTION); if(q != 0) return false; DefaultRemoveHandler.removeFromParent(co); return true; } private void showUniqueMessae(XModelObject parent, XModelObject source) { ServiceDialog d = parent.getModel().getService(); String message = MessageFormat.format( "{0} may have only one {1}. You cannot add its copy.", DefaultCreateHandler.title(parent, true), source.getAttributeValue(XModelObjectConstants.ATTR_ELEMENT_TYPE)); d.showDialog(ModelMessages.WARNING, message, new String[]{SpecialWizardSupport.OK}, null, ServiceDialog.WARNING); } protected void onChildPasted(XModelObject child) {} protected void pasteOnDrop(XModelObject parent, int sourceIndex, Properties p) throws XModelException { paste(parent, sourceIndex, p); } protected final void drop(XModelObject parent, XModelObject source, Properties p) throws XModelException { XAdoptManager am = parent.getModelEntity().getAdoptManager(); if(am != null) am.adopt(parent, source, p); } protected XModelObject modify(XModelObject c) { return c; } public boolean isEnabled(XModelObject object) { XModelBuffer buffer = object.getModel().getModelBuffer(); int bs = buffer.getSize(); if(bs == 0 || object == null || !object.isObjectEditable()) return false; for (int i = 0; i < bs; i++) { XModelObject s = buffer.source(i); boolean b = (s != null && (isParent(object, s) || canAdopt(object, s))); if(!b) return false; } return true; } protected boolean isParent(XModelObject p, XModelObject c) { c = c.copy(true, 0); return (c != null) && (p.getModelEntity().getChild(c.getModelEntity().getName()) != null); } protected boolean canAdopt(XModelObject target, XModelObject bullet) { XAdoptManager am = target.getModelEntity().getAdoptManager(); return (am != null && am.isAdoptable(target, bullet)); } protected String getEntityName(XModelObject object, int i) { String entity = action.getProperty(XMetaDataConstants.ENTITY); if(entity != null) return entity; return getBuffer(object).source(i).getModelEntity().getName(); } protected String getAttributeName(String entity) { XModelEntity e = XModelMetaDataImpl.getInstance().getEntity(entity); if(e.getAttribute(XModelObjectLoaderUtil.ATTR_ID_NAME) != null) return XModelObjectLoaderUtil.ATTR_ID_NAME; XAttribute[] as = e.getAttributes(); for (int i = 0; i < as.length; i++) if(XModelObjectConstants.TRUE.equals(as[i].getProperty("id"))) return as[i].getName(); //$NON-NLS-1$ if(e.getAttribute(XModelObjectConstants.ATTR_NAME) != null) return XModelObjectConstants.ATTR_NAME; return null; } protected boolean mustGenerate(String entity) { XModelEntity e = XModelMetaDataImpl.getInstance().getEntity(entity); if(e.getAttribute(XModelObjectLoaderUtil.ATTR_ID_NAME) != null) return true; XAttribute[] as = e.getAttributes(); for (int i = 0; i < as.length; i++) if(XModelObjectConstants.TRUE.equals(as[i].getProperty("id")) && //$NON-NLS-1$ XModelObjectConstants.TRUE.equals(as[i].getProperty("generate"))) return true; //$NON-NLS-1$ return false; } protected int generate(XModelObject parent, XModelObject copy, String attr) { String v = copy.getAttributeValue(attr); while(v.length() > 0 && Character.isDigit(v.charAt(v.length() - 1))) v = v.substring(0, v.length() - 1); int k = 1; String pp = copy.getPathPart(); while(parent.getChildByPath(pp) != null) { copy.setAttributeValue(attr, v + k); String ppn = copy.getPathPart(); /// if(ppn.equals(pp)) return 0; pp = ppn; ++k; } return 0; } protected boolean hasAttribute(XModel model, String attr, int bi) { return model.getMetaData().getEntity(getEntityName(model.getRoot(), bi)).getAttribute(attr) != null; } public void setDefaultData(XModelObject object) { setDefaultData(object, 0); } public void setDefaultData(XModelObject object, int bi) { if(!isEnabled(object)) return; XModelObject c = getBuffer(object).copy(bi); XAttributeData[] ad = ((XEntityData[])data)[0].getAttributeData(); for (int i = 0; i < ad.length; i++) ad[i].setValue(c.getAttributeValue(ad[i].getAttribute().getName())); } public void setData(XEntityData[] data) {} private XModelBuffer getBuffer(XModelObject o) { return o.getModel().getModelBuffer(); } public boolean isEnabled(XModelObject object, XModelObject[] objects) { return (objects == null || objects.length == 1) && isEnabled(object); } }