blob: 36eabcf59473e408f5031f937b0a1b5dad82b322 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2012 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.ui.internal.commands;
import java.util.Map;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jpt.common.core.internal.utility.PlatformTools;
import org.eclipse.jpt.common.ui.internal.util.SWTUtil;
import org.eclipse.jpt.common.utility.internal.RunnableAdapter;
import org.eclipse.jpt.jpa.core.context.PersistentAttribute;
import org.eclipse.jpt.jpa.ui.selection.JpaSelectionManager;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.menus.UIElement;
import org.eclipse.ui.services.IEvaluationService;
/**
* This handler changes the mapping type of the selected
* {@link PersistentAttribute}(s).
* It will be invoked by the mapping action dynamically created by the
* {@link org.eclipse.jpt.jpa.ui.internal.menus.PersistentAttributeMapAsContribution}.
* <p>
* See <code>org.eclipse.jpt.jpa.ui/plugin.xml</code>.
*
* @see org.eclipse.jpt.jpa.ui.internal.menus.PersistentAttributeMapAsContribution
* @see PersistentAttribute
* @version 2.0
* @since 2.0
*/
@SuppressWarnings("nls")
public class PersistentAttributeMapAsHandler
extends AbstractHandler
implements IElementUpdater
{
/**
* The unique identifier of the "Map As" command used for
* {@link PersistentAttribute}(s).
* <p>
* See <code>org.eclipse.jpt.jpa.ui/plugin.xml</code>.
*/
public static final String COMMAND_ID = "org.eclipse.jpt.jpa.ui.persistentAttributeMapAs";
/**
* The unique identifier of the "Map As" command parameter used for
* {@link PersistentAttribute}(s).
* <p>
* See <code>org.eclipse.jpt.jpa.ui/plugin.xml</code>.
*/
public static final String SPECIFIED_MAPPING_COMMAND_PARAMETER_ID = "specifiedPersistentAttributeMappingKey";
public static final String DEFAULT_MAPPING_COMMAND_PARAMETER_ID = "defaultPersistentAttributeMappingKey";
/**
* Default constructor.
*/
public PersistentAttributeMapAsHandler() {
super();
}
public Object execute(ExecutionEvent event) throws ExecutionException {
IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
String mappingKey = event.getParameter(SPECIFIED_MAPPING_COMMAND_PARAMETER_ID);
final Object[] items = selection.toArray();
for (Object item : items) {
PersistentAttribute attribute = (PersistentAttribute) item;
attribute.setMappingKey(mappingKey);
}
this.setJpaSelection(items);
return null;
}
/**
* When we are changing an attribute mapping in the <code>orm.xml</code>
* file (by calling {@link PersistentAttribute#setMappingKey(String)},
* the following happens synchronously during the call:<ul>
* <li>The mapping (persistent attribute) is removed from the XML file.
* <li>The cursor moves to the empty position where the mapping used to be,
* between the remaining, surrounding mappings, effectively changing the
* JPA selection to the persistent type that contained the selected
* persistent attribute.
* <li>The new mapping (persistent attribute) is added to the XML file in
* the appropriate position, usually not at the same location as the old
* mapping.
* </ul>
* At this point, the JPA selection is still the selected persistent
* attribute; but a text editor event has been fired (with a half-second
* delay - see
* {@link org.eclipse.jface.text.TextViewer#queuePostSelectionChanged(boolean)})
* that will change the JPA selection to the persistent type that contains
* the selected persistent attribute (as calculated from the current cursor
* position). We short-circuit this event by setting the JPA selection to
* <code>null</code> and back to the selected persistent attribute. We set
* the JPA selection to <code>null</code> and back because we
* must <em>change</em> the JPA selection (as opposed to simply re-setting
* it to the same persistent attribute) or no change event will be fired
* (since nothing changed). This double change should be invisible to the
* user....
*/
private void setJpaSelection(Object[] items) {
if (items.length == 1) {
new PostExecutionJob((PersistentAttribute) items[0]).schedule();
}
}
/**
* This job will not run until any outstanding updates etc. are complete.
* As a result, the runnable dispatched to the UI thread will not run
* until the previously scheduled UI runnables are complete also (e.g. the
* events triggered by the aforementioned updates etc.).
*/
/* CU private */ static class PostExecutionJob
extends Job
{
private final Runnable setSelectionRunnable;
PostExecutionJob(PersistentAttribute attribute) {
super("select attribute");
this.setSelectionRunnable = new SetSelectionRunnable(attribute);
this.setRule(attribute.getJpaProject().getProject());
}
@Override
protected IStatus run(IProgressMonitor monitor) {
SWTUtil.execute(this.setSelectionRunnable);
return Status.OK_STATUS;
}
/* class private */ static class SetSelectionRunnable
extends RunnableAdapter
{
private final PersistentAttribute attribute;
SetSelectionRunnable(PersistentAttribute attribute) {
super();
this.attribute = attribute;
}
@Override
public void run() {
JpaSelectionManager mgr = PlatformTools.getAdapter(PlatformUI.getWorkbench(), JpaSelectionManager.class);
mgr.setSelection(null);
mgr.setSelection(attribute);
}
}
}
public void updateElement(UIElement element, @SuppressWarnings("rawtypes") Map parameters) {
// Retrieve the selection for the UIElement
// Due to Bug 226746, we have to use API workaround to retrieve current
// selection
IEvaluationService es
= (IEvaluationService) element.getServiceLocator().getService(IEvaluationService.class);
IViewPart part =
(IViewPart) es.getCurrentState().getVariable(ISources.ACTIVE_PART_NAME);
IStructuredSelection selection
= (IStructuredSelection) part.getSite().getSelectionProvider().getSelection();
element.setChecked(this.selectedElementsMappingKeysMatch(selection, parameters));
}
//Check all the selected persistent attribute and verify that they have the same mapping type.
//They must all be either default mappings or specified mappings as well.
protected boolean selectedElementsMappingKeysMatch(IStructuredSelection selection, @SuppressWarnings("rawtypes") Map parameters) {
String handlerSpecifiedMappingKey = (String) parameters.get(SPECIFIED_MAPPING_COMMAND_PARAMETER_ID);
String handlerDefaultMappingKey = (String) parameters.get(DEFAULT_MAPPING_COMMAND_PARAMETER_ID);
String commonDefaultKey = null;
String commonSpecifiedKey = null;
for (Object obj : selection.toArray()) {
if (! (obj instanceof PersistentAttribute)) {
//oddly enough, you have to check instanceof here, seems like a bug in the framework
return false;
}
PersistentAttribute persistentAttribute = (PersistentAttribute) obj;
if (persistentAttribute.getMapping().isDefault()) {
if (commonSpecifiedKey != null) {
return false;
}
if (commonDefaultKey == null) {
commonDefaultKey = persistentAttribute.getMappingKey();
}
else if (!commonDefaultKey.equals(persistentAttribute.getMappingKey())) {
return false;
}
}
else {
if (commonDefaultKey != null) {
return false;
}
if (commonSpecifiedKey == null) {
commonSpecifiedKey = persistentAttribute.getMappingKey();
}
else if (!commonSpecifiedKey.equals(persistentAttribute.getMappingKey())) {
return false;
}
}
}
if (handlerSpecifiedMappingKey != null) {
return handlerSpecifiedMappingKey.equals(commonSpecifiedKey);
}
else if (handlerDefaultMappingKey != null) {
return handlerDefaultMappingKey.equals(commonDefaultKey);
}
return false;
}
}