diff --git a/plugins/org.locationtech.udig.core.tests/META-INF/MANIFEST.MF b/plugins/org.locationtech.udig.core.tests/META-INF/MANIFEST.MF index fdf561a34d..d45d81f3bb 100644 --- a/plugins/org.locationtech.udig.core.tests/META-INF/MANIFEST.MF +++ b/plugins/org.locationtech.udig.core.tests/META-INF/MANIFEST.MF @@ -6,8 +6,12 @@ Bundle-Version: 2.3.0.qualifier Bundle-Vendor: udig.refractions.net Eclipse-BuddyPolicy: ext Require-Bundle: org.eclipse.core.runtime, - org.junit, - org.locationtech.udig.libs + org.junit;bundle-version="4.12.0", + org.locationtech.udig.libs, + org.mockito;bundle-version="2.23.0", + org.objenesis;bundle-version="2.6.0", + net.bytebuddy.byte-buddy;bundle-version="1.9.0", + net.bytebuddy.byte-buddy-agent;bundle-version="1.9.0" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Fragment-Host: org.locationtech.udig.core diff --git a/plugins/org.locationtech.udig.core.tests/build.properties b/plugins/org.locationtech.udig.core.tests/build.properties index 868644f3a3..735bfbe639 100644 --- a/plugins/org.locationtech.udig.core.tests/build.properties +++ b/plugins/org.locationtech.udig.core.tests/build.properties @@ -5,5 +5,6 @@ bin.includes = META-INF/,\ .,\ bsd3-v10.html,\ epl-v10.html,\ - about.html + about.html,\ + src/mockito-extensions/ src.includes = LICENSE.txt diff --git a/plugins/org.locationtech.udig.core.tests/src/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/org.locationtech.udig.core.tests/src/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..ca6ee9cea8 --- /dev/null +++ b/plugins/org.locationtech.udig.core.tests/src/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file diff --git a/plugins/org.locationtech.udig.core.tests/src/org/locationtech/udig/core/logging/LoggingSupportTest.java b/plugins/org.locationtech.udig.core.tests/src/org/locationtech/udig/core/logging/LoggingSupportTest.java new file mode 100644 index 0000000000..40bb1bb2eb --- /dev/null +++ b/plugins/org.locationtech.udig.core.tests/src/org/locationtech/udig/core/logging/LoggingSupportTest.java @@ -0,0 +1,107 @@ +/** + * uDig - User Friendly Desktop Internet GIS client + * https://locationtech.org/projects/technology.udig + * (C) 2021, Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution + * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). + */ +package org.locationtech.udig.core.logging; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Plugin; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.osgi.framework.Bundle; + +@RunWith(MockitoJUnitRunner.class) +public class LoggingSupportTest { + + private static final String BUNDLE_NAME = "test.bundle"; + + @Mock + Plugin plugin; + + @Mock + ILog log; + + @Mock + Bundle bundle; + + @Captor + ArgumentCaptor statusCapture; + + @Before + public void setUp() { + when(plugin.getLog()).thenReturn(log); + when(plugin.getBundle()).thenReturn(bundle); + when(bundle.getSymbolicName()).thenReturn(BUNDLE_NAME); + } + + @Test + public void logErrorSeverityWhileExceptionIsGiven() { + LoggingSupport.log(plugin, "whatever", new Exception("expect error test")); + + verify(log).log(statusCapture.capture()); + assertEquals(IStatus.ERROR, statusCapture.getValue().getSeverity()); + } + + @Test + public void logWarningSeverityWhileThrowableIsGiven() { + String errorMessage = "ErrorMessage 1"; + LoggingSupport.log(plugin, errorMessage, new Throwable("expect error test")); + + verify(log).log(statusCapture.capture()); + assertStatus(IStatus.WARNING, errorMessage, BUNDLE_NAME, statusCapture.getValue()); + } + + @Test + public void logInfoSeverityWithNullThrowableIsGiven() { + String errorMessage = "ErrorMessage 1"; + LoggingSupport.log(plugin, errorMessage, null); + + verify(log).log(statusCapture.capture()); + assertStatus(IStatus.INFO, errorMessage, BUNDLE_NAME, statusCapture.getValue()); + } + + @Test + public void logWithNullMessage() { + LoggingSupport.log(plugin, null, new Exception("expect error test")); + + verify(log).log(statusCapture.capture()); + assertStatus(IStatus.ERROR, "", "test.bundle", statusCapture.getValue()); + } + + @Test + public void doNotLogAnythingNullMessageAndNullThrowable() { + LoggingSupport.log(plugin, null, null); + verifyNoMoreInteractions(log); + } + + @Test + public void doNotLogAnythingEmptyMessageAndNullThrowable() { + LoggingSupport.log(plugin, "", null); + verifyNoMoreInteractions(log); + } + + private void assertStatus(int expectedSeverity, String expectedMessage, + String expectedBundleName, IStatus givenStatus) { + assertEquals(expectedSeverity, givenStatus.getSeverity()); + assertEquals(expectedMessage, givenStatus.getMessage()); + assertEquals(expectedBundleName, givenStatus.getPlugin()); + } + +} diff --git a/plugins/org.locationtech.udig.core/META-INF/MANIFEST.MF b/plugins/org.locationtech.udig.core/META-INF/MANIFEST.MF index fd6a97edd4..16e46b18a7 100644 --- a/plugins/org.locationtech.udig.core/META-INF/MANIFEST.MF +++ b/plugins/org.locationtech.udig.core/META-INF/MANIFEST.MF @@ -13,6 +13,7 @@ Export-Package: org.locationtech.udig.core, org.locationtech.udig.core.filter, org.locationtech.udig.core.internal, org.locationtech.udig.core.jts, + org.locationtech.udig.core.logging, org.locationtech.udig.core.opengis Require-Bundle: org.eclipse.core.runtime, org.eclipse.ui, diff --git a/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/internal/CorePlugin.java b/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/internal/CorePlugin.java index 7d39cea100..7d0ec59882 100644 --- a/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/internal/CorePlugin.java +++ b/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/internal/CorePlugin.java @@ -1,4 +1,5 @@ -/* uDig - User Friendly Desktop Internet GIS client +/** + * uDig - User Friendly Desktop Internet GIS client * http://udig.refractions.net * (C) 2012, Refractions Research Inc. * @@ -20,10 +21,9 @@ import java.util.ArrayList; import java.util.List; -import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; -import org.eclipse.core.runtime.Status; +import org.locationtech.udig.core.logging.LoggingSupport; import org.osgi.framework.BundleContext; /** @@ -34,23 +34,20 @@ */ public class CorePlugin extends Plugin { - /** Plugin ID field */ - public static final String ID = "org.locationtech.udig.core"; //$NON-NLS-1$ private static CorePlugin plugin; - - /** - * A url stream handler that delegates to the default one but if it doesn't work then it returns null as the stream. + * A url stream handler that delegates to the default one but if it doesn't work then it returns + * null as the stream. */ - public static final URLStreamHandler RELAXED_HANDLER=new URLStreamHandler(){ + public static final URLStreamHandler RELAXED_HANDLER = new URLStreamHandler() { @Override - protected URLConnection openConnection( URL u ) throws IOException { - try{ - URL url=new URL(u.toString()); + protected URLConnection openConnection(URL u) throws IOException { + try { + URL url = new URL(u.toString()); return url.openConnection(); - }catch (MalformedURLException e){ + } catch (MalformedURLException e) { return null; } } @@ -67,40 +64,40 @@ public CorePlugin() { /** * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ - public void start( BundleContext context ) throws Exception { + @Override + public void start(BundleContext context) throws Exception { super.start(context); } /** - * Create a URL from the provided spec; willing to create - * a URL even if the spec does not have a registered handler. - * Can be used to create "jdbc" URLs for example. + * Create a URL from the provided spec; willing to create a URL even if the spec does not have a + * registered handler. Can be used to create "jdbc" URLs for example. * * @param spec * @return URL if possible * @throws RuntimeException of a MalformedURLException resulted */ - public static URL createSafeURL( String spec ) { + public static URL createSafeURL(String spec) { try { return new URL(null, spec, RELAXED_HANDLER); } catch (MalformedURLException e) { - throw (RuntimeException) new RuntimeException( e ); + throw new RuntimeException(e); } } + /** - * Create a URI from the provided spec; willing to create - * a URI even if the spec does not have a registered handler. - * Can be used to create "jdbc" URLs for example. + * Create a URI from the provided spec; willing to create a URI even if the spec does not have a + * registered handler. Can be used to create "jdbc" URLs for example. * * @param spec * @return URI if possible * @throws RuntimeException of a URISyntaxException resulted */ - public static URI createSafeURI( String spec ){ + public static URI createSafeURI(String spec) { try { - return new URI( spec ); + return new URI(spec); } catch (URISyntaxException e) { - throw (RuntimeException) new RuntimeException( e ); + throw new RuntimeException(e); } } @@ -116,7 +113,7 @@ public static CorePlugin getDefault() { /** * Takes a string, and splits it on '\n' and calls stringsToURLs(String[]) */ - public static List stringsToURLs( String string ) { + public static List stringsToURLs(String string) { String[] strings = string.split("\n"); //$NON-NLS-1$ return stringsToURLs(strings); @@ -131,16 +128,16 @@ public static List stringsToURLs( String string ) { * @param strings an array of strings, each to be converted to a URL * @return a List of URLs, in the same order as the array */ - public static List stringsToURLs( String[] strings ) { - List urls = new ArrayList(); + public static List stringsToURLs(String[] strings) { + List urls = new ArrayList<>(); - for( String string : strings ) { + for (String string : strings) { try { urls.add(new URL(string)); } catch (MalformedURLException e) { // not a URL, maybe it is a file try { - urls.add( new File(string).toURI().toURL()); + urls.add(new File(string).toURI().toURL()); } catch (MalformedURLException e1) { // Not a URL, not a File. nothing to do now. } @@ -154,33 +151,31 @@ public static List stringsToURLs( String[] strings ) { *

* This should be used for user level messages. *

+ * + * @deprecated Use {@link LoggingSupport#log(Plugin, String, Throwable)} instead. */ - public static void log( String message2, Throwable e ) { - String message=message2; - if (message == null) - message = ""; //$NON-NLS-1$ - getDefault().getLog().log(new Status(IStatus.INFO, ID, 0, message, e)); + public static void log(String message2, Throwable e) { + LoggingSupport.log(getDefault(), message2, e); } + /** * Messages that only engage if getDefault().isDebugging() *

- * It is much prefered to do this: + * It is much preferred to do this: * - *


-     * private static final String RENDERING = "org.locationtech.udig.project/render/trace";
-     * if (ProjectUIPlugin.getDefault().isDebugging() && "true".equalsIgnoreCase(RENDERING)) {
-     *     System.out.println("your message here");
-     * }
+     * 
+     *  private static final String RENDERING =
+     * "org.locationtech.udig.project/render/trace"; if
+     * (ProjectUIPlugin.getDefault().isDebugging() &&
+     * "true".equalsIgnoreCase(RENDERING)) { System.out.println("your message
+     * here"); }
      *
+     * @deprecated Use {@link LoggingSupport#trace(Plugin, String, Throwable)} instead.
      */
-    public static void trace( String message, Throwable e ) {
-        if (getDefault().isDebugging()) {
-            if (message != null)
-                System.out.println(message);
-            if (e != null)
-                e.printStackTrace();
-        }
+    public static void trace(String message, Throwable e) {
+        LoggingSupport.trace(getDefault(), message, e);
     }
+
     /**
      * Performs the Platform.getDebugOption true check on the provided trace
      * 

@@ -192,7 +187,7 @@ public static void trace( String message, Throwable e ) { * * @param trace currently only RENDER is defined */ - public static boolean isDebugging( final String trace ) { + public static boolean isDebugging(final String trace) { return getDefault().isDebugging() && "true".equalsIgnoreCase(Platform.getDebugOption(trace)); //$NON-NLS-1$ } diff --git a/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/logging/LoggingSupport.java b/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/logging/LoggingSupport.java new file mode 100644 index 0000000000..08237b30e2 --- /dev/null +++ b/plugins/org.locationtech.udig.core/src/org/locationtech/udig/core/logging/LoggingSupport.java @@ -0,0 +1,175 @@ +/** + * uDig - User Friendly Desktop Internet GIS client + * https://locationtech.org/projects/technology.udig + * (C) 2021, Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution + * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). + */ +package org.locationtech.udig.core.logging; + +import java.text.MessageFormat; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.locationtech.udig.core.internal.CorePlugin; + +/** + * To allow logging in the same way and with the same behaviour overall modules this provides access + * to Plug-In Logging capability. + * + * In addition for developer purposes it allows you to trace messages, in case of Debugging-Mode for + * Plug-In is enabled (see {@link Plugin#isDebugging()}). + * + * @author Frank Gasdorf (fgdrf) + * + */ +public class LoggingSupport { + + /** + * @param plugin Plug-In to create log messages for + * @param status Status to log + */ + public static void log(Plugin plugin, IStatus status) { + if (plugin != null) { + plugin.getLog().log(status); + } + } + + /** + * Writes an info log in the plugin's log. + *

+ * This should be used for user level messages. + * + * @param plugin Plug-In to create log messages for + * @param logMessage message or just null, in case of Just logging throwable/exception + * @param e {@link Throwable} will be logged as {@link IStatus#WARNING}, {@link Exception} is + * logged as {@link IStatus#ERROR}, if null that just {@link IStatus#INFO} + */ + public static void log(Plugin plugin, String logMessage, Throwable e) { + String message = logMessage; + + Plugin logPlugin = (plugin == null ? CorePlugin.getDefault() : plugin); + + int status = (e == null ? IStatus.INFO + : (e instanceof Exception ? IStatus.ERROR : IStatus.WARNING)); + + if (!(status == IStatus.INFO && StringUtils.isEmpty(message))) { + log(logPlugin, new Status(status, logPlugin.getBundle().getSymbolicName(), message, e)); + } + } + + /** + * See {@link #log(Plugin, String, Throwable)} just without an explicit logMessage. + */ + public static void log(Plugin plugin, Throwable e) { + log(plugin, null, e); + } + + /** + * See {@link #log(Plugin, String, Throwable)} just without an explicit {@link Throwable} + */ + public static void log(Plugin plugin, String logMessage) { + log(plugin, logMessage, null); + } + + /** + * Logs the given throwable to the platform log, indicating the class and + * method from where it is being logged (this is not necessarily where it + * occurred). + * + * This convenience method is for internal use by the Workbench only and + * must not be called outside the Workbench. + * + * @param plugin Plug-In to create log messages for + * @param clazz + * The calling class. + * @param methodName + * The calling method name. + * @param t + * The throwable from where the problem actually occurred. + */ + public static void log(Plugin plugin, Class clazz, String methodName, Throwable t) { + final String msg = MessageFormat.format("Exception in {0}.{1}: {2}", //$NON-NLS-1$ + new Object[] { clazz.getName(), methodName, t }); + log(plugin, msg, t); + } + + /** + * Messages that only engage if is debugging is enabled for the given Plug-In. + *

+ * It is much preferred to do this: + * + *

+     * 
+     * private static final String RENDERING = "org.locationtech.udig.project/render/trace";
+     * if (ProjectUIPlugin.getDefault().isDebugging() && "true".equalsIgnoreCase(RENDERING)) {
+     *     System.out.println("your message here");
+     * }
+     * 
+     *
+     * @param plugin
+     */
+    public static void trace(Plugin plugin, String message, Throwable e) {
+        if (plugin != null && plugin.isDebugging()) {
+            if (message != null)
+                System.out.println(message);
+            if (e != null)
+                e.printStackTrace();
+        }
+    }
+
+    /**
+     * Adds the name of the caller class to the message.
+     *
+     * @param plugin Plug-In to create log messages for
+     * @param caller class of the object doing the trace.
+     * @param message tracing message, may be null.
+     * @param e exception, may be null.
+     */
+    public static void trace(Plugin plugin,  Class< ? > caller, String message, Throwable e ) {
+        if (caller != null) {
+            trace(plugin, caller.getSimpleName() + ": " + message, e); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Messages that only engage if getDefault().isDebugging() and the trace option traceID is true.
+     * Available trace options can be found in the Trace class.  (They must also be part of the .options file)
+     *
+     * @param plugin Plug-In to create log messages for
+     * @param traceID
+     * @param caller class of the object doing the trace.
+     * @param message tracing message, may be null.
+     * @param e exception, may be null.
+
+     * @param default1
+     * @param caller
+     * @param message
+     * @param e
+     */
+    public static void trace(Plugin plugin, String traceID, Class caller, String message,
+            Throwable e) {
+        if (isDebugging(plugin, traceID)) {
+            trace(plugin, traceID, caller, message, e);
+        }
+    }
+
+    /**
+     * Performs the Platform.getDebugOption true check on the provided trace
+     * 

+ * Note: plugin.isDebugging() must also be on. + *

+ * @param plugin Plug-In to check if trace is set to true a debugging is enabled. + * @param trace currently only RENDER is defined + */ + public static boolean isDebugging(final Plugin plugin, final String trace ) { + return plugin != null && plugin.isDebugging() && "true".equalsIgnoreCase(Platform.getDebugOption(trace)); //$NON-NLS-1$ + } + +} diff --git a/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/DocumentPlugin.java b/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/DocumentPlugin.java index 002b5063c1..0258c5c3c8 100644 --- a/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/DocumentPlugin.java +++ b/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/DocumentPlugin.java @@ -3,13 +3,12 @@ import java.net.URL; import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.document.ui.IDocumentImages; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; @@ -33,9 +32,10 @@ public DocumentPlugin() { /* * (non-Javadoc) - * + * * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) */ + @Override public void start(BundleContext context) throws Exception { super.start(context); plugin = this; @@ -43,9 +43,10 @@ public void start(BundleContext context) throws Exception { /* * (non-Javadoc) - * + * * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) */ + @Override public void stop(BundleContext context) throws Exception { plugin = null; super.stop(context); @@ -60,16 +61,6 @@ public static DocumentPlugin getDefault() { return plugin; } - /** - * Writes an info log in the plugin's log. - *

- * This should be used for user level messages. - *

- */ - public static void log(String message, Throwable e) { - getDefault().getLog().log(new Status(IStatus.INFO, PLUGIN_ID, 0, message, e)); - } - @Override protected void initializeImageRegistry(ImageRegistry reg) { super.initializeImageRegistry(reg); @@ -88,7 +79,7 @@ protected void initializeImageRegistry(ImageRegistry reg) { /** * Adds image to the registry. - * + * * @param reg * @param imagePath */ @@ -102,7 +93,7 @@ private void addImage(ImageRegistry reg, String imagePath) { if (url != null) { attachImg = ImageDescriptor.createFromURL(url); } else { - log("Unable to find image for " + imagePath, null); + LoggingSupport.log(getDefault(), "Unable to find image for " + imagePath, null); attachImg = ImageDescriptor.getMissingImageDescriptor(); } reg.put(imagePath, attachImg); diff --git a/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/source/BasicHotlinkDescriptorParser.java b/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/source/BasicHotlinkDescriptorParser.java index 9518ea322a..78f8e150c6 100644 --- a/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/source/BasicHotlinkDescriptorParser.java +++ b/plugins/org.locationtech.udig.document/src/org/locationtech/udig/document/source/BasicHotlinkDescriptorParser.java @@ -18,6 +18,7 @@ import org.locationtech.udig.catalog.IGeoResource; import org.locationtech.udig.catalog.document.IHotlinkSource.HotlinkDescriptor; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.document.DocumentPlugin; /** @@ -112,7 +113,7 @@ public List getDescriptors() { HotlinkDescriptor descriptor = new HotlinkDescriptor(definition); descriptors.add(descriptor); } catch (Throwable t) { - DocumentPlugin.log("Unable describe hotlink:" + definition, t); //$NON-NLS-1$ + LoggingSupport.log(DocumentPlugin.getDefault(), "Unable describe hotlink:" + definition, t); //$NON-NLS-1$ } } } diff --git a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoPlugin.java b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoPlugin.java index 7a029aa22c..b85a4120b8 100644 --- a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoPlugin.java +++ b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoPlugin.java @@ -10,10 +10,9 @@ */ package org.locationtech.udig.tool.info; -import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.locationtech.udig.core.logging.LoggingSupport; import org.osgi.framework.BundleContext; /** @@ -45,10 +44,12 @@ public InfoPlugin() { plugin = this; } + @Override public void start(BundleContext context) throws Exception { super.start(context); } + @Override public void stop(BundleContext context) throws Exception { plugin = null; super.stop(context); @@ -56,7 +57,7 @@ public void stop(BundleContext context) throws Exception { /** * Access shared InfoPlugin instance. - * + * * @return Shared Instance */ public static InfoPlugin getDefault() { @@ -68,29 +69,22 @@ public static InfoPlugin getDefault() { *

* This should be used for user level messages. *

+ * + * @deprecated Use LoggerSupport */ public static void log(String message, Throwable e) { - getDefault().getLog().log(new Status(IStatus.INFO, ID, 0, message, e)); + LoggingSupport.log(getDefault(), message, e); } /** * Messages that only engage if getDefault().isDebugging() - *

- * It is much prefered to do this: - * - *


-     * private static final String RENDERING = "org.locationtech.udig.project/render/trace";
-     * if( ProjectUIPlugin.getDefault().isDebugging() && "true".equalsIgnoreCase( RENDERING ) ){
-     *      System.out.println( "your message here" );
-     * }
+     *
+     * @deprecated Use
+     *             {@link LoggingSupport#trace(org.eclipse.core.runtime.Plugin, String, Throwable)}
+     *             instead.
      */
     public static void trace(String message, Throwable e) {
-        if (getDefault().isDebugging()) {
-            if (message != null)
-                System.out.println(message);
-            if (e != null)
-                e.printStackTrace();
-        }
+        LoggingSupport.trace(getDefault(), message, e);
     }
 
     /**
@@ -101,11 +95,11 @@ public static void trace(String message, Throwable e) {
      * 
  • Trace.RENDER - trace rendering progress * *

    - * + * * @param trace currently only RENDER is defined */ public static boolean isDebugging(final String trace) { return getDefault().isDebugging() - && "true".equalsIgnoreCase(Platform.getDebugOption(trace)); //$NON-NLS-1$ + && "true".equalsIgnoreCase(Platform.getDebugOption(trace)); //$NON-NLS-1$ } } diff --git a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoTool.java b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoTool.java index dca000c6ad..cfbaae9a7f 100644 --- a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoTool.java +++ b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/InfoTool.java @@ -11,9 +11,9 @@ */ package org.locationtech.udig.tool.info; -import java.awt.Point; import java.awt.Rectangle; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.project.ui.ApplicationGIS; import org.locationtech.udig.project.ui.commands.SelectionBoxCommand; import org.locationtech.udig.project.ui.render.displayAdapter.MapMouseEvent; @@ -27,13 +27,12 @@ import org.eclipse.ui.PlatformUI; import org.geotools.geometry.jts.ReferencedEnvelope; - /** * InfoTool is Map Tool used to grab identity information about what is on the screen. *

    - * InfoTool makes use its ModalTool superclass to access RenderManager; - * getInfo is a first class request supported by the API. You can however trace through - * this code as an example for creating your own tools. + * InfoTool makes use its ModalTool superclass to access RenderManager; getInfo is a first class + * request supported by the API. You can however trace through this code as an example for creating + * your own tools. *

    *

    * Workflow: @@ -46,108 +45,119 @@ *

  • LayerPointInfo.getObject() & LayerPointInfo.getMimeType() * *

    - * + * * @author Jody Garnett * @version $Revision: 1.9 $ */ public class InfoTool extends AbstractModalTool implements ModalTool { - /** * ID of the current tool. */ public static final String ID = "org.locationtech.udig.tool.info.infoMode"; //$NON-NLS-1$ - public static final String CATEGORY_ID = "org.locationtech.udig.tool.category.info"; //$NON-NLS-1$ + + public static final String CATEGORY_ID = "org.locationtech.udig.tool.category.info"; //$NON-NLS-1$ /** * Creates an LayerPointInfo Tool. */ public InfoTool() { - super( MOUSE | MOTION ); + super(MOUSE | MOTION); } - + @Override - public void mousePressed( MapMouseEvent e ) { - draw.setValid( true ); // make sure context.getViewportPane().repaint() knows about us - context.sendASyncCommand( draw ); // should of isValided us - feedback( e ); - + public void mousePressed(MapMouseEvent e) { + draw.setValid(true); // make sure context.getViewportPane().repaint() knows about us + context.sendASyncCommand(draw); // should of isValided us + feedback(e); + } + @Override - public void mouseDragged( MapMouseEvent e ) { - feedback( e ); - + public void mouseDragged(MapMouseEvent e) { + feedback(e); + } - + SelectionBoxCommand draw = new SelectionBoxCommand(); - + /** This is the "previous" square so we can refresh the screen correctly */ - private Rectangle previous; - + private Rectangle previous; + /** * Provides user feedback - * @param e + * + * @param e */ - public void feedback( MapMouseEvent e ) { - Rectangle square = new Rectangle(e.x-3, e.y-3, 5, 5); - draw.setShape( square ); - if( previous != null ){ - context.getViewportPane().repaint(previous.x-4, previous.y-4, previous.width+8, previous.height+8); + public void feedback(MapMouseEvent e) { + Rectangle square = new Rectangle(e.x - 3, e.y - 3, 5, 5); + draw.setShape(square); + if (previous != null) { + context.getViewportPane().repaint(previous.x - 4, previous.y - 4, previous.width + 8, + previous.height + 8); } previous = square; - context.getViewportPane().repaint(square.x-4, square.y-4, square.width+8, square.height+8); - //context.getViewportPane().repaint(); + context.getViewportPane().repaint(square.x - 4, square.y - 4, square.width + 8, + square.height + 8); + // context.getViewportPane().repaint(); } - /** * What's this then? *

    * See class description for intended workflow. *

    + * * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseReleased(MapMouseEvent) */ + @Override public void mouseReleased(MapMouseEvent e) { - try { - - ReferencedEnvelope bbox = context.getBoundingBox( e.getPoint(), 5 ); - + try { + + ReferencedEnvelope bbox = context.getBoundingBox(e.getPoint(), 5); + final InfoView2.InfoRequest request = new InfoView2.InfoRequest(); request.bbox = bbox; request.layers = context.getMapLayers(); - - Display.getDefault().asyncExec(new Runnable(){ + + Display.getDefault().asyncExec(new Runnable() { + @Override public void run() { - InfoView2 infoView=(InfoView2) ApplicationGIS.getView(true, InfoView2.VIEW_ID); - - // JONES: deselect current feature so it won't flash when view is activated (it won't be valid - // one the new search passes. - if( infoView!=null) - if( infoView.getSite().getSelectionProvider()!=null ) - infoView.getSite().getSelectionProvider().setSelection(new StructuredSelection()); - - //JONES: activate view now that there is no current selection. - IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); - if (!page.isPartVisible(infoView)) page.bringToTop(infoView); - + InfoView2 infoView = (InfoView2) ApplicationGIS.getView(true, + InfoView2.VIEW_ID); + + // JONES: deselect current feature so it won't flash when view is activated (it + // won't be valid + // one the new search passes. + if (infoView != null) + if (infoView.getSite().getSelectionProvider() != null) + infoView.getSite().getSelectionProvider() + .setSelection(new StructuredSelection()); + + // JONES: activate view now that there is no current selection. + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage(); + if (!page.isPartVisible(infoView)) + page.bringToTop(infoView); + // we got here and info was null? Don't want to fail on first attempt - infoView=(InfoView2) ApplicationGIS.getView(false, InfoView2.VIEW_ID); - infoView.search( request ); + infoView = (InfoView2) ApplicationGIS.getView(false, InfoView2.VIEW_ID); + infoView.search(request); } - }); - } catch ( Throwable e1) { - // Should log problem .. - InfoPlugin.log( "Could not display information", e1 ); //$NON-NLS-1$ - } - finally { - draw.setValid( false ); // get us off the draw stack for context.getViewportPane().repaint(); + }); + } catch (Throwable e1) { + LoggingSupport.log(InfoPlugin.getDefault(), "Could not display information", e1); //$NON-NLS-1$ + } finally { + draw.setValid(false); // get us off the draw stack for + // context.getViewportPane().repaint(); context.getViewportPane().repaint(); } } - + /** * @see org.locationtech.udig.project.ui.tool.Tool#dispose() */ + @Override public void dispose() { super.dispose(); } diff --git a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/InfoView2.java b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/InfoView2.java index 9ce8758430..e03fcfe99c 100644 --- a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/InfoView2.java +++ b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/InfoView2.java @@ -56,6 +56,7 @@ import org.geotools.util.factory.GeoTools; import org.locationtech.udig.catalog.IGeoResource; import org.locationtech.udig.core.internal.FeatureUtils; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.project.AdaptableFeature; import org.locationtech.udig.project.ILayer; import org.locationtech.udig.project.ILayerListener; @@ -352,7 +353,8 @@ protected void showDetail(Object selection) { StructuredSelection sel = new StructuredSelection(src); featureDisplay.selectionChanged(null, sel); } catch (IOException ex) { - InfoPlugin.log("GML value could not be acquired.", ex); //$NON-NLS-1$ + LoggingSupport.log(InfoPlugin.getDefault(), "GML value could not be acquired.", //$NON-NLS-1$ + ex); } // featureDisplay.setInfo(info); } else if (info.getRequestURL() != null @@ -430,7 +432,7 @@ protected void searchImplementation(Object filter, IProgressMonitor monitor, Res set.addAll(more); } } catch (Throwable t) { - InfoPlugin.log("Information request " + layer.getName() + " failed " + t, t); //$NON-NLS-1$ //$NON-NLS-2$ + LoggingSupport.log(InfoPlugin.getDefault(), "Information request " + layer.getName() + " failed " + t, t); //$NON-NLS-1$ //$NON-NLS-2$ } continue; } diff --git a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/WMSDescribeLayer.java b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/WMSDescribeLayer.java index b259dc4654..b68655659c 100644 --- a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/WMSDescribeLayer.java +++ b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/WMSDescribeLayer.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.project.ILayer; import org.locationtech.udig.project.IMap; import org.locationtech.udig.project.render.ICompositeRenderContext; @@ -42,7 +43,6 @@ import org.geotools.ows.wms.response.GetFeatureInfoResponse; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; -import org.geotools.referencing.crs.DefaultGeographicCRS; import org.opengis.metadata.Identifier; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; @@ -52,53 +52,53 @@ import org.locationtech.jts.geom.Envelope; public class WMSDescribeLayer { - + /** Figures out the mapping from wms layers to udig layers */ private Map getLayerMap( ICompositeRenderContext composite, IProgressMonitor monitor ) throws IOException { - Map mapping=new HashMap(); + Map mapping=new HashMap<>(); for( IRenderContext context: composite.getContexts() ) { ILayer layer = context.getLayer(); if( context.getLayer().isVisible() //&& layer.isApplicable("information" ) - ) { + ) { Layer wmslayer = layer.getResource( Layer.class, monitor ); mapping.put( wmslayer, layer ); } } return mapping; } - + public WebMapServer getWMS( ICompositeRenderContext context, IProgressMonitor monitor ) throws IOException { return context.getLayer().getResource(WebMapServer.class, monitor ); } - + /** Get list of applicable wms layers from composite */ private List getLayerList(ICompositeRenderContext composite) throws IOException { - List layers = new ArrayList(); + List layers = new ArrayList<>(); for( IRenderContext context: composite.getContexts()) { ILayer layer = context.getLayer(); if( layer.isVisible() // && layer.isApplicable("information") ) { - Layer wmslayer = layer.getResource( org.geotools.ows.wms.Layer.class, null ); + Layer wmslayer = layer.getResource( org.geotools.ows.wms.Layer.class, null ); layers.add( wmslayer ); - } - } + } + } return layers; } - + /** - * Implementation is forgiving codes must be in uppercase etc ... + * Implementation is forgiving codes must be in uppercase etc ... * * @param crs CoordinateReferenceSystem * @param codes Set of valid vodes - * + * * @return Code common to both or null */ - private static String commonCode( CoordinateReferenceSystem crs, Set codes ) { + private static String commonCode( CoordinateReferenceSystem crs, Set codes ) { // First pass based on string identity // - Set crsCodes = new HashSet(); + Set crsCodes = new HashSet<>(); for( Identifier id : crs.getIdentifiers() ) { String code = id.toString(); if( codes.contains( code ) ) return code; @@ -106,7 +106,7 @@ private static String commonCode( CoordinateReferenceSystem crs, Set cod } // Second pass based on CoordinateReferenceSystem equality for( String code : codes ) { - try { + try { CoordinateReferenceSystem check = CRS.decode( code ); if( crs.equals( check )) { // note we are trusting the code of the matched crs @@ -114,73 +114,73 @@ private static String commonCode( CoordinateReferenceSystem crs, Set cod // not get this far // return check.getIdentifiers().iterator().next().getCode(); - } + } } catch (NoSuchAuthorityCodeException e) { // could not understand code } catch (FactoryException e) { - // could not understand code + // could not understand code } } // last pass do the power set lookup based on id // for( String code : codes ) { - try { + try { CoordinateReferenceSystem check = CRS.decode( code ); for( Identifier checkId : check.getIdentifiers() ) { String checkCode = checkId.toString(); if( crsCodes.contains( checkCode ) ) { return code; - } - } + } + } } catch (NoSuchAuthorityCodeException e) { // could not understand code } catch (FactoryException e) { // could not understand code } - } + } return null; } - + @SuppressWarnings("unchecked") public static List info( ILayer layer, ReferencedEnvelope bbox ) throws IOException { LayerPointInfo info = info2( layer, bbox ); if( info == null ) return Collections.EMPTY_LIST; - - return Collections.singletonList( info ); + + return Collections.singletonList( info ); } - + /** * Aquire info for the provided bbox - * - * @param layer Must be associated with a wms layer + * + * @param layer Must be associated with a wms layer * @param bbox * @return LayerPointInfo object or null if information is unavailable. - * @throws IOException + * @throws IOException * @throws IOException if Response could not be understood - * - * TODO: possible problem with client side reprojection - may need to + * + * TODO: possible problem with client side reprojection - may need to * properly reproject the center point that was clicked on - * + * * TODO: this requires some testing */ - public static LayerPointInfo info2( ILayer layer, ReferencedEnvelope query ) throws IOException { + public static LayerPointInfo info2( ILayer layer, ReferencedEnvelope query ) throws IOException { Envelope reprojected = null; IMap map = layer.getMap(); try { reprojected = query.transform(map.getViewportModel().getCRS(), true); } catch (Exception e) { - InfoPlugin.log("", e); //$NON-NLS-1$ + LoggingSupport.log(InfoPlugin.getDefault(), e); return null; } Point centre = map.getViewportModel().worldToPixel(reprojected.centre()); Envelope sanebbox = map.getViewportModel().getBounds(); ReferencedEnvelope bbox = new ReferencedEnvelope(sanebbox, query.getCoordinateReferenceSystem()); - + Layer wmslayer; wmslayer = layer.getResource( Layer.class, null ); - + if( wmslayer == null ) { throw new IllegalArgumentException("Provided layer is not a WMS layer" ); //$NON-NLS-1$ } @@ -188,28 +188,28 @@ public static LayerPointInfo info2( ILayer layer, ReferencedEnvelope query ) thr return null; } // TODO: Fix wmslayer so we can ask who its "source" is. - final WebMapServer wms = layer.getResource( WebMapServer.class, null ); + final WebMapServer wms = layer.getResource( WebMapServer.class, null ); if( wms == null ) { throw new IllegalArgumentException("Provided layer cannot resolve to a wms" ); //$NON-NLS-1$ } - String desiredFormat = desiredInfoFormat( wms ); + String desiredFormat = desiredInfoFormat( wms ); if( desiredFormat == null ){ return null; } - GetMapRequest getmap = wms.createGetMapRequest(); + GetMapRequest getmap = wms.createGetMapRequest(); String code = BasicWMSRenderer2.findRequestCRS( Collections.singletonList( wmslayer ), map.getViewportModel().getCRS(), map ); getmap.setBBox( bbox ); String srs = CRS.toSRS(bbox.getCoordinateReferenceSystem() ); getmap.setSRS( code != null ? code : srs ); - + getmap.setProperty( GetMapRequest.LAYERS, wmslayer.getName() ); int width = map.getRenderManager().getMapDisplay().getWidth(); int height = map.getRenderManager().getMapDisplay().getHeight(); getmap.setDimensions(width, height); //getmap.setSRS(code); - + List formats = wms.getCapabilities().getRequest().getGetMap().getFormats(); if (formats.contains("image/png")) { //$NON-NLS-1$ getmap.setProperty(GetMapRequest.FORMAT, "image/png"); //$NON-NLS-1$ @@ -220,7 +220,7 @@ public static LayerPointInfo info2( ILayer layer, ReferencedEnvelope query ) thr } else if (formats.contains("image/bmp")) { //$NON-NLS-1$ getmap.setProperty(GetMapRequest.FORMAT, "image/bmp"); //$NON-NLS-1$ } - + StyleImpl wmsStyle = (StyleImpl) layer.getStyleBlackboard().get(WMSStyleContent.WMSSTYLE); if (wmsStyle != null) { getmap.setProperty(GetMapRequest.STYLES, wmsStyle.getName()); @@ -229,17 +229,17 @@ public static LayerPointInfo info2( ILayer layer, ReferencedEnvelope query ) thr // supply an empty String as per UDIG-1507 getmap.setProperty(GetMapRequest.STYLES, ""); } - - final GetFeatureInfoRequest request = wms.createGetFeatureInfoRequest( getmap ); + + final GetFeatureInfoRequest request = wms.createGetFeatureInfoRequest( getmap ); request.setInfoFormat( desiredFormat ); - request.setQueryPoint( centre.x, centre.y ); + request.setQueryPoint( centre.x, centre.y ); request.setQueryLayers( Collections.singleton( wmslayer ) ); - + LayerPointInfo info = new LayerPointInfo( layer ){ - + private GetFeatureInfoResponse response; /** Lazy request */ - + protected GetFeatureInfoResponse getResponse() throws IOException { if (this.response == null) { try { @@ -252,10 +252,12 @@ protected GetFeatureInfoResponse getResponse() throws IOException { } return this.response; } + @Override public URL getRequestURL() { return request.getFinalURL(); } /** Only acquire the value if needed */ + @Override public String getMimeType() { try { return getResponse().getContentType(); @@ -264,6 +266,7 @@ public String getMimeType() { } } /** Only acquire the value if needed */ + @Override public Object acquireValue() throws IOException { // final String CONTENT_TYPE = response.getContentType(); // if ("text/plain".equals( CONTENT_TYPE ) || @@ -306,9 +309,9 @@ public Object acquireValue() throws IOException { private static String desiredInfoFormat( WebMapServer wms ) { List formats = wms.getCapabilities().getRequest().getGetFeatureInfo().getFormats(); - + String desiredFormat; - + if (formats.contains("text/html")) { //$NON-NLS-1$ desiredFormat = "text/html"; //$NON-NLS-1$ } else if (formats.contains("text/plain")) { //$NON-NLS-1$ diff --git a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/display/BrowserInfoDisplay.java b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/display/BrowserInfoDisplay.java index 90d7de6f9f..0314a50dc8 100644 --- a/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/display/BrowserInfoDisplay.java +++ b/plugins/org.locationtech.udig.info/src/org/locationtech/udig/tool/info/internal/display/BrowserInfoDisplay.java @@ -13,6 +13,7 @@ import java.io.IOException; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.tool.info.InfoDisplay; import org.locationtech.udig.tool.info.InfoPlugin; import org.locationtech.udig.tool.info.LayerPointInfo; @@ -34,7 +35,7 @@ /** * Nested browser used to display LayerPointInfo. - * + * * @author Jody Garnett * @since 0.3 */ @@ -42,19 +43,22 @@ public class BrowserInfoDisplay extends InfoDisplay { /** browser field */ protected Browser browser; - + private Action backAction = new Action("Back") { //$NON-NLS-1$ + @Override public void run() { browser.back(); } - }; + }; private Action forwardAction = new Action("Forward") { //$NON-NLS-1$ + @Override public void run() { browser.forward(); } }; private Action stopAction = new Action("Stop") { //$NON-NLS-1$ + @Override public void run() { browser.stop(); // cancel any partial progress. @@ -63,6 +67,7 @@ public void run() { }; private Action refreshAction = new Action("Refresh") { //$NON-NLS-1$ + @Override public void run() { browser.refresh(); } @@ -71,38 +76,41 @@ public void run() { static final protected boolean DEBUG = false; //private CLabel label; private ViewForm viewForm; - + /* - * Nested viewForm containing browser, locationbar and toolbar + * Nested viewForm containing browser, locationbar and toolbar * @return embded browser */ + @Override public Control getControl() { return viewForm; } /* * Set up w/ an embeded brower. */ + @Override public void createDisplay( Composite parent ) { viewForm= new ViewForm( parent, SWT.NONE); - + //label= new CLabel( viewForm, SWT.NONE); //viewForm.setTopLeft( label ); - + ToolBar toolBar= new ToolBar( viewForm, SWT.FLAT | SWT.WRAP); viewForm.setTopCenter(toolBar); - - browser = createBrowser( viewForm, toolBar ); + + browser = createBrowser( viewForm, toolBar ); browser.setUrl( "about:blank" ); //$NON-NLS-1$ - + viewForm.setContent( browser ); } - + /** * Focus the browser onto LayerPointInfo.getRequestURL. - * + * * @see org.locationtech.udig.tool.info.InfoDisplay#setInfo(org.locationtech.udig.project.render.LayerPointInfo) * @param info */ + @Override public void setInfo( LayerPointInfo info ) { if( info == null || info.getRequestURL() == null ) { browser.setVisible( false ); @@ -112,21 +120,21 @@ public void setInfo( LayerPointInfo info ) { try { browser.setText((String) info.acquireValue()); } catch (IOException e) { - InfoPlugin.trace("Could not acquire info value", e); + LoggingSupport.trace(InfoPlugin.getDefault(), "Could not acquire info value", e); } } } - - - private Browser createBrowser(Composite parent, final ToolBar toolbar) { + + private Browser createBrowser(Composite parent, final ToolBar toolbar) { try{ browser = new Browser(parent, SWT.NONE); }catch(Exception e){ - InfoPlugin.log( "Could not create browser", e); //$NON-NLS-1$ + LoggingSupport.log(InfoPlugin.getDefault(), "Could not create browser", e); //$NON-NLS-1$ } - + browser.addStatusTextListener(new StatusTextListener() { - // IStatusLineManager status = toolbar.getStatusLineManager(); + // IStatusLineManager status = toolbar.getStatusLineManager(); + @Override public void changed(StatusTextEvent event) { /* if (DEBUG) { @@ -134,29 +142,31 @@ public void changed(StatusTextEvent event) { } status.setMessage(event.text); */ - } + } }); browser.addLocationListener(new LocationAdapter() { + @Override public void changed(LocationEvent event) { if (event.top){ - //label.setToolTipText( browser.getUrl() ); + //label.setToolTipText( browser.getUrl() ); } } }); browser.addTitleListener(new TitleListener() { + @Override public void changed(TitleEvent event) { //label.setText( event.title ); } }); - + // Hook the navigation actons as handlers for the retargetable actions // defined in BrowserActionBuilder. - ToolBarManager tbmanager= new ToolBarManager( toolbar ); + ToolBarManager tbmanager= new ToolBarManager( toolbar ); tbmanager.add( backAction ); tbmanager.add( forwardAction ); tbmanager.add( stopAction) ; tbmanager.add( refreshAction ); - + return browser; } } diff --git a/plugins/org.locationtech.udig.issues.tests/META-INF/MANIFEST.MF b/plugins/org.locationtech.udig.issues.tests/META-INF/MANIFEST.MF index 714ee123b5..703c69547d 100644 --- a/plugins/org.locationtech.udig.issues.tests/META-INF/MANIFEST.MF +++ b/plugins/org.locationtech.udig.issues.tests/META-INF/MANIFEST.MF @@ -8,6 +8,8 @@ Bundle-Vendor: udig.refractions.net Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.locationtech.udig.issues, - org.locationtech.udig.project.ui.tests + org.locationtech.udig.project.ui.tests, + org.locationtech.udig.project;bundle-version="2.3.0", + org.locationtech.udig.ui Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/plugins/org.locationtech.udig.issues/META-INF/MANIFEST.MF b/plugins/org.locationtech.udig.issues/META-INF/MANIFEST.MF index bcb6a94c93..79443f2b5f 100644 --- a/plugins/org.locationtech.udig.issues/META-INF/MANIFEST.MF +++ b/plugins/org.locationtech.udig.issues/META-INF/MANIFEST.MF @@ -8,10 +8,12 @@ Bundle-Vendor: udig.refractions.net Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, - org.locationtech.udig.project.ui;visibility:=reexport, org.locationtech.udig.catalog.postgis, org.eclipse.ui.cheatsheets, - org.locationtech.udig.libs + org.locationtech.udig.libs, + org.locationtech.udig.core, + org.locationtech.udig.project, + org.locationtech.udig.project.ui Bundle-ActivationPolicy: lazy Export-Package: org.locationtech.udig.issues, org.locationtech.udig.issues.internal;x-friends:="org.locationtech.udig.issues.tests", diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AbstractFixableIssue.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AbstractFixableIssue.java index f53f59df41..9b2ae0edec 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AbstractFixableIssue.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AbstractFixableIssue.java @@ -15,6 +15,7 @@ import org.locationtech.udig.core.IFixer; import org.locationtech.udig.core.enums.Resolution; import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.internal.IssuesActivator; import org.eclipse.core.runtime.IConfigurationElement; @@ -28,7 +29,7 @@ * Base implementation of IIssue which persists a fixerMemento (for use with an IssueFixer). *

    *

    - * + * * @author chorner * @since 1.1.0 */ @@ -42,9 +43,10 @@ public abstract class AbstractFixableIssue extends AbstractIssue { public static final String KEY_FIXERMEMENTO = "fixerMemento"; //$NON-NLS-1$ public static final String XPID_ISSUEFIXER = "org.locationtech.udig.issues.issueFixer"; //$NON-NLS-1$ - + IMemento fixerMemento = null; - + + @Override public void fixIssue( IViewPart part, IEditorPart editor ) { IFixer fixer = findIssueFixer(fixerMemento); if (fixer == null) { @@ -77,7 +79,7 @@ protected IFixer findIssueFixer( IMemento fixerMemento ) { break; } } - if (isValid) { //check the target class + if (isValid) { //check the target class String targetClass = element.getAttribute(ATT_TARGET); //first ensure that this class name and target name are not identical if (targetClass != null && this.getClass().getCanonicalName() != targetClass) { @@ -90,7 +92,7 @@ protected IFixer findIssueFixer( IMemento fixerMemento ) { } catch (ClassNotFoundException e) { //can't instantiate isValid = false; - IssuesActivator.log("couldn't create class " + targetClass, e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "couldn't create class " + targetClass, e); //$NON-NLS-1$ } } } @@ -100,8 +102,7 @@ protected IFixer findIssueFixer( IMemento fixerMemento ) { try { fixer = (IFixer) element.createExecutableExtension(ATT_CLASS); } catch (Exception e) { - e.printStackTrace(); - IssuesActivator.log("Could not instantiate IssueFixer extension", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "Could not instantiate IssueFixer extension", e); //$NON-NLS-1$ } if (fixer != null && fixer.canFix(this, fixerMemento)) { return fixer; @@ -111,6 +112,7 @@ protected IFixer findIssueFixer( IMemento fixerMemento ) { return null; } + @Override public void init( IMemento memento, IMemento viewMemento, String issueId, String groupId, ReferencedEnvelope bounds ) { setViewMemento(viewMemento); @@ -125,16 +127,17 @@ public void init( IMemento memento, IMemento viewMemento, String issueId, String } /** - * Subclasses should override and call super.save(). + * Subclasses should override and call super.save(). */ + @Override public void save( IMemento memento ) { memento.putMemento(fixerMemento); } - + /** * Obtains the fixer memento, which contains issue state and initialization data for the * IssueFixer. - * + * * @return fixerMemento */ public IMemento getFixerMemento() { diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AddIssueOperation.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AddIssueOperation.java index 782825c739..29382baaea 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AddIssueOperation.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/AddIssueOperation.java @@ -16,6 +16,7 @@ import java.util.HashSet; import org.locationtech.udig.core.enums.Priority; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.internal.IssuesActivator; import org.locationtech.udig.issues.internal.Messages; import org.locationtech.udig.issues.internal.view.IssuesView; @@ -55,12 +56,13 @@ /** * Adds selected features as issues to the issues list - * + * * @author Jesse * @since 1.1.0 */ public class AddIssueOperation implements IOp { + @Override public void op( Display display, Object target, IProgressMonitor monitor ) throws Exception { Object[] array = (Object[]) target; @@ -88,7 +90,8 @@ public void op( Display display, Object target, IProgressMonitor monitor ) throw private void select(Display display, final Collection issues) { display.asyncExec(new Runnable() { - public void run() { + @Override + public void run() { IWorkbenchPage page = findPage(); if( page!=null ){ IViewPart view = page.findView(IssuesView.VIEW_ID); @@ -108,7 +111,7 @@ private void showView() { activePage.showView(IssuesView.VIEW_ID, null, IWorkbenchPage.VIEW_VISIBLE); } } catch (PartInitException e) { - IssuesActivator.log("Error showing issues view",e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "Error showing issues view",e); //$NON-NLS-1$ } } @@ -132,6 +135,7 @@ private IWorkbenchPage findPage() { private InformationDialog openInformationDialog( final Display display ) { final InformationDialog[] dialog = new InformationDialog[1]; PlatformGIS.syncInDisplayThread(display, new Runnable(){ + @Override public void run() { dialog[0] = new InformationDialog(display.getActiveShell()); showView(); @@ -144,48 +148,46 @@ public void run() { private Collection addFeatureIssues( SimpleFeature[] features, InformationDialog dialog, IProgressMonitor monitor ) { - Collection issues = new HashSet(); - + Collection issues = new HashSet<>(); + for( SimpleFeature feature : features ) { if (feature instanceof IAdaptable) { IAdaptable adaptable = (IAdaptable) feature; - ILayer layer = (ILayer) adaptable.getAdapter(ILayer.class); + ILayer layer = adaptable.getAdapter(ILayer.class); if (layer == null) { - IssuesActivator - .log( - "Couldn't adapt the feature to a layer so therefore couldn't add it as an issue", //$NON-NLS-1$ - null); + LoggingSupport.log(IssuesActivator.getDefault(), + "Couldn't adapt the feature to a layer so therefore couldn't add it as an issue"); //$NON-NLS-1$ } else { issues.add(addFeatureIssue(feature, layer, dialog)); } } else { - IssuesActivator.log( + LoggingSupport.log(IssuesActivator.getDefault(), "The feature is not adaptable and therefore a layor couldn't be determined for it. " //$NON-NLS-1$ - + "So it couldn't add it as an issue", null); //$NON-NLS-1$ + + "So it couldn't add it as an issue"); //$NON-NLS-1$ } monitor.worked(1); } issues.remove(null); return issues; - + } private Collection addFeatureIssues( Filter[] filters, InformationDialog dialog, IProgressMonitor monitor ) throws IOException { - Collection issues = new HashSet(); + Collection issues = new HashSet<>(); for( Filter filter : filters ) { FeatureSource featureSource = null; ILayer layer = null; if (filter instanceof IAdaptable) { IAdaptable adaptable = (IAdaptable) filter; - layer = (ILayer) adaptable.getAdapter(ILayer.class); + layer = adaptable.getAdapter(ILayer.class); if (layer != null) { featureSource = layer.getResource(FeatureSource.class, monitor); } } - + if (featureSource == null) { - IssuesActivator.log("SimpleFeature Source for filter: " + filter, null); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(),"SimpleFeature Source for filter: " + filter); //$NON-NLS-1$ } else { FeatureCollection features = featureSource.getFeatures(filter); FeatureIterator iter = features.features(); @@ -205,7 +207,7 @@ private Collection addFeatureIssues( Filter[] filters, InformationDialog private IIssue addFeatureIssue( SimpleFeature feature, ILayer layer, InformationDialog dialog ) { if (feature == null) { - IssuesActivator.log("Can't construct an issue from a null feature!", null); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(),"Can't construct an issue from a null feature!"); //$NON-NLS-1$ return null; } else { String description = dialog.getDescription(); @@ -257,7 +259,7 @@ protected Control createDialogArea( Composite parent ) { createGroupIDWidgets(comp); createDescriptionWidgets(comp); - + createOperationDescription(comp); return comp; @@ -318,6 +320,7 @@ private static GridData createLayoutData( boolean fillHorizontal ) { return new GridData(SWT.FILL, SWT.TOP, fillHorizontal, false); } + @Override public void handleEvent( Event event ) { if (event.widget == description) { descriptionText = description.getText(); diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesList.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesList.java index 3621eaeea8..a82874ef95 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesList.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesList.java @@ -21,6 +21,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.locks.ReentrantLock; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.internal.IssuesActivator; import org.locationtech.udig.issues.listeners.IIssuesListListener; import org.locationtech.udig.issues.listeners.IssuesListEvent; @@ -36,19 +37,19 @@ *

    * Notifies listeners when issues are added or removed from list. *

    - * + * * @author jones * @since 1.0.0 */ public class IssuesList extends AbstractSequentialList implements IIssuesList { - LinkedList list = new LinkedList(); + LinkedList list = new LinkedList<>(); private static final String ID = "org.locationtech.udig.issues.memory"; //$NON-NLS-1$ private boolean notify = true; - Set ids = new CopyOnWriteArraySet(); + Set ids = new CopyOnWriteArraySet<>(); volatile int nextID = 0; @@ -64,6 +65,7 @@ private String findNextID(int index) { return "Issue." + nextID++; //$NON-NLS-1$ } + @Override public boolean add(IIssue o) { checkID(o, list.size()); list.add(o); @@ -71,12 +73,14 @@ public boolean add(IIssue o) { return true; } + @Override public void add(int index, IIssue element) { checkID(element, index); list.add(index, element); notify(element, IssuesListEventType.ADD); } + @Override public boolean addAll(Collection c) { try { notify = false; @@ -91,6 +95,7 @@ public boolean addAll(Collection c) { return true; } + @Override public boolean addAll(int index, Collection c) { boolean doNotify = notify; try { @@ -119,6 +124,7 @@ public IIssue remove() { return issue; } + @Override public IIssue remove(int index) { IIssue issue = list.remove(index); ids.remove(issue); @@ -127,6 +133,7 @@ public IIssue remove(int index) { return issue; } + @Override public boolean remove(Object o) { if (o instanceof IIssue) { IIssue issue = (IIssue) o; @@ -140,8 +147,9 @@ public boolean remove(Object o) { return false; } + @Override public boolean removeAll(Collection c) { - Collection i = new HashSet(); + Collection i = new HashSet<>(); for (Object object : c) { if (!(object instanceof IIssue)) return false; @@ -170,6 +178,7 @@ public IIssue removeLast() { return remove(list.size() - 1); } + @Override public IIssue set(int index, IIssue element) { IIssue old = list.set(index, element); element.setId(old.getId()); @@ -178,8 +187,9 @@ public IIssue set(int index, IIssue element) { return old; } + @Override public boolean retainAll(Collection c) { - List changed = new LinkedList(); + List changed = new LinkedList<>(); boolean modified = false; Iterator e = list.iterator(); try { @@ -200,6 +210,7 @@ public boolean retainAll(Collection c) { return modified; } + @Override @SuppressWarnings("unchecked") public void clear() { List changed; @@ -218,10 +229,11 @@ public void clear() { /** * This is public for tesing purposes only!!!! */ - public Collection listeners = new CopyOnWriteArraySet(); + public Collection listeners = new CopyOnWriteArraySet<>(); private ReentrantLock issuesListLock = new ReentrantLock(); + @Override public void addListener(IIssuesListListener listener) { issuesListLock.lock(); try { @@ -231,6 +243,7 @@ public void addListener(IIssuesListListener listener) { } } + @Override public void removeListener(IIssuesListListener listener) { issuesListLock.lock(); try { @@ -252,26 +265,28 @@ protected void notify(Collection changed, IssuesListEventType /** * Notify listeners of a change to the list. - * + * * @param changed issue that has changed. * @param type Type of change. */ public void notify(IIssue changed, IssuesListEventType type) { - HashSet set = new HashSet(); + HashSet set = new HashSet<>(); set.add(changed); notify(set, type); } + @Override public Set getGroups() { - Set groups = new HashSet(); + Set groups = new HashSet<>(); for (IIssue issue : list) { groups.add(issue.getGroupId()); } return groups; } + @Override public List getIssues(String groupId) { - List group = new LinkedList(); + List group = new LinkedList<>(); for (IIssue issue : list) { if (groupId == null) { if (issue.getGroupId() == null) { @@ -284,10 +299,11 @@ public List getIssues(String groupId) { return group; } + @Override public void removeIssues(String groupId) { if (groupId == null) return; - LinkedList group = new LinkedList(); + LinkedList group = new LinkedList<>(); for (IIssue issue : list) { if (groupId.equals(issue.getGroupId())) group.add(issue); @@ -305,13 +321,14 @@ public int size() { return list.size(); } + @Override public String getExtensionID() { return ID; } /** * Sets it so that adds and removes will not raise notifications. - * + * * @param notifyListeners true if notifications should be sent */ public void setNotify(boolean notifyListeners) { @@ -326,10 +343,11 @@ public void load() { try { persister.load(); } catch (WorkbenchException e) { - IssuesActivator.log( + LoggingSupport.log(IssuesActivator.getDefault(), "Failed to load old issues because the memento could not be parsed", e); //$NON-NLS-1$ } catch (IOException e) { - IssuesActivator.log("Failed to load old issues because the file could not be read", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), + "Failed to load old issues because the file could not be read", e); //$NON-NLS-1$ } } @@ -341,7 +359,8 @@ public void save() { try { persister.save(); } catch (IOException e) { - IssuesActivator.log("Failed to save issues because the file could not be written", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), + "Failed to save issues because the file could not be written", e); //$NON-NLS-1$ } } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListPersister.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListPersister.java index af4eb7de0e..e7f7f0c956 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListPersister.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListPersister.java @@ -16,6 +16,7 @@ import org.locationtech.udig.core.enums.Priority; import org.locationtech.udig.core.enums.Resolution; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.internal.IssuesActivator; import org.locationtech.udig.issues.internal.Messages; @@ -30,154 +31,138 @@ /** * Persists an issues list to a file - * + * * @author Jesse */ public class IssuesListPersister { - private static final String MEMENTO_CHILD_TYPE = "issue"; //$NON-NLS-1$ - - private static final String MEMENTO_ISSUE_DATA = "MEMENTO_ISSUE_DATA"; //$NON-NLS-1$ - - private static final String EXTENSION_ID = "EXTENSION_ID"; //$NON-NLS-1$ - - private static final String MEMENTO_VIEW_DATA = "MEMENTO_VIEW_DATA"; //$NON-NLS-1$ - - private static final String GROUP_ID = "GROUP_ID"; //$NON-NLS-1$ - - private static final String DESCRIPTION = "DESCRIPTION"; //$NON-NLS-1$ - - private static final String MIN_X = "MIN_X"; //$NON-NLS-1$ - - private static final String MAX_X = "MAX_X"; //$NON-NLS-1$ - - private static final String MIN_Y = "MIN_Y"; //$NON-NLS-1$ - - private static final String MAX_Y = "MAX_Y"; //$NON-NLS-1$ - - private static final String CRS = "CRS"; //$NON-NLS-1$ - - private static final String PRIORITY = "PRIORITY"; //$NON-NLS-1$ - - private static final String RESOLUTION = "RESOLUTION"; //$NON-NLS-1$ - - private IIssuesList list; - - public IssuesListPersister(IIssuesList list, String fileName) { - this.list = list; - } - - /** - * Saves the issues list to the workspace - * - * @throws IOException - * Thrown if there is a failure writing the output file. - */ - public void save() throws IOException { - XMLMemento memento = XMLMemento.createWriteRoot(Messages.IssuesListPersister_xmlRootElement); - for (IIssue issue : this.list) { - try { - IMemento child = memento.createChild(MEMENTO_CHILD_TYPE, issue - .getId()); - - child.putString(GROUP_ID, issue.getGroupId()); - child.putString(EXTENSION_ID, issue.getExtensionID()); - child.putString(DESCRIPTION, issue.getDescription()); - child.putString(PRIORITY, issue.getPriority().name()); - child.putString(RESOLUTION, issue.getResolution().name()); - - // persist bounds - ReferencedEnvelope bounds = issue.getBounds(); - child.putString(MIN_X, Double.toString(bounds.getMinX())); - child.putString(MAX_X, Double.toString(bounds.getMaxX())); - child.putString(MIN_Y, Double.toString(bounds.getMinY())); - child.putString(MAX_Y, Double.toString(bounds.getMaxY())); - child.putString(CRS, bounds.getCoordinateReferenceSystem() - .toWKT()); - - issue.getViewMemento(child.createChild(MEMENTO_VIEW_DATA)); - issue.save(child.createChild(MEMENTO_ISSUE_DATA)); - } catch (Throwable e) { - IssuesActivator.log("error when daving issue", e); //$NON-NLS-1$ - } - } - FileWriter fileWriter = new FileWriter(getLocalIssuesFile()); - try { - memento.save(fileWriter); - } finally { - fileWriter.close(); - } - } - - /** - * Reads the local issues from disk - * - * @throws IOException - * thrown if there was a problem reading the issues file - * @throws WorkbenchException - * thrown if the xml in the file is bad or doesn't conform to - * what the XMLMemento expects - */ - public void load() throws IOException, WorkbenchException { - if (getLocalIssuesFile().exists()) { - FileReader reader = new FileReader(getLocalIssuesFile()); - XMLMemento memento = XMLMemento.createReadRoot(reader); - IMemento[] children = memento.getChildren(MEMENTO_CHILD_TYPE); - for (IMemento issueMemento : children) { - try { - IIssue issue = IssuesListUtil.createIssue(issueMemento - .getString(EXTENSION_ID)); - if (issue == null) { - continue; - } - IMemento dataMemento = issueMemento - .getChild(MEMENTO_ISSUE_DATA); - IMemento viewMemento = issueMemento - .getChild(MEMENTO_VIEW_DATA); - String issueId = issueMemento.getID(); - String groupId = issueMemento.getString(GROUP_ID); - - double minX = Double.parseDouble(issueMemento - .getString(MIN_X)); - double maxX = Double.parseDouble(issueMemento - .getString(MAX_X)); - double minY = Double.parseDouble(issueMemento - .getString(MIN_Y)); - double maxY = Double.parseDouble(issueMemento - .getString(MAX_Y)); - CoordinateReferenceSystem crs; - try { - crs = org.geotools.referencing.CRS - .parseWKT(issueMemento.getString(CRS)); - } catch (FactoryException e) { - crs = null; - } - ReferencedEnvelope bounds = new ReferencedEnvelope(minX, - maxX, minY, maxY, crs); - issue.init(dataMemento, viewMemento, issueId, groupId, - bounds); - issue.setDescription(issueMemento.getString(DESCRIPTION)); - issue.setPriority(Priority.valueOf(issueMemento - .getString(PRIORITY))); - issue.setResolution(Resolution.valueOf(issueMemento - .getString(RESOLUTION))); - - list.add(issue); - } catch (Throwable e) { - IssuesActivator.log("error when loading issue", e); //$NON-NLS-1$ - } - - } - } - } - - private File getLocalIssuesFile() throws IOException { - File userLocation = new File(FileLocator.toFileURL( - Platform.getInstanceLocation().getURL()).getFile()); - if (!userLocation.exists()) - userLocation.mkdirs(); - File catalogLocation = new File(userLocation, ".issues.xml"); //$NON-NLS-1$ - return catalogLocation; - } + private static final String MEMENTO_CHILD_TYPE = "issue"; //$NON-NLS-1$ + + private static final String MEMENTO_ISSUE_DATA = "MEMENTO_ISSUE_DATA"; //$NON-NLS-1$ + + private static final String EXTENSION_ID = "EXTENSION_ID"; //$NON-NLS-1$ + + private static final String MEMENTO_VIEW_DATA = "MEMENTO_VIEW_DATA"; //$NON-NLS-1$ + + private static final String GROUP_ID = "GROUP_ID"; //$NON-NLS-1$ + + private static final String DESCRIPTION = "DESCRIPTION"; //$NON-NLS-1$ + + private static final String MIN_X = "MIN_X"; //$NON-NLS-1$ + + private static final String MAX_X = "MAX_X"; //$NON-NLS-1$ + + private static final String MIN_Y = "MIN_Y"; //$NON-NLS-1$ + + private static final String MAX_Y = "MAX_Y"; //$NON-NLS-1$ + + private static final String CRS = "CRS"; //$NON-NLS-1$ + + private static final String PRIORITY = "PRIORITY"; //$NON-NLS-1$ + + private static final String RESOLUTION = "RESOLUTION"; //$NON-NLS-1$ + + private IIssuesList list; + + public IssuesListPersister(IIssuesList list, String fileName) { + this.list = list; + } + + /** + * Saves the issues list to the workspace + * + * @throws IOException Thrown if there is a failure writing the output file. + */ + public void save() throws IOException { + XMLMemento memento = XMLMemento + .createWriteRoot(Messages.IssuesListPersister_xmlRootElement); + for (IIssue issue : this.list) { + try { + IMemento child = memento.createChild(MEMENTO_CHILD_TYPE, issue.getId()); + + child.putString(GROUP_ID, issue.getGroupId()); + child.putString(EXTENSION_ID, issue.getExtensionID()); + child.putString(DESCRIPTION, issue.getDescription()); + child.putString(PRIORITY, issue.getPriority().name()); + child.putString(RESOLUTION, issue.getResolution().name()); + + // persist bounds + ReferencedEnvelope bounds = issue.getBounds(); + child.putString(MIN_X, Double.toString(bounds.getMinX())); + child.putString(MAX_X, Double.toString(bounds.getMaxX())); + child.putString(MIN_Y, Double.toString(bounds.getMinY())); + child.putString(MAX_Y, Double.toString(bounds.getMaxY())); + child.putString(CRS, bounds.getCoordinateReferenceSystem().toWKT()); + + issue.getViewMemento(child.createChild(MEMENTO_VIEW_DATA)); + issue.save(child.createChild(MEMENTO_ISSUE_DATA)); + } catch (Throwable e) { + LoggingSupport.log(IssuesActivator.getDefault(), "error when daving issue", e); //$NON-NLS-1$ + } + } + FileWriter fileWriter = new FileWriter(getLocalIssuesFile()); + try { + memento.save(fileWriter); + } finally { + fileWriter.close(); + } + } + + /** + * Reads the local issues from disk + * + * @throws IOException thrown if there was a problem reading the issues file + * @throws WorkbenchException thrown if the xml in the file is bad or doesn't conform to what + * the XMLMemento expects + */ + public void load() throws IOException, WorkbenchException { + if (getLocalIssuesFile().exists()) { + FileReader reader = new FileReader(getLocalIssuesFile()); + XMLMemento memento = XMLMemento.createReadRoot(reader); + IMemento[] children = memento.getChildren(MEMENTO_CHILD_TYPE); + for (IMemento issueMemento : children) { + try { + IIssue issue = IssuesListUtil.createIssue(issueMemento.getString(EXTENSION_ID)); + if (issue == null) { + continue; + } + IMemento dataMemento = issueMemento.getChild(MEMENTO_ISSUE_DATA); + IMemento viewMemento = issueMemento.getChild(MEMENTO_VIEW_DATA); + String issueId = issueMemento.getID(); + String groupId = issueMemento.getString(GROUP_ID); + + double minX = Double.parseDouble(issueMemento.getString(MIN_X)); + double maxX = Double.parseDouble(issueMemento.getString(MAX_X)); + double minY = Double.parseDouble(issueMemento.getString(MIN_Y)); + double maxY = Double.parseDouble(issueMemento.getString(MAX_Y)); + CoordinateReferenceSystem crs; + try { + crs = org.geotools.referencing.CRS.parseWKT(issueMemento.getString(CRS)); + } catch (FactoryException e) { + crs = null; + } + ReferencedEnvelope bounds = new ReferencedEnvelope(minX, maxX, minY, maxY, crs); + issue.init(dataMemento, viewMemento, issueId, groupId, bounds); + issue.setDescription(issueMemento.getString(DESCRIPTION)); + issue.setPriority(Priority.valueOf(issueMemento.getString(PRIORITY))); + issue.setResolution(Resolution.valueOf(issueMemento.getString(RESOLUTION))); + + list.add(issue); + } catch (Throwable e) { + LoggingSupport.log(IssuesActivator.getDefault(), "error when loading issue", e); //$NON-NLS-1$ + } + + } + } + } + + private File getLocalIssuesFile() throws IOException { + File userLocation = new File( + FileLocator.toFileURL(Platform.getInstanceLocation().getURL()).getFile()); + if (!userLocation.exists()) + userLocation.mkdirs(); + File catalogLocation = new File(userLocation, ".issues.xml"); //$NON-NLS-1$ + return catalogLocation; + } } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListUtil.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListUtil.java index 4ab3303074..0eaad11cf7 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListUtil.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/IssuesListUtil.java @@ -1,5 +1,5 @@ /** - * + * */ package org.locationtech.udig.issues; @@ -9,6 +9,7 @@ import java.util.List; import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.internal.IssuesActivator; import org.eclipse.core.runtime.CoreException; @@ -16,60 +17,58 @@ /** * @author Jesse - * + * */ public final class IssuesListUtil { - private IssuesListUtil() { - } + private IssuesListUtil() { + } - /** - * Looks up the issue type from the extension point ID. If the current - * installation does not have the extension then null is returned. Look in - * the log for the reason. - * - * @param extensionPointID - * @return - * @throws CoreException - */ - public static IIssue createIssue(String extensionPointID) { - List extensions = ExtensionPointList - .getExtensionPointList(ISSUES_EXTENSION_ID); + /** + * Looks up the issue type from the extension point ID. If the current installation does not + * have the extension then null is returned. Look in the log for the reason. + * + * @param extensionPointID + * @return + * @throws CoreException + */ + public static IIssue createIssue(String extensionPointID) { + List extensions = ExtensionPointList + .getExtensionPointList(ISSUES_EXTENSION_ID); - IConfigurationElement found = null; - for (IConfigurationElement elem : extensions) { - String namespace = elem.getNamespaceIdentifier(); - String name = elem.getAttribute("id"); //$NON-NLS-1$ - String id = namespace + "." + name; //$NON-NLS-1$ - if (extensionPointID.equals(id)) { - found = elem; - break; - } - } - if (found == null) { - IssuesActivator - .log( - "No matching issue extension was found: " + extensionPointID, null); //$NON-NLS-1$ - return null; - } + IConfigurationElement found = null; + for (IConfigurationElement elem : extensions) { + String namespace = elem.getNamespaceIdentifier(); + String name = elem.getAttribute("id"); //$NON-NLS-1$ + String id = namespace + "." + name; //$NON-NLS-1$ + if (extensionPointID.equals(id)) { + found = elem; + break; + } + } + if (found == null) { + LoggingSupport.log(IssuesActivator.getDefault(), + "No matching issue extension was found: " + extensionPointID, null); //$NON-NLS-1$ + return null; + } - Object created; - try { - created = found.createExecutableExtension(EXTENSION_CLASS_ATTR); - if (!(created instanceof IIssue)) { - IssuesActivator - .log( - "Extension found did not create an issue object: " + extensionPointID, null); //$NON-NLS-1$ - return null; - } + Object created; + try { + created = found.createExecutableExtension(EXTENSION_CLASS_ATTR); + if (!(created instanceof IIssue)) { + LoggingSupport.log(IssuesActivator.getDefault(), + "Extension found did not create an issue object: " + extensionPointID); //$NON-NLS-1$ + return null; + } - return (IIssue) created; - } catch (CoreException e) { - IssuesActivator - .log( - "An exception was raised when trying to instantiate the extension for the issue: " + extensionPointID, e); //$NON-NLS-1$ - return null; - } - } + return (IIssue) created; + } catch (CoreException e) { + LoggingSupport.log(IssuesActivator.getDefault(), + "An exception was raised when trying to instantiate the extension for the issue: " //$NON-NLS-1$ + + extensionPointID, + e); + return null; + } + } } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesActivator.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesActivator.java index 4360dd33ea..0fb316fab1 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesActivator.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesActivator.java @@ -11,6 +11,7 @@ package org.locationtech.udig.issues.internal; import org.locationtech.udig.core.AbstractUdigUIPlugin; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.IIssuesManager; import org.locationtech.udig.ui.ProgressManager; @@ -46,22 +47,25 @@ public IssuesActivator() { /* * (non-Javadoc) - * + * * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) */ + @Override public void start(BundleContext context) throws Exception { super.start(context); INSTANCE = this; PlatformUI.getWorkbench().addWorkbenchListener(new IWorkbenchListener() { + @Override public void postShutdown(IWorkbench workbench) { } + @Override public boolean preShutdown(IWorkbench workbench, boolean forced) { try { IIssuesManager.defaultInstance.save(ProgressManager.instance().get()); } catch (Exception e) { - log("Error saving issues", e); //$NON-NLS-1$ + LoggingSupport.log(getDefault(), "Error saving issues", e); //$NON-NLS-1$ boolean result = MessageDialog.openQuestion(Display.getCurrent() .getActiveShell(), Messages.IssuesActivator_errorTitle, Messages.IssuesActivator_errorMessage); @@ -74,28 +78,16 @@ public boolean preShutdown(IWorkbench workbench, boolean forced) { }); } - /** - * Writes an info log in the plugin's log. - *

    - * This should be used for user level messages. - *

    - */ - public static void log(String message2, Throwable e) { - String message = message2; - if (message == null) - message = "Error in Issues plugin:" + e; //$NON-NLS-1$ - getDefault().getLog().log(new Status(IStatus.INFO, PLUGIN_ID, IStatus.OK, message, e)); - } - public static IssuesActivator getDefault() { return INSTANCE; } /* * (non-Javadoc) - * + * * @see org.locationtech.udig.core.AbstractUdigUIPlugin#getIconPath() */ + @Override public IPath getIconPath() { return new Path(ICONS_PATH); } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesManager.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesManager.java index b8feb84e57..001cd5c9d7 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesManager.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesManager.java @@ -21,6 +21,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.IIssue; import org.locationtech.udig.issues.IIssuesList; import org.locationtech.udig.issues.IIssuesManager; @@ -52,10 +53,13 @@ */ public class IssuesManager extends Object implements IIssuesManager { - private volatile IIssuesList issuesList; + private volatile IIssuesList issuesList; + private volatile DirtyIssueList dirtyListener; - private Collection listeners=new CopyOnWriteArraySet(); - private Collection listListeners=new CopyOnWriteArraySet(); + + private Collection listeners = new CopyOnWriteArraySet<>(); + + private Collection listListeners = new CopyOnWriteArraySet<>(); public IssuesManager() { setIssuesList(createListFromPreferences()); @@ -71,7 +75,7 @@ static IIssuesList createListFromPreferences() { String listID = preferenceStore.getString(IssuesPreferencePage.PREFERENCE_ID); List extensions = ExtensionPointList .getExtensionPointList(IssueConstants.ISSUES_LIST_EXTENSION_ID); - for( IConfigurationElement element : extensions ) { + for (IConfigurationElement element : extensions) { String string = element.getNamespaceIdentifier() + "." + element.getAttribute("id");//$NON-NLS-1$//$NON-NLS-2$ if ((string).equals(listID)) { try { @@ -80,15 +84,15 @@ static IIssuesList createListFromPreferences() { if (config != null) { IssuesListConfigurator configurator = (IssuesListConfigurator) element .createExecutableExtension("configurator"); //$NON-NLS-1$ - String data = preferenceStore.getString(IssuesPreferencePage.PREFERENCE_ID - + "/" + listID); //$NON-NLS-1$ + String data = preferenceStore + .getString(IssuesPreferencePage.PREFERENCE_ID + "/" + listID); //$NON-NLS-1$ XMLMemento memento = XMLMemento.createReadRoot(new StringReader(data)); configurator.initConfiguration(issuesList, memento); } break; } catch (CoreException e) { issuesList = null; - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); } } } @@ -96,40 +100,44 @@ static IIssuesList createListFromPreferences() { if (issuesList == null) { issuesList = new IssuesList(); } - - if( issuesList instanceof IRemoteIssuesList ){ + + if (issuesList instanceof IRemoteIssuesList) { try { - ((IRemoteIssuesList)issuesList).refresh(); + ((IRemoteIssuesList) issuesList).refresh(); } catch (IOException e) { - IssuesActivator.log("failed to refresh issues list", e); //$NON-NLS-1$ - issuesList=new IssuesList(); + LoggingSupport.log(IssuesActivator.getDefault(), "failed to refresh issues list", //$NON-NLS-1$ + e); + issuesList = new IssuesList(); } - }else if (issuesList instanceof IssuesList){ - ((IssuesList)issuesList).load(); + } else if (issuesList instanceof IssuesList) { + ((IssuesList) issuesList).load(); } return issuesList; } + @Override public IIssuesList getIssuesList() { return issuesList; } - public void addIssuesListListener( IIssuesListListener listener ) { + @Override + public void addIssuesListListener(IIssuesListListener listener) { if (listener == null) throw new NullPointerException(); issuesList.addListener(listener); listListeners.add(listener); } - public void removeIssuesListListener( IIssuesListListener listener ) { + @Override + public void removeIssuesListListener(IIssuesListListener listener) { if (listener == null) throw new NullPointerException(); issuesList.removeListener(listener); listListeners.remove(listener); } - public void removeIssues( String groupId ) { + public void removeIssues(String groupId) { if (groupId == null) throw new NullPointerException(); issuesList.removeIssues(groupId); @@ -139,82 +147,88 @@ public Set getGroups() { return issuesList.getGroups(); } - public List getIssues( String groupId ) { + public List getIssues(String groupId) { if (groupId == null) throw new NullPointerException(); return issuesList.getIssues(groupId); } - public void setIssuesList( IIssuesList newList ) { - Object lock=issuesList==null?this:issuesList; + @Override + public void setIssuesList(IIssuesList newList) { + Object lock = issuesList == null ? this : issuesList; synchronized (lock) { if (newList == null) throw new NullPointerException(); if (issuesList != null) { issuesList.removeListener(dirtyListener); - for( IIssue issue : issuesList ) { + for (IIssue issue : issuesList) { issue.removeIssueListener(dirtyListener); } } - + IIssuesList oldList = issuesList; issuesList = newList; testIssues(newList, null); this.dirtyListener = new DirtyIssueList(); issuesList.addListener(dirtyListener); - - IssuesActivator.getDefault().getPreferenceStore().setValue(PREFERENCE_ID, newList.getExtensionID()); - - for( IIssuesListListener l : listListeners ) { + + IssuesActivator.getDefault().getPreferenceStore().setValue(PREFERENCE_ID, + newList.getExtensionID()); + + for (IIssuesListListener l : listListeners) { issuesList.addListener(l); } - - for( IIssue issue : newList ) { + + for (IIssue issue : newList) { issue.addIssueListener(dirtyListener); } - - notifyListeners( newList, oldList, IssuesManagerEventType.ISSUES_LIST_CHANGE ); + + notifyListeners(newList, oldList, IssuesManagerEventType.ISSUES_LIST_CHANGE); } - + } - private void notifyListeners( Object newValue, Object oldValue, IssuesManagerEventType type ) { - if( type==IssuesManagerEventType.DIRTY_ISSUE && !(issuesList instanceof IRemoteIssuesList)) + private void notifyListeners(Object newValue, Object oldValue, IssuesManagerEventType type) { + if (type == IssuesManagerEventType.DIRTY_ISSUE + && !(issuesList instanceof IRemoteIssuesList)) return; - - IssuesManagerEvent event=new IssuesManagerEvent(this, type, newValue, oldValue); - for( IIssuesManagerListener listener : listeners ) { + + IssuesManagerEvent event = new IssuesManagerEvent(this, type, newValue, oldValue); + for (IIssuesManagerListener listener : listeners) { listener.notifyChange(event); } } + @Override public boolean save(IProgressMonitor monitor) throws IOException { - if (!(issuesList instanceof IRemoteIssuesList)){ - if (issuesList instanceof IssuesList ){ - ((IssuesList)issuesList).save(); - } + if (!(issuesList instanceof IRemoteIssuesList)) { + if (issuesList instanceof IssuesList) { + ((IssuesList) issuesList).save(); + } return false; } - - Object lock=issuesList==null?this:issuesList; - final boolean[] result= new boolean[1]; - result[0]=false; - final Collection dirtyIssues=new ArrayList(); + Object lock = issuesList == null ? this : issuesList; + final boolean[] result = new boolean[1]; + result[0] = false; + final Collection dirtyIssues = new ArrayList<>(); synchronized (lock) { - monitor.beginTask(Messages.IssuesManager_task_title, dirtyListener.dirtyIssues.size()+1); + monitor.beginTask(Messages.IssuesManager_task_title, + dirtyListener.dirtyIssues.size() + 1); monitor.worked(1); - + final IOException[] exception = new IOException[1]; try { - PlatformGIS.runBlockingOperation(new IRunnableWithProgress(){ - - public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { - + PlatformGIS.runBlockingOperation(new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + dirtyIssues.addAll(dirtyListener.dirtyIssues); IRemoteIssuesList list = (IRemoteIssuesList) issuesList; - for( IIssue issue : dirtyListener.dirtyIssues ) { + for (IIssue issue : dirtyListener.dirtyIssues) { result[0] = true; try { list.save(issue); @@ -224,50 +238,54 @@ public void run( IProgressMonitor monitor ) throws InvocationTargetException, In } } } - + }, monitor); } catch (Exception e) { - IssuesActivator.log("Error saving issues", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "Error saving issues", e); //$NON-NLS-1$ } - + if (exception[0] != null) throw exception[0]; - } + } monitor.done(); notifyListeners(null, dirtyIssues, IssuesManagerEventType.SAVE); - + return result[0]; } - public void addListener( IIssuesManagerListener listener ) { + @Override + public void addListener(IIssuesManagerListener listener) { listeners.add(listener); } - public void removeListener( IIssuesManagerListener listener ) { + @Override + public void removeListener(IIssuesManagerListener listener) { listeners.remove(listener); } + @Override public boolean isDirty() { return !dirtyListener.dirtyIssues.isEmpty() && (issuesList instanceof IRemoteIssuesList); } - /** * Keeps track of which issues in the list are dirty. - * + * * @author Jesse * @since 1.1.0 */ public class DirtyIssueList implements IIssuesListListener, IIssueListener { - Collection dirtyIssues = new CopyOnWriteArraySet(); - public void notifyChange( IssuesListEvent event ) { - switch( event.getType() ) { + Collection dirtyIssues = new CopyOnWriteArraySet<>(); + + @Override + public void notifyChange(IssuesListEvent event) { + switch (event.getType()) { case ADD: testIssues(event.getChanged(), this); break; case REMOVE: - for( IIssue issue : event.getChanged() ) { + for (IIssue issue : event.getChanged()) { issue.removeIssueListener(this); } break; @@ -282,24 +300,28 @@ public void notifyChange( IssuesListEvent event ) { break; } } - public void notifyChanged( IssueEvent event ) { - Boolean oldValue = dirtyIssues.isEmpty()?Boolean.FALSE:Boolean.TRUE; + + @Override + public void notifyChanged(IssueEvent event) { + Boolean oldValue = dirtyIssues.isEmpty() ? Boolean.FALSE : Boolean.TRUE; dirtyIssues.add(event.getSource()); notifyListeners(Boolean.TRUE, oldValue, IssuesManagerEventType.DIRTY_ISSUE); } - public void notifyPropertyChanged( IssuePropertyChangeEvent event ) { - Boolean oldValue = dirtyIssues.isEmpty()?Boolean.FALSE:Boolean.TRUE; + + @Override + public void notifyPropertyChanged(IssuePropertyChangeEvent event) { + Boolean oldValue = dirtyIssues.isEmpty() ? Boolean.FALSE : Boolean.TRUE; dirtyIssues.add(event.getSource()); notifyListeners(Boolean.TRUE, oldValue, IssuesManagerEventType.DIRTY_ISSUE); } } - void testIssues( Collection< ? extends IIssue> issueList, IIssueListener listener ) { - final Collection toRemove=new ArrayList(); - for( IIssue issue : issueList ) { - try{ - + void testIssues(Collection issueList, IIssueListener listener) { + final Collection toRemove = new ArrayList<>(); + for (IIssue issue : issueList) { + try { + // testing to ensure that the issue is a valid issue issue.getBounds(); issue.getDescription(); @@ -314,24 +336,24 @@ void testIssues( Collection< ? extends IIssue> issueList, IIssueListener listene issue.getPropertyNames(); issue.getResolution(); issue.getViewPartId(); - - if( listener!=null ) + + if (listener != null) issue.addIssueListener(listener); - }catch (Throwable t) { + } catch (Throwable t) { toRemove.add(issue); } } - if( !toRemove.isEmpty() ){ - PlatformGIS.run(new IRunnableWithProgress(){ - - public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { + if (!toRemove.isEmpty()) { + PlatformGIS.run(new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { issuesList.removeAll(toRemove); } - + }); } } - - } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferenceInitializer.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferenceInitializer.java index 20dc854d62..5b13eee4ca 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferenceInitializer.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferenceInitializer.java @@ -23,10 +23,11 @@ import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; import org.eclipse.jface.preference.IPreferenceStore; +import org.locationtech.udig.core.logging.LoggingSupport; /** * Initialize preferences - * + * * @author Jesse * @since 1.1.0 */ @@ -39,9 +40,9 @@ public void initializeDefaultPreferences() { preferenceStore.setDefault(KEY_VIEW_CONTENT_PROVIDER, ""); //$NON-NLS-1$ preferenceStore.setDefault(KEY_VIEW_EXPANSION_PROVIDER, ""); //$NON-NLS-1$ preferenceStore.setDefault(KEY_VIEW_SORTER, ""); //$NON-NLS-1$ - + URL url=IssuesActivator.getDefault().getBundle().getEntry(".config"); //$NON-NLS-1$ - + InputStream in = null; InputStreamReader reader = null; try { @@ -58,8 +59,8 @@ public void initializeDefaultPreferences() { String substring = buffer.substring(0, buffer.length()-1); preferenceStore.setDefault(KEY_ACTIVE_LIST, substring); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ - preferenceStore.setDefault(KEY_ACTIVE_LIST, VALUE_MEMORY_LIST); + LoggingSupport.log(IssuesActivator.getDefault(), e); + preferenceStore.setDefault(KEY_ACTIVE_LIST, VALUE_MEMORY_LIST); }finally{ try { if( in!=null ) @@ -67,7 +68,7 @@ public void initializeDefaultPreferences() { if( reader!=null) reader.close(); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); } } } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferencePage.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferencePage.java index 2d0a2f4dc0..7ce126d22d 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferencePage.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/IssuesPreferencePage.java @@ -22,6 +22,7 @@ import java.util.Map; import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.IIssuesList; import org.locationtech.udig.issues.IIssuesManager; import org.locationtech.udig.issues.IIssuesPreferencePage; @@ -55,7 +56,7 @@ /** * The Preference Page for configuring what issues list is used. - * + * * @author Jesse * @since 1.1.0 */ @@ -69,14 +70,14 @@ public class IssuesPreferencePage extends PreferencePage implements IWorkbenchPr private List extensionMapping; private List names; private ListData issuesList; - private Map lists=new HashMap(); + private Map lists=new HashMap<>(); private Composite progressArea; public IssuesPreferencePage() { - super(Messages.IssuesPreferencePage_pageTitle); - setDescription(Messages.IssuesPreferencePage_pageDesc); + super(Messages.IssuesPreferencePage_pageTitle); + setDescription(Messages.IssuesPreferencePage_pageDesc); setPreferenceStore(IssuesActivator.getDefault().getPreferenceStore()); - + //Ping the issues manager to make sure it is initialized IIssuesManager.defaultInstance.getIssuesList(); } @@ -100,7 +101,7 @@ private void createProgressArea( Composite composite ) { data.horizontalSpan=2; data.heightHint=50; progressArea.setLayoutData(data); - + } private void createConfigArea( Composite c ) { @@ -118,10 +119,12 @@ private void createCombo( Composite c ) { combo.select(getCurrentIndex()); combo.addSelectionListener(new SelectionListener(){ + @Override public void widgetDefaultSelected( SelectionEvent e ) { widgetSelected(e); } + @Override public void widgetSelected( SelectionEvent e ) { createList(); } @@ -132,7 +135,7 @@ public void widgetSelected( SelectionEvent e ) { void createList() { setErrorMessage(null); - setMessage(getTitle()); + setMessage(getTitle()); int selectionIndex = combo.getSelectionIndex(); IConfigurationElement elem=extensionMapping.get(selectionIndex); ListData data=new ListData(selectionIndex); @@ -144,13 +147,13 @@ void createList() { if( data==issuesList ) return; - + try { storeCurrentConfiguration(); } catch (Exception e2) { - IssuesActivator.log("", e2); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e2); //$NON-NLS-1$ } - + try { createList(elem, data); if( data.configurator!=ERROR_CONFIG) @@ -160,8 +163,8 @@ void createList() { issuesList=data; } catch (Exception e1) { data.configurator=ERROR_CONFIG; - setErrorMessage(Messages.IssuesPreferencePage_ListCreationError); - IssuesActivator.log("",e1); //$NON-NLS-1$ + setErrorMessage(Messages.IssuesPreferencePage_ListCreationError); + LoggingSupport.log(IssuesActivator.getDefault(),e1); //$NON-NLS-1$ } } @@ -188,13 +191,13 @@ private void createList( IConfigurationElement elem, ListData data ) throws Core } } if( data.configurator==ERROR_CONFIG ) - setErrorMessage(Messages.IssuesPreferencePage_ListCreationError); + setErrorMessage(Messages.IssuesPreferencePage_ListCreationError); } private void createConfiguration( IConfigurationElement elem, ListData data ) throws CoreException { if( data.configurator!=null ) return; - + if( elem.getAttribute("configurator")==null ){ //$NON-NLS-1$ data.configurator=null; return; @@ -207,7 +210,7 @@ private void createConfiguration( IConfigurationElement elem, ListData data ) th setErrorMessage("An error occurred while creating the configuration panel for this issues list. Please choose another."); //$NON-NLS-1$ } } - + protected IMemento createMemento( ListData data ) { try { String id = getId(data.index); @@ -240,7 +243,7 @@ private void createLabel( Composite parent, Composite c ) { GridData gridData = new GridData(SWT.NONE, SWT.NONE, false, false); gridData.verticalAlignment=SWT.CENTER; label.setLayoutData(gridData); - label.setText(Messages.IssuesPreferencePage_currentLabelText); + label.setText(Messages.IssuesPreferencePage_currentLabelText); } private int getCurrentIndex() { @@ -281,7 +284,7 @@ private List getExtensionList() { } private void processExtensionPoint() { - names=new ArrayList(); + names=new ArrayList<>(); extensionMapping=ExtensionPointList.getExtensionPointList(IssueConstants.ISSUES_LIST_EXTENSION_ID); for( IConfigurationElement element : extensionMapping ) { names.add(element.getAttribute("name")); //$NON-NLS-1$ @@ -293,7 +296,7 @@ protected void performDefaults() { combo.select(indexOf(getPreferenceStore().getDefaultString(PREFERENCE_ID))); createList(); } - + @Override public boolean performOk() { if( issuesList.configurator==ERROR_CONFIG ) @@ -304,15 +307,16 @@ public boolean performOk() { final int selectionIndex = combo.getSelectionIndex(); runWithProgress(true, new IRunnableWithProgress(){ + @Override public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { - monitor.beginTask(Messages.IssuesPreferencePage_TestTaskName, IProgressMonitor.UNKNOWN); + monitor.beginTask(Messages.IssuesPreferencePage_TestTaskName, IProgressMonitor.UNKNOWN); if ( issuesList.configurator.isConfigured() ){ storeListIDInPrefs(selectionIndex); try { storeCurrentConfiguration(); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ - throw new InvocationTargetException(e,Messages.IssuesPreferencePage_StorageError); + LoggingSupport.log(IssuesActivator.getDefault(), e); + throw new InvocationTargetException(e,Messages.IssuesPreferencePage_StorageError); } configured[0]=true; } else { @@ -320,21 +324,21 @@ public void run( IProgressMonitor monitor ) throws InvocationTargetException, In } monitor.done(); } - + }); if( !configured[0] ){ setErrorMessage(issuesList.configurator.getError()); - getPreferenceStore().setValue(PREFERENCE_ID, + getPreferenceStore().setValue(PREFERENCE_ID, getPreferenceStore().getDefaultString(PREFERENCE_ID)); }else{ setErrorMessage(""); //$NON-NLS-1$ setList(); } - + return configured[0]; } catch (Exception e) { - setErrorMessage(Messages.IssuesPreferencePage_testError+e.getLocalizedMessage()); + setErrorMessage(Messages.IssuesPreferencePage_testError+e.getLocalizedMessage()); return false; } } @@ -344,7 +348,7 @@ public void run( IProgressMonitor monitor ) throws InvocationTargetException, In setList(); return super.performOk(); } - + private void storeListIDInPrefs( final int selectionIndex ) { // String id = getExtensionList().get(selectionIndex).getAttribute("id"); //$NON-NLS-1$ @@ -365,7 +369,7 @@ private void setList() { protected String getXMLConfiguration() throws IOException { if( issuesList==null || issuesList.configurator==null || issuesList.configurator==ERROR_CONFIG ) return null; - + XMLMemento memento=XMLMemento.createWriteRoot("configuration"); //$NON-NLS-1$ issuesList.configurator.getConfiguration(memento); StringWriter stringWriter=new StringWriter(); @@ -375,6 +379,7 @@ protected String getXMLConfiguration() throws IOException { return configuration; } + @Override public void runWithProgress( boolean mayBlock, final IRunnableWithProgress runnable ) throws InvocationTargetException, InterruptedException { if (Display.getCurrent() == null) @@ -391,26 +396,32 @@ public void runWithProgress( boolean mayBlock, final IRunnableWithProgress runna } + @Override public void init( IWorkbench workbench ) { } - - + + protected static final IssuesListConfigurator ERROR_CONFIG = new IssuesListConfigurator(){ + @Override public void getConfiguration( IMemento memento ) { } + @Override public Control getControl( Composite parent, IIssuesPreferencePage page ) { return null; } + @Override public String getError() { return null; } + @Override public void initConfiguration( IIssuesList list, IMemento memento ) { } + @Override public boolean isConfigured() { return false; } @@ -423,5 +434,5 @@ private static class ListData{ final int index; ListData(int index){ this.index=index; } } - + } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/FeatureCollectionToIssueCollectionAdapter.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/FeatureCollectionToIssueCollectionAdapter.java index 2681cfb7a3..a5fa2af391 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/FeatureCollectionToIssueCollectionAdapter.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/FeatureCollectionToIssueCollectionAdapter.java @@ -21,6 +21,7 @@ import org.geotools.geometry.jts.ReferencedEnvelope; import org.locationtech.udig.core.enums.Priority; import org.locationtech.udig.core.enums.Resolution; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.IIssue; import org.locationtech.udig.issues.IssuesListUtil; import org.locationtech.udig.issues.internal.IssuesActivator; @@ -30,10 +31,10 @@ /** * Converts a features collection(issues that have been saved as features) to a collection of issues. - * + * * Note a DefaultFeatureCollection is explicitly used in order to force the contents * into memory (allowing us to use an iterator through memory). - * + * * @author Jesse * @since 1.1.0 */ @@ -50,33 +51,36 @@ public FeatureCollectionToIssueCollectionAdapter( FeatureCollection iterator() { final FeatureIterator iter = features.features(); - + return new Iterator(){ - + + @Override public boolean hasNext() { return iter.hasNext(); } + @Override public IIssue next() { SimpleFeature feature = iter.next(); String extensionPointID=(String) feature.getAttribute(mapper.getExtensionId()); try{ IIssue issue = IssuesListUtil.createIssue(extensionPointID); - + if( issue==null ){ return createPlaceHolder(feature, extensionPointID); } - + initIssue(feature,issue); - + return issue; } catch (Throwable e) { - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); return createPlaceHolder(feature, extensionPointID); } - + } + @Override public void remove() { iter.close(); } @@ -86,7 +90,7 @@ protected void initIssue( SimpleFeature feature, IIssue issue ) { String viewData=(String) feature.getAttribute(mapper.getViewMemento()); String groupId=(String) feature.getAttribute(mapper.getGroupId()); String id=(String) feature.getAttribute(mapper.getId()); - + String resolutionInt=(String) feature.getAttribute(mapper.getResolution()); String priorityInt=(String) feature.getAttribute(mapper.getPriority()); String description=(String) feature.getAttribute(mapper.getDescription()); @@ -97,12 +101,12 @@ protected void initIssue( SimpleFeature feature, IIssue issue ) { Priority priority=Priority.valueOf(priorityInt); if( priority==null ) priority=Priority.WARNING; - + issue.setDescription(description); issue.setResolution(resolution); issue.setPriority(priority); - + XMLMemento issueMemento=null; if (mementoData != null) { try { @@ -119,12 +123,12 @@ protected void initIssue( SimpleFeature feature, IIssue issue ) { viewMemento = null; } } - + ReferencedEnvelope env = new ReferencedEnvelope(feature.getBounds()); issue.init(issueMemento, viewMemento, id, groupId, env); } - + protected IIssue createPlaceHolder( SimpleFeature feature, String extensionId ) { PlaceholderIssue issue=new PlaceholderIssue(); issue.setExtensionID(extensionId); diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/IssuesCollectionToFeatureCollection.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/IssuesCollectionToFeatureCollection.java index fbca190836..ee82349559 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/IssuesCollectionToFeatureCollection.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/datastore/IssuesCollectionToFeatureCollection.java @@ -16,6 +16,7 @@ import org.locationtech.udig.core.enums.Priority; import org.locationtech.udig.core.enums.Resolution; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.IIssue; import org.locationtech.udig.issues.internal.IssuesActivator; import org.locationtech.udig.issues.internal.Messages; @@ -50,13 +51,13 @@ public class IssuesCollectionToFeatureCollection extends AdaptorFeatureCollectio private final ReferencedEnvelope DEFAULT_BOUNDS=new ReferencedEnvelope(-180,180,-90,90, DefaultGeographicCRS.WGS84); private Collection issues; private FeatureTypeAttributeMapper mapper; - + public IssuesCollectionToFeatureCollection(Collection issues, FeatureTypeAttributeMapper mapper){ super("Issues To Issues FeatureCollection", mapper.getSchema()); this.issues=issues; this.mapper=mapper; } - + @Override protected void closeIterator( Iterator close ) { } @@ -65,21 +66,23 @@ protected void closeIterator( Iterator close ) { protected Iterator openIterator() { return new Iterator(){ Iterator iter=issues.iterator(); + @Override public boolean hasNext() { return iter.hasNext(); } + @Override public SimpleFeature next() { IIssue issue = iter.next(); String extId=issue.getExtensionID(); String groupId=issue.getGroupId(); - + String id=issue.getId(); - + String resolution=issue.getResolution().name(); String priority=issue.getPriority().name(); String description=issue.getDescription(); - + String viewMemento=createViewMemento(issue); String issueMemento=createIssueMemento(issue); @@ -92,7 +95,7 @@ public SimpleFeature next() { bounds=toMultiPolygon(DEFAULT_BOUNDS); feature.setAttribute(mapper.getBounds(), bounds); if( groupId==null ) - groupId=Messages.IssuesCollectionToFeatureCollection_defaultGroup; + groupId=Messages.IssuesCollectionToFeatureCollection_defaultGroup; feature.setAttribute(mapper.getGroupId(), groupId); feature.setAttribute(mapper.getId(), id); if( resolution==null ) @@ -114,10 +117,11 @@ public SimpleFeature next() { } } + @Override public void remove() { iter.remove(); } - + }; } @@ -128,12 +132,12 @@ protected Geometry createBounds( IIssue issue ) { return toPolygon(issue.getBounds()); } - + protected MultiPolygon toMultiPolygon(ReferencedEnvelope env2){ GeometryFactory factory=new GeometryFactory(); return factory.createMultiPolygon(new Polygon[]{ toPolygon(env2)} ); } - + protected Polygon toPolygon(ReferencedEnvelope env2){ ReferencedEnvelope env=env2; if( env==null ) @@ -141,18 +145,18 @@ protected Polygon toPolygon(ReferencedEnvelope env2){ AttributeDescriptor att=mapper.getSchema().getDescriptor(mapper.getBounds()); CoordinateReferenceSystem crs=null; - + if( att instanceof GeometryDescriptor ) crs=((GeometryDescriptor)att).getCoordinateReferenceSystem(); - + if( crs==null ) crs=DefaultGeographicCRS.WGS84; - + GeometryFactory factory=new GeometryFactory(); - try{ - env=env.transform(crs, true); - }catch(Exception e){ - IssuesActivator.log("", e); //$NON-NLS-1$ + try { + env = env.transform(crs, true); + } catch (Exception e) { + LoggingSupport.log(IssuesActivator.getDefault(), e); } return factory.createPolygon(factory.createLinearRing(new Coordinate[]{ @@ -161,10 +165,10 @@ protected Polygon toPolygon(ReferencedEnvelope env2){ new Coordinate(env.getMaxX(), env.getMaxY()), new Coordinate(env.getMinX(), env.getMaxY()), new Coordinate(env.getMinX(), env.getMinY()), - + }), new LinearRing[0]); } - + protected String createIssueMemento( IIssue issue ) { StringWriter out; @@ -175,7 +179,7 @@ protected String createIssueMemento( IIssue issue ) { try { memento.save(out); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); } return out.toString(); } @@ -187,7 +191,7 @@ protected String createViewMemento( IIssue issue ) { try { memento.save(out); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); } return out.toString(); } diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesView.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesView.java index 6d92c6712a..9b3ba23d80 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesView.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesView.java @@ -63,6 +63,7 @@ import org.eclipse.ui.part.ViewPart; import org.locationtech.udig.core.enums.Resolution; import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.Column; import org.locationtech.udig.issues.IIssue; import org.locationtech.udig.issues.IIssuesContentProvider; @@ -80,7 +81,6 @@ import org.locationtech.udig.issues.listeners.IIssuesManagerListener; import org.locationtech.udig.issues.listeners.IssuesListEvent; import org.locationtech.udig.issues.listeners.IssuesManagerEvent; -import org.locationtech.udig.project.ui.internal.ProjectUIPlugin; import org.locationtech.udig.ui.PlatformGIS; import org.locationtech.udig.ui.ProgressManager; @@ -282,7 +282,7 @@ private T load(String expectedConfigurationElementName, String preferenceID, } } } catch (Exception e) { - IssuesActivator.log("Error loading Issues View Content Provider", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "Error loading Issues View Content Provider", e); //$NON-NLS-1$ } return defaultValue; } @@ -382,8 +382,7 @@ public void runWithEvent(Event event) { return; if (!(sel.getFirstElement() instanceof IIssue)) { - ProjectUIPlugin.log("IssuesView somehow has a non Issue Selected", //$NON-NLS-1$ - null); + LoggingSupport.log(IssuesActivator.getDefault(), "IssuesView somehow has a non Issue Selected"); //$NON-NLS-1$ return; } boolean doDelete; @@ -553,7 +552,7 @@ public void runWithEvent(Event event) { try { issuesManager.save(ProgressManager.instance().get()); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); //$NON-NLS-1$ } } }; @@ -580,7 +579,7 @@ public void runWithEvent(Event event) { try { ((IRemoteIssuesList) list).refresh(); } catch (IOException e) { - IssuesActivator.log("", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), e); //$NON-NLS-1$ } } }; @@ -642,7 +641,7 @@ public void dispose() { try { IIssuesManager.defaultInstance.save(ProgressManager.instance().get()); } catch (IOException e) { - IssuesActivator.log("Error Saving issues List!!!", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "Error Saving issues List!!!", e); //$NON-NLS-1$ } updateTimerJob.cancel(); disposeListeners(); diff --git a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesViewRefresher.java b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesViewRefresher.java index fa2703a2fa..21c073e4f4 100644 --- a/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesViewRefresher.java +++ b/plugins/org.locationtech.udig.issues/src/org/locationtech/udig/issues/internal/view/IssuesViewRefresher.java @@ -9,6 +9,7 @@ */ package org.locationtech.udig.issues.internal.view; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.issues.IRefreshControl; import org.locationtech.udig.issues.IssueConstants; import org.locationtech.udig.issues.internal.IssuesActivator; @@ -20,7 +21,7 @@ /** * Handles refreshing the issues viewer - * + * * @author Jesse * @since 1.1.0 */ @@ -28,18 +29,22 @@ public class IssuesViewRefresher implements IRefreshControl { IssuesView view; + @Override public void refresh() { refresh(true); } + @Override public void refresh( boolean updateLabels ) { getView().refresh(updateLabels); } + @Override public void refresh( Object element ) { refresh(element); } + @Override public void refresh( Object element, boolean updateLabels ) { getView().refresh(element, updateLabels); } @@ -47,20 +52,21 @@ public void refresh( Object element, boolean updateLabels ) { private IssuesView getView() { final IViewPart[] view =new IViewPart[1]; Runnable runnable = new Runnable(){ + @Override public void run() { view[0]=PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(IssueConstants.VIEW_ID); if( view[0]==null ){ try { view[0]=PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(IssueConstants.VIEW_ID); } catch (PartInitException e) { - IssuesActivator.log("Error finding issues view", e); //$NON-NLS-1$ + LoggingSupport.log(IssuesActivator.getDefault(), "Error finding issues view", e); //$NON-NLS-1$ } } } }; - + PlatformGIS.syncInDisplayThread(runnable); - + return (IssuesView) view[0]; } diff --git a/plugins/org.locationtech.udig.printing.ui/src/org/locationtech/udig/printing/ui/actions/CreatePageAction.java b/plugins/org.locationtech.udig.printing.ui/src/org/locationtech/udig/printing/ui/actions/CreatePageAction.java index f1bfe90bb4..4f4ce6d29a 100644 --- a/plugins/org.locationtech.udig.printing.ui/src/org/locationtech/udig/printing/ui/actions/CreatePageAction.java +++ b/plugins/org.locationtech.udig.printing.ui/src/org/locationtech/udig/printing/ui/actions/CreatePageAction.java @@ -46,9 +46,8 @@ import org.locationtech.udig.project.internal.Project; import org.locationtech.udig.project.ui.ApplicationGIS; import org.locationtech.udig.project.ui.internal.ApplicationGISInternal; -import org.locationtech.udig.project.ui.internal.MapEditorPart; -import org.locationtech.udig.project.ui.internal.MapEditorWithPalette; import org.locationtech.udig.project.ui.internal.MapPart; +import org.locationtech.udig.project.ui.render.displayAdapter.ViewportPane; /** * Creates a page using the current map @@ -62,9 +61,9 @@ public class CreatePageAction implements IEditorActionDelegate { @Override public void run(IAction action) { - MapPart mapEditor = ApplicationGISInternal.getActiveMapPart(); + MapPart mapPart = ApplicationGISInternal.getActiveMapPart(); - if (mapEditor == null) { + if (mapPart == null) { MessageDialog.openError(Display.getDefault().getActiveShell(), Messages.CreatePageAction_printError_title, Messages.CreatePageAction_printError_text); @@ -79,28 +78,19 @@ public void run(IAction action) { Map map = null; Project project = null; - Map oldMap = mapEditor.getAdapter(Map.class); + Map oldMap = mapPart.getAdapter(Map.class); project = oldMap.getProjectInternal(); try { map = EcoreUtil.copy(oldMap); } catch (Throwable t) { // unable to copy map? - t.printStackTrace(); + PrintingPlugin.log("Something went wrong to create a copy of the map", t); return; } project.getElementsInternal().add(map); - Point partSize; - if (mapEditor instanceof MapEditorPart) { - MapEditorPart part = (MapEditorPart) mapEditor; - partSize = part.getComposite().getSize(); - } else if (mapEditor instanceof MapEditorWithPalette) { - MapEditorWithPalette part = (MapEditorWithPalette) mapEditor; - partSize = part.getComposite().getSize(); - } else { - partSize = new Point(500, 500); - } + Point partSize = getViewportPaneSize(mapPart); Page page = createPage(template, map, project, partSize); ApplicationGIS.openProjectElement(page, false); @@ -108,21 +98,37 @@ public void run(IAction action) { } } + private Point getViewportPaneSize(MapPart mapPart) { + if (mapPart == null) { + return null; + } + + ViewportPane viewportPane = mapPart.getAdapter(ViewportPane.class); + if (viewportPane == null) { + PrintingPlugin.log("MapPart " + mapPart.getClass().getName() + " can't be adapted to ViewportPane", null); + return null; + } + + int viewportWidth = viewportPane.getWidth(); + int viewportHeight = viewportPane.getHeight(); + if (viewportWidth <= 0 || viewportHeight <= 0) { + return null; + } + return new Point(viewportWidth, viewportHeight); + } + private Page createPage(Template template, Map map, Project project, Point partSize) { - int width = 800; - int height = 600; + Dimension pageDimension = null; if (partSize != null) { - width = partSize.x; - height = partSize.y; + pageDimension = new Dimension(partSize.x, partSize.y); } else { PageFormat pageFormat = PrinterJob.getPrinterJob().defaultPage(); - width = Double.valueOf(pageFormat.getImageableWidth()).intValue(); - height = Double.valueOf(pageFormat.getImageableHeight()).intValue(); + pageDimension = new Dimension(Double.valueOf(pageFormat.getImageableWidth()).intValue(), Double.valueOf(pageFormat.getImageableHeight()).intValue()); } Page page = ModelFactory.eINSTANCE.createPage(); - page.setSize(new Dimension(width, height)); + page.setSize(pageDimension); MessageFormat formatter = new MessageFormat("{0} - " + template.getAbbreviation(), Locale //$NON-NLS-1$ .getDefault()); diff --git a/plugins/org.locationtech.udig.project.ui.editor/plugin.properties b/plugins/org.locationtech.udig.project.ui.editor/plugin.properties index f79ce0fb0b..7629cb4394 100644 --- a/plugins/org.locationtech.udig.project.ui.editor/plugin.properties +++ b/plugins/org.locationtech.udig.project.ui.editor/plugin.properties @@ -18,7 +18,6 @@ layer.new.label = New Layer layerSummary = &Layer Summary map.new.label = New Map mapEditor.name = Map Editor -mapEditorPalette.name = Map Editor Palette modifyActionSet.description = Modify and Edit information modifyActionSet.label = Modify Actions mylarAction.label = Mylar diff --git a/plugins/org.locationtech.udig.project.ui.editor/plugin.xml b/plugins/org.locationtech.udig.project.ui.editor/plugin.xml index aa1cf24f68..fa286d7691 100644 --- a/plugins/org.locationtech.udig.project.ui.editor/plugin.xml +++ b/plugins/org.locationtech.udig.project.ui.editor/plugin.xml @@ -37,7 +37,7 @@ default="true" icon="icons/obj16/map_obj.gif" id="org.locationtech.udig.project.ui.mapEditor" - name="%mapEditorPalette.name"> + name="%mapEditor.name"> diff --git a/plugins/org.locationtech.udig.project.ui.editor/plugin_ko.properties b/plugins/org.locationtech.udig.project.ui.editor/plugin_ko.properties index 419ec3805d..d50a839deb 100644 --- a/plugins/org.locationtech.udig.project.ui.editor/plugin_ko.properties +++ b/plugins/org.locationtech.udig.project.ui.editor/plugin_ko.properties @@ -155,7 +155,6 @@ layerStatus.label = \ub808\uc774\uc5b4 \uc0c1\ud0dc layerSummary = &\ub808\uc774\uc5b4 \uac1c\uc694 mapEditor.name = \uc9c0\ub3c4 \ud3b8\uc9d1\uae30 -mapEditorPalette.name = \uc9c0\ub3c4 \ud3b8\uc9d1\uae30 \ud314\ub808\ud2b8 menu.map.label = \uc9c0\ub3c4 diff --git a/plugins/org.locationtech.udig.project.ui.editor/plugin_ru.properties b/plugins/org.locationtech.udig.project.ui.editor/plugin_ru.properties index 550b9a78bd..663677565f 100644 --- a/plugins/org.locationtech.udig.project.ui.editor/plugin_ru.properties +++ b/plugins/org.locationtech.udig.project.ui.editor/plugin_ru.properties @@ -155,7 +155,6 @@ layerStatus.label = \u0421\u0442\u0430\u0442\u0443\u0441 \u0441\u043b\u043 layerSummary = \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u043b\u043e\u0435 mapEditor.name = \u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u043a\u0430\u0440\u0442\u044b -mapEditorPalette.name = \u041f\u0430\u043b\u0438\u0442\u0440\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u043a\u0430\u0440\u0442\u044b menu.map.label = \u041a\u0430\u0440\u0442\u0430 diff --git a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/MapPaletteSaveStrategy.java b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/MapPaletteSaveStrategy.java index bcf1c2d702..f90fd68a80 100644 --- a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/MapPaletteSaveStrategy.java +++ b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/MapPaletteSaveStrategy.java @@ -1,142 +1,142 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.project.ui.internal; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.dialogs.MessageDialog; -import org.locationtech.udig.catalog.IGeoResource; -import org.locationtech.udig.catalog.URLUtils; -import org.locationtech.udig.catalog.ui.export.CatalogExport; -import org.locationtech.udig.catalog.ui.export.CatalogExportWizard; -import org.locationtech.udig.catalog.ui.export.Data; -import org.locationtech.udig.catalog.ui.export.ExportResourceSelectionState; -import org.locationtech.udig.catalog.ui.workflow.State; -import org.locationtech.udig.catalog.ui.workflow.Workflow; -import org.locationtech.udig.catalog.ui.workflow.WorkflowWizard; -import org.locationtech.udig.catalog.ui.workflow.WorkflowWizardPageProvider; -import org.locationtech.udig.project.internal.Layer; -import org.locationtech.udig.project.internal.LayerFactory; -import org.locationtech.udig.project.internal.StyleBlackboard; - -/** - * Save strategy for Map Palette - * - * @author Jody Garnett - * @since 1.3.0 - * @version 1.3.0 - */ -public final class MapPaletteSaveStrategy extends CatalogExport { - private final ExportResourceSelectionState state; - private MapEditorWithPalette editor; - - public MapPaletteSaveStrategy(ExportResourceSelectionState state, MapEditorWithPalette editor) { - super(false); - this.state = state; - this.editor = editor; - - initWorkflow(); - } - - @Override - protected Workflow createWorkflow() { - final Workflow workflow = new Workflow(new State[] { state }); - - // create the workflow for the export wizard - return workflow; - } - - @Override - protected WorkflowWizard createWorkflowWizard(Workflow workflow, - java.util.Map, WorkflowWizardPageProvider> map) { - CatalogExportWizard catalogExportWizard = new CatalogExportWizard( - workflow, map) { - @Override - protected boolean performFinish(IProgressMonitor monitor) { - boolean result = super.performFinish(monitor); - replaceExportedLayers(state); - try { - editor.getMap().getEditManagerInternal() - .commitTransaction(); - editor.setDirty(false); - } catch (IOException e) { - ProjectUIPlugin.log("failed committing transaction", e); //$NON-NLS-1$ - MessageDialog.openError(editor.getSite().getShell(), Messages.MapSaveStrategy_error_title, Messages.MapSaveStrategy_error_messages); - } - return result; - } - - private void replaceExportedLayers( - final ExportResourceSelectionState layerState) { - List exportedLayers = layerState.getExportData(); - for (Data data : exportedLayers) { - Collection exported = data - .getExportedResources(); - replaceLayer(data.getResource(), exported); - } - } - - private void replaceLayer(IGeoResource resource, - Collection exported) { - List layers = MapPaletteSaveStrategy.this.editor.getMap() - .getLayersInternal(); - Layer found; - do { - found = null; - for (Layer layer : layers) { - if (URLUtils.urlEquals(layer.getID(), resource - .getIdentifier(), false)) { - found = layer; - break; - } - } - - if (found != null) { - layers.addAll(layers.indexOf(found), toLayers(found, - exported)); - layers.remove(found); - } - } while (found != null); - - } - - private Collection toLayers(Layer found, - Collection exported) { - LayerFactory layerFactory = MapPaletteSaveStrategy.this.editor - .getMap().getLayerFactory(); - Collection newLayers = new ArrayList(); - - for (IGeoResource exportedResource : exported) { - try { - Layer createLayer = layerFactory - .createLayer(exportedResource); - StyleBlackboard clone = (StyleBlackboard) found - .getStyleBlackboard().clone(); - createLayer.setStyleBlackboard(clone); - newLayers.add(createLayer); - } catch (IOException e) { - throw (RuntimeException) new RuntimeException() - .initCause(e); - } - } - - return newLayers; - } - - }; - catalogExportWizard.setSelectExportedInCatalog(false); - return catalogExportWizard; - } - -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.project.ui.internal; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.locationtech.udig.catalog.IGeoResource; +import org.locationtech.udig.catalog.URLUtils; +import org.locationtech.udig.catalog.ui.export.CatalogExport; +import org.locationtech.udig.catalog.ui.export.CatalogExportWizard; +import org.locationtech.udig.catalog.ui.export.Data; +import org.locationtech.udig.catalog.ui.export.ExportResourceSelectionState; +import org.locationtech.udig.catalog.ui.workflow.State; +import org.locationtech.udig.catalog.ui.workflow.Workflow; +import org.locationtech.udig.catalog.ui.workflow.WorkflowWizard; +import org.locationtech.udig.catalog.ui.workflow.WorkflowWizardPageProvider; +import org.locationtech.udig.project.internal.Layer; +import org.locationtech.udig.project.internal.LayerFactory; +import org.locationtech.udig.project.internal.StyleBlackboard; + +/** + * Save strategy for Map Palette + * + * @author Jody Garnett + * @since 1.3.0 + * @version 1.3.0 + */ +public final class MapPaletteSaveStrategy extends CatalogExport { + private final ExportResourceSelectionState state; + private MapEditorWithPalette editor; + + public MapPaletteSaveStrategy(ExportResourceSelectionState state, MapEditorWithPalette editor) { + super(false); + this.state = state; + this.editor = editor; + + initWorkflow(); + } + + @Override + protected Workflow createWorkflow() { + final Workflow workflow = new Workflow(new State[] { state }); + + // create the workflow for the export wizard + return workflow; + } + + @Override + protected WorkflowWizard createWorkflowWizard(Workflow workflow, + java.util.Map, WorkflowWizardPageProvider> map) { + CatalogExportWizard catalogExportWizard = new CatalogExportWizard( + workflow, map) { + @Override + protected boolean performFinish(IProgressMonitor monitor) { + boolean result = super.performFinish(monitor); + replaceExportedLayers(state); + try { + editor.getMap().getEditManagerInternal() + .commitTransaction(); + editor.setDirty(false); + } catch (IOException e) { + ProjectUIPlugin.log("failed committing transaction", e); //$NON-NLS-1$ + MessageDialog.openError(editor.getSite().getShell(), Messages.MapSaveStrategy_error_title, Messages.MapSaveStrategy_error_messages); + } + return result; + } + + private void replaceExportedLayers( + final ExportResourceSelectionState layerState) { + List exportedLayers = layerState.getExportData(); + for (Data data : exportedLayers) { + Collection exported = data + .getExportedResources(); + replaceLayer(data.getResource(), exported); + } + } + + private void replaceLayer(IGeoResource resource, + Collection exported) { + List layers = MapPaletteSaveStrategy.this.editor.getMap() + .getLayersInternal(); + Layer found; + do { + found = null; + for (Layer layer : layers) { + if (URLUtils.urlEquals(layer.getID(), resource + .getIdentifier(), false)) { + found = layer; + break; + } + } + + if (found != null) { + layers.addAll(layers.indexOf(found), toLayers(found, + exported)); + layers.remove(found); + } + } while (found != null); + + } + + private Collection toLayers(Layer found, + Collection exported) { + LayerFactory layerFactory = MapPaletteSaveStrategy.this.editor + .getMap().getLayerFactory(); + Collection newLayers = new ArrayList<>(); + + for (IGeoResource exportedResource : exported) { + try { + Layer createLayer = layerFactory + .createLayer(exportedResource); + StyleBlackboard clone = (StyleBlackboard) found + .getStyleBlackboard().clone(); + createLayer.setStyleBlackboard(clone); + newLayers.add(createLayer); + } catch (IOException e) { + throw (RuntimeException) new RuntimeException() + .initCause(e); + } + } + + return newLayers; + } + + }; + catalogExportWizard.setSelectExportedInCatalog(false); + return catalogExportWizard; + } + +} diff --git a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/SaveMapPaletteRunnable.java b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/SaveMapPaletteRunnable.java index 3b547d233a..63cb810f12 100644 --- a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/SaveMapPaletteRunnable.java +++ b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/SaveMapPaletteRunnable.java @@ -1,81 +1,82 @@ -/** - * - */ -package org.locationtech.udig.project.ui.internal; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jface.viewers.StructuredSelection; -import org.locationtech.udig.catalog.IGeoResource; -import org.locationtech.udig.catalog.ITransientResolve; -import org.locationtech.udig.catalog.ui.export.CatalogExport; -import org.locationtech.udig.catalog.ui.export.ExportResourceSelectionState; -import org.locationtech.udig.project.ILayer; -import org.locationtech.udig.project.internal.EditManager; - -/** - * Save strategy for Map Palette - * - * @author Jody Garnett - * @since 1.3.0 - * @version 1.3.0 - */ -class SaveMapPaletteRunnable implements Runnable{ - private final MapEditorWithPalette mapEditor; - private final boolean[] success; - - - public SaveMapPaletteRunnable(MapEditorWithPalette mapEditor, boolean[] success) { - super(); - this.mapEditor = mapEditor; - this.success = success; - } - - private enum Result{NO_TEMP_LAYERS, EXPORT_WIZARD_RUNNING}; - public void run() { - try{ - - EditManager editManagerInternal = mapEditor.getMap().getEditManagerInternal(); - - SaveMapPaletteRunnable.Result result = saveTemporaryLayers(); - if( result == Result.NO_TEMP_LAYERS ){ - editManagerInternal.commitTransaction(); - - success[0] = true; - } else { - success[0] = false; - } - }catch (IOException e) { - ProjectUIPlugin.log("Error saving", e); //$NON-NLS-1$ - success[0] = false; - } - } - - private SaveMapPaletteRunnable.Result saveTemporaryLayers( ) { - List resources=new ArrayList(); - for( ILayer layer : mapEditor.getMap().getMapLayers() ) { - if( layer.hasResource(ITransientResolve.class) ) - resources.addAll(layer.getGeoResources()); - } - - if( resources.isEmpty() ){ - return Result.NO_TEMP_LAYERS; - } - - final StructuredSelection selection = new StructuredSelection(resources); - final ExportResourceSelectionState layerState = new ExportResourceSelectionState(selection); - - CatalogExport exp = new MapPaletteSaveStrategy(layerState, mapEditor); - - // open the export dialog - exp.open(); - - // Since dialog is opened after this returns return cancelled and we'll make sure the MapSaveStrategy will clear the - // dirty state if the export takes place. - - return Result.EXPORT_WIZARD_RUNNING; - } - - } +/** + * + */ +package org.locationtech.udig.project.ui.internal; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.StructuredSelection; +import org.locationtech.udig.catalog.IGeoResource; +import org.locationtech.udig.catalog.ITransientResolve; +import org.locationtech.udig.catalog.ui.export.CatalogExport; +import org.locationtech.udig.catalog.ui.export.ExportResourceSelectionState; +import org.locationtech.udig.project.ILayer; +import org.locationtech.udig.project.internal.EditManager; + +/** + * Save strategy for Map Palette + * + * @author Jody Garnett + * @since 1.3.0 + * @version 1.3.0 + */ +class SaveMapPaletteRunnable implements Runnable{ + private final MapEditorWithPalette mapEditor; + private final boolean[] success; + + + public SaveMapPaletteRunnable(MapEditorWithPalette mapEditor, boolean[] success) { + super(); + this.mapEditor = mapEditor; + this.success = success; + } + + private enum Result{NO_TEMP_LAYERS, EXPORT_WIZARD_RUNNING}; + @Override + public void run() { + try{ + + EditManager editManagerInternal = mapEditor.getMap().getEditManagerInternal(); + + SaveMapPaletteRunnable.Result result = saveTemporaryLayers(); + if( result == Result.NO_TEMP_LAYERS ){ + editManagerInternal.commitTransaction(); + + success[0] = true; + } else { + success[0] = false; + } + }catch (IOException e) { + ProjectUIPlugin.log("Error saving", e); //$NON-NLS-1$ + success[0] = false; + } + } + + private SaveMapPaletteRunnable.Result saveTemporaryLayers( ) { + List resources=new ArrayList<>(); + for( ILayer layer : mapEditor.getMap().getMapLayers() ) { + if( layer.hasResource(ITransientResolve.class) ) + resources.addAll(layer.getGeoResources()); + } + + if( resources.isEmpty() ){ + return Result.NO_TEMP_LAYERS; + } + + final StructuredSelection selection = new StructuredSelection(resources); + final ExportResourceSelectionState layerState = new ExportResourceSelectionState(selection); + + CatalogExport exp = new MapPaletteSaveStrategy(layerState, mapEditor); + + // open the export dialog + exp.open(); + + // Since dialog is opened after this returns return cancelled and we'll make sure the MapSaveStrategy will clear the + // dirty state if the export takes place. + + return Result.EXPORT_WIZARD_RUNNING; + } + + } diff --git a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/tool/display/ToolManager.java b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/tool/display/ToolManager.java index 3c51820ad8..a27b735f84 100644 --- a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/tool/display/ToolManager.java +++ b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/internal/tool/display/ToolManager.java @@ -725,8 +725,7 @@ void setActiveTool(MapPart editor) { editor.setSelectionProvider(activeModalToolProxy.getSelectionProvider()); if (editor instanceof MapEditorWithPalette) { // temporary cast while we sort out if MapPart can own an MapEditDomain - MapEditorWithPalette editor2 = (MapEditorWithPalette) editor; - MapEditDomain editDomain = editor2.getEditDomain(); + MapEditDomain editDomain = ((MapEditorWithPalette) editor).getEditDomain(); editDomain.setActiveTool(activeModalToolProxy.getId()); } diff --git a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/preferences/PreferenceInitializer.java b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/preferences/PreferenceInitializer.java index d62ed2893f..2a066a7f7d 100644 --- a/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/preferences/PreferenceInitializer.java +++ b/plugins/org.locationtech.udig.project.ui/src/org/locationtech/udig/project/ui/preferences/PreferenceInitializer.java @@ -12,7 +12,6 @@ import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; import org.eclipse.jface.preference.IPreferenceStore; -import org.locationtech.udig.project.ui.internal.MapEditorWithPalette; import org.locationtech.udig.project.ui.internal.ProjectUIPlugin; public class PreferenceInitializer extends AbstractPreferenceInitializer { diff --git a/plugins/org.locationtech.udig.tutorials.examples/src/org/locationtech/udig/tutorials/examples/ListenToActiveMap.java b/plugins/org.locationtech.udig.tutorials.examples/src/org/locationtech/udig/tutorials/examples/ListenToActiveMap.java index fb583a42ac..76eca03748 100644 --- a/plugins/org.locationtech.udig.tutorials.examples/src/org/locationtech/udig/tutorials/examples/ListenToActiveMap.java +++ b/plugins/org.locationtech.udig.tutorials.examples/src/org/locationtech/udig/tutorials/examples/ListenToActiveMap.java @@ -9,106 +9,111 @@ */ package org.locationtech.udig.tutorials.examples; -import org.locationtech.udig.project.ui.internal.MapEditorWithPalette; - import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchPartSite; +import org.locationtech.udig.project.ui.internal.MapEditorWithPalette; /** - * This class demonstrates how to listen for events that signal that the current map is being changed (to another map). - * + * This class demonstrates how to listen for events that signal that the current map is being + * changed (to another map). + * *

    - * In order to be the active map the MapEditor for the map must be the last map editor that was activated. Being - * visible or opened is not sufficient. However if the active map is closed or hidden then the active map is the new - * Map Editor that is visible. + * In order to be the active map the MapEditor for the map must be the last map editor that was + * activated. Being visible or opened is not sufficient. However if the active map is closed or + * hidden then the active map is the new Map Editor that is visible. *

    - * + * * @author Jesse */ public class ListenToActiveMap { - private IPartListener2 activeMapListener=new IPartListener2(){ - - public void partActivated(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // ok this is a map and the map is actually activated (focus has been given to the editor. - // could also use the following check instead of comparing IDs: - // partRef.getPart(false) instanceof MapEditor - } - - } - - public void partBroughtToTop(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // The "active" map editor has changed. The "top" editor is the active one. - // coud also use the following check instead of comparing IDs: - // partRef.getPart(false) instanceof MapEditor - } - - } - - public void partClosed(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // a map editor has closed it is not necessarilly the active one. You - // need to do your own checks for that. - } - - } - - public void partDeactivated(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // This doesn't necessarily mean that the active map has changed - // Just that the editor no longer has focus. - } - - - } - - public void partHidden(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // The "active" map has been hidden there is now a new active map - // the method partBroughtToTop will be called so wait for that method before actually - // changing current map. - } - - - } - - public void partInputChanged(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // This should never be called - } - - } - - public void partOpened(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // A map has been openned and will probably be the active map. - } - - - - } - - public void partVisible(IWorkbenchPartReference partRef) { - if( partRef.getId().equals(MapEditorWithPalette.ID) ){ - // a map is visible but not necessarily the active map. - } - - - - } - - }; - - /** - * This assumes that the caller has acces to a site. Usually can be obtained by getSite() from a view or editor. - * - * @param site - */ - public void addActiveMapListener(IWorkbenchPartSite site){ - IWorkbenchPage page = site.getPage(); - page.addPartListener(activeMapListener); - } + private IPartListener2 activeMapListener = new IPartListener2() { + + @Override + public void partActivated(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // ok this is a map and the map is actually activated (focus has been given to the + // editor. + // could also use the following check instead of comparing IDs: + // partRef.getPart(false) instanceof MapEditor + } + + } + + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // The "active" map editor has changed. The "top" editor is the active one. + // coud also use the following check instead of comparing IDs: + // partRef.getPart(false) instanceof MapEditor + } + + } + + @Override + public void partClosed(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // a map editor has closed it is not necessarilly the active one. You + // need to do your own checks for that. + } + + } + + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // This doesn't necessarily mean that the active map has changed + // Just that the editor no longer has focus. + } + + } + + @Override + public void partHidden(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // The "active" map has been hidden there is now a new active map + // the method partBroughtToTop will be called so wait for that method before + // actually + // changing current map. + } + + } + + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // This should never be called + } + + } + + @Override + public void partOpened(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // A map has been openned and will probably be the active map. + } + + } + + @Override + public void partVisible(IWorkbenchPartReference partRef) { + if (partRef.getId().equals(MapEditorWithPalette.ID)) { + // a map is visible but not necessarily the active map. + } + + } + + }; + + /** + * This assumes that the caller has acces to a site. Usually can be obtained by getSite() from a + * view or editor. + * + * @param site + */ + public void addActiveMapListener(IWorkbenchPartSite site) { + IWorkbenchPage page = site.getPage(); + page.addPartListener(activeMapListener); + } } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/aoi/IAOIStrategy.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/aoi/IAOIStrategy.java index 59d8a34628..6fd6a08943 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/aoi/IAOIStrategy.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/aoi/IAOIStrategy.java @@ -1,127 +1,126 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2011, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.aoi; - -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.ui.part.IPageBookViewPage; -import org.geotools.geometry.jts.ReferencedEnvelope; -import org.opengis.referencing.crs.CoordinateReferenceSystem; - -import org.locationtech.jts.geom.Geometry; - -/** - * Defines the changing functionality of the AOI (Area of Interest) service. - * - * @author paul.pfeiffer - */ -public abstract class IAOIStrategy { - - /** - * Returns the extent of the current AOI. - * Should return null for an "All" extent - * - * @return ReferencedEnvelope - */ - public abstract ReferencedEnvelope getExtent(); - - /** - * Returns a geometry of the current AOI selected. - * Returning a null geometry specifies no AOI and by default will - * be treated as a world extent - * - * @return Geometry - */ - public abstract Geometry getGeometry(); - - /** - * Returns the CRS of the current AOI selected - * - * @return - */ - public abstract CoordinateReferenceSystem getCrs(); - - /** - * Returns the name of the AOI strategy. This is used when adding to the combo to select - * from. - * - * @return String - */ - public abstract String getName(); - - /** - * A list of listeners to be notified when the Strategy changes - */ - protected Set listeners = new CopyOnWriteArraySet(); - - /** - * Allows notification of changes to the AOI represented by the - * strategy. This is used for dynamic boundaries that change over time - * (perhaps in response to a user using a tool to specifiy a new - * clipping area). - *

    - * The AOIServiceImpl will register a single listener in order - * to track what is going on. - * - * @param listener - */ - public void addListener( AOIListener listener ) { - if( listener == null ){ - throw new NullPointerException("AOIService listener required to be non null"); - } - if( !listeners.contains(listener)){ - listeners.add(listener); - } - } - /** - * Remove a listener for AOI chages. - * - * @param listener - */ - public void removeListener( AOIListener listener ) { - listeners.remove(listener); - } - - /** - * Notifies listener that the value of the filter has changed. - *

    - * - * @param data Geometry supplied to listeners using event.data - */ - protected void notifyListeners(AOIListener.Event event) { - for( AOIListener listener : listeners ) { - if( event == null ){ - event = new AOIListener.Event(this); - } - try { - if( listener != null ){ - listener.handleEvent( event ); - } - } catch (Exception e) { - UiPlugin.trace(UiPlugin.ID, listener.getClass(), e.getMessage(), e ); - } - } - } - - /** - * Creates a Page (used for extra selection like the bookmark strategy). - *

    - * Please note this is provided by the extension point information via AOIProxy. - * As such this method is expected to return null. - * - * @return Page if it exists otherwise null - */ - public IPageBookViewPage createPage() { - return null; - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2011, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.aoi; + +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.eclipse.ui.part.IPageBookViewPage; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +/** + * Defines the changing functionality of the AOI (Area of Interest) service. + * + * @author paul.pfeiffer + */ +public abstract class IAOIStrategy { + + /** + * Returns the extent of the current AOI. + * Should return null for an "All" extent + * + * @return ReferencedEnvelope + */ + public abstract ReferencedEnvelope getExtent(); + + /** + * Returns a geometry of the current AOI selected. + * Returning a null geometry specifies no AOI and by default will + * be treated as a world extent + * + * @return Geometry + */ + public abstract Geometry getGeometry(); + + /** + * Returns the CRS of the current AOI selected + * + * @return + */ + public abstract CoordinateReferenceSystem getCrs(); + + /** + * Returns the name of the AOI strategy. This is used when adding to the combo to select + * from. + * + * @return String + */ + public abstract String getName(); + + /** + * A list of listeners to be notified when the Strategy changes + */ + protected Set listeners = new CopyOnWriteArraySet<>(); + + /** + * Allows notification of changes to the AOI represented by the + * strategy. This is used for dynamic boundaries that change over time + * (perhaps in response to a user using a tool to specifiy a new + * clipping area). + *

    + * The AOIServiceImpl will register a single listener in order + * to track what is going on. + * + * @param listener + */ + public void addListener( AOIListener listener ) { + if( listener == null ){ + throw new NullPointerException("AOIService listener required to be non null"); + } + if( !listeners.contains(listener)){ + listeners.add(listener); + } + } + /** + * Remove a listener for AOI chages. + * + * @param listener + */ + public void removeListener( AOIListener listener ) { + listeners.remove(listener); + } + + /** + * Notifies listener that the value of the filter has changed. + *

    + * + * @param data Geometry supplied to listeners using event.data + */ + protected void notifyListeners(AOIListener.Event event) { + for( AOIListener listener : listeners ) { + if( event == null ){ + event = new AOIListener.Event(this); + } + try { + if( listener != null ){ + listener.handleEvent( event ); + } + } catch (Exception e) { + LoggingSupport.trace(UiPlugin.getDefault(), UiPlugin.ID, listener.getClass(), e.getMessage(), e ); + } + } + } + + /** + * Creates a Page (used for extra selection like the bookmark strategy). + *

    + * Please note this is provided by the extension point information via AOIProxy. + * As such this method is expected to return null. + * + * @return Page if it exists otherwise null + */ + public IPageBookViewPage createPage() { + return null; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/aoi/AOIServiceImpl.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/aoi/AOIServiceImpl.java index 079c22f226..fd4a3796df 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/aoi/AOIServiceImpl.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/aoi/AOIServiceImpl.java @@ -1,174 +1,175 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2011, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.internal.aoi; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.locationtech.udig.aoi.AOIListener; -import org.locationtech.udig.aoi.AOIProxy; -import org.locationtech.udig.aoi.IAOIService; -import org.locationtech.udig.core.internal.ExtensionPointProcessor; -import org.locationtech.udig.core.internal.ExtensionPointUtil; -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExtension; -import org.geotools.geometry.jts.ReferencedEnvelope; -import org.opengis.referencing.crs.CoordinateReferenceSystem; - -import org.locationtech.jts.geom.Geometry; - -/** - * This is the default implementation of AOIService; it delegates to the internal strategy - * object. - * - * @author pfeiffp - */ -public class AOIServiceImpl implements IAOIService { - - /** This is the AOI extension point processed to get AOIStrategy entries */ - private static final String EXT_ID = "org.locationtech.udig.ui.aoi"; - - /** - * the id of the all strategy (ie the default) - */ - public static final String STRATEGY_ALL_ID = "org.locationtech.udig.ui.aoiAll"; - - /* - * A list of all the strategies - */ - protected List proxyList = new ArrayList(); - - protected AOIListener watcher = new AOIListener(){ - public void handleEvent( AOIListener.Event event ) { - notifyListeners(event); - } - }; - /* - * A list of listeners to be notified when the Strategy changes - */ - protected Set listeners = new CopyOnWriteArraySet(); - - @Override - public void addListener( AOIListener listener ) { - if (listener == null) { - throw new NullPointerException("AOIService listener required to be non null"); - } - listeners.add(listener); - } - - @Override - public void removeListener( AOIListener listener ) { - if (listeners.contains(listener)) { - listeners.remove(listener); - } - } - - /* - * Notifies listener that the value of the filter has changed. - */ - private void notifyListeners( AOIListener.Event event ) { - if (event == null) { - event = new AOIListener.Event(getProxy()); - } - for( AOIListener listener : listeners ) { - try { - if (listener != null) { - listener.handleEvent(event); - } - } catch (Exception e) { - UiPlugin.log(getClass(), "notifyListeners", e); - } - } - } - - private AOIProxy currentProxy; - - public AOIServiceImpl() { - - // process the extension point here to get the list of Strategies - ExtensionPointProcessor processAOIItems = new ExtensionPointProcessor(){ - @Override - public void process( IExtension extension, IConfigurationElement element ) - throws Exception { - AOIProxy proxy = new AOIProxy(element); - proxyList.add(proxy); - /* - * String className = element.getAttribute("class"); if( currentClassName != null && - * currentClassName.equals( className )){ initialStrategy = strategy; } - */ - } - }; - ExtensionPointUtil.process(UiPlugin.getDefault(), EXT_ID, processAOIItems); - - this.setProxy(this.getDefault()); - } - - @Override - public ReferencedEnvelope getExtent() { - return this.currentProxy.getExtent(); - } - - @Override - public void setProxy( AOIProxy proxy ) { - if (this.currentProxy == proxy) { - return; // no change - } - if (this.currentProxy != null) { - this.currentProxy.removeListener(watcher); - } - this.currentProxy = proxy; - if (this.currentProxy != null) { - this.currentProxy.addListener(watcher); - } - AOIListener.Event event = new AOIListener.Event(proxy); - // we are not filling in event.geometry here as we only changed strategy - notifyListeners(event); - } - - @Override - public Geometry getGeometry() { - return this.currentProxy.getGeometry(); - } - - @Override - public CoordinateReferenceSystem getCrs() { - return this.currentProxy.getCrs(); - } - - @Override - public AOIProxy getProxy() { - return this.currentProxy; - } - - @Override - public AOIProxy getDefault() { - return this.findProxy(STRATEGY_ALL_ID); - } - - @Override - public List getProxyList() { - return Collections.unmodifiableList(proxyList); - } - - @Override - public AOIProxy findProxy( String id ) { - for( AOIProxy aOIProxy : proxyList ) { - if (aOIProxy.getId().equals(id)) { - return aOIProxy; - } - } - return null; - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2011, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.internal.aoi; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.ui.internal.UIPlugin; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.udig.aoi.AOIListener; +import org.locationtech.udig.aoi.AOIProxy; +import org.locationtech.udig.aoi.IAOIService; +import org.locationtech.udig.core.internal.ExtensionPointProcessor; +import org.locationtech.udig.core.internal.ExtensionPointUtil; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +/** + * This is the default implementation of AOIService; it delegates to the internal strategy + * object. + * + * @author pfeiffp + */ +public class AOIServiceImpl implements IAOIService { + + /** This is the AOI extension point processed to get AOIStrategy entries */ + private static final String EXT_ID = "org.locationtech.udig.ui.aoi"; + + /** + * the id of the all strategy (ie the default) + */ + public static final String STRATEGY_ALL_ID = "org.locationtech.udig.ui.aoiAll"; + + /* + * A list of all the strategies + */ + protected List proxyList = new ArrayList<>(); + + protected AOIListener watcher = new AOIListener(){ + @Override + public void handleEvent( AOIListener.Event event ) { + notifyListeners(event); + } + }; + /* + * A list of listeners to be notified when the Strategy changes + */ + protected Set listeners = new CopyOnWriteArraySet<>(); + + @Override + public void addListener( AOIListener listener ) { + if (listener == null) { + throw new NullPointerException("AOIService listener required to be non null"); + } + listeners.add(listener); + } + + @Override + public void removeListener( AOIListener listener ) { + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } + + /* + * Notifies listener that the value of the filter has changed. + */ + private void notifyListeners( AOIListener.Event event ) { + if (event == null) { + event = new AOIListener.Event(getProxy()); + } + for( AOIListener listener : listeners ) { + try { + if (listener != null) { + listener.handleEvent(event); + } + } catch (Exception e) { + LoggingSupport.log(UIPlugin.getDefault(), getClass(), "notifyListeners", e); + } + } + } + + private AOIProxy currentProxy; + + public AOIServiceImpl() { + + // process the extension point here to get the list of Strategies + ExtensionPointProcessor processAOIItems = new ExtensionPointProcessor(){ + @Override + public void process( IExtension extension, IConfigurationElement element ) + throws Exception { + AOIProxy proxy = new AOIProxy(element); + proxyList.add(proxy); + /* + * String className = element.getAttribute("class"); if( currentClassName != null && + * currentClassName.equals( className )){ initialStrategy = strategy; } + */ + } + }; + ExtensionPointUtil.process(UiPlugin.getDefault(), EXT_ID, processAOIItems); + + this.setProxy(this.getDefault()); + } + + @Override + public ReferencedEnvelope getExtent() { + return this.currentProxy.getExtent(); + } + + @Override + public void setProxy( AOIProxy proxy ) { + if (this.currentProxy == proxy) { + return; // no change + } + if (this.currentProxy != null) { + this.currentProxy.removeListener(watcher); + } + this.currentProxy = proxy; + if (this.currentProxy != null) { + this.currentProxy.addListener(watcher); + } + AOIListener.Event event = new AOIListener.Event(proxy); + // we are not filling in event.geometry here as we only changed strategy + notifyListeners(event); + } + + @Override + public Geometry getGeometry() { + return this.currentProxy.getGeometry(); + } + + @Override + public CoordinateReferenceSystem getCrs() { + return this.currentProxy.getCrs(); + } + + @Override + public AOIProxy getProxy() { + return this.currentProxy; + } + + @Override + public AOIProxy getDefault() { + return this.findProxy(STRATEGY_ALL_ID); + } + + @Override + public List getProxyList() { + return Collections.unmodifiableList(proxyList); + } + + @Override + public AOIProxy findProxy( String id ) { + for( AOIProxy aOIProxy : proxyList ) { + if (aOIProxy.getId().equals(id)) { + return aOIProxy; + } + } + return null; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/FeatureTextTransfer.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/FeatureTextTransfer.java index d3295d7b06..a251603bd0 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/FeatureTextTransfer.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/FeatureTextTransfer.java @@ -28,6 +28,7 @@ import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.io.WKTWriter; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.ui.AbstractTextStrategizedTransfer; import org.locationtech.udig.ui.internal.Messages; import org.opengis.feature.simple.SimpleFeature; @@ -176,7 +177,7 @@ public Object nativeToJava(TransferData transferData) { return SimpleFeatureBuilder.build(ft, new Object[] { read }, null); } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), e); } return null; } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/SendLogDialog.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/SendLogDialog.java index c709bf02da..5ee7117b0c 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/SendLogDialog.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/SendLogDialog.java @@ -1,305 +1,310 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.internal.ui; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; - -import org.locationtech.udig.ui.PlatformGIS; -import org.locationtech.udig.ui.internal.Messages; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** - * Dialog for sending the error log to the development team. - * - * @author chorner - */ -public class SendLogDialog extends TitleAreaDialog { - - private Label contactLabel; - private Text contact; - private Label noteLabel; - private Text notes; - private Label logLabel; - private Text log; - - boolean hasLog = false; - - protected SendLogDialog( Shell parentShell ) { - super(parentShell); - setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL - | getDefaultOrientation()); - } - - @Override - protected void configureShell( Shell newShell ) { - super.configureShell(newShell); - newShell.setText(Messages.SendLogDialog_title); - } - - @Override - protected Point getInitialSize() { - return new Point(640, 720); - } - - @Override - protected Control createDialogArea( Composite parent ) { - setTitle(Messages.SendLogDialog_description); - ImageDescriptor image = UiPlugin.getDefault().getImageDescriptor(ImageConstants.LOG_WIZ); - if (image != null) setTitleImage(image.createImage()); - - // create a composite with standard margins and spacing - Composite composite = new Composite(parent, SWT.RESIZE); - GridLayout layout = new GridLayout(2, false); - layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); - layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); - layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); - layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); - composite.setLayout(layout); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - applyDialogFont(composite); - - contactLabel = new Label(composite, SWT.NONE); - contactLabel.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); - contactLabel.setText(Messages.SendLogDialog_contact); - - contact = new Text(composite, SWT.BORDER); - GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); - gridData = new GridData(SWT.FILL, SWT.FILL, true, false); - gridData.horizontalSpan = 2; - contact.setLayoutData(gridData); - contact.addModifyListener(new ModifyListener() { - - public void modifyText( ModifyEvent e ) { - refreshButtons(); - } - - }); - - noteLabel = new Label(composite, SWT.NONE); - noteLabel.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); - noteLabel.setText(Messages.SendLogDialog_notes); - - notes = new Text(composite, SWT.WRAP | SWT.BORDER | SWT.MULTI); - gridData = new GridData(SWT.FILL, SWT.FILL, true, false); - gridData = new GridData(SWT.FILL, SWT.FILL, true, false); - gridData.heightHint = notes.getLineHeight() * 2; - gridData.horizontalSpan = 2; - notes.setLayoutData(gridData); - notes.addModifyListener(new ModifyListener() { - - public void modifyText( ModifyEvent e ) { - refreshButtons(); - } - - }); - - logLabel = new Label(composite, SWT.NONE); - gridData = new GridData(SWT.FILL, SWT.FILL, true, false); - gridData.verticalAlignment = SWT.END; - logLabel.setLayoutData(gridData); - logLabel.setText(Messages.SendLogDialog_log); - - log = new Text(composite, SWT.WRAP | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL | SWT.MULTI); - log.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); - gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - gridData.horizontalSpan = 2; - log.setLayoutData(gridData); - log.setText(Messages.SendLogDialog_reading); - log.setEnabled(false); - - //start a thread to acquire the log file - PopulateLogRunnable populateLog = new PopulateLogRunnable(); - PlatformGIS.run(populateLog); - contact.setFocus(); - - return composite; - } - - @Override - protected void createButtonsForButtonBar( Composite parent ) { - createButton(parent, IDialogConstants.PROCEED_ID, Messages.SendLogDialog_submit, false); - createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); - refreshButtons(); - } - - private void refreshButtons() { - boolean hasContact = false; - boolean hasNote = false; - if (notes.getText() != null && notes.getText().length() > 0) { - hasNote = true; - } - if (contact.getText() != null && contact.getText().length() > 0) { - hasContact = true; - } - Button proceed = getButton(IDialogConstants.PROCEED_ID); - if (hasContact && hasNote) { - setMessage(null); - proceed.setEnabled(hasLog); //only allow submission if a log exists - } else if (!hasContact) { - setMessage(Messages.SendLogDialog_contact_message, IMessageProvider.WARNING); - proceed.setEnabled(false); - } else { - setMessage(Messages.SendLogDialog_notes_message, IMessageProvider.WARNING); - proceed.setEnabled(false); - } - - } - - @Override - protected void buttonPressed( int buttonId ) { - if (IDialogConstants.PROCEED_ID == buttonId) { - try { - sendLog(); - } catch (RuntimeException e) { - throw (RuntimeException) new RuntimeException().initCause(e); - } finally { - okPressed(); - } - } - if (buttonId == IDialogConstants.CANCEL_ID) { - okPressed(); - } - } - - private void sendLog() { - try { - URL url = new URL("http://udig.refractions.net/errorlog.php"); //$NON-NLS-1$ - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); //$NON-NLS-1$ - connection.setDoOutput(true); - connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); //$NON-NLS-1$ //$NON-NLS-2$ - connection.setDoInput(true); - - StringBuilder text = new StringBuilder(); - text.append("Contact:\r\n"); //$NON-NLS-1$ - text.append(contact.getText()); - text.append("\r\n\r\nUser comments:\r\n"); //$NON-NLS-1$ - text.append(notes.getText()); - text.append("\r\n\r\nSystem Info:\r\n"); //$NON-NLS-1$ - text.append(getSystemInfo()); - text.append("\r\n----\r\n\r\n"); //$NON-NLS-1$ - text.append(log.getText()); - text.append("\r\n"); //$NON-NLS-1$ - String body = "body=" + URLEncoder.encode(text.toString(), "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ - - OutputStream outStream; - outStream = connection.getOutputStream(); - outStream.write(body.getBytes()); - outStream.flush(); - outStream.close(); - - connection.getResponseCode(); - } catch (Exception e) { - UiPlugin.log("Error log submission failed", e); //$NON-NLS-1$ - } finally { - UiPlugin.log("Log submitted, chars: " + log.getText().length(), null); //$NON-NLS-1$ - } - } - - public static boolean logExists() { - String filename = Platform.getLogFileLocation().toOSString(); - File log = new File(filename); - return log.exists(); - } - - private String getSystemInfo() { - StringBuilder content = new StringBuilder(); - //udig version number - content.append("uDig "); //$NON-NLS-1$ - content.append(UiPlugin.getDefault().getVersion()); - return content.toString(); - } - - private String getLogText( IProgressMonitor monitor ) { - String filename = Platform.getLogFileLocation().toOSString(); - File file = new File(filename); - FileReader in = null; - BufferedReader br = null; - try { - StringBuilder content = new StringBuilder(); - in = new FileReader(file); - br = new BufferedReader(in); - String line; - while( (line = br.readLine()) != null ) { - content.append(line); - content.append("\n"); //$NON-NLS-1$ - } - return content.toString(); - } catch (IOException e) { - return null; - } finally { - try { - if (br != null) - br.close(); - if (in != null) - in.close(); - } catch (IOException e) { - } - } - } - - private class PopulateLogRunnable implements IRunnableWithProgress { - - public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { - String text; - if (logExists()) { - text = getLogText(monitor); - } else { - text = Messages.SendLogDialog_empty; - } - - if (monitor.isCanceled()) { - //freak out - throw new InterruptedException("Log acquisition was canceled."); //$NON-NLS-1$ - } else { - //update dialog contents, mark log as acquired - final String logText = text; - PlatformGIS.syncInDisplayThread(new Runnable() { - - public void run() { - log.setText(logText); - log.setEnabled(true); - hasLog = true; - refreshButtons(); - } - - }); - } - } - } - -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.internal.ui; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.ui.PlatformGIS; +import org.locationtech.udig.ui.internal.Messages; + +/** + * Dialog for sending the error log to the development team. + * + * @author chorner + */ +public class SendLogDialog extends TitleAreaDialog { + + private Label contactLabel; + private Text contact; + private Label noteLabel; + private Text notes; + private Label logLabel; + private Text log; + + boolean hasLog = false; + + protected SendLogDialog( Shell parentShell ) { + super(parentShell); + setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL + | getDefaultOrientation()); + } + + @Override + protected void configureShell( Shell newShell ) { + super.configureShell(newShell); + newShell.setText(Messages.SendLogDialog_title); + } + + @Override + protected Point getInitialSize() { + return new Point(640, 720); + } + + @Override + protected Control createDialogArea( Composite parent ) { + setTitle(Messages.SendLogDialog_description); + ImageDescriptor image = UiPlugin.getDefault().getImageDescriptor(ImageConstants.LOG_WIZ); + if (image != null) setTitleImage(image.createImage()); + + // create a composite with standard margins and spacing + Composite composite = new Composite(parent, SWT.RESIZE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); + layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); + layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + applyDialogFont(composite); + + contactLabel = new Label(composite, SWT.NONE); + contactLabel.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); + contactLabel.setText(Messages.SendLogDialog_contact); + + contact = new Text(composite, SWT.BORDER); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + gridData.horizontalSpan = 2; + contact.setLayoutData(gridData); + contact.addModifyListener(new ModifyListener() { + + @Override + public void modifyText( ModifyEvent e ) { + refreshButtons(); + } + + }); + + noteLabel = new Label(composite, SWT.NONE); + noteLabel.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); + noteLabel.setText(Messages.SendLogDialog_notes); + + notes = new Text(composite, SWT.WRAP | SWT.BORDER | SWT.MULTI); + gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + gridData.heightHint = notes.getLineHeight() * 2; + gridData.horizontalSpan = 2; + notes.setLayoutData(gridData); + notes.addModifyListener(new ModifyListener() { + + @Override + public void modifyText( ModifyEvent e ) { + refreshButtons(); + } + + }); + + logLabel = new Label(composite, SWT.NONE); + gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + gridData.verticalAlignment = SWT.END; + logLabel.setLayoutData(gridData); + logLabel.setText(Messages.SendLogDialog_log); + + log = new Text(composite, SWT.WRAP | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL | SWT.MULTI); + log.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.horizontalSpan = 2; + log.setLayoutData(gridData); + log.setText(Messages.SendLogDialog_reading); + log.setEnabled(false); + + //start a thread to acquire the log file + PopulateLogRunnable populateLog = new PopulateLogRunnable(); + PlatformGIS.run(populateLog); + contact.setFocus(); + + return composite; + } + + @Override + protected void createButtonsForButtonBar( Composite parent ) { + createButton(parent, IDialogConstants.PROCEED_ID, Messages.SendLogDialog_submit, false); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + refreshButtons(); + } + + private void refreshButtons() { + boolean hasContact = false; + boolean hasNote = false; + if (notes.getText() != null && notes.getText().length() > 0) { + hasNote = true; + } + if (contact.getText() != null && contact.getText().length() > 0) { + hasContact = true; + } + Button proceed = getButton(IDialogConstants.PROCEED_ID); + if (hasContact && hasNote) { + setMessage(null); + proceed.setEnabled(hasLog); //only allow submission if a log exists + } else if (!hasContact) { + setMessage(Messages.SendLogDialog_contact_message, IMessageProvider.WARNING); + proceed.setEnabled(false); + } else { + setMessage(Messages.SendLogDialog_notes_message, IMessageProvider.WARNING); + proceed.setEnabled(false); + } + + } + + @Override + protected void buttonPressed( int buttonId ) { + if (IDialogConstants.PROCEED_ID == buttonId) { + try { + sendLog(); + } catch (RuntimeException e) { + throw (RuntimeException) new RuntimeException().initCause(e); + } finally { + okPressed(); + } + } + if (buttonId == IDialogConstants.CANCEL_ID) { + okPressed(); + } + } + + private void sendLog() { + try { + URL url = new URL("http://udig.refractions.net/errorlog.php"); //$NON-NLS-1$ + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); //$NON-NLS-1$ + connection.setDoOutput(true); + connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); //$NON-NLS-1$ //$NON-NLS-2$ + connection.setDoInput(true); + + StringBuilder text = new StringBuilder(); + text.append("Contact:\r\n"); //$NON-NLS-1$ + text.append(contact.getText()); + text.append("\r\n\r\nUser comments:\r\n"); //$NON-NLS-1$ + text.append(notes.getText()); + text.append("\r\n\r\nSystem Info:\r\n"); //$NON-NLS-1$ + text.append(getSystemInfo()); + text.append("\r\n----\r\n\r\n"); //$NON-NLS-1$ + text.append(log.getText()); + text.append("\r\n"); //$NON-NLS-1$ + String body = "body=" + URLEncoder.encode(text.toString(), "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + + OutputStream outStream; + outStream = connection.getOutputStream(); + outStream.write(body.getBytes()); + outStream.flush(); + outStream.close(); + + connection.getResponseCode(); + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error log submission failed", e); //$NON-NLS-1$ + } finally { + LoggingSupport.log(UiPlugin.getDefault(), + "Log submitted, chars: " + log.getText().length()); //$NON-NLS-1$ + } + } + + public static boolean logExists() { + String filename = Platform.getLogFileLocation().toOSString(); + File log = new File(filename); + return log.exists(); + } + + private String getSystemInfo() { + StringBuilder content = new StringBuilder(); + //udig version number + content.append("uDig "); //$NON-NLS-1$ + content.append(UiPlugin.getDefault().getVersion()); + return content.toString(); + } + + private String getLogText( IProgressMonitor monitor ) { + String filename = Platform.getLogFileLocation().toOSString(); + File file = new File(filename); + FileReader in = null; + BufferedReader br = null; + try { + StringBuilder content = new StringBuilder(); + in = new FileReader(file); + br = new BufferedReader(in); + String line; + while( (line = br.readLine()) != null ) { + content.append(line); + content.append("\n"); //$NON-NLS-1$ + } + return content.toString(); + } catch (IOException e) { + return null; + } finally { + try { + if (br != null) + br.close(); + if (in != null) + in.close(); + } catch (IOException e) { + } + } + } + + private class PopulateLogRunnable implements IRunnableWithProgress { + + @Override + public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { + String text; + if (logExists()) { + text = getLogText(monitor); + } else { + text = Messages.SendLogDialog_empty; + } + + if (monitor.isCanceled()) { + //freak out + throw new InterruptedException("Log acquisition was canceled."); //$NON-NLS-1$ + } else { + //update dialog contents, mark log as acquired + final String logText = text; + PlatformGIS.syncInDisplayThread(new Runnable() { + + @Override + public void run() { + log.setText(logText); + log.setEnabled(true); + hasLog = true; + refreshButtons(); + } + + }); + } + } + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/TipDialog.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/TipDialog.java index e28c84eab5..aa69df4417 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/TipDialog.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/TipDialog.java @@ -1,4 +1,5 @@ -/* uDig - User Friendly Desktop Internet GIS client +/** + * uDig - User Friendly Desktop Internet GIS client * http://udig.refractions.net * (C) 2004, Refractions Research Inc. * @@ -15,10 +16,6 @@ import java.util.List; import java.util.Random; -import org.locationtech.udig.core.internal.ExtensionPointList; -import org.locationtech.udig.ui.internal.Messages; -import org.locationtech.udig.ui.preferences.PreferenceConstants; - import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.jface.dialogs.Dialog; @@ -39,277 +36,277 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.ui.internal.Messages; +import org.locationtech.udig.ui.preferences.PreferenceConstants; import org.osgi.service.prefs.Preferences; /** * Dialog for showing tips from the tip extension point. */ public class TipDialog extends Dialog { - public static final String PREFERENCE_ID = "org.locationtech.udig.ui.tips"; //$NON-NLS-1$ + public static final String PREFERENCE_ID = "org.locationtech.udig.ui.tips"; //$NON-NLS-1$ - public static final String EXTENSION_ID = "org.locationtech.udig.ui.tip"; //$NON-NLS-1$ + public static final String EXTENSION_ID = "org.locationtech.udig.ui.tip"; //$NON-NLS-1$ - private static Tip current; + private static Tip current; - private static Configuration currentConfiguration; + private static Configuration currentConfiguration; - private Image image; + private Image image; - private Label title; + private Label title; - private Text tip; + private Text tip; - private Button check; + private Button check; - private Label imageLabel; + private Label imageLabel; - protected TipDialog(Shell parentShell) { - super(parentShell); - setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX); - } + protected TipDialog(Shell parentShell) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX); + } - @Override - protected void configureShell(Shell newShell) { - newShell.setText(Messages.TipDialog_shellText); - super.configureShell(newShell); - } + @Override + protected void configureShell(Shell newShell) { + newShell.setText(Messages.TipDialog_shellText); + super.configureShell(newShell); + } - @Override - protected Point getInitialSize() { - return new Point(400, 300); - } + @Override + protected Point getInitialSize() { + return new Point(400, 300); + } - @Override - protected Control createDialogArea(Composite parent) { - // create a composite with standard margins and spacing - Composite composite = (Composite) super.createDialogArea(parent); - composite.setLayout(new GridLayout(2, false)); + @Override + protected Control createDialogArea(Composite parent) { + // create a composite with standard margins and spacing + Composite composite = (Composite) super.createDialogArea(parent); + composite.setLayout(new GridLayout(2, false)); - imageLabel = new Label(composite, SWT.NONE); - imageLabel - .setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); + imageLabel = new Label(composite, SWT.NONE); + imageLabel.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); - title = new Label(composite, SWT.NONE); - GridData gridData = new GridData(SWT.FILL, SWT.NONE, true, false); - gridData.verticalAlignment = SWT.END; - title.setLayoutData(gridData); + title = new Label(composite, SWT.NONE); + GridData gridData = new GridData(SWT.FILL, SWT.NONE, true, false); + gridData.verticalAlignment = SWT.END; + title.setLayoutData(gridData); - tip = new Text(composite, SWT.WRAP|SWT.READ_ONLY| SWT.V_SCROLL); - tip.setBackground(getShell().getDisplay().getSystemColor( - SWT.COLOR_WIDGET_BACKGROUND)); - gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - gridData.horizontalSpan = 2; - tip.setLayoutData(gridData); + tip = new Text(composite, SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL); + tip.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.horizontalSpan = 2; + tip.setLayoutData(gridData); - updateTip(); + updateTip(); - check = new Button(composite, SWT.CHECK); - gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - gridData.horizontalSpan = 2; - check.setLayoutData(gridData); - check.setText(Messages.TipDialog_question); - boolean selected; - try { + check = new Button(composite, SWT.CHECK); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.horizontalSpan = 2; + check.setLayoutData(gridData); + check.setText(Messages.TipDialog_question); + boolean selected; + try { IPreferenceStore store = UiPlugin.getDefault().getPreferenceStore(); selected = store.getBoolean(PreferenceConstants.P_SHOW_TIPS); - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - selected = true; - } - check.setSelection(selected); - - return composite; - } - - private void updateTip() { - if (getCurrentTip().image != null) { - this.image = getCurrentTip().image.createImage(); - imageLabel.setImage(this.image); - } - title.setText(getCurrentTip().name); - FontData[] fontData = getShell().getFont().getFontData(); - FontData[] newData = new FontData[fontData.length]; - for (int i = 0; i < fontData.length; i++) { - FontData data = fontData[i]; - newData[i] = new FontData(data.getName(), data.getHeight() + 2, SWT.BOLD); - } - title.setFont(new Font(getShell().getDisplay(), newData)); - - if( getCurrentTip() != null && getCurrentTip().hint!=null ) + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + selected = true; + } + check.setSelection(selected); + + return composite; + } + + private void updateTip() { + if (getCurrentTip().image != null) { + this.image = getCurrentTip().image.createImage(); + imageLabel.setImage(this.image); + } + title.setText(getCurrentTip().name); + FontData[] fontData = getShell().getFont().getFontData(); + FontData[] newData = new FontData[fontData.length]; + for (int i = 0; i < fontData.length; i++) { + FontData data = fontData[i]; + newData[i] = new FontData(data.getName(), data.getHeight() + 2, SWT.BOLD); + } + title.setFont(new Font(getShell().getDisplay(), newData)); + + if (getCurrentTip() != null && getCurrentTip().hint != null) tip.setText(getCurrentTip().hint); - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - createButton(parent, IDialogConstants.NEXT_ID, - IDialogConstants.NEXT_LABEL, false); - createButton(parent, IDialogConstants.CLOSE_ID, - IDialogConstants.CLOSE_LABEL, true); - } - - @Override - protected void buttonPressed(int buttonId) { - if (IDialogConstants.NEXT_ID == buttonId) { - next(-1); - updateTip(); - } - if (buttonId == IDialogConstants.CLOSE_ID) { - IPreferenceStore store = UiPlugin.getDefault().getPreferenceStore(); - store.setValue(PreferenceConstants.P_SHOW_TIPS, check.getSelection()); - okPressed(); - } - } - - public static boolean hasTips() { - return getCurrentTip() != null; - } - - private static Tip getCurrentTip() { - if (current == null) { - next(-1); - } - return current; - } - - private static boolean isInCurrentConfiguration(IConfigurationElement elem) { - if (currentConfiguration == null) { - - List extensions = ExtensionPointList - .getExtensionPointList(EXTENSION_ID); - IConfigurationElement mostRecent = null; - for (IConfigurationElement element : extensions) { - if (element.getName().equals("activeConfiguration")) { //$NON-NLS-1$ - String attribute = element.getAttribute("configurationID"); //$NON-NLS-1$ - if (attribute != null) - mostRecent = element; - } - } - if (mostRecent == null) { - currentConfiguration = Configuration.DEFAULT; - } else { - for (IConfigurationElement element : extensions) { - if( mostRecent.getAttribute("configurationID").equals(element.getAttribute("id")) ) { //$NON-NLS-1$ //$NON-NLS-2$ - currentConfiguration=new Configuration(element); - break; - } - } - if( currentConfiguration.extensionIDs.size()==0 && - currentConfiguration.tipIDs.size()==0 ) - currentConfiguration = Configuration.DEFAULT; - - } - } - if (currentConfiguration == Configuration.DEFAULT) { - return true; - } - - return currentConfiguration.tipIDs.contains(elem.getAttribute("id")) //$NON-NLS-1$ - || currentConfiguration.extensionIDs.contains(elem.getDeclaringExtension().getUniqueIdentifier()); - } - - private static void next(int next2) { - int next=next2; - try { - Preferences node = getPreferences(); - List extensions = ExtensionPointList - .getExtensionPointList(EXTENSION_ID); - if (next == -1) { - Random r = new Random(); - next = r.nextInt(extensions.size()); - } - for (int i = next; i < extensions.size(); i++) { - IConfigurationElement elem = extensions.get(i); - if (isPermittedNext(node, elem)) { - node.put(elem.getAttribute("id"), ""); //$NON-NLS-1$ //$NON-NLS-2$ - current = new Tip(elem); - return; - } - } - for (int i = 0; i < next; i++) { - IConfigurationElement elem = extensions.get(i); - if (isPermittedNext(node, elem)) { - node.put(elem.getAttribute("id"), ""); //$NON-NLS-1$ //$NON-NLS-2$ - current = new Tip(elem); - return; - } - } - if (node.keys().length == 0) { - current = null; - return; - } - node.clear(); - next(next); - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - - private static boolean isPermittedNext(Preferences node, - IConfigurationElement elem) { - if (!elem.getName().equals("tip")) //$NON-NLS-1$ - return false; - boolean notPreviouslyShown = node.get(elem.getAttribute("id"), null) == null; //$NON-NLS-1$ - boolean notSameAsCurrent = (current == null || !elem.getAttribute("id") //$NON-NLS-1$ - .equals(current.id)); - return notPreviouslyShown && notSameAsCurrent - && isInCurrentConfiguration(elem); - } - - public static Preferences getPreferences() throws CoreException, - IOException { - Preferences userPreferences = UiPlugin.getUserPreferences(); - Preferences node = userPreferences.node(PREFERENCE_ID); - return node; - } - - private static class Configuration { - public static final Configuration DEFAULT=new Configuration(); - - Collection tipIDs; - Collection extensionIDs; - - Configuration(IConfigurationElement confElem) { - this.tipIDs=new HashSet(); - this.extensionIDs=new HashSet(); - IConfigurationElement[] tipRefs = confElem.getChildren("tipRef"); //$NON-NLS-1$ - for (IConfigurationElement element : tipRefs) { - String attribute = element.getAttribute("tipID"); //$NON-NLS-1$ - if( attribute!=null ) - tipIDs.add(attribute); - } - IConfigurationElement[] extensionRefs = confElem.getChildren("tipExtensionRef"); //$NON-NLS-1$ - for (IConfigurationElement element : extensionRefs) { - String attribute = element.getAttribute("extensionID"); //$NON-NLS-1$ - if( attribute!=null ) - extensionIDs.add(attribute); - } - } - - Configuration() { - // do nothing - } - } - - private static class Tip { - public String id; - - ImageDescriptor image; - - String name; - - String hint; - - Tip(IConfigurationElement tipElem) { - id = tipElem.getAttribute("id"); //$NON-NLS-1$ - name = tipElem.getAttribute("name"); //$NON-NLS-1$ - hint = tipElem.getValue(); - if (tipElem.getAttribute("icon") != null) { //$NON-NLS-1$ - image = AbstractUIPlugin.imageDescriptorFromPlugin(tipElem - .getNamespaceIdentifier(), tipElem.getAttribute("icon")); //$NON-NLS-1$ - } else { - image = AbstractUIPlugin.imageDescriptorFromPlugin(UiPlugin.ID, - "icons/elcl16/light.GIF"); //$NON-NLS-1$ - } - } - } + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.NEXT_ID, IDialogConstants.NEXT_LABEL, false); + createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, true); + } + + @Override + protected void buttonPressed(int buttonId) { + if (IDialogConstants.NEXT_ID == buttonId) { + next(-1); + updateTip(); + } + if (buttonId == IDialogConstants.CLOSE_ID) { + IPreferenceStore store = UiPlugin.getDefault().getPreferenceStore(); + store.setValue(PreferenceConstants.P_SHOW_TIPS, check.getSelection()); + okPressed(); + } + } + + public static boolean hasTips() { + return getCurrentTip() != null; + } + + private static Tip getCurrentTip() { + if (current == null) { + next(-1); + } + return current; + } + + private static boolean isInCurrentConfiguration(IConfigurationElement elem) { + if (currentConfiguration == null) { + + List extensions = ExtensionPointList + .getExtensionPointList(EXTENSION_ID); + IConfigurationElement mostRecent = null; + for (IConfigurationElement element : extensions) { + if (element.getName().equals("activeConfiguration")) { //$NON-NLS-1$ + String attribute = element.getAttribute("configurationID"); //$NON-NLS-1$ + if (attribute != null) + mostRecent = element; + } + } + if (mostRecent == null) { + currentConfiguration = Configuration.DEFAULT; + } else { + for (IConfigurationElement element : extensions) { + if (mostRecent.getAttribute("configurationID") //$NON-NLS-1$ + .equals(element.getAttribute("id"))) { //$NON-NLS-1$ + currentConfiguration = new Configuration(element); + break; + } + } + if (currentConfiguration.extensionIDs.size() == 0 + && currentConfiguration.tipIDs.size() == 0) + currentConfiguration = Configuration.DEFAULT; + + } + } + if (currentConfiguration == Configuration.DEFAULT) { + return true; + } + + return currentConfiguration.tipIDs.contains(elem.getAttribute("id")) //$NON-NLS-1$ + || currentConfiguration.extensionIDs + .contains(elem.getDeclaringExtension().getUniqueIdentifier()); + } + + private static void next(int next2) { + int next = next2; + try { + Preferences node = getPreferences(); + List extensions = ExtensionPointList + .getExtensionPointList(EXTENSION_ID); + if (next == -1) { + Random r = new Random(); + next = r.nextInt(extensions.size()); + } + for (int i = next; i < extensions.size(); i++) { + IConfigurationElement elem = extensions.get(i); + if (isPermittedNext(node, elem)) { + node.put(elem.getAttribute("id"), ""); //$NON-NLS-1$ //$NON-NLS-2$ + current = new Tip(elem); + return; + } + } + for (int i = 0; i < next; i++) { + IConfigurationElement elem = extensions.get(i); + if (isPermittedNext(node, elem)) { + node.put(elem.getAttribute("id"), ""); //$NON-NLS-1$ //$NON-NLS-2$ + current = new Tip(elem); + return; + } + } + if (node.keys().length == 0) { + current = null; + return; + } + node.clear(); + next(next); + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + + private static boolean isPermittedNext(Preferences node, IConfigurationElement elem) { + if (!elem.getName().equals("tip")) //$NON-NLS-1$ + return false; + boolean notPreviouslyShown = node.get(elem.getAttribute("id"), null) == null; //$NON-NLS-1$ + boolean notSameAsCurrent = (current == null || !elem.getAttribute("id") //$NON-NLS-1$ + .equals(current.id)); + return notPreviouslyShown && notSameAsCurrent && isInCurrentConfiguration(elem); + } + + public static Preferences getPreferences() throws CoreException, IOException { + Preferences userPreferences = UiPlugin.getUserPreferences(); + Preferences node = userPreferences.node(PREFERENCE_ID); + return node; + } + + private static class Configuration { + public static final Configuration DEFAULT = new Configuration(); + + Collection tipIDs; + + Collection extensionIDs; + + Configuration(IConfigurationElement confElem) { + this.tipIDs = new HashSet<>(); + this.extensionIDs = new HashSet<>(); + IConfigurationElement[] tipRefs = confElem.getChildren("tipRef"); //$NON-NLS-1$ + for (IConfigurationElement element : tipRefs) { + String attribute = element.getAttribute("tipID"); //$NON-NLS-1$ + if (attribute != null) + tipIDs.add(attribute); + } + IConfigurationElement[] extensionRefs = confElem.getChildren("tipExtensionRef"); //$NON-NLS-1$ + for (IConfigurationElement element : extensionRefs) { + String attribute = element.getAttribute("extensionID"); //$NON-NLS-1$ + if (attribute != null) + extensionIDs.add(attribute); + } + } + + Configuration() { + // do nothing + } + } + + private static class Tip { + public String id; + + ImageDescriptor image; + + String name; + + String hint; + + Tip(IConfigurationElement tipElem) { + id = tipElem.getAttribute("id"); //$NON-NLS-1$ + name = tipElem.getAttribute("name"); //$NON-NLS-1$ + hint = tipElem.getValue(); + if (tipElem.getAttribute("icon") != null) { //$NON-NLS-1$ + image = AbstractUIPlugin.imageDescriptorFromPlugin(tipElem.getNamespaceIdentifier(), + tipElem.getAttribute("icon")); //$NON-NLS-1$ + } else { + image = AbstractUIPlugin.imageDescriptorFromPlugin(UiPlugin.ID, + "icons/elcl16/light.GIF"); //$NON-NLS-1$ + } + } + } } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGActionBarAdvisor.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGActionBarAdvisor.java index 36b730866b..c6eb16c96e 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGActionBarAdvisor.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGActionBarAdvisor.java @@ -1,544 +1,544 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.internal.ui; - -import java.text.MessageFormat; -import java.util.Collections; -import java.util.List; - -import org.locationtech.udig.core.internal.ExtensionPointList; -import org.locationtech.udig.ui.Constants; -import org.locationtech.udig.ui.MenuBuilder; -import org.locationtech.udig.ui.UDIGMenuBuilder; -import org.locationtech.udig.ui.action.NewObjectContribution; -import org.locationtech.udig.ui.action.NewObjectDelegate; -import org.locationtech.udig.ui.action.NewObjectDelegateComparator; -import org.locationtech.udig.ui.internal.Messages; -import org.locationtech.udig.ui.preferences.PreferenceConstants; - -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IProduct; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.ActionContributionItem; -import org.eclipse.jface.action.GroupMarker; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.action.IContributionItem; -import org.eclipse.jface.action.ICoolBarManager; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.ui.IWorkbenchActionConstants; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.ContributionItemFactory; -import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; -import org.eclipse.ui.application.ActionBarAdvisor; -import org.eclipse.ui.application.IActionBarConfigurer; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; - -/** - * Public base class for configuring the action bars of a workbench window. - *

    - * For UDIG 1.1: An application should leave this alone; and use the *org.eclipse.ui.menu* extension - * point to slot commands into menus as needed. This ActionBarAdvisor provides the following basic - * menus that should be applicable to all UDIG based applications: - *

      - *
    • - *
    - * If you are wondering about the Navigate, Layer and Data menus please go check out the - * net.refractions.catalog.ui and net.refractions.project.ui. - *

    - * For UDIG 1.0: An application should declare a subclass of ActionBarAdvisor and - * override methods to configure a window's action bars to suit the needs of the particular - * application. - *

    - *

    - * The following advisor methods are called at strategic points in the - * workbench's lifecycle (all occur within the dynamic scope of the call - * to {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}): - *

      - *
    • fillActionBars - called after WorkbenchWindowAdvisor.preWindowOpen - * to configure a window's action bars
    • - *
    - *

    - * - * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer) - * @author cole.markham - * @since 1.0.0 - */ -public class UDIGActionBarAdvisor extends ActionBarAdvisor { - /** - * Strategy Object used to configure menus according to external preference. Considering that is - * also the job of an ActionBarAdvisor we have some duplication going on here. - */ - private MenuBuilder menuBuilder; - /** - * Default constructor - * - * @param configurer - */ - public UDIGActionBarAdvisor( IActionBarConfigurer configurer ) { - super(configurer); - } - - private MenuBuilder lookupMenuBuilder() { - Class interfaceClass = MenuBuilder.class; - String prefConstant = PreferenceConstants.P_MENU_BUILDER; - String xpid = MenuBuilder.XPID; - String idField = MenuBuilder.ATTR_ID; - String classField = MenuBuilder.ATTR_CLASS; - - MenuBuilder mb = (MenuBuilder) UiPlugin.lookupConfigurationObject(interfaceClass, - UiPlugin.getDefault().getPreferenceStore(), UiPlugin.ID, prefConstant, xpid, - idField, classField); - if (mb != null) { - return mb; - } - return new UDIGMenuBuilder(); - } - - /** - * Get the MenuFactory which will create the menus for this plugin - * - * @return The MenuFactory singleton - */ - protected MenuBuilder getMenuFactory() { - if (menuBuilder == null) { - menuBuilder = lookupMenuBuilder(); - } - return menuBuilder; - } - - @Override - protected void fillCoolBar( ICoolBarManager coolBar ) { - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - - MenuBuilder override = getMenuFactory(); - if (override != null && !(override instanceof UDIGMenuBuilder)) { - // Allows override; deprecated; please write your - // own ActionBarAdvisor rather - override.fillCoolBar(coolBar, window); - } else { - new UDIGMenuBuilder().fillCoolBar(coolBar, window); - } - } - - @Override - protected void fillMenuBar( IMenuManager menuBar ) { - menuBar.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); - - // Support use of MenuBuilder for RCP applications based on uDig - // (org.eclipse.ui.menu is preferred!) - MenuBuilder override = getMenuFactory(); - if (override != null && !(override instanceof UDIGMenuBuilder)) { - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - override.fillMenuBar(menuBar, window); - return; - } - - MenuManager fileMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_file, - IWorkbenchActionConstants.M_FILE); - fillFileMenu(fileMenu); - menuBar.add(fileMenu); - - IMenuManager editMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_edit, - IWorkbenchActionConstants.M_EDIT); - editMenu.add(new GroupMarker(IWorkbenchActionConstants.FIND_EXT)); - fillEditMenu(editMenu); - menuBar.add(editMenu); - - if( true ){ - // TODO: phase these out with org.eclipse.ui.menus - IMenuManager navMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_navigationMenu, - Constants.M_NAVIGATE); - fillNavigateMenu(navMenu); - menuBar.add(navMenu); - - IMenuManager toolMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_tools, - Constants.M_TOOL); - fillToolMenu(toolMenu); - menuBar.add(toolMenu); - } - - menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - - IMenuManager windowMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_window, - IWorkbenchActionConstants.M_WINDOW); - fillWindowMenu(windowMenu); - menuBar.add(windowMenu); - - IMenuManager helpMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_help, - IWorkbenchActionConstants.M_HELP); - fillHelpMenu(helpMenu); - menuBar.add(helpMenu); - - menuBar.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); - - if( true ){ - // clue in operations about the window - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - - UiPlugin.getDefault().getOperationMenuFactory().setWindow(window); - } - } - - /** - * Set up customary Navigate menu structure as defined by Constants. - *

    - * The uDig navigate menu is a mash up between the traditional functionality - * such as "showIn" to open views; along side commands to navigate around the - * current map (complete with back / forward history like a web browser). - *

    -     * navigate
    -     * navigate/navStart
    -     * navigate/zoom.ext
    -     * navigate/additions
    -     * navigate/bottom
    -     * navigate/navEnd
    -     * 
    - * - * @param menu - */ - protected void fillNavigateMenu( IMenuManager menu ) { - // menu.add(ActionFactory.BACKWARD_HISTORY.create(window)); - // menu.add(ActionFactory.FORWARD_HISTORY.create(window)); - menu.add(new GroupMarker(Constants.NAV_START)); - menu.add(new Separator()); - menu.add(new GroupMarker(Constants.NAV_ZOOM_EXT)); - - menu.add(new Separator()); - menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - - menu.add(new Separator()); - menu.add(new GroupMarker(Constants.NAV_BOTTOM)); - menu.add(new GroupMarker(Constants.NAV_END)); - menu.setVisible(true); - } - - /** - * Set up Tool menu, used to interact with Map Editor. - *
    -     * tools
    -     * tools/wbStart
    -     * tools/zoom.ext
    -     * tools/additions
    -     * tools/wbEnd
    -     * 
    - * @param menu - */ - protected void fillToolMenu( IMenuManager menu) { - menu.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); - menu.add(new GroupMarker(Constants.TOOL_ACTION)); - menu.add(new Separator()); - menu.add(new GroupMarker(Constants.TOOL_MODAL)); - menu.add(new Separator()); - menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - menu.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); - } - - /** - * Set up customary File menu structure as defined by IWorkBenchActionConstants. - *

    - * We are focused on providing the usual "group markers" so that menu paths for action sets, - * tools, operations or menus will work out okay (for this or *any* RCP application). - * - *

    -     * file/fileStart
    -     * file/new.ext
    -     * file/new
    -     * file/project.ext
    -     * file/close.ext
    -     * file/close
    -     * file/save.ext
    -     * file/save
    -     * file/additions
    -     * file/print.ext
    -     * file/import.ext
    -     * file/import
    -     * file/export
    -     * file/mru
    -     * file/fileEnd
    -     * file/quit
    -     * 
    - * - * @param window - * @param fileMenu - */ - protected void fillFileMenu( IMenuManager fileMenu ) { - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - - fileMenu.add(new GroupMarker(Constants.FILE_START)); - - IMenuManager newMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_new, ActionFactory.NEW - .getId()); - newMenu.add(new GroupMarker(Constants.NEW_START)); - List list = ExtensionPointList - .getExtensionPointList(NewObjectContribution.NEW_ACTION_ID); - Collections.sort(list, new NewObjectDelegateComparator()); - for( IConfigurationElement element : list ) { - final NewObjectDelegate item = new NewObjectDelegate(element, window); - Action newAction = new Action(){ - @Override - public void runWithEvent( org.eclipse.swt.widgets.Event event ) { - item.runAction(); - } - }; - newAction.setText(item.text); - newAction.setImageDescriptor(item.icon); - newMenu.appendToGroup(Constants.NEW_START, newAction); - } - newMenu.add(ContributionItemFactory.NEW_WIZARD_SHORTLIST.create(window)); - - fileMenu.add(newMenu); - fileMenu.add(new GroupMarker(Constants.OPEN_EXT)); - fileMenu.add(new Separator()); - fileMenu.add(new GroupMarker(Constants.PROJECT_EXT)); - fileMenu.add(new Separator()); - fileMenu.add(new GroupMarker(Constants.CLOSE_EXT)); - fileMenu.add(ActionFactory.CLOSE.create(window)); - fileMenu.add(ActionFactory.CLOSE_ALL.create(window)); - fileMenu.add(new Separator()); - - fileMenu.add(new GroupMarker(Constants.SAVE_EXT)); - fileMenu.add(ActionFactory.SAVE.create(window)); - fileMenu.add(ActionFactory.SAVE_ALL.create(window)); - fileMenu.add(new Separator()); - - fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - fileMenu.add(new GroupMarker(ActionFactory.REFRESH.getId())); - fileMenu.add(new GroupMarker(Constants.RENAME_EXT)); - fileMenu.add(new Separator()); - - fileMenu.add(new GroupMarker(IWorkbenchActionConstants.PRINT_EXT)); - fileMenu.add(new Separator()); - - fileMenu.add(ActionFactory.IMPORT.create(window)); - fileMenu.add(ActionFactory.EXPORT.create(window)); - fileMenu.add(new Separator()); - fileMenu.add(ActionFactory.PROPERTIES.create(window)); - - fileMenu.add(new GroupMarker(Constants.CONFIG_EXT)); - fileMenu.add(new Separator()); - - fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MRU)); - - fileMenu.add(new GroupMarker(IWorkbenchActionConstants.FILE_END)); - - IWorkbenchAction quit = ActionFactory.QUIT.create(window); - IContributionItem item = new ActionContributionItem(quit); - item.setVisible(!Platform.OS_MACOSX.equals(Platform.getOS())); - - fileMenu.add(item); - } - - /** - * Define the Edit Menu according to RCP "custom". - *

    - * Most of the "custom" here is recorded as part of IWorkbenchActionsConstants; we are doing the - * bare minimum here; only positioning the "group markers" in the correct spot so the relative - * menu path goodness will work for later plugin contributions (using org.eclipse.ui.menu - * extensions). - * - *

    -     * edit/editStart
    -     * edit/undo.ext
    -     * edit/cut.ext
    -     * edit/add.ext
    -     * edit/additions
    -     * edit/other
    -     * edit/commit.ext
    -     * edit/editEnd
    -     * 
    - * - * @param window - * @param editMenu - */ - protected void fillEditMenu( IMenuManager editMenu ) { - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - - editMenu.add(new GroupMarker(Constants.EDIT_START)); - - editMenu.add(new GroupMarker(Constants.UNDO_EXT)); - editMenu.add(ActionFactory.UNDO.create(window)); - editMenu.add(ActionFactory.REDO.create(window)); - editMenu.add(new Separator()); - - editMenu.add(new GroupMarker(Constants.CUT_EXT)); - editMenu.add(ActionFactory.CUT.create(window)); - editMenu.add(ActionFactory.COPY.create(window)); - editMenu.add(ActionFactory.PASTE.create(window)); - editMenu.add(new Separator()); - - editMenu.add(ActionFactory.DELETE.create(window)); - editMenu.add(ActionFactory.SELECT_ALL.create(window)); - editMenu.add(new GroupMarker(Constants.ADD_EXT)); - editMenu.add(new Separator()); - - editMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - editMenu.add(new GroupMarker(Constants.OTHER)); - editMenu.add(new Separator()); - - editMenu.add(new GroupMarker(Constants.COMMIT_EXT)); - editMenu.add(new GroupMarker(Constants.EDIT_END)); - } - - private void fillLayerMenu( IMenuManager menu) { - menu.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); - menu.add(new GroupMarker(Constants.LAYER_ADD_EXT)); - menu.add(new Separator()); - menu.add(new GroupMarker(Constants.LAYER_MAPGRAPHIC_EXT)); - menu.add(new GroupMarker(Constants.LAYER_MAPGRAPHIC_OTHER)); - menu.add(new Separator()); - menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - menu.add(new GroupMarker(Constants.LAYER_EDIT_EXT)); - menu.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); - } - - /** - * Define the Window Menu according to RCP "custom". - *

    - * The window menu is mostly concerned with the care and feeding of application wide - * customisations and settings; from access to application preferences to opening up views and - * switching perspectives. - *

    - * window/wbStart window/... window/additions window/wbEnd - * - * @param windowMenu - */ - protected void fillWindowMenu( IMenuManager windowMenu ) { - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - - windowMenu.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); - - //IAction openNewWindow = ActionFactory.OPEN_NEW_WINDOW.create(window); - //openNewWindow.setText(Messages.UDIGWorkbenchAdvisor_newWindow_text); - //windowMenu.add(openNewWindow); - - //windowMenu.add( new Separator()); - - IMenuManager perspectiveMenu = new MenuManager( - Messages.UDIGWorkbenchAdvisor_open_perspective, - ContributionItemFactory.PERSPECTIVES_SHORTLIST.getId()); - perspectiveMenu.add(ContributionItemFactory.PERSPECTIVES_SHORTLIST.create(window)); - windowMenu.add(perspectiveMenu); - - IMenuManager viewMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_show_view, - ContributionItemFactory.VIEWS_SHORTLIST.getId()); - viewMenu.add(ContributionItemFactory.VIEWS_SHORTLIST.create(window)); - windowMenu.add(viewMenu); - windowMenu.add( new Separator()); - - IAction resetPerspective = ActionFactory.RESET_PERSPECTIVE.create(window); - resetPerspective.setText(Messages.UDIGWorkbenchAdvisor_resetPerspective_text); - windowMenu.add(resetPerspective); - - IAction closePerspective = ActionFactory.CLOSE_PERSPECTIVE.create(window); - closePerspective.setText(Messages.UDIGWorkbenchAdvisor_closePerspective_text); - windowMenu.add(closePerspective); - - IAction closeAllPerspectives = ActionFactory.CLOSE_ALL_PERSPECTIVES.create(window); - closeAllPerspectives.setText(Messages.UDIGWorkbenchAdvisor_closeAllPerspectives_text); - windowMenu.add(closeAllPerspectives); - - windowMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - - windowMenu.add( new Separator()); - - IAction preferences = ActionFactory.PREFERENCES.create(window); - preferences.setText(Messages.UDIGWorkbenchAdvisor_preferences_text); - IContributionItem item = new ActionContributionItem(preferences); - item.setVisible(!Platform.OS_MACOSX.equals(Platform.getOS())); - - windowMenu.add(item); - - windowMenu.add(ContributionItemFactory.OPEN_WINDOWS.create(window)); - - windowMenu.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); - } - - protected void fillHelpMenu( IMenuManager helpMenu ) { - IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); - - boolean hasIntro = window - .getWorkbench().getIntroManager().hasIntro(); - if (hasIntro) { - if (helpMenu.findUsingPath(ActionFactory.INTRO.getId()) == null) { - IAction welcome = ActionFactory.INTRO.create(window); - welcome.setText(Messages.UDIGWorkbenchAdvisor_welcome_text); - if (helpMenu.getItems().length > 0) { - helpMenu.insertBefore(helpMenu.getItems()[0].getId(), welcome); - } else { - helpMenu.add(welcome); - } - } - } else { - Separator welcome = new Separator(ActionFactory.INTRO.getId()); - if (helpMenu.getItems().length > 0) { - helpMenu.insertBefore(helpMenu.getItems()[0].getId(), welcome); - } else { - helpMenu.add(welcome); - } - } - - if (helpMenu.findUsingPath(Constants.HELP_START) == null) { - helpMenu - .insertAfter(ActionFactory.INTRO.getId(), new GroupMarker(Constants.HELP_START)); - } - - if (helpMenu.findUsingPath(ActionFactory.HELP_CONTENTS.getId()) == null) { - IAction helpContents = ActionFactory.HELP_CONTENTS.create(window); - helpContents.setText(Messages.UDIGWorkbenchAdvisor_helpContents_text); - helpMenu.insertBefore(Constants.HELP_START, helpContents); - } - - if (helpMenu.findUsingPath(Constants.HELP_END) == null) { - helpMenu.insertAfter(Constants.HELP_START, new GroupMarker(Constants.HELP_END)); - } - - // Tips and tricks page would go after HELP_START - - if (helpMenu.findUsingPath(IWorkbenchActionConstants.MB_ADDITIONS) == null) { - helpMenu.insertAfter(Constants.HELP_END, new GroupMarker( - IWorkbenchActionConstants.MB_ADDITIONS)); - } - - // Add the separators - helpMenu.insertAfter(ActionFactory.INTRO.getId(), new Separator()); - helpMenu.insertBefore(Constants.HELP_START, new Separator()); - helpMenu.insertAfter(Constants.HELP_END, new Separator()); - // helpMenu.insertAfter(, new Separator()); - - addAboutItem(helpMenu, window); - } - - private void addAboutItem( IMenuManager helpMenu, IWorkbenchWindow window ) { - if (helpMenu.findUsingPath(ActionFactory.ABOUT.getId()) == null) { - IAction about = ActionFactory.ABOUT.create(window); - String pattern = Messages.UDIGWorkbenchAdvisor_aboutUDig_text; - IProduct product = Platform.getProduct(); - String productName; - if( product == null ){ - UiPlugin.log("there is no product so default to uDig", null); - productName = "uDig"; - }else{ - productName = product.getName(); - } - about.setText(MessageFormat.format(pattern, productName)); - // About should always be at the bottom, so just append it to the menu - IContributionItem item = new ActionContributionItem(about); - item.setVisible(!Platform.OS_MACOSX.equals(Platform.getOS())); - - helpMenu.add(item); - } - } -} +/** + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.internal.ui; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IProduct; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.ICoolBarManager; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.actions.ContributionItemFactory; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.ui.Constants; +import org.locationtech.udig.ui.MenuBuilder; +import org.locationtech.udig.ui.UDIGMenuBuilder; +import org.locationtech.udig.ui.action.NewObjectContribution; +import org.locationtech.udig.ui.action.NewObjectDelegate; +import org.locationtech.udig.ui.action.NewObjectDelegateComparator; +import org.locationtech.udig.ui.internal.Messages; +import org.locationtech.udig.ui.preferences.PreferenceConstants; + +/** + * Public base class for configuring the action bars of a workbench window. + *

    + * For UDIG 1.1: An application should leave this alone; and use the *org.eclipse.ui.menu* extension + * point to slot commands into menus as needed. This ActionBarAdvisor provides the following basic + * menus that should be applicable to all UDIG based applications: + *

      + *
    • + *
    + * If you are wondering about the Navigate, Layer and Data menus please go check out the + * net.refractions.catalog.ui and net.refractions.project.ui. + *

    + * For UDIG 1.0: An application should declare a subclass of ActionBarAdvisor and + * override methods to configure a window's action bars to suit the needs of the particular + * application. + *

    + *

    + * The following advisor methods are called at strategic points in the + * workbench's lifecycle (all occur within the dynamic scope of the call + * to {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}): + *

      + *
    • fillActionBars - called after WorkbenchWindowAdvisor.preWindowOpen + * to configure a window's action bars
    • + *
    + *

    + * + * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer) + * @author cole.markham + * @since 1.0.0 + */ +public class UDIGActionBarAdvisor extends ActionBarAdvisor { + /** + * Strategy Object used to configure menus according to external preference. Considering that is + * also the job of an ActionBarAdvisor we have some duplication going on here. + */ + private MenuBuilder menuBuilder; + /** + * Default constructor + * + * @param configurer + */ + public UDIGActionBarAdvisor( IActionBarConfigurer configurer ) { + super(configurer); + } + + private MenuBuilder lookupMenuBuilder() { + Class interfaceClass = MenuBuilder.class; + String prefConstant = PreferenceConstants.P_MENU_BUILDER; + String xpid = MenuBuilder.XPID; + String idField = MenuBuilder.ATTR_ID; + String classField = MenuBuilder.ATTR_CLASS; + + MenuBuilder mb = (MenuBuilder) UiPlugin.lookupConfigurationObject(interfaceClass, + UiPlugin.getDefault().getPreferenceStore(), UiPlugin.ID, prefConstant, xpid, + idField, classField); + if (mb != null) { + return mb; + } + return new UDIGMenuBuilder(); + } + + /** + * Get the MenuFactory which will create the menus for this plugin + * + * @return The MenuFactory singleton + */ + protected MenuBuilder getMenuFactory() { + if (menuBuilder == null) { + menuBuilder = lookupMenuBuilder(); + } + return menuBuilder; + } + + @Override + protected void fillCoolBar( ICoolBarManager coolBar ) { + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + + MenuBuilder override = getMenuFactory(); + if (override != null && !(override instanceof UDIGMenuBuilder)) { + // Allows override; deprecated; please write your + // own ActionBarAdvisor rather + override.fillCoolBar(coolBar, window); + } else { + new UDIGMenuBuilder().fillCoolBar(coolBar, window); + } + } + + @Override + protected void fillMenuBar( IMenuManager menuBar ) { + menuBar.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); + + // Support use of MenuBuilder for RCP applications based on uDig + // (org.eclipse.ui.menu is preferred!) + MenuBuilder override = getMenuFactory(); + if (override != null && !(override instanceof UDIGMenuBuilder)) { + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + override.fillMenuBar(menuBar, window); + return; + } + + MenuManager fileMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_file, + IWorkbenchActionConstants.M_FILE); + fillFileMenu(fileMenu); + menuBar.add(fileMenu); + + IMenuManager editMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_edit, + IWorkbenchActionConstants.M_EDIT); + editMenu.add(new GroupMarker(IWorkbenchActionConstants.FIND_EXT)); + fillEditMenu(editMenu); + menuBar.add(editMenu); + + if( true ){ + // TODO: phase these out with org.eclipse.ui.menus + IMenuManager navMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_navigationMenu, + Constants.M_NAVIGATE); + fillNavigateMenu(navMenu); + menuBar.add(navMenu); + + IMenuManager toolMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_tools, + Constants.M_TOOL); + fillToolMenu(toolMenu); + menuBar.add(toolMenu); + } + + menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + + IMenuManager windowMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_window, + IWorkbenchActionConstants.M_WINDOW); + fillWindowMenu(windowMenu); + menuBar.add(windowMenu); + + IMenuManager helpMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_help, + IWorkbenchActionConstants.M_HELP); + fillHelpMenu(helpMenu); + menuBar.add(helpMenu); + + menuBar.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); + + if( true ){ + // clue in operations about the window + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + + UiPlugin.getDefault().getOperationMenuFactory().setWindow(window); + } + } + + /** + * Set up customary Navigate menu structure as defined by Constants. + *

    + * The uDig navigate menu is a mash up between the traditional functionality + * such as "showIn" to open views; along side commands to navigate around the + * current map (complete with back / forward history like a web browser). + *

    +     * navigate
    +     * navigate/navStart
    +     * navigate/zoom.ext
    +     * navigate/additions
    +     * navigate/bottom
    +     * navigate/navEnd
    +     * 
    + * + * @param menu + */ + protected void fillNavigateMenu( IMenuManager menu ) { + // menu.add(ActionFactory.BACKWARD_HISTORY.create(window)); + // menu.add(ActionFactory.FORWARD_HISTORY.create(window)); + menu.add(new GroupMarker(Constants.NAV_START)); + menu.add(new Separator()); + menu.add(new GroupMarker(Constants.NAV_ZOOM_EXT)); + + menu.add(new Separator()); + menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + + menu.add(new Separator()); + menu.add(new GroupMarker(Constants.NAV_BOTTOM)); + menu.add(new GroupMarker(Constants.NAV_END)); + menu.setVisible(true); + } + + /** + * Set up Tool menu, used to interact with Map Editor. + *
    +     * tools
    +     * tools/wbStart
    +     * tools/zoom.ext
    +     * tools/additions
    +     * tools/wbEnd
    +     * 
    + * @param menu + */ + protected void fillToolMenu( IMenuManager menu) { + menu.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); + menu.add(new GroupMarker(Constants.TOOL_ACTION)); + menu.add(new Separator()); + menu.add(new GroupMarker(Constants.TOOL_MODAL)); + menu.add(new Separator()); + menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + menu.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); + } + + /** + * Set up customary File menu structure as defined by IWorkBenchActionConstants. + *

    + * We are focused on providing the usual "group markers" so that menu paths for action sets, + * tools, operations or menus will work out okay (for this or *any* RCP application). + * + *

    +     * file/fileStart
    +     * file/new.ext
    +     * file/new
    +     * file/project.ext
    +     * file/close.ext
    +     * file/close
    +     * file/save.ext
    +     * file/save
    +     * file/additions
    +     * file/print.ext
    +     * file/import.ext
    +     * file/import
    +     * file/export
    +     * file/mru
    +     * file/fileEnd
    +     * file/quit
    +     * 
    + * + * @param window + * @param fileMenu + */ + protected void fillFileMenu( IMenuManager fileMenu ) { + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + + fileMenu.add(new GroupMarker(Constants.FILE_START)); + + IMenuManager newMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_new, ActionFactory.NEW + .getId()); + newMenu.add(new GroupMarker(Constants.NEW_START)); + List list = ExtensionPointList + .getExtensionPointList(NewObjectContribution.NEW_ACTION_ID); + Collections.sort(list, new NewObjectDelegateComparator()); + for( IConfigurationElement element : list ) { + final NewObjectDelegate item = new NewObjectDelegate(element, window); + Action newAction = new Action(){ + @Override + public void runWithEvent( org.eclipse.swt.widgets.Event event ) { + item.runAction(); + } + }; + newAction.setText(item.text); + newAction.setImageDescriptor(item.icon); + newMenu.appendToGroup(Constants.NEW_START, newAction); + } + newMenu.add(ContributionItemFactory.NEW_WIZARD_SHORTLIST.create(window)); + + fileMenu.add(newMenu); + fileMenu.add(new GroupMarker(Constants.OPEN_EXT)); + fileMenu.add(new Separator()); + fileMenu.add(new GroupMarker(Constants.PROJECT_EXT)); + fileMenu.add(new Separator()); + fileMenu.add(new GroupMarker(Constants.CLOSE_EXT)); + fileMenu.add(ActionFactory.CLOSE.create(window)); + fileMenu.add(ActionFactory.CLOSE_ALL.create(window)); + fileMenu.add(new Separator()); + + fileMenu.add(new GroupMarker(Constants.SAVE_EXT)); + fileMenu.add(ActionFactory.SAVE.create(window)); + fileMenu.add(ActionFactory.SAVE_ALL.create(window)); + fileMenu.add(new Separator()); + + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + fileMenu.add(new GroupMarker(ActionFactory.REFRESH.getId())); + fileMenu.add(new GroupMarker(Constants.RENAME_EXT)); + fileMenu.add(new Separator()); + + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.PRINT_EXT)); + fileMenu.add(new Separator()); + + fileMenu.add(ActionFactory.IMPORT.create(window)); + fileMenu.add(ActionFactory.EXPORT.create(window)); + fileMenu.add(new Separator()); + fileMenu.add(ActionFactory.PROPERTIES.create(window)); + + fileMenu.add(new GroupMarker(Constants.CONFIG_EXT)); + fileMenu.add(new Separator()); + + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MRU)); + + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.FILE_END)); + + IWorkbenchAction quit = ActionFactory.QUIT.create(window); + IContributionItem item = new ActionContributionItem(quit); + item.setVisible(!Platform.OS_MACOSX.equals(Platform.getOS())); + + fileMenu.add(item); + } + + /** + * Define the Edit Menu according to RCP "custom". + *

    + * Most of the "custom" here is recorded as part of IWorkbenchActionsConstants; we are doing the + * bare minimum here; only positioning the "group markers" in the correct spot so the relative + * menu path goodness will work for later plugin contributions (using org.eclipse.ui.menu + * extensions). + * + *

    +     * edit/editStart
    +     * edit/undo.ext
    +     * edit/cut.ext
    +     * edit/add.ext
    +     * edit/additions
    +     * edit/other
    +     * edit/commit.ext
    +     * edit/editEnd
    +     * 
    + * + * @param window + * @param editMenu + */ + protected void fillEditMenu( IMenuManager editMenu ) { + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + + editMenu.add(new GroupMarker(Constants.EDIT_START)); + + editMenu.add(new GroupMarker(Constants.UNDO_EXT)); + editMenu.add(ActionFactory.UNDO.create(window)); + editMenu.add(ActionFactory.REDO.create(window)); + editMenu.add(new Separator()); + + editMenu.add(new GroupMarker(Constants.CUT_EXT)); + editMenu.add(ActionFactory.CUT.create(window)); + editMenu.add(ActionFactory.COPY.create(window)); + editMenu.add(ActionFactory.PASTE.create(window)); + editMenu.add(new Separator()); + + editMenu.add(ActionFactory.DELETE.create(window)); + editMenu.add(ActionFactory.SELECT_ALL.create(window)); + editMenu.add(new GroupMarker(Constants.ADD_EXT)); + editMenu.add(new Separator()); + + editMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + editMenu.add(new GroupMarker(Constants.OTHER)); + editMenu.add(new Separator()); + + editMenu.add(new GroupMarker(Constants.COMMIT_EXT)); + editMenu.add(new GroupMarker(Constants.EDIT_END)); + } + + private void fillLayerMenu( IMenuManager menu) { + menu.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); + menu.add(new GroupMarker(Constants.LAYER_ADD_EXT)); + menu.add(new Separator()); + menu.add(new GroupMarker(Constants.LAYER_MAPGRAPHIC_EXT)); + menu.add(new GroupMarker(Constants.LAYER_MAPGRAPHIC_OTHER)); + menu.add(new Separator()); + menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + menu.add(new GroupMarker(Constants.LAYER_EDIT_EXT)); + menu.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); + } + + /** + * Define the Window Menu according to RCP "custom". + *

    + * The window menu is mostly concerned with the care and feeding of application wide + * customisations and settings; from access to application preferences to opening up views and + * switching perspectives. + *

    + * window/wbStart window/... window/additions window/wbEnd + * + * @param windowMenu + */ + protected void fillWindowMenu( IMenuManager windowMenu ) { + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + + windowMenu.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); + + //IAction openNewWindow = ActionFactory.OPEN_NEW_WINDOW.create(window); + //openNewWindow.setText(Messages.UDIGWorkbenchAdvisor_newWindow_text); + //windowMenu.add(openNewWindow); + + //windowMenu.add( new Separator()); + + IMenuManager perspectiveMenu = new MenuManager( + Messages.UDIGWorkbenchAdvisor_open_perspective, + ContributionItemFactory.PERSPECTIVES_SHORTLIST.getId()); + perspectiveMenu.add(ContributionItemFactory.PERSPECTIVES_SHORTLIST.create(window)); + windowMenu.add(perspectiveMenu); + + IMenuManager viewMenu = new MenuManager(Messages.UDIGWorkbenchAdvisor_show_view, + ContributionItemFactory.VIEWS_SHORTLIST.getId()); + viewMenu.add(ContributionItemFactory.VIEWS_SHORTLIST.create(window)); + windowMenu.add(viewMenu); + windowMenu.add( new Separator()); + + IAction resetPerspective = ActionFactory.RESET_PERSPECTIVE.create(window); + resetPerspective.setText(Messages.UDIGWorkbenchAdvisor_resetPerspective_text); + windowMenu.add(resetPerspective); + + IAction closePerspective = ActionFactory.CLOSE_PERSPECTIVE.create(window); + closePerspective.setText(Messages.UDIGWorkbenchAdvisor_closePerspective_text); + windowMenu.add(closePerspective); + + IAction closeAllPerspectives = ActionFactory.CLOSE_ALL_PERSPECTIVES.create(window); + closeAllPerspectives.setText(Messages.UDIGWorkbenchAdvisor_closeAllPerspectives_text); + windowMenu.add(closeAllPerspectives); + + windowMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + + windowMenu.add( new Separator()); + + IAction preferences = ActionFactory.PREFERENCES.create(window); + preferences.setText(Messages.UDIGWorkbenchAdvisor_preferences_text); + IContributionItem item = new ActionContributionItem(preferences); + item.setVisible(!Platform.OS_MACOSX.equals(Platform.getOS())); + + windowMenu.add(item); + + windowMenu.add(ContributionItemFactory.OPEN_WINDOWS.create(window)); + + windowMenu.add(new GroupMarker(IWorkbenchActionConstants.WB_END)); + } + + protected void fillHelpMenu( IMenuManager helpMenu ) { + IWorkbenchWindow window = getActionBarConfigurer().getWindowConfigurer().getWindow(); + + boolean hasIntro = window + .getWorkbench().getIntroManager().hasIntro(); + if (hasIntro) { + if (helpMenu.findUsingPath(ActionFactory.INTRO.getId()) == null) { + IAction welcome = ActionFactory.INTRO.create(window); + welcome.setText(Messages.UDIGWorkbenchAdvisor_welcome_text); + if (helpMenu.getItems().length > 0) { + helpMenu.insertBefore(helpMenu.getItems()[0].getId(), welcome); + } else { + helpMenu.add(welcome); + } + } + } else { + Separator welcome = new Separator(ActionFactory.INTRO.getId()); + if (helpMenu.getItems().length > 0) { + helpMenu.insertBefore(helpMenu.getItems()[0].getId(), welcome); + } else { + helpMenu.add(welcome); + } + } + + if (helpMenu.findUsingPath(Constants.HELP_START) == null) { + helpMenu + .insertAfter(ActionFactory.INTRO.getId(), new GroupMarker(Constants.HELP_START)); + } + + if (helpMenu.findUsingPath(ActionFactory.HELP_CONTENTS.getId()) == null) { + IAction helpContents = ActionFactory.HELP_CONTENTS.create(window); + helpContents.setText(Messages.UDIGWorkbenchAdvisor_helpContents_text); + helpMenu.insertBefore(Constants.HELP_START, helpContents); + } + + if (helpMenu.findUsingPath(Constants.HELP_END) == null) { + helpMenu.insertAfter(Constants.HELP_START, new GroupMarker(Constants.HELP_END)); + } + + // Tips and tricks page would go after HELP_START + + if (helpMenu.findUsingPath(IWorkbenchActionConstants.MB_ADDITIONS) == null) { + helpMenu.insertAfter(Constants.HELP_END, new GroupMarker( + IWorkbenchActionConstants.MB_ADDITIONS)); + } + + // Add the separators + helpMenu.insertAfter(ActionFactory.INTRO.getId(), new Separator()); + helpMenu.insertBefore(Constants.HELP_START, new Separator()); + helpMenu.insertAfter(Constants.HELP_END, new Separator()); + // helpMenu.insertAfter(, new Separator()); + + addAboutItem(helpMenu, window); + } + + private void addAboutItem(IMenuManager helpMenu, IWorkbenchWindow window) { + if (helpMenu.findUsingPath(ActionFactory.ABOUT.getId()) == null) { + IAction about = ActionFactory.ABOUT.create(window); + String pattern = Messages.UDIGWorkbenchAdvisor_aboutUDig_text; + IProduct product = Platform.getProduct(); + String productName; + if (product == null) { + LoggingSupport.log(UiPlugin.getDefault(), "there is no product so default to uDig"); //$NON-NLS-1$ + productName = "uDig"; + } else { + productName = product.getName(); + } + about.setText(MessageFormat.format(pattern, productName)); + // About should always be at the bottom, so just append it to the menu + IContributionItem item = new ActionContributionItem(about); + item.setVisible(!Platform.OS_MACOSX.equals(Platform.getOS())); + + helpMenu.add(item); + } + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGApplication.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGApplication.java index 6e796f7b0b..2f6414f5bc 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGApplication.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGApplication.java @@ -32,6 +32,7 @@ import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.application.WorkbenchAdvisor; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.libs.internal.Activator; import org.locationtech.udig.ui.internal.Messages; import org.osgi.framework.Bundle; @@ -134,7 +135,7 @@ public Object start(IApplicationContext context) throws Exception { try { returnCode = PlatformUI.createAndRunWorkbench(display, workbenchAdvisor); } catch (Throwable t) { - UiPlugin.log(Messages.UDIGApplication_error, t); + LoggingSupport.log(UiPlugin.getDefault(), Messages.UDIGApplication_error, t); } finally { context.applicationRunning(); display.dispose(); diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGAuthenticator.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGAuthenticator.java index 09f53c8506..6129e8c9a2 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGAuthenticator.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGAuthenticator.java @@ -1,163 +1,165 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - * - */ -package org.locationtech.udig.internal.ui; - -import java.io.UnsupportedEncodingException; -import java.net.Authenticator; -import java.net.PasswordAuthentication; -import java.net.URLEncoder; -import java.util.HashSet; -import java.util.Set; - -import org.locationtech.udig.ui.PlatformGIS; - -import org.eclipse.jface.window.Window; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.PlatformUI; -import org.osgi.service.prefs.Preferences; - -/** - * This is an Authenticator used when URL connection negotiation - * needs to ask for the users credentials. - *

    - * This implementation is written to prompt the user with SWT; and - * to store the username/password if possible. - *

    - * @since 1.0.0 - */ -public class UDIGAuthenticator extends Authenticator { - private static final String NAME = "NAME"; //$NON-NLS-1$ - private static final String PASSWORD = "PASSWORD"; //$NON-NLS-1$ - private static final String URL_AUTHENTICATION = "URL_AUTHENTICATION"; //$NON-NLS-1$ - private String username; - private String password; - private boolean storePassword; - - /** - * The {@link Set} of nodeKeys that this authenticator has tried the stored username/password - * pair for. This is to make sure that the user is asked to reenter username/password instead of - * reusing the old invalid username/password. - */ - private Set triedStoredForNodeKey = new HashSet(); - - protected PasswordAuthentication getPasswordAuthentication() { - final String[] name=new String[1]; - final String[] pass=new String[1]; - - // only try the stored username/password once before asking the user - // for a new username/password. - if (!isTriedStored()) { - name[0] = loadName(); - pass[0] = loadPassword(); - setTriedStored(true); - } - - if (name[0] == null && pass[0] == null) { - //TODO check if credentials have been previously entered and remembered - PlatformGIS.syncInDisplayThread(new Runnable(){ - public void run() { - promptForPassword(); - name[0]=username; - pass[0]=password; - } - }); - } - if (name[0] == null && pass[0] == null) { - return null; - } - if( storePassword ) - store(name[0], pass[0]); - return new PasswordAuthentication(name[0], pass[0].toCharArray()); - } - - private boolean isTriedStored() { - try { - return triedStoredForNodeKey.contains(getNodeKey()); - } catch (UnsupportedEncodingException e) { - UiPlugin.log("", e); //$NON-NLS-1$ - return false; - } - } - - private void setTriedStored(boolean mark) { - try { - if(mark) { - triedStoredForNodeKey.add(getNodeKey()); - } else { - triedStoredForNodeKey.remove(getNodeKey()); - } - } catch (UnsupportedEncodingException e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - - private void store(String name, String pass) { - try { - Preferences node = UiPlugin.getUserPreferences().node(getNodeKey()); - node.put(NAME, name); - node.put(PASSWORD, pass); - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - - private String loadPassword() { - try { - Preferences node = UiPlugin.getUserPreferences().node(getNodeKey()); - String pass = node.get(PASSWORD, null); - if( pass == null ) - return null; - - return pass; - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - return null; - } - } - - private String getNodeKey() throws UnsupportedEncodingException { - return URL_AUTHENTICATION + URLEncoder.encode(getRequestingURL().toString(), "UTF-8"); //$NON-NLS-1$ - } - - private String loadName() { - try { - Preferences node = UiPlugin.getUserPreferences().node(getNodeKey()); - return node.get(NAME, null); - - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - return null; - } - } - - protected void promptForPassword() { - - Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); - AuthenticationDialog dialog = new AuthenticationDialog(shell); - dialog.setBlockOnOpen(true); - int result = dialog.open(); - if (result == Window.CANCEL) { - username = null; - password = null; - return; - } - username = dialog.getUsername(); - if (username == null) { - username = ""; //$NON-NLS-1$ - } - password = dialog.getPassword(); - if (password == null) { - password = ""; //$NON-NLS-1$ - } - storePassword = dialog.shouldRemember(); - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + * + */ +package org.locationtech.udig.internal.ui; + +import java.io.UnsupportedEncodingException; +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.net.URLEncoder; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.ui.PlatformGIS; +import org.osgi.service.prefs.Preferences; + +/** + * This is an Authenticator used when URL connection negotiation + * needs to ask for the users credentials. + *

    + * This implementation is written to prompt the user with SWT; and + * to store the username/password if possible. + *

    + * @since 1.0.0 + */ +public class UDIGAuthenticator extends Authenticator { + private static final String NAME = "NAME"; //$NON-NLS-1$ + private static final String PASSWORD = "PASSWORD"; //$NON-NLS-1$ + private static final String URL_AUTHENTICATION = "URL_AUTHENTICATION"; //$NON-NLS-1$ + private String username; + private String password; + private boolean storePassword; + + /** + * The {@link Set} of nodeKeys that this authenticator has tried the stored username/password + * pair for. This is to make sure that the user is asked to reenter username/password instead of + * reusing the old invalid username/password. + */ + private Set triedStoredForNodeKey = new HashSet<>(); + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + final String[] name=new String[1]; + final String[] pass=new String[1]; + + // only try the stored username/password once before asking the user + // for a new username/password. + if (!isTriedStored()) { + name[0] = loadName(); + pass[0] = loadPassword(); + setTriedStored(true); + } + + if (name[0] == null && pass[0] == null) { + //TODO check if credentials have been previously entered and remembered + PlatformGIS.syncInDisplayThread(new Runnable(){ + @Override + public void run() { + promptForPassword(); + name[0]=username; + pass[0]=password; + } + }); + } + if (name[0] == null && pass[0] == null) { + return null; + } + if( storePassword ) + store(name[0], pass[0]); + return new PasswordAuthentication(name[0], pass[0].toCharArray()); + } + + private boolean isTriedStored() { + try { + return triedStoredForNodeKey.contains(getNodeKey()); + } catch (UnsupportedEncodingException e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + return false; + } + } + + private void setTriedStored(boolean mark) { + try { + if(mark) { + triedStoredForNodeKey.add(getNodeKey()); + } else { + triedStoredForNodeKey.remove(getNodeKey()); + } + } catch (UnsupportedEncodingException e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + + private void store(String name, String pass) { + try { + Preferences node = UiPlugin.getUserPreferences().node(getNodeKey()); + node.put(NAME, name); + node.put(PASSWORD, pass); + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + + private String loadPassword() { + try { + Preferences node = UiPlugin.getUserPreferences().node(getNodeKey()); + String pass = node.get(PASSWORD, null); + if( pass == null ) + return null; + + return pass; + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + return null; + } + } + + private String getNodeKey() throws UnsupportedEncodingException { + return URL_AUTHENTICATION + URLEncoder.encode(getRequestingURL().toString(), "UTF-8"); //$NON-NLS-1$ + } + + private String loadName() { + try { + Preferences node = UiPlugin.getUserPreferences().node(getNodeKey()); + return node.get(NAME, null); + + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + return null; + } + } + + protected void promptForPassword() { + + Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + AuthenticationDialog dialog = new AuthenticationDialog(shell); + dialog.setBlockOnOpen(true); + int result = dialog.open(); + if (result == Window.CANCEL) { + username = null; + password = null; + return; + } + username = dialog.getUsername(); + if (username == null) { + username = ""; //$NON-NLS-1$ + } + password = dialog.getPassword(); + if (password == null) { + password = ""; //$NON-NLS-1$ + } + storePassword = dialog.shouldRemember(); + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGExportedPreferences.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGExportedPreferences.java index 6bbc5242f1..063cb4ae0e 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGExportedPreferences.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGExportedPreferences.java @@ -1,250 +1,283 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.internal.ui; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.eclipse.core.runtime.preferences.IExportedPreferences; -import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor; -import org.eclipse.jface.preference.IPreferenceStore; -import org.osgi.service.prefs.BackingStoreException; -import org.osgi.service.prefs.Preferences; - -/** - * Uses a scoped preferences to store preferences. - * - * @author Jesse - * @since 1.1.0 - */ -public class UDIGExportedPreferences implements IExportedPreferences { - - private IPreferenceStore store; - private CopyOnWriteArraySet nodeChangeListeners=new CopyOnWriteArraySet(); - private CopyOnWriteArraySet preferenceChangeListeners=new CopyOnWriteArraySet(); - private String nodePath; - private Map map=new HashMap(); - private Map children=new HashMap(); - - public UDIGExportedPreferences(IPreferenceStore store, String nodePath){ - if( nodePath.contains(":") ) //$NON-NLS-1$ - throw new IllegalArgumentException("Node name cannot contain a ':'"); //$NON-NLS-1$ - if( nodePath.contains("$") ) //$NON-NLS-1$ - throw new IllegalArgumentException("Node name cannot contain a '$'"); //$NON-NLS-1$ - this.store=store; - this.nodePath=nodePath; - try{ - sync(); - }catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - - public boolean isExportRoot() { - return false; - } - - public void addNodeChangeListener( INodeChangeListener listener ) { - nodeChangeListeners.add(listener); - } - - public void removeNodeChangeListener( INodeChangeListener listener ) { - nodeChangeListeners.remove(listener); - } - - public void addPreferenceChangeListener( IPreferenceChangeListener listener ) { - preferenceChangeListeners.add(listener); - } - - public void removePreferenceChangeListener( IPreferenceChangeListener listener ) { - preferenceChangeListeners.remove(listener); - } - - public void removeNode() throws BackingStoreException { - store.setToDefault(nodePath); - } - - public Preferences node( String path ) { - String string = nodePath+"/"+path; //$NON-NLS-1$ - if( children.get(path)!=null ) - return children.get(path); - - UDIGExportedPreferences preferences=new UDIGExportedPreferences(store, string); - children.put(path, preferences); - return preferences; - } - - public void accept( IPreferenceNodeVisitor visitor ) throws BackingStoreException { - visitor.visit(this); - } - - public void put( String key, String value ) { - map.put(key,value); - } - - public String get( String key, String def ) { - return map.get(key); - } - - public void remove( String key ) { - map.remove(key); - } - - public void clear() throws BackingStoreException { - map.clear(); - } - - public void putInt( String key, int value ) { - map.put(key, String.valueOf(value)); - } - - public int getInt( String key, int def ) { - String string = map.get(key); - if( string==null ) - return def; - return Integer.parseInt(string); - } - - public void putLong( String key, long value ) { - map.put(key, String.valueOf(value)); - } - - public long getLong( String key, long def ) { - String string = map.get(key); - if( string==null ) - return def; - return Long.parseLong(string); - } - - public void putBoolean( String key, boolean value ) { - map.put(key, String.valueOf(value)); - } - - public boolean getBoolean( String key, boolean def ) { - String string = map.get(key); - if( string==null ) - return def; - return Boolean.parseBoolean(string); } - - public void putFloat( String key, float value ) { - map.put(key, String.valueOf(value)); - } - - public float getFloat( String key, float def ) { - String string = map.get(key); - if( string==null ) - return def; - return Float.parseFloat(string); } - - public void putDouble( String key, double value ) { - map.put(key, String.valueOf(value)); - } - - public double getDouble( String key, double def ) { - String string = map.get(key); - if( string==null ) - return def; - return Double.parseDouble(string); } - - public void putByteArray( String key, byte[] value ) { - map.put(key, String.valueOf(value)); - } - - public byte[] getByteArray( String key, byte[] def ) { - String string = map.get(key); - if( string==null ) - return def; - return string.getBytes(); - } - - public String[] keys() throws BackingStoreException { - return map.keySet().toArray(new String[0]); - } - - public String[] childrenNames() throws BackingStoreException { - return children.keySet().toArray(new String[0]); - } - - public Preferences parent() { - return null; - } - - public boolean nodeExists( String pathName ) throws BackingStoreException { - String s = store.getString(nodePath+"/"+pathName); //$NON-NLS-1$ - return s.length()>0; - } - - public String name() { - int lastIndexOf = nodePath.lastIndexOf('/'); - if(lastIndexOf==-1) - return ""; //$NON-NLS-1$ - return nodePath.substring(lastIndexOf); - } - - public String absolutePath() { - return nodePath; - } - - public void flush() throws BackingStoreException { - StringBuilder builder = null; - for( Map.Entry entry : map.entrySet() ) { - if( builder==null ) - builder=new StringBuilder(); - else - builder.append(":"); //$NON-NLS-1$ - builder.append(entry.getKey()); - builder.append(":"); //$NON-NLS-1$ - builder.append(entry.getValue()); - } - if( builder!=null ) - store.putValue(nodePath, builder.toString()); - - StringBuilder encodedChildren=null; - for( String entry : children.keySet() ) { - if( encodedChildren==null ) - encodedChildren=new StringBuilder(); - else - encodedChildren.append(":"); //$NON-NLS-1$ - encodedChildren.append(nodePath+"/"+entry); //$NON-NLS-1$ - } - if( encodedChildren!=null ) - store.putValue(nodePath+"$children", encodedChildren.toString()); //$NON-NLS-1$ - - for( UDIGExportedPreferences p : children.values() ) { - if( p!=null ) - p.flush(); - } - } - - public void sync() throws BackingStoreException { - String[] data=store.getString(nodePath).split(":"); //$NON-NLS-1$ - if (data.length > 1) { - for( int i = 0; i < data.length; i++ ) { - String key = data[i]; - i++; - String value=null; - if( data.length>i) - value = data[i]; - map.put(key, value); - } - } - String[] encodedChildren=store.getString(nodePath+"$children").split(":"); //$NON-NLS-1$//$NON-NLS-2$ - if (encodedChildren.length>1){ - for( String string : encodedChildren ) { - if( string.length()>0){ - String[] name=string.split("/"); //$NON-NLS-1$ - children.put(name[name.length-1], null); - } - } - } - } - -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.internal.ui; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.eclipse.core.runtime.preferences.IExportedPreferences; +import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor; +import org.eclipse.jface.preference.IPreferenceStore; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.osgi.service.prefs.BackingStoreException; +import org.osgi.service.prefs.Preferences; + +/** + * Uses a scoped preferences to store preferences. + * + * @author Jesse + * @since 1.1.0 + */ +public class UDIGExportedPreferences implements IExportedPreferences { + + private IPreferenceStore store; + private CopyOnWriteArraySet nodeChangeListeners=new CopyOnWriteArraySet<>(); + private CopyOnWriteArraySet preferenceChangeListeners=new CopyOnWriteArraySet<>(); + private String nodePath; + private Map map=new HashMap<>(); + private Map children=new HashMap<>(); + + public UDIGExportedPreferences(IPreferenceStore store, String nodePath){ + if( nodePath.contains(":") ) //$NON-NLS-1$ + throw new IllegalArgumentException("Node name cannot contain a ':'"); //$NON-NLS-1$ + if( nodePath.contains("$") ) //$NON-NLS-1$ + throw new IllegalArgumentException("Node name cannot contain a '$'"); //$NON-NLS-1$ + this.store=store; + this.nodePath=nodePath; + try{ + sync(); + }catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + + @Override + public boolean isExportRoot() { + return false; + } + + @Override + public void addNodeChangeListener( INodeChangeListener listener ) { + nodeChangeListeners.add(listener); + } + + @Override + public void removeNodeChangeListener( INodeChangeListener listener ) { + nodeChangeListeners.remove(listener); + } + + @Override + public void addPreferenceChangeListener( IPreferenceChangeListener listener ) { + preferenceChangeListeners.add(listener); + } + + @Override + public void removePreferenceChangeListener( IPreferenceChangeListener listener ) { + preferenceChangeListeners.remove(listener); + } + + @Override + public void removeNode() throws BackingStoreException { + store.setToDefault(nodePath); + } + + @Override + public Preferences node( String path ) { + String string = nodePath+"/"+path; //$NON-NLS-1$ + if( children.get(path)!=null ) + return children.get(path); + + UDIGExportedPreferences preferences=new UDIGExportedPreferences(store, string); + children.put(path, preferences); + return preferences; + } + + @Override + public void accept( IPreferenceNodeVisitor visitor ) throws BackingStoreException { + visitor.visit(this); + } + + @Override + public void put( String key, String value ) { + map.put(key,value); + } + + @Override + public String get( String key, String def ) { + return map.get(key); + } + + @Override + public void remove( String key ) { + map.remove(key); + } + + @Override + public void clear() throws BackingStoreException { + map.clear(); + } + + @Override + public void putInt( String key, int value ) { + map.put(key, String.valueOf(value)); + } + + @Override + public int getInt( String key, int def ) { + String string = map.get(key); + if( string==null ) + return def; + return Integer.parseInt(string); + } + + @Override + public void putLong( String key, long value ) { + map.put(key, String.valueOf(value)); + } + + @Override + public long getLong( String key, long def ) { + String string = map.get(key); + if( string==null ) + return def; + return Long.parseLong(string); + } + + @Override + public void putBoolean( String key, boolean value ) { + map.put(key, String.valueOf(value)); + } + + @Override + public boolean getBoolean( String key, boolean def ) { + String string = map.get(key); + if( string==null ) + return def; + return Boolean.parseBoolean(string); } + + @Override + public void putFloat( String key, float value ) { + map.put(key, String.valueOf(value)); + } + + @Override + public float getFloat( String key, float def ) { + String string = map.get(key); + if( string==null ) + return def; + return Float.parseFloat(string); } + + @Override + public void putDouble( String key, double value ) { + map.put(key, String.valueOf(value)); + } + + @Override + public double getDouble( String key, double def ) { + String string = map.get(key); + if( string==null ) + return def; + return Double.parseDouble(string); } + + @Override + public void putByteArray( String key, byte[] value ) { + map.put(key, String.valueOf(value)); + } + + @Override + public byte[] getByteArray( String key, byte[] def ) { + String string = map.get(key); + if( string==null ) + return def; + return string.getBytes(); + } + + @Override + public String[] keys() throws BackingStoreException { + return map.keySet().toArray(new String[0]); + } + + @Override + public String[] childrenNames() throws BackingStoreException { + return children.keySet().toArray(new String[0]); + } + + @Override + public Preferences parent() { + return null; + } + + @Override + public boolean nodeExists( String pathName ) throws BackingStoreException { + String s = store.getString(nodePath+"/"+pathName); //$NON-NLS-1$ + return s.length()>0; + } + + @Override + public String name() { + int lastIndexOf = nodePath.lastIndexOf('/'); + if(lastIndexOf==-1) + return ""; //$NON-NLS-1$ + return nodePath.substring(lastIndexOf); + } + + @Override + public String absolutePath() { + return nodePath; + } + + @Override + public void flush() throws BackingStoreException { + StringBuilder builder = null; + for( Map.Entry entry : map.entrySet() ) { + if( builder==null ) + builder=new StringBuilder(); + else + builder.append(":"); //$NON-NLS-1$ + builder.append(entry.getKey()); + builder.append(":"); //$NON-NLS-1$ + builder.append(entry.getValue()); + } + if( builder!=null ) + store.putValue(nodePath, builder.toString()); + + StringBuilder encodedChildren=null; + for( String entry : children.keySet() ) { + if( encodedChildren==null ) + encodedChildren=new StringBuilder(); + else + encodedChildren.append(":"); //$NON-NLS-1$ + encodedChildren.append(nodePath+"/"+entry); //$NON-NLS-1$ + } + if( encodedChildren!=null ) + store.putValue(nodePath+"$children", encodedChildren.toString()); //$NON-NLS-1$ + + for( UDIGExportedPreferences p : children.values() ) { + if( p!=null ) + p.flush(); + } + } + + @Override + public void sync() throws BackingStoreException { + String[] data=store.getString(nodePath).split(":"); //$NON-NLS-1$ + if (data.length > 1) { + for( int i = 0; i < data.length; i++ ) { + String key = data[i]; + i++; + String value=null; + if( data.length>i) + value = data[i]; + map.put(key, value); + } + } + String[] encodedChildren=store.getString(nodePath+"$children").split(":"); //$NON-NLS-1$//$NON-NLS-2$ + if (encodedChildren.length>1){ + for( String string : encodedChildren ) { + if( string.length()>0){ + String[] name=string.split("/"); //$NON-NLS-1$ + children.put(name[name.length-1], null); + } + } + } + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGStartup.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGStartup.java index 4865fcee8d..9f6c921213 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGStartup.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGStartup.java @@ -12,11 +12,6 @@ import java.awt.Rectangle; import java.rmi.server.UID; -import org.locationtech.udig.ui.ShutdownTaskList; -import org.locationtech.udig.ui.graphics.AWTSWTImageUtils; -import org.locationtech.udig.ui.internal.Messages; - -import si.uom.SI; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.MessageDialog; @@ -25,6 +20,13 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IStartup; import org.eclipse.ui.PlatformUI; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.ui.PlatformGIS; +import org.locationtech.udig.ui.ShutdownTaskList; +import org.locationtech.udig.ui.graphics.AWTSWTImageUtils; +import org.locationtech.udig.ui.internal.Messages; + +import si.uom.SI; /** * This class checks that the UDIG plug-ins are able to function. @@ -101,10 +103,11 @@ public void run() { path = AWTSWTImageUtils.convertToPath(new Rectangle(0, 0, 8, 8), display); status[0] = true; } catch (Exception e) { - final String message = Messages.UDIGApplication_error1 - + Messages.UDIGApplication_error2 - + "http://www.microsoft.com/downloads/details.aspx?FamilyID=6A63AB9C-DF12-4D41-933C-BE590FEAA05A&displaylang=en"; //$NON-NLS-1$ - UiPlugin.log(message, null); + final String message = + Messages.UDIGApplication_error1 + + Messages.UDIGApplication_error2 + + "http://www.microsoft.com/downloads/details.aspx?FamilyID=6A63AB9C-DF12-4D41-933C-BE590FEAA05A&displaylang=en"; //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), message); MessageDialog dialog = new MessageDialog(display.getActiveShell(), Messages.UDIGApplication_title, null, message, MessageDialog.ERROR, diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGWorkbenchWindowAdvisor.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGWorkbenchWindowAdvisor.java index 0bc2aa0c00..90c318e3df 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGWorkbenchWindowAdvisor.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDIGWorkbenchWindowAdvisor.java @@ -1,147 +1,145 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.internal.ui; - -import org.locationtech.udig.core.internal.CorePlugin; -import org.locationtech.udig.ui.UDIGDragDropUtilities; -import org.locationtech.udig.ui.WorkbenchConfiguration; -import org.locationtech.udig.ui.preferences.PreferenceConstants; - -import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.application.ActionBarAdvisor; -import org.eclipse.ui.application.IActionBarConfigurer; -import org.eclipse.ui.application.IWorkbenchWindowConfigurer; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; -import org.osgi.service.prefs.Preferences; - -/** - * Public base class for configuring a workbench window. - *

    - * The workbench window advisor object is created in response to a workbench window being created - * (one per window), and is used to configure the window. - *

    - *

    - * An application should declare a subclass of WorkbenchWindowAdvisor and override - * methods to configure workbench windows to suit the needs of the particular application. - *

    - *

    - * The following advisor methods are called at strategic points in the workbench window's lifecycle - * (as with the workbench advisor, all occur within the dynamic scope of the call to - * {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}): - *

      - *
    • preWindowOpen - called as the window is being opened; use to configure - * aspects of the window other than actions bars
    • - *
    • postWindowRestore - called after the window has been recreated from a - * previously saved state; use to adjust the restored window
    • - *
    • postWindowCreate - called after the window has been created, either from an - * initial state or from a restored state; used to adjust the window
    • - *
    • openIntro - called immediately before the window is opened in order to create - * the introduction component, if any
    • - *
    • postWindowOpen - called after the window has been opened; use to hook window - * listeners, etc.
    • - *
    • preWindowShellClose - called when the window's shell is closed by the user; - * use to pre-screen window closings
    • - *
    - *

    - * - * @author cole.markham - * @since 1.0.0 - */ -public class UDIGWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { - - /** - * Constructor - * - * @param configurer - */ - public UDIGWorkbenchWindowAdvisor( IWorkbenchWindowConfigurer configurer ) { - super(configurer); - } - - @Override - public void preWindowOpen() { - IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); - WorkbenchConfiguration configuration = lookupConfiguration(); - configuration.configureWorkbench(configurer); - - UDIGDragDropUtilities.registerUDigDND(configurer); - } - - /** - * Look up configuration object, using UDIGWorkbenchConfiguration as a default. - * @return WorkbenchConfiguration from preferences, or UDIGWorkbenchConfiguration if not found - */ - private WorkbenchConfiguration lookupConfiguration() { - - Class interfaceClass = WorkbenchConfiguration.class; - String prefConstant = PreferenceConstants.P_WORKBENCH_CONFIGURATION; - String xpid = WorkbenchConfiguration.XPID; - String idField = WorkbenchConfiguration.ATTR_ID; - String classField = WorkbenchConfiguration.ATTR_CLASS; - - WorkbenchConfiguration config = (WorkbenchConfiguration) UiPlugin - .lookupConfigurationObject(interfaceClass, UiPlugin.getDefault() - .getPreferenceStore(), UiPlugin.ID, prefConstant, xpid, idField, classField); - if (config == null) { - return new UDIGWorkbenchConfiguration(); - } - return config; - } - - @Override - public ActionBarAdvisor createActionBarAdvisor( IActionBarConfigurer configurer ) { - return new UDIGActionBarAdvisor(configurer); - } - - @Override - public void postWindowOpen() { - super.postWindowOpen(); - try { - Preferences userPreferences = UiPlugin.getUserPreferences(); - if (!userPreferences.nodeExists("org.locationtech.udig.ui.firstRun")) { //$NON-NLS-1$ - firstRun(); - } else { - showTip(); - } - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - - private void showTip() { - - try { - IPreferenceStore store = UiPlugin.getDefault().getPreferenceStore(); - if (store.getBoolean(PreferenceConstants.P_SHOW_TIPS) && TipDialog.hasTips() - && !CorePlugin.isDeveloping()) { - TipDialog dialog = new TipDialog(this.getWindowConfigurer().getWindow().getShell()); - dialog.setBlockOnOpen(false); - dialog.open(); - } - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - - private void firstRun() throws Exception { - // getWindowConfigurer().getWindow().getShell().setMaximized(true); - Preferences userPreferences = UiPlugin.getUserPreferences(); - userPreferences - .node("org.locationtech.udig.ui.firstRun").putBoolean("org.locationtech.udig.ui.isFirstRun", false); //$NON-NLS-1$ //$NON-NLS-2$ - -// if (Platform.getOS().equals(Platform.OS_LINUX)) { -// MessageDialog.openWarning(getWindowConfigurer().getWindow() -// .getShell(), "Warning", "Some Linux users have experienced issues with map display being slow or strange artifacts on some versions of Linux. This is now very rare but if you experience this problem go into the preferences and disable *Advanced Graphics*."); -// } - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.internal.ui; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.locationtech.udig.core.internal.CorePlugin; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.ui.UDIGDragDropUtilities; +import org.locationtech.udig.ui.WorkbenchConfiguration; +import org.locationtech.udig.ui.preferences.PreferenceConstants; +import org.osgi.service.prefs.Preferences; + +/** + * Public base class for configuring a workbench window. + *

    + * The workbench window advisor object is created in response to a workbench window being created + * (one per window), and is used to configure the window. + *

    + *

    + * An application should declare a subclass of WorkbenchWindowAdvisor and override + * methods to configure workbench windows to suit the needs of the particular application. + *

    + *

    + * The following advisor methods are called at strategic points in the workbench window's lifecycle + * (as with the workbench advisor, all occur within the dynamic scope of the call to + * {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}): + *

      + *
    • preWindowOpen - called as the window is being opened; use to configure + * aspects of the window other than actions bars
    • + *
    • postWindowRestore - called after the window has been recreated from a + * previously saved state; use to adjust the restored window
    • + *
    • postWindowCreate - called after the window has been created, either from an + * initial state or from a restored state; used to adjust the window
    • + *
    • openIntro - called immediately before the window is opened in order to create + * the introduction component, if any
    • + *
    • postWindowOpen - called after the window has been opened; use to hook window + * listeners, etc.
    • + *
    • preWindowShellClose - called when the window's shell is closed by the user; + * use to pre-screen window closings
    • + *
    + *

    + * + * @author cole.markham + * @since 1.0.0 + */ +public class UDIGWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { + + /** + * Constructor + * + * @param configurer + */ + public UDIGWorkbenchWindowAdvisor( IWorkbenchWindowConfigurer configurer ) { + super(configurer); + } + + @Override + public void preWindowOpen() { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + WorkbenchConfiguration configuration = lookupConfiguration(); + configuration.configureWorkbench(configurer); + + UDIGDragDropUtilities.registerUDigDND(configurer); + } + + /** + * Look up configuration object, using UDIGWorkbenchConfiguration as a default. + * @return WorkbenchConfiguration from preferences, or UDIGWorkbenchConfiguration if not found + */ + private WorkbenchConfiguration lookupConfiguration() { + + Class interfaceClass = WorkbenchConfiguration.class; + String prefConstant = PreferenceConstants.P_WORKBENCH_CONFIGURATION; + String xpid = WorkbenchConfiguration.XPID; + String idField = WorkbenchConfiguration.ATTR_ID; + String classField = WorkbenchConfiguration.ATTR_CLASS; + + WorkbenchConfiguration config = (WorkbenchConfiguration) UiPlugin + .lookupConfigurationObject(interfaceClass, UiPlugin.getDefault() + .getPreferenceStore(), UiPlugin.ID, prefConstant, xpid, idField, classField); + if (config == null) { + return new UDIGWorkbenchConfiguration(); + } + return config; + } + + @Override + public ActionBarAdvisor createActionBarAdvisor( IActionBarConfigurer configurer ) { + return new UDIGActionBarAdvisor(configurer); + } + + @Override + public void postWindowOpen() { + super.postWindowOpen(); + try { + Preferences userPreferences = UiPlugin.getUserPreferences(); + if (!userPreferences.nodeExists("org.locationtech.udig.ui.firstRun")) { //$NON-NLS-1$ + firstRun(); + } else { + showTip(); + } + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + + private void showTip() { + + try { + IPreferenceStore store = UiPlugin.getDefault().getPreferenceStore(); + if (store.getBoolean(PreferenceConstants.P_SHOW_TIPS) && TipDialog.hasTips() + && !CorePlugin.isDeveloping()) { + TipDialog dialog = new TipDialog(this.getWindowConfigurer().getWindow().getShell()); + dialog.setBlockOnOpen(false); + dialog.open(); + } + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + + private void firstRun() throws Exception { + // getWindowConfigurer().getWindow().getShell().setMaximized(true); + Preferences userPreferences = UiPlugin.getUserPreferences(); + userPreferences + .node("org.locationtech.udig.ui.firstRun").putBoolean("org.locationtech.udig.ui.isFirstRun", false); //$NON-NLS-1$ //$NON-NLS-2$ + +// if (Platform.getOS().equals(Platform.OS_LINUX)) { +// MessageDialog.openWarning(getWindowConfigurer().getWindow() +// .getShell(), "Warning", "Some Linux users have experienced issues with map display being slow or strange artifacts on some versions of Linux. This is now very rare but if you experience this problem go into the preferences and disable *Advanced Graphics*."); +// } + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDigByteAndLocalTransfer.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDigByteAndLocalTransfer.java index 5ffbd2c7d4..2c0483dd13 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDigByteAndLocalTransfer.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UDigByteAndLocalTransfer.java @@ -1,140 +1,145 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.internal.ui; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.swt.dnd.ByteArrayTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.dnd.TransferData; - -/** - * Appears to be a transfer for passing an object around - * the uDig application. - *

    - * The internals of this class appear to duplicate URLTransfer; so this may - * be a cut and paste of the URLTransfer type prior to it being added to - * Eclipse 3.4? - *

    - */ -public class UDigByteAndLocalTransfer extends ByteArrayTransfer implements UDIGTransfer{ - private static UDigByteAndLocalTransfer _instance = new UDigByteAndLocalTransfer(); - - static final String CFSTR_INETURL = "InternalObject"; //$NON-NLS-1$ - - private static final int CFSTR_INETURLID = Transfer - .registerType(CFSTR_INETURL); - - private long startTime; - - public Object object; - - @Override - public boolean isSupportedType( TransferData transferData ) { - return super.isSupportedType(transferData); - } - - public UDigByteAndLocalTransfer() { - - // do nothing. - } - - public static UDigByteAndLocalTransfer getInstance() { - - return _instance; - } - - protected int[] getTypeIds() { - - return new int[] { CFSTR_INETURLID }; - } - - public String[] getTypeNames() { - - return new String[] { CFSTR_INETURL }; - } - - @Override - public TransferData[] getSupportedTypes() { - return super.getSupportedTypes(); - } - - @SuppressWarnings("unchecked") - @Override - public void javaToNative(Object object, TransferData transferData) { - - startTime = System.currentTimeMillis(); - if( object instanceof IStructuredSelection){ - IStructuredSelection selection=(IStructuredSelection) object; - List elements=new ArrayList(); - for (Iterator iter = selection.iterator(); iter.hasNext();) { - elements.add(iter.next()); - } - this.object=elements.toArray(); - } - this.object = object; - if (transferData != null) - { - super.javaToNative(String.valueOf(startTime).getBytes(), transferData); - } - } - - /** - * This implementation of nativeToJava converts a platform - * specific representation of a URL and optionally, a title to a java - * String[]. For additional information see - * Transfer#nativeToJava. - * - * @param transferData - * the platform specific representation of the data to be been - * converted - * @return a java String[] containing a URL and optionally a - * title if the conversion was successful; otherwise null - */ - public Object nativeToJava(TransferData transferData) { - - byte[] bytes = (byte[])super.nativeToJava(transferData); - if (bytes == null) return null; - - try - { - long startTime = Long.valueOf(new String(bytes)).longValue(); - return this.startTime == startTime ? object : null; - } - catch (NumberFormatException exception) - { - InputStreamReader reader = new InputStreamReader( - new ByteArrayInputStream(bytes)); - StringBuffer buf = new StringBuffer(); - char[] chars = new char[bytes.length / 2]; - int read=0; - try { - read=reader.read(chars); - } catch (IOException e) { - UiPlugin.log("Error reading transfer data", e); //$NON-NLS-1$ - } - buf.append(chars,0,read); - return buf.toString().trim(); - } - - - } - - public boolean validate(Object object) { - return true; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.internal.ui; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.locationtech.udig.core.logging.LoggingSupport; + +/** + * Appears to be a transfer for passing an object around + * the uDig application. + *

    + * The internals of this class appear to duplicate URLTransfer; so this may + * be a cut and paste of the URLTransfer type prior to it being added to + * Eclipse 3.4? + *

    + */ +public class UDigByteAndLocalTransfer extends ByteArrayTransfer implements UDIGTransfer{ + private static UDigByteAndLocalTransfer _instance = new UDigByteAndLocalTransfer(); + + static final String CFSTR_INETURL = "InternalObject"; //$NON-NLS-1$ + + private static final int CFSTR_INETURLID = Transfer + .registerType(CFSTR_INETURL); + + private long startTime; + + public Object object; + + @Override + public boolean isSupportedType( TransferData transferData ) { + return super.isSupportedType(transferData); + } + + public UDigByteAndLocalTransfer() { + + // do nothing. + } + + public static UDigByteAndLocalTransfer getInstance() { + + return _instance; + } + + @Override + protected int[] getTypeIds() { + + return new int[] { CFSTR_INETURLID }; + } + + @Override + public String[] getTypeNames() { + + return new String[] { CFSTR_INETURL }; + } + + @Override + public TransferData[] getSupportedTypes() { + return super.getSupportedTypes(); + } + + @SuppressWarnings("unchecked") + @Override + public void javaToNative(Object object, TransferData transferData) { + + startTime = System.currentTimeMillis(); + if( object instanceof IStructuredSelection){ + IStructuredSelection selection=(IStructuredSelection) object; + List elements=new ArrayList<>(); + for (Iterator iter = selection.iterator(); iter.hasNext();) { + elements.add(iter.next()); + } + this.object=elements.toArray(); + } + this.object = object; + if (transferData != null) + { + super.javaToNative(String.valueOf(startTime).getBytes(), transferData); + } + } + + /** + * This implementation of nativeToJava converts a platform + * specific representation of a URL and optionally, a title to a java + * String[]. For additional information see + * Transfer#nativeToJava. + * + * @param transferData + * the platform specific representation of the data to be been + * converted + * @return a java String[] containing a URL and optionally a + * title if the conversion was successful; otherwise null + */ + @Override + public Object nativeToJava(TransferData transferData) { + + byte[] bytes = (byte[])super.nativeToJava(transferData); + if (bytes == null) return null; + + try + { + long startTime = Long.valueOf(new String(bytes)).longValue(); + return this.startTime == startTime ? object : null; + } + catch (NumberFormatException exception) + { + InputStreamReader reader = new InputStreamReader( + new ByteArrayInputStream(bytes)); + StringBuffer buf = new StringBuffer(); + char[] chars = new char[bytes.length / 2]; + int read=0; + try { + read=reader.read(chars); + } catch (IOException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error reading transfer data", e); //$NON-NLS-1$ + } + buf.append(chars,0,read); + return buf.toString().trim(); + } + + + } + + @Override + public boolean validate(Object object) { + return true; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UiPlugin.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UiPlugin.java index daabe9618f..89bd1f6680 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UiPlugin.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/UiPlugin.java @@ -50,6 +50,7 @@ import org.locationtech.udig.core.AbstractUdigUIPlugin; import org.locationtech.udig.core.internal.ExtensionPointProcessor; import org.locationtech.udig.core.internal.ExtensionPointUtil; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.internal.ui.operations.OperationMenuFactory; import org.locationtech.udig.ui.MenuBuilder; import org.locationtech.udig.ui.UDIGMenuBuilder; @@ -297,11 +298,12 @@ public OperationMenuFactory getOperationMenuFactory() { * @param clazz The calling class. * @param methodName The calling method name. * @param t The throwable from where the problem actually occurred. + * @deprecated Use + * {@link LoggingSupport#log(org.eclipse.core.runtime.Plugin, Class, String, Throwable)} + * instead. */ - public static void log(Class clazz, String methodName, Throwable t) { - String msg = MessageFormat.format("Exception in {0}.{1}: {2}", //$NON-NLS-1$ - new Object[] { clazz.getName(), methodName, t }); - log(msg, t); + public static void log(Class clazz, String methodName, Throwable t) { + LoggingSupport.log(getDefault(), clazz, methodName, t); } /** @@ -309,54 +311,37 @@ public static void log(Class clazz, String methodName, Throwable t) { *

    * This should be used for user level messages. *

    + * @deprecated Use {@link LoggingSupport#log(org.eclipse.core.runtime.Plugin, String, Throwable)} instead. */ public static void log(String message2, Throwable e) { - String message = message2; - if (message == null) - message = ""; //$NON-NLS-1$ - getDefault().getLog().log(new Status(IStatus.INFO, ID, 0, message, e)); + LoggingSupport.log(getDefault(), message2, e); } /** * Log the status to the default log. * * @param status + * + * @deprecated Use {@link LoggingSupport#log(org.eclipse.core.runtime.Plugin, IStatus)} instead. */ public static void log(IStatus status) { - getDefault().getLog().log(status); + LoggingSupport.log(getDefault(), status); } /** - * Messages that only engage if getDefault().isDebugging() - *

    - * It is much preferred to do this: - * - *

    -     *  private static final String RENDERING = "org.locationtech.udig.project/render/trace";
    -     * if (ProjectUIPlugin.getDefault().isDebugging() && "true".equalsIgnoreCase(RENDERING)) {
    -     *      System.out.println( "your message here" );
    -     * }
    +     * @deprecated Use {@link LoggingSupport#trace(org.eclipse.core.runtime.Plugin, String, Throwable)} instead.
          */
         private static void trace(String message, Throwable e) {
    -        if (getDefault().isDebugging()) {
    -            if (message != null) {
    -                System.out.println(message); // $NON-NLS-1$
    -            }
    -            if (e != null) {
    -                e.printStackTrace(System.out);
    -            }
    -        }
    +        LoggingSupport.trace(getDefault(), message, e);
         }
     
         /**
          * Messages that only engage if getDefault().isDebugging() and the trace option traceID is true.
          * Available trace options can be found in the Trace class. (They must also be part of the
    -     * .options file)
    +     * @deprecated Use {@link LoggingSupport#trace(org.eclipse.core.runtime.Plugin, String, Class, String, Throwable)} instead.
          */
         public static void trace(String traceID, Class caller, String message, Throwable e) {
    -        if (isDebugging(traceID)) {
    -            trace(caller, message, e);
    -        }
    +        LoggingSupport.trace(getDefault(), traceID, caller, message, e);
         }
     
         /**
    @@ -365,9 +350,11 @@ public static void trace(String traceID, Class caller, String message, Throwa
          * @param caller class of the object doing the trace.
          * @param message tracing message, may be null.
          * @param e exception, may be null.
    +     *
    +     * @deprecated Use {@link LoggingSupport#trace(org.eclipse.core.runtime.Plugin, Class, String, Throwable)} instead.
          */
         public static void trace(Class caller, String message, Throwable e) {
    -        trace(caller.getSimpleName() + ": " + message, e); //$NON-NLS-1$ //$NON-NLS-2$
    +        LoggingSupport.trace(getDefault(), caller, message, e);
         }
     
         /**
    @@ -380,10 +367,11 @@ public static void trace(Class caller, String message, Throwable e) {
          * 

    * * @param trace currently only RENDER is defined + * + * @deprecated Use {@link LoggingSupport#isDebugging(org.eclipse.core.runtime.Plugin, String)} instead. */ public static boolean isDebugging(final String trace) { - return (getDefault() != null && getDefault().isDebugging() - && "true".equalsIgnoreCase(Platform.getDebugOption(trace))); //$NON-NLS-1$ + return LoggingSupport.isDebugging(getDefault(), trace); } /** @@ -535,7 +523,6 @@ public static void setProxy(String proxyHost, String proxyPort, String proxyNonH * @throws FileNotFoundException * @throws IOException */ - @SuppressWarnings("nls") public static Properties getProxySettings() throws FileNotFoundException, IOException { Properties properties = new Properties(); File iniFile = getIniFile(); @@ -572,7 +559,7 @@ private static void processAppIni(boolean readOnly, Function fun BufferedReader bR = null; BufferedWriter bW = null; try { - Collection updatedLines = new ArrayList(); + Collection updatedLines = new ArrayList<>(); bR = new BufferedReader(new FileReader(iniFile)); String line = null; while ((line = bR.readLine()) != null) { @@ -598,7 +585,7 @@ private static void processAppIni(boolean readOnly, Function fun } if (!readOnly) { - UiPlugin.log("udig.ini changed:" + iniFile, null); + LoggingSupport.log(UiPlugin.getDefault(), "udig.ini changed:" + iniFile); } } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/operations/OperationMenuFactory.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/operations/OperationMenuFactory.java index 81b54acb52..0cd5b2f5d1 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/operations/OperationMenuFactory.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/internal/ui/operations/OperationMenuFactory.java @@ -1,344 +1,347 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - * - */ -package org.locationtech.udig.internal.ui.operations; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.locationtech.udig.core.internal.ExtensionPointList; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; -import org.locationtech.udig.ui.operations.OpAction; - -import org.eclipse.core.expressions.Expression; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.jface.action.ActionContributionItem; -import org.eclipse.jface.action.GroupMarker; -import org.eclipse.jface.action.IContributionItem; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.action.SubContributionItem; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IWorkbenchActionConstants; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.menus.AbstractContributionFactory; -import org.eclipse.ui.menus.IContributionRoot; -import org.eclipse.ui.menus.IMenuService; -import org.eclipse.ui.services.IServiceLocator; - -/** - * Creates an Operation Sub menu containing operations for all - * operations defined for an object. - * - * @author jeichar - * @since 0.6.0 - */ -public class OperationMenuFactory { - List extensionPoints; - private MenuManager contextManager; - private ArrayList actions = new ArrayList(); - private Map categories = new HashMap(); - private MenuManager menuManager; - private IWorkbenchWindow window; - /** - * Create instance - */ - public OperationMenuFactory() { - extensionPoints = ExtensionPointList.getExtensionPointList("org.locationtech.udig.ui.operation"); //$NON-NLS-1$ - createActionList(extensionPoints); - } - - /** - * Gets a context menu containing all the enabled operations - * - * @param selection the current selection. - * @return a context menu containing all the enabled operations - */ - public MenuManager getContextMenu(ISelection selection) { - contextManager = createMenuManager(); - Iterator iter = getCategories().values().iterator(); - while( iter.hasNext()) { - OperationCategory category = (OperationCategory) iter.next(); - - for (OpAction action : category.getActions()) { - if( selection instanceof IStructuredSelection ) - action.updateEnablement((IStructuredSelection) selection, true); - if (action.isEnabled()) - contextManager.add(action); - } - if (iter.hasNext()) - contextManager.add(new Separator()); - } - - if (getActions().size() != 0) { - contextManager.add(new Separator()); - } - for( OpAction action : getActions() ) { - if( selection instanceof IStructuredSelection ) - action.updateEnablement((IStructuredSelection) selection, true); - if (action.isEnabled()) { - contextManager.add(action); - } - } - return contextManager; - } - - /** - * Creates a menu manager with actions that will enable - * based on the current workbench selection. - * - * @return a menu manager with all the Operation Actions. - */ - public MenuManager getMenu( ) { - if (menuManager == null) { - menuManager = new MenuManager(getMenuText()); - for( OperationCategory category : categories.values() ) { - if (category.getItems().length > 0) { - menuManager.add(category); - } - } - for( OpAction action : actions ) { - menuManager.add(action); - } - menuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); - } - return menuManager; - } - - /** - */ - public void add( ) { - menuManager.update(); - } - - private void createActionList( List list ) { - for( IConfigurationElement element : list ) { - try { - if (element.getName().equals("category")) //$NON-NLS-1$ - categories.put(element.getAttribute("id"), new OperationCategory(element)); //$NON-NLS-1$ - } catch (Exception e) { - UiPlugin.log(null, e); - } - } - for( IConfigurationElement element : list ) { - if (element.getName().equals("category")) //$NON-NLS-1$ - continue; - OpAction action = new OpAction(element); - - if (window != null) - window.getSelectionService().addSelectionListener(action); - OperationCategory category = categories.get(element.getAttribute("categoryId")); //$NON-NLS-1$ - if (category != null) { - category.add(action); - } else { - actions.add(action); - if (element.getAttribute("categoryId") != null && element.getAttribute("categoryId").length() != 0) { //$NON-NLS-1$ //$NON-NLS-2$ - UiPlugin.log("Action '"+action.getText()+"' references invalid category '"+element.getAttribute("categoryId")+"'.", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } - } - } - } - - /** - * Adds actions defined by extension points to the menu bar. - * @param menuBar - */ - public void contributeActions( IMenuManager menuBar ) { - for( OperationCategory category : categories.values() ) { - for( OpAction action : category.getActions() ) { - addActionToMenu(menuBar, action); - } - } - for( OpAction action : actions ) { - addActionToMenu(menuBar, action); - } - } - /** - * TODO summary sentence for addActionToMenu ... - * - * @param menuBar - * @param action - */ - private void addActionToMenu( IMenuManager menuBar, OpAction action ) { - if (action.getMenuPath() != null) - try { - String[] paths = action.getMenuPath().split("/"); //$NON-NLS-1$ - IMenuManager manager = menuBar.findMenuUsingPath(IWorkbenchActionConstants.MB_ADDITIONS); - if(manager == null){ - manager = menuBar; - } - String markerID = null; - for( String path : paths ) { - markerID = null; - IContributionItem item = manager.findUsingPath(path); - if (item == null) { - UiPlugin.log(action.getMenuPath() + " is not a valid menuPath", null); //$NON-NLS-1$ - break; - } - if (item instanceof IMenuManager) { - manager = (IMenuManager) item; - } else if (item.isGroupMarker()) { - markerID = item.getId(); - } else if (item instanceof SubContributionItem) { - item = ((SubContributionItem) item).getInnerItem(); - if (item instanceof IMenuManager) { - manager = (IMenuManager) item; - } else if (item.isGroupMarker()) { - markerID = item.getId(); - } - } - } - if (manager != null) { - if (markerID != null) - manager.appendToGroup(markerID, action); - else { - manager.add(action); - } - } else { - UiPlugin.log(action.getMenuPath() + " is not a valid menuPath", null); //$NON-NLS-1$ - } - } catch (Exception e) { - UiPlugin.log("Error adding operation to menu", e); //$NON-NLS-1$ - } - } - - /** - * @return Returns the window. - */ - public IWorkbenchWindow getWindow() { - return window; - } - - /** - * @param window The window to set. - */ - public void setWindow( IWorkbenchWindow window ) { - IWorkbenchWindow oldwindow = this.window; - this.window = window; - Collection cat = categories.values(); - for( OperationCategory category : cat ) { - List catActions = category.getActions(); - for( OpAction action : catActions ) { - if( window!=null) - window.getSelectionService().addSelectionListener(action); - if( oldwindow!=null ) - oldwindow.getSelectionService().removeSelectionListener(action); - } - } - for( OpAction action : actions ) { - if( window!=null) - window.getSelectionService().addSelectionListener(action); - if( oldwindow!=null ) - oldwindow.getSelectionService().removeSelectionListener(action); - } - } - - public List getActions() { - return Collections.unmodifiableList(actions); - } - - public Map getCategories() { - return Collections.unmodifiableMap(categories); - } - - private String getMenuText() { - return Messages.OperationMenuFactory_menu_text; - } - - public MenuManager createMenuManager() { - return new MenuManager(getMenuText(), "analysis"); //$NON-NLS-1$ - } - - public OperationCategory findCategory( String categoryId ) { - return getCategories().get(categoryId); - } - - public OpAction find( String actionId ) { - for (OpAction action : getActions()) { - if (action.getId().equals(actionId)) { - return action; - } - } - - for (OperationCategory category : getCategories().values()) { - for (OpAction action : category.actions) { - if (action.getId().equals(actionId)) { - return action; - } - } - } - - return null; - } - - /** - * The provided men - * @param menuService - */ - public void addWorkbenchMenus( IMenuService menuService ) { - String locationURI; - locationURI = "menu:org.eclipse.ui.main.menu?after=additions"; - menuService.addContributionFactory( new AbstractContributionFactory(locationURI,null){ - @Override - public void createContributionItems( IServiceLocator serviceLocator, - IContributionRoot additions ) { - additions.addContributionItem( getMenu(), Expression.TRUE ); - } - }); - - locationURI = "menu:edit?after=additions"; - menuService.addContributionFactory( new AbstractContributionFactory(locationURI,null){ - @Override - public void createContributionItems( IServiceLocator serviceLocator, - IContributionRoot additions ) { - for( OpAction action : getActions() ){ - IContributionItem item = new ActionContributionItem(action); - Expression visibleWhen = Expression.TRUE; - - additions.addContributionItem(item, visibleWhen); - } - } - }); - } - - /** - * Create array of contribution items; suitable for use in a dynamic menu. - * - * @param categoryId - * @return ActionItems for provided OperationCategory - */ - public List createContributionItems( String categoryId ){ - List items = new ArrayList(); - - OperationCategory category = findCategory( categoryId ); - if( category == null || category.getActions().isEmpty() ){ - return items; - } - List actions = category.getActions(); - for( OpAction action : actions ){ - if( action == null ){ - continue; // TODO: why do we have a null action here? - } - IContributionItem item = new ActionContributionItem(action); - item.setVisible(true); - items.add( item ); - } - return items; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + * + */ +package org.locationtech.udig.internal.ui.operations; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.action.SubContributionItem; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.menus.AbstractContributionFactory; +import org.eclipse.ui.menus.IContributionRoot; +import org.eclipse.ui.menus.IMenuService; +import org.eclipse.ui.services.IServiceLocator; +import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.locationtech.udig.ui.operations.OpAction; + +/** + * Creates an Operation Sub menu containing operations for all + * operations defined for an object. + * + * @author jeichar + * @since 0.6.0 + */ +public class OperationMenuFactory { + List extensionPoints; + private MenuManager contextManager; + private ArrayList actions = new ArrayList<>(); + private Map categories = new HashMap<>(); + private MenuManager menuManager; + private IWorkbenchWindow window; + /** + * Create instance + */ + public OperationMenuFactory() { + extensionPoints = ExtensionPointList.getExtensionPointList("org.locationtech.udig.ui.operation"); //$NON-NLS-1$ + createActionList(extensionPoints); + } + + /** + * Gets a context menu containing all the enabled operations + * + * @param selection the current selection. + * @return a context menu containing all the enabled operations + */ + public MenuManager getContextMenu(ISelection selection) { + contextManager = createMenuManager(); + Iterator iter = getCategories().values().iterator(); + while( iter.hasNext()) { + OperationCategory category = (OperationCategory) iter.next(); + + for (OpAction action : category.getActions()) { + if( selection instanceof IStructuredSelection ) + action.updateEnablement((IStructuredSelection) selection, true); + if (action.isEnabled()) + contextManager.add(action); + } + if (iter.hasNext()) + contextManager.add(new Separator()); + } + + if (getActions().size() != 0) { + contextManager.add(new Separator()); + } + for( OpAction action : getActions() ) { + if( selection instanceof IStructuredSelection ) + action.updateEnablement((IStructuredSelection) selection, true); + if (action.isEnabled()) { + contextManager.add(action); + } + } + return contextManager; + } + + /** + * Creates a menu manager with actions that will enable + * based on the current workbench selection. + * + * @return a menu manager with all the Operation Actions. + */ + public MenuManager getMenu( ) { + if (menuManager == null) { + menuManager = new MenuManager(getMenuText()); + for( OperationCategory category : categories.values() ) { + if (category.getItems().length > 0) { + menuManager.add(category); + } + } + for( OpAction action : actions ) { + menuManager.add(action); + } + menuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + } + return menuManager; + } + + /** + */ + public void add( ) { + menuManager.update(); + } + + private void createActionList( List list ) { + for( IConfigurationElement element : list ) { + try { + if (element.getName().equals("category")) //$NON-NLS-1$ + categories.put(element.getAttribute("id"), new OperationCategory(element)); //$NON-NLS-1$ + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + for( IConfigurationElement element : list ) { + if (element.getName().equals("category")) //$NON-NLS-1$ + continue; + OpAction action = new OpAction(element); + + if (window != null) + window.getSelectionService().addSelectionListener(action); + OperationCategory category = categories.get(element.getAttribute("categoryId")); //$NON-NLS-1$ + if (category != null) { + category.add(action); + } else { + actions.add(action); + if (element.getAttribute("categoryId") != null //$NON-NLS-1$ + && element.getAttribute("categoryId").length() != 0) { //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), + "Action '" + action.getText() + "' references invalid category '" //$NON-NLS-1$ //$NON-NLS-2$ + + element.getAttribute("categoryId") + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + } + + /** + * Adds actions defined by extension points to the menu bar. + * @param menuBar + */ + public void contributeActions( IMenuManager menuBar ) { + for( OperationCategory category : categories.values() ) { + for( OpAction action : category.getActions() ) { + addActionToMenu(menuBar, action); + } + } + for( OpAction action : actions ) { + addActionToMenu(menuBar, action); + } + } + /** + * TODO summary sentence for addActionToMenu ... + * + * @param menuBar + * @param action + */ + private void addActionToMenu( IMenuManager menuBar, OpAction action ) { + if (action.getMenuPath() != null) + try { + String[] paths = action.getMenuPath().split("/"); //$NON-NLS-1$ + IMenuManager manager = menuBar.findMenuUsingPath(IWorkbenchActionConstants.MB_ADDITIONS); + if(manager == null){ + manager = menuBar; + } + String markerID = null; + for( String path : paths ) { + markerID = null; + IContributionItem item = manager.findUsingPath(path); + if (item == null) { + LoggingSupport.log(UiPlugin.getDefault(), action.getMenuPath() + " is not a valid menuPath"); //$NON-NLS-1$ + break; + } + if (item instanceof IMenuManager) { + manager = (IMenuManager) item; + } else if (item.isGroupMarker()) { + markerID = item.getId(); + } else if (item instanceof SubContributionItem) { + item = ((SubContributionItem) item).getInnerItem(); + if (item instanceof IMenuManager) { + manager = (IMenuManager) item; + } else if (item.isGroupMarker()) { + markerID = item.getId(); + } + } + } + if (manager != null) { + if (markerID != null) + manager.appendToGroup(markerID, action); + else { + manager.add(action); + } + } else { + LoggingSupport.log(UiPlugin.getDefault(), action.getMenuPath() + " is not a valid menuPath"); + } + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error adding operation to menu", e); //$NON-NLS-1$ + } + } + + /** + * @return Returns the window. + */ + public IWorkbenchWindow getWindow() { + return window; + } + + /** + * @param window The window to set. + */ + public void setWindow( IWorkbenchWindow window ) { + IWorkbenchWindow oldwindow = this.window; + this.window = window; + Collection cat = categories.values(); + for( OperationCategory category : cat ) { + List catActions = category.getActions(); + for( OpAction action : catActions ) { + if( window!=null) + window.getSelectionService().addSelectionListener(action); + if( oldwindow!=null ) + oldwindow.getSelectionService().removeSelectionListener(action); + } + } + for( OpAction action : actions ) { + if( window!=null) + window.getSelectionService().addSelectionListener(action); + if( oldwindow!=null ) + oldwindow.getSelectionService().removeSelectionListener(action); + } + } + + public List getActions() { + return Collections.unmodifiableList(actions); + } + + public Map getCategories() { + return Collections.unmodifiableMap(categories); + } + + private String getMenuText() { + return Messages.OperationMenuFactory_menu_text; + } + + public MenuManager createMenuManager() { + return new MenuManager(getMenuText(), "analysis"); //$NON-NLS-1$ + } + + public OperationCategory findCategory( String categoryId ) { + return getCategories().get(categoryId); + } + + public OpAction find( String actionId ) { + for (OpAction action : getActions()) { + if (action.getId().equals(actionId)) { + return action; + } + } + + for (OperationCategory category : getCategories().values()) { + for (OpAction action : category.actions) { + if (action.getId().equals(actionId)) { + return action; + } + } + } + + return null; + } + + /** + * The provided men + * @param menuService + */ + public void addWorkbenchMenus( IMenuService menuService ) { + String locationURI; + locationURI = "menu:org.eclipse.ui.main.menu?after=additions"; + menuService.addContributionFactory( new AbstractContributionFactory(locationURI,null){ + @Override + public void createContributionItems( IServiceLocator serviceLocator, + IContributionRoot additions ) { + additions.addContributionItem( getMenu(), Expression.TRUE ); + } + }); + + locationURI = "menu:edit?after=additions"; + menuService.addContributionFactory( new AbstractContributionFactory(locationURI,null){ + @Override + public void createContributionItems( IServiceLocator serviceLocator, + IContributionRoot additions ) { + for( OpAction action : getActions() ){ + IContributionItem item = new ActionContributionItem(action); + Expression visibleWhen = Expression.TRUE; + + additions.addContributionItem(item, visibleWhen); + } + } + }); + } + + /** + * Create array of contribution items; suitable for use in a dynamic menu. + * + * @param categoryId + * @return ActionItems for provided OperationCategory + */ + public List createContributionItems( String categoryId ){ + List items = new ArrayList<>(); + + OperationCategory category = findCategory( categoryId ); + if( category == null || category.getActions().isEmpty() ){ + return items; + } + List actions = category.getActions(); + for( OpAction action : actions ){ + if( action == null ){ + continue; // TODO: why do we have a null action here? + } + IContributionItem item = new ActionContributionItem(action); + item.setVisible(true); + items.add( item ); + } + return items; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AbstractStrategizedTransfer.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AbstractStrategizedTransfer.java index 868b780c56..4c7d5b8e5a 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AbstractStrategizedTransfer.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AbstractStrategizedTransfer.java @@ -1,142 +1,152 @@ -/** - * - */ -package org.locationtech.udig.ui; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.locationtech.udig.internal.ui.TransferStrategy; -import org.locationtech.udig.internal.ui.UDIGTransfer; -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.swt.dnd.ByteArrayTransfer; -import org.eclipse.swt.dnd.TransferData; - -/** - * This class provides the framework for a transfer to have different behaviours depending on the - * strategy that is set. - *

    - * For example: - *

    - * A GeometryTextTransfer can encode the geometry as a GML string or a WKT string (as created by JTS WKTWriter). - * The GeometryTextTransfer class subclasses AbstractStrategizedTransfer and only needs to provide the current - * strategy and the set of possible strategies. The AbstractStrategizedTransfer will first try to use the current strategy for - * encoding the geometry then all the rest if the current strategy fails. - * Similarly for decoding an input(nativeToJava) the current strategy will be tried first then the rest of the - * known strategies will be used until an object is obtained. - *

    - * - * @see org.locationtech.udig.internal.ui.TransferStrategy - * @author jeichar - */ -public abstract class AbstractStrategizedTransfer extends ByteArrayTransfer implements UDIGTransfer{ - - final Set knownStrategies=Collections.synchronizedSet(new HashSet()); - public AbstractStrategizedTransfer(){ - knownStrategies.addAll(Arrays.asList(getAllStrategies())); - } - - @Override - public void javaToNative(Object object, TransferData transferData) { - try{ - getCurrentStrategy().javaToNative(object, transferData); - return; - }catch(Throwable e){ - UiPlugin.log("Error encoding "+object, e); //$NON-NLS-1$ - } - for (TransferStrategy strategy : knownStrategies) { - if( strategy==getCurrentStrategy()) - continue; - try{ - strategy.javaToNative(object, transferData); - return; - }catch(Throwable e){ - UiPlugin.log("Error encoding "+object, e); //$NON-NLS-1$ - continue; - } - } - throw new RuntimeException("No strategies were capable of encoding "+object); //$NON-NLS-1$ - } - - @Override - public Object nativeToJava(TransferData transferData) { - try{ - return getCurrentStrategy().nativeToJava(transferData); - }catch(Throwable e){ - UiPlugin.trace( getClass(), "Error decoding transferData", e); //$NON-NLS-1$ - } - for (TransferStrategy strategy : knownStrategies) { - if( strategy==getCurrentStrategy()) - continue; - try{ - Object value = strategy.nativeToJava(transferData); - if( value!=null ) - return value; - }catch(Throwable e){ - UiPlugin.log("Error decoding transferData", e); //$NON-NLS-1$ - continue; - } - } - throw new RuntimeException("No strategies were capable of decoding transfer data"); //$NON-NLS-1$ - } - - /** - * Returns the current strategy as indicated by the pereferences - * - * @return the current strategy as indicated by the pereferences - */ - public TransferStrategy getCurrentStrategy() { - String indicator=UiPlugin.getDefault().getPreferenceStore().getString(getClass().getName()); - if( indicator==null || indicator.length()==0 ) - return getDefaultStrategy(); - try{ - return getAllStrategies()[Integer.valueOf(indicator)]; - }catch (Exception e) { - return getDefaultStrategy(); - } - } - - /** - * Returns the default strategy that is used to encode the java objects. - * - * @return the strategy to use for encoding the java object. - */ - public abstract TransferStrategy getDefaultStrategy(); - /** - * This method is only called once during construction to get the list of strategies known by - * the implementation. - * - * @return - */ - public abstract TransferStrategy[] getAllStrategies(); - /** - * Returns the names for the strategies returned by {@link #getAllStrategies()}. The ith name - * must correspond to the ith strategy. - * - * @return the names for the strategies returned by {@link #getAllStrategies()} - */ - public abstract String[] getStrategyNames(); - /** - * Returns true if the transfer can transfer to and from the object. - * - * @return true if the transfer can transfer to and from the object. - */ - public abstract boolean validate(Object object); - - /** - * Adds a new strategy the list of known strategies. - */ - public void addStrategy( TransferStrategy newStrategy ){ - knownStrategies.add(newStrategy); - } - - /** - * Returns a name for the Transfer. - * - * @return name for the Transfer - */ - public abstract String getTransferName(); -} +/** + * + */ +package org.locationtech.udig.ui; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.TransferData; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.TransferStrategy; +import org.locationtech.udig.internal.ui.UDIGTransfer; +import org.locationtech.udig.internal.ui.UiPlugin; + +/** + * This class provides the framework for a transfer to have different behaviours depending on the + * strategy that is set. + *

    + * For example: + *

    + *

    + * A GeometryTextTransfer can encode the geometry as a GML string or a WKT string (as created by JTS + * WKTWriter). The GeometryTextTransfer class subclasses AbstractStrategizedTransfer and only needs + * to provide the current strategy and the set of possible strategies. The + * AbstractStrategizedTransfer will first try to use the current strategy for encoding the geometry + * then all the rest if the current strategy fails. Similarly for decoding an input(nativeToJava) + * the current strategy will be tried first then the rest of the known strategies will be used until + * an object is obtained. + *

    + * + * @see org.locationtech.udig.internal.ui.TransferStrategy + * @author jeichar + */ +public abstract class AbstractStrategizedTransfer extends ByteArrayTransfer + implements UDIGTransfer { + + final Set knownStrategies = Collections + .synchronizedSet(new HashSet()); + + public AbstractStrategizedTransfer() { + knownStrategies.addAll(Arrays.asList(getAllStrategies())); + } + + @Override + public void javaToNative(Object object, TransferData transferData) { + try { + getCurrentStrategy().javaToNative(object, transferData); + return; + } catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error encoding " + object, e); //$NON-NLS-1$ + } + for (TransferStrategy strategy : knownStrategies) { + if (strategy == getCurrentStrategy()) + continue; + try { + strategy.javaToNative(object, transferData); + return; + } catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error encoding " + object, e); //$NON-NLS-1$ + continue; + } + } + throw new RuntimeException("No strategies were capable of encoding " + object); //$NON-NLS-1$ + } + + @Override + public Object nativeToJava(TransferData transferData) { + try { + return getCurrentStrategy().nativeToJava(transferData); + } catch (Throwable e) { + UiPlugin.trace(getClass(), "Error decoding transferData", e); //$NON-NLS-1$ + } + for (TransferStrategy strategy : knownStrategies) { + if (strategy == getCurrentStrategy()) + continue; + try { + Object value = strategy.nativeToJava(transferData); + if (value != null) + return value; + } catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error decoding transferData", e); //$NON-NLS-1$ + continue; + } + } + throw new RuntimeException("No strategies were capable of decoding transfer data"); //$NON-NLS-1$ + } + + /** + * Returns the current strategy as indicated by the preferences + * + * @return the current strategy as indicated by the preferences + */ + public TransferStrategy getCurrentStrategy() { + String indicator = UiPlugin.getDefault().getPreferenceStore() + .getString(getClass().getName()); + if (indicator == null || indicator.length() == 0) + return getDefaultStrategy(); + try { + return getAllStrategies()[Integer.valueOf(indicator)]; + } catch (Exception e) { + return getDefaultStrategy(); + } + } + + /** + * Returns the default strategy that is used to encode the java objects. + * + * @return the strategy to use for encoding the java object. + */ + public abstract TransferStrategy getDefaultStrategy(); + + /** + * This method is only called once during construction to get the list of strategies known by + * the implementation. + * + * @return + */ + public abstract TransferStrategy[] getAllStrategies(); + + /** + * Returns the names for the strategies returned by {@link #getAllStrategies()}. The ith name + * must correspond to the ith strategy. + * + * @return the names for the strategies returned by {@link #getAllStrategies()} + */ + public abstract String[] getStrategyNames(); + + /** + * Returns true if the transfer can transfer to and from the object. + * + * @return true if the transfer can transfer to and from the object. + */ + @Override + public abstract boolean validate(Object object); + + /** + * Adds a new strategy the list of known strategies. + */ + public void addStrategy(TransferStrategy newStrategy) { + knownStrategies.add(newStrategy); + } + + /** + * Returns a name for the Transfer. + * + * @return name for the Transfer + */ + public abstract String getTransferName(); +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AttributeValidator.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AttributeValidator.java index b88cdd2f3f..accbc5e874 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AttributeValidator.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/AttributeValidator.java @@ -1,97 +1,97 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - * - */ -package org.locationtech.udig.ui; - -import org.locationtech.udig.ui.internal.Messages; - -import org.eclipse.jface.viewers.ICellEditorValidator; -import org.geotools.feature.type.Types; -import org.opengis.feature.simple.SimpleFeatureType; -import org.opengis.feature.type.AttributeDescriptor; - -/** - * Validates that an input is a legal input - *

    - * For details on the kind of work this class does (or needs to do) - * check the following: - * Validating a Feature. - *

    - * This is for the table view cell editing; and the default feature editor. - * - * @author jeichar - * @since 0.3 - */ -public class AttributeValidator implements ICellEditorValidator { - private final AttributeDescriptor attributeDescriptor; - private final SimpleFeatureType featureType; - private Object value; - - /** "Expected" index of the attributeType in the SimpleFeatureType */ - private int indexof; - - /** - * Creates a new instance of AttributeValidator - * - * @param attributeType The AttributeDescriptor that the new instance will validate - * @param featureType the featureType that contains the attributeType. - */ - public AttributeValidator( AttributeDescriptor attributeType, SimpleFeatureType featureType) { - this.attributeDescriptor = attributeType; - this.featureType=featureType; - for( int i = 0; i < featureType.getAttributeCount(); i++ ) { - AttributeDescriptor attributeType2 = featureType.getDescriptor(i); - if( attributeType2==attributeType ){ - this.indexof=i; - value=attributeType2.getDefaultValue(); - } - - } - } - - @SuppressWarnings("unchecked") - public String isValid( Object value ) { - - if( value==null || (value instanceof String && ((String)value).equals(""))){ //$NON-NLS-1$ - if( !attributeDescriptor.isNillable() ) - return Messages.AttributeValidator_missingAtt1+attributeDescriptor.getName()+Messages.AttributeValidator_missingAtt2; - else - return null; - } - if( !attributeDescriptor.getType().getBinding().isAssignableFrom(value.getClass()) ){ - return Messages.AttributeValidator_wrongType+ attributeDescriptor.getType().getBinding().getSimpleName(); - } - /* - if( false ){ - values[indexof]=value; - try { - // FIXME: The following line is fatal when restrictions are in place - SimpleFeature feature = SimpleFeatureBuilder.build( featureType, values, null ); - - for( Filter filter : attributeDescriptor.getType().getRestrictions() ){ - if( filter != null && !filter.evaluate(feature) ){ - return Messages.AttributeValidator_restriction+filter; - } - } - } catch (Throwable e1) { - UiPlugin.log("Tried to create a feature for validating the attribute value but something went wrong (this may not be an error)", e1); //$NON-NLS-1$ - } - } - */ - try { - Types.validate( attributeDescriptor, value ); - return null; - } catch (Throwable e) { - return e.getLocalizedMessage(); - } - - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + * + */ +package org.locationtech.udig.ui; + +import org.locationtech.udig.ui.internal.Messages; + +import org.eclipse.jface.viewers.ICellEditorValidator; +import org.geotools.feature.type.Types; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.AttributeDescriptor; + +/** + * Validates that an input is a legal input + *

    + * For details on the kind of work this class does (or needs to do) + * check the following: + * Validating a Feature. + *

    + * This is for the table view cell editing; and the default feature editor. + * + * @author jeichar + * @since 0.3 + */ +public class AttributeValidator implements ICellEditorValidator { + private final AttributeDescriptor attributeDescriptor; + private final SimpleFeatureType featureType; + private Object value; + + /** "Expected" index of the attributeType in the SimpleFeatureType */ + private int indexof; + + /** + * Creates a new instance of AttributeValidator + * + * @param attributeType The AttributeDescriptor that the new instance will validate + * @param featureType the featureType that contains the attributeType. + */ + public AttributeValidator( AttributeDescriptor attributeType, SimpleFeatureType featureType) { + this.attributeDescriptor = attributeType; + this.featureType=featureType; + for( int i = 0; i < featureType.getAttributeCount(); i++ ) { + AttributeDescriptor attributeType2 = featureType.getDescriptor(i); + if( attributeType2==attributeType ){ + this.indexof=i; + value=attributeType2.getDefaultValue(); + } + + } + } + + @SuppressWarnings("unchecked") + public String isValid( Object value ) { + + if( value==null || (value instanceof String && ((String)value).equals(""))){ //$NON-NLS-1$ + if( !attributeDescriptor.isNillable() ) + return Messages.AttributeValidator_missingAtt1+attributeDescriptor.getName()+Messages.AttributeValidator_missingAtt2; + else + return null; + } + if( !attributeDescriptor.getType().getBinding().isAssignableFrom(value.getClass()) ){ + return Messages.AttributeValidator_wrongType+ attributeDescriptor.getType().getBinding().getSimpleName(); + } + /* + if( false ){ + values[indexof]=value; + try { + // FIXME: The following line is fatal when restrictions are in place + SimpleFeature feature = SimpleFeatureBuilder.build( featureType, values, null ); + + for( Filter filter : attributeDescriptor.getType().getRestrictions() ){ + if( filter != null && !filter.evaluate(feature) ){ + return Messages.AttributeValidator_restriction+filter; + } + } + } catch (Throwable e1) { + LoggingSupport.log(UiPlugin.getDefault()"Tried to create a feature for validating the attribute value but something went wrong (this may not be an error)", e1); //$NON-NLS-1$ + } + } + */ + try { + Types.validate( attributeDescriptor, value ); + return null; + } catch (Throwable e) { + return e.getLocalizedMessage(); + } + + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/CRSChooser.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/CRSChooser.java index 8b3e950b9c..9afaf30b1e 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/CRSChooser.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/CRSChooser.java @@ -1,694 +1,704 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - * - */ -package org.locationtech.udig.ui; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.ListViewer; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.List; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.TabFolder; -import org.eclipse.swt.widgets.TabItem; -import org.eclipse.swt.widgets.Text; -import org.geotools.referencing.CRS; -import org.geotools.referencing.ReferencingFactoryFinder; -import org.geotools.referencing.crs.DefaultGeographicCRS; -import org.opengis.metadata.Identifier; -import org.opengis.referencing.FactoryException; -import org.opengis.referencing.IdentifiedObject; -import org.opengis.referencing.ReferenceIdentifier; -import org.opengis.referencing.crs.CRSAuthorityFactory; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.osgi.service.prefs.BackingStoreException; -import org.osgi.service.prefs.Preferences; - -/** - * Creates a Control for choosing a Coordinate Reference System. - * - * @author jeichar - * @since 0.6.0 - */ -public class CRSChooser { - - private static final String WKT_ID = "WKT"; //$NON-NLS-1$ - private static final String ALIASES_ID = "ALIASES"; //$NON-NLS-1$ - private static final String LAST_ID = "LAST_ID"; //$NON-NLS-1$ - private static final String NAME_ID = "NAME_ID"; //$NON-NLS-1$ - private static final String CUSTOM_ID = "CRS.Custom.Services"; //$NON-NLS-1$ - private static final Controller DEFAULT = new Controller(){ - - public void handleClose() { - } - - public void handleOk() { - } - - }; - - ListViewer codesList; - Text searchText; - Text wktText; - Text keywordsText; - CoordinateReferenceSystem selectedCRS; - Matcher matcher; - private TabFolder folder; - private Controller parentPage; - private HashMap crsCodeMap; - private CoordinateReferenceSystem sourceCRS; - - public CRSChooser( Controller parentPage ) { - matcher = Pattern.compile(".*?\\(([^(]*)\\)$").matcher(""); //$NON-NLS-1$ //$NON-NLS-2$ - this.parentPage = parentPage; - } - - public CRSChooser() { - this(DEFAULT); - } - - private Control createCustomCRSControl( Composite parent ) { - Composite composite = new Composite(parent, SWT.NONE); - - GridLayout layout = new GridLayout(2, false); - composite.setLayout(layout); - - GridData gridData = new GridData(); - Label keywordsLabel = new Label(composite, SWT.NONE); - keywordsLabel.setText(Messages.CRSChooser_keywordsLabel); - keywordsLabel.setLayoutData(gridData); - keywordsLabel.setToolTipText(Messages.CRSChooser_tooltip); - - gridData = new GridData(SWT.FILL, SWT.NONE, true, false); - keywordsText = new Text(composite, SWT.SINGLE | SWT.BORDER); - keywordsText.setLayoutData(gridData); - keywordsText.setToolTipText(Messages.CRSChooser_tooltip); - - gridData = new GridData(SWT.FILL, SWT.NONE, true, false); - gridData.horizontalSpan = 2; - Label editorLabel = new Label(composite, SWT.NONE); - editorLabel.setText(Messages.CRSChooser_label_crsWKT); - editorLabel.setLayoutData(gridData); - - gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - gridData.horizontalSpan = 2; - wktText = new Text(composite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); - if (selectedCRS != null) - wktText.setText(selectedCRS.toWKT()); - wktText.setLayoutData(gridData); - wktText.addModifyListener(new ModifyListener(){ - - public void modifyText( ModifyEvent e ) { - if (!keywordsText.isEnabled()) - keywordsText.setEnabled(true); - } - - }); - - searchText.setFocus(); - return composite; - } - - private Control createStandardCRSControl( Composite parent ) { - Composite composite = new Composite(parent, SWT.NONE); - GridLayout layout = new GridLayout(); - composite.setLayout(layout); - - GridData gridData = new GridData(); - Label codesLabel = new Label(composite, SWT.NONE); - codesLabel.setText(Messages.CRSChooser_label_crs); - codesLabel.setLayoutData(gridData); - - gridData = new GridData(SWT.FILL, SWT.FILL, false, false); - searchText = new Text(composite, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.CANCEL); - searchText.setLayoutData(gridData); - searchText.addModifyListener(new ModifyListener(){ - public void modifyText( ModifyEvent e ) { - fillCodesList(); - } - }); - searchText.addListener(SWT.KeyUp, new Listener(){ - - public void handleEvent(Event event) { - if( event.keyCode==SWT.ARROW_DOWN){ - codesList.getControl().setFocus(); - } - } - - }); - gridData = new GridData(400, 300); - codesList = new ListViewer(composite); - codesList.setContentProvider(new ArrayContentProvider()); - codesList.setLabelProvider(new LabelProvider()); - codesList.addSelectionChangedListener(new ISelectionChangedListener(){ - - public void selectionChanged( SelectionChangedEvent event ) { - selectedCRS = null; - String crsCode = (String) ((IStructuredSelection) codesList.getSelection()) - .getFirstElement(); - if (crsCode == null) - return; - matcher.reset(crsCode); - if (matcher.matches()) { - selectedCRS = createCRS(matcher.group(1)); - if (selectedCRS != null && wktText != null) { - wktText.setEditable(true); - String wkt = null; - try{ - wkt = selectedCRS.toWKT(); - }catch (Exception e) { - /* - * if unable to generate WKT, just return the - * string and make the text area non editable. - */ - wkt = selectedCRS.toString(); - wktText.setEditable(false); - } - wktText.setText(wkt); - Preferences node = findNode(matcher.group(1)); - if( node!=null ){ - Preferences kn = node.node(ALIASES_ID); - try { - String[] keywords=kn.keys(); - if( keywords.length>0 ){ - StringBuffer buffer=new StringBuffer(); - for( String string : keywords ) { - buffer.append(", "); //$NON-NLS-1$ - buffer.append(string); - } - buffer.delete(0,2); - keywordsText.setText(buffer.toString()); - } - } catch (BackingStoreException e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - - }else{ - keywordsText.setText(""); //$NON-NLS-1$ - } - } - } - - } - - }); - - codesList.addDoubleClickListener(new IDoubleClickListener(){ - - public void doubleClick( DoubleClickEvent event ) { - parentPage.handleOk(); - parentPage.handleClose(); - - } - - }); - - codesList.getControl().setLayoutData(gridData); - /* - * fillCodesList() by itself resizes the Preferences Page but in the paintlistener it - * flickers the window - */ - fillCodesList(); - - searchText.setFocus(); - - return composite; - } - - public void setFocus(){ - searchText.setFocus(); - } - - /** - * Creates the CRS PreferencePage root control with a CRS already selected - * - * @param parent PreferencePage for this chooser - * @param crs current CRS for the associated map - * @return control for the PreferencePage - */ - public Control createControl( Composite parent, CoordinateReferenceSystem crs ) { - Control control = createControl(parent); - selectedCRS = crs; - gotoCRS(selectedCRS); - return control; - } - - public void clearSearch() { - searchText.setText(""); //$NON-NLS-1$ - } - - /** - * Takes in a CRS, finds it in the list and highlights it - * - * @param crs - */ - @SuppressWarnings("unchecked") - public void gotoCRS( CoordinateReferenceSystem crs ) { - if (crs != null) { - final List list = codesList.getList(); - Set identifiers = new HashSet(crs.getIdentifiers()); - - final Set candidates=new HashSet(); - - for( int i = 0; i < list.getItemCount(); i++ ) { - for( Identifier identifier : identifiers ) { - final String item = list.getItem(i); - if( sameEPSG( crs, identifier, item) || exactMatch( crs, identifier, item )){ - codesList.setSelection(new StructuredSelection(item), false); - list.setTopIndex(i); - return; - } - if (isMatch(crs, identifier, item)) { - candidates.add(i); - } - } - } - if( candidates.isEmpty() ){ - java.util.List input=(java.util.List) codesList.getInput(); - String sourceCRSName = crs.getName().toString(); - sourceCRS = crs; - input.add(0, sourceCRSName); - codesList.setInput(input); - codesList.setSelection(new StructuredSelection(sourceCRSName), false); - list.setTopIndex(0); - try{ - String toWKT = crs.toWKT(); - wktText.setText(toWKT); - }catch(RuntimeException e){ - UiPlugin.log(crs.toString()+" cannot be formatted as WKT", e); //$NON-NLS-1$ - wktText.setText(Messages.CRSChooser_unknownWKT); - } - }else{ - Integer next = candidates.iterator().next(); - codesList.setSelection(new StructuredSelection(list.getItem(next)), false); - list.setTopIndex(next); - - } - } - } - - private boolean exactMatch( CoordinateReferenceSystem crs, Identifier identifier, String item ) { - return (crs==DefaultGeographicCRS.WGS84 && item.equals("WGS 84 (4326)")) || //$NON-NLS-1$ - item.equalsIgnoreCase(identifier.toString()) || isInCodeMap(identifier, item); - } - - private boolean isInCodeMap( Identifier identifier, String item ) { - - String name = crsCodeMap.get(identifier.getCode()); - if(name==null ) return false; - else return name.equals(item); - } - - private boolean sameEPSG( CoordinateReferenceSystem crs, Identifier identifier, String item ) { - String toString = identifier.toString(); - return toString.contains("EPSG:") && item.contains(toString); //$NON-NLS-1$ - } - - private boolean isMatch( CoordinateReferenceSystem crs, Identifier identifier, String item ) { - return (crs==DefaultGeographicCRS.WGS84 && item.contains("4326")) || item.contains(identifier.toString()); //$NON-NLS-1$ - } - - /** - * Creates the CRS PreferencePage root control with no CRS selected - * - * @param parent PreferencePage for this chooser - * @return control for the PreferencePage - */ - public Control createControl( Composite parent ) { - GridData gridData = null; - - gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - folder = new TabFolder(parent, SWT.NONE); - folder.setLayoutData(gridData); - - TabItem standard = new TabItem(folder, SWT.NONE); - standard.setText(Messages.CRSChooser_tab_standardCRS); - Control stdCRS = createStandardCRSControl(folder); - standard.setControl(stdCRS); - - TabItem custom = new TabItem(folder, SWT.NONE); - custom.setText(Messages.CRSChooser_tab_customCRS); - Control cstCRS = createCustomCRSControl(folder); - custom.setControl(cstCRS); - - return folder; - } - - /** - * checks if all keywords in filter array are in input - * - * @param input test string - * @param filter array of keywords - * @return true, if all keywords in filter are in the input, false otherwise - */ - protected boolean matchesFilter( String input, String[] filter ) { - for( String match : filter ) { - if (!input.contains(match)) - return false; - } - return true; - } - - /** - * filters all CRS Names from all available CRS authorities - * - * @param filter array of keywords - * @return Set of CRS Names which contain all the filter keywords - */ - protected Set filterCRSNames( String[] filter ) { - crsCodeMap = new HashMap(); - Set descriptions = new TreeSet(); - for( Object object : ReferencingFactoryFinder.getCRSAuthorityFactories(null) ) { - CRSAuthorityFactory factory = (CRSAuthorityFactory) object; - try { - Set codes = factory.getAuthorityCodes(CoordinateReferenceSystem.class); - for( Object codeObj : codes ) { - String code = (String) codeObj; - String description; - try { - description = factory.getDescriptionText(code).toString(); - } catch (Exception e1) { - description = Messages.CRSChooser_unnamed; - } - description += " (" + code + ")"; //$NON-NLS-1$ //$NON-NLS-2$ - crsCodeMap.put(code, description); - if (matchesFilter(description.toUpperCase(), filter)){ - descriptions.add(description); - } - } - } catch (FactoryException e) { - UiPlugin.trace( CRSChooser.class, "CRS Authority:"+e.getMessage(), e ); - } - } - return descriptions; - } - - /** - * populates the codes list with a filtered list of CRS names - */ - protected void fillCodesList() { - String[] searchParms = searchText.getText().toUpperCase().split(" "); //$NON-NLS-1$ - Set descriptions = filterCRSNames(searchParms); - descriptions = filterCustomCRSs(descriptions, searchParms); - java.util.List list = new ArrayList(descriptions); - codesList.setInput(list); - if (list != null && !list.isEmpty()) { - codesList.setSelection(new StructuredSelection(list.get(0))); - } else { - codesList.setSelection(new StructuredSelection()); -// System.out.println( "skipped"); - } - } - - private Set filterCustomCRSs( Set descriptions, String[] searchParms ) { - try { - Preferences root = UiPlugin.getUserPreferences(); - Preferences node = root.node(InstanceScope.SCOPE).node(CUSTOM_ID); - - for( String id : node.childrenNames() ) { - Preferences child = node.node(id); - String string = child.get(NAME_ID, null); - if (string != null && matchesFilter(string.toUpperCase(), searchParms)) { - descriptions.add(string); - continue; - } - - Preferences aliases = child.node(ALIASES_ID); - for( String alias : aliases.keys() ) { - if (matchesFilter(alias.toUpperCase(), searchParms)) { - descriptions.add(string); - continue; - } - } - } - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - return descriptions; - } - - /** - * creates a CRS from a code when the appropriate CRSAuthorityFactory is unknown - * - * @param code CRS code - * @return CRS object from appropriate authority, or null if the appropriate factory cannot be - * determined - */ - protected CoordinateReferenceSystem createCRS( String code ) { - if (code == null) - return null; - for( Object object : ReferencingFactoryFinder.getCRSAuthorityFactories(null) ) { - CRSAuthorityFactory factory = (CRSAuthorityFactory) object; - try { - IdentifiedObject identifiedObject = factory.createObject(code); - if (identifiedObject instanceof CoordinateReferenceSystem) { - return (CoordinateReferenceSystem) factory.createObject(code); - } - } catch (FactoryException e2) { - // then we have the wrong factory - // is there a better way to do this? - }catch (Exception e) { - UiPlugin.log("Error creating CRS object, trying more...", e); - } - } - try { - Preferences child = findNode(code); - if (child != null) { - String wkt = child.get(WKT_ID, null); - if (wkt != null) { - try { - return ReferencingFactoryFinder.getCRSFactory(null).createFromWKT(wkt); - } catch (Exception e) { - UiPlugin.log(wkt, e); - child.removeNode(); - } - } - } - - } catch (Exception e) { - UiPlugin.log(null, e); - } - return null; // should throw an exception? - } - - private Preferences findNode( String code ) { - try { - Preferences root = UiPlugin.getUserPreferences(); - Preferences node = root.node(InstanceScope.SCOPE).node(CUSTOM_ID); - - if (node.nodeExists(code)) { - return node.node(code); - } - - for( String id : node.childrenNames() ) { - Preferences child = node.node(id); - String name = child.get(NAME_ID, null); - if (name != null && matchesFilter(name, new String[]{code})) { - return child; - } - } - return null; - } catch (BackingStoreException e) { - UiPlugin.log("Error loading", e);//$NON-NLS-1$ - return null; - } - } - - /** - * returns the selected CRS - * - * @return selected CRS - */ - public CoordinateReferenceSystem getCRS() { - if (folder == null) - return selectedCRS; - if (folder.getSelectionIndex() == 1) { - try { - String text = wktText.getText(); - CoordinateReferenceSystem createdCRS = ReferencingFactoryFinder.getCRSFactory(null) - .createFromWKT(text); - - if (keywordsText.getText().trim().length() > 0) { - Preferences node = findNode(createdCRS.getName().getCode()); - if( node!=null ){ - Preferences kn = node.node(ALIASES_ID); - String[] keywords = keywordsText.getText().split(","); //$NON-NLS-1$ - kn.clear(); - for( String string : keywords ) { - string=string.trim().toUpperCase(); - if(string.length()>0) - kn.put(string,string); - } - kn.flush(); - }else{ - CoordinateReferenceSystem found = createCRS(createdCRS.getName().getCode()); - if (found != null && CRS.findMathTransform(found, createdCRS, true).isIdentity()) { - saveKeywords(found); - return found; - } - - Set identifiers = new HashSet(createdCRS.getIdentifiers()); - for( Identifier identifier : identifiers ) { - found = createCRS(identifier.toString()); - if (found != null && CRS.findMathTransform(found, createdCRS, true).isIdentity()) { - saveKeywords(found); - return found; - } - } - return saveCustomizedCRS(text, true, createdCRS); - } - } - - return createdCRS; - } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - if (selectedCRS == null) { - String crsCode = (String) ((IStructuredSelection) codesList.getSelection()).getFirstElement(); - if(sourceCRS != null && crsCode!=null && crsCode.equals(sourceCRS.getName().toString())){ - System.out.println("source crs: " + sourceCRS.getName().toString()); - return sourceCRS; - } - return createCRS(searchText.getText()); - } - return selectedCRS; - } - - /** - * - * @param found - * @throws CoreException - * @throws IOException - * @throws BackingStoreException - */ - private void saveKeywords( CoordinateReferenceSystem found ) throws CoreException, IOException, BackingStoreException { - String[] keywords=keywordsText.getText().split(","); //$NON-NLS-1$ - if( keywords.length>0 ){ - boolean legalKeyword=false; - // determine whether there are any keywords that are not blank. - for( int i=0; i0 ){ - legalKeyword=true; - break; - } - } - if( legalKeyword ){ - saveCustomizedCRS(found.toWKT(), false, found); - } - } - keywordsText.setText(""); //$NON-NLS-1$ - wktText.setText(found.toWKT()); - } - - /** - * @param text - * @param createdCRS - * @throws CoreException - * @throws IOException - * @throws BackingStoreException - */ - private CoordinateReferenceSystem saveCustomizedCRS( String text, boolean processWKT, CoordinateReferenceSystem createdCRS ) - throws CoreException, IOException, BackingStoreException { - Preferences root = UiPlugin.getUserPreferences(); - Preferences node = root.node(InstanceScope.SCOPE).node(CUSTOM_ID); - int lastID; - String code; - String name; - String newWKT; - if( processWKT ){ - lastID = Integer.parseInt(node.get(LAST_ID, "0")); //$NON-NLS-1$ - code = "UDIG:" + lastID; //$NON-NLS-1$ - name = createdCRS.getName().toString() + "(" + code + ")";//$NON-NLS-1$ //$NON-NLS-2$ - lastID++; - node.putInt(LAST_ID, lastID); - newWKT = processingWKT(text, lastID); - }else{ - Set ids = createdCRS.getIdentifiers(); - if( !ids.isEmpty() ){ - Identifier id = ids.iterator().next(); - code=id.toString(); - name=createdCRS.getName().getCode()+" ("+code+")"; //$NON-NLS-1$ //$NON-NLS-2$ - }else{ - name=code=createdCRS.getName().getCode(); - } - - newWKT=text; - } - - Preferences child = node.node(code); - child.put(NAME_ID, name); - child.put(WKT_ID, newWKT); - String[] keywords = keywordsText.getText().split(","); //$NON-NLS-1$ - if (keywords.length > 0) { - Preferences keyworkNode = child.node(ALIASES_ID); - for( String string : keywords ) { - string=string.trim().toUpperCase(); - keyworkNode.put(string, string); - } - } - node.flush(); - - return createdCRS; - } - - /** - * Remove the last AUTHORITY if it exists and add a UDIG Authority - */ - private String processingWKT( String text, int lastID ) { - String newWKT; - String[] prep = text.split(","); //$NON-NLS-1$ - if (prep[prep.length - 2].toUpperCase().contains("AUTHORITY")) { //$NON-NLS-1$ - String substring = text.substring(0, text.lastIndexOf(',')); - newWKT = substring.substring(0, substring.lastIndexOf(',')) - + ", AUTHORITY[\"UDIG\",\"" + (lastID - 1) + "\"]]"; //$NON-NLS-1$ //$NON-NLS-2$ - } else { - newWKT = text.substring(0, text.lastIndexOf(']')) - + ", AUTHORITY[\"UDIG\",\"" + (lastID - 1) + "\"]]"; //$NON-NLS-1$ //$NON-NLS-2$ - } - wktText.setText(newWKT); - return newWKT; - } - - public void setController( Controller controller ) { - parentPage=controller; - } - -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + * + */ +package org.locationtech.udig.ui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Text; +import org.geotools.referencing.CRS; +import org.geotools.referencing.ReferencingFactoryFinder; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.opengis.metadata.Identifier; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.IdentifiedObject; +import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.referencing.crs.CRSAuthorityFactory; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.osgi.service.prefs.BackingStoreException; +import org.osgi.service.prefs.Preferences; + +/** + * Creates a Control for choosing a Coordinate Reference System. + * + * @author jeichar + * @since 0.6.0 + */ +public class CRSChooser { + + private static final String WKT_ID = "WKT"; //$NON-NLS-1$ + private static final String ALIASES_ID = "ALIASES"; //$NON-NLS-1$ + private static final String LAST_ID = "LAST_ID"; //$NON-NLS-1$ + private static final String NAME_ID = "NAME_ID"; //$NON-NLS-1$ + private static final String CUSTOM_ID = "CRS.Custom.Services"; //$NON-NLS-1$ + private static final Controller DEFAULT = new Controller(){ + + @Override + public void handleClose() { + } + + @Override + public void handleOk() { + } + + }; + + ListViewer codesList; + Text searchText; + Text wktText; + Text keywordsText; + CoordinateReferenceSystem selectedCRS; + Matcher matcher; + private TabFolder folder; + private Controller parentPage; + private HashMap crsCodeMap; + private CoordinateReferenceSystem sourceCRS; + + public CRSChooser( Controller parentPage ) { + matcher = Pattern.compile(".*?\\(([^(]*)\\)$").matcher(""); //$NON-NLS-1$ //$NON-NLS-2$ + this.parentPage = parentPage; + } + + public CRSChooser() { + this(DEFAULT); + } + + private Control createCustomCRSControl( Composite parent ) { + Composite composite = new Composite(parent, SWT.NONE); + + GridLayout layout = new GridLayout(2, false); + composite.setLayout(layout); + + GridData gridData = new GridData(); + Label keywordsLabel = new Label(composite, SWT.NONE); + keywordsLabel.setText(Messages.CRSChooser_keywordsLabel); + keywordsLabel.setLayoutData(gridData); + keywordsLabel.setToolTipText(Messages.CRSChooser_tooltip); + + gridData = new GridData(SWT.FILL, SWT.NONE, true, false); + keywordsText = new Text(composite, SWT.SINGLE | SWT.BORDER); + keywordsText.setLayoutData(gridData); + keywordsText.setToolTipText(Messages.CRSChooser_tooltip); + + gridData = new GridData(SWT.FILL, SWT.NONE, true, false); + gridData.horizontalSpan = 2; + Label editorLabel = new Label(composite, SWT.NONE); + editorLabel.setText(Messages.CRSChooser_label_crsWKT); + editorLabel.setLayoutData(gridData); + + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.horizontalSpan = 2; + wktText = new Text(composite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + if (selectedCRS != null) + wktText.setText(selectedCRS.toWKT()); + wktText.setLayoutData(gridData); + wktText.addModifyListener(new ModifyListener(){ + + @Override + public void modifyText( ModifyEvent e ) { + if (!keywordsText.isEnabled()) + keywordsText.setEnabled(true); + } + + }); + + searchText.setFocus(); + return composite; + } + + private Control createStandardCRSControl( Composite parent ) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + composite.setLayout(layout); + + GridData gridData = new GridData(); + Label codesLabel = new Label(composite, SWT.NONE); + codesLabel.setText(Messages.CRSChooser_label_crs); + codesLabel.setLayoutData(gridData); + + gridData = new GridData(SWT.FILL, SWT.FILL, false, false); + searchText = new Text(composite, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.CANCEL); + searchText.setLayoutData(gridData); + searchText.addModifyListener(new ModifyListener(){ + @Override + public void modifyText( ModifyEvent e ) { + fillCodesList(); + } + }); + searchText.addListener(SWT.KeyUp, new Listener(){ + + @Override + public void handleEvent(Event event) { + if( event.keyCode==SWT.ARROW_DOWN){ + codesList.getControl().setFocus(); + } + } + + }); + gridData = new GridData(400, 300); + codesList = new ListViewer(composite); + codesList.setContentProvider(new ArrayContentProvider()); + codesList.setLabelProvider(new LabelProvider()); + codesList.addSelectionChangedListener(new ISelectionChangedListener(){ + + @Override + public void selectionChanged( SelectionChangedEvent event ) { + selectedCRS = null; + String crsCode = (String) ((IStructuredSelection) codesList.getSelection()) + .getFirstElement(); + if (crsCode == null) + return; + matcher.reset(crsCode); + if (matcher.matches()) { + selectedCRS = createCRS(matcher.group(1)); + if (selectedCRS != null && wktText != null) { + wktText.setEditable(true); + String wkt = null; + try{ + wkt = selectedCRS.toWKT(); + }catch (Exception e) { + /* + * if unable to generate WKT, just return the + * string and make the text area non editable. + */ + wkt = selectedCRS.toString(); + wktText.setEditable(false); + } + wktText.setText(wkt); + Preferences node = findNode(matcher.group(1)); + if( node!=null ){ + Preferences kn = node.node(ALIASES_ID); + try { + String[] keywords=kn.keys(); + if( keywords.length>0 ){ + StringBuffer buffer=new StringBuffer(); + for( String string : keywords ) { + buffer.append(", "); //$NON-NLS-1$ + buffer.append(string); + } + buffer.delete(0,2); + keywordsText.setText(buffer.toString()); + } + } catch (BackingStoreException e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + + }else{ + keywordsText.setText(""); //$NON-NLS-1$ + } + } + } + + } + + }); + + codesList.addDoubleClickListener(new IDoubleClickListener(){ + + @Override + public void doubleClick( DoubleClickEvent event ) { + parentPage.handleOk(); + parentPage.handleClose(); + + } + + }); + + codesList.getControl().setLayoutData(gridData); + /* + * fillCodesList() by itself resizes the Preferences Page but in the paintlistener it + * flickers the window + */ + fillCodesList(); + + searchText.setFocus(); + + return composite; + } + + public void setFocus(){ + searchText.setFocus(); + } + + /** + * Creates the CRS PreferencePage root control with a CRS already selected + * + * @param parent PreferencePage for this chooser + * @param crs current CRS for the associated map + * @return control for the PreferencePage + */ + public Control createControl( Composite parent, CoordinateReferenceSystem crs ) { + Control control = createControl(parent); + selectedCRS = crs; + gotoCRS(selectedCRS); + return control; + } + + public void clearSearch() { + searchText.setText(""); //$NON-NLS-1$ + } + + /** + * Takes in a CRS, finds it in the list and highlights it + * + * @param crs + */ + @SuppressWarnings("unchecked") + public void gotoCRS( CoordinateReferenceSystem crs ) { + if (crs != null) { + final List list = codesList.getList(); + Set identifiers = new HashSet<>(crs.getIdentifiers()); + + final Set candidates=new HashSet<>(); + + for( int i = 0; i < list.getItemCount(); i++ ) { + for( Identifier identifier : identifiers ) { + final String item = list.getItem(i); + if( sameEPSG( crs, identifier, item) || exactMatch( crs, identifier, item )){ + codesList.setSelection(new StructuredSelection(item), false); + list.setTopIndex(i); + return; + } + if (isMatch(crs, identifier, item)) { + candidates.add(i); + } + } + } + if( candidates.isEmpty() ){ + java.util.List input=(java.util.List) codesList.getInput(); + String sourceCRSName = crs.getName().toString(); + sourceCRS = crs; + input.add(0, sourceCRSName); + codesList.setInput(input); + codesList.setSelection(new StructuredSelection(sourceCRSName), false); + list.setTopIndex(0); + try{ + String toWKT = crs.toWKT(); + wktText.setText(toWKT); + }catch(RuntimeException e){ + LoggingSupport.log(UiPlugin.getDefault(), crs.toString()+" cannot be formatted as WKT", e); //$NON-NLS-1$ + wktText.setText(Messages.CRSChooser_unknownWKT); + } + }else{ + Integer next = candidates.iterator().next(); + codesList.setSelection(new StructuredSelection(list.getItem(next)), false); + list.setTopIndex(next); + + } + } + } + + private boolean exactMatch( CoordinateReferenceSystem crs, Identifier identifier, String item ) { + return (crs==DefaultGeographicCRS.WGS84 && item.equals("WGS 84 (4326)")) || //$NON-NLS-1$ + item.equalsIgnoreCase(identifier.toString()) || isInCodeMap(identifier, item); + } + + private boolean isInCodeMap( Identifier identifier, String item ) { + + String name = crsCodeMap.get(identifier.getCode()); + if(name==null ) return false; + else return name.equals(item); + } + + private boolean sameEPSG( CoordinateReferenceSystem crs, Identifier identifier, String item ) { + String toString = identifier.toString(); + return toString.contains("EPSG:") && item.contains(toString); //$NON-NLS-1$ + } + + private boolean isMatch( CoordinateReferenceSystem crs, Identifier identifier, String item ) { + return (crs==DefaultGeographicCRS.WGS84 && item.contains("4326")) || item.contains(identifier.toString()); //$NON-NLS-1$ + } + + /** + * Creates the CRS PreferencePage root control with no CRS selected + * + * @param parent PreferencePage for this chooser + * @return control for the PreferencePage + */ + public Control createControl( Composite parent ) { + GridData gridData = null; + + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + folder = new TabFolder(parent, SWT.NONE); + folder.setLayoutData(gridData); + + TabItem standard = new TabItem(folder, SWT.NONE); + standard.setText(Messages.CRSChooser_tab_standardCRS); + Control stdCRS = createStandardCRSControl(folder); + standard.setControl(stdCRS); + + TabItem custom = new TabItem(folder, SWT.NONE); + custom.setText(Messages.CRSChooser_tab_customCRS); + Control cstCRS = createCustomCRSControl(folder); + custom.setControl(cstCRS); + + return folder; + } + + /** + * checks if all keywords in filter array are in input + * + * @param input test string + * @param filter array of keywords + * @return true, if all keywords in filter are in the input, false otherwise + */ + protected boolean matchesFilter( String input, String[] filter ) { + for( String match : filter ) { + if (!input.contains(match)) + return false; + } + return true; + } + + /** + * filters all CRS Names from all available CRS authorities + * + * @param filter array of keywords + * @return Set of CRS Names which contain all the filter keywords + */ + protected Set filterCRSNames( String[] filter ) { + crsCodeMap = new HashMap<>(); + Set descriptions = new TreeSet<>(); + for( Object object : ReferencingFactoryFinder.getCRSAuthorityFactories(null) ) { + CRSAuthorityFactory factory = (CRSAuthorityFactory) object; + try { + Set codes = factory.getAuthorityCodes(CoordinateReferenceSystem.class); + for( Object codeObj : codes ) { + String code = (String) codeObj; + String description; + try { + description = factory.getDescriptionText(code).toString(); + } catch (Exception e1) { + description = Messages.CRSChooser_unnamed; + } + description += " (" + code + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + crsCodeMap.put(code, description); + if (matchesFilter(description.toUpperCase(), filter)){ + descriptions.add(description); + } + } + } catch (FactoryException e) { + UiPlugin.trace(CRSChooser.class, "CRS Authority:" + e.getMessage(), e); + } + } + return descriptions; + } + + /** + * populates the codes list with a filtered list of CRS names + */ + protected void fillCodesList() { + String[] searchParms = searchText.getText().toUpperCase().split(" "); //$NON-NLS-1$ + Set descriptions = filterCRSNames(searchParms); + descriptions = filterCustomCRSs(descriptions, searchParms); + java.util.List list = new ArrayList<>(descriptions); + codesList.setInput(list); + if (list != null && !list.isEmpty()) { + codesList.setSelection(new StructuredSelection(list.get(0))); + } else { + codesList.setSelection(new StructuredSelection()); + // System.out.println( "skipped"); + } + } + + private Set filterCustomCRSs( Set descriptions, String[] searchParms ) { + try { + Preferences root = UiPlugin.getUserPreferences(); + Preferences node = root.node(InstanceScope.SCOPE).node(CUSTOM_ID); + + for( String id : node.childrenNames() ) { + Preferences child = node.node(id); + String string = child.get(NAME_ID, null); + if (string != null && matchesFilter(string.toUpperCase(), searchParms)) { + descriptions.add(string); + continue; + } + + Preferences aliases = child.node(ALIASES_ID); + for( String alias : aliases.keys() ) { + if (matchesFilter(alias.toUpperCase(), searchParms)) { + descriptions.add(string); + continue; + } + } + } + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + return descriptions; + } + + /** + * creates a CRS from a code when the appropriate CRSAuthorityFactory is unknown + * + * @param code CRS code + * @return CRS object from appropriate authority, or null if the appropriate factory cannot be + * determined + */ + protected CoordinateReferenceSystem createCRS( String code ) { + if (code == null) + return null; + for( Object object : ReferencingFactoryFinder.getCRSAuthorityFactories(null) ) { + CRSAuthorityFactory factory = (CRSAuthorityFactory) object; + try { + IdentifiedObject identifiedObject = factory.createObject(code); + if (identifiedObject instanceof CoordinateReferenceSystem) { + return (CoordinateReferenceSystem) factory.createObject(code); + } + } catch (FactoryException e2) { + // then we have the wrong factory + // is there a better way to do this? + }catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error creating CRS object, trying more...", e); + } + } + try { + Preferences child = findNode(code); + if (child != null) { + String wkt = child.get(WKT_ID, null); + if (wkt != null) { + try { + return ReferencingFactoryFinder.getCRSFactory(null).createFromWKT(wkt); + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), wkt, e); + child.removeNode(); + } + } + } + + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + return null; // should throw an exception? + } + + private Preferences findNode( String code ) { + try { + Preferences root = UiPlugin.getUserPreferences(); + Preferences node = root.node(InstanceScope.SCOPE).node(CUSTOM_ID); + + if (node.nodeExists(code)) { + return node.node(code); + } + + for( String id : node.childrenNames() ) { + Preferences child = node.node(id); + String name = child.get(NAME_ID, null); + if (name != null && matchesFilter(name, new String[]{code})) { + return child; + } + } + return null; + } catch (BackingStoreException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error loading", e);//$NON-NLS-1$ + return null; + } + } + + /** + * returns the selected CRS + * + * @return selected CRS + */ + public CoordinateReferenceSystem getCRS() { + if (folder == null) + return selectedCRS; + if (folder.getSelectionIndex() == 1) { + try { + String text = wktText.getText(); + CoordinateReferenceSystem createdCRS = ReferencingFactoryFinder.getCRSFactory(null) + .createFromWKT(text); + + if (keywordsText.getText().trim().length() > 0) { + Preferences node = findNode(createdCRS.getName().getCode()); + if( node!=null ){ + Preferences kn = node.node(ALIASES_ID); + String[] keywords = keywordsText.getText().split(","); //$NON-NLS-1$ + kn.clear(); + for( String string : keywords ) { + string=string.trim().toUpperCase(); + if(string.length()>0) + kn.put(string,string); + } + kn.flush(); + }else{ + CoordinateReferenceSystem found = createCRS(createdCRS.getName().getCode()); + if (found != null && CRS.findMathTransform(found, createdCRS, true).isIdentity()) { + saveKeywords(found); + return found; + } + + Set identifiers = new HashSet<>(createdCRS.getIdentifiers()); + for( Identifier identifier : identifiers ) { + found = createCRS(identifier.toString()); + if (found != null && CRS.findMathTransform(found, createdCRS, true).isIdentity()) { + saveKeywords(found); + return found; + } + } + return saveCustomizedCRS(text, true, createdCRS); + } + } + + return createdCRS; + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), e); //$NON-NLS-1$ + } + } + if (selectedCRS == null) { + String crsCode = (String) ((IStructuredSelection) codesList.getSelection()).getFirstElement(); + if(sourceCRS != null && crsCode!=null && crsCode.equals(sourceCRS.getName().toString())){ + System.out.println("source crs: " + sourceCRS.getName().toString()); + return sourceCRS; + } + return createCRS(searchText.getText()); + } + return selectedCRS; + } + + /** + * + * @param found + * @throws CoreException + * @throws IOException + * @throws BackingStoreException + */ + private void saveKeywords(CoordinateReferenceSystem found) + throws CoreException, IOException, BackingStoreException { + String[] keywords = keywordsText.getText().split(","); //$NON-NLS-1$ + if (keywords.length > 0) { + boolean legalKeyword = false; + // determine whether there are any keywords that are not blank. + for (int i = 0; i < keywords.length; i++) { + String string = keywords[i]; + string = string.trim().toUpperCase(); + if (string.length() > 0) { + legalKeyword = true; + break; + } + } + if (legalKeyword) { + saveCustomizedCRS(found.toWKT(), false, found); + } + } + keywordsText.setText(""); //$NON-NLS-1$ + wktText.setText(found.toWKT()); + } + + /** + * @param text + * @param createdCRS + * @throws CoreException + * @throws IOException + * @throws BackingStoreException + */ + private CoordinateReferenceSystem saveCustomizedCRS(String text, boolean processWKT, + CoordinateReferenceSystem createdCRS) + throws CoreException, IOException, BackingStoreException { + Preferences root = UiPlugin.getUserPreferences(); + Preferences node = root.node(InstanceScope.SCOPE).node(CUSTOM_ID); + int lastID; + String code; + String name; + String newWKT; + if (processWKT) { + lastID = Integer.parseInt(node.get(LAST_ID, "0")); //$NON-NLS-1$ + code = "UDIG:" + lastID; //$NON-NLS-1$ + name = createdCRS.getName().toString() + "(" + code + ")";//$NON-NLS-1$ //$NON-NLS-2$ + lastID++; + node.putInt(LAST_ID, lastID); + newWKT = processingWKT(text, lastID); + } else { + Set ids = createdCRS.getIdentifiers(); + if (!ids.isEmpty()) { + Identifier id = ids.iterator().next(); + code = id.toString(); + name = createdCRS.getName().getCode() + " (" + code + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } else { + name = code = createdCRS.getName().getCode(); + } + + newWKT = text; + } + + Preferences child = node.node(code); + child.put(NAME_ID, name); + child.put(WKT_ID, newWKT); + String[] keywords = keywordsText.getText().split(","); //$NON-NLS-1$ + if (keywords.length > 0) { + Preferences keyworkNode = child.node(ALIASES_ID); + for (String string : keywords) { + string = string.trim().toUpperCase(); + keyworkNode.put(string, string); + } + } + node.flush(); + + return createdCRS; + } + + /** + * Remove the last AUTHORITY if it exists and add a UDIG Authority + */ + private String processingWKT(String text, int lastID) { + String newWKT; + String[] prep = text.split(","); //$NON-NLS-1$ + if (prep[prep.length - 2].toUpperCase().contains("AUTHORITY")) { //$NON-NLS-1$ + String substring = text.substring(0, text.lastIndexOf(',')); + newWKT = substring.substring(0, substring.lastIndexOf(',')) + ", AUTHORITY[\"UDIG\",\"" //$NON-NLS-1$ + + (lastID - 1) + "\"]]"; //$NON-NLS-1$ + } else { + newWKT = text.substring(0, text.lastIndexOf(']')) + ", AUTHORITY[\"UDIG\",\"" //$NON-NLS-1$ + + (lastID - 1) + "\"]]"; //$NON-NLS-1$ + } + wktText.setText(newWKT); + return newWKT; + } + + public void setController(Controller controller) { + parentPage = controller; + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableContentProvider.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableContentProvider.java index a88310382f..01a8091a38 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableContentProvider.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableContentProvider.java @@ -1,666 +1,685 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.ISafeRunnable; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.viewers.ILazyContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Scrollable; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.PlatformUI; -import org.geotools.data.FeatureEvent; -import org.geotools.data.FeatureListener; -import org.geotools.data.FeatureSource; -import org.geotools.data.Query; -import org.geotools.data.simple.SimpleFeatureCollection; -import org.geotools.feature.DefaultFeatureCollection; -import org.geotools.feature.FeatureCollection; -import org.geotools.feature.FeatureIterator; -import org.locationtech.udig.core.IProvider; -import org.locationtech.udig.core.feature.AdaptableFeatureCollection; -import org.locationtech.udig.internal.ui.Trace; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; - -/** - * ContentProvider that agressively listens to FeatureCollection (using FeatureSource FeatureEvents). - * - * @author Jody Garnett - */ -class FeatureTableContentProvider implements ILazyContentProvider, IProvider> { - - private static final IProgressMonitor NULL = new NullProgressMonitor(); - /** FeatureContentProvider owningFeatureTableControl field */ - private final FeatureTableControl owningFeatureTableControl; - - private volatile IProgressMonitor monitor = NULL; - private IProvider progressMonitorProvider; - - public FeatureTableContentProvider( FeatureTableControl control, IProvider progressMonitorProvider ) { - owningFeatureTableControl = control; - this.progressMonitorProvider=progressMonitorProvider; - } - - /** - * Listens for changes in FeatureSource, updates the viewer if content provider changes. - *

    - * If we were extra cool we could filter the incoming FeatureEvents based on if they - * are actually included in our ContentProvider. As it is we will refresh everything. - */ - private FeatureListener listener = new FeatureListener() { - - @Override - public void changed(FeatureEvent event) { - if (listener == null) { - event.getFeatureSource().removeFeatureListener(this); - return; - } - - TableViewer viewer = FeatureTableContentProvider.this.owningFeatureTableControl - .getViewer(); - - switch (event.getType()) { - case ADDED: - try { - SimpleFeatureCollection changed = (SimpleFeatureCollection) event - .getFeatureSource().getFeatures(event.getFilter()); - FeatureIterator iterator = changed.features(); - try { - while (iterator.hasNext()) { - SimpleFeature newFeature = iterator.next(); - features.add(newFeature); - } - viewer.setItemCount(event.getFeatureSource().getCount(Query.ALL)); - viewer.getTable().clearAll(); - } finally { - iterator.close(); - } - } catch (IOException accessError) { - } - break; - case REMOVED: - for (Iterator iter = features.iterator(); iter.hasNext();) { - SimpleFeature feature = iter.next(); - if (event.getFilter().evaluate(feature)) { - iter.remove(); // event indicated this feature has been removed - } - } - viewer.setItemCount(features.size()); - viewer.getTable().clearAll(); - break; - case CHANGED: - try { - SimpleFeatureCollection changed = (SimpleFeatureCollection) event - .getFeatureSource().getFeatures(event.getFilter()); - - FeatureIterator iterator = changed.features(); - try { - while (iterator.hasNext()) { - SimpleFeature changedFeature = iterator.next(); - SCAN: for (ListIterator iter = features.listIterator(); iter - .hasNext();) { - SimpleFeature item = iter.next(); - if (item.getID().equals(changedFeature.getID())) { - iter.set(changedFeature); - break SCAN; - } - } - } - viewer.setItemCount(event.getFeatureSource().getCount(Query.ALL)); - viewer.getTable().clearAll(); - } finally { - iterator.close(); - } - } catch (IOException accessError) { - } - viewer.getTable().clearAll(); - break; - case COMMIT: - //TBD - break; - case ROLLBACK: - //TBD - break; - - default: - break; - } - } - }; - - /** Memory bound cache of features for table. - * May be sorted according to FID or any of the attributes so don't rely on any given order because - * its liable to change. User Lookup instead for quickly locating a features - */ - List features = Collections.synchronizedList( new ArrayList()); - - /** - * Contains same features as Features but sorted by id - */ - Map lookup = new HashMap(); - /** - * If true then an edit has occurred and the table is being updated. - */ - private volatile boolean updating=false; - private boolean disposed=false; - /** - * Does nothing. - * - * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, - * java.lang.Object, java.lang.Object) - * @param viewer - * @param oldInput - * @param newInput - */ - public void inputChanged( Viewer viewer, Object oldInput, final Object newInput ) { - - synchronized (this) { - if (monitor != NULL) { - monitor.setCanceled(true); - - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "#inputChanged(): cancelled monitor", null); //$NON-NLS-1$ - try { - PlatformGIS.wait(500, -1, new WaitCondition(){ - - public boolean isTrue() { - return monitor == NULL; - } - - }, this); - } catch (InterruptedException e) { - UiPlugin.log("Interrupted", e); //$NON-NLS-1$ - return; - } - } - features.clear(); - - if (oldInput != null && oldInput instanceof AdaptableFeatureCollection) { - AdaptableFeatureCollection old = (AdaptableFeatureCollection) oldInput; - FeatureSource source = (FeatureSource) old.getAdapter(FeatureSource.class); - if (source != null) { - source.removeFeatureListener(listener); - } - } - if (newInput != null && newInput instanceof AdaptableFeatureCollection) { - AdaptableFeatureCollection input = (AdaptableFeatureCollection) newInput; - FeatureSource source = (FeatureSource) input.getAdapter(FeatureSource.class); - if (source != null) { - source.addFeatureListener(listener); - } else { - UiPlugin.trace(UiPlugin.ID, FeatureTableContentProvider.class, - "Unable to adapt to FeatureSource (to listen for changes):" + input, - null); - } - } else { - UiPlugin.trace(UiPlugin.ID, FeatureTableContentProvider.class, - "Unable to access FeatureSource (to listen for changes):" + newInput, null); - } - - if (newInput == null) - return; - - monitor = progressMonitorProvider.get(); - monitor.setCanceled(false); - owningFeatureTableControl.message(null); - owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(false, monitor, true)); - - final FeatureCollection input = (FeatureCollection) newInput; - Display display = Display.getCurrent(); - owningFeatureTableControl.message(Messages.FeatureTableContentProvider_loading, display - .getSystemColor(SWT.COLOR_INFO_BACKGROUND), display - .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); - PlatformGIS.run(new ContentLoader(input)); - } - } - public void dispose() { - synchronized( this ){ - if( disposed ) - return; - - disposed=true; - } - features.clear(); - - if (monitor != NULL) { - monitor.setCanceled(true); - try { - PlatformGIS.wait(200, -1, new WaitCondition(){ - - public boolean isTrue() { - return monitor == NULL; - } - - }, this); - } catch (InterruptedException e) { - UiPlugin.log("Interrupted", e); //$NON-NLS-1$ - return; - } - } - } - public Collection get(Object... params) { - return features; - } - public void updateElement( int index ) { - if (index >= features.size()) { - owningFeatureTableControl.getViewer().replace("", index); //$NON-NLS-1$ - } else if (monitor != NULL && index == 0 && !updating) { - owningFeatureTableControl.getViewer().replace(FeatureTableControl.LOADING, 0); - } else { - int resolvedIndex=index; - //commented fragment below not needed since features list - //is already sorted using Collections.sort - //if( owningFeatureTableControl.getViewer().getTable().getSortDirection()==SWT.UP ) - // resolvedIndex=features.size()-index-1; - SimpleFeature feature = features.get(resolvedIndex); - owningFeatureTableControl.getViewer().replace(feature, index); - } - } - - private class ContentLoader implements ISafeRunnable { - - private final FeatureCollection input; - - public ContentLoader( FeatureCollection input ) { - this.input = input; - } - - public void handleException( Throwable exception ) { - UiPlugin.log("Error loading features", exception); //$NON-NLS-1$ - } - - public void run() throws Exception { - if (cancel()) - return; - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "Starting ContentLoader", null); //$NON-NLS-1$ - setEnabled(false); - int i = 0; - final int[] monitorUpdate = new int[1]; - monitorUpdate[0] = 0; - boolean updated = false; - long start = System.currentTimeMillis(); - FeatureIterator iterator = null; - try { - iterator = input.features(); - while( iterator.hasNext() ) { - if (System.currentTimeMillis() - start > 500) { - if (!updated) { - updated = true; - updateTable(input, false); - } - start = System.currentTimeMillis(); - updateMonitor(i, monitorUpdate); - } - if (cancel()) - return; - SimpleFeature next = iterator.next(); - features.add(next); - lookup.put(next.getID(), next); - i++; - } - } catch (OutOfMemoryError error) { - error(input, i + " " + Messages.FeatureTableContentProvider_outOfMemory, true); //$NON-NLS-1$ - UiPlugin.log("Out of memory error in table view", error); //$NON-NLS-1$ - return; - } catch (IndexOutOfBoundsException e) { - error(input, Messages.FeatureTableContentProvider_unexpectedErro - + " " + Messages.FeatureTableContentProvider_probablecharseterror, false); - UiPlugin.log("error loading features in table view", e); //$NON-NLS-1$ - return; - } catch (Throwable t) { - error(input, Messages.FeatureTableContentProvider_unexpectedErro - + t.getLocalizedMessage(), false); - UiPlugin.log("error loading features in table view", t); //$NON-NLS-1$ - return; - } finally { - if (iterator != null) - iterator.close(); - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "Ending ContentLoader, Cancel state is:"+monitor.isCanceled(), null); //$NON-NLS-1$ - } - if (!cancel()) { - updateTable(input, true); - setEnabled(true); - } - } - - /** - * will setenable and set an error message on the feature table control. - */ - private void error( final FeatureCollection input, final String string, - final boolean clearFeatures ) { - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "ContentLoader#error: Error occurred in ContentLoader:\n"+string, null); //$NON-NLS-1$ - - final Display display = owningFeatureTableControl.getViewer().getControl().getDisplay(); - display.asyncExec(new Runnable(){ - public void run() { - monitor.setCanceled(true); - } - }); - done(); - display.asyncExec(new Runnable(){ - public void run() { - owningFeatureTableControl.message(string, display - .getSystemColor(SWT.COLOR_INFO_BACKGROUND), display - .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); - } - }); - } - - private void updateMonitor( int i, final int[] monitorUpdate ) { - final int j = i; - owningFeatureTableControl.getViewer().getControl().getDisplay().asyncExec( - new Runnable(){ - public void run() { - monitor - .subTask(Messages.FeatureTableContentProvider_loadedFeatures - + j); - monitor.worked(j - monitorUpdate[0]); - monitorUpdate[0] = j; - } - }); - } - - /** - * If enabled it will finish the {@link IProgressMonitor}, null it out, notify listeners - * and enable the table control. if not enabled it will begin the progress task and disable - * the Table control - * - * @param enabled - */ - private void setEnabled( final boolean enabled ) { - - final Scrollable control = owningFeatureTableControl.getViewer().getTable(); - final int size; - if (!enabled) - size = input.size(); - else - size = IProgressMonitor.UNKNOWN; - - control.getDisplay().asyncExec(new Runnable(){ - public void run() { - - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "ContentLoader#setEnabled():"+enabled, null); //$NON-NLS-1$ - if (enabled) { - done(); - } else { - monitor.beginTask(Messages.FeatureTableControl_loading1 - + input.getSchema().getName().getLocalPart() - + Messages.FeatureTableControl_loading2, size + 1); - monitor.worked(1); - } - } - }); - } - private void done() { - final Table control = owningFeatureTableControl.getViewer().getTable(); - Runnable runnable = new Runnable(){ - public void run() { - - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "ContentLoader#done()|run():", null); //$NON-NLS-1$ - - monitor.done(); - synchronized (FeatureTableContentProvider.this) { - monitor = NULL; - FeatureTableContentProvider.this.notifyAll(); - if (!control.isDisposed()) - control.getVerticalBar().setEnabled(true); - if (control.getItemCount() > 0) { - owningFeatureTableControl.getViewer().replace(features.get(0), 0); - } - owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(monitor - .isCanceled(), null, false)); - } - } - }; - if (Display.getCurrent() != control.getDisplay()) { - control.getDisplay().asyncExec(runnable); - } else { - runnable.run(); - } - } - - private void updateTable( final FeatureCollection newInput, final boolean done ) { - final Table table = owningFeatureTableControl.getViewer().getTable(); - table.getDisplay().asyncExec(new Runnable(){ - public void run() { - - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, - "ContentLoader#updateTable(): done="+done, null); //$NON-NLS-1$ - - owningFeatureTableControl.message(null); - int size = features.size(); - owningFeatureTableControl.getViewer().setItemCount(size); - if (!done && !table.isDisposed()) - table.getVerticalBar().setEnabled(false); - } - }); - } - - private boolean cancel() { - synchronized (FeatureTableContentProvider.this) { - if (monitor.isCanceled() || PlatformUI.getWorkbench().isClosing()) { - done(); - return true; - } - return false; - } - } - - } - - /** - * Updates the features that have the same feature ID to match the new feature or adds the features if they are not part of the - * current collection. - * - * @param features2 the feature collection that contains the modified or new features. - */ - public void update( FeatureCollection features2 ) throws IllegalArgumentException{ - if( features==null ) - return; - - if( !owningFeatureTableControl.features.getSchema().equals(features2.getSchema()) ) - throw new IllegalArgumentException( "The feature type of the SimpleFeature Collection passed as a parameter does not have the same" + //$NON-NLS-1$ - " feature type as the features in the table so it cannot be used to update the features." ); //$NON-NLS-1$ - - ContentUpdater updater=new ContentUpdater(features2); - PlatformGIS.run(updater); - } - - SimpleFeature findFeature(String featureId ){ - return lookup.get(featureId); - } - - private class ContentUpdater implements ISafeRunnable{ - - private FeatureCollection newFeatures; - private int loaded=0; - - public ContentUpdater( FeatureCollection features2 ) { - this.newFeatures=features2; - } - - public void handleException( Throwable exception ) { - UiPlugin.log("Exception while updating the features in the FeatureTableControl", exception); //$NON-NLS-1$ - } - - public void run() throws Exception { - synchronized( FeatureTableContentProvider.this){ - updating=true; - if (monitor != NULL) { - // wait until finished loading - try { - PlatformGIS.wait(500, -1, new WaitCondition(){ - - public boolean isTrue() { - return monitor == NULL; - } - - }, FeatureTableContentProvider.this); - } catch (InterruptedException e) { - UiPlugin.log("Interrupted", e); //$NON-NLS-1$ - return; - } - } - - startLoading(); - - SimpleFeatureType schema = newFeatures.getSchema(); - FeatureIterator iter=newFeatures.features(); - try{ - boolean featuresWereAdded=false; - while( iter.hasNext() ){ - if( monitor.isCanceled() ) - break; - SimpleFeature newValue = iter.next(); - SimpleFeature oldValue = findFeature(newValue.getID()); - if( oldValue==null ){ - featuresWereAdded=true; - features.add(newValue); - lookup.put(newValue.getID(), newValue); - }else{ - for( int i = 0; i < schema.getAttributeCount(); i++ ) { - oldValue.setAttribute(i, newValue.getAttribute(i)); - } - } - loaded++; - updateMonitor(loaded+Messages.FeatureTableContentProvider_updatingFeatures); - } - - updateTable(featuresWereAdded); - }finally{ - iter.close(); - } - - } - } - - private void updateTable(final boolean featuresWereAdded) { - final Table table = owningFeatureTableControl.getViewer().getTable(); - table.getDisplay().asyncExec(new Runnable(){ - public void run() { - if( featuresWereAdded ){ - updateMonitor(Messages.FeatureTableContentProvider_sortTable); - owningFeatureTableControl.sort(false); - owningFeatureTableControl.getViewer().setItemCount(features.size()); - }else{ - table.clearAll(); - } - monitor.done(); - boolean cancelled = monitor.isCanceled(); - monitor=NULL; - updating=false; - synchronized (FeatureTableContentProvider.this) { - FeatureTableContentProvider.this.notifyAll(); - } - owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(cancelled, null, false)); - } - }); - } - - - private void updateMonitor(final String subTask) { - Display display = owningFeatureTableControl.getControl().getDisplay(); - display.asyncExec(new Runnable(){ - public void run() { - monitor.subTask(subTask); - monitor.worked(1); - } - }); - } - - private void startLoading() { - Display display = owningFeatureTableControl.getControl().getDisplay(); - display.asyncExec(new Runnable(){ - public void run() { - owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(false, monitor, true)); - monitor=progressMonitorProvider.get(); - monitor.setCanceled(false); - monitor.beginTask(Messages.FeatureTableContentProvider_updateTaskName, IProgressMonitor.UNKNOWN); - } - }); - } - } - - /** - * Checks the lookup table and the feature list to ensure that they have the same number of features and the same features. - * An exception will be thrown otherwise. - */ - public void assertInternallyConsistent(){ - if( features.size()!=lookup.size()) - throw new AssertionError("lookup table has "+lookup.size()+" features while feature list has "+features.size()+" features"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - - for( SimpleFeature feature : features ) { - SimpleFeature lookupFeature = lookup.get(feature.getID()); - if( lookup==null ){ - throw new AssertionError("Lookup table is missing "+feature); //$NON-NLS-1$ - } - if( lookupFeature!=feature ) - throw new AssertionError("Lookup table contains: "+lookupFeature+" while feature list contains"+feature+". They are" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - " not the same instance"); //$NON-NLS-1$ - } - } - /** - * Removes the selected features (the features selected by the owning {@link FeatureTableControl}). - * @return returns a collection of the deleted features - */ - public FeatureCollection deleteSelection() { - final DefaultFeatureCollection deletedFeatures = new DefaultFeatureCollection(); - Runnable updateTable = new Runnable(){ - @SuppressWarnings("unchecked") - public void run() { - Collection selectionFids = owningFeatureTableControl.getSelectionProvider().getSelectionFids(); - - for( Iterator iter = features.iterator(); iter.hasNext(); ) { - SimpleFeature feature = iter.next(); - if( selectionFids.contains(feature.getID()) ){ - deletedFeatures.add(feature); - iter.remove(); - lookup.remove(feature.getID()); - } - } - - selectionFids.clear(); - owningFeatureTableControl.getViewer().getTable().clearAll(); - } - }; - - if( Display.getCurrent()==null ){ - PlatformGIS.syncInDisplayThread(owningFeatureTableControl.getControl().getDisplay(), updateTable); - }else{ - updateTable.run(); - } - - return deletedFeatures; - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.viewers.ILazyContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Scrollable; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.PlatformUI; +import org.geotools.data.FeatureEvent; +import org.geotools.data.FeatureListener; +import org.geotools.data.FeatureSource; +import org.geotools.data.Query; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.feature.DefaultFeatureCollection; +import org.geotools.feature.FeatureCollection; +import org.geotools.feature.FeatureIterator; +import org.locationtech.udig.core.IProvider; +import org.locationtech.udig.core.feature.AdaptableFeatureCollection; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.Trace; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; + +/** + * ContentProvider that agressively listens to FeatureCollection (using FeatureSource FeatureEvents). + * + * @author Jody Garnett + */ +class FeatureTableContentProvider implements ILazyContentProvider, IProvider> { + + private static final IProgressMonitor NULL = new NullProgressMonitor(); + /** FeatureContentProvider owningFeatureTableControl field */ + private final FeatureTableControl owningFeatureTableControl; + + private volatile IProgressMonitor monitor = NULL; + private IProvider progressMonitorProvider; + + public FeatureTableContentProvider( FeatureTableControl control, IProvider progressMonitorProvider ) { + owningFeatureTableControl = control; + this.progressMonitorProvider=progressMonitorProvider; + } + + /** + * Listens for changes in FeatureSource, updates the viewer if content provider changes. + *

    + * If we were extra cool we could filter the incoming FeatureEvents based on if they + * are actually included in our ContentProvider. As it is we will refresh everything. + */ + private FeatureListener listener = new FeatureListener() { + + @Override + public void changed(FeatureEvent event) { + if (listener == null) { + event.getFeatureSource().removeFeatureListener(this); + return; + } + + TableViewer viewer = FeatureTableContentProvider.this.owningFeatureTableControl + .getViewer(); + + switch (event.getType()) { + case ADDED: + try { + SimpleFeatureCollection changed = (SimpleFeatureCollection) event + .getFeatureSource().getFeatures(event.getFilter()); + FeatureIterator iterator = changed.features(); + try { + while (iterator.hasNext()) { + SimpleFeature newFeature = iterator.next(); + features.add(newFeature); + } + viewer.setItemCount(event.getFeatureSource().getCount(Query.ALL)); + viewer.getTable().clearAll(); + } finally { + iterator.close(); + } + } catch (IOException accessError) { + } + break; + case REMOVED: + for (Iterator iter = features.iterator(); iter.hasNext();) { + SimpleFeature feature = iter.next(); + if (event.getFilter().evaluate(feature)) { + iter.remove(); // event indicated this feature has been removed + } + } + viewer.setItemCount(features.size()); + viewer.getTable().clearAll(); + break; + case CHANGED: + try { + SimpleFeatureCollection changed = (SimpleFeatureCollection) event + .getFeatureSource().getFeatures(event.getFilter()); + + FeatureIterator iterator = changed.features(); + try { + while (iterator.hasNext()) { + SimpleFeature changedFeature = iterator.next(); + SCAN: for (ListIterator iter = features.listIterator(); iter + .hasNext();) { + SimpleFeature item = iter.next(); + if (item.getID().equals(changedFeature.getID())) { + iter.set(changedFeature); + break SCAN; + } + } + } + viewer.setItemCount(event.getFeatureSource().getCount(Query.ALL)); + viewer.getTable().clearAll(); + } finally { + iterator.close(); + } + } catch (IOException accessError) { + } + viewer.getTable().clearAll(); + break; + case COMMIT: + //TBD + break; + case ROLLBACK: + //TBD + break; + + default: + break; + } + } + }; + + /** Memory bound cache of features for table. + * May be sorted according to FID or any of the attributes so don't rely on any given order because + * its liable to change. User Lookup instead for quickly locating a features + */ + List features = Collections.synchronizedList( new ArrayList()); + + /** + * Contains same features as Features but sorted by id + */ + Map lookup = new HashMap<>(); + /** + * If true then an edit has occurred and the table is being updated. + */ + private volatile boolean updating=false; + private boolean disposed=false; + /** + * Does nothing. + * + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, + * java.lang.Object, java.lang.Object) + * @param viewer + * @param oldInput + * @param newInput + */ + @Override + public void inputChanged( Viewer viewer, Object oldInput, final Object newInput ) { + + synchronized (this) { + if (monitor != NULL) { + monitor.setCanceled(true); + + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "#inputChanged(): cancelled monitor", null); //$NON-NLS-1$ + try { + PlatformGIS.wait(500, -1, new WaitCondition(){ + + @Override + public boolean isTrue() { + return monitor == NULL; + } + + }, this); + } catch (InterruptedException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Interrupted", e); //$NON-NLS-1$ + return; + } + } + features.clear(); + + if (oldInput != null && oldInput instanceof AdaptableFeatureCollection) { + AdaptableFeatureCollection old = (AdaptableFeatureCollection) oldInput; + FeatureSource source = (FeatureSource) old.getAdapter(FeatureSource.class); + if (source != null) { + source.removeFeatureListener(listener); + } + } + if (newInput != null && newInput instanceof AdaptableFeatureCollection) { + AdaptableFeatureCollection input = (AdaptableFeatureCollection) newInput; + FeatureSource source = (FeatureSource) input.getAdapter(FeatureSource.class); + if (source != null) { + source.addFeatureListener(listener); + } else { + UiPlugin.trace(UiPlugin.ID, FeatureTableContentProvider.class, + "Unable to adapt to FeatureSource (to listen for changes):" + input, + null); + } + } else { + UiPlugin.trace(UiPlugin.ID, FeatureTableContentProvider.class, + "Unable to access FeatureSource (to listen for changes):" + newInput, null); + } + + if (newInput == null) + return; + + monitor = progressMonitorProvider.get(); + monitor.setCanceled(false); + owningFeatureTableControl.message(null); + owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(false, monitor, true)); + + final FeatureCollection input = (FeatureCollection) newInput; + Display display = Display.getCurrent(); + owningFeatureTableControl.message(Messages.FeatureTableContentProvider_loading, display + .getSystemColor(SWT.COLOR_INFO_BACKGROUND), display + .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + PlatformGIS.run(new ContentLoader(input)); + } + } + @Override + public void dispose() { + synchronized( this ){ + if( disposed ) + return; + + disposed=true; + } + features.clear(); + + if (monitor != NULL) { + monitor.setCanceled(true); + try { + PlatformGIS.wait(200, -1, new WaitCondition(){ + + @Override + public boolean isTrue() { + return monitor == NULL; + } + + }, this); + } catch (InterruptedException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Interrupted", e); //$NON-NLS-1$ + return; + } + } + } + @Override + public Collection get(Object... params) { + return features; + } + @Override + public void updateElement( int index ) { + if (index >= features.size()) { + owningFeatureTableControl.getViewer().replace("", index); //$NON-NLS-1$ + } else if (monitor != NULL && index == 0 && !updating) { + owningFeatureTableControl.getViewer().replace(FeatureTableControl.LOADING, 0); + } else { + int resolvedIndex=index; + //commented fragment below not needed since features list + //is already sorted using Collections.sort + //if( owningFeatureTableControl.getViewer().getTable().getSortDirection()==SWT.UP ) + // resolvedIndex=features.size()-index-1; + SimpleFeature feature = features.get(resolvedIndex); + owningFeatureTableControl.getViewer().replace(feature, index); + } + } + + private class ContentLoader implements ISafeRunnable { + + private final FeatureCollection input; + + public ContentLoader( FeatureCollection input ) { + this.input = input; + } + + @Override + public void handleException( Throwable exception ) { + LoggingSupport.log(UiPlugin.getDefault(), "Error loading features", exception); //$NON-NLS-1$ + } + + @Override + public void run() throws Exception { + if (cancel()) + return; + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "Starting ContentLoader", null); //$NON-NLS-1$ + setEnabled(false); + int i = 0; + final int[] monitorUpdate = new int[1]; + monitorUpdate[0] = 0; + boolean updated = false; + long start = System.currentTimeMillis(); + FeatureIterator iterator = null; + try { + iterator = input.features(); + while( iterator.hasNext() ) { + if (System.currentTimeMillis() - start > 500) { + if (!updated) { + updated = true; + updateTable(input, false); + } + start = System.currentTimeMillis(); + updateMonitor(i, monitorUpdate); + } + if (cancel()) + return; + SimpleFeature next = iterator.next(); + features.add(next); + lookup.put(next.getID(), next); + i++; + } + } catch (OutOfMemoryError error) { + error(input, i + " " + Messages.FeatureTableContentProvider_outOfMemory, true); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), "Out of memory error in table view", error); //$NON-NLS-1$ + return; + } catch (IndexOutOfBoundsException e) { + error(input, Messages.FeatureTableContentProvider_unexpectedErro + + " " + Messages.FeatureTableContentProvider_probablecharseterror, false); + LoggingSupport.log(UiPlugin.getDefault(), "error loading features in table view", e); //$NON-NLS-1$ + return; + } catch (Throwable t) { + error(input, Messages.FeatureTableContentProvider_unexpectedErro + + t.getLocalizedMessage(), false); + LoggingSupport.log(UiPlugin.getDefault(), "error loading features in table view", t); //$NON-NLS-1$ + return; + } finally { + if (iterator != null) + iterator.close(); + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "Ending ContentLoader, Cancel state is:"+monitor.isCanceled(), null); //$NON-NLS-1$ + } + if (!cancel()) { + updateTable(input, true); + setEnabled(true); + } + } + + /** + * will setenable and set an error message on the feature table control. + */ + private void error( final FeatureCollection input, final String string, + final boolean clearFeatures ) { + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "ContentLoader#error: Error occurred in ContentLoader:\n"+string, null); //$NON-NLS-1$ + + final Display display = owningFeatureTableControl.getViewer().getControl().getDisplay(); + display.asyncExec(new Runnable(){ + @Override + public void run() { + monitor.setCanceled(true); + } + }); + done(); + display.asyncExec(new Runnable(){ + @Override + public void run() { + owningFeatureTableControl.message(string, display + .getSystemColor(SWT.COLOR_INFO_BACKGROUND), display + .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + } + }); + } + + private void updateMonitor( int i, final int[] monitorUpdate ) { + final int j = i; + owningFeatureTableControl.getViewer().getControl().getDisplay().asyncExec( + new Runnable(){ + @Override + public void run() { + monitor + .subTask(Messages.FeatureTableContentProvider_loadedFeatures + + j); + monitor.worked(j - monitorUpdate[0]); + monitorUpdate[0] = j; + } + }); + } + + /** + * If enabled it will finish the {@link IProgressMonitor}, null it out, notify listeners + * and enable the table control. if not enabled it will begin the progress task and disable + * the Table control + * + * @param enabled + */ + private void setEnabled( final boolean enabled ) { + + final Scrollable control = owningFeatureTableControl.getViewer().getTable(); + final int size; + if (!enabled) + size = input.size(); + else + size = IProgressMonitor.UNKNOWN; + + control.getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "ContentLoader#setEnabled():"+enabled, null); //$NON-NLS-1$ + if (enabled) { + done(); + } else { + monitor.beginTask(Messages.FeatureTableControl_loading1 + + input.getSchema().getName().getLocalPart() + + Messages.FeatureTableControl_loading2, size + 1); + monitor.worked(1); + } + } + }); + } + private void done() { + final Table control = owningFeatureTableControl.getViewer().getTable(); + Runnable runnable = new Runnable(){ + @Override + public void run() { + + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "ContentLoader#done()|run():", null); //$NON-NLS-1$ + + monitor.done(); + synchronized (FeatureTableContentProvider.this) { + monitor = NULL; + FeatureTableContentProvider.this.notifyAll(); + if (!control.isDisposed()) + control.getVerticalBar().setEnabled(true); + if (control.getItemCount() > 0) { + owningFeatureTableControl.getViewer().replace(features.get(0), 0); + } + owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(monitor + .isCanceled(), null, false)); + } + } + }; + if (Display.getCurrent() != control.getDisplay()) { + control.getDisplay().asyncExec(runnable); + } else { + runnable.run(); + } + } + + private void updateTable( final FeatureCollection newInput, final boolean done ) { + final Table table = owningFeatureTableControl.getViewer().getTable(); + table.getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableContentProvider.class, + "ContentLoader#updateTable(): done="+done, null); //$NON-NLS-1$ + + owningFeatureTableControl.message(null); + int size = features.size(); + owningFeatureTableControl.getViewer().setItemCount(size); + if (!done && !table.isDisposed()) + table.getVerticalBar().setEnabled(false); + } + }); + } + + private boolean cancel() { + synchronized (FeatureTableContentProvider.this) { + if (monitor.isCanceled() || PlatformUI.getWorkbench().isClosing()) { + done(); + return true; + } + return false; + } + } + + } + + /** + * Updates the features that have the same feature ID to match the new feature or adds the features if they are not part of the + * current collection. + * + * @param features2 the feature collection that contains the modified or new features. + */ + public void update( FeatureCollection features2 ) throws IllegalArgumentException{ + if( features==null ) + return; + + if( !owningFeatureTableControl.features.getSchema().equals(features2.getSchema()) ) + throw new IllegalArgumentException( "The feature type of the SimpleFeature Collection passed as a parameter does not have the same" + //$NON-NLS-1$ + " feature type as the features in the table so it cannot be used to update the features." ); //$NON-NLS-1$ + + ContentUpdater updater=new ContentUpdater(features2); + PlatformGIS.run(updater); + } + + SimpleFeature findFeature(String featureId ){ + return lookup.get(featureId); + } + + private class ContentUpdater implements ISafeRunnable{ + + private FeatureCollection newFeatures; + private int loaded=0; + + public ContentUpdater( FeatureCollection features2 ) { + this.newFeatures=features2; + } + + @Override + public void handleException( Throwable exception ) { + LoggingSupport.log(UiPlugin.getDefault(), "Exception while updating the features in the FeatureTableControl", exception); //$NON-NLS-1$ + } + + @Override + public void run() throws Exception { + synchronized( FeatureTableContentProvider.this){ + updating=true; + if (monitor != NULL) { + // wait until finished loading + try { + PlatformGIS.wait(500, -1, new WaitCondition(){ + + @Override + public boolean isTrue() { + return monitor == NULL; + } + + }, FeatureTableContentProvider.this); + } catch (InterruptedException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Interrupted", e); //$NON-NLS-1$ + return; + } + } + + startLoading(); + + SimpleFeatureType schema = newFeatures.getSchema(); + FeatureIterator iter=newFeatures.features(); + try{ + boolean featuresWereAdded=false; + while( iter.hasNext() ){ + if( monitor.isCanceled() ) + break; + SimpleFeature newValue = iter.next(); + SimpleFeature oldValue = findFeature(newValue.getID()); + if( oldValue==null ){ + featuresWereAdded=true; + features.add(newValue); + lookup.put(newValue.getID(), newValue); + }else{ + for( int i = 0; i < schema.getAttributeCount(); i++ ) { + oldValue.setAttribute(i, newValue.getAttribute(i)); + } + } + loaded++; + updateMonitor(loaded+Messages.FeatureTableContentProvider_updatingFeatures); + } + + updateTable(featuresWereAdded); + }finally{ + iter.close(); + } + + } + } + + private void updateTable(final boolean featuresWereAdded) { + final Table table = owningFeatureTableControl.getViewer().getTable(); + table.getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + if( featuresWereAdded ){ + updateMonitor(Messages.FeatureTableContentProvider_sortTable); + owningFeatureTableControl.sort(false); + owningFeatureTableControl.getViewer().setItemCount(features.size()); + }else{ + table.clearAll(); + } + monitor.done(); + boolean cancelled = monitor.isCanceled(); + monitor=NULL; + updating=false; + synchronized (FeatureTableContentProvider.this) { + FeatureTableContentProvider.this.notifyAll(); + } + owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(cancelled, null, false)); + } + }); + } + + + private void updateMonitor(final String subTask) { + Display display = owningFeatureTableControl.getControl().getDisplay(); + display.asyncExec(new Runnable(){ + @Override + public void run() { + monitor.subTask(subTask); + monitor.worked(1); + } + }); + } + + private void startLoading() { + Display display = owningFeatureTableControl.getControl().getDisplay(); + display.asyncExec(new Runnable(){ + @Override + public void run() { + owningFeatureTableControl.notifyLoadingListeners(new LoadingEvent(false, monitor, true)); + monitor=progressMonitorProvider.get(); + monitor.setCanceled(false); + monitor.beginTask(Messages.FeatureTableContentProvider_updateTaskName, IProgressMonitor.UNKNOWN); + } + }); + } + } + + /** + * Checks the lookup table and the feature list to ensure that they have the same number of features and the same features. + * An exception will be thrown otherwise. + */ + public void assertInternallyConsistent(){ + if( features.size()!=lookup.size()) + throw new AssertionError("lookup table has "+lookup.size()+" features while feature list has "+features.size()+" features"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + for( SimpleFeature feature : features ) { + SimpleFeature lookupFeature = lookup.get(feature.getID()); + if( lookup==null ){ + throw new AssertionError("Lookup table is missing "+feature); //$NON-NLS-1$ + } + if( lookupFeature!=feature ) + throw new AssertionError("Lookup table contains: "+lookupFeature+" while feature list contains"+feature+". They are" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + " not the same instance"); //$NON-NLS-1$ + } + } + /** + * Removes the selected features (the features selected by the owning {@link FeatureTableControl}). + * @return returns a collection of the deleted features + */ + public FeatureCollection deleteSelection() { + final DefaultFeatureCollection deletedFeatures = new DefaultFeatureCollection(); + Runnable updateTable = new Runnable(){ + @Override + public void run() { + Collection selectionFids = owningFeatureTableControl.getSelectionProvider().getSelectionFids(); + + for( Iterator iter = features.iterator(); iter.hasNext(); ) { + SimpleFeature feature = iter.next(); + if( selectionFids.contains(feature.getID()) ){ + deletedFeatures.add(feature); + iter.remove(); + lookup.remove(feature.getID()); + } + } + + selectionFids.clear(); + owningFeatureTableControl.getViewer().getTable().clearAll(); + } + }; + + if( Display.getCurrent()==null ){ + PlatformGIS.syncInDisplayThread(owningFeatureTableControl.getControl().getDisplay(), updateTable); + }else{ + updateTable.run(); + } + + return deletedFeatures; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableControl.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableControl.java index c05a34a261..a9040594df 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableControl.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableControl.java @@ -1,1167 +1,1173 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.dialogs.MessageDialogWithToggle; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.IBaseLabelProvider; -import org.eclipse.jface.viewers.ICellEditorListener; -import org.eclipse.jface.viewers.ICellEditorValidator; -import org.eclipse.jface.viewers.ICellModifier; -import org.eclipse.jface.viewers.IContentProvider; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableLayout; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.part.PageBook; -import org.geotools.feature.FeatureCollection; -import org.geotools.filter.text.cql2.CQL; -import org.geotools.filter.text.cql2.CQLException; -import org.locationtech.udig.core.IProvider; -import org.locationtech.udig.internal.ui.Trace; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; -import org.opengis.feature.type.AttributeDescriptor; -import org.opengis.filter.Filter; -import org.opengis.filter.Id; -import org.opengis.filter.identity.FeatureId; - -import org.locationtech.jts.geom.Geometry; - -/** - * A TreeViewer control for viewing a table of SimpleFeature attributes. - *

    - * The object is used by using a FeatureCollection. In this case the control hangs on to a reference - * to the FeatureCollection and populates the table entries directory from it. This method results - * in a single page containing all features. - *

    - *

    - * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to - * {@link ICellModifier} then the table is editable. The {@link ICellModifier} is used to modify the - * features. The Column properties passed to the {@link ICellModifier} are the attribute name of the - * attribute being modified. - *

    - *

    - * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to - * {@link CellEditor[]} then the cell editors will be used to edit the cells. This is optional for - * editing. By default a {@link TextCellEditor} is used for editing most cells, and an - * {@link AttributeValidator} is used to validate the new values. The first column is for the fid - * column and will not be used since FIDS are assigned by the datastore and can not be modified. The - * number of Items the array (this is the same for the cell editor validators and cell editor - * listeners) must be either the number of attributes in the feature type or the number of - * attributes + 1 (one for the FID column). If the number of editors it Attributes+1 then the first - * element in the array will not be used as it is assumed to be a placeholder for the fid column. - *

    - *

    - * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to - * {@link ICellEditorValidator[]} then the validators will be used to validate the cells. - *

    - *

    - * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to - * {@link ICellEditorListener[]} then the listeners will be added to the {@link CellEditor}s. - *

    - * - * @author jdeolive - * @author jeichar - * @since 0.3 - */ -public class FeatureTableControl implements ISelectionProvider { - - public static final String FEATURE_ID_COLUMN_PROPERTY = "FeatureIDProperty"; //$NON-NLS-1$ - - public static final Object ERROR_COLUMN_PROPERTY = "ErrorProperty"; //$NON-NLS-1$ - - public static final Object LOADING = new Object(); - - /** results per page * */ - private int pageSize = 10; // XXX: actual put this as a user pref - - /** table viewer control * */ - private TableViewer tableViewer; - - private PageBook book; - - private Text message; - - FeatureCollection features; - - private final IProvider progressMonitorProvider; - - private FeatureTableSelectionProvider selectionProvider; - - private Color messageBackground; - - private Color messageForeground; - - private Set loadingListeners = new CopyOnWriteArraySet(); - - private Comparator currentComparator; - - private MenuManager contextMenu; - - private IProvider selectionColor; - - private boolean shown; - - /** - * Construct FeatureTableControl. - *

    - * Must call setFeatures before use. - *

    - */ - public FeatureTableControl() { - this(ProgressManager.instance()); - } - - /** - * Construct a FeatureTableControl. - * - * @param monitorProvider a provider that will provider progress monitors for displaying loading - * information. - * @param fReader The FeatureReader that returns the actual features. - * @param resPerPage Results per page to be shown in the table. - */ - public FeatureTableControl( Composite parent, - FeatureCollection features ) { - this(ProgressManager.instance(), parent, features); - } - /** - * Construct FeatureTableControl. - *

    - * Must call setFeatures before use. - *

    - * - * @param monitorProvider a provider that will provider progress monitors for displaying loading - * information. - */ - public FeatureTableControl( final IProvider monitorProvider ) { - this.progressMonitorProvider = monitorProvider; - this.selectionProvider = new FeatureTableSelectionProvider(this, ProgressManager.instance()); - } - - /** - * Construct a FeatureTableControl. - * - * @param monitorProvider a provider that will provider progress monitors for displaying loading - * information. - * @param fReader The FeatureReader that returns the actual features. - * @param resPerPage Results per page to be shown in the table. - */ - public FeatureTableControl( final IProvider monitorProvider, - Composite parent, FeatureCollection features ) { - this(monitorProvider); - this.features = features; - createTableControl(parent); - } - - /** - * Sets the number of features viewed in the table per page. - * - * @param resPerPage positive integer. - */ - public void setPageSize( int resPerPage ) { - this.pageSize = resPerPage; - } - - /** - * Returns the number of features viewed in the table per page. - * - * @return positive integer. - */ - public int getPageSize() { - return pageSize; - } - - /** - * Returns the control representing the table control. - * - * @return The internal table viewer control. - */ - public Control getControl() { - return book; - } - - public void dispose() { - disposeTableViewer(); - } - - /** - * Creates the table control. - * - * @param parent The to be parent of the control. - */ - public void createTableControl( Composite parent ) { - book = new PageBook(parent, SWT.NONE); - message = new Text(book, SWT.WRAP); - messageBackground = message.getBackground(); - messageForeground = message.getForeground(); - createTableViewer(book); - } - - /** - * Key for indicating whether the warning should be displayed. false if the warning is displayed - */ - public static final String CACHING_WARNING = "FEATURE_TABLE_CACHING_IN_MEMORY_WARNING"; //$NON-NLS-1$ - - /** - * Indicates that all attribute types will be searched by the select method - * - * @see #select(String, String[], boolean) - */ - public static final String[] ALL = new String[0]; - - private static final boolean SHOW_PATH = false; - - /** - * show the warning about loading features into memory. - * - * @returns true if the user wishes to continue to load features; false otherwise. - */ - public boolean showWarning( Display display ) { - - IPreferenceStore preferenceStore = UiPlugin.getDefault().getPreferenceStore(); - if (!preferenceStore.getBoolean(CACHING_WARNING) && !shown) { - shown = true; - - MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm(display - .getActiveShell(), Messages.FeatureTableControl_warningTitle, - Messages.FeatureTableControl_warningMessage, - Messages.FeatureTableControl_warningToggle, false, null, null); - // MessageDialogWithToggle dialog = MessageDialogWithToggle.openWarning(display - // .getActiveShell(), Messages.FeatureTableControl_warningTitle, - // Messages.FeatureTableControl_warningMessage, - // Messages.FeatureTableControl_warningToggle, false, null, null); - preferenceStore.setValue(CACHING_WARNING, dialog.getToggleState()); - if (dialog.getReturnCode() == MessageDialogWithToggle.OK) { - return true; - } else { - return false; - } - - } - return true; - - } - - /** - * Updates the table control with the current set of features. - *

    - * This method will ensure that the column information gets updated - *

    - */ - public void update() { - checkWidget(); - if (tableViewer != null) { - tableViewer.setInput(features); - tableViewer.getTable().clearAll(); - } - } - - /** - * Creates the table control itself. - * - * @param parent - */ - protected void createTableViewer( Composite parent ) { - int style = SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.H_SCROLL | SWT.V_SCROLL; - if (tableViewer != null) { - disposeTableViewer(); - } - final Table table = new Table(parent, style); - table.setLinesVisible(true); - TableLayout layout = new TableLayout(); - table.setLayout(layout); - - FeatureTableContentProvider ftp = new FeatureTableContentProvider(this, - this.progressMonitorProvider); - FeatureTableLabelProvider flp = new FeatureTableLabelProvider(this); - flp.setSelectionColor(selectionColor); - tableViewer = new TableViewer(table); - - tableViewer.setContentProvider(ftp); - tableViewer.setLabelProvider(flp); - - // create columns after tableViewer is created because Column listeners need to access the - // tableViewer. - createAttributeColumns(table, tableViewer, layout); - table.setHeaderVisible(true); - - addSelectionListener(table); - if (features instanceof IAdaptable - && ((IAdaptable) features).getAdapter(ICellModifier.class) != null) { - - IAdaptable adaptable = (IAdaptable) features; - SimpleFeatureType schema = features.getSchema(); - int attributeCount = schema.getAttributeCount(); - setCellEditors(adaptable, attributeCount); - - setCellValidators(adaptable); - addCellEditorListeners(adaptable); - tableViewer.setCellModifier((ICellModifier) adaptable.getAdapter(ICellModifier.class)); - - String[] properties = new String[attributeCount + 1]; - for( int i = 0; i < properties.length; i++ ) { - if (i == 0) - properties[i] = FEATURE_ID_COLUMN_PROPERTY; - else { - properties[i] = schema.getDescriptor(i - 1).getName().getLocalPart(); - } - } - tableViewer.setColumnProperties(properties); - } - if (contextMenu != null) { - Menu menu = contextMenu.createContextMenu(tableViewer.getControl()); - tableViewer.getControl().setMenu(menu); - } - book.showPage(tableViewer.getControl()); - - UiPlugin.trace(Trace.FEATURE_TABLE, getClass(), - "createTableViewer(): showing table View", SHOW_PATH ? new Exception() : null); //$NON-NLS-1$ - - if (features != null) { - tableViewer.setInput(features); - } - - } - - private void addSelectionListener( final Table table ) { - // We are not using default selection provided by the table because it is too slow - // so I am doing my own listening and based on which items are selected and what - // keys are down I am simulating the selection behaviour. - table.addListener(SWT.MouseDown, new Listener(){ - - int lastIndex = -1; - - public void handleEvent( Event e ) { - - if (e.button != 1) { - return; - } - - int index = table.getSelectionIndex(); - FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer - .getContentProvider(); - Collection selectionFids = selectionProvider.getSelectionFids(); - - table.deselect(index); - if ((e.stateMask & SWT.MOD2) != 0 && lastIndex != -1) { - if (lastIndex == index) - return; - handleSelecteRange(table, index, provider, selectionFids); - } else if ((e.stateMask & SWT.MOD1) != 0) { - handleXORSelect(table, index, provider, selectionFids); - } else { - if (lastIndex == index) - return; - handleDefault(table, index, provider, selectionFids); - } - - selectionProvider.notifyListeners(); - } - - private void handleDefault( final Table table, int index, - FeatureTableContentProvider provider, Collection selectionFids ) { - if (index == -1) { - selectionFids.clear(); - table.clearAll(); - } else { - String fid = provider.features.get(index).getID(); - selectionFids.clear(); - selectionFids.add(fid); - table.clearAll(); - } - lastIndex = index; - } - - private void handleXORSelect( final Table table, int index, - FeatureTableContentProvider provider, Collection selectionFids ) { - String fid = provider.features.get(index).getID(); - if (selectionFids.contains(fid)) { - selectionFids.remove(fid); - } else { - selectionFids.add(fid); - } - table.clear(index); - lastIndex = index; - } - - private void handleSelecteRange( final Table table, int index, - FeatureTableContentProvider provider, Collection selectionFids ) { - selectionFids.clear(); - - int low = Math.min(lastIndex, index); - int high = Math.max(lastIndex, index); - if (low == -1 || high == -1) { - table.clearAll(); - return; - } - List toAdd = provider.features.subList(low, high + 1); - boolean foundUnselectedItem = false; - int i = low; - for( SimpleFeature feature : toAdd ) { - if (selectionFids.add(feature.getID())) { - foundUnselectedItem = true; - } - i++; - } - if (foundUnselectedItem) { - table.clearAll(); - } - } - - }); - } - - private void disposeTableViewer() { - if (tableViewer == null) - return; - IContentProvider contentProvider = tableViewer.getContentProvider(); - if (contentProvider != null) - contentProvider.dispose(); - IBaseLabelProvider labelProvider = tableViewer.getLabelProvider(); - if (labelProvider != null) - labelProvider.dispose(); - Control control = tableViewer.getControl(); - if (control != null) - control.dispose(); - tableViewer = null; - } - - private void setCellEditors( IAdaptable adaptable, int attributeCount ) { - if (adaptable.getAdapter(CellEditor[].class) != null) { - CellEditor[] editors = (CellEditor[]) adaptable.getAdapter(CellEditor[].class); - if (editors.length < attributeCount) { - UiPlugin.log( - "not enough cell editors for feature type so not used", new Exception()); //$NON-NLS-1$ - createCellEditors(); - } else { - CellEditor[] copy = new CellEditor[editors.length + 1]; - if (editors.length == attributeCount) { - // there is an editor for each attribute. First element in copy if for the - // fid column (which is not editable). - System.arraycopy(editors, 0, copy, 1, attributeCount); - } else { - - // ignore 1st element in editors because it is for the FID column which is read - // only. - System.arraycopy(editors, 1, copy, 1, attributeCount); - - } - tableViewer.setCellEditors(copy); - } - } else { - createCellEditors(); - } - } - - private void addCellEditorListeners( IAdaptable adaptable ) { - CellEditor[] editors = tableViewer.getCellEditors(); - // offset is usually 1 but if the number of validators==number of attributes then the offset - // is 0 - // because the first column is the FID column which doesn't have a listener. - int offset = 1; - - ICellEditorListener[] listener = null; - if (adaptable.getAdapter(ICellEditorListener[].class) != null) { - listener = (ICellEditorListener[]) adaptable.getAdapter(ICellEditorListener[].class); - int attributeCount = features.getSchema().getAttributeCount(); - if (listener.length < attributeCount) { - UiPlugin.log( - "not enough cell editors for feature type so not used", new Exception()); //$NON-NLS-1$ - return; - } else if (listener.length == attributeCount + 1) { - offset = 0; - } - } - - for( int i = 0; i < editors.length - offset; i++ ) { - final CellEditor editor = editors[i + offset]; - if (editor == null) - continue; - if (listener != null && listener[i] != null) - editor.addListener(listener[i]); - editor.addListener(new DisplayErrorCellListener(editor)); - } - } - - private void setCellValidators( IAdaptable adaptable ) { - CellEditor[] editors = tableViewer.getCellEditors(); - SimpleFeatureType schema = features.getSchema(); - // offset is usually 1 but if the number of validators==number of attributes then the offset - // is 0 - // because the first column is the FID column which doesn't have a listener. - int offset = 1; - - ICellEditorValidator[] validators = null; - if (adaptable.getAdapter(ICellEditorValidator[].class) != null) { - validators = (ICellEditorValidator[]) adaptable - .getAdapter(ICellEditorValidator[].class); - int attributeCount = features.getSchema().getAttributeCount(); - if (validators.length < attributeCount) { - UiPlugin.log( - "not enough cell editors for feature type so not used", new Exception()); //$NON-NLS-1$ - validators = null; - } else if (validators.length == attributeCount) { - offset = 0; - } - } - - for( int i = 0; i < editors.length - offset; i++ ) { - CellEditor editor = editors[i + offset]; - if (editor == null) - continue; - if (validators != null && validators[i] != null) - editor.setValidator(validators[i]); - else - editor.setValidator(new AttributeValidator(schema.getDescriptor(i), schema)); - } - } - - @SuppressWarnings("unchecked") - private void createCellEditors() { - SimpleFeatureType schema = features.getSchema(); - org.eclipse.jface.viewers.CellEditor[] editors = new org.eclipse.jface.viewers.CellEditor[schema - .getAttributeCount() + 1]; - - for( int i = 0; i < schema.getAttributeCount(); i++ ) { - AttributeDescriptor aType = schema.getDescriptor(i); - Class< ? extends Object> concreteType = aType.getType().getBinding(); - Composite control = (Composite) tableViewer.getControl(); - if (concreteType.isAssignableFrom(String.class)) { - BasicTypeCellEditor textCellEditor = new BasicTypeCellEditor(control, String.class); - editors[i + 1] = textCellEditor; - } else if (concreteType.isAssignableFrom(Integer.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, Integer.class); - editors[i + 1] = textCellEditor; - } else if (concreteType.isAssignableFrom(Double.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, Double.class); - editors[i + 1] = textCellEditor; - } else if (concreteType.isAssignableFrom(Float.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, Float.class); - editors[i + 1] = textCellEditor; - } else if (concreteType.isAssignableFrom(BigDecimal.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, BigDecimal.class); - editors[i + 1] = textCellEditor; - } else if (concreteType.isAssignableFrom(BigInteger.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, BigInteger.class); - editors[i + 1] = textCellEditor; - - } else if (concreteType.isAssignableFrom(Boolean.class)) { - BooleanCellEditor textCellEditor = new BooleanCellEditor(control); - editors[i + 1] = textCellEditor; - - } else if (concreteType.isAssignableFrom(Character.class)) { - BasicTypeCellEditor textCellEditor = new BasicTypeCellEditor(control, - Character.class); - editors[i + 1] = textCellEditor; - - } else if (Date.class.isAssignableFrom(concreteType)) { - DateTimeCellEditor textCellEditor = new DateTimeCellEditor(control); - editors[i + 1] = textCellEditor; - } - // else if( concreteType.isAssignableFrom(Date.class)){ - // WarningCellEditor textCellEditor = new WarningCellEditor(control, "The Date type does - // not yet have a editor, please make a bug report for this Attribute Type"); - // editors[i+1]=textCellEditor; - // - // } - else if (concreteType.isAssignableFrom(Byte.class)) { - BasicTypeCellEditor textCellEditor = new BasicTypeCellEditor(control, Byte.class); - editors[i + 1] = textCellEditor; - - } else if (concreteType.isAssignableFrom(Short.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, Short.class); - editors[i + 1] = textCellEditor; - - } else if (concreteType.isAssignableFrom(Long.class)) { - NumberCellEditor textCellEditor = new NumberCellEditor(control, Long.class); - editors[i + 1] = textCellEditor; - - } else { - WarningCellEditor textCellEditor = new WarningCellEditor(control, - Messages.FeatureTableControl_noEditor1 + concreteType.getSimpleName() - + Messages.FeatureTableControl_noEditor2); - editors[i + 1] = textCellEditor; - } - } - tableViewer.setCellEditors(editors); - } - - private void createAttributeColumns( final Table table, TableViewer viewer, TableLayout layout ) { - - if (features == null) { - TableColumn column = new TableColumn(table, SWT.CENTER | SWT.BORDER); - column.setText(Messages.FeatureTableControl_1); - layout.addColumnData(new ColumnWeightData(1)); - } else { - - SimpleFeatureType schema = features.getSchema(); - - TableColumn column = new TableColumn(table, SWT.CENTER | SWT.BORDER); - column.setText("FID"); //$NON-NLS-1$ - layout.addColumnData(new ColumnWeightData(1, 150, true)); - column.setMoveable(true); - - column.addListener(SWT.Selection, new AttributeColumnSortListener(this, - FEATURE_ID_COLUMN_PROPERTY)); - - for( int i = 0; i < schema.getAttributeCount(); i++ ) { - AttributeDescriptor aType = schema.getDescriptor(i); - column = new TableColumn(table, SWT.CENTER | SWT.BORDER); - if (Geometry.class.isAssignableFrom(aType.getType().getBinding())) { // was - // aType.isGeometry() - // jg: wot is this maddness? jd: paul said so - column.setText("GEOMETRY"); //$NON-NLS-1$ - } else - column.setText(aType.getName().getLocalPart()); - - layout.addColumnData(new ColumnWeightData(1, 100, true)); - column.setMoveable(true); - - column.addListener(SWT.Selection, new AttributeColumnSortListener(this, aType - .getName().getLocalPart())); - } - - } - } - - /** - * Does nothing. - * - * @see org.eclipse.ui.IWorkbenchPart#setFocus() - */ - public void setFocus() { - // do nothing. - } - - /** - * Contents of the current page of features - * - * @return - */ - public FeatureCollection getFeatures() { - return features; - } - - /** Set up for a single page of content */ - public void setFeatures( FeatureCollection features ) { - checkWidget(); - if (this.features != null && this.features == features) - return; - - this.features = features; - - createTableViewer(book); - } - - private void checkWidget() { - if (Display.getCurrent() == null) - SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS); - } - - /** - * Don't display nothing :-) - */ - public void clear() { - features = null; - selectionProvider.getSelectionFids().clear(); - update(); - } - - /** - * Displays a message. If text == null or "" then the message is hidden and tableViewer is shown - * again. - * - * @param text message to display - * @param background color of the background of the text widget. If null the default color is - * used - * @param foreground color of the foreground of the text widget. If null the default color is - * used - */ - public void message( String text, Color background, Color foreground ) { - checkWidget(); - Color background2 = background; - Color foreground2 = foreground; - if (background2 == null) { - background2 = messageBackground; - } - if (foreground2 == null) { - foreground2 = messageForeground; - } - message.setBackground(background2); - message.setForeground(foreground2); - if (text == null || text.trim().length() == 0) { - message.setText(""); //$NON-NLS-1$ - if (tableViewer != null) { - book.showPage(tableViewer.getControl()); - UiPlugin - .trace( - Trace.FEATURE_TABLE, - getClass(), - "message(String,Color,Color): showing table View", SHOW_PATH ? new Exception() : null); //$NON-NLS-1$ - } - } else { - message.setText(text); - book.showPage(message); - UiPlugin - .trace( - Trace.FEATURE_TABLE, - getClass(), - "message(String,Color,Color): showing message", SHOW_PATH ? new Exception() : null); //$NON-NLS-1$ - } - } - - /** - * Displays a message. If text == null or "" then the message is hidden and tableViewer is shown - * again. - * - * @param text message to display - */ - public void message( String text ) { - message(text, null, null); - } - - /** - * Returns a selection with a single Id indicating the features selected - */ - public ISelection getSelection() { - checkWidget(); - return selectionProvider.getSelection(); - } - - public void addSelectionChangedListener( ISelectionChangedListener listener ) { - selectionProvider.addSelectionChangedListener(listener); - } - public void removeSelectionChangedListener( ISelectionChangedListener listener ) { - selectionProvider.removeSelectionChangedListener(listener); - } - - /** - * Useable selections are: selection of features, FIDS and Filters/Queries that adapt to a - * FeatureSource - */ - public void setSelection( final ISelection newSelection ) { - checkWidget(); - selectionProvider.setSelection(newSelection); - } - - /** - * Sorts the table so that the selection is at the top of the table. It does not last. The next - * selection will not be at the top. - */ - public void promoteSelection() { - checkWidget(); - tableViewer.cancelEditing(); - - Table table = tableViewer.getTable(); - table.setSortColumn(null); - - Id filter = selectionProvider.getId(); - - sort(new SelectionComparator(filter, SWT.UP, new FIDComparator(SWT.UP)), SWT.UP, null); - table.setTopIndex(0); - } - - /** - * Sorts the features in the tableView. - * - * @param comparator comparator to use for the sorting. - * @param dir the direction to set the column SWT.UP or SWT.DOWN. If SWT.UP then the table item - * with index 0 is at the top of the table otherwise it is at the bottom of the table. - * @param sortColumn the column that is being sorted - */ - public void sort( Comparator comparator, int dir, TableColumn sortColumn ) { - checkWidget(); - - FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer - .getContentProvider(); - - boolean sorted = false; - if (!comparator.equals(currentComparator)) { - sorted = true; - currentComparator = comparator; - Collections.sort(provider.features, currentComparator); - } - Table table = tableViewer.getTable(); - if (table.getSortColumn() != sortColumn) { - sorted = true; - table.setSortColumn(sortColumn); - while( Display.getCurrent().readAndDispatch() ); - } - if (table.getSortColumn() != null && dir != table.getSortDirection()) { - sorted = true; - table.setSortDirection(dir); - while( Display.getCurrent().readAndDispatch() ); - } - if (sorted) { - table.deselectAll(); - table.clearAll(); - } - - } - - /** - * Resorts the table using the last comparator. This is useful for cases where features have - * been added to the table - * - * @param refreshTable - */ - void sort( boolean refreshTable ) { - if (currentComparator == null) - return; - - FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer - .getContentProvider(); - - Collections.sort(provider.features, currentComparator); - - tableViewer.getTable().deselectAll(); - if (refreshTable) - tableViewer.getTable().clearAll(); - } - - public TableViewer getViewer() { - return tableViewer; - } - - FeatureTableSelectionProvider getSelectionProvider() { - return selectionProvider; - } - - public void setSelection( StructuredSelection selection, boolean reveal ) { - selectionProvider.setSelection(selection, reveal); - } - - public int getSelectionCount() { - return selectionProvider.getSelectionFids().size(); - } - - public void select( Set selection ) { - getSelectionProvider().getSelectionFids().clear(); - int j = 0; - int firstMatch = -1; - for( FeatureId id : selection ) { - selectionProvider.getSelectionFids().add(id.getID()); - if (firstMatch == -1) { - firstMatch = j; - } - j++; - } - Table table = tableViewer.getTable(); - if (firstMatch != -1) { - // display the selected item - table.setTopIndex(firstMatch); - } - // trigger a refresh of table - table.clearAll(); - // tell the world.. - selectionProvider.notifyListeners(); - } - public void select( String cql, boolean selectAll ) throws CQLException { - Filter filter = (Filter) CQL.toFilter(cql); - - FeatureTableContentProvider provider = (FeatureTableContentProvider) this.tableViewer - .getContentProvider(); - List toSearch = provider.features; - - IProgressMonitor progressMonitor = getSelectionProvider().progressMonitor; - if (progressMonitor != null) { - progressMonitor.setCanceled(true); - } - getSelectionProvider().getSelectionFids().clear(); - int j = 0; - int firstMatch = -1; - OUTER: for( SimpleFeature feature : toSearch ) { - if (filter.evaluate(feature)) { - selectionProvider.getSelectionFids().add(feature.getID()); - if (firstMatch == -1) - firstMatch = j; - if (!selectAll) - break OUTER; - } - j++; - } - - Table table = tableViewer.getTable(); - if (firstMatch != -1) { - // display the selected item - table.setTopIndex(firstMatch); - } - // trigger a refresh of table - table.clearAll(); - // tell the world.. - selectionProvider.notifyListeners(); - } - - /** - * select the features found that has the text. Only the attributes indicated are searched. If - * {@link #ALL} is selected then all attributes will be searched - * - * @param text text to search for it will first be assumed that it is a reg ex expression - * @param attributes the attributes to search. See {@link #ALL} - * @param selectAll if true all matched features will be selected otherwise just the first - * feature - */ - public void select( String text, String[] attributes, boolean selectAll ) - throws PatternSyntaxException { - - Pattern pattern = compilePattern(text); - - if (pattern == null) { - return; - } - - FeatureTableContentProvider provider = (FeatureTableContentProvider) this.tableViewer - .getContentProvider(); - List toSearch = provider.features; - - IProgressMonitor progressMonitor = getSelectionProvider().progressMonitor; - if (progressMonitor != null) { - progressMonitor.setCanceled(true); - } - getSelectionProvider().getSelectionFids().clear(); - int j = 0; - int firstMatch = -1; - OUTER: for( SimpleFeature feature : toSearch ) { - if (searchFeature(feature, pattern, attributes)) { - if (firstMatch == -1) - firstMatch = j; - if (!selectAll) - break OUTER; - } - j++; - } - - Table table = tableViewer.getTable(); - if (firstMatch != -1) { - // display the selected item - table.setTopIndex(firstMatch); - } - // trigger a refresh of table - table.clearAll(); - // tell the world.. - selectionProvider.notifyListeners(); - } - - private Pattern compilePattern( final String text ) { - - String[] parts = text.split("\\|"); - - StringBuilder builder = new StringBuilder(); - - for( String string : parts ) { - String pre = ".*"; - String post = ".*"; - if (string.startsWith("^") || string.startsWith(".") || string.startsWith("\\A")) { - pre = ""; - } - if (string.startsWith("&") || string.startsWith("\\Z") || string.startsWith("\\z")) { - post = ""; - } - builder.append(pre); - builder.append(string); - builder.append(post); - builder.append('|'); - } - if (builder.length() > 0) { - builder.deleteCharAt(builder.length() - 1); - } - Pattern pattern; - try { - pattern = Pattern.compile(builder.toString(), Pattern.CASE_INSENSITIVE); - } catch (IllegalArgumentException e) { - try { - pattern = Pattern.compile(".*" + convertToLiteral(text) + ".*"); //$NON-NLS-1$//$NON-NLS-2$ - } catch (IllegalArgumentException e2) { - return null; - } - } - return pattern; - } - - private boolean searchFeature( SimpleFeature feature, Pattern pattern, String[] attributes ) { - SimpleFeatureType featureType = feature.getFeatureType(); - if (attributes == ALL) { - for( int i = 0; i < featureType.getAttributeCount(); i++ ) { - if (matches(pattern, feature.getAttribute(i))) { - selectionProvider.getSelectionFids().add(feature.getID()); - return true; - } - } - } - for( int i = 0; i < attributes.length; i++ ) { - if (matches(pattern, feature.getAttribute(attributes[i]))) { - getSelectionProvider().getSelectionFids().add(feature.getID()); - return true; - - } - } - return false; - } - - private String convertToLiteral( String text ) { - String text2 = text.replace("\\", "\\\\"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("*", "\\*"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("+", "\\+"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("?", "\\?"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("[", "\\["); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("]", "\\]"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("^", "\\^"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("-", "\\-"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("&", "\\&"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("(", "\\("); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace(")", "\\)"); //$NON-NLS-1$ //$NON-NLS-2$ - text2 = text2.replace("|", "\\|"); //$NON-NLS-1$ //$NON-NLS-2$ - return text2; - } - - private boolean matches( Pattern pattern, Object attribute ) { - if (attribute == null) { - attribute = ""; - } - String stringValue = attribute.toString(); - return pattern.matcher(stringValue).matches(); - } - - public void addLoadingListener( IFeatureTableLoadingListener listener ) { - loadingListeners.add(listener); - } - - public void remove( IFeatureTableLoadingListener listener ) { - loadingListeners.remove(listener); - } - - protected void notifyLoadingListeners( LoadingEvent event ) { - this.checkWidget(); - if (event.loading) { - if (event.monitor == null) - throw new NullPointerException(); - for( IFeatureTableLoadingListener listener : loadingListeners ) { - try { - listener.loadingStarted(event.monitor); - } catch (Throwable e) { - UiPlugin.log(listener + " threw an exception", e); //$NON-NLS-1$ - } - } - } else { - for( IFeatureTableLoadingListener listener : loadingListeners ) { - try { - listener.loadingStopped(event.canceled); - } catch (Throwable e) { - UiPlugin.log(listener + " threw an exception", e); //$NON-NLS-1$ - } - } - } - } - - /** - * Updates the features that have the same feature ID to match the new feature or adds the - * features if they are not part of the current collection. - * - * @param features2 the feature collection that contains the modified or new features. - */ - public void update( FeatureCollection features2 ) { - if (features == null) - return; // nothing to update since the table is not in use... Should this be an - // exception? - FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer - .getContentProvider(); - provider.update(features2); - } - - /** - * Checks all the lists, caches, content providers, etc... are consistent with each other. This - * is an expensive method so should be called with care. A test is a good example. - */ - public void assertInternallyConsistent() { - if (tableViewer.getContentProvider() != null) { - FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer - .getContentProvider(); - provider.assertInternallyConsistent(); - } - } - - /** - * Removes the selected features (the features selected by the owning - * {@link FeatureTableControl}). - * - * @return returns a collection of the deleted features - * @see #setSelection(ISelection) - * @see #setSelection(StructuredSelection, boolean) - */ - public FeatureCollection deleteSelection() { - FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer - .getContentProvider(); - return provider.deleteSelection(); - } - - /** - * Sets the context Menu used by the table view. Not menu is used for the message box. - * - * @param contextMenu menu manager used for creating the menu. - */ - public void setMenuManager( MenuManager contextMenu ) { - checkWidget(); - this.contextMenu = contextMenu; - if (tableViewer != null && tableViewer.getControl() != null) { - Menu oldMenu = tableViewer.getControl().getMenu(); - if (oldMenu != null) - oldMenu.dispose(); - Menu menu = contextMenu.createContextMenu(tableViewer.getControl()); - tableViewer.getControl().setMenu(menu); - } - } - - public void setSelectionColor( IProvider selectionColor ) { - this.selectionColor = selectionColor; - if (tableViewer != null) { - FeatureTableLabelProvider labelProvider = (FeatureTableLabelProvider) tableViewer - .getLabelProvider(); - labelProvider.setSelectionColor(selectionColor); - } - } - -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.dialogs.MessageDialogWithToggle; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.ICellEditorListener; +import org.eclipse.jface.viewers.ICellEditorValidator; +import org.eclipse.jface.viewers.ICellModifier; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.part.PageBook; +import org.geotools.feature.FeatureCollection; +import org.geotools.filter.text.cql2.CQL; +import org.geotools.filter.text.cql2.CQLException; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.udig.core.IProvider; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.Trace; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.AttributeDescriptor; +import org.opengis.filter.Filter; +import org.opengis.filter.Id; +import org.opengis.filter.identity.FeatureId; + +/** + * A TreeViewer control for viewing a table of SimpleFeature attributes. + *

    + * The object is used by using a FeatureCollection. In this case the control hangs on to a reference + * to the FeatureCollection and populates the table entries directory from it. This method results + * in a single page containing all features. + *

    + *

    + * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to + * {@link ICellModifier} then the table is editable. The {@link ICellModifier} is used to modify the + * features. The Column properties passed to the {@link ICellModifier} are the attribute name of the + * attribute being modified. + *

    + *

    + * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to + * {@link CellEditor[]} then the cell editors will be used to edit the cells. This is optional for + * editing. By default a {@link TextCellEditor} is used for editing most cells, and an + * {@link AttributeValidator} is used to validate the new values. The first column is for the fid + * column and will not be used since FIDS are assigned by the datastore and can not be modified. The + * number of Items the array (this is the same for the cell editor validators and cell editor + * listeners) must be either the number of attributes in the feature type or the number of + * attributes + 1 (one for the FID column). If the number of editors it Attributes+1 then the first + * element in the array will not be used as it is assumed to be a placeholder for the fid column. + *

    + *

    + * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to + * {@link ICellEditorValidator[]} then the validators will be used to validate the cells. + *

    + *

    + * If the FeatureCollection implements the {@link IAdaptable} interface and adapts to + * {@link ICellEditorListener[]} then the listeners will be added to the {@link CellEditor}s. + *

    + * + * @author jdeolive + * @author jeichar + * @since 0.3 + */ +public class FeatureTableControl implements ISelectionProvider { + + public static final String FEATURE_ID_COLUMN_PROPERTY = "FeatureIDProperty"; //$NON-NLS-1$ + + public static final Object ERROR_COLUMN_PROPERTY = "ErrorProperty"; //$NON-NLS-1$ + + public static final Object LOADING = new Object(); + + /** results per page * */ + private int pageSize = 10; // XXX: actual put this as a user pref + + /** table viewer control * */ + private TableViewer tableViewer; + + private PageBook book; + + private Text message; + + FeatureCollection features; + + private final IProvider progressMonitorProvider; + + private FeatureTableSelectionProvider selectionProvider; + + private Color messageBackground; + + private Color messageForeground; + + private Set loadingListeners = new CopyOnWriteArraySet<>(); + + private Comparator currentComparator; + + private MenuManager contextMenu; + + private IProvider selectionColor; + + private boolean shown; + + /** + * Construct FeatureTableControl. + *

    + * Must call setFeatures before use. + *

    + */ + public FeatureTableControl() { + this(ProgressManager.instance()); + } + + /** + * Construct a FeatureTableControl. + * + * @param monitorProvider a provider that will provider progress monitors for displaying loading + * information. + * @param fReader The FeatureReader that returns the actual features. + * @param resPerPage Results per page to be shown in the table. + */ + public FeatureTableControl(Composite parent, + FeatureCollection features) { + this(ProgressManager.instance(), parent, features); + } + + /** + * Construct FeatureTableControl. + *

    + * Must call setFeatures before use. + *

    + * + * @param monitorProvider a provider that will provider progress monitors for displaying loading + * information. + */ + public FeatureTableControl(final IProvider monitorProvider) { + this.progressMonitorProvider = monitorProvider; + this.selectionProvider = new FeatureTableSelectionProvider(this, + ProgressManager.instance()); + } + + /** + * Construct a FeatureTableControl. + * + * @param monitorProvider a provider that will provider progress monitors for displaying loading + * information. + * @param fReader The FeatureReader that returns the actual features. + * @param resPerPage Results per page to be shown in the table. + */ + public FeatureTableControl(final IProvider monitorProvider, Composite parent, + FeatureCollection features) { + this(monitorProvider); + this.features = features; + createTableControl(parent); + } + + /** + * Sets the number of features viewed in the table per page. + * + * @param resPerPage positive integer. + */ + public void setPageSize(int resPerPage) { + this.pageSize = resPerPage; + } + + /** + * Returns the number of features viewed in the table per page. + * + * @return positive integer. + */ + public int getPageSize() { + return pageSize; + } + + /** + * Returns the control representing the table control. + * + * @return The internal table viewer control. + */ + public Control getControl() { + return book; + } + + public void dispose() { + disposeTableViewer(); + } + + /** + * Creates the table control. + * + * @param parent The to be parent of the control. + */ + public void createTableControl(Composite parent) { + book = new PageBook(parent, SWT.NONE); + message = new Text(book, SWT.WRAP); + messageBackground = message.getBackground(); + messageForeground = message.getForeground(); + createTableViewer(book); + } + + /** + * Key for indicating whether the warning should be displayed. false if the warning is displayed + */ + public static final String CACHING_WARNING = "FEATURE_TABLE_CACHING_IN_MEMORY_WARNING"; //$NON-NLS-1$ + + /** + * Indicates that all attribute types will be searched by the select method + * + * @see #select(String, String[], boolean) + */ + public static final String[] ALL = new String[0]; + + private static final boolean SHOW_PATH = false; + + /** + * show the warning about loading features into memory. + * + * @returns true if the user wishes to continue to load features; false otherwise. + */ + public boolean showWarning(Display display) { + + IPreferenceStore preferenceStore = UiPlugin.getDefault().getPreferenceStore(); + if (!preferenceStore.getBoolean(CACHING_WARNING) && !shown) { + shown = true; + + MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm( + display.getActiveShell(), Messages.FeatureTableControl_warningTitle, + Messages.FeatureTableControl_warningMessage, + Messages.FeatureTableControl_warningToggle, false, null, null); + // MessageDialogWithToggle dialog = MessageDialogWithToggle.openWarning(display + // .getActiveShell(), Messages.FeatureTableControl_warningTitle, + // Messages.FeatureTableControl_warningMessage, + // Messages.FeatureTableControl_warningToggle, false, null, null); + preferenceStore.setValue(CACHING_WARNING, dialog.getToggleState()); + if (dialog.getReturnCode() == MessageDialogWithToggle.OK) { + return true; + } else { + return false; + } + + } + return true; + + } + + /** + * Updates the table control with the current set of features. + *

    + * This method will ensure that the column information gets updated + *

    + */ + public void update() { + checkWidget(); + if (tableViewer != null) { + tableViewer.setInput(features); + tableViewer.getTable().clearAll(); + } + } + + /** + * Creates the table control itself. + * + * @param parent + */ + protected void createTableViewer(Composite parent) { + int style = SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.H_SCROLL | SWT.V_SCROLL; + if (tableViewer != null) { + disposeTableViewer(); + } + final Table table = new Table(parent, style); + table.setLinesVisible(true); + TableLayout layout = new TableLayout(); + table.setLayout(layout); + + FeatureTableContentProvider ftp = new FeatureTableContentProvider(this, + this.progressMonitorProvider); + FeatureTableLabelProvider flp = new FeatureTableLabelProvider(this); + flp.setSelectionColor(selectionColor); + tableViewer = new TableViewer(table); + + tableViewer.setContentProvider(ftp); + tableViewer.setLabelProvider(flp); + + // create columns after tableViewer is created because Column listeners need to access the + // tableViewer. + createAttributeColumns(table, tableViewer, layout); + table.setHeaderVisible(true); + + addSelectionListener(table); + if (features instanceof IAdaptable + && ((IAdaptable) features).getAdapter(ICellModifier.class) != null) { + + IAdaptable adaptable = (IAdaptable) features; + SimpleFeatureType schema = features.getSchema(); + int attributeCount = schema.getAttributeCount(); + setCellEditors(adaptable, attributeCount); + + setCellValidators(adaptable); + addCellEditorListeners(adaptable); + tableViewer.setCellModifier(adaptable.getAdapter(ICellModifier.class)); + + String[] properties = new String[attributeCount + 1]; + for (int i = 0; i < properties.length; i++) { + if (i == 0) + properties[i] = FEATURE_ID_COLUMN_PROPERTY; + else { + properties[i] = schema.getDescriptor(i - 1).getName().getLocalPart(); + } + } + tableViewer.setColumnProperties(properties); + } + if (contextMenu != null) { + Menu menu = contextMenu.createContextMenu(tableViewer.getControl()); + tableViewer.getControl().setMenu(menu); + } + book.showPage(tableViewer.getControl()); + + UiPlugin.trace(Trace.FEATURE_TABLE, getClass(), "createTableViewer(): showing table View", //$NON-NLS-1$ + SHOW_PATH ? new Exception() : null); + + if (features != null) { + tableViewer.setInput(features); + } + + } + + private void addSelectionListener(final Table table) { + // We are not using default selection provided by the table because it is too slow + // so I am doing my own listening and based on which items are selected and what + // keys are down I am simulating the selection behaviour. + table.addListener(SWT.MouseDown, new Listener() { + + int lastIndex = -1; + + @Override + public void handleEvent(Event e) { + + if (e.button != 1) { + return; + } + + int index = table.getSelectionIndex(); + FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer + .getContentProvider(); + Collection selectionFids = selectionProvider.getSelectionFids(); + + table.deselect(index); + if ((e.stateMask & SWT.MOD2) != 0 && lastIndex != -1) { + if (lastIndex == index) + return; + handleSelecteRange(table, index, provider, selectionFids); + } else if ((e.stateMask & SWT.MOD1) != 0) { + handleXORSelect(table, index, provider, selectionFids); + } else { + if (lastIndex == index) + return; + handleDefault(table, index, provider, selectionFids); + } + + selectionProvider.notifyListeners(); + } + + private void handleDefault(final Table table, int index, + FeatureTableContentProvider provider, Collection selectionFids) { + if (index == -1) { + selectionFids.clear(); + table.clearAll(); + } else { + String fid = provider.features.get(index).getID(); + selectionFids.clear(); + selectionFids.add(fid); + table.clearAll(); + } + lastIndex = index; + } + + private void handleXORSelect(final Table table, int index, + FeatureTableContentProvider provider, Collection selectionFids) { + String fid = provider.features.get(index).getID(); + if (selectionFids.contains(fid)) { + selectionFids.remove(fid); + } else { + selectionFids.add(fid); + } + table.clear(index); + lastIndex = index; + } + + private void handleSelecteRange(final Table table, int index, + FeatureTableContentProvider provider, Collection selectionFids) { + selectionFids.clear(); + + int low = Math.min(lastIndex, index); + int high = Math.max(lastIndex, index); + if (low == -1 || high == -1) { + table.clearAll(); + return; + } + List toAdd = provider.features.subList(low, high + 1); + boolean foundUnselectedItem = false; + int i = low; + for (SimpleFeature feature : toAdd) { + if (selectionFids.add(feature.getID())) { + foundUnselectedItem = true; + } + i++; + } + if (foundUnselectedItem) { + table.clearAll(); + } + } + + }); + } + + private void disposeTableViewer() { + if (tableViewer == null) + return; + IContentProvider contentProvider = tableViewer.getContentProvider(); + if (contentProvider != null) + contentProvider.dispose(); + IBaseLabelProvider labelProvider = tableViewer.getLabelProvider(); + if (labelProvider != null) + labelProvider.dispose(); + Control control = tableViewer.getControl(); + if (control != null) + control.dispose(); + tableViewer = null; + } + + private void setCellEditors(IAdaptable adaptable, int attributeCount) { + if (adaptable.getAdapter(CellEditor[].class) != null) { + CellEditor[] editors = adaptable.getAdapter(CellEditor[].class); + if (editors.length < attributeCount) { + LoggingSupport.log(UiPlugin.getDefault(), new IllegalStateException( + "not enough cell editors for feature type so not used")); //$NON-NLS-1$ + createCellEditors(); + } else { + CellEditor[] copy = new CellEditor[editors.length + 1]; + if (editors.length == attributeCount) { + // there is an editor for each attribute. First element in copy if for the + // fid column (which is not editable). + System.arraycopy(editors, 0, copy, 1, attributeCount); + } else { + + // ignore 1st element in editors because it is for the FID column which is read + // only. + System.arraycopy(editors, 1, copy, 1, attributeCount); + + } + tableViewer.setCellEditors(copy); + } + } else { + createCellEditors(); + } + } + + private void addCellEditorListeners(IAdaptable adaptable) { + CellEditor[] editors = tableViewer.getCellEditors(); + // offset is usually 1 but if the number of validators==number of attributes then the offset + // is 0 + // because the first column is the FID column which doesn't have a listener. + int offset = 1; + + ICellEditorListener[] listener = null; + if (adaptable.getAdapter(ICellEditorListener[].class) != null) { + listener = adaptable.getAdapter(ICellEditorListener[].class); + int attributeCount = features.getSchema().getAttributeCount(); + if (listener.length < attributeCount) { + LoggingSupport.log(UiPlugin.getDefault(), new IllegalStateException( + "not enough cell editors for feature type so not used")); //$NON-NLS-1$ + return; + } else if (listener.length == attributeCount + 1) { + offset = 0; + } + } + + for (int i = 0; i < editors.length - offset; i++) { + final CellEditor editor = editors[i + offset]; + if (editor == null) + continue; + if (listener != null && listener[i] != null) + editor.addListener(listener[i]); + editor.addListener(new DisplayErrorCellListener(editor)); + } + } + + private void setCellValidators(IAdaptable adaptable) { + CellEditor[] editors = tableViewer.getCellEditors(); + SimpleFeatureType schema = features.getSchema(); + // offset is usually 1 but if the number of validators==number of attributes then the offset + // is 0 + // because the first column is the FID column which doesn't have a listener. + int offset = 1; + + ICellEditorValidator[] validators = null; + if (adaptable.getAdapter(ICellEditorValidator[].class) != null) { + validators = adaptable.getAdapter(ICellEditorValidator[].class); + int attributeCount = features.getSchema().getAttributeCount(); + if (validators.length < attributeCount) { + LoggingSupport.log(UiPlugin.getDefault(), new IllegalStateException( + "not enough cell editors for feature type so not used")); //$NON-NLS-1$ + validators = null; + } else if (validators.length == attributeCount) { + offset = 0; + } + } + + for (int i = 0; i < editors.length - offset; i++) { + CellEditor editor = editors[i + offset]; + if (editor == null) + continue; + if (validators != null && validators[i] != null) + editor.setValidator(validators[i]); + else + editor.setValidator(new AttributeValidator(schema.getDescriptor(i), schema)); + } + } + + @SuppressWarnings("unchecked") + private void createCellEditors() { + SimpleFeatureType schema = features.getSchema(); + org.eclipse.jface.viewers.CellEditor[] editors = new org.eclipse.jface.viewers.CellEditor[schema + .getAttributeCount() + 1]; + + for (int i = 0; i < schema.getAttributeCount(); i++) { + AttributeDescriptor aType = schema.getDescriptor(i); + Class concreteType = aType.getType().getBinding(); + Composite control = (Composite) tableViewer.getControl(); + if (concreteType.isAssignableFrom(String.class)) { + BasicTypeCellEditor textCellEditor = new BasicTypeCellEditor(control, String.class); + editors[i + 1] = textCellEditor; + } else if (concreteType.isAssignableFrom(Integer.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, Integer.class); + editors[i + 1] = textCellEditor; + } else if (concreteType.isAssignableFrom(Double.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, Double.class); + editors[i + 1] = textCellEditor; + } else if (concreteType.isAssignableFrom(Float.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, Float.class); + editors[i + 1] = textCellEditor; + } else if (concreteType.isAssignableFrom(BigDecimal.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, BigDecimal.class); + editors[i + 1] = textCellEditor; + } else if (concreteType.isAssignableFrom(BigInteger.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, BigInteger.class); + editors[i + 1] = textCellEditor; + + } else if (concreteType.isAssignableFrom(Boolean.class)) { + BooleanCellEditor textCellEditor = new BooleanCellEditor(control); + editors[i + 1] = textCellEditor; + + } else if (concreteType.isAssignableFrom(Character.class)) { + BasicTypeCellEditor textCellEditor = new BasicTypeCellEditor(control, + Character.class); + editors[i + 1] = textCellEditor; + + } else if (Date.class.isAssignableFrom(concreteType)) { + DateTimeCellEditor textCellEditor = new DateTimeCellEditor(control); + editors[i + 1] = textCellEditor; + } + // else if( concreteType.isAssignableFrom(Date.class)){ + // WarningCellEditor textCellEditor = new WarningCellEditor(control, "The Date type does + // not yet have a editor, please make a bug report for this Attribute Type"); + // editors[i+1]=textCellEditor; + // + // } + else if (concreteType.isAssignableFrom(Byte.class)) { + BasicTypeCellEditor textCellEditor = new BasicTypeCellEditor(control, Byte.class); + editors[i + 1] = textCellEditor; + + } else if (concreteType.isAssignableFrom(Short.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, Short.class); + editors[i + 1] = textCellEditor; + + } else if (concreteType.isAssignableFrom(Long.class)) { + NumberCellEditor textCellEditor = new NumberCellEditor(control, Long.class); + editors[i + 1] = textCellEditor; + + } else { + WarningCellEditor textCellEditor = new WarningCellEditor(control, + Messages.FeatureTableControl_noEditor1 + concreteType.getSimpleName() + + Messages.FeatureTableControl_noEditor2); + editors[i + 1] = textCellEditor; + } + } + tableViewer.setCellEditors(editors); + } + + private void createAttributeColumns(final Table table, TableViewer viewer, TableLayout layout) { + + if (features == null) { + TableColumn column = new TableColumn(table, SWT.CENTER | SWT.BORDER); + column.setText(Messages.FeatureTableControl_1); + layout.addColumnData(new ColumnWeightData(1)); + } else { + + SimpleFeatureType schema = features.getSchema(); + + TableColumn column = new TableColumn(table, SWT.CENTER | SWT.BORDER); + column.setText("FID"); //$NON-NLS-1$ + layout.addColumnData(new ColumnWeightData(1, 150, true)); + column.setMoveable(true); + + column.addListener(SWT.Selection, + new AttributeColumnSortListener(this, FEATURE_ID_COLUMN_PROPERTY)); + + for (int i = 0; i < schema.getAttributeCount(); i++) { + AttributeDescriptor aType = schema.getDescriptor(i); + column = new TableColumn(table, SWT.CENTER | SWT.BORDER); + if (Geometry.class.isAssignableFrom(aType.getType().getBinding())) { // was + // aType.isGeometry() + // jg: wot is this maddness? jd: paul said so + column.setText("GEOMETRY"); //$NON-NLS-1$ + } else + column.setText(aType.getName().getLocalPart()); + + layout.addColumnData(new ColumnWeightData(1, 100, true)); + column.setMoveable(true); + + column.addListener(SWT.Selection, + new AttributeColumnSortListener(this, aType.getName().getLocalPart())); + } + + } + } + + /** + * Does nothing. + * + * @see org.eclipse.ui.IWorkbenchPart#setFocus() + */ + public void setFocus() { + // do nothing. + } + + /** + * Contents of the current page of features + * + * @return + */ + public FeatureCollection getFeatures() { + return features; + } + + /** Set up for a single page of content */ + public void setFeatures(FeatureCollection features) { + checkWidget(); + if (this.features != null && this.features == features) + return; + + this.features = features; + + createTableViewer(book); + } + + private void checkWidget() { + if (Display.getCurrent() == null) + SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + + /** + * Don't display nothing :-) + */ + public void clear() { + features = null; + selectionProvider.getSelectionFids().clear(); + update(); + } + + /** + * Displays a message. If text == null or "" then the message is hidden and tableViewer is shown + * again. + * + * @param text message to display + * @param background color of the background of the text widget. If null the default color is + * used + * @param foreground color of the foreground of the text widget. If null the default color is + * used + */ + public void message(String text, Color background, Color foreground) { + checkWidget(); + Color background2 = background; + Color foreground2 = foreground; + if (background2 == null) { + background2 = messageBackground; + } + if (foreground2 == null) { + foreground2 = messageForeground; + } + message.setBackground(background2); + message.setForeground(foreground2); + if (text == null || text.trim().length() == 0) { + message.setText(""); //$NON-NLS-1$ + if (tableViewer != null) { + book.showPage(tableViewer.getControl()); + UiPlugin.trace(Trace.FEATURE_TABLE, getClass(), + "message(String,Color,Color): showing table View", //$NON-NLS-1$ + SHOW_PATH ? new Exception() : null); + } + } else { + message.setText(text); + book.showPage(message); + UiPlugin.trace(Trace.FEATURE_TABLE, getClass(), + "message(String,Color,Color): showing message", //$NON-NLS-1$ + SHOW_PATH ? new Exception() : null); + } + } + + /** + * Displays a message. If text == null or "" then the message is hidden and tableViewer is shown + * again. + * + * @param text message to display + */ + public void message(String text) { + message(text, null, null); + } + + /** + * Returns a selection with a single Id indicating the features selected + */ + @Override + public ISelection getSelection() { + checkWidget(); + return selectionProvider.getSelection(); + } + + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + selectionProvider.addSelectionChangedListener(listener); + } + + @Override + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + selectionProvider.removeSelectionChangedListener(listener); + } + + /** + * Useable selections are: selection of features, FIDS and Filters/Queries that adapt to a + * FeatureSource + */ + @Override + public void setSelection(final ISelection newSelection) { + checkWidget(); + selectionProvider.setSelection(newSelection); + } + + /** + * Sorts the table so that the selection is at the top of the table. It does not last. The next + * selection will not be at the top. + */ + public void promoteSelection() { + checkWidget(); + tableViewer.cancelEditing(); + + Table table = tableViewer.getTable(); + table.setSortColumn(null); + + Id filter = selectionProvider.getId(); + + sort(new SelectionComparator(filter, SWT.UP, new FIDComparator(SWT.UP)), SWT.UP, null); + table.setTopIndex(0); + } + + /** + * Sorts the features in the tableView. + * + * @param comparator comparator to use for the sorting. + * @param dir the direction to set the column SWT.UP or SWT.DOWN. If SWT.UP then the table item + * with index 0 is at the top of the table otherwise it is at the bottom of the table. + * @param sortColumn the column that is being sorted + */ + public void sort(Comparator comparator, int dir, TableColumn sortColumn) { + checkWidget(); + + FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer + .getContentProvider(); + + boolean sorted = false; + if (!comparator.equals(currentComparator)) { + sorted = true; + currentComparator = comparator; + Collections.sort(provider.features, currentComparator); + } + Table table = tableViewer.getTable(); + if (table.getSortColumn() != sortColumn) { + sorted = true; + table.setSortColumn(sortColumn); + while (Display.getCurrent().readAndDispatch()) + ; + } + if (table.getSortColumn() != null && dir != table.getSortDirection()) { + sorted = true; + table.setSortDirection(dir); + while (Display.getCurrent().readAndDispatch()) + ; + } + if (sorted) { + table.deselectAll(); + table.clearAll(); + } + + } + + /** + * Resorts the table using the last comparator. This is useful for cases where features have + * been added to the table + * + * @param refreshTable + */ + void sort(boolean refreshTable) { + if (currentComparator == null) + return; + + FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer + .getContentProvider(); + + Collections.sort(provider.features, currentComparator); + + tableViewer.getTable().deselectAll(); + if (refreshTable) + tableViewer.getTable().clearAll(); + } + + public TableViewer getViewer() { + return tableViewer; + } + + FeatureTableSelectionProvider getSelectionProvider() { + return selectionProvider; + } + + public void setSelection(StructuredSelection selection, boolean reveal) { + selectionProvider.setSelection(selection, reveal); + } + + public int getSelectionCount() { + return selectionProvider.getSelectionFids().size(); + } + + public void select(Set selection) { + getSelectionProvider().getSelectionFids().clear(); + int j = 0; + int firstMatch = -1; + for (FeatureId id : selection) { + selectionProvider.getSelectionFids().add(id.getID()); + if (firstMatch == -1) { + firstMatch = j; + } + j++; + } + Table table = tableViewer.getTable(); + if (firstMatch != -1) { + // display the selected item + table.setTopIndex(firstMatch); + } + // trigger a refresh of table + table.clearAll(); + // tell the world.. + selectionProvider.notifyListeners(); + } + + public void select(String cql, boolean selectAll) throws CQLException { + Filter filter = CQL.toFilter(cql); + + FeatureTableContentProvider provider = (FeatureTableContentProvider) this.tableViewer + .getContentProvider(); + List toSearch = provider.features; + + IProgressMonitor progressMonitor = getSelectionProvider().progressMonitor; + if (progressMonitor != null) { + progressMonitor.setCanceled(true); + } + getSelectionProvider().getSelectionFids().clear(); + int j = 0; + int firstMatch = -1; + OUTER: for (SimpleFeature feature : toSearch) { + if (filter.evaluate(feature)) { + selectionProvider.getSelectionFids().add(feature.getID()); + if (firstMatch == -1) + firstMatch = j; + if (!selectAll) + break OUTER; + } + j++; + } + + Table table = tableViewer.getTable(); + if (firstMatch != -1) { + // display the selected item + table.setTopIndex(firstMatch); + } + // trigger a refresh of table + table.clearAll(); + // tell the world.. + selectionProvider.notifyListeners(); + } + + /** + * select the features found that has the text. Only the attributes indicated are searched. If + * {@link #ALL} is selected then all attributes will be searched + * + * @param text text to search for it will first be assumed that it is a reg ex expression + * @param attributes the attributes to search. See {@link #ALL} + * @param selectAll if true all matched features will be selected otherwise just the first + * feature + */ + public void select(String text, String[] attributes, boolean selectAll) + throws PatternSyntaxException { + + Pattern pattern = compilePattern(text); + + if (pattern == null) { + return; + } + + FeatureTableContentProvider provider = (FeatureTableContentProvider) this.tableViewer + .getContentProvider(); + List toSearch = provider.features; + + IProgressMonitor progressMonitor = getSelectionProvider().progressMonitor; + if (progressMonitor != null) { + progressMonitor.setCanceled(true); + } + getSelectionProvider().getSelectionFids().clear(); + int j = 0; + int firstMatch = -1; + OUTER: for (SimpleFeature feature : toSearch) { + if (searchFeature(feature, pattern, attributes)) { + if (firstMatch == -1) + firstMatch = j; + if (!selectAll) + break OUTER; + } + j++; + } + + Table table = tableViewer.getTable(); + if (firstMatch != -1) { + // display the selected item + table.setTopIndex(firstMatch); + } + // trigger a refresh of table + table.clearAll(); + // tell the world.. + selectionProvider.notifyListeners(); + } + + private Pattern compilePattern(final String text) { + + String[] parts = text.split("\\|"); + + StringBuilder builder = new StringBuilder(); + + for (String string : parts) { + String pre = ".*"; + String post = ".*"; + if (string.startsWith("^") || string.startsWith(".") || string.startsWith("\\A")) { + pre = ""; + } + if (string.startsWith("&") || string.startsWith("\\Z") || string.startsWith("\\z")) { + post = ""; + } + builder.append(pre); + builder.append(string); + builder.append(post); + builder.append('|'); + } + if (builder.length() > 0) { + builder.deleteCharAt(builder.length() - 1); + } + Pattern pattern; + try { + pattern = Pattern.compile(builder.toString(), Pattern.CASE_INSENSITIVE); + } catch (IllegalArgumentException e) { + try { + pattern = Pattern.compile(".*" + convertToLiteral(text) + ".*"); //$NON-NLS-1$//$NON-NLS-2$ + } catch (IllegalArgumentException e2) { + return null; + } + } + return pattern; + } + + private boolean searchFeature(SimpleFeature feature, Pattern pattern, String[] attributes) { + SimpleFeatureType featureType = feature.getFeatureType(); + if (attributes == ALL) { + for (int i = 0; i < featureType.getAttributeCount(); i++) { + if (matches(pattern, feature.getAttribute(i))) { + selectionProvider.getSelectionFids().add(feature.getID()); + return true; + } + } + } + for (int i = 0; i < attributes.length; i++) { + if (matches(pattern, feature.getAttribute(attributes[i]))) { + getSelectionProvider().getSelectionFids().add(feature.getID()); + return true; + + } + } + return false; + } + + private String convertToLiteral(String text) { + String text2 = text.replace("\\", "\\\\"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("*", "\\*"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("+", "\\+"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("?", "\\?"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("[", "\\["); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("]", "\\]"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("^", "\\^"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("-", "\\-"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("&", "\\&"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("(", "\\("); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace(")", "\\)"); //$NON-NLS-1$ //$NON-NLS-2$ + text2 = text2.replace("|", "\\|"); //$NON-NLS-1$ //$NON-NLS-2$ + return text2; + } + + private boolean matches(Pattern pattern, Object attribute) { + if (attribute == null) { + attribute = ""; + } + String stringValue = attribute.toString(); + return pattern.matcher(stringValue).matches(); + } + + public void addLoadingListener(IFeatureTableLoadingListener listener) { + loadingListeners.add(listener); + } + + public void remove(IFeatureTableLoadingListener listener) { + loadingListeners.remove(listener); + } + + protected void notifyLoadingListeners( LoadingEvent event ) { + this.checkWidget(); + if (event.loading) { + if (event.monitor == null) + throw new NullPointerException(); + for( IFeatureTableLoadingListener listener : loadingListeners ) { + try { + listener.loadingStarted(event.monitor); + } catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), listener + " threw an exception", e); //$NON-NLS-1$ + } + } + } else { + for( IFeatureTableLoadingListener listener : loadingListeners ) { + try { + listener.loadingStopped(event.canceled); + } catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), listener + " threw an exception", e); //$NON-NLS-1$ + } + } + } + } + + /** + * Updates the features that have the same feature ID to match the new feature or adds the + * features if they are not part of the current collection. + * + * @param features2 the feature collection that contains the modified or new features. + */ + public void update(FeatureCollection features2) { + if (features == null) + return; // nothing to update since the table is not in use... Should this be an + // exception? + FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer + .getContentProvider(); + provider.update(features2); + } + + /** + * Checks all the lists, caches, content providers, etc... are consistent with each other. This + * is an expensive method so should be called with care. A test is a good example. + */ + public void assertInternallyConsistent() { + if (tableViewer.getContentProvider() != null) { + FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer + .getContentProvider(); + provider.assertInternallyConsistent(); + } + } + + /** + * Removes the selected features (the features selected by the owning + * {@link FeatureTableControl}). + * + * @return returns a collection of the deleted features + * @see #setSelection(ISelection) + * @see #setSelection(StructuredSelection, boolean) + */ + public FeatureCollection deleteSelection() { + FeatureTableContentProvider provider = (FeatureTableContentProvider) tableViewer + .getContentProvider(); + return provider.deleteSelection(); + } + + /** + * Sets the context Menu used by the table view. Not menu is used for the message box. + * + * @param contextMenu menu manager used for creating the menu. + */ + public void setMenuManager(MenuManager contextMenu) { + checkWidget(); + this.contextMenu = contextMenu; + if (tableViewer != null && tableViewer.getControl() != null) { + Menu oldMenu = tableViewer.getControl().getMenu(); + if (oldMenu != null) + oldMenu.dispose(); + Menu menu = contextMenu.createContextMenu(tableViewer.getControl()); + tableViewer.getControl().setMenu(menu); + } + } + + public void setSelectionColor(IProvider selectionColor) { + this.selectionColor = selectionColor; + if (tableViewer != null) { + FeatureTableLabelProvider labelProvider = (FeatureTableLabelProvider) tableViewer + .getLabelProvider(); + labelProvider.setSelectionColor(selectionColor); + } + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableSelectionProvider.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableSelectionProvider.java index 932673311e..7607e0fb13 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableSelectionProvider.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTableSelectionProvider.java @@ -1,416 +1,427 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -import org.locationtech.udig.core.IProvider; -import org.locationtech.udig.core.internal.FeatureUtils; -import org.locationtech.udig.internal.ui.Trace; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; - -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.ISafeRunnable; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; -import org.geotools.data.Query; -import org.geotools.data.FeatureSource; -import org.geotools.data.Query; -import org.geotools.factory.CommonFactoryFinder; -import org.geotools.util.factory.GeoTools; -import org.geotools.feature.FeatureCollection; -import org.geotools.feature.FeatureIterator; -import org.geotools.filter.FilterAttributeExtractor; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; -import org.opengis.filter.Filter; -import org.opengis.filter.FilterFactory2; -import org.opengis.filter.Id; -import org.opengis.filter.identity.Identifier; - -/** - * Manages selection for the {@link FeatureTableControl} - * - * @author Jesse - * @since 1.1.0 - */ -class FeatureTableSelectionProvider implements ISelectionProvider { - - private FeatureTableControl owner; - private Set selectionFids = new HashSet(); - private Set selectionChangedListeners = new CopyOnWriteArraySet(); - - /** - * if null then no set selection is running if not null then it must be cancelled. - */ - volatile IProgressMonitor progressMonitor; - private IProvider progressMonitorProvider; - - public FeatureTableSelectionProvider( FeatureTableControl control, IProvider progressMonitorProvider ) { - this.owner = control; - this.progressMonitorProvider=progressMonitorProvider; - } - - public void addSelectionChangedListener( ISelectionChangedListener listener ) { - selectionChangedListeners.add(listener); - } - - public ISelection getSelection() { - checkWidget(); - if (selectionFids.isEmpty()) - return new StructuredSelection(); - return new StructuredSelection(getId()); - - } - - public void removeSelectionChangedListener( ISelectionChangedListener listener ) { - selectionChangedListeners.remove(listener); - } - - public void setSelection( ISelection selection ) { - setSelection(selection, true); - } - - void setSelection( final ISelection newSelection, final boolean reveal ) { - checkWidget(); - if (progressMonitor != null) { - progressMonitor.setCanceled(true); - UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableSelectionProvider.class, - "#setSelection(): cancelled monitor", null); //$NON-NLS-1$ - - } - try { - PlatformGIS.wait(500, -1, new WaitCondition(){ - - public boolean isTrue() { - return progressMonitor==null; - } - - }, this); - } catch (InterruptedException e) { - UiPlugin.log("Interrupted", e); //$NON-NLS-1$ - return; - } - - synchronized (this) { - progressMonitor = progressMonitorProvider.get(); - progressMonitor.setCanceled(false); - - PlatformGIS.run(new SelectionLoader(newSelection, reveal)); - } - } - - protected void notifyListeners() { - // let listeners know the selection has changed. - SelectionChangedEvent event = new SelectionChangedEvent(owner, - getSelection()); - for( ISelectionChangedListener listener : selectionChangedListeners ) { - try{ - listener.selectionChanged(event); - }catch (Throwable e) { - UiPlugin.log("", e); //$NON-NLS-1$ - } - } - } - /** - * Returns the fids. It can be used to add new fids. No notification of the change is raised. - * - * @return - */ - public Collection getSelectionFids() { - checkWidget(); - return selectionFids; - } - - public Id getId() { - checkWidget(); - FilterFactory2 fac = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints()); - Set ids = FeatureUtils.stringToId(fac, selectionFids); - return fac.id(ids); - } - - private void checkWidget() { - if (Display.getCurrent() == null) - SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS); - } - - private class SelectionLoader implements ISafeRunnable { - - private final ISelection newSelection; - private final boolean reveal; - - public SelectionLoader( ISelection newSelection, boolean reveal ) { - this.newSelection = newSelection; - this.reveal = reveal; - } - - public void handleException( Throwable exception ) { - UiPlugin.log("Error setting selection on table view", exception); //$NON-NLS-1$ - } - - public void run() throws Exception { - startProgress(); - try { - if (newSelection.isEmpty()) { - if (owner.getViewer().getControl().isDisposed()){ - done(); - return; - } - owner.getViewer().getControl().getDisplay().asyncExec(new Runnable(){ - public void run() { - updateMonitor(3); - owner.getViewer().getTable().setSelection(new TableItem[0]); - - selectionFids.clear(); - - updateMonitor(3); - - owner.getViewer().getTable().clearAll(); - notifyListeners(); - } - - }); - - } else if (newSelection instanceof IStructuredSelection) { - IStructuredSelection structured = (IStructuredSelection) newSelection; - final Set fids = new HashSet(); - obtainFidsFromSelection(structured, fids); - - // selection is equivalent to last selection so return - if (selectionFids.equals(fids)) - return; - - FeatureTableContentProvider provider = (FeatureTableContentProvider) owner - .getViewer().getContentProvider(); - - final List features = provider.features; - int i = 0; - synchronized( provider.features ){ - for( SimpleFeature feature : features ) { - if (fids.contains(feature.getID())) { - break; - } - i++; - } - } - - updateMonitor(1); - - final int index = i; - - owner.getViewer().getControl().getDisplay().asyncExec(new Runnable(){ - public void run() { - updateMonitor(1); - - owner.getViewer().getTable().setSelection(new TableItem[0]); - - selectionFids = fids; - - final Table table = owner.getViewer().getTable(); - // clear non-virtual data so that it will be re-labelled. This is not - // too - // bad of an operation (I think) - table.clearAll(); - if (reveal && index < features.size()) { - // show selection if there is one. - table.setTopIndex(index); - } - - notifyListeners(); - } - }); - } - } catch (Abort e) { - // its ok just aborting the finally will clean up - }finally { - done(); - } - } - - private void updateMonitor( final int ticks ) { - if( Display.getCurrent()!=null ){ - progressMonitor.worked(ticks); - }else{ - owner.getControl().getDisplay().asyncExec(new Runnable(){ - public void run() { - progressMonitor.worked(ticks); - } - }); - } - } - - private void done() { - Runnable runnable = new Runnable(){ - public void run() { - synchronized (FeatureTableSelectionProvider.this) { - progressMonitor.done(); - progressMonitor = null; - FeatureTableSelectionProvider.this.notifyAll(); - } - } - }; - if( Display.getCurrent()!=null ){ - runnable.run(); - }else{ - owner.getControl().getDisplay().asyncExec(runnable); - } - } - - private void startProgress() { - Runnable runnable = new Runnable(){ - public void run() { - progressMonitor.beginTask(Messages.FeatureTableSelectionProvider_loading_new_selection, 10); - progressMonitor.worked(1); - } - }; - if( Display.getCurrent()!=null ){ - runnable.run(); - }else{ - owner.getControl().getDisplay().asyncExec(runnable); - } - } - - private void obtainFidsFromSelection( IStructuredSelection structured, - final Set fids ) throws IOException, Abort { - int usedTicks = 0; - for( Iterator iter = structured.iterator(); iter.hasNext(); ) { - - if (progressMonitor.isCanceled()) - throw new Abort(); - - Object element = (Object) iter.next(); - - if (element instanceof String) { - fids.add((String) element); - } else if (element instanceof SimpleFeature) { - fids.add(((SimpleFeature) element).getID()); - } else if (element instanceof Id) { - String[] fids2 = ((Id) element).getIDs().toArray(new String[0]); - fids.addAll(Arrays.asList(fids2)); - } else if (element instanceof IAdaptable) { - - obtainFidsFromAdaptable(fids, (IAdaptable) element); - } else if (element instanceof Filter) { - UiPlugin - .log( - "Tried to set selection on table but the selection contained a non-Fid Filter that could not " + //$NON-NLS-1$ - "adapt to a FeatureSource so the selection could not be applied. Ignoring filter", //$NON-NLS-1$ - null); - } else { - UiPlugin - .log( - "Tried to set selection on table but the selection contained a " + element.getClass().getSimpleName() + //$NON-NLS-1$ - " but this type cannot be converted to Fids", null); //$NON-NLS-1$ - } - if( usedTicks < 7 ) - updateMonitor(1); - } - if( usedTicks < 7 ) - updateMonitor(7-usedTicks); - } - - /** - * Obtain fids from the features source if possible. - * - * @param fids the set to add fids to - * @param adaptable the object that adapted to the filter. hopefully can adapt to a feature - * source as well - * @param filter filter to use for obtaining fids. - * @throws IOException - * @throws Abort - */ - private void obtainFidsFromAdaptable( final Set fids, IAdaptable adaptable ) - throws IOException, Abort { - Filter filter = null; - if (adaptable.getAdapter(Filter.class) != null) - filter = (Filter) adaptable.getAdapter(Filter.class); - else if (adaptable.getAdapter(Query.class) != null) - filter = ((Query) adaptable.getAdapter(Query.class)).getFilter(); - - if (filter == null) - return; - - FeatureSource source = null; - if (adaptable.getAdapter(FeatureSource.class) != null) { - source = (FeatureSource) adaptable.getAdapter(FeatureSource.class); - } - - if (source == null) { - UiPlugin - .log( - "last resource run filter on features in table view... Might now work since table view" + //$NON-NLS-1$ - " does not have any Geometries", new Exception()); //$NON-NLS-1$ - - if (owner.getViewer() != null && owner.getViewer().getInput() != null) - for( SimpleFeature feature : ((FeatureTableContentProvider) owner.getViewer() - .getContentProvider()).features ) { - if (progressMonitor.isCanceled()) - throw new Abort(); - if (filter.evaluate(feature)) - fids.add(feature.getID()); - } - } else { - Query defaultQuery = new Query(source.getSchema().getName().getLocalPart(), - filter, new String[0]); - // TODO: Remove this workaround in 2.6.1 (note this has no performance impact) - Set required = (Set) filter.accept( new FilterAttributeExtractor(), null ); - defaultQuery.setPropertyNames( required.toArray(new String[0]) ); - - // get features that are just fids no attributes - FeatureCollection features = source.getFeatures(defaultQuery); - long start=System.currentTimeMillis(); - - FeatureIterator featureIterator = features.features(); - try { - while( featureIterator.hasNext() ) { - if (progressMonitor.isCanceled()) - throw new Abort(); - if( System.currentTimeMillis()-start>500){ - start=System.currentTimeMillis(); - owner.getViewer().getControl().getDisplay().asyncExec(new Runnable(){ - public void run() { - progressMonitor.subTask(fids.size()+" selected"); //$NON-NLS-1$ - } - }); - } - fids.add(featureIterator.next().getID()); - } - } finally { - featureIterator.close(); - } - } - } - } - - private static class Abort extends Exception { - - /** long serialVersionUID field */ - private static final long serialVersionUID = 1L; - } - -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.geotools.data.FeatureSource; +import org.geotools.data.Query; +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.feature.FeatureCollection; +import org.geotools.feature.FeatureIterator; +import org.geotools.filter.FilterAttributeExtractor; +import org.geotools.util.factory.GeoTools; +import org.locationtech.udig.core.IProvider; +import org.locationtech.udig.core.internal.FeatureUtils; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.Trace; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.filter.Filter; +import org.opengis.filter.FilterFactory2; +import org.opengis.filter.Id; +import org.opengis.filter.identity.Identifier; + +/** + * Manages selection for the {@link FeatureTableControl} + * + * @author Jesse + * @since 1.1.0 + */ +class FeatureTableSelectionProvider implements ISelectionProvider { + + private FeatureTableControl owner; + private Set selectionFids = new HashSet<>(); + private Set selectionChangedListeners = new CopyOnWriteArraySet<>(); + + /** + * if null then no set selection is running if not null then it must be cancelled. + */ + volatile IProgressMonitor progressMonitor; + private IProvider progressMonitorProvider; + + public FeatureTableSelectionProvider( FeatureTableControl control, IProvider progressMonitorProvider ) { + this.owner = control; + this.progressMonitorProvider=progressMonitorProvider; + } + + @Override + public void addSelectionChangedListener( ISelectionChangedListener listener ) { + selectionChangedListeners.add(listener); + } + + @Override + public ISelection getSelection() { + checkWidget(); + if (selectionFids.isEmpty()) + return new StructuredSelection(); + return new StructuredSelection(getId()); + + } + + @Override + public void removeSelectionChangedListener( ISelectionChangedListener listener ) { + selectionChangedListeners.remove(listener); + } + + @Override + public void setSelection( ISelection selection ) { + setSelection(selection, true); + } + + void setSelection( final ISelection newSelection, final boolean reveal ) { + checkWidget(); + if (progressMonitor != null) { + progressMonitor.setCanceled(true); + UiPlugin.trace(Trace.FEATURE_TABLE, FeatureTableSelectionProvider.class, + "#setSelection(): cancelled monitor", null); //$NON-NLS-1$ + + } + try { + PlatformGIS.wait(500, -1, new WaitCondition(){ + + @Override + public boolean isTrue() { + return progressMonitor==null; + } + + }, this); + } catch (InterruptedException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Interrupted", e); //$NON-NLS-1$ + return; + } + + synchronized (this) { + progressMonitor = progressMonitorProvider.get(); + progressMonitor.setCanceled(false); + + PlatformGIS.run(new SelectionLoader(newSelection, reveal)); + } + } + + protected void notifyListeners() { + // let listeners know the selection has changed. + SelectionChangedEvent event = new SelectionChangedEvent(owner, + getSelection()); + for( ISelectionChangedListener listener : selectionChangedListeners ) { + try{ + listener.selectionChanged(event); + }catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + } + /** + * Returns the fids. It can be used to add new fids. No notification of the change is raised. + * + * @return + */ + public Collection getSelectionFids() { + checkWidget(); + return selectionFids; + } + + public Id getId() { + checkWidget(); + FilterFactory2 fac = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints()); + Set ids = FeatureUtils.stringToId(fac, selectionFids); + return fac.id(ids); + } + + private void checkWidget() { + if (Display.getCurrent() == null) + SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS); + } + + private class SelectionLoader implements ISafeRunnable { + + private final ISelection newSelection; + private final boolean reveal; + + public SelectionLoader( ISelection newSelection, boolean reveal ) { + this.newSelection = newSelection; + this.reveal = reveal; + } + + @Override + public void handleException( Throwable exception ) { + LoggingSupport.log(UiPlugin.getDefault(), "Error setting selection on table view", exception); //$NON-NLS-1$ + } + + @Override + public void run() throws Exception { + startProgress(); + try { + if (newSelection.isEmpty()) { + if (owner.getViewer().getControl().isDisposed()){ + done(); + return; + } + owner.getViewer().getControl().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + updateMonitor(3); + owner.getViewer().getTable().setSelection(new TableItem[0]); + + selectionFids.clear(); + + updateMonitor(3); + + owner.getViewer().getTable().clearAll(); + notifyListeners(); + } + + }); + + } else if (newSelection instanceof IStructuredSelection) { + IStructuredSelection structured = (IStructuredSelection) newSelection; + final Set fids = new HashSet<>(); + obtainFidsFromSelection(structured, fids); + + // selection is equivalent to last selection so return + if (selectionFids.equals(fids)) + return; + + FeatureTableContentProvider provider = (FeatureTableContentProvider) owner + .getViewer().getContentProvider(); + + final List features = provider.features; + int i = 0; + synchronized( provider.features ){ + for( SimpleFeature feature : features ) { + if (fids.contains(feature.getID())) { + break; + } + i++; + } + } + + updateMonitor(1); + + final int index = i; + + owner.getViewer().getControl().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + updateMonitor(1); + + owner.getViewer().getTable().setSelection(new TableItem[0]); + + selectionFids = fids; + + final Table table = owner.getViewer().getTable(); + // clear non-virtual data so that it will be re-labelled. This is not + // too + // bad of an operation (I think) + table.clearAll(); + if (reveal && index < features.size()) { + // show selection if there is one. + table.setTopIndex(index); + } + + notifyListeners(); + } + }); + } + } catch (Abort e) { + // its ok just aborting the finally will clean up + }finally { + done(); + } + } + + private void updateMonitor( final int ticks ) { + if( Display.getCurrent()!=null ){ + progressMonitor.worked(ticks); + }else{ + owner.getControl().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + progressMonitor.worked(ticks); + } + }); + } + } + + private void done() { + Runnable runnable = new Runnable(){ + @Override + public void run() { + synchronized (FeatureTableSelectionProvider.this) { + progressMonitor.done(); + progressMonitor = null; + FeatureTableSelectionProvider.this.notifyAll(); + } + } + }; + if( Display.getCurrent()!=null ){ + runnable.run(); + }else{ + owner.getControl().getDisplay().asyncExec(runnable); + } + } + + private void startProgress() { + Runnable runnable = new Runnable(){ + @Override + public void run() { + progressMonitor.beginTask(Messages.FeatureTableSelectionProvider_loading_new_selection, 10); + progressMonitor.worked(1); + } + }; + if( Display.getCurrent()!=null ){ + runnable.run(); + }else{ + owner.getControl().getDisplay().asyncExec(runnable); + } + } + + private void obtainFidsFromSelection( IStructuredSelection structured, + final Set fids ) throws IOException, Abort { + int usedTicks = 0; + for( Iterator iter = structured.iterator(); iter.hasNext(); ) { + + if (progressMonitor.isCanceled()) + throw new Abort(); + + Object element = iter.next(); + + if (element instanceof String) { + fids.add((String) element); + } else if (element instanceof SimpleFeature) { + fids.add(((SimpleFeature) element).getID()); + } else if (element instanceof Id) { + String[] fids2 = ((Id) element).getIDs().toArray(new String[0]); + fids.addAll(Arrays.asList(fids2)); + } else if (element instanceof IAdaptable) { + + obtainFidsFromAdaptable(fids, (IAdaptable) element); + } else if (element instanceof Filter) { + UiPlugin + .log( + "Tried to set selection on table but the selection contained a non-Fid Filter that could not " + //$NON-NLS-1$ + "adapt to a FeatureSource so the selection could not be applied. Ignoring filter", //$NON-NLS-1$ + null); + } else { + UiPlugin + .log( + "Tried to set selection on table but the selection contained a " + element.getClass().getSimpleName() + //$NON-NLS-1$ + " but this type cannot be converted to Fids", null); //$NON-NLS-1$ + } + if( usedTicks < 7 ) + updateMonitor(1); + } + if( usedTicks < 7 ) + updateMonitor(7-usedTicks); + } + + /** + * Obtain fids from the features source if possible. + * + * @param fids the set to add fids to + * @param adaptable the object that adapted to the filter. hopefully can adapt to a feature + * source as well + * @param filter filter to use for obtaining fids. + * @throws IOException + * @throws Abort + */ + private void obtainFidsFromAdaptable( final Set fids, IAdaptable adaptable ) + throws IOException, Abort { + Filter filter = null; + if (adaptable.getAdapter(Filter.class) != null) + filter = adaptable.getAdapter(Filter.class); + else if (adaptable.getAdapter(Query.class) != null) + filter = adaptable.getAdapter(Query.class).getFilter(); + + if (filter == null) + return; + + FeatureSource source = null; + if (adaptable.getAdapter(FeatureSource.class) != null) { + source = adaptable.getAdapter(FeatureSource.class); + } + + if (source == null) { + UiPlugin + .log( + "last resource run filter on features in table view... Might now work since table view" + //$NON-NLS-1$ + " does not have any Geometries", new Exception()); //$NON-NLS-1$ + + if (owner.getViewer() != null && owner.getViewer().getInput() != null) + for( SimpleFeature feature : ((FeatureTableContentProvider) owner.getViewer() + .getContentProvider()).features ) { + if (progressMonitor.isCanceled()) + throw new Abort(); + if (filter.evaluate(feature)) + fids.add(feature.getID()); + } + } else { + Query defaultQuery = new Query(source.getSchema().getName().getLocalPart(), + filter, new String[0]); + // TODO: Remove this workaround in 2.6.1 (note this has no performance impact) + Set required = (Set) filter.accept( new FilterAttributeExtractor(), null ); + defaultQuery.setPropertyNames( required.toArray(new String[0]) ); + + // get features that are just fids no attributes + FeatureCollection features = source.getFeatures(defaultQuery); + long start=System.currentTimeMillis(); + + FeatureIterator featureIterator = features.features(); + try { + while( featureIterator.hasNext() ) { + if (progressMonitor.isCanceled()) + throw new Abort(); + if( System.currentTimeMillis()-start>500){ + start=System.currentTimeMillis(); + owner.getViewer().getControl().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + progressMonitor.subTask(fids.size()+" selected"); //$NON-NLS-1$ + } + }); + } + fids.add(featureIterator.next().getID()); + } + } finally { + featureIterator.close(); + } + } + } + } + + private static class Abort extends Exception { + + /** long serialVersionUID field */ + private static final long serialVersionUID = 1L; + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditor.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditor.java index 0d54de5e24..4f30a2d2dc 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditor.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditor.java @@ -1,966 +1,968 @@ -/** - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.fieldassist.ControlDecoration; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.ComboBoxCellEditor; -import org.eclipse.jface.viewers.DialogCellEditor; -import org.eclipse.jface.viewers.IBaseLabelProvider; -import org.eclipse.jface.viewers.ICellModifier; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.TableLayout; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.swt.widgets.TreeItem; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.actions.ActionFactory; -import org.geotools.feature.AttributeTypeBuilder; -import org.geotools.feature.simple.SimpleFeatureTypeBuilder; -import org.geotools.referencing.CRS; -import org.geotools.referencing.crs.DefaultGeographicCRS; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.LineString; -import org.locationtech.jts.geom.MultiLineString; -import org.locationtech.jts.geom.MultiPoint; -import org.locationtech.jts.geom.MultiPolygon; -import org.locationtech.jts.geom.Point; -import org.locationtech.jts.geom.Polygon; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; -import org.locationtech.udig.ui.preferences.PreferenceConstants; -import org.opengis.feature.simple.SimpleFeatureType; -import org.opengis.feature.type.AttributeDescriptor; -import org.opengis.feature.type.FeatureType; -import org.opengis.feature.type.GeometryDescriptor; -import org.opengis.filter.Filter; -import org.opengis.filter.PropertyIsLessThanOrEqualTo; -import org.opengis.filter.expression.Function; -import org.opengis.filter.expression.Literal; -import org.opengis.metadata.Identifier; -import org.opengis.referencing.ReferenceIdentifier; -import org.opengis.referencing.crs.CoordinateReferenceSystem; - -/** - * A composite editor based on a JFace TreeViewer for creating and editing feature types. - * - * @author jones - * @author Andrea Antonello (www.hydrologis.com) - * @since 1.1.0 - */ -public class FeatureTypeEditor { - - private static final int MAX_ATTRIBUTE_LENGTH = 10485759; // Maximum allows by postgis and is - // "big enough" - - private static final List ALLOWED_BINDINGS_FOR_LENGHT_SET = Arrays.asList(String.class, - Double.class, Long.class, Integer.class, Short.class); - - /** - * The index of the name column in the viewer. - */ - private static final int NAME_COLUMN = 0; - - /** - * The index of the type column in the viewer. - */ - private static final int TYPE_COLUMN = 1; - - /** - * The index of the type column in the viewer. - */ - private static final int OTHER_COLUMN = 2; - - /** - * The index of the length column in the viewer. - */ - private static final int LENGTH_COLUMN = 3; - - /** - * The index of the NULL column in the viewer. - */ - private static final int IS_NULL_COLUMN = 4; - - private static final List TYPES; - static { - List types = new ArrayList<>(); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_stringType, String.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_booleanType, Boolean.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_dateType, Date.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_integerType, Integer.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_longType, Long.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_floatType, Float.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_doubleType, Double.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_pointType, Point.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_lineStringType, - LineString.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_polygonType, Polygon.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_geometryType, Geometry.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_multiPointType, - MultiPoint.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_multiLineStringType, - MultiLineString.class)); - types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_multiPolygonType, - MultiPolygon.class)); - - TYPES = Collections.unmodifiableList(types); - } - - private TreeViewer viewer; - - private IAction createAttributeAction; - - private IAction deleteAttributeAction; - - private Text nameText; - - private List legalTypes = TYPES; - - private SimpleFeatureType featureType; - - private ControlDecoration errorDecorator; - - /** - * Create the table control and set the input. - * - * @param parent the composite that will be used as the TreeViewer's parent. - * @param layoutData the layout data to use to layout the editor. If null GridData(Fill_Both) - */ - public void createTable(Composite parent, Object layoutData) { - createTable(parent, layoutData, featureType, true); - } - - /** - * Create the table control and set the input. - * - * @param parent the composite that will be used as the TreeViewer's parent. - * @param layoutData the layout data to use to layout the editor. If null GridData(Fill_Both) - */ - public void createTable(Composite parent, Object layoutData, SimpleFeatureType type) { - SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); - builder.setName(type.getName()); - builder.init(type); - createTable(parent, layoutData, builder.buildFeatureType(), true); - } - - /** - * Create the table control and set the input. - * - * @param parent the composite that will be used as the TreeViewer's parent. - * @param layoutData the layout data to use to layout the editor. If null GridData(Fill_Both). - * @param featureType the {@link FeatureType} to use to populate the table. - * @param editable the editable flag of the table - */ - public void createTable(Composite parent, Object layoutData, SimpleFeatureType featureType, - boolean editable) { - - viewer = new TreeViewer(parent, SWT.FULL_SELECTION); - - Tree tree = viewer.getTree(); - if (layoutData == null) - tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - else - tree.setLayoutData(layoutData); - - tree.setHeaderVisible(true); - TableLayout tableLayout = new TableLayout(); - tableLayout.addColumnData(new ColumnWeightData(1)); - tableLayout.addColumnData(new ColumnWeightData(1)); - tableLayout.addColumnData(new ColumnWeightData(1)); - tableLayout.addColumnData(new ColumnWeightData(1)); - tableLayout.addColumnData(new ColumnWeightData(1)); - - tree.setLayout(tableLayout); - - TreeColumn column = new TreeColumn(tree, SWT.CENTER); - column.setResizable(true); - column.setText(Messages.FeatureTypeEditor_nameColumnName); - - column = new TreeColumn(tree, SWT.CENTER); - column.setResizable(true); - column.setText(Messages.FeatureTypeEditor_typeColumnName); - - column = new TreeColumn(tree, SWT.CENTER); - column.setResizable(true); - - column = new TreeColumn(tree, SWT.CENTER); - column.setResizable(true); - column.setText(Messages.FeatureTypeEditor_lengthColumnName); - - column = new TreeColumn(tree, SWT.CENTER); - column.setResizable(true); - column.setText(Messages.FeatureTypeEditor_isNullColumnName); - - viewer.setContentProvider(new FeatureTypeContentProvider(viewer)); - viewer.setLabelProvider(new FeatureTypeLabelProvider()); - viewer.setColumnProperties(new String[] { String.valueOf(NAME_COLUMN), - String.valueOf(TYPE_COLUMN), String.valueOf(OTHER_COLUMN), - String.valueOf(LENGTH_COLUMN), String.valueOf(IS_NULL_COLUMN) }); - - setEditable(editable); - setFeatureType(featureType); - } - - /** - * Declares what types are permitted as attributes. For example Shapefiles do not permit - * Geometry as a legal type. - * - * @param legalTypes the List of legal types in the order they will be displayed. - */ - public void setLegalTypes(List legalTypes) { - this.legalTypes = Collections.unmodifiableList(legalTypes); - } - - /** - * @return Returns the list of types that this editor will allow the use to select - */ - public List getLegalTypes() { - return Collections.unmodifiableList(legalTypes); - } - - /** - * Sets whether the table is editable or just a viewer. - * - * @param editable if true then the table can be edited - */ - public void setEditable(boolean editable) { - if (editable) { - Tree tree = viewer.getTree(); - String[] comboItems = new String[legalTypes.size()]; - for (int i = 0; i < comboItems.length; i++) { - comboItems[i] = legalTypes.get(i).getName(); - } - - TextCellEditor attributeNameEditor = new TextCellEditor(tree); - ComboBoxCellEditor attributeTypeEditor = new ComboBoxCellEditor(tree, comboItems, - SWT.READ_ONLY | SWT.FULL_SELECTION); - TextCellEditor attributeLengthEditor = new TextCellEditor(tree); - BooleanCellEditor attributeIsNullEditor = new BooleanCellEditor(tree); - DialogCellEditor crsEditor = createCRSEditor(tree); - viewer.setCellEditors(new CellEditor[] { attributeNameEditor, attributeTypeEditor, - crsEditor, attributeLengthEditor, attributeIsNullEditor }); - - viewer.setCellModifier(new AttributeCellModifier()); - } else { - viewer.setCellEditors(null); - viewer.setCellModifier(null); - } - } - - private DialogCellEditor createCRSEditor(Tree tree) { - return new CRSDialogCellEditor(tree); - } - - public SimpleFeatureTypeBuilder builderFromFeatureType(SimpleFeatureType ft) { - SimpleFeatureTypeBuilder ftB; - ftB = new SimpleFeatureTypeBuilder(); - ftB.init(ft); - ftB.setName(ft.getName()); - return ftB; - } - - /** - * Creates a ContextMenu (the menu is created using the Table's composite as a parent) and - * returns the contextMenu. - * - *

    - * It is recommended that the MenuManager be registered with an IWorkbenchPartSite - *

    - * - * @return a MenuManager for the contextMenu. - */ - public MenuManager createContextMenu() { - final MenuManager contextMenu = new MenuManager(); - - contextMenu.setRemoveAllWhenShown(true); - contextMenu.addMenuListener(new IMenuListener() { - @Override - public void menuAboutToShow(IMenuManager mgr) { - contextMenu.add(getCreateAttributeAction()); - contextMenu.add(getDeleteAction()); - } - }); - - Menu menu = contextMenu.createContextMenu(viewer.getTree()); - viewer.getControl().setMenu(menu); - - return contextMenu; - } - - /** - * Sets the Global actions that apply. IE sets the delete global action. - * - * @param actionBars - */ - public void setGlobalActions(IActionBars actionBars) { - actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), getDeleteAction()); - } - - /** - * Sets the {@link SimpleFeatureType} being edited. - * - *

    - * If type is null then a new featureType is created. Must be called in the display thread. - *

    - * - * @param type then new SimpleFeatureType to be edited, or null to create a new type. - */ - public void setFeatureType(SimpleFeatureType type) { - SimpleFeatureTypeBuilder builder = null; - if (type != null) { - builder = new SimpleFeatureTypeBuilder(); - builder.init(type); - builder.setName(type.getName()); - featureType = builder.buildFeatureType(); - } else { - featureType = createDefaultFeatureType(); - } - if (viewer != null) { - setInput(featureType); - } - - } - - /** - * Sets the FeatureTypeBuilder used for creating the feature type. - * - * @param builder - * @deprecated with the new {@link SimpleFeatureTypeBuilder} this is no more possible, therefore - * deprecating. - */ - @Deprecated - public final void setFeatureTypeBuilder(SimpleFeatureTypeBuilder newBuilder) { - - } - - /** - * Creates a default {@link FeatureType}. - * - *

    - * The default type has a {@link Geometry} attribute and a name attribute. The geometry - * attribute is a {@link LineString}. - *

    - * - * @return a default FeatureType. - */ - public SimpleFeatureType createDefaultFeatureType() { - SimpleFeatureTypeBuilder builder; - builder = new SimpleFeatureTypeBuilder(); - builder.setName(Messages.FeatureTypeEditor_newFeatureTypeName); - builder.setCRS(getDefaultCRS()); - // no need to provide a default length since length can be specified via the UI - // builder.length(MAX_ATTRIBUTE_LENGTH).add(Messages.FeatureTypeEditor_defaultNameAttributeName, - // String.class); - builder.add(Messages.FeatureTypeEditor_defaultNameAttributeName, String.class); - - // add geometry attribute as not null - AttributeTypeBuilder attribBuilder = new AttributeTypeBuilder(); - attribBuilder.setName(Messages.FeatureTypeEditor_defaultGeometryName); - attribBuilder.setCRS(builder.getCRS()); - attribBuilder.nillable(false); - attribBuilder.binding(LineString.class); - builder.add(attribBuilder.buildDescriptor(Messages.FeatureTypeEditor_defaultGeometryName)); - return builder.buildFeatureType(); - } - - private CoordinateReferenceSystem getDefaultCRS() { - String crsInfo = UiPlugin.getDefault().getPreferenceStore() - .getString(PreferenceConstants.P_DEFAULT_GEOMEMTRY_CRS); - if (crsInfo != null && crsInfo.trim().length() > 0) { - try { - crsInfo = crsInfo.trim(); - if (crsInfo.startsWith("EPSG")) { //$NON-NLS-1$ - return CRS.decode(crsInfo); - } - return CRS.parseWKT(crsInfo); - } catch (Throwable t) { - UiPlugin.log("", t); //$NON-NLS-1$ - } - } - return DefaultGeographicCRS.WGS84; - } - - public void setDefaultCRS(CoordinateReferenceSystem crs) { - String crsInfo = null; - - Set identifiers = crs.getIdentifiers(); - for (Identifier identifier : identifiers) { - if (identifier.toString().startsWith("EPSG")) { //$NON-NLS-1$ - crsInfo = identifier.toString(); - break; - } - } - - if (crsInfo == null) - crsInfo = crs.toWKT(); - - UiPlugin.getDefault().getPreferenceStore() - .setValue(PreferenceConstants.P_DEFAULT_GEOMEMTRY_CRS, crsInfo); - - SimpleFeatureTypeBuilder tmpBuilder = new SimpleFeatureTypeBuilder(); - tmpBuilder.init(featureType); - tmpBuilder.setName(featureType.getTypeName()); - tmpBuilder.setCRS(crs); - featureType = tmpBuilder.buildFeatureType(); - - } - - private void setInput(SimpleFeatureType featureType) { - viewer.setInput(featureType); - if (nameText != null && !nameText.isDisposed()) { - nameText.setText(featureType.getTypeName()); - } - } - - /** - * Returns an action that will add a new attribute to the SimpleFeatureType. - * - * @return an action that will add a new attribute to the SimpleFeatureType. - */ - public synchronized IAction getCreateAttributeAction() { - if (createAttributeAction == null) { - createAttributeAction = new Action() { - @Override - public void runWithEvent(Event event) { - SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); - SimpleFeatureTypeBuilder ftB = builderFromFeatureType(ft); - - int index = 0; - List usedIndices = new ArrayList<>(); - - // get max Index of added attributes - for (AttributeDescriptor at : ft.getAttributeDescriptors()) { - if (at.getLocalName().startsWith( - Messages.FeatureTypeEditor_newAttributeTypeDefaultName)) { - try { - usedIndices.add(Integer.valueOf(at.getLocalName().replace( - Messages.FeatureTypeEditor_newAttributeTypeDefaultName, - ""))); //$NON-NLS-1$ - } catch (Exception e) { - // ignore, user has changed attribute - } - index++; - - } - } - - Collections.sort(usedIndices, Collections.reverseOrder()); - // TODO improve : implement algorithm to find first unused number in sorted list - if (!usedIndices.isEmpty()) { - index = usedIndices.get(0) + 1; // reverse ordered, highest first - } - - ftB.add(Messages.FeatureTypeEditor_newAttributeTypeDefaultName + index, - String.class); - featureType = ftB.buildFeatureType(); - viewer.setInput(featureType); - // TODO check if it is better to do something and then: viewer.refresh(false); - } - }; - createAttributeAction - .setId("org.locationtech.udig.ui.FeatureTypeEditor.createAttributeAction"); //$NON-NLS-1$ - createAttributeAction.setText(Messages.addAttributeAction_label); - createAttributeAction.setToolTipText(Messages.addAttributeAction_label); - createAttributeAction.setImageDescriptor( - UiPlugin.getDefault().getImageDescriptor("elcl16/new_attribute.gif")); //$NON-NLS-1$ - } - return createAttributeAction; - } - - /** - * Returns an action that will delete the selected attributes from the SimpleFeatureType. - * - * @return an action that will delete the selected attributes from the SimpleFeatureType. - */ - public synchronized IAction getDeleteAction() { - if (deleteAttributeAction == null) { - deleteAttributeAction = new Action() { - - @SuppressWarnings("unchecked") - @Override - public void runWithEvent(Event event) { - SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); - SimpleFeatureTypeBuilder ftB = builderFromFeatureType(ft); - IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); - for (Iterator iter = selection.iterator(); iter - .hasNext();) { - AttributeDescriptor element = iter.next(); - ftB.remove(element.getLocalName()); - } - featureType = ftB.buildFeatureType(); - viewer.setInput(featureType); - } - }; - deleteAttributeAction.setText(Messages.deleteAttributeAction_label); - deleteAttributeAction.setToolTipText(Messages.deleteAttributeAction_tooltip); - deleteAttributeAction.setImageDescriptor( - UiPlugin.getDefault().getImageDescriptor("elcl16/delete.gif")); //$NON-NLS-1$ - deleteAttributeAction.setDescription(Messages.deleteAttributeAction_description); - deleteAttributeAction - .setId("org.locationtech.udig.ui.FeatureTypeEditor.deleteAttributeAction"); //$NON-NLS-1$ - } - return deleteAttributeAction; - } - - /** - * Creates a Text input object that for modify the feature type name. - * - * @param parent the parent of the text object - * @return - */ - public void createFeatureTypeNameText(Composite parent, Object layoutData) { - - nameText = new Text(parent, SWT.SINGLE | SWT.LEFT | SWT.BORDER); - errorDecorator = new ControlDecoration(nameText, SWT.TOP | SWT.LEFT); - Image image = PlatformUI.getWorkbench().getSharedImages() - .getImage(ISharedImages.IMG_DEC_FIELD_ERROR); - errorDecorator.setImage(image); - - if (viewer != null) { - SimpleFeatureType input = ((SimpleFeatureType) viewer.getInput()); - if (input != null) { - nameText.setText(input.getTypeName()); - } - } - if (layoutData != null) { - nameText.setLayoutData(layoutData); - } else { - nameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - } - - class NameListener implements KeyListener, FocusListener { - - @Override - public void keyPressed(KeyEvent e) { - SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); - if (e.character == SWT.ESC) { - nameText.setText(ft.getTypeName()); - } else if (e.character == SWT.Selection) { - SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); - ftB.init(ft); - ftB.setName(nameText.getText()); - featureType = ftB.buildFeatureType(); - viewer.setInput(featureType); - } else { - errorDecorator.hide(); - } - } - - @Override - public void keyReleased(KeyEvent e) { - SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); - SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); - ftB.init(ft); - ftB.setName(nameText.getText()); - featureType = ftB.buildFeatureType(); - viewer.setInput(featureType); - } - - @Override - public void focusGained(FocusEvent e) { - int end = nameText.getText().length(); - nameText.setSelection(0, end); - } - - @Override - public void focusLost(FocusEvent e) { - SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); - SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); - ftB.init(ft); - ftB.setName(nameText.getText()); - featureType = ftB.buildFeatureType(); - viewer.setInput(featureType); - } - - } - - nameText.setFocus(); - NameListener listener = new NameListener(); - nameText.addKeyListener(listener); - nameText.addFocusListener(listener); - - } - - /** - * Retrieves the new SimpleFeatureType. Must be called in the display thread. May return null. - * - * @return the new SimpleFeatureType. - */ - public SimpleFeatureType getFeatureType() { - if (viewer == null) { - return null; - } - return (SimpleFeatureType) viewer.getInput(); - } - - /** - * Returns the FeatureTypeBuilder that is used for editing the feature type. - * - * @return the FeatureTypeBuilder that is used for editing the feature type. - */ - public SimpleFeatureTypeBuilder getFeatureTypeBuilder() { - if (viewer == null) { - return null; - } - return builderFromFeatureType((SimpleFeatureType) viewer.getInput()); - } - - /** - * Returns the control that is the FeatureTypeEditor. - * - * @return the control that is the FeatureTypeEditor. - */ - public Control getControl() { - return viewer.getControl(); - } - - /** - * Label provider for labeling AttributeTypes. - * - * @author jones - * @since 1.1.0 - */ - public static class FeatureTypeLabelProvider extends LabelProvider - implements IBaseLabelProvider, ITableLabelProvider { - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - AttributeDescriptor attribute = (AttributeDescriptor) element; - switch (columnIndex) { - case 0: // Attribute Name element - return attribute.getLocalName(); - case 1: // Attribute Type element - return attribute.getType().getBinding().getSimpleName(); - case 2: // Attribute Type element - if (attribute instanceof GeometryDescriptor) { - CoordinateReferenceSystem crs = ((GeometryDescriptor) attribute) - .getCoordinateReferenceSystem(); - if (crs != null) { - return crs.getName().toString(); - } else { - return "Unspecified"; - } - } - break; - case 3: // Attribute Type element - return getAttributeRestriction(attribute, "length", String.class); //$NON-NLS-1$ - case 4: // Attribute Type element - return Boolean.toString(attribute.isNillable()); - - default: - break; - } - return null; - } - - } - - /** - * A Tree Content Provider that serves up attributeTypes from a SimpleFeatureType as a parent. - * - * @author jones - * @since 1.1.0 - */ - public static class FeatureTypeContentProvider implements ITreeContentProvider { - - private TreeViewer viewer; - - public FeatureTypeContentProvider(TreeViewer viewer) { - this.viewer = viewer; - } - - @Override - public void dispose() { - - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - - } - - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof SimpleFeatureType) { - SimpleFeatureType featureType = (SimpleFeatureType) parentElement; - Object[] attributes = new Object[featureType.getAttributeCount()]; - for (int i = 0; i < attributes.length; i++) { - attributes[i] = featureType.getDescriptor(i); - } - return attributes; - } - return null; - } - - @Override - public Object getParent(Object element) { - if (element instanceof AttributeDescriptor) { - return viewer.getInput(); - } - return null; - } - - @Override - public boolean hasChildren(Object element) { - if (element instanceof SimpleFeatureType) { - return true; - } - return false; - } - - @Override - public Object[] getElements(Object inputElement) { - return getChildren(inputElement); - } - - } - - public class AttributeCellModifier implements ICellModifier { - - private Object lastCRS = getDefaultCRS(); - - @Override - public boolean canModify(Object element, String property) { - if (String.valueOf(OTHER_COLUMN).equals(property) - && !(element instanceof GeometryDescriptor)) { - return false; - } - if (String.valueOf(LENGTH_COLUMN).equals(property) && !(ALLOWED_BINDINGS_FOR_LENGHT_SET - .contains(((AttributeDescriptor) element).getType().getBinding()))) { - return false; - } - return true; - } - - @Override - public Object getValue(Object element, String property) { - AttributeDescriptor editElement = (AttributeDescriptor) element; - switch (Integer.parseInt(property)) { - case NAME_COLUMN: - return editElement.getName().toString(); - case TYPE_COLUMN: - for (int i = 0; i < legalTypes.size(); i++) { - if (legalTypes.get(i).getType() == editElement.getType().getBinding()) - return i; - } - return -1; - case OTHER_COLUMN: - return ((GeometryDescriptor) element).getCoordinateReferenceSystem(); - case LENGTH_COLUMN: - String lengthValue = getAttributeRestriction(editElement, "length", String.class); //$NON-NLS-1$ - return lengthValue != null ? lengthValue : ""; - case IS_NULL_COLUMN: - String nullValue = getAttributeRestriction(editElement, "nillable", String.class); //$NON-NLS-1$ - return nullValue == null ? editElement.isNillable() : Boolean.getBoolean(nullValue); - } - - return null; - } - - @Override - public void modify(Object element, String property, Object value) { - if (element == null || property == null || value == null) { - return; - } - - AttributeDescriptor editElement = (AttributeDescriptor) ((TreeItem) element).getData(); - SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); - AttributeDescriptor newAttr = createNewAttributeType(editElement, property, value); - - if (newAttr == null) { - return; - } - int index = 0; - for (; index < ft.getAttributeCount(); index++) { - if (ft.getDescriptor(index) == editElement) { - break; - } - } - if (index == ft.getAttributeCount()) { - return; - } - SimpleFeatureTypeBuilder builder = builderFromFeatureType(ft); - builder.remove(ft.getDescriptor(index).getLocalName()); - builder.add(index, newAttr); - featureType = builder.buildFeatureType(); - viewer.setInput(featureType); - } - - private AttributeDescriptor createNewAttributeType(AttributeDescriptor editElement, - String property, Object value) { - AttributeTypeBuilder builder = new AttributeTypeBuilder(); - builder.init(editElement); - // builder.setName((String)property); - - switch (Integer.parseInt(property)) { - case NAME_COLUMN: - return builder.buildDescriptor((String) value); - case TYPE_COLUMN: - int choice = -1; - if (value instanceof Integer) { - choice = (Integer) value; - } else if (value instanceof String) { - choice = Integer.parseInt((String) value); - } - - if (choice == -1) { - return null; - } else { - Class type = legalTypes.get(choice).getType(); - builder.setBinding(type); - return builder.buildDescriptor(editElement.getLocalName()); - } - case OTHER_COLUMN: - lastCRS = value; - - CoordinateReferenceSystem crs = (CoordinateReferenceSystem) value; - if (FeatureTypeEditor.this.featureType.getGeometryDescriptor() == editElement) { - setDefaultCRS(crs); - } - - builder.setCRS(crs); - return builder.buildDescriptor(editElement.getLocalName()); - case LENGTH_COLUMN: - try { - int length = Integer.parseInt((String) value); - builder.length(length); - return builder.buildDescriptor(editElement.getLocalName()); - } catch (NumberFormatException e) { - // e.printStackTrace(); - return null; - } - case IS_NULL_COLUMN: - boolean isNull = true; - if (value instanceof Boolean) { - isNull = (Boolean) value; - } else if (value instanceof String) { - isNull = Boolean.getBoolean((String) value); - } - builder.nillable(isNull); - builder.setMinOccurs(1); - return builder.buildDescriptor(editElement.getLocalName()); - - default: - return null; - } - } - - } - - /** - * PUBLIC ONLY so tests can verify the correct behaviour. - */ - public TreeViewer testingGetViewer() { - return viewer; - } - - /** - * PUBLIC ONLY so tests can verify the correct behaviour. - */ - public static List testingGetTYPES() { - return TYPES; - } - - public Text testingGetNameText() { - return nameText; - } - - /** - * Updates the viewer so it matches the state of the builder. - */ - public void builderChanged() { - viewer.refresh(); - if (nameText != null && !nameText.isDisposed()) { - if (viewer.getInput() != null) { - String typeName = ((SimpleFeatureType) viewer.getInput()).getTypeName(); - nameText.setText(typeName); - } - } - } - - /** - * - * @param errorMessage - */ - public void setErrorMessage(String errorMessage) { - errorDecorator.setDescriptionText(errorMessage); - errorDecorator.show(); - errorDecorator.showHoverText(errorMessage); - } - - /** - * - * @param editElement - * @param restrictionName - * @param type - * @return - */ - protected static T getAttributeRestriction(AttributeDescriptor editElement, - String restrictionName, Class type) { - if (restrictionName == null) { - return null; - } - for (Filter r : editElement.getType().getRestrictions()) { - if (r instanceof PropertyIsLessThanOrEqualTo) { - PropertyIsLessThanOrEqualTo c = (PropertyIsLessThanOrEqualTo) r; - if (c.getExpression1() instanceof Function && ((Function) c.getExpression1()) - .getName().toLowerCase().endsWith(restrictionName.toLowerCase())) { - if (c.getExpression2() instanceof Literal) { - T value = c.getExpression2().evaluate(null, type); - if (value != null) { - return value; - } - } - } - } - } - return null; - } -} +/** + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ComboBoxCellEditor; +import org.eclipse.jface.viewers.DialogCellEditor; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.ICellModifier; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.ActionFactory; +import org.geotools.feature.AttributeTypeBuilder; +import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.MultiLineString; +import org.locationtech.jts.geom.MultiPoint; +import org.locationtech.jts.geom.MultiPolygon; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.locationtech.udig.ui.preferences.PreferenceConstants; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.AttributeDescriptor; +import org.opengis.feature.type.FeatureType; +import org.opengis.feature.type.GeometryDescriptor; +import org.opengis.filter.Filter; +import org.opengis.filter.PropertyIsLessThanOrEqualTo; +import org.opengis.filter.expression.Function; +import org.opengis.filter.expression.Literal; +import org.opengis.metadata.Identifier; +import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +/** + * A composite editor based on a JFace TreeViewer for creating and editing feature types. + * + * @author jones + * @author Andrea Antonello (www.hydrologis.com) + * @since 1.1.0 + */ +public class FeatureTypeEditor { + + private static final int MAX_ATTRIBUTE_LENGTH = 10485759; // Maximum allows by postgis and is + // "big enough" + + private static final List ALLOWED_BINDINGS_FOR_LENGHT_SET = Arrays.asList(String.class, + Double.class, Long.class, Integer.class, Short.class); + + /** + * The index of the name column in the viewer. + */ + private static final int NAME_COLUMN = 0; + + /** + * The index of the type column in the viewer. + */ + private static final int TYPE_COLUMN = 1; + + /** + * The index of the type column in the viewer. + */ + private static final int OTHER_COLUMN = 2; + + /** + * The index of the length column in the viewer. + */ + private static final int LENGTH_COLUMN = 3; + + /** + * The index of the NULL column in the viewer. + */ + private static final int IS_NULL_COLUMN = 4; + + private static final List TYPES; + static { + List types = new ArrayList<>(); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_stringType, String.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_booleanType, Boolean.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_dateType, Date.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_integerType, Integer.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_longType, Long.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_floatType, Float.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_doubleType, Double.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_pointType, Point.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_lineStringType, + LineString.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_polygonType, Polygon.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_geometryType, Geometry.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_multiPointType, + MultiPoint.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_multiLineStringType, + MultiLineString.class)); + types.add(new LegalAttributeTypes(Messages.FeatureTypeEditor_multiPolygonType, + MultiPolygon.class)); + + TYPES = Collections.unmodifiableList(types); + } + + private TreeViewer viewer; + + private IAction createAttributeAction; + + private IAction deleteAttributeAction; + + private Text nameText; + + private List legalTypes = TYPES; + + private SimpleFeatureType featureType; + + private ControlDecoration errorDecorator; + + /** + * Create the table control and set the input. + * + * @param parent the composite that will be used as the TreeViewer's parent. + * @param layoutData the layout data to use to layout the editor. If null GridData(Fill_Both) + */ + public void createTable(Composite parent, Object layoutData) { + createTable(parent, layoutData, featureType, true); + } + + /** + * Create the table control and set the input. + * + * @param parent the composite that will be used as the TreeViewer's parent. + * @param layoutData the layout data to use to layout the editor. If null GridData(Fill_Both) + */ + public void createTable(Composite parent, Object layoutData, SimpleFeatureType type) { + SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); + builder.setName(type.getName()); + builder.init(type); + createTable(parent, layoutData, builder.buildFeatureType(), true); + } + + /** + * Create the table control and set the input. + * + * @param parent the composite that will be used as the TreeViewer's parent. + * @param layoutData the layout data to use to layout the editor. If null GridData(Fill_Both). + * @param featureType the {@link FeatureType} to use to populate the table. + * @param editable the editable flag of the table + */ + public void createTable(Composite parent, Object layoutData, SimpleFeatureType featureType, + boolean editable) { + + viewer = new TreeViewer(parent, SWT.FULL_SELECTION); + + Tree tree = viewer.getTree(); + if (layoutData == null) + tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + else + tree.setLayoutData(layoutData); + + tree.setHeaderVisible(true); + TableLayout tableLayout = new TableLayout(); + tableLayout.addColumnData(new ColumnWeightData(1)); + tableLayout.addColumnData(new ColumnWeightData(1)); + tableLayout.addColumnData(new ColumnWeightData(1)); + tableLayout.addColumnData(new ColumnWeightData(1)); + tableLayout.addColumnData(new ColumnWeightData(1)); + + tree.setLayout(tableLayout); + + TreeColumn column = new TreeColumn(tree, SWT.CENTER); + column.setResizable(true); + column.setText(Messages.FeatureTypeEditor_nameColumnName); + + column = new TreeColumn(tree, SWT.CENTER); + column.setResizable(true); + column.setText(Messages.FeatureTypeEditor_typeColumnName); + + column = new TreeColumn(tree, SWT.CENTER); + column.setResizable(true); + + column = new TreeColumn(tree, SWT.CENTER); + column.setResizable(true); + column.setText(Messages.FeatureTypeEditor_lengthColumnName); + + column = new TreeColumn(tree, SWT.CENTER); + column.setResizable(true); + column.setText(Messages.FeatureTypeEditor_isNullColumnName); + + viewer.setContentProvider(new FeatureTypeContentProvider(viewer)); + viewer.setLabelProvider(new FeatureTypeLabelProvider()); + viewer.setColumnProperties(new String[] { String.valueOf(NAME_COLUMN), + String.valueOf(TYPE_COLUMN), String.valueOf(OTHER_COLUMN), + String.valueOf(LENGTH_COLUMN), String.valueOf(IS_NULL_COLUMN) }); + + setEditable(editable); + setFeatureType(featureType); + } + + /** + * Declares what types are permitted as attributes. For example Shapefiles do not permit + * Geometry as a legal type. + * + * @param legalTypes the List of legal types in the order they will be displayed. + */ + public void setLegalTypes(List legalTypes) { + this.legalTypes = Collections.unmodifiableList(legalTypes); + } + + /** + * @return Returns the list of types that this editor will allow the use to select + */ + public List getLegalTypes() { + return Collections.unmodifiableList(legalTypes); + } + + /** + * Sets whether the table is editable or just a viewer. + * + * @param editable if true then the table can be edited + */ + public void setEditable(boolean editable) { + if (editable) { + Tree tree = viewer.getTree(); + String[] comboItems = new String[legalTypes.size()]; + for (int i = 0; i < comboItems.length; i++) { + comboItems[i] = legalTypes.get(i).getName(); + } + + TextCellEditor attributeNameEditor = new TextCellEditor(tree); + ComboBoxCellEditor attributeTypeEditor = new ComboBoxCellEditor(tree, comboItems, + SWT.READ_ONLY | SWT.FULL_SELECTION); + TextCellEditor attributeLengthEditor = new TextCellEditor(tree); + BooleanCellEditor attributeIsNullEditor = new BooleanCellEditor(tree); + DialogCellEditor crsEditor = createCRSEditor(tree); + viewer.setCellEditors(new CellEditor[] { attributeNameEditor, attributeTypeEditor, + crsEditor, attributeLengthEditor, attributeIsNullEditor }); + + viewer.setCellModifier(new AttributeCellModifier()); + } else { + viewer.setCellEditors(null); + viewer.setCellModifier(null); + } + } + + private DialogCellEditor createCRSEditor(Tree tree) { + return new CRSDialogCellEditor(tree); + } + + public SimpleFeatureTypeBuilder builderFromFeatureType(SimpleFeatureType ft) { + SimpleFeatureTypeBuilder ftB; + ftB = new SimpleFeatureTypeBuilder(); + ftB.init(ft); + ftB.setName(ft.getName()); + return ftB; + } + + /** + * Creates a ContextMenu (the menu is created using the Table's composite as a parent) and + * returns the contextMenu. + * + *

    + * It is recommended that the MenuManager be registered with an IWorkbenchPartSite + *

    + * + * @return a MenuManager for the contextMenu. + */ + public MenuManager createContextMenu() { + final MenuManager contextMenu = new MenuManager(); + + contextMenu.setRemoveAllWhenShown(true); + contextMenu.addMenuListener(new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager mgr) { + contextMenu.add(getCreateAttributeAction()); + contextMenu.add(getDeleteAction()); + } + }); + + Menu menu = contextMenu.createContextMenu(viewer.getTree()); + viewer.getControl().setMenu(menu); + + return contextMenu; + } + + /** + * Sets the Global actions that apply. IE sets the delete global action. + * + * @param actionBars + */ + public void setGlobalActions(IActionBars actionBars) { + actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), getDeleteAction()); + } + + /** + * Sets the {@link SimpleFeatureType} being edited. + * + *

    + * If type is null then a new featureType is created. Must be called in the display thread. + *

    + * + * @param type then new SimpleFeatureType to be edited, or null to create a new type. + */ + public void setFeatureType(SimpleFeatureType type) { + SimpleFeatureTypeBuilder builder = null; + if (type != null) { + builder = new SimpleFeatureTypeBuilder(); + builder.init(type); + builder.setName(type.getName()); + featureType = builder.buildFeatureType(); + } else { + featureType = createDefaultFeatureType(); + } + if (viewer != null) { + setInput(featureType); + } + + } + + /** + * Sets the FeatureTypeBuilder used for creating the feature type. + * + * @param builder + * @deprecated with the new {@link SimpleFeatureTypeBuilder} this is no more possible, therefore + * deprecating. + */ + @Deprecated + public final void setFeatureTypeBuilder(SimpleFeatureTypeBuilder newBuilder) { + + } + + /** + * Creates a default {@link FeatureType}. + * + *

    + * The default type has a {@link Geometry} attribute and a name + * attribute. + * The geometry attribute is a {@link LineString}. + *

    + * + * @return a default FeatureType. + */ + public SimpleFeatureType createDefaultFeatureType() { + SimpleFeatureTypeBuilder builder; + builder = new SimpleFeatureTypeBuilder(); + builder.setName(Messages.FeatureTypeEditor_newFeatureTypeName); + builder.setCRS(getDefaultCRS()); + // no need to provide a default length since length can be specified via the UI + //builder.length(MAX_ATTRIBUTE_LENGTH).add(Messages.FeatureTypeEditor_defaultNameAttributeName, String.class); + // String.class); + builder.add(Messages.FeatureTypeEditor_defaultNameAttributeName, String.class); + + // add geometry attribute as not null + AttributeTypeBuilder attribBuilder = new AttributeTypeBuilder(); + attribBuilder.setName(Messages.FeatureTypeEditor_defaultGeometryName); + attribBuilder.setCRS(builder.getCRS()); + attribBuilder.nillable(false); + attribBuilder.binding(LineString.class); + builder.add(attribBuilder.buildDescriptor(Messages.FeatureTypeEditor_defaultGeometryName)); + return builder.buildFeatureType(); + } + + private CoordinateReferenceSystem getDefaultCRS() { + String crsInfo = UiPlugin.getDefault().getPreferenceStore() + .getString(PreferenceConstants.P_DEFAULT_GEOMEMTRY_CRS); + if (crsInfo != null && crsInfo.trim().length() > 0) { + try { + crsInfo = crsInfo.trim(); + if (crsInfo.startsWith("EPSG")) { //$NON-NLS-1$ + return CRS.decode(crsInfo); + } + return CRS.parseWKT(crsInfo); + } catch (Throwable t) { + LoggingSupport.log(UiPlugin.getDefault(),t); + } + } + return DefaultGeographicCRS.WGS84; + } + + public void setDefaultCRS(CoordinateReferenceSystem crs) { + String crsInfo = null; + + Set identifiers = crs.getIdentifiers(); + for (Identifier identifier : identifiers) { + if (identifier.toString().startsWith("EPSG")) { //$NON-NLS-1$ + crsInfo = identifier.toString(); + break; + } + } + + if (crsInfo == null) + crsInfo = crs.toWKT(); + + UiPlugin.getDefault().getPreferenceStore() + .setValue(PreferenceConstants.P_DEFAULT_GEOMEMTRY_CRS, crsInfo); + + SimpleFeatureTypeBuilder tmpBuilder = new SimpleFeatureTypeBuilder(); + tmpBuilder.init(featureType); + tmpBuilder.setName(featureType.getTypeName()); + tmpBuilder.setCRS(crs); + featureType = tmpBuilder.buildFeatureType(); + + } + + private void setInput(SimpleFeatureType featureType) { + viewer.setInput(featureType); + if (nameText != null && !nameText.isDisposed()) { + nameText.setText(featureType.getTypeName()); + } + } + + /** + * Returns an action that will add a new attribute to the SimpleFeatureType. + * + * @return an action that will add a new attribute to the SimpleFeatureType. + */ + public synchronized IAction getCreateAttributeAction() { + if (createAttributeAction == null) { + createAttributeAction = new Action() { + @Override + public void runWithEvent(Event event) { + SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); + SimpleFeatureTypeBuilder ftB = builderFromFeatureType(ft); + + int index = 0; + List usedIndices = new ArrayList<>(); + + // get max Index of added attributes + for (AttributeDescriptor at : ft.getAttributeDescriptors()) { + if (at.getLocalName().startsWith( + Messages.FeatureTypeEditor_newAttributeTypeDefaultName)) { + try { + usedIndices.add(Integer.valueOf(at.getLocalName().replace( + Messages.FeatureTypeEditor_newAttributeTypeDefaultName, + ""))); //$NON-NLS-1$ + } catch (Exception e) { + // ignore, user has changed attribute + } + index++; + + } + } + + Collections.sort(usedIndices, Collections.reverseOrder()); + // TODO improve : implement algorithm to find first unused number in sorted list + if (!usedIndices.isEmpty()) { + index = usedIndices.get(0) + 1; // reverse ordered, highest first + } + + ftB.add(Messages.FeatureTypeEditor_newAttributeTypeDefaultName + index, + String.class); + featureType = ftB.buildFeatureType(); + viewer.setInput(featureType); + // TODO check if it is better to do something and then: viewer.refresh(false); + } + }; + createAttributeAction + .setId("org.locationtech.udig.ui.FeatureTypeEditor.createAttributeAction"); //$NON-NLS-1$ + createAttributeAction.setText(Messages.addAttributeAction_label); + createAttributeAction.setToolTipText(Messages.addAttributeAction_label); + createAttributeAction.setImageDescriptor( + UiPlugin.getDefault().getImageDescriptor("elcl16/new_attribute.gif")); //$NON-NLS-1$ + } + return createAttributeAction; + } + + /** + * Returns an action that will delete the selected attributes from the SimpleFeatureType. + * + * @return an action that will delete the selected attributes from the SimpleFeatureType. + */ + public synchronized IAction getDeleteAction() { + if (deleteAttributeAction == null) { + deleteAttributeAction = new Action() { + + @SuppressWarnings("unchecked") + @Override + public void runWithEvent(Event event) { + SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); + SimpleFeatureTypeBuilder ftB = builderFromFeatureType(ft); + IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); + for (Iterator iter = selection.iterator(); iter + .hasNext();) { + AttributeDescriptor element = iter.next(); + ftB.remove(element.getLocalName()); + } + featureType = ftB.buildFeatureType(); + viewer.setInput(featureType); + } + }; + deleteAttributeAction.setText(Messages.deleteAttributeAction_label); + deleteAttributeAction.setToolTipText(Messages.deleteAttributeAction_tooltip); + deleteAttributeAction.setImageDescriptor( + UiPlugin.getDefault().getImageDescriptor("elcl16/delete.gif")); //$NON-NLS-1$ + deleteAttributeAction.setDescription(Messages.deleteAttributeAction_description); + deleteAttributeAction + .setId("org.locationtech.udig.ui.FeatureTypeEditor.deleteAttributeAction"); //$NON-NLS-1$ + } + return deleteAttributeAction; + } + + /** + * Creates a Text input object that for modify the feature type name. + * + * @param parent the parent of the text object + * @return + */ + public void createFeatureTypeNameText(Composite parent, Object layoutData) { + + nameText = new Text(parent, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + errorDecorator = new ControlDecoration(nameText, SWT.TOP | SWT.LEFT); + Image image = PlatformUI.getWorkbench().getSharedImages() + .getImage(ISharedImages.IMG_DEC_FIELD_ERROR); + errorDecorator.setImage(image); + + if (viewer != null) { + SimpleFeatureType input = ((SimpleFeatureType) viewer.getInput()); + if (input != null) { + nameText.setText(input.getTypeName()); + } + } + if (layoutData != null) { + nameText.setLayoutData(layoutData); + } else { + nameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + } + + class NameListener implements KeyListener, FocusListener { + + @Override + public void keyPressed(KeyEvent e) { + SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); + if (e.character == SWT.ESC) { + nameText.setText(ft.getTypeName()); + } else if (e.character == SWT.Selection) { + SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); + ftB.init(ft); + ftB.setName(nameText.getText()); + featureType = ftB.buildFeatureType(); + viewer.setInput(featureType); + } else { + errorDecorator.hide(); + } + } + + @Override + public void keyReleased(KeyEvent e) { + SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); + SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); + ftB.init(ft); + ftB.setName(nameText.getText()); + featureType = ftB.buildFeatureType(); + viewer.setInput(featureType); + } + + @Override + public void focusGained(FocusEvent e) { + int end = nameText.getText().length(); + nameText.setSelection(0, end); + } + + @Override + public void focusLost(FocusEvent e) { + SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); + SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); + ftB.init(ft); + ftB.setName(nameText.getText()); + featureType = ftB.buildFeatureType(); + viewer.setInput(featureType); + } + + } + + nameText.setFocus(); + NameListener listener = new NameListener(); + nameText.addKeyListener(listener); + nameText.addFocusListener(listener); + + } + + /** + * Retrieves the new SimpleFeatureType. Must be called in the display thread. May return null. + * + * @return the new SimpleFeatureType. + */ + public SimpleFeatureType getFeatureType() { + if (viewer == null) { + return null; + } + return (SimpleFeatureType) viewer.getInput(); + } + + /** + * Returns the FeatureTypeBuilder that is used for editing the feature type. + * + * @return the FeatureTypeBuilder that is used for editing the feature type. + */ + public SimpleFeatureTypeBuilder getFeatureTypeBuilder() { + if (viewer == null) { + return null; + } + return builderFromFeatureType((SimpleFeatureType) viewer.getInput()); + } + + /** + * Returns the control that is the FeatureTypeEditor. + * + * @return the control that is the FeatureTypeEditor. + */ + public Control getControl() { + return viewer.getControl(); + } + + /** + * Label provider for labeling AttributeTypes. + * + * @author jones + * @since 1.1.0 + */ + public static class FeatureTypeLabelProvider extends LabelProvider + implements IBaseLabelProvider, ITableLabelProvider { + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + @Override + public String getColumnText(Object element, int columnIndex) { + AttributeDescriptor attribute = (AttributeDescriptor) element; + switch (columnIndex) { + case 0: // Attribute Name element + return attribute.getLocalName(); + case 1: // Attribute Type element + return attribute.getType().getBinding().getSimpleName(); + case 2: // Attribute Type element + if (attribute instanceof GeometryDescriptor) { + CoordinateReferenceSystem crs = ((GeometryDescriptor) attribute) + .getCoordinateReferenceSystem(); + if (crs != null) { + return crs.getName().toString(); + } else { + return "Unspecified"; + } + } + break; + case 3: // Attribute Type element + return getAttributeRestriction(attribute, "length", String.class); //$NON-NLS-1$ + case 4: // Attribute Type element + return Boolean.toString(attribute.isNillable()); + + default: + break; + } + return null; + } + + } + + /** + * A Tree Content Provider that serves up attributeTypes from a SimpleFeatureType as a parent. + * + * @author jones + * @since 1.1.0 + */ + public static class FeatureTypeContentProvider implements ITreeContentProvider { + + private TreeViewer viewer; + + public FeatureTypeContentProvider(TreeViewer viewer) { + this.viewer = viewer; + } + + @Override + public void dispose() { + + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof SimpleFeatureType) { + SimpleFeatureType featureType = (SimpleFeatureType) parentElement; + Object[] attributes = new Object[featureType.getAttributeCount()]; + for (int i = 0; i < attributes.length; i++) { + attributes[i] = featureType.getDescriptor(i); + } + return attributes; + } + return null; + } + + @Override + public Object getParent(Object element) { + if (element instanceof AttributeDescriptor) { + return viewer.getInput(); + } + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof SimpleFeatureType) { + return true; + } + return false; + } + + @Override + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + } + + public class AttributeCellModifier implements ICellModifier { + + private Object lastCRS = getDefaultCRS(); + + @Override + public boolean canModify(Object element, String property) { + if (String.valueOf(OTHER_COLUMN).equals(property) + && !(element instanceof GeometryDescriptor)) { + return false; + } + if (String.valueOf(LENGTH_COLUMN).equals(property) && !(ALLOWED_BINDINGS_FOR_LENGHT_SET + .contains(((AttributeDescriptor) element).getType().getBinding()))) { + return false; + } + return true; + } + + @Override + public Object getValue(Object element, String property) { + AttributeDescriptor editElement = (AttributeDescriptor) element; + switch (Integer.parseInt(property)) { + case NAME_COLUMN: + return editElement.getName().toString(); + case TYPE_COLUMN: + for (int i = 0; i < legalTypes.size(); i++) { + if (legalTypes.get(i).getType() == editElement.getType().getBinding()) + return i; + } + return -1; + case OTHER_COLUMN: + return ((GeometryDescriptor) element).getCoordinateReferenceSystem(); + case LENGTH_COLUMN: + String lengthValue = getAttributeRestriction(editElement, "length", String.class); //$NON-NLS-1$ + return lengthValue != null ? lengthValue : ""; + case IS_NULL_COLUMN: + String nullValue = getAttributeRestriction(editElement, "nillable", String.class); //$NON-NLS-1$ + return nullValue == null ? editElement.isNillable() : Boolean.getBoolean(nullValue); + } + + return null; + } + + @Override + public void modify(Object element, String property, Object value) { + if (element == null || property == null || value == null) { + return; + } + + AttributeDescriptor editElement = (AttributeDescriptor) ((TreeItem) element).getData(); + SimpleFeatureType ft = (SimpleFeatureType) viewer.getInput(); + AttributeDescriptor newAttr = createNewAttributeType(editElement, property, value); + + if (newAttr == null) { + return; + } + int index = 0; + for (; index < ft.getAttributeCount(); index++) { + if (ft.getDescriptor(index) == editElement) { + break; + } + } + if (index == ft.getAttributeCount()) { + return; + } + SimpleFeatureTypeBuilder builder = builderFromFeatureType(ft); + builder.remove(ft.getDescriptor(index).getLocalName()); + builder.add(index, newAttr); + featureType = builder.buildFeatureType(); + viewer.setInput(featureType); + } + + private AttributeDescriptor createNewAttributeType(AttributeDescriptor editElement, + String property, Object value) { + AttributeTypeBuilder builder = new AttributeTypeBuilder(); + builder.init(editElement); + // builder.setName((String)property); + + switch (Integer.parseInt(property)) { + case NAME_COLUMN: + return builder.buildDescriptor((String) value); + case TYPE_COLUMN: + int choice = -1; + if (value instanceof Integer) { + choice = (Integer) value; + } else if (value instanceof String) { + choice = Integer.parseInt((String) value); + } + + if (choice == -1) { + return null; + } else { + Class type = legalTypes.get(choice).getType(); + builder.setBinding(type); + return builder.buildDescriptor(editElement.getLocalName()); + } + case OTHER_COLUMN: + lastCRS = value; + + CoordinateReferenceSystem crs = (CoordinateReferenceSystem) value; + if (FeatureTypeEditor.this.featureType.getGeometryDescriptor() == editElement) { + setDefaultCRS(crs); + } + + builder.setCRS(crs); + return builder.buildDescriptor(editElement.getLocalName()); + case LENGTH_COLUMN: + try { + int length = Integer.parseInt((String) value); + builder.length(length); + return builder.buildDescriptor(editElement.getLocalName()); + } catch (NumberFormatException e) { + // e.printStackTrace(); + return null; + } + case IS_NULL_COLUMN: + boolean isNull = true; + if (value instanceof Boolean) { + isNull = (Boolean) value; + } else if (value instanceof String) { + isNull = Boolean.getBoolean((String) value); + } + builder.nillable(isNull); + builder.setMinOccurs(1); + return builder.buildDescriptor(editElement.getLocalName()); + + default: + return null; + } + } + + } + + /** + * PUBLIC ONLY so tests can verify the correct behaviour. + */ + public TreeViewer testingGetViewer() { + return viewer; + } + + /** + * PUBLIC ONLY so tests can verify the correct behaviour. + */ + public static List testingGetTYPES() { + return TYPES; + } + + public Text testingGetNameText() { + return nameText; + } + + /** + * Updates the viewer so it matches the state of the builder. + */ + public void builderChanged() { + viewer.refresh(); + if (nameText != null && !nameText.isDisposed()) { + if (viewer.getInput() != null) { + String typeName = ((SimpleFeatureType) viewer.getInput()).getTypeName(); + nameText.setText(typeName); + } + } + } + + /** + * + * @param errorMessage + */ + public void setErrorMessage(String errorMessage) { + errorDecorator.setDescriptionText(errorMessage); + errorDecorator.show(); + errorDecorator.showHoverText(errorMessage); + } + + /** + * + * @param editElement + * @param restrictionName + * @param type + * @return + */ + protected static T getAttributeRestriction(AttributeDescriptor editElement, + String restrictionName, Class type) { + if (restrictionName == null) { + return null; + } + for (Filter r : editElement.getType().getRestrictions()) { + if (r instanceof PropertyIsLessThanOrEqualTo) { + PropertyIsLessThanOrEqualTo c = (PropertyIsLessThanOrEqualTo) r; + if (c.getExpression1() instanceof Function && ((Function) c.getExpression1()) + .getName().toLowerCase().endsWith(restrictionName.toLowerCase())) { + if (c.getExpression2() instanceof Literal) { + T value = c.getExpression2().evaluate(null, type); + if (value != null) { + return value; + } + } + } + } + } + return null; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditorDialog.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditorDialog.java index 1746d87e93..200c3ab435 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditorDialog.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/FeatureTypeEditorDialog.java @@ -1,246 +1,246 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; - -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.resource.ImageRegistry; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.geotools.data.DataStore; -import org.geotools.data.shapefile.ShapefileDataStore; -import org.geotools.feature.SchemaException; -import org.geotools.feature.simple.SimpleFeatureTypeBuilder; -import org.opengis.feature.simple.SimpleFeatureType; -import org.opengis.feature.type.FeatureType; - -import org.locationtech.jts.geom.Geometry; - -/** - * Opens a dialog that allows a SimpleFeatureType to be defined. - * - * @author Jesse - * @author Andrea Antonello (www.hydrologis.com) - * @since 1.1.0 - */ -public class FeatureTypeEditorDialog extends Dialog { - final FeatureTypeEditor editor; - private SimpleFeatureType defaultFeatureType; - private DataStore dataStore; - private SimpleFeatureType result; - private ValidateFeatureType validateFeatureType; - - public FeatureTypeEditorDialog( Shell parentShell, ValidateFeatureType strategy ) { - super(parentShell); - editor = new FeatureTypeEditor(); - defaultFeatureType=editor.createDefaultFeatureType(); - this.validateFeatureType=strategy; - setShellStyle(SWT.RESIZE|SWT.DIALOG_TRIM|SWT.CLOSE); - } - - @Override - protected Control createDialogArea( Composite parent ) { - getShell().setText(Messages.FeatureTypeEditorDialog_ShellTitle); - Composite composite=new Composite(parent, SWT.NONE); - GridLayout gridLayout = new GridLayout(8, false); - gridLayout.marginWidth=0; - gridLayout.marginHeight=0; - - composite.setLayout(gridLayout); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - editor.createFeatureTypeNameText(composite, new GridData(SWT.FILL, SWT.FILL, true,false, 8,1)); - - Composite buttons=new Composite(composite, SWT.NONE); - gridLayout = new GridLayout(); - gridLayout.marginWidth=0; - gridLayout.marginHeight=0; - gridLayout.horizontalSpacing=0; - gridLayout.verticalSpacing=0; - buttons.setLayout(gridLayout); - GridData gridData = new GridData(SWT.FILL, SWT.FILL, false,true, 1,1); - gridData.widthHint=32; - buttons.setLayoutData(gridData); - createButton(buttons, editor.getCreateAttributeAction()); - createButton(buttons, editor.getDeleteAction()); - - editor.createTable(composite, new GridData(SWT.FILL, SWT.FILL, true,true, 7,1), - defaultFeatureType, true); - editor.createContextMenu(); - - return composite; - } - - private void createButton( Composite composite, final IAction action ) { - final Button button = new Button(composite, SWT.PUSH | SWT.FLAT); - GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); - button.setLayoutData(data); - button.setToolTipText(action.getToolTipText()); - - ImageRegistry images = UiPlugin.getDefault().getImageRegistry(); - Image image = images.get(action.getId()); - if (image == null || image.isDisposed()) { - images.put(action.getId(), action.getImageDescriptor()); - image = images.get(action.getId()); - } - button.setImage(image); - - button.addListener(SWT.Selection, new Listener(){ - public void handleEvent( Event event ) { - action.runWithEvent(event); - } - }); - } - - @Override - protected Point getInitialSize() { - return new Point(500, 500); - } - - @Override - public boolean close() { - result = editor.getFeatureType(); - editor.getControl().setFocus(); - return super.close(); - } - - public void setDataStore(DataStore dataStore){ - this.dataStore=dataStore; - if( dataStore instanceof ShapefileDataStore ){ - List list=new ArrayList(editor.getLegalTypes()); - for( Iterator iter=list.iterator(); iter.hasNext(); ){ - LegalAttributeTypes type=iter.next(); - if( type.getType()==Geometry.class ){ - iter.remove(); - } - } - editor.setLegalTypes(list); - } - } - - @Override - protected void okPressed() { - String errorMessage = validateFeatureType.validate(editor.getFeatureType()); - if( errorMessage != null ){ - editor.setErrorMessage(errorMessage); - }else{ - editor.builderChanged(); - super.okPressed(); - } - } - - public FeatureTypeEditor getEditor() { - return editor; - } - - @Override - public int open() { - result=null; - return super.open(); - } - - /** - * Returns the feature type defined by user or null if it is not a legal feature type for the setDataStore. - * - *

    If setDataStore has previously been called then the feature typename - * will be checked to determine if the typename already exists. - * If it does then null is returned and the dialog should be opened a - * second time.

    - * - * @param checkForDuplicateFeatureType If true null will be returned if - * the datastore has a feature type with the same - * feature type name. - * @return the feature type defined by user - */ - public SimpleFeatureType getFeatureType(boolean checkForDuplicateFeatureType) { - if (result!=null) { - try { - if (!checkForDuplicateFeatureType || isFeatureTypeOK()) { - return result; - } - } catch (SchemaException e) { - UiPlugin.log("Error creating feature type", e); //$NON-NLS-1$ - } - } - return null; - - } - - private boolean isFeatureTypeOK( ) throws SchemaException { - if( dataStore==null ) - return true; - try { - // verify that the typename does not already exist. if it doesn't - // getSchema throws an exception - dataStore.getSchema(defaultFeatureType.getName()); - - /* - * FIXME not sure if it is enough to recreate the featureType, or if - * somewhere the reference to the old object is needed. - */ - SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); - ftB.setName(Messages.NewFeatureTypeOp_duplicateTypeName); - ftB.init(defaultFeatureType); - defaultFeatureType = ftB.buildFeatureType(); - return false; - } catch (IOException e) { - return true; - } - } - - /** - * Validates the feature type to determine whether it is acceptable and can be created. - * - *

    This is used to determine if the dialog can close.

    - * - * @author Jesse - * @author Andrea Antonello (www.hydrologis.com) - * @since 1.2 - */ - public interface ValidateFeatureType { - /** - * Returns true if the feature type builder is ok and the dialog may close. - * - *

    Changes to the builder will be reflected in the dialog.

    - * - * @param featureType the {@link FeatureType} to validate. - * @return null if the feature type is ok and the dialog may close, otherwise an error message - */ - String validate(SimpleFeatureType featureType); - } - - public SimpleFeatureTypeBuilder getDefaultBuilder() { - SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); - ftB.setName(defaultFeatureType.getName()); - ftB.init(defaultFeatureType); - return ftB; - } - - public void setDefaultFeatureType(SimpleFeatureType defaultFeatureType) { - this.defaultFeatureType = defaultFeatureType; - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.geotools.data.DataStore; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.feature.SchemaException; +import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.FeatureType; + +/** + * Opens a dialog that allows a SimpleFeatureType to be defined. + * + * @author Jesse + * @author Andrea Antonello (www.hydrologis.com) + * @since 1.1.0 + */ +public class FeatureTypeEditorDialog extends Dialog { + final FeatureTypeEditor editor; + private SimpleFeatureType defaultFeatureType; + private DataStore dataStore; + private SimpleFeatureType result; + private ValidateFeatureType validateFeatureType; + + public FeatureTypeEditorDialog( Shell parentShell, ValidateFeatureType strategy ) { + super(parentShell); + editor = new FeatureTypeEditor(); + defaultFeatureType=editor.createDefaultFeatureType(); + this.validateFeatureType=strategy; + setShellStyle(SWT.RESIZE|SWT.DIALOG_TRIM|SWT.CLOSE); + } + + @Override + protected Control createDialogArea( Composite parent ) { + getShell().setText(Messages.FeatureTypeEditorDialog_ShellTitle); + Composite composite=new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(8, false); + gridLayout.marginWidth=0; + gridLayout.marginHeight=0; + + composite.setLayout(gridLayout); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + editor.createFeatureTypeNameText(composite, new GridData(SWT.FILL, SWT.FILL, true,false, 8,1)); + + Composite buttons=new Composite(composite, SWT.NONE); + gridLayout = new GridLayout(); + gridLayout.marginWidth=0; + gridLayout.marginHeight=0; + gridLayout.horizontalSpacing=0; + gridLayout.verticalSpacing=0; + buttons.setLayout(gridLayout); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, false,true, 1,1); + gridData.widthHint=32; + buttons.setLayoutData(gridData); + createButton(buttons, editor.getCreateAttributeAction()); + createButton(buttons, editor.getDeleteAction()); + + editor.createTable(composite, new GridData(SWT.FILL, SWT.FILL, true,true, 7,1), + defaultFeatureType, true); + editor.createContextMenu(); + + return composite; + } + + private void createButton( Composite composite, final IAction action ) { + final Button button = new Button(composite, SWT.PUSH | SWT.FLAT); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); + button.setLayoutData(data); + button.setToolTipText(action.getToolTipText()); + + ImageRegistry images = UiPlugin.getDefault().getImageRegistry(); + Image image = images.get(action.getId()); + if (image == null || image.isDisposed()) { + images.put(action.getId(), action.getImageDescriptor()); + image = images.get(action.getId()); + } + button.setImage(image); + + button.addListener(SWT.Selection, new Listener(){ + @Override + public void handleEvent( Event event ) { + action.runWithEvent(event); + } + }); + } + + @Override + protected Point getInitialSize() { + return new Point(500, 500); + } + + @Override + public boolean close() { + result = editor.getFeatureType(); + editor.getControl().setFocus(); + return super.close(); + } + + public void setDataStore(DataStore dataStore){ + this.dataStore=dataStore; + if( dataStore instanceof ShapefileDataStore ){ + List list=new ArrayList<>(editor.getLegalTypes()); + for( Iterator iter=list.iterator(); iter.hasNext(); ){ + LegalAttributeTypes type=iter.next(); + if( type.getType()==Geometry.class ){ + iter.remove(); + } + } + editor.setLegalTypes(list); + } + } + + @Override + protected void okPressed() { + String errorMessage = validateFeatureType.validate(editor.getFeatureType()); + if( errorMessage != null ){ + editor.setErrorMessage(errorMessage); + }else{ + editor.builderChanged(); + super.okPressed(); + } + } + + public FeatureTypeEditor getEditor() { + return editor; + } + + @Override + public int open() { + result=null; + return super.open(); + } + + /** + * Returns the feature type defined by user or null if it is not a legal feature type for the setDataStore. + * + *

    If setDataStore has previously been called then the feature typename + * will be checked to determine if the typename already exists. + * If it does then null is returned and the dialog should be opened a + * second time.

    + * + * @param checkForDuplicateFeatureType If true null will be returned if + * the datastore has a feature type with the same + * feature type name. + * @return the feature type defined by user + */ + public SimpleFeatureType getFeatureType(boolean checkForDuplicateFeatureType) { + if (result!=null) { + try { + if (!checkForDuplicateFeatureType || isFeatureTypeOK()) { + return result; + } + } catch (SchemaException e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error creating feature type", e); //$NON-NLS-1$ + } + } + return null; + + } + + private boolean isFeatureTypeOK( ) throws SchemaException { + if( dataStore==null ) + return true; + try { + // verify that the typename does not already exist. if it doesn't + // getSchema throws an exception + dataStore.getSchema(defaultFeatureType.getName()); + + /* + * FIXME not sure if it is enough to recreate the featureType, or if + * somewhere the reference to the old object is needed. + */ + SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); + ftB.setName(Messages.NewFeatureTypeOp_duplicateTypeName); + ftB.init(defaultFeatureType); + defaultFeatureType = ftB.buildFeatureType(); + return false; + } catch (IOException e) { + return true; + } + } + + /** + * Validates the feature type to determine whether it is acceptable and can be created. + * + *

    This is used to determine if the dialog can close.

    + * + * @author Jesse + * @author Andrea Antonello (www.hydrologis.com) + * @since 1.2 + */ + public interface ValidateFeatureType { + /** + * Returns true if the feature type builder is ok and the dialog may close. + * + *

    Changes to the builder will be reflected in the dialog.

    + * + * @param featureType the {@link FeatureType} to validate. + * @return null if the feature type is ok and the dialog may close, otherwise an error message + */ + String validate(SimpleFeatureType featureType); + } + + public SimpleFeatureTypeBuilder getDefaultBuilder() { + SimpleFeatureTypeBuilder ftB = new SimpleFeatureTypeBuilder(); + ftB.setName(defaultFeatureType.getName()); + ftB.init(defaultFeatureType); + return ftB; + } + + public void setDefaultFeatureType(SimpleFeatureType defaultFeatureType) { + this.defaultFeatureType = defaultFeatureType; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/PlatformGIS.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/PlatformGIS.java index 49f79024a5..7c23fd03ee 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/PlatformGIS.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/PlatformGIS.java @@ -18,10 +18,6 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import org.locationtech.udig.aoi.IAOIService; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.internal.Messages; - import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; @@ -36,13 +32,15 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.internal.services.ServiceLocator; -import org.eclipse.ui.internal.services.WorkbenchServiceRegistry; import org.geotools.brewer.color.ColorBrewer; +import org.locationtech.udig.aoi.IAOIService; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.internal.Messages; /** * A facade into udig to simplify operations relating to performing platform operations. - * + * * @author jeichar * @since 1.1 * @version 1.2.3 @@ -70,7 +68,7 @@ public static void run( IRunnableWithProgress request, IProgressMonitor monitorT RunnableAndProgress runnable = new RunnableAndProgress(request, monitorToUse); runner.setRequest(runnable); runner.schedule(); - + } /** @@ -83,7 +81,7 @@ public static void run( IRunnableWithProgress request, IProgressMonitor monitorT * runnable, and we will take over the {@link Display#readAndDispatch()} cycle while waiting * for the background runable to complete. When completed normal display thread execution will * resume. - * + * * @param runnable The runnable(operation) to run * @param monitor the progress monitor to update. * @throws InvocationTargetException @@ -106,6 +104,7 @@ public static void runBlockingOperation( final IRunnableWithProgress runnable, Future future = executor.submit(new Callable(){ @SuppressWarnings("unused") Exception e = new Exception("For debugging"); //$NON-NLS-1$ + @Override public Object call() throws Exception { try { runnable.run(new OffThreadProgressMonitor(monitor != null @@ -135,7 +134,8 @@ public Object call() throws Exception { wait(mutex, 200); } } catch (Exception e) { - UiPlugin.log("Error occurred while waiting for an operation to complete", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), + "Error occurred while waiting for an operation to complete", e); //$NON-NLS-1$ } } } @@ -179,7 +179,7 @@ public Runner( ) { /** * Add a runnable object to be run. - * + * * @param runnable */ public void setRequest( Object runnable ) { @@ -191,9 +191,10 @@ private void run( ISafeRunnable runnable ) { runnable.run(); } catch (Throwable e) { if (e.getMessage() != null) { - UiPlugin.log(e.getMessage(), e); + LoggingSupport.log(UiPlugin.getDefault(), e); } else { - UiPlugin.log("", e); //$NON-NLS-1$ + // TODO REVIEW : What would happen in Error-View, if message is empty? + LoggingSupport.log(UiPlugin.getDefault(), "", e); //$NON-NLS-1$ } runnable.handleException(e); } @@ -203,15 +204,15 @@ private void run( IRunnableWithProgress runnable, IProgressMonitor monitor ) { try { runnable.run(monitor); } catch (Throwable t) { - UiPlugin.log("", t); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), t); } } @Override - protected IStatus run( IProgressMonitor monitor ) { + protected IStatus run( IProgressMonitor monitor ) { if (!PlatformUI.getWorkbench().isClosing()) { if (runnable != null) { - + if (runnable instanceof ISafeRunnable) { run((ISafeRunnable) runnable); } else if (runnable instanceof IRunnableWithProgress) { @@ -238,7 +239,7 @@ public RunnableAndProgress( IRunnableWithProgress request, IProgressMonitor moni IRunnableWithProgress runnable; IProgressMonitor monitor; } - + public static ColorBrewer getColorBrewer() { synchronized (ColorBrewer.class) { if (colorBrewer == null) { @@ -254,7 +255,7 @@ public static ColorBrewer getColorBrewer() { * executed. So this method uses Display.asyncExec and patiently waits for the result to be * returned. Can be called from display thread or non-display thread. Runnable should not be * blocking or it will block the display thread. - * + * * @param runnable runnable to execute */ public static void syncInDisplayThread( final Runnable runnable ) { @@ -267,7 +268,7 @@ public static void syncInDisplayThread( final Runnable runnable ) { /** * Run in the display thread at the next reasonable opportunity, current thread will * wait for the runnable to complete. - * + * * @param display * @param runnable */ @@ -276,6 +277,7 @@ public static void syncInDisplayThread( Display display, final Runnable runnable final AtomicBoolean done = new AtomicBoolean(false); final Object mutex=new Object(); display.asyncExec(new Runnable(){ + @Override public void run() { try { runnable.run(); @@ -300,7 +302,7 @@ public void run() { /** * Waits for the condition to become true. Will call Display#readAndDispatch() if currently in * the display thread. - * + * * @param interval the time to wait between testing of condition, in milliseconds. Must be a * positive number and is recommended to be larger than 50 * @param timeout maximum time to wait. Will throw an {@link InterruptedException} if reached. @@ -341,7 +343,7 @@ public static void wait( long interval, long timeout, WaitCondition condition, O * Runs a blocking task in a ProgressDialog. It is ran in such a way that even if the task * blocks it can be cancelled. This is unlike the normal ProgressDialog.run(...) method which * requires that the {@link IProgressMonitor} be checked and the task to "nicely" cancel. - * + * * @param dialogTitle The title of the Progress dialog * @param showRunInBackground if true a button added to the dialog that will make the job be ran * in the background. @@ -353,6 +355,7 @@ public static void runInProgressDialog( final String dialogTitle, boolean runASync ) { Runnable object = new Runnable(){ + @Override public void run() { Shell shell = Display.getDefault().getActiveShell(); ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell){ @@ -385,23 +388,25 @@ protected void buttonPressed( int buttonId ) { try { dialog.run(true, true, new IRunnableWithProgress(){ + @Override public void run( IProgressMonitor monitor ) { try { runBlockingOperation(new IRunnableWithProgress(){ + @Override public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { runnable.run(monitor); } }, monitor); } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), e); } } }); } catch (Exception e) { - UiPlugin.log("", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), e); } } }; @@ -414,7 +419,7 @@ public void run( IProgressMonitor monitor ) /** * Runs the runnable in the display thread but asynchronously. - * + * * @param runnable the runnable to execute * @param executeIfInDisplay if true and the current thread is the display thread then the * runnable will just be executed. @@ -429,7 +434,7 @@ public static void asyncInDisplayThread( Runnable runnable, boolean executeIfInD /** * Runs the runnable in the display thread but asynchronously. - * + * * @param display the display in which to run the runnable * @param runnable the runnable to execute * @param executeIfInDisplay if true and the current thread is the display thread then the @@ -443,14 +448,14 @@ public static void asyncInDisplayThread( Display display, Runnable runnable, display.asyncExec(runnable); } } - + /** * Gets the Area of Interest workbench service * @return */ public static IAOIService getAOIService() { IWorkbench workbench = PlatformUI.getWorkbench(); - return (IAOIService) workbench.getService(IAOIService.class); + return workbench.getService(IAOIService.class); } - + } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ShutdownTaskList.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ShutdownTaskList.java index 13de940242..4748500368 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ShutdownTaskList.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ShutdownTaskList.java @@ -22,6 +22,7 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchListener; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.internal.ui.UiPlugin; import org.locationtech.udig.ui.internal.Messages; @@ -60,7 +61,8 @@ public void run(IProgressMonitor monitor2) task.steps = task.task.getProgressMonitorSteps(); totalsteps += task.steps; } catch (Throwable e) { - UiPlugin.log("error calling getProgressMonitorSteps() on " + task.task, //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), + "error calling getProgressMonitorSteps() on " + task.task, //$NON-NLS-1$ e); } } @@ -113,7 +115,8 @@ public void run(IProgressMonitor monitor2) task.steps = task.task.getProgressMonitorSteps(); totalsteps += task.steps; } catch (Throwable e) { - UiPlugin.log("error calling getProgressMonitorSteps() on " + task.task, //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), + "error calling getProgressMonitorSteps() on " + task.task, //$NON-NLS-1$ e); } } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/StartupOperations.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/StartupOperations.java index bb0be95128..c535baf538 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/StartupOperations.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/StartupOperations.java @@ -1,180 +1,182 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.util.ArrayList; -import java.util.List; - -import org.locationtech.udig.core.internal.ExtensionPointList; -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.commands.Category; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.ui.IStartup; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.commands.ICommandService; -import org.eclipse.ui.handlers.IHandlerService; -import org.eclipse.ui.menus.AbstractContributionFactory; -import org.eclipse.ui.menus.IContributionRoot; -import org.eclipse.ui.menus.IMenuService; -import org.eclipse.ui.services.IServiceLocator; - -/** - * Add additional operation menu contributions to the screen. - *

    - * This is an experiment it may be too late; since it appears the workbench - * window is already set up? - * - * @author Jody Garnett - */ -public class StartupOperations implements IStartup { - - public void earlyStartup() { - final IWorkbench workbench = PlatformUI.getWorkbench(); - //workbench.getDisplay().asyncExec(new Runnable() { - // public void run() { - // IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - // if (window != null) { - processOperations( workbench ); - } - - /** - * Process operations for the provided scope. - * - * @param workbench - * @param scope - */ - protected void processOperations( IWorkbench workbench ){ - IHandlerService handlers = (IHandlerService)workbench.getService( IHandlerService.class ); - ICommandService commands = (ICommandService)workbench.getService( ICommandService.class ); - IMenuService menuService = (IMenuService) workbench.getService(IMenuService.class); - IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - - List list = ExtensionPointList.getExtensionPointList("org.locationtech.udig.ui.operation"); //$NON-NLS-1$ - List categoryElements = listCategories(list); - if( categoryElements == null || categoryElements.isEmpty() ) return; - - for( IConfigurationElement element : categoryElements ) { - final String ID = element.getAttribute("id"); - final String NAME = element.getName(); - final String DESCRIPTION = element.getName(); - List operationElements = listOperationsForCategory(list, ID ); - try { - // Do not create operation category anymore; only worked for one window - // categories.put(ID, new OperationCategory(element)); //$NON-NLS-1$ - - // Create a Command Category - Category category = commands.getCategory(ID); - if( !category.isDefined()){ - category.define(NAME, DESCRIPTION); - } - // TODO: Create an ActionSet - - // TODO: Create a Definition to Check the ActionSet - - // TODO: Create the MenuGroup - AbstractContributionFactory categoryAdditions = operationsMenu( menuService, operationElements, "menu:nav?after=layer.ext", ID); - menuService.addContributionFactory(categoryAdditions); - } catch (Exception e) { - UiPlugin.log("Operation category "+ID+":"+e, e); - } - } - - for( IConfigurationElement element : list ) { - final String NAME = element.getName(); - final String ID = element.getAttribute("id"); - try { - if (NAME.equals("category")) {//$NON-NLS-1$ - continue; - } - /* - Command command = commands.getCommand(ID); - if( !command.isDefined()){ - final String DESCRIPTION = element.getName(); - final String CATEGORY = element.getAttribute("categoryId"); - - // Create the Command - Category category = commands.getCategory(CATEGORY); - command.define(NAME, DESCRIPTION, category ); - } - IHandler handler = new OpHandler( element ); - handlers.activateHandler(ID, handler); - */ - - } - catch (Exception e) { - UiPlugin.log("Operation "+ID+":"+e, e); - } - } - } - /** - * List all IConfigurationElements with name "category". - * @param list - * @return IConfigurationElments with name "category" - */ - List listCategories( List list) { - List results = new ArrayList(); - for( IConfigurationElement element : list ) { - final String NAME = element.getName(); - final String ID = element.getAttribute("id"); - if (NAME.equals("category")) {//$NON-NLS-1$ - results.add( element ); - } - } - return results; - } - /** - * List all IConfigurationElements operations that match the provided categoryId. - * - * @param list List of IConfigurationElement, assumed to come from operation extension point. - * @param categoryId - * @return List, perhaps empty, of IConfigurationElements - */ - List listOperationsForCategory( List list, String categoryId) { - List results = new ArrayList(); - for( IConfigurationElement element : list ) { - final String NAME = element.getName(); - final String ID = element.getAttribute("id"); - if (NAME.equals("category")) {//$NON-NLS-1$ - continue; - } - final String CATEGORY = element.getAttribute("categoryId"); - if( CATEGORY != null && CATEGORY.equals(categoryId)){ - results.add( element ); - } - } - return results; - } - - /** - * This will produce an AbstractConfigurationFactory that adds a CommandContribution for - * each operation in the indicated category. - *

    - * The following are all related "categoryId": - *

      - *
    • actionSet - actionSet used to toggle this visibility of this contribution - *
    • expression - true when actionSet is enabled - *
    • - *
    - * @param list - * @param locationURI - */ - protected AbstractContributionFactory operationsMenu( IMenuService menuService, final List list, String locationURI, final String categoryId ){ - return new AbstractContributionFactory(locationURI,null){ - public void createContributionItems( IServiceLocator serviceLocator, - IContributionRoot additions ) { - - } - }; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.commands.Category; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.ui.IStartup; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.menus.AbstractContributionFactory; +import org.eclipse.ui.menus.IContributionRoot; +import org.eclipse.ui.menus.IMenuService; +import org.eclipse.ui.services.IServiceLocator; +import org.locationtech.udig.core.internal.ExtensionPointList; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +/** + * Add additional operation menu contributions to the screen. + *

    + * This is an experiment it may be too late; since it appears the workbench + * window is already set up? + * + * @author Jody Garnett + */ +public class StartupOperations implements IStartup { + + @Override + public void earlyStartup() { + final IWorkbench workbench = PlatformUI.getWorkbench(); + //workbench.getDisplay().asyncExec(new Runnable() { + // public void run() { + // IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + // if (window != null) { + processOperations( workbench ); + } + + /** + * Process operations for the provided scope. + * + * @param workbench + * @param scope + */ + protected void processOperations( IWorkbench workbench ){ + IHandlerService handlers = workbench.getService( IHandlerService.class ); + ICommandService commands = workbench.getService( ICommandService.class ); + IMenuService menuService = workbench.getService(IMenuService.class); + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + + List list = ExtensionPointList.getExtensionPointList("org.locationtech.udig.ui.operation"); //$NON-NLS-1$ + List categoryElements = listCategories(list); + if( categoryElements == null || categoryElements.isEmpty() ) return; + + for( IConfigurationElement element : categoryElements ) { + final String ID = element.getAttribute("id"); + final String NAME = element.getName(); + final String DESCRIPTION = element.getName(); + List operationElements = listOperationsForCategory(list, ID ); + try { + // Do not create operation category anymore; only worked for one window + // categories.put(ID, new OperationCategory(element)); //$NON-NLS-1$ + + // Create a Command Category + Category category = commands.getCategory(ID); + if( !category.isDefined()){ + category.define(NAME, DESCRIPTION); + } + // TODO: Create an ActionSet + + // TODO: Create a Definition to Check the ActionSet + + // TODO: Create the MenuGroup + AbstractContributionFactory categoryAdditions = operationsMenu( menuService, operationElements, "menu:nav?after=layer.ext", ID); + menuService.addContributionFactory(categoryAdditions); + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Operation category " + ID + ":" + e, e); + } + } + + for( IConfigurationElement element : list ) { + final String NAME = element.getName(); + final String ID = element.getAttribute("id"); + try { + if (NAME.equals("category")) {//$NON-NLS-1$ + continue; + } + /* + Command command = commands.getCommand(ID); + if( !command.isDefined()){ + final String DESCRIPTION = element.getName(); + final String CATEGORY = element.getAttribute("categoryId"); + + // Create the Command + Category category = commands.getCategory(CATEGORY); + command.define(NAME, DESCRIPTION, category ); + } + IHandler handler = new OpHandler( element ); + handlers.activateHandler(ID, handler); + */ + + } + catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Operation " + ID + ":" + e, e); + } + } + } + /** + * List all IConfigurationElements with name "category". + * @param list + * @return IConfigurationElments with name "category" + */ + List listCategories( List list) { + List results = new ArrayList<>(); + for( IConfigurationElement element : list ) { + final String NAME = element.getName(); + final String ID = element.getAttribute("id"); + if (NAME.equals("category")) {//$NON-NLS-1$ + results.add( element ); + } + } + return results; + } + /** + * List all IConfigurationElements operations that match the provided categoryId. + * + * @param list List of IConfigurationElement, assumed to come from operation extension point. + * @param categoryId + * @return List, perhaps empty, of IConfigurationElements + */ + List listOperationsForCategory( List list, String categoryId) { + List results = new ArrayList<>(); + for( IConfigurationElement element : list ) { + final String NAME = element.getName(); + final String ID = element.getAttribute("id"); + if (NAME.equals("category")) {//$NON-NLS-1$ + continue; + } + final String CATEGORY = element.getAttribute("categoryId"); + if( CATEGORY != null && CATEGORY.equals(categoryId)){ + results.add( element ); + } + } + return results; + } + + /** + * This will produce an AbstractConfigurationFactory that adds a CommandContribution for + * each operation in the indicated category. + *

    + * The following are all related "categoryId": + *

      + *
    • actionSet - actionSet used to toggle this visibility of this contribution + *
    • expression - true when actionSet is enabled + *
    • + *
    + * @param list + * @param locationURI + */ + protected AbstractContributionFactory operationsMenu( IMenuService menuService, final List list, String locationURI, final String categoryId ){ + return new AbstractContributionFactory(locationURI,null){ + @Override + public void createContributionItems( IServiceLocator serviceLocator, + IContributionRoot additions ) { + + } + }; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/UDIGDisplaySafeCondition.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/UDIGDisplaySafeCondition.java index 7f5edeafff..9420cbcb07 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/UDIGDisplaySafeCondition.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/UDIGDisplaySafeCondition.java @@ -1,195 +1,202 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui; - -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.swt.widgets.Display; - -class UDIGDisplaySafeCondition implements Condition{ - /** SafeCondition owningLock field */ - private final UDIGDisplaySafeLock owningLock; - private final Condition nonDisplayCondition; - private final Condition displayCondition; - private volatile Set displayNotified=new HashSet(); - - UDIGDisplaySafeCondition( UDIGDisplaySafeLock lock ) { - if( lock==null ) - throw new NullPointerException("Lock cannot be null"); //$NON-NLS-1$ - owningLock = lock; - - nonDisplayCondition=owningLock.internalLock.newCondition(); - displayCondition=owningLock.internalLock.newCondition(); - } - - public void await() throws InterruptedException { - doAwait( -1, null, true); - } - - /** - * @param wait - * @param unit - * @param allowInterrupts - * @return see {@linkplain Condition#await(long, TimeUnit)} - * @throws InterruptedException - */ - boolean doAwait( long wait, TimeUnit unit, boolean allowInterrupts ) throws InterruptedException { - owningLock.internalLock.lock(); - try{ - checkState(); - owningLock.unlock(); - - if ( Display.getCurrent()==null ){ - if( !allowInterrupts ){ - // findbugs note: this is correct behaviour. I know its not in a while loop - nonDisplayCondition.awaitUninterruptibly(); - return true; - }else{ - if( unit==null ){ - nonDisplayCondition.await(); - return true; - }else - return nonDisplayCondition.await(wait, unit); - } - }else{ - return displayAwait(wait, unit, allowInterrupts)<=0; - } - }finally{ - // findbugs note: this is correct behaviour. - owningLock.lock(); - owningLock.internalLock.unlock(); - } - } - - private long displayAwait(long time, TimeUnit unit, boolean allowInterrupts) throws InterruptedException { - long remaining; - displayNotified.add(Thread.currentThread()); - long start=System.nanoTime(); - - if( unit!=null ){ - remaining=TimeUnit.NANOSECONDS.convert(time, unit); - }else{ - remaining=-1; - } - - long nextInterval=TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS);; - Display current = Display.getCurrent(); - while( nextInterval>0 && displayNotified.contains(Thread.currentThread())){ - if( unit!=null ){ - nextInterval=Math.min(nextInterval, remaining); - } - // unlock while running display events. - owningLock.internalLock.unlock(); - boolean readAndDispatch = true; - try{ - readAndDispatch = current.readAndDispatch(); - }catch (Throwable e) { - UiPlugin.log("error occurred in a display event", e); - } - - // findbugs note: this is correct behaviour. It is closed outside this method - owningLock.internalLock.lock(); - if( !readAndDispatch ){ - try{ - displayCondition.await(nextInterval, TimeUnit.NANOSECONDS); - }catch (InterruptedException e) { - if( allowInterrupts ) - throw e; - } - } - remaining-=System.nanoTime()-start; - } - return remaining; - } - - public boolean await( long time, TimeUnit unit ) throws InterruptedException { - return doAwait(time, unit, true); - } - - public long awaitNanos( long nanosTimeout ) throws InterruptedException { - long remaining; - if( Display.getCurrent()==null ){ - remaining=nonDisplayCondition.awaitNanos(nanosTimeout); - }else{ - remaining=displayAwait(nanosTimeout, TimeUnit.NANOSECONDS, true); - } - return remaining; - } - - public void awaitUninterruptibly() { - try { - doAwait(-1, null, false); - } catch (InterruptedException e) { - throw new Error("This should not be permitted to happen", e); //$NON-NLS-1$ - } - } - - public boolean awaitUntil( Date deadline ) throws InterruptedException { - checkState(); - long waitTime=deadline.getTime()-System.currentTimeMillis(); - - return doAwait(waitTime, TimeUnit.MILLISECONDS, true); - } - - public void signal() { - owningLock.internalLock.lock(); - try{ - checkState(); - - if( !displayNotified.isEmpty() ){ - Thread next = displayNotified.iterator().next(); - displayNotified.remove(next); - displayCondition.signal(); - }else{ - nonDisplayCondition.signal(); - } - }finally{ - owningLock.internalLock.unlock(); - } - } - - public void signalAll() { - owningLock.internalLock.lock(); - try{ - checkState(); - if( !displayNotified.isEmpty() ){ - displayNotified.clear(); - displayCondition.signalAll(); - } - nonDisplayCondition.signalAll(); - }finally{ - owningLock.internalLock.unlock(); - } - } - - private void checkState() { - if( !owningLock.isHeldByCurrentThread() ) - throw new IllegalStateException("current thread does not own lock!!!"); //$NON-NLS-1$ - } - - public int getWaitQueueLength() { - - int count=displayNotified.size(); - - int i = count+owningLock.internalLock.getWaitQueueLength(this.nonDisplayCondition); - return i; - } - - public boolean isOwner( UDIGDisplaySafeLock lock ) { - return owningLock==lock; - } - -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui; + +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; + +import org.eclipse.swt.widgets.Display; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +class UDIGDisplaySafeCondition implements Condition{ + /** SafeCondition owningLock field */ + private final UDIGDisplaySafeLock owningLock; + private final Condition nonDisplayCondition; + private final Condition displayCondition; + private volatile Set displayNotified=new HashSet<>(); + + UDIGDisplaySafeCondition( UDIGDisplaySafeLock lock ) { + if( lock==null ) + throw new NullPointerException("Lock cannot be null"); //$NON-NLS-1$ + owningLock = lock; + + nonDisplayCondition=owningLock.internalLock.newCondition(); + displayCondition=owningLock.internalLock.newCondition(); + } + + @Override + public void await() throws InterruptedException { + doAwait( -1, null, true); + } + + /** + * @param wait + * @param unit + * @param allowInterrupts + * @return see {@linkplain Condition#await(long, TimeUnit)} + * @throws InterruptedException + */ + boolean doAwait( long wait, TimeUnit unit, boolean allowInterrupts ) throws InterruptedException { + owningLock.internalLock.lock(); + try{ + checkState(); + owningLock.unlock(); + + if ( Display.getCurrent()==null ){ + if( !allowInterrupts ){ + // findbugs note: this is correct behaviour. I know its not in a while loop + nonDisplayCondition.awaitUninterruptibly(); + return true; + }else{ + if( unit==null ){ + nonDisplayCondition.await(); + return true; + }else + return nonDisplayCondition.await(wait, unit); + } + }else{ + return displayAwait(wait, unit, allowInterrupts)<=0; + } + }finally{ + // findbugs note: this is correct behaviour. + owningLock.lock(); + owningLock.internalLock.unlock(); + } + } + + private long displayAwait(long time, TimeUnit unit, boolean allowInterrupts) throws InterruptedException { + long remaining; + displayNotified.add(Thread.currentThread()); + long start=System.nanoTime(); + + if( unit!=null ){ + remaining=TimeUnit.NANOSECONDS.convert(time, unit); + }else{ + remaining=-1; + } + + long nextInterval=TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS);; + Display current = Display.getCurrent(); + while( nextInterval>0 && displayNotified.contains(Thread.currentThread())){ + if( unit!=null ){ + nextInterval=Math.min(nextInterval, remaining); + } + // unlock while running display events. + owningLock.internalLock.unlock(); + boolean readAndDispatch = true; + try { + readAndDispatch = current.readAndDispatch(); + } catch (Throwable e) { + LoggingSupport.log(UiPlugin.getDefault(), "error occurred in a display event", e); + } + + // findbugs note: this is correct behaviour. It is closed outside this method + owningLock.internalLock.lock(); + if( !readAndDispatch ){ + try{ + displayCondition.await(nextInterval, TimeUnit.NANOSECONDS); + }catch (InterruptedException e) { + if( allowInterrupts ) + throw e; + } + } + remaining-=System.nanoTime()-start; + } + return remaining; + } + + @Override + public boolean await( long time, TimeUnit unit ) throws InterruptedException { + return doAwait(time, unit, true); + } + + @Override + public long awaitNanos( long nanosTimeout ) throws InterruptedException { + long remaining; + if( Display.getCurrent()==null ){ + remaining=nonDisplayCondition.awaitNanos(nanosTimeout); + }else{ + remaining=displayAwait(nanosTimeout, TimeUnit.NANOSECONDS, true); + } + return remaining; + } + + @Override + public void awaitUninterruptibly() { + try { + doAwait(-1, null, false); + } catch (InterruptedException e) { + throw new Error("This should not be permitted to happen", e); //$NON-NLS-1$ + } + } + + @Override + public boolean awaitUntil( Date deadline ) throws InterruptedException { + checkState(); + long waitTime=deadline.getTime()-System.currentTimeMillis(); + + return doAwait(waitTime, TimeUnit.MILLISECONDS, true); + } + + @Override + public void signal() { + owningLock.internalLock.lock(); + try{ + checkState(); + + if( !displayNotified.isEmpty() ){ + Thread next = displayNotified.iterator().next(); + displayNotified.remove(next); + displayCondition.signal(); + }else{ + nonDisplayCondition.signal(); + } + }finally{ + owningLock.internalLock.unlock(); + } + } + + @Override + public void signalAll() { + owningLock.internalLock.lock(); + try{ + checkState(); + if( !displayNotified.isEmpty() ){ + displayNotified.clear(); + displayCondition.signalAll(); + } + nonDisplayCondition.signalAll(); + }finally{ + owningLock.internalLock.unlock(); + } + } + + private void checkState() { + if( !owningLock.isHeldByCurrentThread() ) + throw new IllegalStateException("current thread does not own lock!!!"); //$NON-NLS-1$ + } + + public int getWaitQueueLength() { + + int count=displayNotified.size(); + + int i = count+owningLock.internalLock.getWaitQueueLength(this.nonDisplayCondition); + return i; + } + + public boolean isOwner( UDIGDisplaySafeLock lock ) { + return owningLock==lock; + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ZoomingDialog.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ZoomingDialog.java index 4e379039a9..8ebc65491b 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ZoomingDialog.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/ZoomingDialog.java @@ -24,6 +24,7 @@ import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TreeItem; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.internal.ui.UiPlugin; /** @@ -179,7 +180,8 @@ private void runEventLoop(Shell loopShell) { display.sleep(); } } catch (Throwable e) { - UiPlugin.log( "Exception in UI thread while waiting", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), "Exception in UI thread while waiting", //$NON-NLS-1$ + e); } } display.update(); diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/action/NewObjectDelegate.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/action/NewObjectDelegate.java index d653d496ac..4b55f98e91 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/action/NewObjectDelegate.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/action/NewObjectDelegate.java @@ -1,83 +1,83 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.action; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.IWorkbenchWindowActionDelegate; -import org.eclipse.ui.plugin.AbstractUIPlugin; - -/** - * Description of NewObjectAction. - *

    - * Information about NewObjectAction is processed from the extension point IConfigurationElement data. - *

    - * You can consider this a really early version of "Action" back before Eclipse 3.3 made - * this sort of thing easy. - * - * @author jones - * @since 0.6.0 - */ -public class NewObjectDelegate { - /** NewItem id field */ - public final String id; - /** NewItem text field */ - public final String text; - /** NewItem icon field */ - public final ImageDescriptor icon; - /** NewItem element field */ - public final IConfigurationElement element; - private IWorkbenchWindowActionDelegate delegate; - private IWorkbenchWindow window; - - /** - * Construct UDIGActionBarAdvisor.NewContribution.NewItem. - * - * @param element The configuration element that holds the properties (from plugin.xml) - * @param window The window this action will operate in. - */ - public NewObjectDelegate( IConfigurationElement element, IWorkbenchWindow window ) { - this.element = element; - this.text = element.getAttribute("label"); //$NON-NLS-1$ - this.id = element.getAttribute("id"); //$NON-NLS-1$ - String iconPath = element.getAttribute("icon"); //$NON-NLS-1$ - if (iconPath != null) { - this.icon = AbstractUIPlugin.imageDescriptorFromPlugin(element.getNamespaceIdentifier(), - iconPath); - } else - this.icon = null; - this.window = window; - } - - /** - * Create the IWorkbenchWindowActionDelegate (if required) and call run. - */ - public void runAction() { - if (delegate == null) { - try { - delegate = (IWorkbenchWindowActionDelegate) element - .createExecutableExtension("class"); //$NON-NLS-1$ - } catch (CoreException e) { - UiPlugin.log(null, e); - } - } - if (delegate != null) { - delegate.init(window); - delegate.selectionChanged(null, new StructuredSelection()); - delegate.run(null); - } - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.action; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +/** + * Description of NewObjectAction. + *

    + * Information about NewObjectAction is processed from the extension point IConfigurationElement data. + *

    + * You can consider this a really early version of "Action" back before Eclipse 3.3 made + * this sort of thing easy. + * + * @author jones + * @since 0.6.0 + */ +public class NewObjectDelegate { + /** NewItem id field */ + public final String id; + /** NewItem text field */ + public final String text; + /** NewItem icon field */ + public final ImageDescriptor icon; + /** NewItem element field */ + public final IConfigurationElement element; + private IWorkbenchWindowActionDelegate delegate; + private IWorkbenchWindow window; + + /** + * Construct UDIGActionBarAdvisor.NewContribution.NewItem. + * + * @param element The configuration element that holds the properties (from plugin.xml) + * @param window The window this action will operate in. + */ + public NewObjectDelegate( IConfigurationElement element, IWorkbenchWindow window ) { + this.element = element; + this.text = element.getAttribute("label"); //$NON-NLS-1$ + this.id = element.getAttribute("id"); //$NON-NLS-1$ + String iconPath = element.getAttribute("icon"); //$NON-NLS-1$ + if (iconPath != null) { + this.icon = AbstractUIPlugin.imageDescriptorFromPlugin(element.getNamespaceIdentifier(), + iconPath); + } else + this.icon = null; + this.window = window; + } + + /** + * Create the IWorkbenchWindowActionDelegate (if required) and call run. + */ + public void runAction() { + if (delegate == null) { + try { + delegate = (IWorkbenchWindowActionDelegate) element + .createExecutableExtension("class"); //$NON-NLS-1$ + } catch (CoreException e) { + LoggingSupport.log(UiPlugin.getDefault(), e); + } + } + if (delegate != null) { + delegate.init(window); + delegate.selectionChanged(null, new StructuredSelection()); + delegate.run(null); + } + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/aoi/AOIView.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/aoi/AOIView.java index fc5a1c3fed..b0a0055672 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/aoi/AOIView.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/aoi/AOIView.java @@ -1,331 +1,332 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2011, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.aoi; - -import java.util.HashMap; -import java.util.Map; - -import org.locationtech.udig.aoi.AOIListener; -import org.locationtech.udig.aoi.AOIProxy; -import org.locationtech.udig.aoi.IAOIService; -import org.locationtech.udig.aoi.IAOIStrategy; -import org.locationtech.udig.internal.ui.UiPlugin; -import org.locationtech.udig.ui.PlatformGIS; - -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ComboViewer; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.ui.IMemento; -import org.eclipse.ui.IViewSite; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.IPageBookViewPage; -import org.eclipse.ui.part.MessagePage; -import org.eclipse.ui.part.PageBook; -import org.eclipse.ui.part.ViewPart; - -/** - * Allows a user to select the AOIStrategy to define the AOI (Area of Interest) - *

    - * This view processes the "AOI" extension point in order to obtain the list of options to - * display to the user. Each AOIStrategy may optionally provide a "page" used to further refine the - * limit used for the AOI. - * - * @author pfeiffp - * @sinve 1.3.0 - */ -public class AOIView extends ViewPart { - - /** - * Listens to the global IAOIService and updates our view if anything changes! - */ - private AOIListener serviceWatcher = new AOIListener(){ - // private IAOIStrategy selectedStrategy = null; - public void handleEvent( AOIListener.Event event ) { - final AOIListener.Event aoiEvent = event; - // must be run in the UI thread to be able to call setSelected - PlatformGIS.asyncInDisplayThread(new Runnable(){ - - @Override - public void run() { - AOIProxy currentStrategy; - if (aoiEvent.source instanceof AOIProxy) { - currentStrategy = (AOIProxy) aoiEvent.source; - } else { - currentStrategy = PlatformGIS.getAOIService().getProxy(); - } - setSelected(currentStrategy); - - } - }, true); - } - }; - - // private Combo combo; - private ComboViewer comboViewer; - - /** - * Listens to the user and changes the global IAOIService to the indicated strategy. - */ - private ISelectionChangedListener comboListener = new ISelectionChangedListener(){ - @Override - public void selectionChanged( SelectionChangedEvent event ) { - IStructuredSelection selectedStrategy = (IStructuredSelection) event.getSelection(); - AOIProxy selected = (AOIProxy) selectedStrategy.getFirstElement(); - - publishAOIStrategy(selected); - } - }; - - private PageBook pagebook; - private Map pages = new HashMap(); - - private Composite placeholder; - - //private List pages = new ArrayList(); - //private Map controls = new HashMap(); - - /** - * AOI View constructor adds the known strategies - */ - public AOIView() { - } - - - private void publishAOIStrategy( AOIProxy selected ) { - IAOIService aOIService = PlatformGIS.getAOIService(); - aOIService.setProxy(selected); - } - - /** - * This will update the combo viewer and pagebook (carefully unhooking events while the viewer is updated). - * - * @param selected - */ - public void setSelected( AOIProxy selected ) { - if (selected == null) { - selected = PlatformGIS.getAOIService().getDefault(); - } - - boolean disposed = comboViewer.getControl().isDisposed(); - if (comboViewer == null || disposed) { - listenService(false); - return; // the view has shutdown! - } - - AOIProxy current = getSelected(); - // check combo - if (current != selected) { - try { - listenCombo(false); - comboViewer.setSelection(new StructuredSelection(selected), true); - } finally { - listenCombo(true); - } - } - - // this is the control displayed right now - Control currentControl = null; - for( Control page : pagebook.getChildren() ){ - if( page.isVisible() ){ - currentControl = page; - break; - } - } - - // Check if we already created the control for selected - PageRecord record = pages.get(selected); - if( record == null ){ - // record has not been created yet - IPageBookViewPage page = selected.createPage(); - if( page == null ){ - MessagePage messagePage = new MessagePage(); - - record = new PageRecord( this, messagePage); - - messagePage.init( record.getSite() ); - - messagePage.createControl( pagebook ); - messagePage.setMessage( selected.getName() ); - } - else { - record = new PageRecord( this, page ); - try { - page.init( record.getSite() ); - } catch (PartInitException e) { - UiPlugin.log(getClass(), "initPage", e); //$NON-NLS-1$ - } - page.createControl( pagebook ); - } - pages.put(selected, record ); - } - Control selectedControl = record.getControl(); - - if( selectedControl == null ){ - // this is not expected to be null! - if( placeholder == null ){ - // placeholder just so we see something! - Composite content = new Composite(pagebook, SWT.NULL); - content.setLayout(new FillLayout()); - - Label label = new Label( content, SWT.LEFT | SWT.TOP | SWT.WRAP ); - label.setText("Current Area of Interest used for filtering content."); - - placeholder = content; - } - selectedControl = placeholder; - } - - if( currentControl != selectedControl ){ - if( selectedControl != null ){ - pagebook.showPage(selectedControl); // done! - } - } - } - /** - * Access the IAOIStrategy selected by the user - * - * @return IAOIStrategy selected by the user - */ - public AOIProxy getSelected() { - if (comboViewer.getSelection() instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection) comboViewer.getSelection(); - return (AOIProxy) selection.getFirstElement(); - } - return null; - } - - protected void listenCombo( boolean listen ) { - if (comboViewer == null || comboViewer.getControl().isDisposed()) { - return; // run away! - } - if (listen) { - comboViewer.addSelectionChangedListener(comboListener); - } else { - comboViewer.removeSelectionChangedListener(comboListener); - } - } - - protected void listenService( boolean listen ) { - IAOIService aOIService = PlatformGIS.getAOIService(); - if (listen) { - aOIService.addListener(serviceWatcher); - } else { - aOIService.removeListener(serviceWatcher); - } - } - - @Override - public void init( IViewSite site, IMemento memento ) throws PartInitException { - super.init(site, memento); - - // this is where you read your memento to remember - // anything the user told you from last time - // this.addAOIStrategy(); - if( memento != null ){ -// String id = memento.getString("AOI"); -// IAOIService service = PlatformGIS.getAOIService(); -// this.initialStrategy = service.findProxy(id); - } - } - - @Override - public void saveState( IMemento memento ) { - super.saveState(memento); - - IAOIService service = PlatformGIS.getAOIService(); - String id = service.getProxy().getId(); - - memento.putString("AOI", id ); - } - - @Override - public void createPartControl( Composite parent ) { - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - parent.setLayout(layout); - Label label = new Label(parent, SWT.LEFT); - label.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); - label.setText("Area of Interest: "); - - // get the current strategy - IAOIService aOIService = PlatformGIS.getAOIService(); - listenService(true); - - // eclipse combo viewer - comboViewer = new ComboViewer(parent, SWT.READ_ONLY); - comboViewer.setContentProvider(new ArrayContentProvider()); - comboViewer.setLabelProvider(new LabelProvider(){ - @Override - public String getText( Object element ) { - if (element instanceof IAOIStrategy) { - IAOIStrategy comboStrategy = (IAOIStrategy) element; - return comboStrategy.getName(); - } - return super.getText(element); - } - }); - comboViewer.setInput(aOIService.getProxyList()); - // set the current strategy - AOIProxy proxy = aOIService.getProxy(); - if (proxy == null) { - proxy = aOIService.getDefault(); - } - comboViewer.setSelection(new StructuredSelection(proxy)); - - // now that we are configured we can start to listen! - listenCombo(true); - - pagebook = new PageBook(parent, SWT.NONE ); - GridData layoutData = new GridData(SWT.LEFT, SWT.TOP, true, true); - layoutData.widthHint=400; - layoutData.horizontalSpan=2; - layoutData.heightHint=400; - pagebook.setLayoutData(layoutData); - } - - @Override - public void setFocus() { - comboViewer.getControl().setFocus(); - } - - @Override - public void dispose() { - super.dispose(); - // clean up any page stuffs - if( pages != null && !pages.isEmpty() ){ - for( PageRecord record : pages.values() ){ - record.dispose(); - } - pages.clear(); - pages = null; - } - if (comboViewer != null) { - comboViewer.removeSelectionChangedListener(comboListener); - } - if (serviceWatcher != null) { - IAOIService aOIService = PlatformGIS.getAOIService(); - if (aOIService != null) { - aOIService.removeListener(serviceWatcher); - } - serviceWatcher = null; - } - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2011, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.aoi; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ComboViewer; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.part.IPageBookViewPage; +import org.eclipse.ui.part.MessagePage; +import org.eclipse.ui.part.PageBook; +import org.eclipse.ui.part.ViewPart; +import org.locationtech.udig.aoi.AOIListener; +import org.locationtech.udig.aoi.AOIProxy; +import org.locationtech.udig.aoi.IAOIService; +import org.locationtech.udig.aoi.IAOIStrategy; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.locationtech.udig.ui.PlatformGIS; + +/** + * Allows a user to select the AOIStrategy to define the AOI (Area of Interest) + *

    + * This view processes the "AOI" extension point in order to obtain the list of options to + * display to the user. Each AOIStrategy may optionally provide a "page" used to further refine the + * limit used for the AOI. + * + * @author pfeiffp + * @sinve 1.3.0 + */ +public class AOIView extends ViewPart { + + /** + * Listens to the global IAOIService and updates our view if anything changes! + */ + private AOIListener serviceWatcher = new AOIListener(){ + // private IAOIStrategy selectedStrategy = null; + @Override + public void handleEvent( AOIListener.Event event ) { + final AOIListener.Event aoiEvent = event; + // must be run in the UI thread to be able to call setSelected + PlatformGIS.asyncInDisplayThread(new Runnable(){ + + @Override + public void run() { + AOIProxy currentStrategy; + if (aoiEvent.source instanceof AOIProxy) { + currentStrategy = (AOIProxy) aoiEvent.source; + } else { + currentStrategy = PlatformGIS.getAOIService().getProxy(); + } + setSelected(currentStrategy); + + } + }, true); + } + }; + + // private Combo combo; + private ComboViewer comboViewer; + + /** + * Listens to the user and changes the global IAOIService to the indicated strategy. + */ + private ISelectionChangedListener comboListener = new ISelectionChangedListener(){ + @Override + public void selectionChanged( SelectionChangedEvent event ) { + IStructuredSelection selectedStrategy = (IStructuredSelection) event.getSelection(); + AOIProxy selected = (AOIProxy) selectedStrategy.getFirstElement(); + + publishAOIStrategy(selected); + } + }; + + private PageBook pagebook; + private Map pages = new HashMap<>(); + + private Composite placeholder; + + //private List pages = new ArrayList(); + //private Map controls = new HashMap(); + + /** + * AOI View constructor adds the known strategies + */ + public AOIView() { + } + + + private void publishAOIStrategy( AOIProxy selected ) { + IAOIService aOIService = PlatformGIS.getAOIService(); + aOIService.setProxy(selected); + } + + /** + * This will update the combo viewer and pagebook (carefully unhooking events while the viewer is updated). + * + * @param selected + */ + public void setSelected( AOIProxy selected ) { + if (selected == null) { + selected = PlatformGIS.getAOIService().getDefault(); + } + + boolean disposed = comboViewer.getControl().isDisposed(); + if (comboViewer == null || disposed) { + listenService(false); + return; // the view has shutdown! + } + + AOIProxy current = getSelected(); + // check combo + if (current != selected) { + try { + listenCombo(false); + comboViewer.setSelection(new StructuredSelection(selected), true); + } finally { + listenCombo(true); + } + } + + // this is the control displayed right now + Control currentControl = null; + for( Control page : pagebook.getChildren() ){ + if( page.isVisible() ){ + currentControl = page; + break; + } + } + + // Check if we already created the control for selected + PageRecord record = pages.get(selected); + if( record == null ){ + // record has not been created yet + IPageBookViewPage page = selected.createPage(); + if( page == null ){ + MessagePage messagePage = new MessagePage(); + + record = new PageRecord( this, messagePage); + + messagePage.init( record.getSite() ); + + messagePage.createControl( pagebook ); + messagePage.setMessage( selected.getName() ); + } + else { + record = new PageRecord( this, page ); + try { + page.init( record.getSite() ); + } catch (PartInitException e) { + LoggingSupport.log(UiPlugin.getDefault(), getClass(), "initPage", e); //$NON-NLS-1$ + } + page.createControl( pagebook ); + } + pages.put(selected, record ); + } + Control selectedControl = record.getControl(); + + if( selectedControl == null ){ + // this is not expected to be null! + if( placeholder == null ){ + // placeholder just so we see something! + Composite content = new Composite(pagebook, SWT.NULL); + content.setLayout(new FillLayout()); + + Label label = new Label( content, SWT.LEFT | SWT.TOP | SWT.WRAP ); + label.setText("Current Area of Interest used for filtering content."); + + placeholder = content; + } + selectedControl = placeholder; + } + + if( currentControl != selectedControl ){ + if( selectedControl != null ){ + pagebook.showPage(selectedControl); // done! + } + } + } + /** + * Access the IAOIStrategy selected by the user + * + * @return IAOIStrategy selected by the user + */ + public AOIProxy getSelected() { + if (comboViewer.getSelection() instanceof IStructuredSelection) { + IStructuredSelection selection = (IStructuredSelection) comboViewer.getSelection(); + return (AOIProxy) selection.getFirstElement(); + } + return null; + } + + protected void listenCombo( boolean listen ) { + if (comboViewer == null || comboViewer.getControl().isDisposed()) { + return; // run away! + } + if (listen) { + comboViewer.addSelectionChangedListener(comboListener); + } else { + comboViewer.removeSelectionChangedListener(comboListener); + } + } + + protected void listenService( boolean listen ) { + IAOIService aOIService = PlatformGIS.getAOIService(); + if (listen) { + aOIService.addListener(serviceWatcher); + } else { + aOIService.removeListener(serviceWatcher); + } + } + + @Override + public void init( IViewSite site, IMemento memento ) throws PartInitException { + super.init(site, memento); + + // this is where you read your memento to remember + // anything the user told you from last time + // this.addAOIStrategy(); + if( memento != null ){ +// String id = memento.getString("AOI"); +// IAOIService service = PlatformGIS.getAOIService(); +// this.initialStrategy = service.findProxy(id); + } + } + + @Override + public void saveState( IMemento memento ) { + super.saveState(memento); + + IAOIService service = PlatformGIS.getAOIService(); + String id = service.getProxy().getId(); + + memento.putString("AOI", id ); + } + + @Override + public void createPartControl( Composite parent ) { + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + parent.setLayout(layout); + Label label = new Label(parent, SWT.LEFT); + label.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + label.setText("Area of Interest: "); + + // get the current strategy + IAOIService aOIService = PlatformGIS.getAOIService(); + listenService(true); + + // eclipse combo viewer + comboViewer = new ComboViewer(parent, SWT.READ_ONLY); + comboViewer.setContentProvider(new ArrayContentProvider()); + comboViewer.setLabelProvider(new LabelProvider(){ + @Override + public String getText( Object element ) { + if (element instanceof IAOIStrategy) { + IAOIStrategy comboStrategy = (IAOIStrategy) element; + return comboStrategy.getName(); + } + return super.getText(element); + } + }); + comboViewer.setInput(aOIService.getProxyList()); + // set the current strategy + AOIProxy proxy = aOIService.getProxy(); + if (proxy == null) { + proxy = aOIService.getDefault(); + } + comboViewer.setSelection(new StructuredSelection(proxy)); + + // now that we are configured we can start to listen! + listenCombo(true); + + pagebook = new PageBook(parent, SWT.NONE ); + GridData layoutData = new GridData(SWT.LEFT, SWT.TOP, true, true); + layoutData.widthHint=400; + layoutData.horizontalSpan=2; + layoutData.heightHint=400; + pagebook.setLayoutData(layoutData); + } + + @Override + public void setFocus() { + comboViewer.getControl().setFocus(); + } + + @Override + public void dispose() { + super.dispose(); + // clean up any page stuffs + if( pages != null && !pages.isEmpty() ){ + for( PageRecord record : pages.values() ){ + record.dispose(); + } + pages.clear(); + pages = null; + } + if (comboViewer != null) { + comboViewer.removeSelectionChangedListener(comboListener); + } + if (serviceWatcher != null) { + IAOIService aOIService = PlatformGIS.getAOIService(); + if (aOIService != null) { + aOIService.removeListener(serviceWatcher); + } + serviceWatcher = null; + } + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/ExpressionViewerFactory.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/ExpressionViewerFactory.java index 376de2454e..5fee706f5e 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/ExpressionViewerFactory.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/ExpressionViewerFactory.java @@ -1,166 +1,168 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.filter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExtensionPoint; -import org.eclipse.core.runtime.IExtensionRegistry; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; -import org.opengis.filter.expression.Expression; - -/** - * Factory class that takes an Expression and returns the appropriate ExpressionViewer. - * - * @author Scott - * @since 1.3.0 - */ -public abstract class ExpressionViewerFactory extends ViewerFactory { - - @Override - public Class getBinding() { - return Expression.class; - } - /** - * Percentage between 0-100 saying how well this viewer can process the provided object. - *

    - * The default implementation assumes {@link ExpressionInput} and {@link Express} in order to - * call {@link #score(ExpressionInput, Expression)} below. - * - * @param input Assumed to be {@link ExpressionInput} - * @param value Assumed to be {@link Express} - * @return score between 0-100 indicating suitability - */ - public int score(Object input, Object value) { - ExpressionInput expressionInput = safeCast(input, ExpressionInput.class); - Expression expression = safeCast(value, Expression.class); - - return score(expressionInput, expression); - } - - /** - * Percentage between 0-100 saying how well this viewer can process the provided object. - *

    - * The default implementation assumes {@link ExpressionInput} and {@link Express} in order to - * call {@link #score(ExpressionInput, Expression)} below. - * - * @param input Context used to assist the user in defining an expresison - * @param expr {@link Expression} displayed to the user for editing - * @return score between 0-100 indicating suitability - */ - public abstract int score(ExpressionInput input, Expression expr); - - /** - * Create the requested {@link IExpressionViewer} using the supplied composite as a parent. - *

    - * The currently supported styles are: - *

      - *
    • {@link SWT#DEFAULT}
    • - *
    • {@link SWT#POP_UP} - hint used to tell the viewer it is being used in a pop up and can - * assume both extra space and the ability of the user to resize.
    • - *
    - *

    - * This method simply creates the viewer; client code is expected to call - * {@link Viewer#setInput(filter )} prior to use. For more information please see the JFace - * {@link Viewer} class. - * - * @param composite - * @param style - * @return requested viewer - */ - public abstract IExpressionViewer createViewer(Composite composite, int style); - - // - // Factory and Extension Point Support - // - /** General purpose {@link IFilterViewer} suitable for use as a default */ - public static final String CQL_EXPRESSION_VIEWER = "org.locationtech.udig.ui.filter.cqlExpressionViewer"; - - /** Extension point ID each "expressionViewer" will be processed into our {@link #factoryList()} */ - public static final String FILTER_VIEWER_EXTENSION = FilterViewerFactory.FILTER_VIEWER_EXTENSION; - - /** - * Internal factory list, read-only access provided by {@link #factoryList()}. - */ - private static List factoryList; - - /** - * Short list {@link ExpressionViewerFactory} suitable for the editing a expression in the provided context. - * - * @param input context information for editing - * @param expression expression presented to the user for editing - * @return - */ - public static List factoryList( - final ExpressionInput input, final Expression expression) { - List list = new ArrayList(); - for( ExpressionViewerFactory factory : factoryList()){ - int score = factory.score( input, expression ); - if( Appropriate.valueOf( score ) == Appropriate.NOT_APPROPRIATE ){ - continue; // skip this one - } - list.add( factory ); - } - Collections.sort(list, new ViewerFactoryComparator( input, expression ) ); - return list; - } - /** - * List of {@link ExpressionViewerFactory} declared using {@link #FILTER_VIEWER_EXTENSION} extension. - *

    - * Note because these factories are active objects (each with an implementation of {@link #score(ExpressionInput, Expression)} - * which we need to call) they are not handled in the traditional eclipse "proxy" style. This is a known violation of the - * Eclipse House rules (that will force each plugin implementing a {@link ExpressionViewerFactory} to be loaded - very bad). - * - * @return Complete list of factories provided by {@link #FILTER_VIEWER_EXTENSION} extension - */ - public synchronized static List factoryList() { - if (factoryList == null) { - ArrayList list = new ArrayList(); - - IExtensionRegistry registery = Platform.getExtensionRegistry(); - IExtensionPoint extensionPoint = registery.getExtensionPoint(FILTER_VIEWER_EXTENSION); - - IConfigurationElement[] configurationElements = extensionPoint - .getConfigurationElements(); - for (IConfigurationElement configuration : configurationElements) { - if ("expressionViewer".equals(configuration.getName())) { - try { - ExpressionViewerFactory factory; - factory = (ExpressionViewerFactory) configuration - .createExecutableExtension("class"); - factory.init(configuration); - - list.add(factory); - } catch (CoreException e) { - String pluginId = configuration.getContributor().getName(); - IStatus status = new Status(IStatus.WARNING, pluginId, e.getMessage(), e); - UiPlugin.log(status); - } - } else { - // skip as it is probably a expressionViewer element - } - } - factoryList = Collections.unmodifiableList(list); - } - return factoryList; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.filter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.opengis.filter.expression.Expression; + +/** + * Factory class that takes an Expression and returns the appropriate ExpressionViewer. + * + * @author Scott + * @since 1.3.0 + */ +public abstract class ExpressionViewerFactory extends ViewerFactory { + + @Override + public Class getBinding() { + return Expression.class; + } + /** + * Percentage between 0-100 saying how well this viewer can process the provided object. + *

    + * The default implementation assumes {@link ExpressionInput} and {@link Express} in order to + * call {@link #score(ExpressionInput, Expression)} below. + * + * @param input Assumed to be {@link ExpressionInput} + * @param value Assumed to be {@link Express} + * @return score between 0-100 indicating suitability + */ + @Override + public int score(Object input, Object value) { + ExpressionInput expressionInput = safeCast(input, ExpressionInput.class); + Expression expression = safeCast(value, Expression.class); + + return score(expressionInput, expression); + } + + /** + * Percentage between 0-100 saying how well this viewer can process the provided object. + *

    + * The default implementation assumes {@link ExpressionInput} and {@link Express} in order to + * call {@link #score(ExpressionInput, Expression)} below. + * + * @param input Context used to assist the user in defining an expresison + * @param expr {@link Expression} displayed to the user for editing + * @return score between 0-100 indicating suitability + */ + public abstract int score(ExpressionInput input, Expression expr); + + /** + * Create the requested {@link IExpressionViewer} using the supplied composite as a parent. + *

    + * The currently supported styles are: + *

      + *
    • {@link SWT#DEFAULT}
    • + *
    • {@link SWT#POP_UP} - hint used to tell the viewer it is being used in a pop up and can + * assume both extra space and the ability of the user to resize.
    • + *
    + *

    + * This method simply creates the viewer; client code is expected to call + * {@link Viewer#setInput(filter )} prior to use. For more information please see the JFace + * {@link Viewer} class. + * + * @param composite + * @param style + * @return requested viewer + */ + @Override + public abstract IExpressionViewer createViewer(Composite composite, int style); + + // + // Factory and Extension Point Support + // + /** General purpose {@link IFilterViewer} suitable for use as a default */ + public static final String CQL_EXPRESSION_VIEWER = "org.locationtech.udig.ui.filter.cqlExpressionViewer"; + + /** Extension point ID each "expressionViewer" will be processed into our {@link #factoryList()} */ + public static final String FILTER_VIEWER_EXTENSION = FilterViewerFactory.FILTER_VIEWER_EXTENSION; + + /** + * Internal factory list, read-only access provided by {@link #factoryList()}. + */ + private static List factoryList; + + /** + * Short list {@link ExpressionViewerFactory} suitable for the editing a expression in the provided context. + * + * @param input context information for editing + * @param expression expression presented to the user for editing + * @return + */ + public static List factoryList( + final ExpressionInput input, final Expression expression) { + List list = new ArrayList<>(); + for( ExpressionViewerFactory factory : factoryList()){ + int score = factory.score( input, expression ); + if( Appropriate.valueOf( score ) == Appropriate.NOT_APPROPRIATE ){ + continue; // skip this one + } + list.add( factory ); + } + Collections.sort(list, new ViewerFactoryComparator( input, expression ) ); + return list; + } + /** + * List of {@link ExpressionViewerFactory} declared using {@link #FILTER_VIEWER_EXTENSION} extension. + *

    + * Note because these factories are active objects (each with an implementation of {@link #score(ExpressionInput, Expression)} + * which we need to call) they are not handled in the traditional eclipse "proxy" style. This is a known violation of the + * Eclipse House rules (that will force each plugin implementing a {@link ExpressionViewerFactory} to be loaded - very bad). + * + * @return Complete list of factories provided by {@link #FILTER_VIEWER_EXTENSION} extension + */ + public synchronized static List factoryList() { + if (factoryList == null) { + ArrayList list = new ArrayList<>(); + + IExtensionRegistry registery = Platform.getExtensionRegistry(); + IExtensionPoint extensionPoint = registery.getExtensionPoint(FILTER_VIEWER_EXTENSION); + + IConfigurationElement[] configurationElements = extensionPoint + .getConfigurationElements(); + for (IConfigurationElement configuration : configurationElements) { + if ("expressionViewer".equals(configuration.getName())) { + try { + ExpressionViewerFactory factory; + factory = (ExpressionViewerFactory) configuration + .createExecutableExtension("class"); + factory.init(configuration); + + list.add(factory); + } catch (CoreException e) { + String pluginId = configuration.getContributor().getName(); + LoggingSupport.log(UiPlugin.getDefault(), + new Status(IStatus.WARNING, pluginId, e.getMessage(), e)); + } + } else { + // skip as it is probably a expressionViewer element + } + } + factoryList = Collections.unmodifiableList(list); + } + return factoryList; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/FilterViewer.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/FilterViewer.java index c11c6c9bb1..3862c5d947 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/FilterViewer.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/filter/FilterViewer.java @@ -1,442 +1,447 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.filter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; - -import net.miginfocom.swt.MigLayout; -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExtensionPoint; -import org.eclipse.core.runtime.IExtensionRegistry; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.action.ContributionItem; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.dialogs.PopupDialog; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.MenuItem; -import org.eclipse.ui.part.PageBook; -import org.opengis.filter.Filter; - -/** - * {@link IFilterViewer} allowing user to switch between implementations. - *

    - * Note this implementation makes use of FilterViewerFactory when creating each viewer. We ask that - * you remember the "viewerId" in dialog settings or IMento so the user is not forced to choose - * which viewer is displayed each time. You can also use this facility as a hint when configuring - * the viewer for use. - * - *

    - * FilterViewer viewer = new FilterViewer(composite, SWT.MULTI);
    - * viewer.setViewerId("cql");
    - * 
    - * - * You will need to consult the extension point for the list of valid viewerIds. - * - * @author Jody Garnett - * @since 1.3.2 - */ -public class FilterViewer extends IFilterViewer { - /** - * IFilterViewer currently displayed in {@link #pageBook}. - */ - protected IFilterViewer delegate; - - private ISelectionChangedListener listener = new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - Filter delegateFilter = delegate.getFilter(); - internalUpdate(delegateFilter); - // The above internalUpdate will issue a fireSelectionChanged(event) - } - }; - - /** Control used to display {@link #pageBook} and {@link #viewerCombo}. */ - Composite control; - - /** - * PageBook acting as our control; used to switch between availabel implementations. - */ - private PageBook pageBook; - - /** - * Id of the viewer set by the user using the provided combo; may be supplied as an initial hint - * or saved and restored using IMemento or DialogSettings in order to preserve user context. - */ - private String viewerId; - - /** - * Remember the style used so we can pass it on when we create a delegate - */ - private int style; - - private SelectionListener menuListener = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - MenuItem menuItem = (MenuItem) e.widget; - - Object data = menuItem.getData(); - boolean selected = menuItem.getSelection(); - - if( selected && data instanceof String ){ - showViewer( (String) data ); - } - if( selected && data instanceof ContributionItem ){ - ContributionItem item = (ContributionItem) data; - - showViewer( (String) item.getId() ); - } - } - }; - - // private Menu menu; - - /** Cache of viewers responsible filter display and input */ - private HashMap pages; - - /** Placeholder displayed to request the user choose a viewer */ - private Label placeholder; - - /** Label offering the popup menu symbol */ - private Label config; - - public FilterViewer(Composite parent) { - this( parent, SWT.DEFAULT ); - } - /** - * Creates an FilterViewer using the provided style. - *
      - *
    • SWT.SINGLE - A simple text field showing the expression using extended CQL notation - *
    • - *
    • SWT.MULTI - A multi line text field
    • - *
    • SWT.READ_ONLY - read only display of a filter
    • - *
    - * - * @param parent - * @param style - */ - public FilterViewer(Composite parent, int style) { - control = new Composite(parent, SWT.NO_SCROLL){ - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - config.setEnabled(enabled); - if( delegate != null ){ - config.setEnabled(enabled); - } - if( input != null && input.getFeedback() != null && input.getFeedback().getControl() != null ){ - Control feedbackLabel = input.getFeedback().getControl(); - Display display = feedbackLabel.getDisplay(); - feedbackLabel.setEnabled(enabled); - if( enabled ){ - feedbackLabel.setForeground(display.getSystemColor(SWT.COLOR_TITLE_FOREGROUND)); - } - else { - feedbackLabel.setForeground(display.getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND)); - } - } - } - }; - control.setLayout(new MigLayout("insets 0", "[fill][]", "[fill]")); - - pageBook = new PageBook(control, SWT.NO_SCROLL); - pageBook.setLayoutData("cell 0 0,grow,width 200:100%:100%,height 18:75%:100%"); - - placeholder = new Label( pageBook, SWT.SINGLE ); - placeholder.setText("Choose filter editor"); - - delegate = new CQLFilterViewer(pageBook, style); - delegate.addSelectionChangedListener(listener); - pageBook.showPage(delegate.getControl()); - - this.pages = new HashMap(); - pages.put( FilterViewerFactory.CQL_FILTER_VIEWER, delegate ); - - config = new Label(control, SWT.SINGLE); - config.setImage(JFaceResources.getImage(PopupDialog.POPUP_IMG_MENU)); - config.setLayoutData("cell 1 0,aligny top,height 16!, width 16!"); - - createContextMenu( config ); - - config.addMouseListener(new MouseAdapter() { - public void mouseDown(org.eclipse.swt.events.MouseEvent e) { - Menu menu = config.getMenu(); - if( menu != null ){ - menu.setVisible(true); - } - } - }); - this.style = style; - } - - protected void showViewer(String newViewerId) { - if( newViewerId == null ){ - // show place holder label or default to CQL - newViewerId = FilterViewerFactory.CQL_FILTER_VIEWER; - } - this.viewerId = newViewerId; - - // update the page book if needed - IFilterViewer viewer = getViewer( this.viewerId ); - if( viewer == delegate ){ - return; // we already have this one displayed - } - String cqlText = null; - if( delegate instanceof CQLFilterViewer ){ - CQLFilterViewer cqlViewer = (CQLFilterViewer) delegate; - cqlText = cqlViewer.text.getText(); - } - - if( viewer == null ){ - pageBook.showPage(placeholder); - } - else { - feedback(); // clear any warnings - - // configure viewer before display! - FilterInput currentInput = getInput(); - Filter currentFilter = getFilter(); - - viewer.setInput( currentInput ); - viewer.setFilter( currentFilter ); - viewer.refresh(); - - // if available we can carry over the users text - typos and all - if( cqlText != null && viewer instanceof CQLFilterViewer){ - CQLFilterViewer cqlViewer = (CQLFilterViewer) viewer; - cqlViewer.text.setText( cqlText ); - } - // show page and listen to it for changes - pageBook.showPage(viewer.getControl()); - viewer.addSelectionChangedListener(listener); - } - if( delegate != null ){ - // showPage has already hidden delegate.getControl() - // so now we need to unplug it - delegate.removeSelectionChangedListener( listener ); - delegate.setInput(null); - } - delegate = viewer; - } - /** - * Lookup viewer implementation for the provided viewerId. - *

    - * The viewer will be created if needed; however it will not be hooked - * up with {@link #setInput}, {@link #setFilter} and {@link #addSelectionChangedListener} - * as this is done by {@link #showViewer(String)} when on an as needed basis. - * - * @param viewerId - * @return IFilterViewer or null if not available - */ - private IFilterViewer getViewer(String lookupId) { - IFilterViewer viewer = pages.get( lookupId ); - if( viewer != null ){ - // already constructed - return viewer; - } - for( FilterViewerFactory factory : filterViewerFactoryList() ){ - if( factory.getId().equals( lookupId )){ - viewer = factory.createViewer( pageBook, this.style ); - pages.put( factory.getId(), viewer ); - - return viewer; - } - } - return null; // user has requested an unknown id - please display placeholder - } - /** - * ViewerId currently shown (as selected by the user) - * - * @return viewerId currently shown (as selected by the user) - */ - public String getViewerId() { - return viewerId; - } - - /** - * This is the widget used to display the Filter; its parent has been provided in the - * ExpressionViewer's constructor; but you may need direct access to it in order to set layout - * data etc. - * - * @return - */ - public Control getControl() { - return control; - } - - @Override - public void refresh() { - if( viewerId == null && getInput() != null && getInput().getViewerId() != null ){ - // if the user has not already chosen a viewer; use the one marked down from dialog settings - showViewer( getInput().getViewerId() ); - } - if (delegate != null) { - delegate.refresh(); - } - List list = filterViewerFactory( getInput(), getFilter() ); - if( !list.isEmpty() ){ - FilterViewerFactory factory = list.get(0); - showViewer(factory.getId()); - } - } - - @Override - public void setInput(Object filterInput) { - super.setInput(filterInput); - if (delegate != null) { - delegate.setInput(filterInput); - } - } - - /** Used to supply a filter for display or editing */ - @Override - public void setFilter(Filter filter) { - if (this.filter == filter) { - return; - } - this.filter = filter; - if (delegate != null && delegate.getControl() != null - && !delegate.getControl().isDisposed()) { - try { - delegate.removeSelectionChangedListener(listener); - delegate.setFilter(filter); - } finally { - delegate.addSelectionChangedListener(listener); - } - } - fireSelectionChanged(new SelectionChangedEvent(FilterViewer.this, getSelection())); - } - - private void createContextMenu( Control control ){ - final MenuManager menuManager = new MenuManager(); - menuManager.setRemoveAllWhenShown(true); // we are going to generate - - menuManager.addMenuListener( new IMenuListener() { - public void menuAboutToShow(IMenuManager manager) { - int current = -1; - for( FilterViewerFactory factory : filterViewerFactory( getInput(), getFilter() ) ){ - int currentScore = factory.appropriate(getInput(), getFilter() ); - int category = FilterViewerFactory.toCategory( currentScore ); - if( current == -1 ){ - current = category; - } - else if( current != category ){ - menuManager.add( new Separator("appropriate "+current)); - current = category; - } - FilterViewerFactoryContributionItem contributionItem = new FilterViewerFactoryContributionItem(factory); - - menuManager.add( contributionItem ); - } - } - }); - Menu menu = menuManager.createContextMenu( control ); - control.setMenu( menu ); - } - - class FilterViewerFactoryContributionItem extends ContributionItem { - - private FilterViewerFactory factory; - - FilterViewerFactoryContributionItem( FilterViewerFactory factory ){ - setId( factory.getId() ); - this.factory = factory; - } - @Override - public void fill(Menu menu, int index) { - MenuItem item = new MenuItem( menu, SWT.RADIO, index ); - - item.setText( factory.getDisplayName() ); - item.setData( factory.getId() ); - item.setSelection( factory.getId().equals( viewerId ) ); - item.addSelectionListener( menuListener ); - - int appropriate = factory.appropriate( getInput(), getFilter() ); - - if( appropriate == FilterViewerFactory.NOT_APPROPRIATE ){ - item.setEnabled(false); - } - } - } - // - // Factory and Extension Point Support - // - /** Extension point ID */ - public static final String FILTER_VIEWER_EXTENSION = "org.locationtech.udig.ui.filterViewer"; - - private static List filterViewerFactoryList; - - private static List filterViewerFactory( final FilterInput input, final Filter filter ){ - List list = new ArrayList( filterViewerFactoryList() ); - Collections.sort( list, new Comparator(){ - public int compare(FilterViewerFactory factory1, FilterViewerFactory factory2) { - int factory1Score = factory1.appropriate( input, filter ); - int factory2Score = factory2.appropriate( input, filter ); - - return factory2Score - factory1Score; - } - }); - return list; - } - - private synchronized static List filterViewerFactoryList() { - if (filterViewerFactoryList == null) { - ArrayList list = new ArrayList(); - - IExtensionRegistry registery = Platform.getExtensionRegistry(); - IExtensionPoint extensionPoint = registery.getExtensionPoint(FILTER_VIEWER_EXTENSION); - - IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements(); - for (IConfigurationElement configuration : configurationElements) { - if ("filterViewer".equals(configuration.getName())) { - try { - FilterViewerFactory factory; - factory = (FilterViewerFactory) configuration.createExecutableExtension("class"); - factory.init(configuration); - - list.add(factory); - } catch (CoreException e) { - String pluginId = configuration.getContributor().getName(); - IStatus status = new Status(IStatus.WARNING, pluginId, e.getMessage(), e); - UiPlugin.log(status); - } - } else { - // skip as it is probably a expressionViewer element - } - } - filterViewerFactoryList = Collections.unmodifiableList( list ); - } - return filterViewerFactoryList; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.filter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.PopupDialog; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.ui.part.PageBook; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; +import org.opengis.filter.Filter; + +import net.miginfocom.swt.MigLayout; + +/** + * {@link IFilterViewer} allowing user to switch between implementations. + *

    + * Note this implementation makes use of FilterViewerFactory when creating each viewer. We ask that + * you remember the "viewerId" in dialog settings or IMento so the user is not forced to choose + * which viewer is displayed each time. You can also use this facility as a hint when configuring + * the viewer for use. + * + *

    + * FilterViewer viewer = new FilterViewer(composite, SWT.MULTI);
    + * viewer.setViewerId("cql");
    + * 
    + * + * You will need to consult the extension point for the list of valid viewerIds. + * + * @author Jody Garnett + * @since 1.3.2 + */ +public class FilterViewer extends IFilterViewer { + /** + * IFilterViewer currently displayed in {@link #pageBook}. + */ + protected IFilterViewer delegate; + + private ISelectionChangedListener listener = new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + Filter delegateFilter = delegate.getFilter(); + internalUpdate(delegateFilter); + // The above internalUpdate will issue a fireSelectionChanged(event) + } + }; + + /** Control used to display {@link #pageBook} and {@link #viewerCombo}. */ + Composite control; + + /** + * PageBook acting as our control; used to switch between availabel implementations. + */ + private PageBook pageBook; + + /** + * Id of the viewer set by the user using the provided combo; may be supplied as an initial hint + * or saved and restored using IMemento or DialogSettings in order to preserve user context. + */ + private String viewerId; + + /** + * Remember the style used so we can pass it on when we create a delegate + */ + private int style; + + private SelectionListener menuListener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + MenuItem menuItem = (MenuItem) e.widget; + + Object data = menuItem.getData(); + boolean selected = menuItem.getSelection(); + + if( selected && data instanceof String ){ + showViewer( (String) data ); + } + if( selected && data instanceof ContributionItem ){ + ContributionItem item = (ContributionItem) data; + + showViewer( item.getId() ); + } + } + }; + + // private Menu menu; + + /** Cache of viewers responsible filter display and input */ + private HashMap pages; + + /** Placeholder displayed to request the user choose a viewer */ + private Label placeholder; + + /** Label offering the popup menu symbol */ + private Label config; + + public FilterViewer(Composite parent) { + this( parent, SWT.DEFAULT ); + } + /** + * Creates an FilterViewer using the provided style. + *
      + *
    • SWT.SINGLE - A simple text field showing the expression using extended CQL notation + *
    • + *
    • SWT.MULTI - A multi line text field
    • + *
    • SWT.READ_ONLY - read only display of a filter
    • + *
    + * + * @param parent + * @param style + */ + public FilterViewer(Composite parent, int style) { + control = new Composite(parent, SWT.NO_SCROLL){ + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + config.setEnabled(enabled); + if( delegate != null ){ + config.setEnabled(enabled); + } + if( input != null && input.getFeedback() != null && input.getFeedback().getControl() != null ){ + Control feedbackLabel = input.getFeedback().getControl(); + Display display = feedbackLabel.getDisplay(); + feedbackLabel.setEnabled(enabled); + if( enabled ){ + feedbackLabel.setForeground(display.getSystemColor(SWT.COLOR_TITLE_FOREGROUND)); + } + else { + feedbackLabel.setForeground(display.getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND)); + } + } + } + }; + control.setLayout(new MigLayout("insets 0", "[fill][]", "[fill]")); + + pageBook = new PageBook(control, SWT.NO_SCROLL); + pageBook.setLayoutData("cell 0 0,grow,width 200:100%:100%,height 18:75%:100%"); + + placeholder = new Label( pageBook, SWT.SINGLE ); + placeholder.setText("Choose filter editor"); + + delegate = new CQLFilterViewer(pageBook, style); + delegate.addSelectionChangedListener(listener); + pageBook.showPage(delegate.getControl()); + + this.pages = new HashMap<>(); + pages.put( FilterViewerFactory.CQL_FILTER_VIEWER, delegate ); + + config = new Label(control, SWT.SINGLE); + config.setImage(JFaceResources.getImage(PopupDialog.POPUP_IMG_MENU)); + config.setLayoutData("cell 1 0,aligny top,height 16!, width 16!"); + + createContextMenu( config ); + + config.addMouseListener(new MouseAdapter() { + @Override + public void mouseDown(org.eclipse.swt.events.MouseEvent e) { + Menu menu = config.getMenu(); + if( menu != null ){ + menu.setVisible(true); + } + } + }); + this.style = style; + } + + protected void showViewer(String newViewerId) { + if( newViewerId == null ){ + // show place holder label or default to CQL + newViewerId = FilterViewerFactory.CQL_FILTER_VIEWER; + } + this.viewerId = newViewerId; + + // update the page book if needed + IFilterViewer viewer = getViewer( this.viewerId ); + if( viewer == delegate ){ + return; // we already have this one displayed + } + String cqlText = null; + if( delegate instanceof CQLFilterViewer ){ + CQLFilterViewer cqlViewer = (CQLFilterViewer) delegate; + cqlText = cqlViewer.text.getText(); + } + + if( viewer == null ){ + pageBook.showPage(placeholder); + } + else { + feedback(); // clear any warnings + + // configure viewer before display! + FilterInput currentInput = getInput(); + Filter currentFilter = getFilter(); + + viewer.setInput( currentInput ); + viewer.setFilter( currentFilter ); + viewer.refresh(); + + // if available we can carry over the users text - typos and all + if( cqlText != null && viewer instanceof CQLFilterViewer){ + CQLFilterViewer cqlViewer = (CQLFilterViewer) viewer; + cqlViewer.text.setText( cqlText ); + } + // show page and listen to it for changes + pageBook.showPage(viewer.getControl()); + viewer.addSelectionChangedListener(listener); + } + if( delegate != null ){ + // showPage has already hidden delegate.getControl() + // so now we need to unplug it + delegate.removeSelectionChangedListener( listener ); + delegate.setInput(null); + } + delegate = viewer; + } + /** + * Lookup viewer implementation for the provided viewerId. + *

    + * The viewer will be created if needed; however it will not be hooked + * up with {@link #setInput}, {@link #setFilter} and {@link #addSelectionChangedListener} + * as this is done by {@link #showViewer(String)} when on an as needed basis. + * + * @param viewerId + * @return IFilterViewer or null if not available + */ + private IFilterViewer getViewer(String lookupId) { + IFilterViewer viewer = pages.get( lookupId ); + if( viewer != null ){ + // already constructed + return viewer; + } + for( FilterViewerFactory factory : filterViewerFactoryList() ){ + if( factory.getId().equals( lookupId )){ + viewer = factory.createViewer( pageBook, this.style ); + pages.put( factory.getId(), viewer ); + + return viewer; + } + } + return null; // user has requested an unknown id - please display placeholder + } + /** + * ViewerId currently shown (as selected by the user) + * + * @return viewerId currently shown (as selected by the user) + */ + public String getViewerId() { + return viewerId; + } + + /** + * This is the widget used to display the Filter; its parent has been provided in the + * ExpressionViewer's constructor; but you may need direct access to it in order to set layout + * data etc. + * + * @return + */ + @Override + public Control getControl() { + return control; + } + + @Override + public void refresh() { + if( viewerId == null && getInput() != null && getInput().getViewerId() != null ){ + // if the user has not already chosen a viewer; use the one marked down from dialog settings + showViewer( getInput().getViewerId() ); + } + if (delegate != null) { + delegate.refresh(); + } + List list = filterViewerFactory( getInput(), getFilter() ); + if( !list.isEmpty() ){ + FilterViewerFactory factory = list.get(0); + showViewer(factory.getId()); + } + } + + @Override + public void setInput(Object filterInput) { + super.setInput(filterInput); + if (delegate != null) { + delegate.setInput(filterInput); + } + } + + /** Used to supply a filter for display or editing */ + @Override + public void setFilter(Filter filter) { + if (this.filter == filter) { + return; + } + this.filter = filter; + if (delegate != null && delegate.getControl() != null + && !delegate.getControl().isDisposed()) { + try { + delegate.removeSelectionChangedListener(listener); + delegate.setFilter(filter); + } finally { + delegate.addSelectionChangedListener(listener); + } + } + fireSelectionChanged(new SelectionChangedEvent(FilterViewer.this, getSelection())); + } + + private void createContextMenu( Control control ){ + final MenuManager menuManager = new MenuManager(); + menuManager.setRemoveAllWhenShown(true); // we are going to generate + + menuManager.addMenuListener( new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager manager) { + int current = -1; + for( FilterViewerFactory factory : filterViewerFactory( getInput(), getFilter() ) ){ + int currentScore = factory.appropriate(getInput(), getFilter() ); + int category = FilterViewerFactory.toCategory( currentScore ); + if( current == -1 ){ + current = category; + } + else if( current != category ){ + menuManager.add( new Separator("appropriate "+current)); + current = category; + } + FilterViewerFactoryContributionItem contributionItem = new FilterViewerFactoryContributionItem(factory); + + menuManager.add( contributionItem ); + } + } + }); + Menu menu = menuManager.createContextMenu( control ); + control.setMenu( menu ); + } + + class FilterViewerFactoryContributionItem extends ContributionItem { + + private FilterViewerFactory factory; + + FilterViewerFactoryContributionItem( FilterViewerFactory factory ){ + setId( factory.getId() ); + this.factory = factory; + } + @Override + public void fill(Menu menu, int index) { + MenuItem item = new MenuItem( menu, SWT.RADIO, index ); + + item.setText( factory.getDisplayName() ); + item.setData( factory.getId() ); + item.setSelection( factory.getId().equals( viewerId ) ); + item.addSelectionListener( menuListener ); + + int appropriate = factory.appropriate( getInput(), getFilter() ); + + if( appropriate == FilterViewerFactory.NOT_APPROPRIATE ){ + item.setEnabled(false); + } + } + } + // + // Factory and Extension Point Support + // + /** Extension point ID */ + public static final String FILTER_VIEWER_EXTENSION = "org.locationtech.udig.ui.filterViewer"; + + private static List filterViewerFactoryList; + + private static List filterViewerFactory( final FilterInput input, final Filter filter ){ + List list = new ArrayList<>( filterViewerFactoryList() ); + Collections.sort( list, new Comparator(){ + @Override + public int compare(FilterViewerFactory factory1, FilterViewerFactory factory2) { + int factory1Score = factory1.appropriate( input, filter ); + int factory2Score = factory2.appropriate( input, filter ); + + return factory2Score - factory1Score; + } + }); + return list; + } + + private synchronized static List filterViewerFactoryList() { + if (filterViewerFactoryList == null) { + ArrayList list = new ArrayList<>(); + + IExtensionRegistry registery = Platform.getExtensionRegistry(); + IExtensionPoint extensionPoint = registery.getExtensionPoint(FILTER_VIEWER_EXTENSION); + + IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements(); + for (IConfigurationElement configuration : configurationElements) { + if ("filterViewer".equals(configuration.getName())) { + try { + FilterViewerFactory factory; + factory = (FilterViewerFactory) configuration.createExecutableExtension("class"); + factory.init(configuration); + + list.add(factory); + } catch (CoreException e) { + String pluginId = configuration.getContributor().getName(); + LoggingSupport.log(UiPlugin.getDefault(), + new Status(IStatus.WARNING, pluginId, e.getMessage(), e)); + } + } else { + // skip as it is probably a expressionViewer element + } + } + filterViewerFactoryList = Collections.unmodifiableList( list ); + } + return filterViewerFactoryList; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/internal/Messages.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/internal/Messages.java index 1c3ac1e6b4..c111bda3b1 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/internal/Messages.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/internal/Messages.java @@ -1,300 +1,300 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - * - */ -package org.locationtech.udig.ui.internal; - -import java.lang.reflect.Field; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS { - private static final String BUNDLE_NAME = "org.locationtech.udig.ui.internal.messages"; //$NON-NLS-1$ - public static String AttributeValidator_missingAtt1; - public static String AttributeValidator_missingAtt2; - public static String AttributeValidator_restriction; - public static String AttributeValidator_wrongType; - public static String BooleanCellEditor_FALSE; - public static String BooleanCellEditor_TRUE; - public static String CharSetFieldEditor_select; - public static String CharsetSelectionDialog_title; - public static String CRSChooser_unknownWKT; - public static String CRSChooserDialog_title; - public static String ErrorManager_very_informative_error; - public static String ExceptionDisplayer_very_informative_error; - public static String FeatureTableContentProvider_loadedFeatures; - public static String FeatureTableContentProvider_loading ; - public static String FeatureTableContentProvider_outOfMemory; - public static String FeatureTableContentProvider_sortTable; - public static String FeatureTableContentProvider_unexpectedErro; - public static String FeatureTableContentProvider_probablecharseterror; - public static String FeatureTableContentProvider_updateTaskName; - public static String FeatureTableContentProvider_updatingFeatures; - public static String FeatureTableControl_1; - public static String FeatureTableControl_loading1; - public static String FeatureTableControl_loading2; - public static String FeatureTableControl_noEditor1; - public static String FeatureTableControl_noEditor2; - public static String FeatureTableControl_warningMessage; - public static String FeatureTableControl_warningTitle; - public static String FeatureTableControl_warningToggle; - public static String FeatureTableSelectionProvider_loading_new_selection; - public static String FeatureTypeEditor_booleanType; - public static String FeatureTypeEditorDialog_ShellTitle; - public static String FileExportOperation_allFiles; - public static String FileExportOperation_defaultName; - public static String FileExportOperation_finishStatus; - public static String FileExportOperation_prompt; - public static String FileExportOperation_writingStatus; - public static String OpAction_errorMessage; - public static String OpAction_errorTitle; - public static String OperationDialog_Message; - public static String OperationDialog_Operate; - public static String OperationDialog_PleaseSelect; - public static String OperationDialog_Title; - public static String OperationLabelProvider_unknown; - public static String PlatformGIS_background; - public static String RunOperationDialog_run_operation; - public static String RuntimeFieldEditor_error; - public static String RuntimeFieldEditor_locale; - public static String RuntimeFieldEditor_maxheap; - public static String RuntimeFieldEditor_memory_positive; - public static String RuntimeFieldEditor_path_not_existing; - public static String RuntimeFieldEditor_restart; - public static String RuntimeFieldEditor_workspace_path; - public static String SendLogDialog_contact; - public static String SendLogDialog_contact_message; - public static String SendLogDialog_description; - public static String SendLogDialog_empty; - public static String SendLogDialog_log; - public static String SendLogDialog_notes; - public static String SendLogDialog_notes_message; - public static String SendLogDialog_reading; - public static String SendLogDialog_submit; - public static String SendLogDialog_title; - public static String SubmitIssueDialog_instructions; - public static String SubmitIssueDialog_copy; - public static String ShutdownTaskList_shutDown; - public static String TransferPreference_transfer_preference_description; - public static String FeatureTextTransfer_transfer_name; - public static String FeatureTextTransfer_strategy_wkt_name; - public static String FeatureTextTransfer_strategy_gml_name; - public static String TipDialog_question; - public static String TipDialog_shellText; - public static String NewFeatureTypeOp_duplicateTypeName; - public static String deleteAttributeAction_tooltip; - public static String deleteAttributeAction_label; - public static String deleteAttributeAction_description; - public static String FeatureTypeEditor_newAttributeTypeDefaultName; - public static String FeatureTypeEditor_newFeatureTypeName; - public static String FeatureTypeEditor_typeColumnName; - public static String FeatureTypeEditor_nameColumnName; - public static String FeatureTypeEditor_lengthColumnName; - public static String FeatureTypeEditor_isNullColumnName; - public static String FeatureTableControl_loadingMessage; - public static String FeatureTypeEditor_multiPolygonType; - public static String FeatureTypeEditor_defaultNameAttributeName; - public static String FeatureTypeEditor_defaultGeometryName; - public static String FeatureTypeEditor_multiLineStringType; - public static String FeatureTypeEditor_multiPointType; - public static String FeatureTypeEditor_geometryType; - public static String FeatureTypeEditor_polygonType; - public static String FeatureTypeEditor_lineStringType; - public static String FeatureTypeEditor_pointType; - public static String FeatureTypeEditor_floatType; - public static String FeatureTypeEditor_doubleType; - public static String FeatureTypeEditor_longType; - public static String FeatureTypeEditor_integerType; - public static String FeatureTypeEditor_dateType; - public static String FeatureTypeEditor_stringType; - public static String UDIGApplication_error2; - public static String UDIGApplication_error1; - public static String UDIGApplication_title; - public static String UDIGApplication_error; - public static String UDIGDropHandler_jobName; - public static String UDIGDropHandler_error; - public static String OperationMenuFactory_menu_text; - public static String AuthenticationDialog_dialog_title; - public static String AuthenticationDialog_label_rememberPassword; - public static String AuthenticationDialog_label_password; - public static String AuthenticationDialog_label_username; - public static String AuthenticationDialog_label_prompt; - public static String UDIGDropHandler_performing_task; - public static String UDIGWorkbenchAdvisor_welcome_text; - public static String UDIGWorkbenchAdvisor_closeAllPerspectives_text; - public static String UDIGWorkbenchAdvisor_closePerspective_text; - public static String UDIGWorkbenchAdvisor_aboutUDig_text; - public static String UDIGWorkbenchAdvisor_newWindow_text; - public static String UDIGWorkbenchAdvisor_navigationMenu; - public static String UDIGWorkbenchAdvisor_helpContents_text; - public static String UDIGWorkbenchAdvisor_preferences_text; - public static String UDIGWorkbenchAdvisor_resetPerspective_text; - public static String UDIGWorkbenchAdvisor_open_perspective; - public static String UDIGWorkbenchAdvisor_help; - public static String UDIGWorkbenchAdvisor_layerMenu; - public static String UDIGWorkbenchAdvisor_show_view; - public static String UDIGWorkbenchAdvisor_window; - public static String UDIGWorkbenchAdvisor_tools; - public static String UDIGWorkbenchAdvisor_edit; - public static String UDIGWorkbenchAdvisor_new; - public static String UDIGWorkbenchAdvisor_file; - public static String UDIGApplication_error_jai_warning_text; - public static String UDIGApplication_error_jai_warning_title; - public static String UDIGApplication_helpstring; - public static String UDIGWorkbenchWindowAdvisor_classNotFound; - public static String UDIGWorkbenchWindowAdvisor_specifiedButNotFound; - public static String RuntimePreferences_desc; - public static String UiPreferences_advancedGraphics_label; - public static String UiPreferences_charset; - public static String UiPreferences_description; - public static String UiPreferences_ImperialUnits; - public static String UiPreferences_MetricUnits; - public static String UiPreferences_AutoUnits; - public static String UiPreferences_UnitsLabel; - public static String CRSChooser_tooltip; - public static String CRSChooser_unnamed; - public static String CRSChooser_keywordsLabel; - public static String CRSChooser_tab_customCRS; - public static String CRSChooser_tab_standardCRS; - public static String CRSChooser_label_crs; - public static String CRSChooser_label_crsWKT; - - public static String cancel_label; - public static String cancel_image; -// public static String cancel_description; -// public static String cancel_tooltip; - - public static String orientation_horizontal_label; - public static String orientation_horizontal_image; -// public static String orientation_horizontal_description; -// public static String orientation_horizontal_tooltip; - - public static String orientation_vertical_label; - public static String orientation_vertical_image; -// public static String orientation_vertical_description; -// public static String orientation_vertical_tooltip; - - public static String orientation_single_label; - public static String orientation_single_image; -// public static String orientation_single_description; -// public static String orientation_single_tooltip; - - public static String orientation_automatic_label; - public static String orientation_automatic_image; -// public static String orientation_automatic_description; -// public static String orientation_automatic_tooltip; - - public static String addAttributeAction_label; - public static String DefaultExpressionViewer_attribute; - public static String DefaultExpressionViewer_operation; - public static String DefaultExpressionViewer_value; - - public static String ExceptionDetailsEditorMessage; - - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } - - /** - * Initialize the given Action from a ResourceBundle. - *

    - * Makes use of the following keys: - *

      - *
    • prefix.label - *
    • prefix.tooltip - *
    • prefix.image - *
    • prefix.description - *

      - *

      - * Note: The use of a single image value is mapped to images for both the enabled and distabled - * state of the IAction. the Local toolbar (elcl16/ and dlcl16/) is assumed if a path has not - * been provided. - * - *

      
      -     *  add_co.gif              (prefix.image)
      -     *     enabled: elcl16/add_co.gif
      -     *    disabled: dlcl/remove_co.gif
      -     *  tool16/discovery_wiz.16 (prefix.image)
      -     *     enabled: etool16/discovery_wiz.16
      -     *    disabled: etool16/discovery_wiz.16
      -     * 
      - * - *

      - * - * @param a action - * @param id used for binding (id.label, id.tooltip, ...) - * @deprecated not safe, using this will cause bugs. jeichar - */ - public static void initAction( IAction a, String id ) { - String labelKey = "_label"; //$NON-NLS-1$ - String tooltipKey = "_tooltip"; //$NON-NLS-1$ - String imageKey = "_image"; //$NON-NLS-1$ - String descriptionKey = "_description"; //$NON-NLS-1$ - if (id != null && id.length() > 0) { - labelKey = id + labelKey; - tooltipKey = id + tooltipKey; - imageKey = id + imageKey; - descriptionKey = id + descriptionKey; - } - String s = bind(labelKey); - if (s != null) - a.setText(s); - s = bind(tooltipKey); - if (s != null) - a.setToolTipText(s); - s = bind(descriptionKey); - if (s != null) - a.setDescription(s); - String relPath = bind(imageKey); - if (relPath != null && !relPath.equals(imageKey) && relPath.trim().length() > 0) { - String dPath; - String ePath; - if (relPath.indexOf("/") >= 0) { //$NON-NLS-1$ - String path = relPath.substring(1); - dPath = 'd' + path; - ePath = 'e' + path; - } else { - dPath = "dlcl16/" + relPath; //$NON-NLS-1$ - ePath = "elcl16/" + relPath; //$NON-NLS-1$ - } - ImageDescriptor image; - - image = UiPlugin.getDefault().getImageDescriptor(ePath); - if (id != null) { - a.setImageDescriptor(image); - } - image = UiPlugin.getDefault().getImageDescriptor(dPath); - if (id != null) { - a.setDisabledImageDescriptor(image); - } - } - } - - private static String bind(String fieldName) { - Field field; - try { - field = Messages.class.getDeclaredField(fieldName); - return (String) field.get(null); - } catch(NoSuchFieldException ignore){ - return null; // not available (example tooltip or description not available) - } catch (Exception e) { - UiPlugin.log("Error loading key " + fieldName, e); //$NON-NLS-1$ - } - return null; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + * + */ +package org.locationtech.udig.ui.internal; + +import java.lang.reflect.Field; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.osgi.util.NLS; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.locationtech.udig.ui.internal.messages"; //$NON-NLS-1$ + public static String AttributeValidator_missingAtt1; + public static String AttributeValidator_missingAtt2; + public static String AttributeValidator_restriction; + public static String AttributeValidator_wrongType; + public static String BooleanCellEditor_FALSE; + public static String BooleanCellEditor_TRUE; + public static String CharSetFieldEditor_select; + public static String CharsetSelectionDialog_title; + public static String CRSChooser_unknownWKT; + public static String CRSChooserDialog_title; + public static String ErrorManager_very_informative_error; + public static String ExceptionDisplayer_very_informative_error; + public static String FeatureTableContentProvider_loadedFeatures; + public static String FeatureTableContentProvider_loading ; + public static String FeatureTableContentProvider_outOfMemory; + public static String FeatureTableContentProvider_sortTable; + public static String FeatureTableContentProvider_unexpectedErro; + public static String FeatureTableContentProvider_probablecharseterror; + public static String FeatureTableContentProvider_updateTaskName; + public static String FeatureTableContentProvider_updatingFeatures; + public static String FeatureTableControl_1; + public static String FeatureTableControl_loading1; + public static String FeatureTableControl_loading2; + public static String FeatureTableControl_noEditor1; + public static String FeatureTableControl_noEditor2; + public static String FeatureTableControl_warningMessage; + public static String FeatureTableControl_warningTitle; + public static String FeatureTableControl_warningToggle; + public static String FeatureTableSelectionProvider_loading_new_selection; + public static String FeatureTypeEditor_booleanType; + public static String FeatureTypeEditorDialog_ShellTitle; + public static String FileExportOperation_allFiles; + public static String FileExportOperation_defaultName; + public static String FileExportOperation_finishStatus; + public static String FileExportOperation_prompt; + public static String FileExportOperation_writingStatus; + public static String OpAction_errorMessage; + public static String OpAction_errorTitle; + public static String OperationDialog_Message; + public static String OperationDialog_Operate; + public static String OperationDialog_PleaseSelect; + public static String OperationDialog_Title; + public static String OperationLabelProvider_unknown; + public static String PlatformGIS_background; + public static String RunOperationDialog_run_operation; + public static String RuntimeFieldEditor_error; + public static String RuntimeFieldEditor_locale; + public static String RuntimeFieldEditor_maxheap; + public static String RuntimeFieldEditor_memory_positive; + public static String RuntimeFieldEditor_path_not_existing; + public static String RuntimeFieldEditor_restart; + public static String RuntimeFieldEditor_workspace_path; + public static String SendLogDialog_contact; + public static String SendLogDialog_contact_message; + public static String SendLogDialog_description; + public static String SendLogDialog_empty; + public static String SendLogDialog_log; + public static String SendLogDialog_notes; + public static String SendLogDialog_notes_message; + public static String SendLogDialog_reading; + public static String SendLogDialog_submit; + public static String SendLogDialog_title; + public static String SubmitIssueDialog_instructions; + public static String SubmitIssueDialog_copy; + public static String ShutdownTaskList_shutDown; + public static String TransferPreference_transfer_preference_description; + public static String FeatureTextTransfer_transfer_name; + public static String FeatureTextTransfer_strategy_wkt_name; + public static String FeatureTextTransfer_strategy_gml_name; + public static String TipDialog_question; + public static String TipDialog_shellText; + public static String NewFeatureTypeOp_duplicateTypeName; + public static String deleteAttributeAction_tooltip; + public static String deleteAttributeAction_label; + public static String deleteAttributeAction_description; + public static String FeatureTypeEditor_newAttributeTypeDefaultName; + public static String FeatureTypeEditor_newFeatureTypeName; + public static String FeatureTypeEditor_typeColumnName; + public static String FeatureTypeEditor_nameColumnName; + public static String FeatureTypeEditor_lengthColumnName; + public static String FeatureTypeEditor_isNullColumnName; + public static String FeatureTableControl_loadingMessage; + public static String FeatureTypeEditor_multiPolygonType; + public static String FeatureTypeEditor_defaultNameAttributeName; + public static String FeatureTypeEditor_defaultGeometryName; + public static String FeatureTypeEditor_multiLineStringType; + public static String FeatureTypeEditor_multiPointType; + public static String FeatureTypeEditor_geometryType; + public static String FeatureTypeEditor_polygonType; + public static String FeatureTypeEditor_lineStringType; + public static String FeatureTypeEditor_pointType; + public static String FeatureTypeEditor_floatType; + public static String FeatureTypeEditor_doubleType; + public static String FeatureTypeEditor_longType; + public static String FeatureTypeEditor_integerType; + public static String FeatureTypeEditor_dateType; + public static String FeatureTypeEditor_stringType; + public static String UDIGApplication_error2; + public static String UDIGApplication_error1; + public static String UDIGApplication_title; + public static String UDIGApplication_error; + public static String UDIGDropHandler_jobName; + public static String UDIGDropHandler_error; + public static String OperationMenuFactory_menu_text; + public static String AuthenticationDialog_dialog_title; + public static String AuthenticationDialog_label_rememberPassword; + public static String AuthenticationDialog_label_password; + public static String AuthenticationDialog_label_username; + public static String AuthenticationDialog_label_prompt; + public static String UDIGDropHandler_performing_task; + public static String UDIGWorkbenchAdvisor_welcome_text; + public static String UDIGWorkbenchAdvisor_closeAllPerspectives_text; + public static String UDIGWorkbenchAdvisor_closePerspective_text; + public static String UDIGWorkbenchAdvisor_aboutUDig_text; + public static String UDIGWorkbenchAdvisor_newWindow_text; + public static String UDIGWorkbenchAdvisor_navigationMenu; + public static String UDIGWorkbenchAdvisor_helpContents_text; + public static String UDIGWorkbenchAdvisor_preferences_text; + public static String UDIGWorkbenchAdvisor_resetPerspective_text; + public static String UDIGWorkbenchAdvisor_open_perspective; + public static String UDIGWorkbenchAdvisor_help; + public static String UDIGWorkbenchAdvisor_layerMenu; + public static String UDIGWorkbenchAdvisor_show_view; + public static String UDIGWorkbenchAdvisor_window; + public static String UDIGWorkbenchAdvisor_tools; + public static String UDIGWorkbenchAdvisor_edit; + public static String UDIGWorkbenchAdvisor_new; + public static String UDIGWorkbenchAdvisor_file; + public static String UDIGApplication_error_jai_warning_text; + public static String UDIGApplication_error_jai_warning_title; + public static String UDIGApplication_helpstring; + public static String UDIGWorkbenchWindowAdvisor_classNotFound; + public static String UDIGWorkbenchWindowAdvisor_specifiedButNotFound; + public static String RuntimePreferences_desc; + public static String UiPreferences_advancedGraphics_label; + public static String UiPreferences_charset; + public static String UiPreferences_description; + public static String UiPreferences_ImperialUnits; + public static String UiPreferences_MetricUnits; + public static String UiPreferences_AutoUnits; + public static String UiPreferences_UnitsLabel; + public static String CRSChooser_tooltip; + public static String CRSChooser_unnamed; + public static String CRSChooser_keywordsLabel; + public static String CRSChooser_tab_customCRS; + public static String CRSChooser_tab_standardCRS; + public static String CRSChooser_label_crs; + public static String CRSChooser_label_crsWKT; + + public static String cancel_label; + public static String cancel_image; +// public static String cancel_description; +// public static String cancel_tooltip; + + public static String orientation_horizontal_label; + public static String orientation_horizontal_image; +// public static String orientation_horizontal_description; +// public static String orientation_horizontal_tooltip; + + public static String orientation_vertical_label; + public static String orientation_vertical_image; +// public static String orientation_vertical_description; +// public static String orientation_vertical_tooltip; + + public static String orientation_single_label; + public static String orientation_single_image; +// public static String orientation_single_description; +// public static String orientation_single_tooltip; + + public static String orientation_automatic_label; + public static String orientation_automatic_image; +// public static String orientation_automatic_description; +// public static String orientation_automatic_tooltip; + + public static String addAttributeAction_label; + public static String DefaultExpressionViewer_attribute; + public static String DefaultExpressionViewer_operation; + public static String DefaultExpressionViewer_value; + + public static String ExceptionDetailsEditorMessage; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } + + /** + * Initialize the given Action from a ResourceBundle. + *

      + * Makes use of the following keys: + *

        + *
      • prefix.label + *
      • prefix.tooltip + *
      • prefix.image + *
      • prefix.description + *

        + *

        + * Note: The use of a single image value is mapped to images for both the enabled and distabled + * state of the IAction. the Local toolbar (elcl16/ and dlcl16/) is assumed if a path has not + * been provided. + * + *

        
        +     *  add_co.gif              (prefix.image)
        +     *     enabled: elcl16/add_co.gif
        +     *    disabled: dlcl/remove_co.gif
        +     *  tool16/discovery_wiz.16 (prefix.image)
        +     *     enabled: etool16/discovery_wiz.16
        +     *    disabled: etool16/discovery_wiz.16
        +     * 
        + * + *

        + * + * @param a action + * @param id used for binding (id.label, id.tooltip, ...) + * @deprecated not safe, using this will cause bugs. jeichar + */ + public static void initAction( IAction a, String id ) { + String labelKey = "_label"; //$NON-NLS-1$ + String tooltipKey = "_tooltip"; //$NON-NLS-1$ + String imageKey = "_image"; //$NON-NLS-1$ + String descriptionKey = "_description"; //$NON-NLS-1$ + if (id != null && id.length() > 0) { + labelKey = id + labelKey; + tooltipKey = id + tooltipKey; + imageKey = id + imageKey; + descriptionKey = id + descriptionKey; + } + String s = bind(labelKey); + if (s != null) + a.setText(s); + s = bind(tooltipKey); + if (s != null) + a.setToolTipText(s); + s = bind(descriptionKey); + if (s != null) + a.setDescription(s); + String relPath = bind(imageKey); + if (relPath != null && !relPath.equals(imageKey) && relPath.trim().length() > 0) { + String dPath; + String ePath; + if (relPath.indexOf("/") >= 0) { //$NON-NLS-1$ + String path = relPath.substring(1); + dPath = 'd' + path; + ePath = 'e' + path; + } else { + dPath = "dlcl16/" + relPath; //$NON-NLS-1$ + ePath = "elcl16/" + relPath; //$NON-NLS-1$ + } + ImageDescriptor image; + + image = UiPlugin.getDefault().getImageDescriptor(ePath); + if (id != null) { + a.setImageDescriptor(image); + } + image = UiPlugin.getDefault().getImageDescriptor(dPath); + if (id != null) { + a.setDisabledImageDescriptor(image); + } + } + } + + private static String bind(String fieldName) { + Field field; + try { + field = Messages.class.getDeclaredField(fieldName); + return (String) field.get(null); + } catch (NoSuchFieldException ignore) { + return null; // not available (example tooltip or description not available) + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error loading key " + fieldName, e); //$NON-NLS-1$ + } + return null; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/AdaptsToParserImpl.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/AdaptsToParserImpl.java index 0c8bbb1cb7..802c36aacd 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/AdaptsToParserImpl.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/AdaptsToParserImpl.java @@ -1,31 +1,36 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.operations; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.runtime.IConfigurationElement; - -public class AdaptsToParserImpl implements FilterParser { - - public OpFilter parse( IConfigurationElement element ) { - String adaptsTo = element.getAttribute("target"); //$NON-NLS-1$ - if( adaptsTo.trim().length()==0 ){ - UiPlugin.log("AdaptsToParserImpl:Parsing OpFilter: adapts to attribute is empty string"+element.getNamespaceIdentifier(), null); //$NON-NLS-1$ - - return OpFilter.TRUE; - } - return new AdaptsToFilter(adaptsTo); - } - - public String getElementName() { - return "adaptsTo"; //$NON-NLS-1$ - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.operations; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +public class AdaptsToParserImpl implements FilterParser { + + @Override + public OpFilter parse(IConfigurationElement element) { + String adaptsTo = element.getAttribute("target"); //$NON-NLS-1$ + if (adaptsTo.trim().length() == 0) { + LoggingSupport.log(UiPlugin.getDefault(), + "AdaptsToParserImpl:Parsing OpFilter: adapts to attribute is empty string" //$NON-NLS-1$ + + element.getNamespaceIdentifier(), + null); + + return OpFilter.TRUE; + } + return new AdaptsToFilter(adaptsTo); + } + + @Override + public String getElementName() { + return "adaptsTo"; //$NON-NLS-1$ + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/EnablementUtil.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/EnablementUtil.java index d0cc65fdaa..01c5409327 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/EnablementUtil.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/EnablementUtil.java @@ -1,95 +1,95 @@ -/** - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.operations; - -import org.eclipse.core.runtime.IConfigurationElement; -import org.locationtech.udig.internal.ui.UiPlugin; - -/** - * Utility class for parsing enablement children - * - * @author Jesse - * @since 1.1.0 - */ -public class EnablementUtil { - - public static OpFilter parseEnablement(String extensionID, IConfigurationElement[] enablement) { - - if (!validateChildren(extensionID, enablement) || enablement[0] == null) { - if (enablement.length > 0 && enablement[0] == null) - UiPlugin.log("EnablementUtil: null enablement", null); //$NON-NLS-1$ - return OpFilter.TRUE; - } - - IConfigurationElement[] children = enablement[0].getChildren(); - if (!validateChildren(extensionID, children)) { - UiPlugin.log( - "EnablementUtil: Expected child of " + extensionID + " but didn't find one...", //$NON-NLS-1$ //$NON-NLS-2$ - null); - return OpFilter.TRUE; - } - OpFilterParser parser = new OpFilterParser( - new FilterParser[] { new AdaptsToParserImpl(), new PropertyParser() }); - return parser.parseFilter(children[0]); - - } - - private static boolean validateChildren(String extensionID, IConfigurationElement[] children) { - - if (children.length < 1) { - return false; - } - if (children.length > 1) { - UiPlugin.log("EnablementUtil: Error, more than one enablement element " + extensionID, //$NON-NLS-1$ - null); - return false; - } - return true; - } - - public static EnablesForData parseEnablesFor(String enablesFor, - IConfigurationElement configElem) { - if (enablesFor == null) { - enablesFor = "1"; //$NON-NLS-1$ - } - - enablesFor = enablesFor.trim(); - EnablesForData data = new EnablesForData(); - if (enablesFor.equals("+")) { //$NON-NLS-1$ - data.minHits = 1; - data.exactMatch = false; - } else if (enablesFor.equals("multiple")) { //$NON-NLS-1$ - data.minHits = 2; - data.exactMatch = false; - } else if (enablesFor.equals("2+")) { //$NON-NLS-1$ - data.minHits = 2; - data.exactMatch = false; - } else { - try { - data.minHits = Integer.parseInt(enablesFor); - data.exactMatch = true; - } catch (Exception e) { - UiPlugin.log("Error parsing extension: " + configElem.getNamespaceIdentifier() + "/" //$NON-NLS-1$//$NON-NLS-2$ - + configElem.getName(), e); - data.minHits = 0; - data.exactMatch = false; - } - } - return data; - } - - public static class EnablesForData { - int minHits = 0; - - boolean exactMatch = false; - } - -} +/** + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.operations; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +/** + * Utility class for parsing enablement children + * + * @author Jesse + * @since 1.1.0 + */ +public class EnablementUtil { + + public static OpFilter parseEnablement(String extensionID, IConfigurationElement[] enablement) { + + if (!validateChildren(extensionID, enablement) || enablement[0] == null) { + if (enablement.length > 0 && enablement[0] == null) + LoggingSupport.log(UiPlugin.getDefault(), "EnablementUtil: null enablement"); //$NON-NLS-1$ + return OpFilter.TRUE; + } + + IConfigurationElement[] children = enablement[0].getChildren(); + if (!validateChildren(extensionID, children)) { + LoggingSupport.log(UiPlugin.getDefault(), + "EnablementUtil: Expected child of " + extensionID + " but didn't find one..."); //$NON-NLS-1$ //$NON-NLS-2$ + return OpFilter.TRUE; + } + OpFilterParser parser = new OpFilterParser( + new FilterParser[] { new AdaptsToParserImpl(), new PropertyParser() }); + return parser.parseFilter(children[0]); + + } + + private static boolean validateChildren(String extensionID, IConfigurationElement[] children) { + + if (children.length < 1) { + return false; + } + if (children.length > 1) { + LoggingSupport.log(UiPlugin.getDefault(), + "EnablementUtil: Error, more than one enablement element " + extensionID); //$NON-NLS-1$ + return false; + } + return true; + } + + public static EnablesForData parseEnablesFor(String enablesFor, + IConfigurationElement configElem) { + if (enablesFor == null) { + enablesFor = "1"; //$NON-NLS-1$ + } + + enablesFor = enablesFor.trim(); + EnablesForData data = new EnablesForData(); + if (enablesFor.equals("+")) { //$NON-NLS-1$ + data.minHits = 1; + data.exactMatch = false; + } else if (enablesFor.equals("multiple")) { //$NON-NLS-1$ + data.minHits = 2; + data.exactMatch = false; + } else if (enablesFor.equals("2+")) { //$NON-NLS-1$ + data.minHits = 2; + data.exactMatch = false; + } else { + try { + data.minHits = Integer.parseInt(enablesFor); + data.exactMatch = true; + } catch (Exception e) { + LoggingSupport.log(UiPlugin.getDefault(), "Error parsing extension: " //$NON-NLS-1$ + + configElem.getNamespace() + "/" + configElem.getName(), e); //$NON-NLS-1$ + data.minHits = 0; + data.exactMatch = false; + } + } + return data; + } + + public static class EnablesForData { + int minHits = 0; + + boolean exactMatch = false; + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/LazyOpFilter.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/LazyOpFilter.java index 72ac941356..c949c367c3 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/LazyOpFilter.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/LazyOpFilter.java @@ -1,197 +1,206 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.operations; - -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.locationtech.udig.internal.ui.UiPlugin; - -/** - * A non-blocking version of the LazyOpFilter. Returns false first then calculates whether it is in - * fact false or true in a seperate thread and notifies the listeners of the actual state. - * - * @author Jesse - * @since 1.1.0 - */ -public class LazyOpFilter implements OpFilter { - - private final OpFilter opFilter; - private final ILazyOpListener listener; - private Worker worker; - final Map cache=new WeakHashMap(); - final boolean blocking, caching; - final Lock lock =new ReentrantLock(); - - private IOpFilterListener changeListener = new IOpFilterListener(){ - - public void notifyChange( Object changedLayer ) { - boolean notify=false; - boolean newResult=false; - - lock.lock(); - try{ - if( !enabled ){ - UiPlugin.log("Warning listener called even though not enabled", new Exception()); //$NON-NLS-1$ - return; - } - if( opFilter.canCacheResult() ){ - Boolean removed = cache.get(changedLayer); - if (removed != null) { - cache.remove(changedLayer); - if (listener != null) { - newResult = acceptInternal(changedLayer, removed); - if (newResult != removed.booleanValue()){ - notify=true; - } - } - } - } - else { - notify = true; - newResult = accept( changedLayer ); - } - }finally{ - lock.unlock(); - } - if( notify ) - listener.notifyResultObtained(newResult); - } - - }; - private boolean enabled; - - /** - * Executor used to run enablement calculation in a background thread. - */ - private static final ExecutorService executor = Executors.newSingleThreadExecutor(); - /** - * Default value to use while enablement worker is running. - */ - public static final boolean DEFAULT_RETURN_VALUE = true; - - public LazyOpFilter( final ILazyOpListener listener, final OpFilter opFilter ) { - this.listener = listener; - this.opFilter = opFilter; - - caching=opFilter.canCacheResult(); - - blocking = opFilter.isBlocking(); - enabled=false; - } - /** - * Will safely run the enablement worker (protected by a lock). - */ - public boolean accept( final Object object ) { - lock.lock(); - try{ - if( !enabled ){ - enabled=true; - opFilter.addListener(changeListener); - } - return acceptInternal(object, DEFAULT_RETURN_VALUE); - }finally{ - lock.unlock(); - } - } - /** Method used by accept; must be protected by lock */ - private boolean acceptInternal( final Object object, boolean defaultReturnValue ) { - if (worker != null) { - worker.cancel(); - } - - Boolean result = cache.get(object); - if (result != null && caching) - return result; - - if( result==null ) - result=defaultReturnValue; - - if (blocking) { - worker = new Worker(object); - executor.submit(worker); - } else { - result = opFilter.accept(object); - cache.put(object, result); - } - - return result; - } - /** - * Internal worker used to check enablement. - */ - private class Worker implements Runnable { - private final Object object; - private volatile boolean cancelled; - - public Worker( final Object object ) { - this.object = object; - cancelled = false; - } - - public void cancel() { - cancelled = true; - } - - public void run() { - boolean result; - synchronized (LazyOpFilter.this) { - result = opFilter.accept(object); - cache.put(object, result); - } - if (!cancelled) { - listener.notifyResultObtained(result); - } - } - - } - /** - * Listener; used to report on worker progress - */ - public void addListener( IOpFilterListener listener ) { - throw new UnsupportedOperationException(); - } - /** - * Subclass must override? - */ - public boolean canCacheResult() { - throw new UnsupportedOperationException(); - } - - /** - * Subclass must override? - */ - public boolean isBlocking() { - throw new UnsupportedOperationException(); - } - - public void removeListener( IOpFilterListener listener ) { - throw new UnsupportedOperationException(); - } - - public void disable(){ - lock.lock(); - try{ - enabled=false; - opFilter.removeListener(changeListener); - }finally{ - lock.unlock(); - } - } - - @Override - public String toString() { - return "LazyOpFilter "+this.opFilter; - } -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.operations; + +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +/** + * A non-blocking version of the LazyOpFilter. Returns false first then calculates whether it is in + * fact false or true in a seperate thread and notifies the listeners of the actual state. + * + * @author Jesse + * @since 1.1.0 + */ +public class LazyOpFilter implements OpFilter { + + private final OpFilter opFilter; + private final ILazyOpListener listener; + private Worker worker; + final Map cache=new WeakHashMap<>(); + final boolean blocking, caching; + final Lock lock =new ReentrantLock(); + + private IOpFilterListener changeListener = new IOpFilterListener(){ + + @Override + public void notifyChange( Object changedLayer ) { + boolean notify=false; + boolean newResult=false; + + lock.lock(); + try{ + if( !enabled ){ + LoggingSupport.log(UiPlugin.getDefault(), new IllegalStateException( + "Warning listener called even though not enabled")); //$NON-NLS-1$ + return; + } + if( opFilter.canCacheResult() ){ + Boolean removed = cache.get(changedLayer); + if (removed != null) { + cache.remove(changedLayer); + if (listener != null) { + newResult = acceptInternal(changedLayer, removed); + if (newResult != removed.booleanValue()){ + notify=true; + } + } + } + } + else { + notify = true; + newResult = accept( changedLayer ); + } + }finally{ + lock.unlock(); + } + if( notify ) + listener.notifyResultObtained(newResult); + } + + }; + private boolean enabled; + + /** + * Executor used to run enablement calculation in a background thread. + */ + private static final ExecutorService executor = Executors.newSingleThreadExecutor(); + /** + * Default value to use while enablement worker is running. + */ + public static final boolean DEFAULT_RETURN_VALUE = true; + + public LazyOpFilter( final ILazyOpListener listener, final OpFilter opFilter ) { + this.listener = listener; + this.opFilter = opFilter; + + caching=opFilter.canCacheResult(); + + blocking = opFilter.isBlocking(); + enabled=false; + } + /** + * Will safely run the enablement worker (protected by a lock). + */ + @Override + public boolean accept( final Object object ) { + lock.lock(); + try{ + if( !enabled ){ + enabled=true; + opFilter.addListener(changeListener); + } + return acceptInternal(object, DEFAULT_RETURN_VALUE); + }finally{ + lock.unlock(); + } + } + /** Method used by accept; must be protected by lock */ + private boolean acceptInternal( final Object object, boolean defaultReturnValue ) { + if (worker != null) { + worker.cancel(); + } + + Boolean result = cache.get(object); + if (result != null && caching) + return result; + + if( result==null ) + result=defaultReturnValue; + + if (blocking) { + worker = new Worker(object); + executor.submit(worker); + } else { + result = opFilter.accept(object); + cache.put(object, result); + } + + return result; + } + /** + * Internal worker used to check enablement. + */ + private class Worker implements Runnable { + private final Object object; + private volatile boolean cancelled; + + public Worker( final Object object ) { + this.object = object; + cancelled = false; + } + + public void cancel() { + cancelled = true; + } + + @Override + public void run() { + boolean result; + synchronized (LazyOpFilter.this) { + result = opFilter.accept(object); + cache.put(object, result); + } + if (!cancelled) { + listener.notifyResultObtained(result); + } + } + + } + /** + * Listener; used to report on worker progress + */ + @Override + public void addListener( IOpFilterListener listener ) { + throw new UnsupportedOperationException(); + } + /** + * Subclass must override? + */ + @Override + public boolean canCacheResult() { + throw new UnsupportedOperationException(); + } + + /** + * Subclass must override? + */ + @Override + public boolean isBlocking() { + throw new UnsupportedOperationException(); + } + + @Override + public void removeListener( IOpFilterListener listener ) { + throw new UnsupportedOperationException(); + } + + public void disable(){ + lock.lock(); + try{ + enabled=false; + opFilter.removeListener(changeListener); + }finally{ + lock.unlock(); + } + } + + @Override + public String toString() { + return "LazyOpFilter "+this.opFilter; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpAction.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpAction.java index 7c05cd06e3..db364b6b6b 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpAction.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpAction.java @@ -37,6 +37,7 @@ import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.locationtech.udig.core.AdapterUtil; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.internal.ui.URLImageDescriptor; import org.locationtech.udig.internal.ui.UiPlugin; import org.locationtech.udig.internal.ui.operations.OperationCategory; @@ -126,7 +127,7 @@ IOp getOperation() { try { operation = (IOp) configElem.createExecutableExtension("class"); //$NON-NLS-1$ } catch (CoreException e) { - UiPlugin.log("Error loading operation implementation", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), "Error loading operation implementation", e); //$NON-NLS-1$ final Display display = Display.getDefault(); Runnable runnable = new Runnable() { @Override @@ -174,15 +175,13 @@ protected IStatus run(IProgressMonitor monitor) { target = AdapterUtil.instance.adapt(targetClass, selection.getFirstElement(), monitor); if (target == null) { - UiPlugin.log("Factory adapting " //$NON-NLS-1$ - + selection.getFirstElement().getClass().getName() + " to a " + //$NON-NLS-1$ - targetClass - + " is returning null even though it is advertising that it can " //$NON-NLS-1$ - + "do the adaptation", null); + LoggingSupport.log(UiPlugin.getDefault(), "Factory adapting "+selection.getFirstElement().getClass().getName()+" to a "+ //$NON-NLS-1$ //$NON-NLS-2$ + targetClass+" is returning null even though it is advertising that it can " + //$NON-NLS-1$ + "do the adaptation"); //$NON-NLS-1$ return Status.OK_STATUS; } } catch (Throwable e) { - UiPlugin.log(null, e); + LoggingSupport.log(UiPlugin.getDefault(), e); return Status.OK_STATUS; } } else { @@ -193,17 +192,15 @@ protected IStatus run(IProgressMonitor monitor) { Object operationTarget = AdapterUtil.instance.adapt(targetClass, entry, monitor); if (operationTarget == null) { - UiPlugin.log("Factory adapting " + entry.getClass().getName() //$NON-NLS-1$ - + " to a " + //$NON-NLS-1$ - targetClass - + " is returning null even though it is advertising that it can " //$NON-NLS-1$ - + "do the adaptation", null); + LoggingSupport.log(UiPlugin.getDefault(), "Factory adapting "+entry.getClass().getName()+" to a "+ //$NON-NLS-1$ //$NON-NLS-2$ + targetClass+" is returning null even though it is advertising that it can " + //$NON-NLS-1$ + "do the adaptation"); //$NON-NLS-1$ return Status.OK_STATUS; } else { targets.add(operationTarget); } } catch (Throwable e) { - UiPlugin.log(null, e); + LoggingSupport.log(UiPlugin.getDefault(), e); return Status.OK_STATUS; } } @@ -219,7 +216,7 @@ protected IStatus run(IProgressMonitor monitor) { IOp op = getOperation(); op.op(display, target, monitor); } catch (Throwable e) { - UiPlugin.log(null, e); + LoggingSupport.log(UiPlugin.getDefault(), e); } return Status.OK_STATUS; } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpFilterParser.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpFilterParser.java index 4d15cdc4df..46f1bb6e7e 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpFilterParser.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/OpFilterParser.java @@ -1,112 +1,122 @@ -/* - * uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.operations; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.eclipse.core.runtime.IConfigurationElement; - -public class OpFilterParser { - - FilterParser[] filterParsers; - - public OpFilterParser( FilterParser[] filterParser ) { - super(); - - assert filterParser != null; - - int i = 0; - if( filterParser!=null ) - i=filterParser.length; - this.filterParsers =new FilterParser[i]; - - System.arraycopy(filterParser, 0, this.filterParsers, 0, i); - - } - - public OpFilter parseFilter( IConfigurationElement element ) { - - if( element==null ){ - UiPlugin.log("OpFilterParser: Parsing OpFilter, Configuration element is null so returning OpFilter null", null); //$NON-NLS-1$ - return OpFilter.TRUE; - } - - String elementName = element.getName(); - if( elementName.equals("or")){ //$NON-NLS-1$ - return orFilter(element); - } - if( elementName.equals("not")){ //$NON-NLS-1$ - return notFilter(element); - } - if( elementName.equals("and")){ //$NON-NLS-1$ - return andFilter(element); - } - for( FilterParser parser : filterParsers ) { - if( elementName.equals(parser.getElementName())){ - return parser.parse(element); - } - } - UiPlugin.log("OpFilterParser: Parsing OpFilter: no parser found for parsing "+element.getNamespaceIdentifier(), null); //$NON-NLS-1$ - - return OpFilter.TRUE; - } - - private OpFilter andFilter( IConfigurationElement element ) { - And andFilter=new And(); - - IConfigurationElement[] children = element.getChildren(); - if( children.length== 0){ - UiPlugin.log("OpFilterParser: Parsing OpFilter: No children of an AND OpFilter "+element.getNamespaceIdentifier(), null); //$NON-NLS-1$ - return OpFilter.TRUE; - } - for( IConfigurationElement element2 : children ) { - andFilter.getFilters().add(parseFilter(element2)); - } - - return andFilter; - } - - private OpFilter notFilter( IConfigurationElement element ) { - IConfigurationElement[] children = element.getChildren(); - if (!validateChildren(children) ){ - return OpFilter.TRUE; - } - return new Not(parseFilter(children[0])); - } - - private OpFilter orFilter( IConfigurationElement element ) { - Or orFilter=new Or(); - - IConfigurationElement[] children = element.getChildren(); - if( children.length== 0){ - UiPlugin.log("OpFilterParser: Parsing OpFilter: No children of an OR OpFilter "+element.getNamespaceIdentifier(), null); //$NON-NLS-1$ - - return OpFilter.TRUE; - } - for( IConfigurationElement element2 : children ) { - orFilter.getFilters().add(parseFilter(element2)); - } - - return orFilter; - - } - - private boolean validateChildren( IConfigurationElement[] children ) { - if( children.length<1){ - return false; - } - if( children.length > 1){ - UiPlugin.log("OpFilterParser: Error, more than one enablement element "+children[0].getDeclaringExtension().getExtensionPointUniqueIdentifier(), new Exception()); //$NON-NLS-1$ - return false; - } - return true; - } -} +/* + * uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.operations; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +public class OpFilterParser { + + FilterParser[] filterParsers; + + public OpFilterParser(FilterParser[] filterParser) { + super(); + + assert filterParser != null; + + int i = 0; + if (filterParser != null) + i = filterParser.length; + this.filterParsers = new FilterParser[i]; + + System.arraycopy(filterParser, 0, this.filterParsers, 0, i); + + } + + public OpFilter parseFilter(IConfigurationElement element) { + + if (element == null) { + LoggingSupport.log(UiPlugin.getDefault(), + "OpFilterParser: Parsing OpFilter, Configuration element is null so returning OpFilter null"); //$NON-NLS-1$ + return OpFilter.TRUE; + } + + String elementName = element.getName(); + if (elementName.equals("or")) { //$NON-NLS-1$ + return orFilter(element); + } + if (elementName.equals("not")) { //$NON-NLS-1$ + return notFilter(element); + } + if (elementName.equals("and")) { //$NON-NLS-1$ + return andFilter(element); + } + for (FilterParser parser : filterParsers) { + if (elementName.equals(parser.getElementName())) { + return parser.parse(element); + } + } + LoggingSupport.log(UiPlugin.getDefault(), + "OpFilterParser: Parsing OpFilter: no parser found for parsing " //$NON-NLS-1$ + + element.getNamespaceIdentifier()); + + return OpFilter.TRUE; + } + + private OpFilter andFilter(IConfigurationElement element) { + And andFilter = new And(); + + IConfigurationElement[] children = element.getChildren(); + if (children.length == 0) { + LoggingSupport.log(UiPlugin.getDefault(), + "OpFilterParser: Parsing OpFilter: No children of an AND OpFilter " //$NON-NLS-1$ + + element.getNamespaceIdentifier()); + return OpFilter.TRUE; + } + for (IConfigurationElement element2 : children) { + andFilter.getFilters().add(parseFilter(element2)); + } + + return andFilter; + } + + private OpFilter notFilter(IConfigurationElement element) { + IConfigurationElement[] children = element.getChildren(); + if (!validateChildren(children)) { + return OpFilter.TRUE; + } + return new Not(parseFilter(children[0])); + } + + private OpFilter orFilter(IConfigurationElement element) { + Or orFilter = new Or(); + + IConfigurationElement[] children = element.getChildren(); + if (children.length == 0) { + LoggingSupport.log(UiPlugin.getDefault(), + "OpFilterParser: Parsing OpFilter: No children of an OR OpFilter " //$NON-NLS-1$ + + element.getNamespaceIdentifier()); + + return OpFilter.TRUE; + } + for (IConfigurationElement element2 : children) { + orFilter.getFilters().add(parseFilter(element2)); + } + + return orFilter; + + } + + private boolean validateChildren(IConfigurationElement[] children) { + if (children.length < 1) { + return false; + } + if (children.length > 1) { + LoggingSupport.log(UiPlugin.getDefault(), + new IllegalStateException( + "OpFilterParser: Error, more than one enablement element " + children[0] //$NON-NLS-1$ + .getDeclaringExtension().getExtensionPointUniqueIdentifier())); + return false; + } + return true; + } +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/PropertyParser.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/PropertyParser.java index 098eb64462..b841a81953 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/PropertyParser.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/operations/PropertyParser.java @@ -11,6 +11,7 @@ import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.internal.ui.UiPlugin; import org.locationtech.udig.internal.ui.operations.OpFilterPropertyValueCondition; @@ -19,52 +20,61 @@ */ public class PropertyParser implements FilterParser { - public PropertyParser( ) { + public PropertyParser() { super(); } @Override - public OpFilter parse( IConfigurationElement element ) { + public OpFilter parse(IConfigurationElement element) { String desiredPropertyId = element.getAttribute("propertyId"); //$NON-NLS-1$ // try the deprecated one if the required new one is not there - if( desiredPropertyId==null || desiredPropertyId.trim().length()==0 ) + if (desiredPropertyId == null || desiredPropertyId.trim().length() == 0) desiredPropertyId = element.getAttribute("name"); //$NON-NLS-1$ - String expectedValue = element.getAttribute("expectedValue"); //$NON-NLS-1$ + String expectedValue = element.getAttribute("expectedValue"); //$NON-NLS-1$ - if (desiredPropertyId == null || desiredPropertyId.length() == 0 ) { - UiPlugin.log("EnablesFor element is not valid. PropertyId must be supplied.", null); //$NON-NLS-1$ + if (desiredPropertyId == null || desiredPropertyId.length() == 0) { + LoggingSupport.log(UiPlugin.getDefault(), + "EnablesFor element is not valid. PropertyId must be supplied."); //$NON-NLS-1$ return OpFilter.TRUE; } - IConfigurationElement[] configuration = Platform.getExtensionRegistry().getConfigurationElementsFor("org.locationtech.udig.ui.objectProperty"); //$NON-NLS-1$ - IConfigurationElement propertyElement=null; - String targetClass = null; - for( IConfigurationElement configurationElement : configuration ) { - if( propertyElement!=null ) + IConfigurationElement[] configuration = Platform.getExtensionRegistry() + .getConfigurationElementsFor("org.locationtech.udig.ui.objectProperty"); //$NON-NLS-1$ + IConfigurationElement propertyElement = null; + String targetClass = null; + for (IConfigurationElement configurationElement : configuration) { + if (propertyElement != null) break; IConfigurationElement[] children = configurationElement.getChildren("property"); //$NON-NLS-1$ - for( IConfigurationElement child : children ) { + for (IConfigurationElement child : children) { String currentPropertyID = child.getAttribute("id"); //$NON-NLS-1$ - String currentPropertyID2=child.getNamespaceIdentifier()+"."+currentPropertyID; //$NON-NLS-1$ - - if( currentPropertyID.equals(desiredPropertyId) || currentPropertyID2.equals(desiredPropertyId)){ + String currentPropertyID2 = child.getNamespaceIdentifier() + "." //$NON-NLS-1$ + + currentPropertyID; + + if (currentPropertyID.equals(desiredPropertyId) + || currentPropertyID2.equals(desiredPropertyId)) { propertyElement = child; targetClass = configurationElement.getAttribute("targetClass"); //$NON-NLS-1$ // try the deprecated one if the required new one is not there - if( targetClass==null || targetClass.trim().length()==0 ) + if (targetClass == null || targetClass.trim().length() == 0) targetClass = configurationElement.getAttribute("class"); //$NON-NLS-1$ break; } } } - if ( propertyElement==null ){ - UiPlugin.log("PropertyParser: Parsing PropertyValue, desired Propert: "+desiredPropertyId+" not found. Referenced in plugin: "+element.getNamespaceIdentifier(), null); //$NON-NLS-1$ //$NON-NLS-2$ + if (propertyElement == null) { + LoggingSupport.log(UiPlugin.getDefault(), + "PropertyParser: Parsing PropertyValue, desired Propert: " + desiredPropertyId //$NON-NLS-1$ + + " not found. Referenced in plugin: " //$NON-NLS-1$ + + element.getNamespaceIdentifier()); return OpFilter.TRUE; } - if (targetClass==null ){ - UiPlugin.log("PropertyParser: Parsing PropertyValue, no target class defined in property"+desiredPropertyId, null); //$NON-NLS-1$ + if (targetClass == null) { + LoggingSupport.log(UiPlugin.getDefault(), + "PropertyParser: Parsing PropertyValue, no target class defined in property" //$NON-NLS-1$ + + desiredPropertyId); return OpFilter.TRUE; } diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/palette/ColourScheme.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/palette/ColourScheme.java index f4fae42794..2a65de969e 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/palette/ColourScheme.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/palette/ColourScheme.java @@ -1,469 +1,470 @@ -/* uDig - User Friendly Desktop Internet GIS client - * http://udig.refractions.net - * (C) 2004-2012, Refractions Research Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD - * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). - */ -package org.locationtech.udig.ui.palette; - -import java.awt.Color; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.Map.Entry; - -import org.locationtech.udig.internal.ui.UiPlugin; - -import org.geotools.brewer.color.BrewerPalette; - -/** - *

        A colour scheme remaps the colours in a palette.

        - * - * @author ptozer - * @author chorner - */ -public class ColourScheme { - /** the number of items which use this scheme */ - private int itemCount = 0; - /** the number of colours we grab from the palette */ - private int colourCount = 0; - /** should the scheme automatically add/remove available colours? */ - private boolean canAutoSize = true; - private HashMap idMap; //object identifier, colour index - private HashMap colourMap; //colour index, new colour index - private BrewerPalette palette; - - public ColourScheme (BrewerPalette palette, int itemSize) { - colourMap = new HashMap(); - idMap = new HashMap(); - setColourPalette(palette); - setSizeScheme(itemSize); - } - - public ColourScheme (BrewerPalette palette, int itemSize, int paletteSize) { - colourMap = new HashMap(); - idMap = new HashMap(); - setColourPalette(palette); - setSizePalette(paletteSize); - setSizeScheme(itemSize); - } - - public ColourScheme (BrewerPalette palette, HashMap colourMap, HashMap idMap, int itemSize, int paletteSize) { - this.idMap = idMap; - this.colourMap = colourMap; - this.palette = palette; - this.colourCount = paletteSize; - this.itemCount = itemSize; - } - - public static ColourScheme getDefault(final BrewerPalette palette) { - return new ColourScheme(palette, 0); - } - - public void setColourPalette(BrewerPalette palette) { - this.palette = palette; - //TODO: check number of colours in palette has not decreased - } - - public boolean getAutoSizing() { - return canAutoSize; - } - - /** - * Sets the behaviour of the colour scheme as items are added. If true, the palette will morph - * in size as items are added or removed. If false, the palette will remain static and scheme - * colours will be repeated even if some are unused. - * - * @param auto boolean - */ - public void setAutoSizing(boolean auto) { - canAutoSize = auto; - } - - /** - * Set the number of items this scheme is used by. The size of the palette is automatically adjusted to fit. - * - * @param numItems the number of items obtaining colours from this scheme - */ - public void setSizeScheme(int numItems) { - if (canAutoSize) { // we are allowed to adjust the number of colours from the palette this scheme uses - setSizePalette(numItems); //setSizePalette is smart enough not to exceed the palette size - } - - if (numItems > itemCount) { //items were added - for (int i = itemCount; i < numItems; i++) { - int newColourIndex = getNextColourIndex(); - colourMap.put(i, newColourIndex); - itemCount++; - } - } else { - //items were removed - for (int i = numItems; i < itemCount; i++) { - if (colourMap.containsKey(i)) - colourMap.remove(i); - } - itemCount = numItems; - } - } - - /** - * Sets the number of colours to use from the current palette. This method checks to ensure the - * number of colours does not exceed the size of the palette. - * - * @param numColours - */ - public void setSizePalette(int numColours) { - int minSize = palette.getMinColors(); - int maxSize = palette.getMaxColors(); - if (numColours > maxSize) { - numColours = maxSize; - } - if (numColours < minSize) { - numColours = minSize; - } - colourCount = numColours; - } - - private int getLargestColourIndex(int numItems) { - int largestIndex = -1; - for (int i = 0; i < numItems; i++) { - if (colourMap.containsKey(i)) { - int thisIndex = colourMap.get(i); - if (thisIndex > largestIndex) - largestIndex = i; - } - } - return largestIndex; - } - - public int getMinColours() { - int minColours = palette.getMinColors(); - int colourWidth = getLargestColourIndex(itemCount) + 1; - if (colourWidth > minColours) { - return colourWidth; - } else { - return minColours; - } - } - - /** - * Obtains a new colour index in the range specified, if unused. Colours are repeated if all are - * in use. - * - * @return colour index of the most appropriate next colour - */ - private int getNextColourIndex() { - // find an unused colour - for (int i = 0; i < colourCount; i++) { - boolean hasColour = false; - for (int j = 0; j < itemCount; j++) { - if (colourMap.containsKey(j) && colourMap.get(j) == i) { - hasColour = true; - break; - } - } - if (!hasColour) { - return i; - } - } - //we're out of colours, re-use one - int[] instances = new int[colourCount]; - for (int i = 0; i < itemCount; i++) { - if (colourMap.containsKey(i)) { - instances[colourMap.get(i)]++; - } - } - //find the first colourIndex which is used the least - int leastInstances = -1; - int index = 0; - for (int i = 0; i < colourCount; i++) { - if (instances[i] < leastInstances || leastInstances == -1) { - leastInstances = instances[i]; - index = i; - } - } - return index; - } - - /** - * Gets the number of colours currently available in the palette. - * - * @return - */ - public int getSizePalette() { - return colourCount; - } - - /** - * Gets the number of classes utilizing this scheme. - * - * @return - */ - public int getSizeScheme() { - return itemCount; - } - - public boolean alignScheme(List colours) { - int size = colours.size(); - if (itemCount < size) { - setSizeScheme(size); - } - for (int i = 0; i < size; i++) { - if (!getColour(i).equals(colours.get(i))) { - boolean consistent = false; - //find the first instance of this colour in the palette - Color[] paletteColours = palette.getColors(colourCount); - for (int j = 0; j < colourCount; j++) { - if (paletteColours[j].equals(colours.get(i))) { - consistent = true; - colourMap.remove(i); - colourMap.put(i, j); - break; - } - } - if (!consistent) { //utter failure - return false; - } - } - } - return true; - } - - /** - * Returns the next available colour. Good for comparing reality to what we think we have. - * - * @param colours - * @return - */ - public Color getNextAvailableColour(List colours) { - boolean[] inUse = new boolean[itemCount]; - for (int i = 0; i < itemCount; i++) { - inUse[i] = false; - } - //for each colour in use - for (Color colour : colours) { - //check off all instances of it - HashMap clrMap = getColourMap(); - for (int index = 0; index < itemCount; index++) { - int i; - if (clrMap.containsKey(index)) { - i = clrMap.get(index); - Color aColour = palette.getColor(i, colourCount); - if (aColour.equals(colour)) { - inUse[index] = true; - } - } else { - //index is not referenced - } - } - } - //find the first unused, yet mapped colour - for (int i = 0; i < itemCount; i++) { - if (!inUse[i]) { - return getColour(i); - } - } - if (palette.getMaxColors() == colourCount && colourCount <= itemCount) { //we're out of colours, so this logic won't work - return getColour(itemCount); - } else { - setSizeScheme(itemCount+1); - return getNextAvailableColour(colours); //recursion! run! - } - } - - public Color getColour(int index) { - if (index >= itemCount) { - setSizeScheme(index+1); - } - HashMap clrMap = getColourMap(); - int i; - if (clrMap.containsKey(index)) { - i = clrMap.get(index); - } else { - UiPlugin.log("ColourScheme getColour("+index+") exceeded bounds", null); //$NON-NLS-1$ //$NON-NLS-2$ - i = 0; //return the first colour, instead of exploding - } - return palette.getColor(i, colourCount); - } - - /** - * @return Returns all the available colours, without duplicates. - */ - public Color[] getAllColours() { - return palette.getColors(colourCount); - } - - public boolean equals(Object other) { - if( !super.equals(other) ) - return false; - if( !(other instanceof ColourScheme) ) - return false; - - ColourScheme schemeToCompare=(ColourScheme) other; - if (schemeToCompare.getSizePalette() != colourCount) - return false; - if (schemeToCompare.getSizeScheme() != itemCount) - return false; - if (!schemeToCompare.getColourPalette().getName().equals(palette.getName())) //only compare name for the moment - return false; - for (int i = 0; i < itemCount; i++) { - if (!schemeToCompare.getColourMap().get(i).equals(colourMap.get(i))) { - return false; - } - } - return true; - } - - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + colourCount; - result = PRIME * result + itemCount; - if( palette!=null && palette.getName()!=null ) - result = PRIME * result + palette.hashCode(); - for (int i = 0; i < itemCount; i++) { - Integer integer = colourMap.get(i); - result = PRIME * result + ((integer == null) ? 0 : integer.hashCode()); - } - return result; - } - - public BrewerPalette getColourPalette() { - return palette; - } - - public HashMap getColourMap() { - HashMap colourMapping = new HashMap(); - for (int i = 0; i < itemCount; i++) { - if (colourMap.containsKey(i)) { - colourMapping.put(i, colourMap.get(i)); - } else { - if (i > colourCount) { - colourMapping.put(i,i%colourCount); - } else { - colourMapping.put(i,i); - } - } - } - return colourMapping; - } - - public HashMap getIdMap() { - return idMap; - } - - public void setColourMap(HashMap colourMap) { - this.colourMap = colourMap; - //TODO: synchronize size - } - - public void swapColours(int firstIndex, int secondIndex) { - if (firstIndex >= colourCount) { - setSizeScheme(firstIndex+1); - } - if (secondIndex >= colourCount) { - setSizeScheme(secondIndex+1); - } - int tempVal = colourMap.get(firstIndex); - colourMap.put(firstIndex, colourMap.get(secondIndex)); - colourMap.put(secondIndex, tempVal); - } - - public Color addItem() { - int size = getSizeScheme(); - return getColour(size); - } - - public Color addItem(String id) { - int size = getSizeScheme(); - Color color = getColour(size); - int index = indexOf(color); - if (index > -1) { - idMap.put(id, index); - } - return color; - } - - /** - * Add an item to the scheme, and modify the palette to contain this colour. - * - * @param color - * @return - */ - public void addItem(Color color) { - //TODO - } - - public int indexOf(String id) { - if (idMap.containsKey(id)) { - return idMap.get(id); - } else { - return -1; - } - } - - private int indexOf(Color color) { - Iterator it = colourMap.keySet().iterator(); - while (it.hasNext()) { - Integer i = it.next(); - if (i < itemCount) { //don't modify the scheme! - if (color.equals(getColour(i))) { - return i; - } - } - } - return -1; - } - - public boolean removeItem(String id) { - if (idMap.containsKey(id)) { - int index = indexOf(id); - idMap.remove(id); - return removeItem(index); - } - return false; - } - - public boolean removeItem(String id, Color colour) { - Set> entries = idMap.entrySet(); - for (Entry entry : entries) { - if (id.equals(entry.getKey())) { - if (colour.equals(getColour(entry.getValue()))) { - entries.remove(entry); - return true; - } - } - } - return false; - } - - public boolean removeItem(int index) { - if (index < 0) { - return false; - } - if (idMap.containsValue(index)) { - //optionally remove target - Iterator> it = idMap.entrySet().iterator(); - while (it.hasNext()) { - Entry entry = it.next(); - if (entry.getValue().equals(index)) { - idMap.remove(entry.getKey()); - } - } - } - if (colourMap.containsKey(index)) { - //remove the entry - colourMap.remove(index); - itemCount--; - } - - return true; - } - -} +/* uDig - User Friendly Desktop Internet GIS client + * http://udig.refractions.net + * (C) 2004-2012, Refractions Research Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD + * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). + */ +package org.locationtech.udig.ui.palette; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + +import org.geotools.brewer.color.BrewerPalette; +import org.locationtech.udig.core.logging.LoggingSupport; +import org.locationtech.udig.internal.ui.UiPlugin; + +/** + *

        A colour scheme remaps the colours in a palette.

        + * + * @author ptozer + * @author chorner + */ +public class ColourScheme { + /** the number of items which use this scheme */ + private int itemCount = 0; + /** the number of colours we grab from the palette */ + private int colourCount = 0; + /** should the scheme automatically add/remove available colours? */ + private boolean canAutoSize = true; + private HashMap idMap; //object identifier, colour index + private HashMap colourMap; //colour index, new colour index + private BrewerPalette palette; + + public ColourScheme (BrewerPalette palette, int itemSize) { + colourMap = new HashMap<>(); + idMap = new HashMap<>(); + setColourPalette(palette); + setSizeScheme(itemSize); + } + + public ColourScheme (BrewerPalette palette, int itemSize, int paletteSize) { + colourMap = new HashMap<>(); + idMap = new HashMap<>(); + setColourPalette(palette); + setSizePalette(paletteSize); + setSizeScheme(itemSize); + } + + public ColourScheme (BrewerPalette palette, HashMap colourMap, HashMap idMap, int itemSize, int paletteSize) { + this.idMap = idMap; + this.colourMap = colourMap; + this.palette = palette; + this.colourCount = paletteSize; + this.itemCount = itemSize; + } + + public static ColourScheme getDefault(final BrewerPalette palette) { + return new ColourScheme(palette, 0); + } + + public void setColourPalette(BrewerPalette palette) { + this.palette = palette; + //TODO: check number of colours in palette has not decreased + } + + public boolean getAutoSizing() { + return canAutoSize; + } + + /** + * Sets the behaviour of the colour scheme as items are added. If true, the palette will morph + * in size as items are added or removed. If false, the palette will remain static and scheme + * colours will be repeated even if some are unused. + * + * @param auto boolean + */ + public void setAutoSizing(boolean auto) { + canAutoSize = auto; + } + + /** + * Set the number of items this scheme is used by. The size of the palette is automatically adjusted to fit. + * + * @param numItems the number of items obtaining colours from this scheme + */ + public void setSizeScheme(int numItems) { + if (canAutoSize) { // we are allowed to adjust the number of colours from the palette this scheme uses + setSizePalette(numItems); //setSizePalette is smart enough not to exceed the palette size + } + + if (numItems > itemCount) { //items were added + for (int i = itemCount; i < numItems; i++) { + int newColourIndex = getNextColourIndex(); + colourMap.put(i, newColourIndex); + itemCount++; + } + } else { + //items were removed + for (int i = numItems; i < itemCount; i++) { + if (colourMap.containsKey(i)) + colourMap.remove(i); + } + itemCount = numItems; + } + } + + /** + * Sets the number of colours to use from the current palette. This method checks to ensure the + * number of colours does not exceed the size of the palette. + * + * @param numColours + */ + public void setSizePalette(int numColours) { + int minSize = palette.getMinColors(); + int maxSize = palette.getMaxColors(); + if (numColours > maxSize) { + numColours = maxSize; + } + if (numColours < minSize) { + numColours = minSize; + } + colourCount = numColours; + } + + private int getLargestColourIndex(int numItems) { + int largestIndex = -1; + for (int i = 0; i < numItems; i++) { + if (colourMap.containsKey(i)) { + int thisIndex = colourMap.get(i); + if (thisIndex > largestIndex) + largestIndex = i; + } + } + return largestIndex; + } + + public int getMinColours() { + int minColours = palette.getMinColors(); + int colourWidth = getLargestColourIndex(itemCount) + 1; + if (colourWidth > minColours) { + return colourWidth; + } else { + return minColours; + } + } + + /** + * Obtains a new colour index in the range specified, if unused. Colours are repeated if all are + * in use. + * + * @return colour index of the most appropriate next colour + */ + private int getNextColourIndex() { + // find an unused colour + for (int i = 0; i < colourCount; i++) { + boolean hasColour = false; + for (int j = 0; j < itemCount; j++) { + if (colourMap.containsKey(j) && colourMap.get(j) == i) { + hasColour = true; + break; + } + } + if (!hasColour) { + return i; + } + } + //we're out of colours, re-use one + int[] instances = new int[colourCount]; + for (int i = 0; i < itemCount; i++) { + if (colourMap.containsKey(i)) { + instances[colourMap.get(i)]++; + } + } + //find the first colourIndex which is used the least + int leastInstances = -1; + int index = 0; + for (int i = 0; i < colourCount; i++) { + if (instances[i] < leastInstances || leastInstances == -1) { + leastInstances = instances[i]; + index = i; + } + } + return index; + } + + /** + * Gets the number of colours currently available in the palette. + * + * @return + */ + public int getSizePalette() { + return colourCount; + } + + /** + * Gets the number of classes utilizing this scheme. + * + * @return + */ + public int getSizeScheme() { + return itemCount; + } + + public boolean alignScheme(List colours) { + int size = colours.size(); + if (itemCount < size) { + setSizeScheme(size); + } + for (int i = 0; i < size; i++) { + if (!getColour(i).equals(colours.get(i))) { + boolean consistent = false; + //find the first instance of this colour in the palette + Color[] paletteColours = palette.getColors(colourCount); + for (int j = 0; j < colourCount; j++) { + if (paletteColours[j].equals(colours.get(i))) { + consistent = true; + colourMap.remove(i); + colourMap.put(i, j); + break; + } + } + if (!consistent) { //utter failure + return false; + } + } + } + return true; + } + + /** + * Returns the next available colour. Good for comparing reality to what we think we have. + * + * @param colours + * @return + */ + public Color getNextAvailableColour(List colours) { + boolean[] inUse = new boolean[itemCount]; + for (int i = 0; i < itemCount; i++) { + inUse[i] = false; + } + //for each colour in use + for (Color colour : colours) { + //check off all instances of it + HashMap clrMap = getColourMap(); + for (int index = 0; index < itemCount; index++) { + int i; + if (clrMap.containsKey(index)) { + i = clrMap.get(index); + Color aColour = palette.getColor(i, colourCount); + if (aColour.equals(colour)) { + inUse[index] = true; + } + } else { + //index is not referenced + } + } + } + //find the first unused, yet mapped colour + for (int i = 0; i < itemCount; i++) { + if (!inUse[i]) { + return getColour(i); + } + } + if (palette.getMaxColors() == colourCount && colourCount <= itemCount) { //we're out of colours, so this logic won't work + return getColour(itemCount); + } else { + setSizeScheme(itemCount+1); + return getNextAvailableColour(colours); //recursion! run! + } + } + + public Color getColour(int index) { + if (index >= itemCount) { + setSizeScheme(index+1); + } + HashMap clrMap = getColourMap(); + int i; + if (clrMap.containsKey(index)) { + i = clrMap.get(index); + } else { + LoggingSupport.log(UiPlugin.getDefault(), "ColourScheme getColour("+index+") exceeded bounds"); //$NON-NLS-1$ //$NON-NLS-2$ + i = 0; //return the first colour, instead of exploding + } + return palette.getColor(i, colourCount); + } + + /** + * @return Returns all the available colours, without duplicates. + */ + public Color[] getAllColours() { + return palette.getColors(colourCount); + } + + @Override + public boolean equals(Object other) { + if( !super.equals(other) ) + return false; + if( !(other instanceof ColourScheme) ) + return false; + + ColourScheme schemeToCompare=(ColourScheme) other; + if (schemeToCompare.getSizePalette() != colourCount) + return false; + if (schemeToCompare.getSizeScheme() != itemCount) + return false; + if (!schemeToCompare.getColourPalette().getName().equals(palette.getName())) //only compare name for the moment + return false; + for (int i = 0; i < itemCount; i++) { + if (!schemeToCompare.getColourMap().get(i).equals(colourMap.get(i))) { + return false; + } + } + return true; + } + + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + colourCount; + result = PRIME * result + itemCount; + if( palette!=null && palette.getName()!=null ) + result = PRIME * result + palette.hashCode(); + for (int i = 0; i < itemCount; i++) { + Integer integer = colourMap.get(i); + result = PRIME * result + ((integer == null) ? 0 : integer.hashCode()); + } + return result; + } + + public BrewerPalette getColourPalette() { + return palette; + } + + public HashMap getColourMap() { + HashMap colourMapping = new HashMap<>(); + for (int i = 0; i < itemCount; i++) { + if (colourMap.containsKey(i)) { + colourMapping.put(i, colourMap.get(i)); + } else { + if (i > colourCount) { + colourMapping.put(i,i%colourCount); + } else { + colourMapping.put(i,i); + } + } + } + return colourMapping; + } + + public HashMap getIdMap() { + return idMap; + } + + public void setColourMap(HashMap colourMap) { + this.colourMap = colourMap; + //TODO: synchronize size + } + + public void swapColours(int firstIndex, int secondIndex) { + if (firstIndex >= colourCount) { + setSizeScheme(firstIndex+1); + } + if (secondIndex >= colourCount) { + setSizeScheme(secondIndex+1); + } + int tempVal = colourMap.get(firstIndex); + colourMap.put(firstIndex, colourMap.get(secondIndex)); + colourMap.put(secondIndex, tempVal); + } + + public Color addItem() { + int size = getSizeScheme(); + return getColour(size); + } + + public Color addItem(String id) { + int size = getSizeScheme(); + Color color = getColour(size); + int index = indexOf(color); + if (index > -1) { + idMap.put(id, index); + } + return color; + } + + /** + * Add an item to the scheme, and modify the palette to contain this colour. + * + * @param color + * @return + */ + public void addItem(Color color) { + //TODO + } + + public int indexOf(String id) { + if (idMap.containsKey(id)) { + return idMap.get(id); + } else { + return -1; + } + } + + private int indexOf(Color color) { + Iterator it = colourMap.keySet().iterator(); + while (it.hasNext()) { + Integer i = it.next(); + if (i < itemCount) { //don't modify the scheme! + if (color.equals(getColour(i))) { + return i; + } + } + } + return -1; + } + + public boolean removeItem(String id) { + if (idMap.containsKey(id)) { + int index = indexOf(id); + idMap.remove(id); + return removeItem(index); + } + return false; + } + + public boolean removeItem(String id, Color colour) { + Set> entries = idMap.entrySet(); + for (Entry entry : entries) { + if (id.equals(entry.getKey())) { + if (colour.equals(getColour(entry.getValue()))) { + entries.remove(entry); + return true; + } + } + } + return false; + } + + public boolean removeItem(int index) { + if (index < 0) { + return false; + } + if (idMap.containsValue(index)) { + //optionally remove target + Iterator> it = idMap.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getValue().equals(index)) { + idMap.remove(entry.getKey()); + } + } + } + if (colourMap.containsKey(index)) { + //remove the entry + colourMap.remove(index); + itemCount--; + } + + return true; + } + +} diff --git a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/preferences/RuntimeFieldEditor.java b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/preferences/RuntimeFieldEditor.java index 17f4b1efd3..a2fdf53f31 100644 --- a/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/preferences/RuntimeFieldEditor.java +++ b/plugins/org.locationtech.udig.ui/src/org/locationtech/udig/ui/preferences/RuntimeFieldEditor.java @@ -38,6 +38,7 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; +import org.locationtech.udig.core.logging.LoggingSupport; import org.locationtech.udig.internal.ui.UiPlugin; import org.locationtech.udig.ui.ExceptionDetailsDialog; import org.locationtech.udig.ui.internal.Messages; @@ -140,7 +141,7 @@ protected void doLoad() { if (nonhost == null) nonhost = ""; //$NON-NLS-1$ } catch (IOException e) { - UiPlugin.log("Problem reading proxy settings.", e); //$NON-NLS-1$ + LoggingSupport.log(UiPlugin.getDefault(), "Problem reading proxy settings.", e); //$NON-NLS-1$ } } if (setStr.equals("")) //$NON-NLS-1$