Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Stieber2013-10-09 09:16:52 -0400
committerUwe Stieber2013-10-09 09:16:52 -0400
commitaa48a9885c6d33cc155c09e1415e9d1fa4a2b406 (patch)
tree6de090f1720fbe1c6bba2eed4dea1c4986731f41
parent1b23929809aa60bcd0fb59accffaa33356e85649 (diff)
downloadorg.eclipse.tcf-aa48a9885c6d33cc155c09e1415e9d1fa4a2b406.tar.gz
org.eclipse.tcf-aa48a9885c6d33cc155c09e1415e9d1fa4a2b406.tar.xz
org.eclipse.tcf-aa48a9885c6d33cc155c09e1415e9d1fa4a2b406.zip
Target Explorer: Added notification popup implementation based on mylyn commons.
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/META-INF/MANIFEST.MF7
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/AbstractNotification.java93
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSink.java22
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSinkEvent.java32
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/interfaces/INotificationService.java39
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tests/META-INF/MANIFEST.MF18
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tests/icons/notifications-category.gifbin0 -> 937 bytes
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tests/plugin.xml17
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/NotificationsTestCase.java64
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/TestNotification.java98
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/META-INF/MANIFEST.MF15
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/build.properties3
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close-active.gifbin0 -> 88 bytes
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close.gifbin0 -> 88 bytes
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/plugin.xml33
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/schema/notifications.exsd311
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/AnimationUtil.java159
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/GradientColors.java187
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/ScalingHyperlink.java112
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/activator/UIPlugin.java94
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/interfaces/ImageConsts.java71
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationAction.java52
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationCategory.java46
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationElement.java80
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationEvent.java116
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationHandler.java41
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationModel.java83
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationService.java100
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationSinkDescriptor.java59
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationsExtensionReader.java142
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.java6
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.properties7
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractNotificationPopup.java617
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractUiNotification.java38
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/NotificationPopup.java180
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/sink/PopupNotificationSink.java167
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/IPreferenceKeys.java29
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/PreferencesInitializer.java32
38 files changed, 3140 insertions, 30 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/META-INF/MANIFEST.MF
index c71dd5b67..6bacfad39 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/META-INF/MANIFEST.MF
+++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/META-INF/MANIFEST.MF
@@ -5,9 +5,12 @@ Bundle-SymbolicName: org.eclipse.tcf.te.runtime.notifications;singleton:=true
Bundle-Version: 1.2.0.qualifier
Bundle-Activator: org.eclipse.tcf.te.runtime.notifications.activator.CoreBundleActivator
Bundle-Vendor: %providerName
-Require-Bundle: org.eclipse.core.runtime;bundle-version="3.8.0"
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.8.0",
+ org.eclipse.tcf.te.runtime.services;bundle-version="1.2.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
-Export-Package: org.eclipse.tcf.te.runtime.notifications.activator;x-internal:=true,
+Export-Package: org.eclipse.tcf.te.runtime.notifications,
+ org.eclipse.tcf.te.runtime.notifications.activator;x-internal:=true,
+ org.eclipse.tcf.te.runtime.notifications.interfaces,
org.eclipse.tcf.te.runtime.notifications.nls;x-internal:=true
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/AbstractNotification.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/AbstractNotification.java
new file mode 100644
index 000000000..d6a1a7e72
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/AbstractNotification.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.runtime.notifications;
+
+import java.util.Date;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * A notification. Each notification has an associated <code>eventId</code> that identifies the type of the
+ * notification.
+ *
+ * @author Rob Elves
+ * @author Mik Kersten
+ * @author Steffen Pingel
+ */
+public abstract class AbstractNotification implements Comparable<AbstractNotification>, IAdaptable {
+
+ private final String eventId;
+
+ /**
+ * Constructor
+ *
+ * @param eventId The event id. Must not be <code>null</code>.
+ */
+ public AbstractNotification(String eventId) {
+ Assert.isNotNull(eventId);
+ this.eventId = eventId;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(AbstractNotification o) {
+ if (o == null) {
+ return 1;
+ }
+ return compare(getDate(), o.getDate());
+ }
+
+ /**
+ * Compares <code>o1</code> and <code>o2</code>.
+ *
+ * @return a negative integer, 0, or a positive, if o1 is less than o2, o1 equals o2 or o1 is more than o2; null is
+ * considered less than any value
+ */
+ private static <T> int compare(Comparable<T> o1, T o2) {
+ if (o1 == null) {
+ return (o2 != null) ? 1 : 0;
+ } else if (o2 == null) {
+ return -1;
+ }
+ return o1.compareTo(o2);
+ }
+
+ /**
+ * Returns the event id.
+ *
+ * @return The event id.
+ */
+ public final String getEventId() {
+ return eventId;
+ }
+
+ public abstract Date getDate();
+
+ public abstract String getDescription();
+
+ public abstract String getLabel();
+
+ /**
+ * Returns a token that identifies correlated notifications, e.g. all notifications resulting from a refresh
+ * operation. Returns <code>null</code> by default.
+ *
+ * @return any object; null, if no token is specified
+ */
+ public Object getToken() {
+ return null;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSink.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSink.java
new file mode 100644
index 000000000..3c37ab97d
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSink.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.runtime.notifications;
+
+/**
+ * @author Steffen Pingel
+ */
+public abstract class NotificationSink {
+
+ public abstract void notify(NotificationSinkEvent event);
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSinkEvent.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSinkEvent.java
new file mode 100644
index 000000000..06084e14f
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/NotificationSinkEvent.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.runtime.notifications;
+
+import java.util.List;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NotificationSinkEvent {
+
+ private final List<AbstractNotification> notifications;
+
+ public NotificationSinkEvent(List<AbstractNotification> notifications) {
+ this.notifications = notifications;
+ }
+
+ public List<AbstractNotification> getNotifications() {
+ return notifications;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/interfaces/INotificationService.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/interfaces/INotificationService.java
new file mode 100644
index 000000000..a8760cb86
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.notifications/src/org/eclipse/tcf/te/runtime/notifications/interfaces/INotificationService.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.runtime.notifications.interfaces;
+
+import org.eclipse.tcf.te.runtime.notifications.AbstractNotification;
+import org.eclipse.tcf.te.runtime.services.interfaces.IService;
+
+/**
+ * @author Steffen Pingel
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface INotificationService extends IService {
+
+ /**
+ * Single notification.
+ *
+ * @param notification The notification. Must not be <code>null</code>.
+ */
+ public void notify(AbstractNotification notification);
+
+ /**
+ * Multi notification.
+ *
+ * @param notifications The notifications. Must not be <code>null</code>.
+ */
+ public void notify(AbstractNotification[] notifications);
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tests/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tcf.te.tests/META-INF/MANIFEST.MF
index a4d96e9ce..102bbbef4 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tests/META-INF/MANIFEST.MF
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tests/META-INF/MANIFEST.MF
@@ -7,29 +7,31 @@ Bundle-Activator: org.eclipse.tcf.te.tests.activator.UIPlugin
Bundle-Vendor: %providerName
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.8.0",
org.eclipse.core.expressions;bundle-version="3.4.400",
- org.eclipse.ui;bundle-version="3.8.0",
- org.junit;bundle-version="4.10.0",
+ org.eclipse.debug.core;bundle-version="3.7.100",
org.eclipse.tcf.core;bundle-version="1.2.0",
org.eclipse.tcf.te.core;bundle-version="1.2.0",
org.eclipse.tcf.te.core.cdt;bundle-version="1.2.0",
+ org.eclipse.tcf.te.launch.core;bundle-version="1.2.0",
org.eclipse.tcf.te.runtime;bundle-version="1.2.0",
+ org.eclipse.tcf.te.runtime.concurrent;bundle-version="1.2.0",
org.eclipse.tcf.te.runtime.model;bundle-version="1.2.0",
+ org.eclipse.tcf.te.runtime.notifications;bundle-version="1.2.0",
+ org.eclipse.tcf.te.runtime.services;bundle-version="1.2.0",
org.eclipse.tcf.te.runtime.statushandler;bundle-version="1.2.0",
org.eclipse.tcf.te.runtime.stepper;bundle-version="1.2.0",
org.eclipse.tcf.te.tcf.core;bundle-version="1.2.0",
org.eclipse.tcf.te.tcf.core.model;bundle-version="1.2.0",
org.eclipse.tcf.te.tcf.filesystem.core;bundle-version="1.2.0",
org.eclipse.tcf.te.tcf.filesystem.ui;bundle-version="1.2.0",
+ org.eclipse.tcf.te.tcf.launch.core;bundle-version="1.2.0",
org.eclipse.tcf.te.tcf.locator;bundle-version="1.2.0",
+ org.eclipse.tcf.te.tcf.processes.core;bundle-version="1.2.0",
org.eclipse.tcf.te.tcf.processes.ui;bundle-version="1.2.0",
org.eclipse.tcf.te.ui;bundle-version="1.2.0",
+ org.eclipse.tcf.te.ui.notifications;bundle-version="1.2.0",
org.eclipse.tcf.te.ui.views;bundle-version="1.2.0",
- org.eclipse.tcf.te.runtime.services;bundle-version="1.2.0",
- org.eclipse.tcf.te.launch.core;bundle-version="1.2.0",
- org.eclipse.tcf.te.tcf.launch.core;bundle-version="1.2.0",
- org.eclipse.debug.core;bundle-version="3.7.100",
- org.eclipse.tcf.te.runtime.concurrent;bundle-version="1.2.0",
- org.eclipse.tcf.te.tcf.processes.core;bundle-version="1.2.0"
+ org.eclipse.ui;bundle-version="3.8.0",
+ org.junit;bundle-version="4.10.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tests/icons/notifications-category.gif b/target_explorer/plugins/org.eclipse.tcf.te.tests/icons/notifications-category.gif
new file mode 100644
index 000000000..7928be603
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tests/icons/notifications-category.gif
Binary files differ
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tests/plugin.xml b/target_explorer/plugins/org.eclipse.tcf.te.tests/plugin.xml
index af7f31f62..4bcd81bf6 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tests/plugin.xml
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tests/plugin.xml
@@ -211,4 +211,21 @@
</references>
</stepGroup>
</extension>
+
+<!-- Test notifications contributions -->
+ <extension point="org.eclipse.tcf.te.ui.notifications.notifications">
+ <category
+ icon="icons/notifications-category.gif"
+ id="org.eclipse.tcf.te.tests.category1"
+ label="Test Notifications">
+ </category>
+ <event
+ categoryId="org.eclipse.tcf.te.tests.category1"
+ id="org.eclipse.tcf.te.tests.event1"
+ label="Test Event">
+ <defaultHandler
+ sinkId="org.eclipse.tcf.te.ui.notifications.sink.popup">
+ </defaultHandler>
+ </event>
+ </extension>
</plugin>
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/NotificationsTestCase.java b/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/NotificationsTestCase.java
new file mode 100644
index 000000000..fd795e74c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/NotificationsTestCase.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tests.notifications;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.tcf.te.runtime.concurrent.util.ExecutorsUtil;
+import org.eclipse.tcf.te.runtime.notifications.interfaces.INotificationService;
+import org.eclipse.tcf.te.runtime.services.ServiceManager;
+import org.eclipse.tcf.te.tests.CoreTestCase;
+
+/**
+ * Notification test cases.
+ */
+public class NotificationsTestCase extends CoreTestCase {
+ /**
+ * Provides a test suite to the caller which combines all single
+ * test bundled within this category.
+ *
+ * @return Test suite containing all test for this test category.
+ */
+ public static Test getTestSuite() {
+ TestSuite testSuite = new TestSuite("Test notifications framework"); //$NON-NLS-1$
+
+ // add ourself to the test suite
+ testSuite.addTestSuite(NotificationsTestCase.class);
+
+ return testSuite;
+ }
+
+ //***** BEGIN SECTION: Single test methods *****
+ //NOTE: All method which represents a single test case must
+ // start with 'test'!
+
+ public void testNotifications() {
+ // Get the service
+ INotificationService service = ServiceManager.getInstance().getService(INotificationService.class);
+ assertNotNull("Failed to get notification service instance.", service); //$NON-NLS-1$
+
+ TestNotification notification = new TestNotification("org.eclipse.tcf.te.tests.event1"); //$NON-NLS-1$
+ assertNotNull("Failed to create test notification.", notification); //$NON-NLS-1$
+
+ notification.setLabel("Test Notification Label"); //$NON-NLS-1$
+ assertEquals("Notification label setter / getter does not match.", "Test Notification Label", notification.getLabel()); //$NON-NLS-1$ //$NON-NLS-2$
+
+ notification.setDescription("Test Notification Description"); //$NON-NLS-1$
+ assertEquals("Notification description setter / getter does not match.", "Test Notification Description", notification.getDescription()); //$NON-NLS-1$ //$NON-NLS-2$
+
+ service.notify(notification);
+
+ ExecutorsUtil.waitAndExecute(20000, null);
+ }
+
+ //***** END SECTION: Single test methods *****
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/TestNotification.java b/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/TestNotification.java
new file mode 100644
index 000000000..49466d1b8
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/notifications/TestNotification.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tests.notifications;
+
+import java.util.Date;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tcf.te.ui.notifications.popup.AbstractUiNotification;
+
+/**
+ * Test notification implementation.
+ */
+public class TestNotification extends AbstractUiNotification {
+ private String description;
+ private String label;
+
+ /**
+ * Constructor
+ *
+ * @param eventId
+ */
+ public TestNotification(String eventId) {
+ super(eventId);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+ */
+ @Override
+ public Object getAdapter(Class adapter) {
+ return Platform.getAdapterManager().getAdapter(this, adapter);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.ui.notifications.popup.AbstractUiNotification#getNotificationImage()
+ */
+ @Override
+ public Image getNotificationImage() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.ui.notifications.popup.AbstractUiNotification#getNotificationKindImage()
+ */
+ @Override
+ public Image getNotificationKindImage() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.ui.notifications.popup.AbstractUiNotification#open()
+ */
+ @Override
+ public void open() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.notifications.AbstractNotification#getDate()
+ */
+ @Override
+ public Date getDate() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.notifications.AbstractNotification#getDescription()
+ */
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.notifications.AbstractNotification#getLabel()
+ */
+ @Override
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/META-INF/MANIFEST.MF
index 62a6efd17..741d896dc 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/META-INF/MANIFEST.MF
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/META-INF/MANIFEST.MF
@@ -5,11 +5,20 @@ Bundle-SymbolicName: org.eclipse.tcf.te.ui.notifications;singleton:=true
Bundle-Version: 1.2.0.qualifier
Bundle-Activator: org.eclipse.tcf.te.ui.notifications.activator.UIPlugin
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.8.0",
+ org.eclipse.tcf.te.runtime;bundle-version="1.2.0",
+ org.eclipse.tcf.te.runtime.notifications;bundle-version="1.2.0",
+ org.eclipse.tcf.te.runtime.services;bundle-version="1.2.0",
org.eclipse.ui;bundle-version="3.8.0",
- org.eclipse.tcf.te.runtime;bundle-version="1.2.0"
+ org.eclipse.ui.forms;bundle-version="3.5.200"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Bundle-Localization: plugin
-Export-Package: org.eclipse.tcf.te.ui.notifications.activator;x-internal:=true,
- org.eclipse.tcf.te.ui.notifications.nls;x-internal:=true
+Export-Package: org.eclipse.tcf.te.ui.notifications,
+ org.eclipse.tcf.te.ui.notifications.activator;x-internal:=true,
+ org.eclipse.tcf.te.ui.notifications.interfaces,
+ org.eclipse.tcf.te.ui.notifications.internal;x-internal:=true,
+ org.eclipse.tcf.te.ui.notifications.nls;x-internal:=true,
+ org.eclipse.tcf.te.ui.notifications.popup,
+ org.eclipse.tcf.te.ui.notifications.popup.sink,
+ org.eclipse.tcf.te.ui.notifications.preferences
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/build.properties b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/build.properties
index b67aba1a4..150016697 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/build.properties
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/build.properties
@@ -3,4 +3,5 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.properties,\
- about.html
+ about.html,\
+ plugin.xml
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close-active.gif b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close-active.gif
new file mode 100644
index 000000000..8816521a8
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close-active.gif
Binary files differ
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close.gif b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close.gif
new file mode 100644
index 000000000..17b757358
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/icons/eview16/notification-close.gif
Binary files differ
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/plugin.xml b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/plugin.xml
new file mode 100644
index 000000000..7e45ddb91
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/plugin.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+<!-- Extension point declarations -->
+ <extension-point id="notifications" name="Noification Provider" schema="schema/notifications.exsd"/>
+
+<!-- Notifications contributions -->
+ <extension point="org.eclipse.tcf.te.ui.notifications.notifications">
+ <sink
+ class="org.eclipse.tcf.te.ui.notifications.popup.sink.PopupNotificationSink"
+ id="org.eclipse.tcf.te.ui.notifications.sink.popup"
+ label="Desktop Popup">
+ </sink>
+ </extension>
+
+<!-- Preference initializer contributions -->
+ <extension point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.tcf.te.ui.notifications.preferences.PreferencesInitializer"/>
+ </extension>
+
+<!-- Service contributions -->
+ <extension point="org.eclipse.tcf.te.runtime.services.services">
+ <service
+ class="org.eclipse.tcf.te.ui.notifications.internal.NotificationService"
+ id="org.eclipse.tcf.te.ui.notifications.service">
+ <serviceType
+ bundleId="org.eclipse.tcf.te.runtime.notifications"
+ class="org.eclipse.tcf.te.runtime.notifications.interfaces.INotificationService">
+ </serviceType>
+ </service>
+ </extension>
+</plugin>
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/schema/notifications.exsd b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/schema/notifications.exsd
new file mode 100644
index 000000000..cc34dc1e8
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/schema/notifications.exsd
@@ -0,0 +1,311 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.tcf.te.ui.notifications" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.tcf.te.ui.notifications" id="notifications" name="Notifications"/>
+ </appinfo>
+ <documentation>
+ Provides support for event categories, types and sinks.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="category"/>
+ <element ref="event"/>
+ <element ref="sink"/>
+ <element ref="eventMapping"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="event">
+ <annotation>
+ <documentation>
+ Event types has an unique identifier, a label and optionally an icon and a category. Whenever a notification is triggered the identifier is used to determine how to present the notification to the user.
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="0" maxOccurs="1">
+ <element ref="description"/>
+ <element ref="defaultHandler" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ a unique event identifier.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="icon" type="string">
+ <annotation>
+ <documentation>
+ a 16x16 icon.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="resource"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="label" type="string" use="required">
+ <annotation>
+ <documentation>
+ a label describing the event type.
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="categoryId" type="string">
+ <annotation>
+ <documentation>
+ parent category identifier.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.tcf.te.ui.notifications.notifications/category/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="category">
+ <annotation>
+ <documentation>
+ Events can (and should) be organised into categories making them easy to locate in the user interface.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ a unique event category identifier.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="icon" type="string">
+ <annotation>
+ <documentation>
+ a 16x16 icon.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="resource"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="label" type="string" use="required">
+ <annotation>
+ <documentation>
+ a label describing the category.
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="sink">
+ <annotation>
+ <documentation>
+ Notification sinks are used to handle events.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ a unique event sink identifier.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ the event sink implementation.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.tcf.te.runtime.notifications.NotificationSink:"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="label" type="string" use="required">
+ <annotation>
+ <documentation>
+ a label describing the event sink.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="description" type="string">
+ <annotation>
+ <appinfo>
+ <meta.element translatable="true"/>
+ </appinfo>
+ <documentation>
+ A description of the event type.
+ </documentation>
+ </annotation>
+ </element>
+
+ <element name="defaultHandler">
+ <annotation>
+ <documentation>
+ One or more &lt;i&gt;defaultHandler&lt;/i&gt; elements may be added to an event for specifying which sink should handle the event. If none are specified all sinks will be used. Note that this element specifies a default setting that may be changed in user preferences.
+
+A similar effect is achieved by the &lt;i&gt;eventMapping&lt;/i&gt; extension.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="sinkId" type="string" use="required">
+ <annotation>
+ <documentation>
+ Identifier of the sink that should handle the event.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.tcf.te.ui.notifications.notifications/sink/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="eventMapping">
+ <annotation>
+ <documentation>
+ Event mappings are used to map one ore more events to a sink. Note that this element specifies a default setting that may be changed in user preferences.
+
+Also see the &lt;i&gt;defaultHandler&lt;/i&gt; element of &lt;i&gt;event&lt;/i&gt; declarations.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="sinkId" type="string" use="required">
+ <annotation>
+ <documentation>
+ Identifier of the sink that should handle the event.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.tcf.te.ui.notifications.notifications/sink/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="eventIds" type="string" use="required">
+ <annotation>
+ <documentation>
+ a comma separated list of event identifiers that will be mapped to the notification sink. The &quot;*&quot; wildcard can be used so that multiple events can be mapped to one sink.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.2.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ Following is an example of use:
+&lt;pre&gt;
+ &lt;extension
+ point=&quot;org.eclipse.tcf.te.ui.notifications.notifications&quot;&gt;
+ &lt;event
+ categoryId=&quot;org.eclipse.mylyn.builds.ui.category.Builds&quot;
+ id=&quot;org.eclipse.mylyn.builds.ui.events.BuildServiceChanged&quot;
+ label=&quot;Build Service Changed&quot;&gt;
+ &lt;description&gt;
+ This event is triggered when the status of a build service is changed. For instance a new server is discovered or is no longer available.
+ &lt;/description&gt;
+ &lt;defaultHandler
+ sinkId=&quot;org.eclipse.mylyn.internal.builds.ui.view.NotificationSinkProxy&quot;/&gt;
+ &lt;/category&gt;
+ &lt;/event&gt;
+ &lt;category
+ icon=&quot;icons/eview16/build-view.png&quot;
+ id=&quot;org.eclipse.mylyn.builds.ui.category.Builds&quot;
+ label=&quot;Builds&quot;&gt;
+ &lt;/category&gt;
+ &lt;sink
+ class=&quot;org.eclipse.mylyn.internal.builds.ui.view.NotificationSinkProxy&quot;
+ id=&quot;org.eclipse.mylyn.builds.ui.sink.View&quot;
+ label=&quot;Builds View&quot;&gt;
+ &lt;/sink&gt;
+ &lt;eventMapping
+ eventIds=&quot;org.eclipse.mylyn.builds.ui.events.*&quot;
+ sinkId=&quot;org.eclipse.tcf.te.ui.notifications.sink.Popup&quot;&gt;
+ &lt;/eventMapping&gt;
+ &lt;/extension&gt;
+&lt;/pre&gt;
+
+This example will declare a new event and assign it to the builds view notification sink. The category for the event is also declared in addition to the builds view notification sink. The last configuration element declares a mapping between all build event types and the popup notification sink.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ The value of the class attribute in sink must represent a class
+that implements &lt;samp&gt;org.eclipse.tcf.te.runtime.notifications.NotificationSink&lt;/samp&gt;.
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2010, 2013 Tasktop Technologies and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/AnimationUtil.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/AnimationUtil.java
new file mode 100644
index 000000000..6a3c33384
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/AnimationUtil.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tcf.te.ui.notifications.nls.Messages;
+
+/**
+ * @author Mik Kersten
+ * @author Steffen Pingel
+ */
+public class AnimationUtil {
+
+ public static final long FADE_RESCHEDULE_DELAY = 80;
+
+ public static final int FADE_IN_INCREMENT = 15;
+
+ public static final int FADE_OUT_INCREMENT = -20;
+
+ public static FadeJob fastFadeIn(Shell shell, IFadeListener listener) {
+ return new FadeJob(shell, 2 * FADE_IN_INCREMENT, FADE_RESCHEDULE_DELAY, listener);
+ }
+
+ public static FadeJob fadeIn(Shell shell, IFadeListener listener) {
+ return new FadeJob(shell, FADE_IN_INCREMENT, FADE_RESCHEDULE_DELAY, listener);
+ }
+
+ public static FadeJob fadeOut(Shell shell, IFadeListener listener) {
+ return new FadeJob(shell, FADE_OUT_INCREMENT, FADE_RESCHEDULE_DELAY, listener);
+ }
+
+ public static class FadeJob extends Job {
+
+ /* default */ final Shell shell;
+
+ private final int increment;
+
+ /* default */ volatile boolean stopped;
+
+ /* default */ volatile int currentAlpha;
+
+ private final long delay;
+
+ /* default */ final IFadeListener fadeListener;
+
+ public FadeJob(Shell shell, int increment, long delay, IFadeListener fadeListener) {
+ super(Messages.SwtUtil_Fading);
+ if (increment < -255 || increment == 0 || increment > 255) {
+ throw new IllegalArgumentException("-255 <= increment <= 255 && increment != 0"); //$NON-NLS-1$
+ }
+ if (delay < 1) {
+ throw new IllegalArgumentException("delay must be > 0"); //$NON-NLS-1$
+ }
+ this.currentAlpha = shell.getAlpha();
+ this.shell = shell;
+ this.increment = increment;
+ this.delay = delay;
+ this.fadeListener = fadeListener;
+
+ setSystem(true);
+ schedule(delay);
+ }
+
+ @Override
+ protected void canceling() {
+ stopped = true;
+ }
+
+ private void reschedule() {
+ if (stopped) {
+ return;
+ }
+ schedule(delay);
+ }
+
+ public void cancelAndWait(final boolean setAlpha) {
+ if (stopped) {
+ return;
+ }
+ cancel();
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (setAlpha) {
+ shell.setAlpha(getLastAlpha());
+ }
+ }
+ });
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ if (stopped) {
+ return Status.OK_STATUS;
+ }
+
+ currentAlpha += increment;
+ if (currentAlpha <= 0) {
+ currentAlpha = 0;
+ } else if (currentAlpha >= 255) {
+ currentAlpha = 255;
+ }
+
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (stopped) {
+ return;
+ }
+
+ if (shell.isDisposed()) {
+ stopped = true;
+ return;
+ }
+
+ shell.setAlpha(currentAlpha);
+
+ if (fadeListener != null) {
+ fadeListener.faded(shell, currentAlpha);
+ }
+ }
+ });
+
+ if (currentAlpha == 0 || currentAlpha == 255) {
+ stopped = true;
+ }
+
+ reschedule();
+ return Status.OK_STATUS;
+ }
+
+ /* default */ int getLastAlpha() {
+ return (increment < 0) ? 0 : 255;
+ }
+
+ }
+
+ public static interface IFadeListener {
+
+ public void faded(Shell shell, int alpha);
+
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/GradientColors.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/GradientColors.java
new file mode 100644
index 000000000..62105e371
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/GradientColors.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Benjamin Pasero - initial API and implementation
+ * Tasktop Technologies - improvements
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications;
+
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Based on FormColors of UI Forms.
+ *
+ * @author Benjamin Pasero (initial contribution from RSSOwl, see bug 177974)
+ * @author Mik Kersten
+ */
+public class GradientColors {
+
+ private final Display display;
+
+ private Color titleText;
+
+ private Color gradientBegin;
+
+ private Color gradientEnd;
+
+ private Color border;
+
+ private final ResourceManager resourceManager;
+
+ public GradientColors(Display display, ResourceManager resourceManager) {
+ this.display = display;
+ this.resourceManager = resourceManager;
+
+ createColors();
+ }
+
+ private void createColors() {
+ createBorderColor();
+ createGradientColors();
+ // previously used SWT.COLOR_TITLE_INACTIVE_FOREGROUND, but too light on Windows XP
+ titleText = getColor(resourceManager, getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
+ }
+
+ public Color getGradientBegin() {
+ return gradientBegin;
+ }
+
+ public Color getGradientEnd() {
+ return gradientEnd;
+ }
+
+ public Color getBorder() {
+ return border;
+ }
+
+ public Color getTitleText() {
+ return titleText;
+ }
+
+ private void createBorderColor() {
+ RGB tbBorder = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+ RGB bg = getImpliedBackground().getRGB();
+
+ // Group 1
+ // Rule: If at least 2 of the RGB values are equal to or between 180 and
+ // 255, then apply specified opacity for Group 1
+ // Examples: Vista, XP Silver, Wn High Con #2
+ // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
+ if (testTwoPrimaryColors(tbBorder, 179, 256)) {
+ tbBorder = blend(tbBorder, bg, 70);
+ } else if (testTwoPrimaryColors(tbBorder, 120, 180)) {
+ tbBorder = blend(tbBorder, bg, 50);
+ } else {
+ tbBorder = blend(tbBorder, bg, 30);
+ }
+
+ border = getColor(resourceManager, tbBorder);
+ }
+
+ private void createGradientColors() {
+ RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+ Color bgColor = getImpliedBackground();
+ RGB bg = bgColor.getRGB();
+ RGB bottom, top;
+
+ // Group 1
+ // Rule: If at least 2 of the RGB values are equal to or between 180 and
+ // 255, then apply specified opacity for Group 1
+ // Examples: Vista, XP Silver, Wn High Con #2
+ // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+ // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+ if (testTwoPrimaryColors(titleBg, 179, 256)) {
+ bottom = blend(titleBg, bg, 30);
+ top = bg;
+ }
+
+ // Group 2
+ // Rule: If at least 2 of the RGB values are equal to or between 121 and
+ // 179, then apply specified opacity for Group 2
+ // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+ // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
+ // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+ else if (testTwoPrimaryColors(titleBg, 120, 180)) {
+ bottom = blend(titleBg, bg, 20);
+ top = bg;
+ }
+
+ // Group 3
+ // Rule: If at least 2 of the RGB values are equal to or between 0 and
+ // 120, then apply specified opacity for Group 3
+ // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+ // Aqua, Wn High Con White, Wn High Con #1
+ // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
+ // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+ else {
+ bottom = blend(titleBg, bg, 10);
+ top = bg;
+ }
+
+ gradientBegin = getColor(resourceManager, top);
+ gradientEnd = getColor(resourceManager, bottom);
+ }
+
+ private RGB blend(RGB c1, RGB c2, int ratio) {
+ int r = blend(c1.red, c2.red, ratio);
+ int g = blend(c1.green, c2.green, ratio);
+ int b = blend(c1.blue, c2.blue, ratio);
+ return new RGB(r, g, b);
+ }
+
+ private int blend(int v1, int v2, int ratio) {
+ int b = (ratio * v1 + (100 - ratio) * v2) / 100;
+ return Math.min(255, b);
+ }
+
+ private boolean testTwoPrimaryColors(RGB rgb, int from, int to) {
+ int total = 0;
+ if (testPrimaryColor(rgb.red, from, to)) {
+ total++;
+ }
+ if (testPrimaryColor(rgb.green, from, to)) {
+ total++;
+ }
+ if (testPrimaryColor(rgb.blue, from, to)) {
+ total++;
+ }
+ return total >= 2;
+ }
+
+ private boolean testPrimaryColor(int value, int from, int to) {
+ return value > from && value < to;
+ }
+
+ private RGB getSystemColor(int code) {
+ return getDisplay().getSystemColor(code).getRGB();
+ }
+
+ private Color getImpliedBackground() {
+ return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+ }
+
+ private Display getDisplay() {
+ return display;
+ }
+
+ private Color getColor(ResourceManager manager, RGB rgb) {
+ try {
+ return manager.createColor(rgb);
+ } catch (DeviceResourceException e) {
+ return manager.getDevice().getSystemColor(SWT.COLOR_BLACK);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/ScalingHyperlink.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/ScalingHyperlink.java
new file mode 100644
index 000000000..6b685b104
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/ScalingHyperlink.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.forms.widgets.ImageHyperlink;
+
+/**
+ * Enhanced {@link ImageHyperlink} that truncates the link text at the end rather than the middle if it is wider than
+ * the available space. Also provides default color and underline on hover.
+ *
+ * @author Leo Dos Santos
+ * @author Mik Kersten
+ */
+public class ScalingHyperlink extends ImageHyperlink {
+
+ private boolean strikeThrough;
+
+ protected final MouseTrackListener MOUSE_TRACK_LISTENER = new MouseTrackListener() {
+
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ setUnderlined(true);
+ }
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ setUnderlined(false);
+ }
+
+ @Override
+ public void mouseHover(MouseEvent e) {
+ }
+ };
+
+ public ScalingHyperlink(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ public void dispose() {
+ removeMouseTrackListener(MOUSE_TRACK_LISTENER);
+ super.dispose();
+ }
+
+ public void registerMouseTrackListener() {
+ addMouseTrackListener(MOUSE_TRACK_LISTENER);
+ }
+
+ public boolean isStrikeThrough() {
+ return strikeThrough;
+ }
+
+ @Override
+ protected void paintText(GC gc, Rectangle bounds) {
+ super.paintText(gc, bounds);
+ if (strikeThrough) {
+ Point totalSize = computeTextSize(SWT.DEFAULT, SWT.DEFAULT);
+ int textWidth = Math.min(bounds.width, totalSize.x);
+ int textHeight = totalSize.y;
+
+ // int descent = gc.getFontMetrics().getDescent();
+ int lineY = bounds.y + (textHeight / 2); // - descent + 1;
+ gc.drawLine(bounds.x, lineY, bounds.x + textWidth, lineY);
+ }
+ }
+
+ public void setStrikeThrough(boolean strikethrough) {
+ this.strikeThrough = strikethrough;
+ }
+
+ @Override
+ protected String shortenText(GC gc, String t, int width) {
+ if (t == null) {
+ return null;
+ }
+
+ if ((getStyle() & SWT.SHORT) != 0) {
+ return t;
+ }
+
+ String returnText = t;
+ if (gc.textExtent(t).x > width) {
+ for (int i = t.length(); i > 0; i--) {
+ String test = t.substring(0, i);
+ test = test + "..."; //$NON-NLS-1$
+ if (gc.textExtent(test).x < width) {
+ returnText = test;
+ break;
+ }
+ }
+ }
+ return returnText;
+ }
+
+} \ No newline at end of file
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/activator/UIPlugin.java
index dc5785c3c..3712b8089 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/activator/UIPlugin.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/activator/UIPlugin.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2013 Wind River Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013 Wind River Systems, Inc. and others. All rights reserved.
* This program and the accompanying materials are made available under the terms
* of the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
@@ -9,8 +9,16 @@
*******************************************************************************/
package org.eclipse.tcf.te.ui.notifications.activator;
-import org.eclipse.tcf.te.runtime.preferences.ScopedEclipsePreferences;
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.tcf.te.runtime.tracing.TraceHandler;
+import org.eclipse.tcf.te.ui.notifications.interfaces.ImageConsts;
+import org.eclipse.tcf.te.ui.notifications.internal.NotificationModel;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.FormColors;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
@@ -20,11 +28,14 @@ import org.osgi.framework.BundleContext;
public class UIPlugin extends AbstractUIPlugin {
// The shared instance
private static UIPlugin plugin;
- // The scoped preferences instance
- private static volatile ScopedEclipsePreferences scopedPreferences;
// The trace handler instance
private static volatile TraceHandler traceHandler;
+ private volatile NotificationModel model;
+
+ // The form colors instance
+ private volatile FormColors formColors = null;
+
/**
* The constructor
*/
@@ -51,16 +62,6 @@ public class UIPlugin extends AbstractUIPlugin {
}
/**
- * Return the scoped preferences for this plugin.
- */
- public static ScopedEclipsePreferences getScopedPreferences() {
- if (scopedPreferences == null) {
- scopedPreferences = new ScopedEclipsePreferences(getUniqueIdentifier());
- }
- return scopedPreferences;
- }
-
- /**
* Returns the bundles trace handler.
*
* @return The bundles trace handler.
@@ -71,6 +72,32 @@ public class UIPlugin extends AbstractUIPlugin {
}
return traceHandler;
}
+
+ /**
+ * Returns the notification model instance.
+ *
+ * @return The notification model.
+ */
+ public NotificationModel getModel() {
+ if (model == null) {
+ model = new NotificationModel();
+ }
+ return model;
+ }
+
+ /**
+ * Returns a form colors instance.
+ *
+ * @return The form colors instance.
+ */
+ public FormColors getFormColors() {
+ if (formColors == null) {
+ formColors = new FormColors(PlatformUI.getWorkbench().getDisplay());
+ formColors.markShared();
+ }
+ return formColors;
+ }
+
/* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
@@ -85,11 +112,46 @@ public class UIPlugin extends AbstractUIPlugin {
*/
@Override
public void stop(BundleContext context) throws Exception {
- // Save the tree viewer's state.
+ if (formColors != null) {
+ formColors.dispose();
+ formColors = null;
+ }
plugin = null;
- scopedPreferences = null;
traceHandler = null;
super.stop(context);
}
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry)
+ */
+ @Override
+ protected void initializeImageRegistry(ImageRegistry registry) {
+ URL url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_EVIEW + "notification-close.gif"); //$NON-NLS-1$
+ registry.put(ImageConsts.NOTIFICATION_CLOSE, ImageDescriptor.createFromURL(url));
+ url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_EVIEW + "notification-close-active.gif"); //$NON-NLS-1$
+ registry.put(ImageConsts.NOTIFICATION_CLOSE_HOVER, ImageDescriptor.createFromURL(url));
+ }
+
+ /**
+ * Loads the image registered under the specified key from the image
+ * registry and returns the <code>Image</code> object instance.
+ *
+ * @param key The key the image is registered with.
+ * @return The <code>Image</code> object instance or <code>null</code>.
+ */
+ public static Image getImage(String key) {
+ return getDefault().getImageRegistry().get(key);
+ }
+
+ /**
+ * Loads the image registered under the specified key from the image
+ * registry and returns the <code>ImageDescriptor</code> object instance.
+ *
+ * @param key The key the image is registered with.
+ * @return The <code>ImageDescriptor</code> object instance or <code>null</code>.
+ */
+ public static ImageDescriptor getImageDescriptor(String key) {
+ return getDefault().getImageRegistry().getDescriptor(key);
+ }
+
}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/interfaces/ImageConsts.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/interfaces/ImageConsts.java
new file mode 100644
index 000000000..edf52fef9
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/interfaces/ImageConsts.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.ui.notifications.interfaces;
+
+/**
+ * Image registry constants.
+ */
+public interface ImageConsts {
+
+ // ***** The directory structure constants *****
+
+ /**
+ * The root directory where to load the images from, relative to
+ * the bundle directory.
+ */
+ public final static String IMAGE_DIR_ROOT = "icons/"; //$NON-NLS-1$
+
+ /**
+ * The directory where to load disabled local toolbar images from,
+ * relative to the image root directory.
+ */
+ public final static String IMAGE_DIR_DLCL = "dlcl16/"; //$NON-NLS-1$
+
+ /**
+ * The directory where to load enabled local toolbar images from,
+ * relative to the image root directory.
+ */
+ public final static String IMAGE_DIR_ELCL = "elcl16/"; //$NON-NLS-1$
+
+ /**
+ * The directory where to load view related images from, relative to
+ * the image root directory.
+ */
+ public final static String IMAGE_DIR_EVIEW = "eview16/"; //$NON-NLS-1$
+
+ /**
+ * The directory where to load wizard banner images from,
+ * relative to the image root directory.
+ */
+ public final static String IMAGE_DIR_WIZBAN = "wizban/"; //$NON-NLS-1$
+
+ /**
+ * The directory where to load object overlay images from,
+ * relative to the image root directory.
+ */
+ public final static String IMAGE_DIR_OVR = "ovr16/"; //$NON-NLS-1$
+
+ /**
+ * The directory where to load model object images from, relative to the image root directory.
+ */
+ public final static String IMAGE_DIR_OBJ = "obj16/"; //$NON-NLS-1$
+
+ // ***** The image constants *****
+
+ /**
+ * The key to access the New target wizard banner image.
+ */
+ public static final String NOTIFICATION_CLOSE = "NotificationClose"; //$NON-NLS-1$
+
+ /**
+ * The key to access the New target wizard image (enabled).
+ */
+ public static final String NOTIFICATION_CLOSE_HOVER = "NotificationCloseHover"; //$NON-NLS-1$
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationAction.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationAction.java
new file mode 100644
index 000000000..34f46ac55
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationAction.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSink;
+
+/**
+ * Describes how a {@link NotificationEvent} is handled. {@link NotificationAction}s store enablement and parameters
+ * that determine how the {@link NotificationSink} executes the action.
+ *
+ * @author Steffen Pingel
+ */
+public class NotificationAction {
+
+ private boolean selected;
+
+ private final NotificationSinkDescriptor sinkDescriptor;
+
+ public NotificationAction(NotificationSinkDescriptor sinkDescriptor) {
+ Assert.isNotNull(sinkDescriptor);
+ this.sinkDescriptor = sinkDescriptor;
+ }
+
+ public NotificationSinkDescriptor getSinkDescriptor() {
+ return sinkDescriptor;
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+
+ @Override
+ public String toString() {
+ return sinkDescriptor.getLabel();
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationCategory.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationCategory.java
new file mode 100644
index 000000000..c9a261922
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationCategory.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NotificationCategory extends NotificationElement {
+
+ private final List<NotificationEvent> events;
+
+ public NotificationCategory(IConfigurationElement element) {
+ super(element);
+ this.events = new ArrayList<NotificationEvent>();
+ }
+
+ public void addEvent(NotificationEvent event) {
+ event.setCategory(this);
+ events.add(event);
+ }
+
+ public List<NotificationEvent> getEvents() {
+ return events;
+ }
+
+ public void removeEvent(NotificationEvent event) {
+ event.setCategory(null);
+ events.remove(event);
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationElement.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationElement.java
new file mode 100644
index 000000000..7de3b44ee
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationElement.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NotificationElement {
+
+ protected final IConfigurationElement element;
+
+ private ImageDescriptor iconDescriptor;
+
+ private final String id;
+
+ private final String label;
+
+ public NotificationElement(IConfigurationElement element) {
+ Assert.isNotNull(element);
+ this.element = element;
+ this.id = element.getAttribute("id"); //$NON-NLS-1$
+ this.label = element.getAttribute("label"); //$NON-NLS-1$
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public ImageDescriptor getImageDescriptor() {
+ if (iconDescriptor == null) {
+ if (element != null) {
+ String iconPath = element.getAttribute("icon"); //$NON-NLS-1$
+ if (iconPath != null) {
+ iconDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(element.getContributor().getName(), iconPath);
+ }
+ }
+ }
+ return iconDescriptor;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public String getPluginId() {
+ return element.getContributor().getName();
+ }
+
+ public IStatus validate() {
+ if (id == null) {
+ return new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(),
+ NLS.bind("Extension {0} contributed by {1} does not specify id attribute", element.getNamespaceIdentifier(), getPluginId())); //$NON-NLS-1$
+ }
+ else if (label == null) {
+ return new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(),
+ NLS.bind("Extension {0} contributed by {1} does not specify label attribute", element.getNamespaceIdentifier(), getPluginId())); //$NON-NLS-1$
+ }
+ return Status.OK_STATUS;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationEvent.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationEvent.java
new file mode 100644
index 000000000..195072533
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationEvent.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Itema AS - bug 331424 handle default event-sink action associations
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSink;
+
+/**
+ * Describes an event that is handled through a notification. The handling of event is stored in
+ * {@link NotificationAction} objects that delegate to {@link NotificationSink} objects for the handling of actual
+ * events.
+ *
+ * @author Steffen Pingel
+ * @author Torkild U. Resheim
+ */
+public class NotificationEvent extends NotificationElement {
+
+ private static final String EXTENSION_POINT_ID = "org.eclipse.tcf.te.ui.notifications.notifications"; //$NON-NLS-1$
+
+ private NotificationCategory category;
+
+ private final ArrayList<String> defaultSinks;
+
+ /**
+ * Tests whether or not the event should per default be handled by the sink with the specified identifier.
+ *
+ * @param sinkId
+ * the sink identifier
+ * @return <code>true</code> if the
+ */
+ public boolean defaultHandledBySink(String sinkId) {
+ if (defaultSinks.isEmpty() || defaultSinks.contains(sinkId)) {
+ return true;
+ }
+ return false;
+ }
+
+ public NotificationEvent(IConfigurationElement element) {
+ super(element);
+ defaultSinks = new ArrayList<String>();
+ IConfigurationElement[] children = element.getChildren("defaultHandler"); //$NON-NLS-1$
+ for (IConfigurationElement child : children) {
+ defaultSinks.add(child.getAttribute("sinkId")); //$NON-NLS-1$
+ }
+ doEventMappings();
+ }
+
+ private void doEventMappings() {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint point = registry.getExtensionPoint(EXTENSION_POINT_ID);
+ if (point != null) {
+ IConfigurationElement[] elements = point.getConfigurationElements();
+ for (IConfigurationElement mapping : elements) {
+ if (mapping.getName().equals("eventMapping")) { //$NON-NLS-1$
+ String eventIds = mapping.getAttribute("eventIds"); //$NON-NLS-1$
+ String[] list = eventIds.split(","); //$NON-NLS-1$
+ for (String item : list) {
+ if (wildCardMatch(getId(), item)) {
+ defaultSinks.add(mapping.getAttribute("sinkId")); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private boolean wildCardMatch(String text, String pattern) {
+ String[] cards = pattern.split("\\*"); //$NON-NLS-1$
+ for (String card : cards) {
+ int idx = text.indexOf(card);
+ if (idx == -1) {
+ return false;
+ }
+ text = text.substring(idx + card.length());
+ }
+
+ return true;
+ }
+
+ public NotificationCategory getCategory() {
+ return category;
+ }
+
+ public String getCategoryId() {
+ return element.getAttribute("categoryId"); //$NON-NLS-1$
+ }
+
+ public String getDescription() {
+ IConfigurationElement[] children = element.getChildren("description"); //$NON-NLS-1$
+ if (children.length > 0) {
+ return children[0].getValue();
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ public void setCategory(NotificationCategory category) {
+ this.category = category;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationHandler.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationHandler.java
new file mode 100644
index 000000000..cd15cf446
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationHandler.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import java.util.List;
+
+/**
+ * Manages actions that are triggered when a {@link NotificationEvent} occurs.
+ *
+ * @author Steffen Pingel
+ */
+public class NotificationHandler {
+
+ private final List<NotificationAction> actions;
+
+ private final NotificationEvent event;
+
+ public NotificationHandler(NotificationEvent event, List<NotificationAction> actions) {
+ this.event = event;
+ this.actions = actions;
+ }
+
+ public List<NotificationAction> getActions() {
+ return actions;
+ }
+
+ public NotificationEvent getEvent() {
+ return event;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationModel.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationModel.java
new file mode 100644
index 000000000..6b4e7763a
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationModel.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Itema AS - bug 330064 notification filtering and model persistence
+ * Itema AS - bug 331424 handle default event-sink action associations
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Steffen Pingel
+ * @author Torkild U. Resheim
+ */
+public class NotificationModel {
+
+ private Map<String, NotificationHandler> handlerByEventId;
+
+ /**
+ * Constructor
+ */
+ public NotificationModel() {
+ this.handlerByEventId = new HashMap<String, NotificationHandler>();
+ // We need the handlerByEventId map to be populated early
+ for (NotificationCategory category : getCategories()) {
+ for (NotificationEvent event : category.getEvents()) {
+ getOrCreateNotificationHandler(event);
+ }
+ }
+ }
+
+ public Collection<NotificationCategory> getCategories() {
+ return NotificationsExtensionReader.getCategories();
+ }
+
+ public NotificationHandler getNotificationHandler(String eventId) {
+ return handlerByEventId.get(eventId);
+ }
+
+ public NotificationHandler getOrCreateNotificationHandler(NotificationEvent event) {
+ NotificationHandler handler = getNotificationHandler(event.getId());
+ if (handler == null) {
+ handler = new NotificationHandler(event, getActions(event));
+ handlerByEventId.put(event.getId(), handler);
+ }
+ return handler;
+ }
+
+ private List<NotificationAction> getActions(NotificationEvent event) {
+ List<NotificationSinkDescriptor> descriptors = NotificationsExtensionReader.getSinks();
+ List<NotificationAction> actions = new ArrayList<NotificationAction>(descriptors.size());
+ for (NotificationSinkDescriptor descriptor : descriptors) {
+ NotificationAction action = new NotificationAction(descriptor);
+ if (event.defaultHandledBySink(descriptor.getId())) {
+ action.setSelected(true);
+ }
+ actions.add(action);
+ }
+ return actions;
+ }
+
+ public boolean isSelected(NotificationEvent event) {
+ NotificationHandler handler = getOrCreateNotificationHandler(event);
+ for (NotificationAction action : handler.getActions()) {
+ if (action.isSelected()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationService.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationService.java
new file mode 100644
index 000000000..0f95e8f97
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationService.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Itema AS - bug 330064 notification filtering and model persistence
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.tcf.te.runtime.notifications.AbstractNotification;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSink;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSinkEvent;
+import org.eclipse.tcf.te.runtime.notifications.interfaces.INotificationService;
+import org.eclipse.tcf.te.runtime.services.AbstractService;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+import org.eclipse.tcf.te.ui.notifications.preferences.IPreferenceKeys;
+
+/**
+ * @author Steffen Pingel
+ * @author Torkild U. Resheim
+ */
+public class NotificationService extends AbstractService implements INotificationService {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.notifications.interfaces.INotificationService#notify(org.eclipse.tcf.te.runtime.notifications.AbstractNotification)
+ */
+ @Override
+ public void notify(AbstractNotification notification) {
+ notify(new AbstractNotification[] { notification });
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.runtime.notifications.interfaces.INotificationService#notify(org.eclipse.tcf.te.runtime.notifications.AbstractNotification[])
+ */
+ @Override
+ public void notify(AbstractNotification[] notifications) {
+ // Return if notifications are not globally enabled.
+ if (!UIPlugin.getDefault().getPreferenceStore().getBoolean(IPreferenceKeys.PREF_SERVICE_ENABLED)) {
+ return;
+ }
+
+ // For each sink assemble a list of notifications that are not blocked
+ // and pass these along.
+ HashMap<NotificationSink, ArrayList<AbstractNotification>> filtered = new HashMap<NotificationSink, ArrayList<AbstractNotification>>();
+ for (AbstractNotification notification : notifications) {
+ String id = notification.getEventId();
+ NotificationHandler handler = UIPlugin.getDefault().getModel().getNotificationHandler(id);
+ if (handler != null) {
+ List<NotificationAction> actions = handler.getActions();
+ for (NotificationAction action : actions) {
+ if (action.isSelected()) {
+ NotificationSink sink = action.getSinkDescriptor().getSink();
+ if (sink != null) {
+ ArrayList<AbstractNotification> list = filtered.get(sink);
+ if (list == null) {
+ list = new ArrayList<AbstractNotification>();
+ filtered.put(sink, list);
+ }
+ list.add(notification);
+ }
+ }
+ }
+ }
+ }
+ // Go through all the sinks that have notifications to display and let
+ // them do their job.
+ for (Entry<NotificationSink, ArrayList<AbstractNotification>> entry : filtered.entrySet()) {
+ final NotificationSink sink = entry.getKey();
+ final NotificationSinkEvent event = new NotificationSinkEvent(new ArrayList<AbstractNotification>(
+ entry.getValue()));
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void handleException(Throwable e) {
+ UIPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, UIPlugin.getUniqueIdentifier(), "Sink failed: " + sink.getClass(), e)); //$NON-NLS-1$
+ }
+
+ @Override
+ public void run() throws Exception {
+ sink.notify(event);
+ }
+ });
+ }
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationSinkDescriptor.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationSinkDescriptor.java
new file mode 100644
index 000000000..55de73fb2
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationSinkDescriptor.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSink;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NotificationSinkDescriptor extends NotificationElement {
+
+ private NotificationSink sink;
+
+ private Status status;
+
+ public NotificationSinkDescriptor(IConfigurationElement element) {
+ super(element);
+ }
+
+ public NotificationSink getSink() {
+ if (sink != null || status != null) {
+ return sink;
+ }
+
+ try {
+ Object object = element.createExecutableExtension("class"); //$NON-NLS-1$
+ if (object instanceof NotificationSink) {
+ sink = (NotificationSink) object;
+ return sink;
+ }
+
+ status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), NLS.bind("Sink ''{0}'' does not extend expected class for extension contributed by {1}", //$NON-NLS-1$
+ object.getClass().getCanonicalName(), getPluginId()));
+ }
+ catch (Throwable e) {
+ status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), NLS.bind("Sink failed to load for extension contributed by {0}", getPluginId()), e); //$NON-NLS-1$
+ }
+
+ StatusManager.getManager().handle(status);
+ return null;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationsExtensionReader.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationsExtensionReader.java
new file mode 100644
index 000000000..a5e728c4a
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/internal/NotificationsExtensionReader.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Itema AS - bug 330064 notification filtering and model persistence
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @author Steffen Pingel
+ * @author Torkild U. Resheim
+ */
+public class NotificationsExtensionReader {
+
+ private static boolean errorLogged = false;
+
+ static List<NotificationSinkDescriptor> sinks;
+
+ private static Collection<NotificationCategory> categories;
+
+ /**
+ * Returns a list of notification categories, each containing their belonging notification
+ * events. Once initialised the same list will be returned upon subsequent calls of this method.
+ *
+ * @return a list of notification categories.
+ * @see NotificationModel#save(org.eclipse.ui.IMemento)
+ * @see NotificationModel#load(org.eclipse.ui.IMemento)
+ */
+ public static Collection<NotificationCategory> getCategories() {
+ if (categories != null) {
+ return categories;
+ }
+ HashMap<String, NotificationCategory> categoryById = new HashMap<String, NotificationCategory>();
+
+ MultiStatus result = new MultiStatus(UIPlugin.getUniqueIdentifier(), 0, "Notifcation extensions failed to load", null); //$NON-NLS-1$
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint repositoriesExtensionPoint = registry.getExtensionPoint(UIPlugin.getUniqueIdentifier() + ".notifications"); //$NON-NLS-1$
+ IExtension[] extensions = repositoriesExtensionPoint.getExtensions();
+ for (IExtension extension : extensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for (IConfigurationElement element : elements) {
+ if ("category".equals(element.getName())) { //$NON-NLS-1$
+ NotificationCategory category = new NotificationCategory(element);
+ IStatus status = category.validate();
+ if (status.isOK()) {
+ categoryById.put(category.getId(), category);
+ }
+ else {
+ result.add(status);
+ }
+ }
+ }
+ for (IConfigurationElement element : elements) {
+ if ("event".equals(element.getName())) { //$NON-NLS-1$
+ NotificationEvent event = new NotificationEvent(element);
+ IStatus status = event.validate();
+ if (status.isOK()) {
+ NotificationCategory category = categoryById.get(event.getCategoryId());
+ if (category != null) {
+ category.addEvent(event);
+ }
+ else {
+ result.add(new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(),
+ NLS.bind("Extension {0} contributed by {1} specify unknown category ''{2}''", new String[] { element.getNamespaceIdentifier(), element.getContributor().getName(), event.getCategoryId() }))); //NON-NLS-1$ //$NON-NLS-1$
+ }
+ }
+ else {
+ result.add(status);
+ }
+ }
+ }
+ }
+
+ if (!result.isOK() && !errorLogged) {
+ StatusManager.getManager().handle(result);
+ errorLogged = true;
+ }
+
+ categories = categoryById.values();
+ return categories;
+ }
+
+ public static List<NotificationSinkDescriptor> getSinks() {
+ if (sinks != null) {
+ return sinks;
+ }
+
+ sinks = new ArrayList<NotificationSinkDescriptor>();
+
+ MultiStatus result = new MultiStatus(UIPlugin.getUniqueIdentifier(), 0, "Notifcation extensions failed to load", null); //$NON-NLS-1$
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint repositoriesExtensionPoint = registry.getExtensionPoint(UIPlugin.getUniqueIdentifier() + ".notifications"); //$NON-NLS-1$
+ IExtension[] extensions = repositoriesExtensionPoint.getExtensions();
+ for (IExtension extension : extensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for (IConfigurationElement element : elements) {
+ if ("sink".equals(element.getName())) { //$NON-NLS-1$
+ NotificationSinkDescriptor descriptor = new NotificationSinkDescriptor(element);
+ IStatus status = descriptor.validate();
+ if (status.isOK()) {
+ sinks.add(descriptor);
+ }
+ else {
+ result.add(status);
+ }
+ }
+ }
+ }
+
+ if (!result.isOK()) {
+ StatusManager.getManager().handle(result);
+ }
+
+ return sinks;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.java
index 633de7375..3e442c3db 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.java
@@ -29,4 +29,10 @@ public class Messages extends NLS {
// **** Declare externalized string id's down here *****
+ public static String PopupNotificationSink_Popup_Notifier_Job_Label;
+
+ public static String AbstractNotificationPopup_Close_Notification_Job;
+ public static String AbstractNotificationPopup_Notification;
+
+ public static String SwtUtil_Fading;
}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.properties
index 6db611c92..8e0eb16bd 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.properties
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/nls/Messages.properties
@@ -7,3 +7,10 @@
# Contributors:
# Wind River Systems - initial API and implementation
###############################################################################
+
+PopupNotificationSink_Popup_Notifier_Job_Label=Popup Notifier
+
+AbstractNotificationPopup_Close_Notification_Job=Close Notification Job
+AbstractNotificationPopup_Notification=Notification
+
+SwtUtil_Fading=Fading
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractNotificationPopup.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractNotificationPopup.java
new file mode 100644
index 000000000..a47a303f5
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractNotificationPopup.java
@@ -0,0 +1,617 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Benjamin Pasero - initial API and implementation
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.popup;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Region;
+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.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Monitor;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tcf.te.ui.notifications.AnimationUtil;
+import org.eclipse.tcf.te.ui.notifications.AnimationUtil.FadeJob;
+import org.eclipse.tcf.te.ui.notifications.AnimationUtil.IFadeListener;
+import org.eclipse.tcf.te.ui.notifications.GradientColors;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+import org.eclipse.tcf.te.ui.notifications.interfaces.ImageConsts;
+import org.eclipse.tcf.te.ui.notifications.nls.Messages;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A popup window with a title bar and message area for displaying notifications.
+ *
+ * @author Benjamin Pasero
+ * @author Mik Kersten
+ * @author Steffen Pingel
+ * @since 3.7
+ */
+public abstract class AbstractNotificationPopup extends Window {
+
+ private static final int TITLE_HEIGHT = 24;
+
+ private static final String LABEL_NOTIFICATION = Messages.AbstractNotificationPopup_Notification;
+
+ private static final String LABEL_JOB_CLOSE = Messages.AbstractNotificationPopup_Close_Notification_Job;
+
+ private static final int MAX_WIDTH = 400;
+
+ private static final int MIN_HEIGHT = 100;
+
+ private static final long DEFAULT_DELAY_CLOSE = 8 * 1000;
+
+ private static final int PADDING_EDGE = 5;
+
+ private long delayClose = DEFAULT_DELAY_CLOSE;
+
+ protected LocalResourceManager resources;
+
+ /* default */ GradientColors color;
+
+ /* default */ final Display display;
+
+ private Shell shell;
+
+ private Region lastUsedRegion;
+
+ /* default */ Image lastUsedBgImage;
+
+ private final Job closeJob = new Job(LABEL_JOB_CLOSE) {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ if (!display.isDisposed()) {
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ Shell shell = AbstractNotificationPopup.this.getShell();
+ if (shell == null || shell.isDisposed()) {
+ return;
+ }
+
+ if (isMouseOver(shell)) {
+ scheduleAutoClose();
+ return;
+ }
+
+ AbstractNotificationPopup.this.closeFade();
+ }
+
+ });
+ }
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ return Status.OK_STATUS;
+ }
+ };
+
+ private final boolean respectDisplayBounds = true;
+
+ private final boolean respectMonitorBounds = true;
+
+ /* default */ FadeJob fadeJob;
+
+ private boolean fadingEnabled;
+
+ public AbstractNotificationPopup(Display display) {
+ this(display, SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
+ }
+
+ public AbstractNotificationPopup(Display display, int style) {
+ super(new Shell(display));
+ setShellStyle(style);
+
+ this.display = display;
+ resources = new LocalResourceManager(JFaceResources.getResources());
+ initResources();
+
+ closeJob.setSystem(true);
+ }
+
+ public boolean isFadingEnabled() {
+ return fadingEnabled;
+ }
+
+ public void setFadingEnabled(boolean fadingEnabled) {
+ this.fadingEnabled = fadingEnabled;
+ }
+
+ /**
+ * Override to return a customized name.
+ *
+ * @return The name to be used in the title of the popup.
+ */
+ protected String getPopupShellTitle() {
+ return LABEL_NOTIFICATION;
+ }
+
+ /**
+ * Override to return a customized image. Defaults to the workbench window image.
+ *
+ * @param maximumHeight The maximum height of the image.
+ * @return The image or <code>null</code>.
+ */
+ protected Image getPopupShellImage(int maximumHeight) {
+ // always use the launching workbench window
+ IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
+ if (windows != null && windows.length > 0) {
+ IWorkbenchWindow workbenchWindow = windows[0];
+ if (workbenchWindow != null && !workbenchWindow.getShell().isDisposed()) {
+ Image image = workbenchWindow.getShell().getImage();
+ int diff = Integer.MAX_VALUE;
+ if (image != null && image.getBounds().height <= maximumHeight) {
+ diff = maximumHeight - image.getBounds().height;
+ } else {
+ image = null;
+ }
+
+ Image[] images = workbenchWindow.getShell().getImages();
+ if (images != null && images.length > 0) {
+ // find the icon that is closest in size, but not larger than maximumHeight
+ for (Image image2 : images) {
+ int newDiff = maximumHeight - image2.getBounds().height;
+ if (newDiff >= 0 && newDiff <= diff) {
+ diff = newDiff;
+ image = image2;
+ }
+ }
+ }
+
+ return image;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Override to populate with notifications.
+ *
+ * @param parent
+ */
+ protected void createContentArea(Composite parent) {
+ // empty by default
+ }
+
+ /**
+ * Override to customize the title bar
+ */
+ protected void createTitleArea(Composite parent) {
+ ((GridData) parent.getLayoutData()).heightHint = TITLE_HEIGHT;
+
+ Label titleImageLabel = new Label(parent, SWT.NONE);
+ titleImageLabel.setImage(getPopupShellImage(TITLE_HEIGHT));
+
+ Label titleTextLabel = new Label(parent, SWT.NONE);
+ titleTextLabel.setText(getPopupShellTitle());
+ titleTextLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
+ titleTextLabel.setForeground(getTitleForeground());
+ titleTextLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+ titleTextLabel.setCursor(parent.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
+
+ final Label button = new Label(parent, SWT.NONE);
+ button.setImage(UIPlugin.getImage(ImageConsts.NOTIFICATION_CLOSE));
+ button.addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ button.setImage(UIPlugin.getImage(ImageConsts.NOTIFICATION_CLOSE_HOVER));
+ }
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ button.setImage(UIPlugin.getImage(ImageConsts.NOTIFICATION_CLOSE));
+ }
+ });
+ button.addMouseListener(new MouseAdapter() {
+
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void mouseUp(MouseEvent e) {
+ close();
+ setReturnCode(CANCEL);
+ }
+
+ });
+ }
+
+ protected Color getTitleForeground() {
+ return color.getTitleText();
+ }
+
+ private void initResources() {
+ color = new GradientColors(display, resources);
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ shell = newShell;
+ newShell.setBackground(color.getBorder());
+ }
+
+ @Override
+ public void create() {
+ super.create();
+ addRegion(shell);
+ }
+
+ private void addRegion(Shell shell) {
+ Region region = new Region();
+ Point s = shell.getSize();
+
+ /* Add entire Shell */
+ region.add(0, 0, s.x, s.y);
+
+ /* Subtract Top-Left Corner */
+ region.subtract(0, 0, 5, 1);
+ region.subtract(0, 1, 3, 1);
+ region.subtract(0, 2, 2, 1);
+ region.subtract(0, 3, 1, 1);
+ region.subtract(0, 4, 1, 1);
+
+ /* Subtract Top-Right Corner */
+ region.subtract(s.x - 5, 0, 5, 1);
+ region.subtract(s.x - 3, 1, 3, 1);
+ region.subtract(s.x - 2, 2, 2, 1);
+ region.subtract(s.x - 1, 3, 1, 1);
+ region.subtract(s.x - 1, 4, 1, 1);
+
+ /* Subtract Bottom-Left Corner */
+ region.subtract(0, s.y, 5, 1);
+ region.subtract(0, s.y - 1, 3, 1);
+ region.subtract(0, s.y - 2, 2, 1);
+ region.subtract(0, s.y - 3, 1, 1);
+ region.subtract(0, s.y - 4, 1, 1);
+
+ /* Subtract Bottom-Right Corner */
+ region.subtract(s.x - 5, s.y - 0, 5, 1);
+ region.subtract(s.x - 3, s.y - 1, 3, 1);
+ region.subtract(s.x - 2, s.y - 2, 2, 1);
+ region.subtract(s.x - 1, s.y - 3, 1, 1);
+ region.subtract(s.x - 1, s.y - 4, 1, 1);
+
+ /* Dispose old first */
+ if (shell.getRegion() != null) {
+ shell.getRegion().dispose();
+ }
+
+ /* Apply Region */
+ shell.setRegion(region);
+
+ /* Remember to dispose later */
+ lastUsedRegion = region;
+ }
+
+ /* default */ boolean isMouseOver(Shell shell) {
+ if (display.isDisposed()) {
+ return false;
+ }
+ return shell.getBounds().contains(display.getCursorLocation());
+ }
+
+ @Override
+ public int open() {
+ if (shell == null || shell.isDisposed()) {
+ shell = null;
+ create();
+ }
+
+ constrainShellSize();
+ shell.setLocation(fixupDisplayBounds(shell.getSize(), shell.getLocation()));
+
+ if (isFadingEnabled()) {
+ shell.setAlpha(0);
+ }
+ shell.setVisible(true);
+ fadeJob = AnimationUtil.fadeIn(shell, new IFadeListener() {
+ @Override
+ public void faded(Shell shell, int alpha) {
+ if (shell.isDisposed()) {
+ return;
+ }
+
+ if (alpha == 255) {
+ scheduleAutoClose();
+ }
+ }
+ });
+
+ return Window.OK;
+ }
+
+ protected void scheduleAutoClose() {
+ if (delayClose > 0) {
+ closeJob.schedule(delayClose);
+ }
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ ((GridLayout) parent.getLayout()).marginWidth = 1;
+ ((GridLayout) parent.getLayout()).marginHeight = 1;
+
+ /* Outer Composite holding the controls */
+ final Composite outerCircle = new Composite(parent, SWT.NO_FOCUS);
+ outerCircle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ outerCircle.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ outerCircle.addControlListener(new ControlAdapter() {
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle clArea = outerCircle.getClientArea();
+ lastUsedBgImage = new Image(outerCircle.getDisplay(), clArea.width, clArea.height);
+ GC gc = new GC(lastUsedBgImage);
+
+ /* Gradient */
+ drawGradient(gc, clArea);
+
+ /* Fix Region Shape */
+ fixRegion(gc, clArea);
+
+ gc.dispose();
+
+ Image oldBGImage = outerCircle.getBackgroundImage();
+ outerCircle.setBackgroundImage(lastUsedBgImage);
+
+ if (oldBGImage != null) {
+ oldBGImage.dispose();
+ }
+ }
+
+ private void drawGradient(GC gc, Rectangle clArea) {
+ gc.setForeground(color.getGradientBegin());
+ gc.setBackground(color.getGradientEnd());
+ gc.fillGradientRectangle(clArea.x, clArea.y, clArea.width, clArea.height, true);
+ }
+
+ private void fixRegion(GC gc, Rectangle clArea) {
+ gc.setForeground(color.getBorder());
+
+ /* Fill Top Left */
+ gc.drawPoint(2, 0);
+ gc.drawPoint(3, 0);
+ gc.drawPoint(1, 1);
+ gc.drawPoint(0, 2);
+ gc.drawPoint(0, 3);
+
+ /* Fill Top Right */
+ gc.drawPoint(clArea.width - 4, 0);
+ gc.drawPoint(clArea.width - 3, 0);
+ gc.drawPoint(clArea.width - 2, 1);
+ gc.drawPoint(clArea.width - 1, 2);
+ gc.drawPoint(clArea.width - 1, 3);
+
+ /* Fill Bottom Left */
+ gc.drawPoint(2, clArea.height - 0);
+ gc.drawPoint(3, clArea.height - 0);
+ gc.drawPoint(1, clArea.height - 1);
+ gc.drawPoint(0, clArea.height - 2);
+ gc.drawPoint(0, clArea.height - 3);
+
+ /* Fill Bottom Right */
+ gc.drawPoint(clArea.width - 4, clArea.height - 0);
+ gc.drawPoint(clArea.width - 3, clArea.height - 0);
+ gc.drawPoint(clArea.width - 2, clArea.height - 1);
+ gc.drawPoint(clArea.width - 1, clArea.height - 2);
+ gc.drawPoint(clArea.width - 1, clArea.height - 3);
+ }
+ });
+
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ layout.verticalSpacing = 0;
+
+ outerCircle.setLayout(layout);
+
+ /* Title area containing label and close button */
+ final Composite titleCircle = new Composite(outerCircle, SWT.NO_FOCUS);
+ titleCircle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ titleCircle.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ layout = new GridLayout(4, false);
+ layout.marginWidth = 3;
+ layout.marginHeight = 0;
+ layout.verticalSpacing = 5;
+ layout.horizontalSpacing = 3;
+
+ titleCircle.setLayout(layout);
+
+ /* Create Title Area */
+ createTitleArea(titleCircle);
+
+ /* Outer composite to hold content controlls */
+ Composite outerContentCircle = new Composite(outerCircle, SWT.NONE);
+ outerContentCircle.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+
+ outerContentCircle.setLayout(layout);
+ outerContentCircle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ outerContentCircle.setBackground(outerCircle.getBackground());
+
+ /* Middle composite to show a 1px black line around the content controls */
+ Composite middleContentCircle = new Composite(outerContentCircle, SWT.NO_FOCUS);
+ middleContentCircle.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ layout.marginTop = 1;
+
+ middleContentCircle.setLayout(layout);
+ middleContentCircle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ middleContentCircle.setBackground(color.getBorder());
+
+ /* Inner composite containing the content controls */
+ Composite innerContent = new Composite(middleContentCircle, SWT.NO_FOCUS);
+ innerContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ innerContent.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ layout = new GridLayout(1, false);
+ layout.marginWidth = 0;
+ layout.marginHeight = 5;
+ layout.marginLeft = 5;
+ layout.marginRight = 5;
+ innerContent.setLayout(layout);
+
+ innerContent.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+
+ /* Content Area */
+ createContentArea(innerContent);
+
+ setNullBackground(outerCircle);
+
+ return outerCircle;
+ }
+
+ private void setNullBackground(final Composite outerCircle) {
+ for (Control c : outerCircle.getChildren()) {
+ c.setBackground(null);
+ if (c instanceof Composite) {
+ setNullBackground((Composite) c);
+ }
+ }
+ }
+
+ @Override
+ protected void initializeBounds() {
+ Rectangle clArea = getPrimaryClientArea();
+ Point initialSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ int height = Math.max(initialSize.y, MIN_HEIGHT);
+ int width = Math.min(initialSize.x, MAX_WIDTH);
+
+ Point size = new Point(width, height);
+ shell.setLocation(clArea.width + clArea.x - size.x - PADDING_EDGE, clArea.height + clArea.y - size.y
+ - PADDING_EDGE);
+ shell.setSize(size);
+ }
+
+ private Rectangle getPrimaryClientArea() {
+ Monitor primaryMonitor = shell.getDisplay().getPrimaryMonitor();
+ return (primaryMonitor != null) ? primaryMonitor.getClientArea() : shell.getDisplay().getClientArea();
+ }
+
+ public void closeFade() {
+ if (fadeJob != null) {
+ fadeJob.cancelAndWait(false);
+ }
+ fadeJob = AnimationUtil.fadeOut(getShell(), new IFadeListener() {
+ @Override
+ public void faded(Shell shell, int alpha) {
+ if (!shell.isDisposed()) {
+ if (alpha == 0) {
+ shell.close();
+ } else if (isMouseOver(shell)) {
+ if (fadeJob != null) {
+ fadeJob.cancelAndWait(false);
+ }
+ fadeJob = AnimationUtil.fastFadeIn(shell, new IFadeListener() {
+ @Override
+ public void faded(Shell shell, int alpha) {
+ if (shell.isDisposed()) {
+ return;
+ }
+
+ if (alpha == 255) {
+ scheduleAutoClose();
+ }
+ }
+ });
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean close() {
+ resources.dispose();
+ if (lastUsedRegion != null) {
+ lastUsedRegion.dispose();
+ }
+ if (lastUsedBgImage != null && !lastUsedBgImage.isDisposed()) {
+ lastUsedBgImage.dispose();
+ }
+ return super.close();
+ }
+
+ public long getDelayClose() {
+ return delayClose;
+ }
+
+ public void setDelayClose(long delayClose) {
+ this.delayClose = delayClose;
+ }
+
+ private Point fixupDisplayBounds(Point tipSize, Point location) {
+ if (respectDisplayBounds) {
+ Rectangle bounds;
+ Point rightBounds = new Point(tipSize.x + location.x, tipSize.y + location.y);
+
+ if (respectMonitorBounds) {
+ bounds = shell.getDisplay().getPrimaryMonitor().getBounds();
+ } else {
+ bounds = getPrimaryClientArea();
+ }
+
+ if (!(bounds.contains(location) && bounds.contains(rightBounds))) {
+ if (rightBounds.x > bounds.x + bounds.width) {
+ location.x -= rightBounds.x - (bounds.x + bounds.width);
+ }
+
+ if (rightBounds.y > bounds.y + bounds.height) {
+ location.y -= rightBounds.y - (bounds.y + bounds.height);
+ }
+
+ if (location.x < bounds.x) {
+ location.x = bounds.x;
+ }
+
+ if (location.y < bounds.y) {
+ location.y = bounds.y;
+ }
+ }
+ }
+
+ return location;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractUiNotification.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractUiNotification.java
new file mode 100644
index 000000000..710a4fd36
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/AbstractUiNotification.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.popup;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tcf.te.runtime.notifications.AbstractNotification;
+
+/**
+ * A notification with UI specific extensions.
+ *
+ * @author Steffen Pingel
+ */
+public abstract class AbstractUiNotification extends AbstractNotification {
+
+ public AbstractUiNotification(String eventId) {
+ super(eventId);
+ }
+
+ public abstract Image getNotificationImage();
+
+ public abstract Image getNotificationKindImage();
+
+ /**
+ * Executes the default action for opening the notification.
+ */
+ public abstract void open();
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/NotificationPopup.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/NotificationPopup.java
new file mode 100644
index 000000000..793f14968
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/NotificationPopup.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.popup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tcf.te.runtime.notifications.AbstractNotification;
+import org.eclipse.tcf.te.ui.notifications.ScalingHyperlink;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.IFormColors;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+
+/**
+ * @author Rob Elves
+ * @author Mik Kersten
+ */
+public class NotificationPopup extends AbstractNotificationPopup {
+
+ private static final int NUM_NOTIFICATIONS_TO_DISPLAY = 4;
+
+ /* default */ Color hyperlinkWidget = null;
+
+ private List<AbstractNotification> notifications;
+
+ /**
+ * Constructor
+ *
+ * @param parent The parent shell. Must not be <code>null</code>.
+ */
+ public NotificationPopup(Shell parent) {
+ super(parent.getDisplay());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.ui.notifications.popup.AbstractNotificationPopup#createContentArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void createContentArea(Composite parent) {
+ Assert.isNotNull(parent);
+ hyperlinkWidget = new Color(parent.getDisplay(), 12, 81, 172);
+ parent.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ if (hyperlinkWidget != null) {
+ hyperlinkWidget.dispose();
+ hyperlinkWidget = null;
+ }
+ }
+ });
+
+ int count = 0;
+ for (final AbstractNotification notification : notifications) {
+ Composite notificationComposite = new Composite(parent, SWT.NO_FOCUS);
+ GridLayout gridLayout = new GridLayout(2, false);
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(notificationComposite);
+ notificationComposite.setLayout(gridLayout);
+ notificationComposite.setBackground(parent.getBackground());
+
+ if (count < NUM_NOTIFICATIONS_TO_DISPLAY) {
+ final Label notificationLabelIcon = new Label(notificationComposite, SWT.NO_FOCUS);
+ notificationLabelIcon.setBackground(parent.getBackground());
+ if (notification instanceof AbstractUiNotification) {
+ notificationLabelIcon.setImage(((AbstractUiNotification) notification).getNotificationKindImage());
+ }
+
+ final ScalingHyperlink itemLink = new ScalingHyperlink(notificationComposite, SWT.BEGINNING | SWT.NO_FOCUS);
+ GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(itemLink);
+ itemLink.setForeground(hyperlinkWidget);
+ itemLink.registerMouseTrackListener();
+ itemLink.setText(LegacyActionTools.escapeMnemonics(notification.getLabel()));
+ if (notification instanceof AbstractUiNotification) {
+ itemLink.setImage(((AbstractUiNotification) notification).getNotificationImage());
+ }
+ itemLink.setBackground(parent.getBackground());
+ itemLink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ if (notification instanceof AbstractUiNotification) {
+ ((AbstractUiNotification) notification).open();
+ }
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ Shell windowShell = window.getShell();
+ if (windowShell != null) {
+ if (windowShell.getMinimized()) {
+ windowShell.setMinimized(false);
+ }
+
+ windowShell.open();
+ windowShell.forceActive();
+ }
+ }
+ }
+ });
+
+ String descriptionText = null;
+ if (notification.getDescription() != null) {
+ descriptionText = notification.getDescription();
+ }
+ if (descriptionText != null && !descriptionText.trim().equals("")) { //$NON-NLS-1$
+ Label descriptionLabel = new Label(notificationComposite, SWT.NO_FOCUS);
+ descriptionLabel.setText(LegacyActionTools.escapeMnemonics(descriptionText));
+ descriptionLabel.setBackground(parent.getBackground());
+ GridDataFactory.fillDefaults()
+ .span(2, SWT.DEFAULT)
+ .grab(true, false)
+ .align(SWT.FILL, SWT.TOP)
+ .applyTo(descriptionLabel);
+ }
+ } else {
+ int numNotificationsRemain = notifications.size() - count;
+ ScalingHyperlink remainingLink = new ScalingHyperlink(notificationComposite, SWT.NO_FOCUS);
+ remainingLink.setForeground(hyperlinkWidget);
+ remainingLink.registerMouseTrackListener();
+ remainingLink.setBackground(parent.getBackground());
+
+ remainingLink.setText(NLS.bind("{0} more", Integer.valueOf(numNotificationsRemain))); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().span(2, SWT.DEFAULT).applyTo(remainingLink);
+ remainingLink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ Shell windowShell = window.getShell();
+ if (windowShell != null) {
+ windowShell.setMaximized(true);
+ windowShell.open();
+ }
+ }
+ }
+ });
+ break;
+ }
+ count++;
+ }
+ }
+
+ public List<AbstractNotification> getNotifications() {
+ return new ArrayList<AbstractNotification>(notifications);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.ui.notifications.popup.AbstractNotificationPopup#getTitleForeground()
+ */
+ @Override
+ protected Color getTitleForeground() {
+ return UIPlugin.getDefault().getFormColors().getColor(IFormColors.TITLE);
+ }
+
+ public void setContents(List<AbstractNotification> notifications) {
+ this.notifications = notifications;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/sink/PopupNotificationSink.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/sink/PopupNotificationSink.java
new file mode 100644
index 000000000..dc7c0675f
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/popup/sink/PopupNotificationSink.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ * Wind River Systems - Extracted from o.e.mylyn.commons and adapted for Target Explorer
+ *******************************************************************************/
+
+package org.eclipse.tcf.te.ui.notifications.popup.sink;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tcf.te.runtime.notifications.AbstractNotification;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSink;
+import org.eclipse.tcf.te.runtime.notifications.NotificationSinkEvent;
+import org.eclipse.tcf.te.ui.notifications.nls.Messages;
+import org.eclipse.tcf.te.ui.notifications.popup.NotificationPopup;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Rob Elves
+ * @author Steffen Pingel
+ */
+public class PopupNotificationSink extends NotificationSink {
+
+ private static final long DELAY_OPEN = 1 * 1000;
+
+ private static final boolean runSystem = true;
+
+ /* default */ NotificationPopup popup;
+
+ /* default */ final WeakHashMap<Object, Object> cancelledTokens = new WeakHashMap<Object, Object>();
+
+ private final Set<AbstractNotification> notifications = new HashSet<AbstractNotification>();
+
+ /* default */ final Set<AbstractNotification> currentlyNotifying = Collections.synchronizedSet(notifications);
+
+ private final Job openJob = new Job(Messages.PopupNotificationSink_Popup_Notifier_Job_Label) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ if (Platform.isRunning() && PlatformUI.getWorkbench() != null
+ && PlatformUI.getWorkbench().getDisplay() != null
+ && !PlatformUI.getWorkbench().getDisplay().isDisposed()) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ collectNotifications();
+
+ if (popup != null && popup.getReturnCode() == Window.CANCEL) {
+ List<AbstractNotification> notifications = popup.getNotifications();
+ for (AbstractNotification notification : notifications) {
+ if (notification.getToken() != null) {
+ cancelledTokens.put(notification.getToken(), null);
+ }
+ }
+ }
+
+ for (Iterator<AbstractNotification> it = currentlyNotifying.iterator(); it.hasNext();) {
+ AbstractNotification notification = it.next();
+ if (notification.getToken() != null
+ && cancelledTokens.containsKey(notification.getToken())) {
+ it.remove();
+ }
+ }
+
+ synchronized (PopupNotificationSink.class) {
+ if (currentlyNotifying.size() > 0) {
+ showPopup();
+ }
+ }
+ }
+ });
+ }
+ } finally {
+ if (popup != null) {
+ schedule(popup.getDelayClose() / 2);
+ }
+ }
+
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ };
+
+
+ public PopupNotificationSink() {
+ openJob.setSystem(runSystem);
+ }
+
+ private void cleanNotified() {
+ currentlyNotifying.clear();
+ }
+
+ /** public for testing */
+ public void collectNotifications() {
+ }
+
+ /**
+ * public for testing purposes
+ */
+ public Set<AbstractNotification> getNotifications() {
+ synchronized (PopupNotificationSink.class) {
+ return currentlyNotifying;
+ }
+ }
+
+ public boolean isAnimationsEnabled() {
+ IPreferenceStore store = PlatformUI.getPreferenceStore();
+ return store.getBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS);
+ }
+
+ @Override
+ public void notify(NotificationSinkEvent event) {
+ currentlyNotifying.addAll(event.getNotifications());
+
+ if (!openJob.cancel()) {
+ try {
+ openJob.join();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ openJob.schedule(DELAY_OPEN);
+ }
+
+ public void showPopup() {
+ if (popup != null) {
+ popup.close();
+ }
+
+ Shell shell = new Shell(PlatformUI.getWorkbench().getDisplay());
+ popup = new NotificationPopup(shell);
+ popup.setFadingEnabled(isAnimationsEnabled());
+ List<AbstractNotification> toDisplay = new ArrayList<AbstractNotification>(currentlyNotifying);
+ Collections.sort(toDisplay);
+ popup.setContents(toDisplay);
+ cleanNotified();
+ popup.setBlockOnOpen(false);
+ popup.open();
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/IPreferenceKeys.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/IPreferenceKeys.java
new file mode 100644
index 000000000..82008acb7
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/IPreferenceKeys.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.ui.notifications.preferences;
+
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+
+
+/**
+ * Preference key identifiers.
+ */
+public interface IPreferenceKeys {
+ /**
+ * Common prefix for all core preference keys
+ */
+ public final String PREFIX = UIPlugin.getUniqueIdentifier();
+
+ /**
+ * If set to <code>true</code>, the notifications service is enabled.
+ */
+ public static final String PREF_SERVICE_ENABLED = PREFIX + ".service.enabled"; //$NON-NLS-1$
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/PreferencesInitializer.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/PreferencesInitializer.java
new file mode 100644
index 000000000..718bd9220
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.notifications/src/org/eclipse/tcf/te/ui/notifications/preferences/PreferencesInitializer.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.ui.notifications.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.tcf.te.ui.notifications.activator.UIPlugin;
+
+/**
+ * Preferences initializer implementation.
+ */
+public class PreferencesInitializer extends AbstractPreferenceInitializer {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+ */
+ @Override
+ public void initializeDefaultPreferences() {
+ // Get the preferences store
+ IPreferenceStore store = UIPlugin.getDefault().getPreferenceStore();
+ // [Hidden] Enable notifications service: default on
+ store.setDefault(IPreferenceKeys.PREF_SERVICE_ENABLED, true);
+ }
+
+}

Back to the top