/*******************************************************************************
* Copyright 2013 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.layer.intent;
import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.layers.Layer;
import gov.nasa.worldwind.render.DrawContext;
import java.net.URI;
import java.net.URISyntaxException;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import au.gov.ga.earthsci.common.util.UTF8URLEncoder;
import au.gov.ga.earthsci.common.util.XmlUtil;
import au.gov.ga.earthsci.core.model.ModelStatus;
import au.gov.ga.earthsci.intent.AbstractIntentCallback;
import au.gov.ga.earthsci.intent.IIntentCallback;
import au.gov.ga.earthsci.intent.Intent;
import au.gov.ga.earthsci.intent.IntentManager;
import au.gov.ga.earthsci.intent.dispatch.DispatchFilter;
import au.gov.ga.earthsci.intent.dispatch.Dispatcher;
import au.gov.ga.earthsci.layer.IPersistentLayer;
import au.gov.ga.earthsci.layer.LegacyLayerHelper;
import au.gov.ga.earthsci.layer.Messages;
import au.gov.ga.earthsci.layer.tree.ILayerNode;
import au.gov.ga.earthsci.notification.NotificationCategory;
import au.gov.ga.earthsci.notification.NotificationManager;
/**
* Layer loading helper which uses the Intent system for loading layers from
* files/URIs.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class IntentLayerLoader
{
public final static String LAYER_URI_KEY = "au.gov.ga.earthsci.layer.intent.uri"; //$NON-NLS-1$
private final static Logger logger = LoggerFactory.getLogger(IntentLayerLoader.class);
/**
* Start an Intent to load a layer from a URI, and set the loaded layer on
* the given layer node.
*
* @param uri
* URI to load the layer resource from
* @param layerNode
* Layer node to set the loaded layer on
* @param context
* Eclipse context
*/
public static void load(URI uri, ILayerNode layerNode, IEclipseContext context)
{
if (layerNode.isGrandLayerSet() && !(layerNode.getLayer() instanceof UriStorageLayer))
{
return;
}
LayerLoadIntent intent = new LayerLoadIntent(context, layerNode);
intent.setURI(uri);
intent.setExpectedReturnType(Layer.class);
layerNode.setLoading(true);
IntentManager.getInstance().start(intent, callback, context);
}
/**
* Intent callback for the intent.
*/
protected static IIntentCallback callback = new AbstractIntentCallback()
{
@Override
public void completed(final Object result, Intent intent)
{
final LayerLoadIntent layerIntent = (LayerLoadIntent) intent;
layerIntent.layerNode.setLoading(false);
if (result instanceof Layer)
{
layerIntent.layerNode.setStatus(ModelStatus.ok());
Layer layer = (Layer) result;
layer.setValue(LAYER_URI_KEY, intent.getURI());
IPersistentLayer persistentLayer = LegacyLayerHelper.wrap(layer);
layerIntent.layerNode.setLayer(persistentLayer);
}
else if (result != null)
{
layerIntent.layerNode.removeFromParent();
final DispatchFilter filter = Dispatcher.getInstance().findFilter(result);
if (filter != null)
{
final Shell shell = layerIntent.context.get(Shell.class);
shell.getDisplay().asyncExec(new Runnable()
{
@Override
public void run()
{
if (MessageDialog.openConfirm(shell, Messages.IntentLayerLoader_UnknownLayerTitle,
Messages.bind(Messages.IntentLayerLoader_UnknownLayerMessage, filter.getName())))
{
Dispatcher.getInstance().dispatch(result, layerIntent, layerIntent.context);
}
}
});
}
else
{
error(new Exception("Expected " + Layer.class.getSimpleName() + ", got " //$NON-NLS-1$ //$NON-NLS-2$
+ result.getClass().getSimpleName()), intent);
}
}
else
{
error(new Exception("Intent produced null result"), intent); //$NON-NLS-1$
}
}
@Override
public void error(Exception e, Intent intent)
{
String uriString = intent.getURI() != null ? UTF8URLEncoder.decode(intent.getURI().toString()) : "null"; //$NON-NLS-1$
String title = Messages.IntentLayerLoader_FailedLoadNotificationTitle;
String message =
Messages.IntentLayerLoader_FailedLoadNotificationDescription + uriString
+ ": " + e.getLocalizedMessage(); //$NON-NLS-1$
LayerLoadIntent layerIntent = (LayerLoadIntent) intent;
layerIntent.layerNode.setStatus(ModelStatus.error(message, e));
layerIntent.layerNode.setLoading(false);
if (!layerIntent.layerNode.isLayerSet())
{
layerIntent.layerNode.setLayer(new UriStorageLayer(intent.getURI()));
}
//cannot let this notification require acknowledgement during initial loading (layer unpersistence)
//as it causes the parts to be created incorrectly (bad parent window perhaps?)
NotificationManager.error(title, message, NotificationCategory.FILE_IO, e);
logger.error(message, e);
}
@Override
public void canceled(Intent intent)
{
LayerLoadIntent layerIntent = (LayerLoadIntent) intent;
Exception e = new Exception(Messages.IntentLayerLoader_LoadCanceledDescription);
layerIntent.layerNode.setStatus(ModelStatus.error(e.getLocalizedMessage(), e));
layerIntent.layerNode.setLoading(false);
if (!layerIntent.layerNode.isLayerSet())
{
layerIntent.layerNode.setLayer(new UriStorageLayer(intent.getURI()));
}
}
@Override
public void aborted(Intent intent)
{
LayerLoadIntent layerIntent = (LayerLoadIntent) intent;
layerIntent.layerNode.setLoading(false);
layerIntent.layerNode.removeFromParent();
}
};
/**
* Intent subclass that stores a layer node and Eclipse context.
*/
protected static class LayerLoadIntent extends Intent
{
private final IEclipseContext context;
private final ILayerNode layerNode;
public LayerLoadIntent(IEclipseContext context, ILayerNode layerNode)
{
this.context = context;
this.layerNode = layerNode;
}
}
public static class UriStorageLayer extends AbstractLayer implements IPersistentLayer
{
private URI uri;
private UriStorageLayer()
{
}
private UriStorageLayer(URI uri)
{
this.uri = uri;
}
@Override
public boolean isLoading()
{
return false;
}
@Override
public void save(Element parent)
{
if (uri != null)
{
XmlUtil.setTextElement(parent, "uri", uri.toString()); //$NON-NLS-1$
}
}
@Override
public void load(Element parent)
{
String uriText = XmlUtil.getText(parent, "uri"); //$NON-NLS-1$
if (uriText != null)
{
try
{
uri = new URI(uriText);
}
catch (URISyntaxException e)
{
}
}
}
@Override
public void initialize(ILayerNode node, IEclipseContext context)
{
IntentLayerLoader.load(uri, node, context);
}
@Override
protected void doRender(DrawContext dc)
{
}
}
}