/*******************************************************************************
* Copyright (c) 2008, 2012 Obeo.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.eef.runtime.impl.components;
import java.util.ArrayList;
import java.util.List;
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.emf.common.notify.Notification;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.change.util.ChangeRecorder;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent;
import org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionEvent;
import org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionListener;
import org.eclipse.emf.eef.runtime.api.notify.NotificationFilter;
import org.eclipse.emf.eef.runtime.api.notify.PropertiesEditingSemanticListener;
import org.eclipse.emf.eef.runtime.api.parts.IPropertiesEditionPart;
import org.eclipse.emf.eef.runtime.context.PropertiesEditingContext;
import org.eclipse.emf.eef.runtime.context.impl.EObjectPropertiesEditionContext;
import org.eclipse.emf.eef.runtime.impl.command.StandardEditingCommand;
import org.eclipse.emf.eef.runtime.impl.notify.PropertiesEditionEvent;
import org.eclipse.emf.eef.runtime.impl.notify.PropertiesValidationEditionEvent;
import org.eclipse.emf.eef.runtime.impl.utils.StringTools;
/**
* @author <a href="mailto:goulwen.lefur@obeo.fr">Goulwen Le Fur</a>
* @author <a href="mailto:mikael.barbero@obeo.fr">Mikaƫl Barbero</a>
*/
public abstract class StandardPropertiesEditionComponent implements IPropertiesEditionComponent {
private static final long DELAY = 500L;
public static final Object FIRE_PROPERTIES_CHANGED_JOB_FAMILY = new Object();
/**
* List of IPropertiesEditionComponentListeners
*/
private List<IPropertiesEditionListener> listeners;
/**
* the semantic listener dedicated to update view
*/
protected PropertiesEditingSemanticListener semanticAdapter;
/**
* the editing domain where to perform live update
*/
protected EditingDomain liveEditingDomain;
/**
* the job that will fire the property changed event
*/
protected FirePropertiesChangedJob firePropertiesChangedJob;
/**
* Editing context
*/
protected PropertiesEditingContext editingContext;
/**
* the editing mode
*/
protected String editing_mode;
/**
* Is the component is current initializing
*/
protected boolean initializing = false;
/**
* List of {@link IPropertiesEditionPart}'s key managed by the component.
*/
protected String[] parts;
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#initPart(java.lang.Object,
* int, org.eclipse.emf.ecore.EObject)
*/
public void initPart(Object key, int kind, EObject element) {
this.initPart(key, kind, element, editingContext.getResourceSet());
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#partsList()
*/
public String[] partsList() {
return parts;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#addListener(org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionListener)
*/
public void addListener(IPropertiesEditionListener listener) {
if (listeners == null)
listeners = new ArrayList<IPropertiesEditionListener>();
listeners.add(listener);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#removeListener(org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionListener)
*/
public void removeListener(IPropertiesEditionListener listener) {
if (listeners != null)
listeners.remove(listener);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#setLiveEditingDomain(org.eclipse.emf.edit.domain.EditingDomain)
*/
public void setLiveEditingDomain(EditingDomain editingDomain) {
this.liveEditingDomain = editingDomain;
}
/**
* Initialize the semantic model listener for live editing mode
*
* @return the semantic model listener
*/
protected PropertiesEditingSemanticListener initializeSemanticAdapter() {
PropertiesEditingSemanticListener listener = new PropertiesEditingSemanticListener(
this, getNotificationFilters()) {
@Override
public void runUpdateRunnable(Notification notification) {
if (getPart() != null && getPart().getFigure() != null
&& !getPart().getFigure().isDisposed()) {
updatePart(notification);
} else {
dispose();
}
}
};
return listener;
}
/**
* Returns the list of notification filters to use.
*
* @return the list of notification filters to use
*/
protected abstract NotificationFilter[] getNotificationFilters();
/**
* Update the part in response to a semantic event
*
* @param msg
* the semantic event
*/
public abstract void updatePart(Notification msg);
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionListener#firePropertiesChanged(org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionEvent)
*/
private void propagateEvent(IPropertiesEditionEvent event) {
event.addHolder(this);
for (IPropertiesEditionListener listener : listeners) {
if (!event.hold(listener))
listener.firePropertiesChanged(event);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionListener#firePropertiesChanged(org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionEvent)
*/
public void firePropertiesChanged(final IPropertiesEditionEvent event) {
if (!isInitializing() && shouldProcess(event)) {
Diagnostic valueDiagnostic = validateValue(event);
if (valueDiagnostic.getSeverity() != Diagnostic.OK && valueDiagnostic instanceof BasicDiagnostic)
propagateEvent(new PropertiesValidationEditionEvent(event, valueDiagnostic));
else {
editingContext.initializeRecorder();
if (IPropertiesEditionComponent.BATCH_MODE.equals(editing_mode)) {
updateSemanticModel(event);
} else if (IPropertiesEditionComponent.LIVE_MODE.equals(editing_mode)) {
switch (event.getKind()) {
case PropertiesEditionEvent.ADD:
case PropertiesEditionEvent.CHANGE:
case PropertiesEditionEvent.EDIT:
case PropertiesEditionEvent.REMOVE:
case PropertiesEditionEvent.MOVE:
case PropertiesEditionEvent.SET:
liveEditingDomain.getCommandStack().execute(
new StandardEditingCommand(new EObjectPropertiesEditionContext(editingContext,
this, editingContext.getEObject(), editingContext.getAdapterFactory())) {
public void execute() {
updateSemanticModel(event);
ChangeRecorder changeRecorder = editingContext.getChangeRecorder();
if (changeRecorder != null) {
description = changeRecorder.endRecording();
editingContext.disposeRecorder();
}
}
});
default:
break;
}
}
Diagnostic validate = validate();
propagateEvent(new PropertiesValidationEditionEvent(event, validate));
}
propagateEvent(event);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionListener#lazyFirePropertiesChanged(org.eclipse.emf.eef.runtime.api.notify.IPropertiesEditionEvent)
*/
public void delayedFirePropertiesChanged(IPropertiesEditionEvent event) {
if (IPropertiesEditionComponent.BATCH_MODE.equals(editing_mode)) {
firePropertiesChanged(event);
} else if (IPropertiesEditionComponent.LIVE_MODE.equals(editing_mode)) {
if (getFirePropertiesChangedJob().cancel()) {
getFirePropertiesChangedJob().setEvent(event);
getFirePropertiesChangedJob().schedule(DELAY);
} else {
try {
getFirePropertiesChangedJob().join();
getFirePropertiesChangedJob().setEvent(event);
getFirePropertiesChangedJob().schedule();
} catch (InterruptedException e) {
getFirePropertiesChangedJob().setEvent(null);
}
}
}
}
protected FirePropertiesChangedJob getFirePropertiesChangedJob() {
if (firePropertiesChangedJob == null) {
firePropertiesChangedJob = new FirePropertiesChangedJob("Fire properties changed...");
}
return firePropertiesChangedJob;
}
protected class FirePropertiesChangedJob extends Job {
private IPropertiesEditionEvent fEvent;
public FirePropertiesChangedJob(String name) {
super(name);
}
@Override
public boolean belongsTo(Object family) {
return family == FIRE_PROPERTIES_CHANGED_JOB_FAMILY;
}
@Override
public boolean shouldSchedule() {
return fEvent != null;
}
@Override
public boolean shouldRun() {
return fEvent != null;
}
@Override
protected void canceling() {
super.canceling();
fEvent = null;
}
public void setEvent(IPropertiesEditionEvent event) {
fEvent = event;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
deactivate();
firePropertiesChanged(fEvent);
activate();
fEvent = null;
return Status.OK_STATUS;
}
}
/**
* @param event
* event to process
* @return <code>true</code> if the event should really launch a command.
* @since 0.9
*/
protected boolean shouldProcess(IPropertiesEditionEvent event) {
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#associatedFeature(Object)
*/
public EStructuralFeature associatedFeature(Object editorKey) {
return null;
}
/**
* Update the model in response to a view event
*
* @param event
* the view event
*/
public abstract void updateSemanticModel(IPropertiesEditionEvent event);
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#mustBeComposed(java.lang.Object,
* int)
*/
public boolean mustBeComposed(Object key, int kind) {
return true;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#isRequired(java.lang.String,
* int)
*/
public boolean isRequired(Object key, int kind) {
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#getHelpContent(java.lang.String,
* int)
*/
public String getHelpContent(Object key, int kind) {
return StringTools.EMPTY_STRING;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#translatePart(java.lang.String)
*/
public Object translatePart(String key) {
return null;
}
/**
* @return the initializing
*/
public boolean isInitializing() {
return initializing;
}
/**
* @param initializing
* the initializing to set
*/
public void setInitializing(boolean initializing) {
this.initializing = initializing;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.eef.runtime.api.component.IPropertiesEditionComponent#setPropertiesEditionPart(java.lang.Object,
* int, org.eclipse.emf.eef.runtime.api.parts.IPropertiesEditionPart)
*/
public void setPropertiesEditionPart(Object key, int kind, IPropertiesEditionPart propertiesEditionPart) {
// Default case : nothing to do
}
}