summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Pingel2012-02-25 09:07:54 (EST)
committer Steffen Pingel2012-02-25 09:07:54 (EST)
commit3910a9fb5ac20c523859ca17ef8aac80d6c17245 (patch)
treee4653a3c4cbeacb151c30d7bbe0992c085546535
parentc04f8f262fa49407fd6dff4420f4644ec8470fdd (diff)
downloadorg.eclipse.mylyn.commons-3910a9fb5ac20c523859ca17ef8aac80d6c17245.zip
org.eclipse.mylyn.commons-3910a9fb5ac20c523859ca17ef8aac80d6c17245.tar.gz
org.eclipse.mylyn.commons-3910a9fb5ac20c523859ca17ef8aac80d6c17245.tar.bz2
NEW - bug 371599: Workbench fails to start: Plug-in
org.eclipse.mylyn.tasks.ui was unable to load class org.eclipse.mylyn.internal.tasks.ui.TaskTrimWidget https://bugs.eclipse.org/bugs/show_bug.cgi?id=371599 Change-Id: Ia209c264ad178e8b7397f3e7354e48a30bdc9b80
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/.project2
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/META-INF/MANIFEST.MF8
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/pom.xml2
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/.placeholder0
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/Account.java127
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IIdentity.java52
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfile.java32
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfileImage.java30
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/IdentityConnector.java31
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/Profile.java87
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/ProfileImage.java68
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/Identity.java311
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/IdentityModel.java103
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Gravatar.java109
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarCallbackAdapter.java34
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarConnector.java111
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarStore.java283
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarUtils.java116
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarCallback.java35
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarConstants.java53
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarHashProvider.java28
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Messages.java42
-rw-r--r--stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/messages.properties2
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/.project2
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/META-INF/MANIFEST.MF14
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/pom.xml2
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/.placeholder0
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/AbstractNotification.java49
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/INotificationService.java25
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSink.java21
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSinkEvent.java31
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/Notifications.java29
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/Messages.java33
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationAction.java51
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationCategory.java45
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationElement.java80
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationEvent.java127
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationHandler.java40
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationModel.java172
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationService.java91
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationSinkDescriptor.java58
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsExtensionReader.java143
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPlugin.java131
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesInitializer.java32
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesPage.java406
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/messages.properties4
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/Messages.java27
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/NotificationPopup.java176
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/PopupNotificationSink.java163
-rw-r--r--stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/messages.properties1
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/.project2
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/META-INF/MANIFEST.MF9
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/pom.xml2
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/.placehoder0
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/ILocationService.java40
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryCategory.java73
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryLocation.java358
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryValidator.java44
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationCredentials.java23
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationType.java29
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/ICredentialsStore.java43
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/UsernamePasswordCredentials.java105
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/CredentialsFactory.java34
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/InMemoryCredentialsStore.java85
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/LocationService.java100
-rw-r--r--stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/SecureCredentialsStore.java85
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/.project2
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/META-INF/MANIFEST.MF17
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/pom.xml2
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/.placehoder0
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/IPartContainer.java27
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/Messages.java66
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryLocationPart.java613
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryPropertyPage.java70
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryUi.java93
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryWizardPage.java117
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/messages.properties19
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/EmptyRepositoryCategoriesFilter.java36
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/Messages.java29
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/NewRepositoryHandler.java32
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoriesView.java72
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategoryContentProvider.java67
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategorySorter.java43
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLabelProvider.java41
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLocationValueProperty.java104
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/ShowInMenuContribution.java56
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/TeamUiPlugin.java52
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/messages.properties2
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizard.java172
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardCollectionComparator.java71
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardNewPage.java727
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardRegistry.java56
-rw-r--r--stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardSelectionPage.java146
93 files changed, 7371 insertions, 12 deletions
diff --git a/stubs/org.eclipse.mylyn.commons.identity/.project b/stubs/org.eclipse.mylyn.commons.identity/.project
index 240751e..5ff8cc4 100644
--- a/stubs/org.eclipse.mylyn.commons.identity/.project
+++ b/stubs/org.eclipse.mylyn.commons.identity/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.mylyn.commons.identity</name>
+ <name>org.eclipse.mylyn.commons.identity-stub</name>
<comment></comment>
<projects>
</projects>
diff --git a/stubs/org.eclipse.mylyn.commons.identity/META-INF/MANIFEST.MF b/stubs/org.eclipse.mylyn.commons.identity/META-INF/MANIFEST.MF
index 415523c..3680286 100644
--- a/stubs/org.eclipse.mylyn.commons.identity/META-INF/MANIFEST.MF
+++ b/stubs/org.eclipse.mylyn.commons.identity/META-INF/MANIFEST.MF
@@ -2,8 +2,14 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.mylyn.commons.identity;singleton:=true
-Bundle-Version: 0.9.0.v20111206-0100
+Bundle-Version: 0.9.0.v20120225-0100
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ClassPath: .
Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.mylyn.commons.identity;x-internal:=true,
+ org.eclipse.mylyn.commons.identity.spi;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.identity;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.identity.gravatar;x-internal:=true
diff --git a/stubs/org.eclipse.mylyn.commons.identity/pom.xml b/stubs/org.eclipse.mylyn.commons.identity/pom.xml
index c67fb0b..5e8a41b 100644
--- a/stubs/org.eclipse.mylyn.commons.identity/pom.xml
+++ b/stubs/org.eclipse.mylyn.commons.identity/pom.xml
@@ -8,7 +8,7 @@
<version>3.7.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.mylyn.commons.identity</artifactId>
- <version>0.9.0.v20111206-0100</version>
+ <version>0.9.0.v20120225-0100</version>
<packaging>eclipse-plugin</packaging>
<build>
<plugins>
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/.placeholder b/stubs/org.eclipse.mylyn.commons.identity/src/.placeholder
deleted file mode 100644
index e69de29..0000000
--- a/stubs/org.eclipse.mylyn.commons.identity/src/.placeholder
+++ /dev/null
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/Account.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/Account.java
new file mode 100644
index 0000000..e3b64ea
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/Account.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tasktop Technologies.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity;
+
+import java.io.Serializable;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * @author Steffen Pingel
+ */
+public class Account implements Serializable {
+
+ private static final long serialVersionUID = 3670630150657553390L;
+
+ public static Account id(String id) {
+ Assert.isNotNull(id);
+ return new Account(id);
+ }
+
+ private final String id;
+
+ private String kind;
+
+ private String name;
+
+ private String url;
+
+ private Account(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Account other = (Account) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (kind == null) {
+ if (other.kind != null) {
+ return false;
+ }
+ } else if (!kind.equals(other.kind)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ if (url == null) {
+ if (other.url != null) {
+ return false;
+ }
+ } else if (!url.equals(other.url)) {
+ return false;
+ }
+ return true;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getKind() {
+ return kind;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((kind == null) ? 0 : kind.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((url == null) ? 0 : url.hashCode());
+ return result;
+ }
+
+ public Account kind(String kind) {
+ this.kind = kind;
+ return this;
+ }
+
+ public Account name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Account url(String url) {
+ this.url = url;
+ return this;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IIdentity.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IIdentity.java
new file mode 100644
index 0000000..0e1efff
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IIdentity.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tasktop Technologies.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity;
+
+import java.beans.PropertyChangeListener;
+import java.util.UUID;
+import java.util.concurrent.Future;
+
+/**
+ * @author Steffen Pingel
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ * @since 0.8
+ */
+public interface IIdentity {
+
+ // public static final String KIND_DEFAULT = "org.eclipse.mylyn.commons.identity.default"; //$NON-NLS-1$
+ //
+ // public static final String KIND_EMAIL = "org.eclipse.mylyn.commons.identity.email"; //$NON-NLS-1$
+
+ public void addAccount(Account account);
+
+ public void addPropertyChangeListener(PropertyChangeListener listener);
+
+ public Account getAccountById(String id);
+
+ public Account getAccountByKind(String kind);
+
+ public Account[] getAccounts();
+
+ public String[] getAliases();
+
+ public UUID getId();
+
+ public void removeAccount(Account account);
+
+ public void removePropertyChangeListener(PropertyChangeListener listener);
+
+ public Future<IProfileImage> requestImage(int preferredWidth, int preferredHeight);
+
+ public Future<IProfile> requestProfile();
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfile.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfile.java
new file mode 100644
index 0000000..42c996e
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfile.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity;
+
+/**
+ * @author Steffen Pingel
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ * @since 0.8
+ */
+public interface IProfile {
+
+ public abstract String getCity();
+
+ public abstract String getCountry();
+
+ public abstract String getEmail();
+
+ public abstract IIdentity getIdentity();
+
+ public abstract String getName();
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfileImage.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfileImage.java
new file mode 100644
index 0000000..763fbc0
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/IProfileImage.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity;
+
+/**
+ * @author Steffen Pingel
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ * @since 0.8
+ */
+public interface IProfileImage {
+
+ public abstract byte[] getData();
+
+ public abstract int getWidth();
+
+ public abstract int getHeight();
+
+ public abstract String getFormat();
+
+} \ No newline at end of file
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/IdentityConnector.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/IdentityConnector.java
new file mode 100644
index 0000000..ca0f84b
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/IdentityConnector.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity.spi;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylyn.commons.identity.IIdentity;
+
+/**
+ * @author Steffen Pingel
+ * @since 0.8
+ */
+public abstract class IdentityConnector {
+
+ public abstract ProfileImage getImage(IIdentity identity, int preferredWidth, int preferredHeight,
+ IProgressMonitor monitor) throws CoreException;
+
+ public abstract boolean supportsImageSize(int preferredWidth, int preferredHeight);
+
+ public abstract void updateProfile(Profile profile, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/Profile.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/Profile.java
new file mode 100644
index 0000000..6183a6f
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/Profile.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tasktop Technologies.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity.spi;
+
+import java.io.Serializable;
+
+import org.eclipse.mylyn.commons.identity.IIdentity;
+import org.eclipse.mylyn.commons.identity.IProfile;
+
+/**
+ * @author Steffen Pingel
+ * @since 0.8
+ */
+public final class Profile implements IProfile, Serializable {
+
+ private static final long serialVersionUID = -1079729573911113939L;
+
+ private String city;
+
+ private String country;
+
+ private String email;
+
+ private final IIdentity identity;
+
+ private String name;
+
+ private int timeZoneOffset;
+
+ public Profile(IIdentity identity) {
+ this.identity = identity;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public IIdentity getIdentity() {
+ return identity;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getTimeZoneOffset() {
+ return timeZoneOffset;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setTimeZoneOffset(int timeZoneOffset) {
+ this.timeZoneOffset = timeZoneOffset;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/ProfileImage.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/ProfileImage.java
new file mode 100644
index 0000000..ad047bc
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/commons/identity/spi/ProfileImage.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tasktop Technologies.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.identity.spi;
+
+import java.io.Serializable;
+
+import org.eclipse.mylyn.commons.identity.IProfileImage;
+
+/**
+ * @author Steffen Pingel
+ * @since 0.8
+ */
+public final class ProfileImage implements IProfileImage, Serializable {
+
+ private static final long serialVersionUID = 8211724823497362719L;
+
+ byte[] data;
+
+ int width;
+
+ int height;
+
+ String format;
+
+ long timestamp;
+
+ public ProfileImage(byte[] data, int width, int height, String format) {
+ this.data = data;
+ this.width = width;
+ this.height = height;
+ this.format = format;
+ this.timestamp = System.currentTimeMillis();
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/Identity.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/Identity.java
new file mode 100644
index 0000000..ddc5eac
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/Identity.java
@@ -0,0 +1,311 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.mylyn.commons.identity.Account;
+import org.eclipse.mylyn.commons.identity.IIdentity;
+import org.eclipse.mylyn.commons.identity.IProfile;
+import org.eclipse.mylyn.commons.identity.IProfileImage;
+import org.eclipse.mylyn.commons.identity.spi.Profile;
+import org.eclipse.mylyn.commons.identity.spi.ProfileImage;
+
+/**
+ * @author Steffen Pingel
+ */
+public class Identity implements IIdentity {
+
+ private static abstract class FutureJob<T> extends Job implements Future<T> {
+
+ private boolean cancelled;
+
+ private final AtomicReference<Throwable> futureException = new AtomicReference<Throwable>();
+
+ private final AtomicReference<T> futureResult = new AtomicReference<T>();
+
+ private final CountDownLatch resultLatch = new CountDownLatch(1);
+
+ public FutureJob(String name) {
+ super(name);
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ this.cancelled = true;
+ return this.cancel();
+ }
+
+ public T get() throws InterruptedException, ExecutionException {
+ resultLatch.await();
+ return getFutureResult();
+ }
+
+ public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!resultLatch.await(timeout, unit)) {
+ throw new TimeoutException();
+ }
+ return getFutureResult();
+ }
+
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ public boolean isDone() {
+ return getResult() != null;
+ }
+
+ private T getFutureResult() throws ExecutionException {
+ Throwable t = futureException.get();
+ if (t != null) {
+ throw new ExecutionException(t);
+ }
+ return futureResult.get();
+ }
+
+ protected void done() {
+ if (resultLatch.getCount() > 0) {
+ error(new RuntimeException());
+ }
+ resultLatch.countDown();
+ }
+
+ protected IStatus error(Throwable t) {
+ futureException.set(t);
+ resultLatch.countDown();
+ if (t instanceof OperationCanceledException) {
+ return Status.CANCEL_STATUS;
+ }
+ return Status.OK_STATUS;
+ }
+
+ protected IStatus success(T result) {
+ futureResult.set(result);
+ resultLatch.countDown();
+ return Status.OK_STATUS;
+ }
+
+ }
+
+ private static final class FutureResult<T> implements Future<T> {
+
+ private final T result;
+
+ private FutureResult(T result) {
+ this.result = result;
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return true;
+ }
+
+ public T get() throws InterruptedException, ExecutionException {
+ return result;
+ }
+
+ public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ return result;
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public boolean isDone() {
+ return true;
+ }
+ }
+
+ private final Set<Account> accounts;
+
+ private final UUID id;
+
+ private List<ProfileImage> images;
+
+ private final List<PropertyChangeListener> listeners;
+
+ private final IdentityModel model;
+
+ private Profile profile;
+
+ private boolean refreshProfile;
+
+ public Identity(IdentityModel model) {
+ this.model = model;
+ this.id = UUID.randomUUID();
+ this.accounts = new CopyOnWriteArraySet<Account>();
+ this.listeners = new CopyOnWriteArrayList<PropertyChangeListener>();
+ }
+
+ public void addAccount(Account account) {
+ accounts.add(account);
+ refreshProfile = true;
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ public Account[] getAccounts() {
+ return accounts.toArray(new Account[accounts.size()]);
+ }
+
+ public Account getAccountById(String id) {
+ if (id == null) {
+ return null;
+ }
+ for (Account account : accounts) {
+ if (id.equals(account.getId())) {
+ return account;
+ }
+ }
+ return null;
+ }
+
+ public Account getAccountByKind(String kind) {
+ if (kind == null) {
+ return null;
+ }
+ for (Account account : accounts) {
+ if (kind.equals(account.getKind())) {
+ return account;
+ }
+ }
+ return null;
+ }
+
+ public String[] getAliases() {
+ Set<String> aliases = new HashSet<String>(accounts.size());
+ for (Account account : accounts) {
+ aliases.add(account.getId());
+ }
+ return aliases.toArray(new String[aliases.size()]);
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public boolean is(Account account) {
+ return accounts.contains(account);
+ }
+
+ public boolean is(String id) {
+ return getAccountById(id) != null;
+ }
+
+ public void removeAccount(Account account) {
+ accounts.remove(account);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+ public synchronized Future<IProfileImage> requestImage(final int preferredWidth, final int preferredHeight) {
+ if (images != null) {
+ for (final ProfileImage image : images) {
+ if (image.getWidth() == preferredWidth && image.getHeight() == preferredHeight) {
+ return new FutureResult<IProfileImage>(image);
+ }
+ }
+ }
+ FutureJob<IProfileImage> job = new FutureJob<IProfileImage>("Retrieving Image") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ ProfileImage image = model.getImage(Identity.this, preferredWidth, preferredHeight, monitor);
+ if (image != null) {
+ addImage(image);
+ }
+ return success(image);
+ } catch (Throwable t) {
+ return error(t);
+ } finally {
+ done();
+ }
+ }
+ };
+ job.schedule();
+ return job;
+ }
+
+ public Future<IProfile> requestProfile() {
+ if (profile != null && !refreshProfile) {
+ return new FutureResult<IProfile>(profile);
+ }
+
+ refreshProfile = false;
+ FutureJob<IProfile> job = new FutureJob<IProfile>("Retrieving Profile") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ Profile profile = new Profile(Identity.this);
+ model.updateProfile(profile, monitor);
+ setProfile(profile);
+ return success(profile);
+ } catch (Throwable t) {
+ return error(t);
+ } finally {
+ done();
+ }
+ }
+ };
+ job.schedule();
+ return job;
+ }
+
+ private void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
+ PropertyChangeEvent event = new PropertyChangeEvent(this, propertyName, oldValue, newValue);
+ for (PropertyChangeListener listener : listeners) {
+ listener.propertyChange(event);
+ }
+ }
+
+ protected synchronized void addImage(ProfileImage image) {
+ if (images == null) {
+ images = new ArrayList<ProfileImage>();
+ }
+ images.add(image);
+ firePropertyChangeEvent("image", null, image); //$NON-NLS-1$
+ }
+
+ protected synchronized void removeImage(ProfileImage image) {
+ if (images != null) {
+ images.remove(image);
+ }
+ }
+
+ protected void setProfile(Profile profile) {
+ this.profile = profile;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/IdentityModel.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/IdentityModel.java
new file mode 100644
index 0000000..189feea
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/IdentityModel.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.WeakHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylyn.commons.identity.Account;
+import org.eclipse.mylyn.commons.identity.IIdentity;
+import org.eclipse.mylyn.commons.identity.spi.IdentityConnector;
+import org.eclipse.mylyn.commons.identity.spi.Profile;
+import org.eclipse.mylyn.commons.identity.spi.ProfileImage;
+import org.eclipse.mylyn.internal.commons.identity.gravatar.GravatarConnector;
+
+/**
+ * @author Steffen Pingel
+ * @since 0.8
+ */
+public final class IdentityModel implements Serializable {
+
+ private transient final List<IdentityConnector> connectors;
+
+ private transient final File cacheDirectory;
+
+ private final Map<UUID, Identity> identityById;
+
+ public IdentityModel(File cacheDirectory) {
+ this.cacheDirectory = cacheDirectory;
+ connectors = new CopyOnWriteArrayList<IdentityConnector>();
+ identityById = new WeakHashMap<UUID, Identity>();
+ }
+
+ public void addConnector(IdentityConnector connector) {
+ connectors.add(new GravatarConnector());
+ }
+
+ public synchronized IIdentity getIdentity(Account account) {
+ for (Identity identity : identityById.values()) {
+ if (identity.is(account)) {
+ return identity;
+ }
+ }
+
+ Identity identity = new Identity(this);
+ identity.addAccount(account);
+
+ // cache identity
+ identityById.put(identity.getId(), identity);
+
+ return identity;
+ }
+
+ public void removeConnector(IdentityConnector connector) {
+ connectors.remove(new GravatarConnector());
+ }
+
+ public IIdentity[] getIdentities() {
+ return identityById.values().toArray(new IIdentity[identityById.values().size()]);
+ }
+
+ public ProfileImage getImage(Identity identity, int preferredWidth, int preferredHeight, IProgressMonitor monitor)
+ throws CoreException {
+ for (IdentityConnector connector : connectors) {
+ ProfileImage image = connector.getImage(identity, preferredHeight, preferredHeight, monitor);
+ if (image != null) {
+ return image;
+ }
+ }
+ return null;
+ }
+
+ public void updateProfile(Profile profile, IProgressMonitor monitor) throws CoreException {
+ Account[] accounts = profile.getIdentity().getAccounts();
+ for (Account account : accounts) {
+ if (profile.getEmail() == null && account.getId().contains("@")) { //$NON-NLS-1$
+ profile.setEmail(account.getId());
+ }
+ if (profile.getName() == null && account.getName() != null) {
+ profile.setName(account.getName());
+ }
+ }
+ for (IdentityConnector connector : connectors) {
+ connector.updateProfile(profile, monitor);
+ }
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Gravatar.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Gravatar.java
new file mode 100644
index 0000000..183e261
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Gravatar.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+import java.io.Serializable;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * Gravatar class containing id and image data.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public class Gravatar implements Serializable {
+
+ /**
+ * serialVersionUID
+ */
+ private static final long serialVersionUID = 7303486086217698261L;
+
+ private final String id;
+
+ private final long updateTime;
+
+ private final byte[] bytes;
+
+ /**
+ * Create gravatar
+ *
+ * @param id
+ * @param updateTime
+ * @param bytes
+ */
+ public Gravatar(String id, long updateTime, byte[] bytes) {
+ Assert.isNotNull(id, "Id cannot be null"); //$NON-NLS-1$
+ Assert.isNotNull(bytes, "Bytes cannot be null"); //$NON-NLS-1$
+ this.id = id;
+ this.updateTime = updateTime;
+ this.bytes = bytes;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return this.id.hashCode();
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof Gravatar) {
+ return getId().equals(((Gravatar) obj).getId());
+ }
+ return false;
+ }
+
+ /**
+ * Get gravatar image as byte array
+ *
+ * @return non-null byte array
+ */
+ public byte[] getBytes() {
+ byte[] copy = new byte[this.bytes.length];
+ System.arraycopy(this.bytes, 0, copy, 0, copy.length);
+ return copy;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.id;
+ }
+
+ /**
+ * Get gravatar id
+ *
+ * @return id
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * Get time gravatar was loaded
+ *
+ * @return update time
+ */
+ public long getUpdateTime() {
+ return this.updateTime;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarCallbackAdapter.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarCallbackAdapter.java
new file mode 100644
index 0000000..a669898
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarCallbackAdapter.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+/**
+ * Base implementation of {@link IGravatarCallback}
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public abstract class GravatarCallbackAdapter implements IGravatarCallback {
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarCallback#loaded(org.eclipse.mylyn.internal.commons.identity.gravatar.Gravatar)
+ */
+ public void loaded(Gravatar avatar) {
+ // Does nothing sub-clsases should override
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarCallback#error(java.lang.Exception)
+ */
+ public void error(Exception exception) {
+ // Does nothing sub-clsases should override
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarConnector.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarConnector.java
new file mode 100644
index 0000000..78d72bf
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarConnector.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.commons.identity.Account;
+import org.eclipse.mylyn.commons.identity.IIdentity;
+import org.eclipse.mylyn.commons.identity.spi.IdentityConnector;
+import org.eclipse.mylyn.commons.identity.spi.Profile;
+import org.eclipse.mylyn.commons.identity.spi.ProfileImage;
+
+/**
+ * @author Steffen Pingel
+ */
+public class GravatarConnector extends IdentityConnector {
+
+ public static final String KIND = "org.eclipse.mylyn.commons.identity.gravatar"; //$NON-NLS-1$
+
+ private final GravatarStore store;
+
+ private final int DEFAULT_SIZE = 80;
+
+ private final Map<String, Long> noImageHashByTimeStamp = new ConcurrentHashMap<String, Long>();
+
+ public GravatarConnector() {
+ this.store = new GravatarStore();
+ }
+
+ @Override
+ public ProfileImage getImage(IIdentity identity, int preferredWidth, int preferredHeight, IProgressMonitor monitor)
+ throws CoreException {
+ String id = getHash(identity);
+ if (id == null) {
+ return null;
+ }
+
+ // avoid retrieving image again i
+ if (noImageHashByTimeStamp.containsKey(id)) {
+ return null;
+ }
+
+ // store id for future retrieval
+ identity.addAccount(Account.id(id).kind(KIND));
+
+ int size = getSize(preferredWidth);
+ Gravatar gravatar;
+ try {
+ gravatar = store.loadGravatarByHash(id, size, null);
+ } catch (IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, KIND, e.getMessage(), e));
+ }
+
+ if (gravatar != null) {
+ return new ProfileImage(gravatar.getBytes(), size, size, "jpg"); //$NON-NLS-1$
+ } else {
+ noImageHashByTimeStamp.put(id, Long.valueOf(System.currentTimeMillis()));
+ }
+ return null;
+ }
+
+ private int getSize(int preferredSize) {
+ if (preferredSize < 1 && preferredSize > 512) {
+ return DEFAULT_SIZE;
+ }
+ return preferredSize;
+ }
+
+ @Override
+ public boolean supportsImageSize(int preferredWidth, int preferredHeight) {
+ return (preferredWidth >= 1 && preferredWidth <= 512 && preferredHeight >= 1 && preferredHeight <= 512 && preferredWidth == preferredHeight);
+ }
+
+ @Override
+ public void updateProfile(Profile profile, IProgressMonitor monitor) throws CoreException {
+ // TODO retrieve Gravatar profile information
+ }
+
+ private String getHash(IIdentity identity) {
+ Account account = identity.getAccountByKind(KIND);
+ if (account != null) {
+ if (GravatarUtils.isValidHash(account.getId())) {
+ return account.getId();
+ }
+ }
+
+ for (String alias : identity.getAliases()) {
+ if (GravatarUtils.isValidEmail(alias)) {
+ return GravatarUtils.getHash(alias);
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarStore.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarStore.java
new file mode 100644
index 0000000..79e535c
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarStore.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * Class that loads and stores gravatars.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public class GravatarStore implements Serializable, ISchedulingRule {
+
+ private boolean cacheEnabled;
+
+ /**
+ * TIMEOUT
+ */
+ public static final int TIMEOUT = 30 * 1000;
+
+ /**
+ * BUFFER_SIZE
+ */
+ public static final int BUFFER_SIZE = 8192;
+
+ public enum Rating {
+ G, PG, R, X
+ };
+
+ private static final long serialVersionUID = 6084425297832914970L;
+
+ private long lastRefresh = 0L;
+
+ private final String url;
+
+ private Map<String, Gravatar> avatars;
+
+ /**
+ * Create gravatar store
+ */
+ public GravatarStore() {
+ this(IGravatarConstants.URL);
+ }
+
+ /**
+ * Create gravatar store
+ *
+ * @param url
+ */
+ public GravatarStore(String url) {
+ Assert.isNotNull(url, "Url cannot be null"); //$NON-NLS-1$
+ // Ensure trailing slash
+ if (!url.endsWith("/")) { //$NON-NLS-1$
+ url += "/"; //$NON-NLS-1$
+ }
+ this.url = url;
+ }
+
+ public boolean isCacheEnabled() {
+ return avatars != null;
+ }
+
+ public void setCacheEnabled(boolean cacheEnabled) {
+ this.cacheEnabled = cacheEnabled;
+ if (cacheEnabled && avatars == null) {
+ avatars = Collections.synchronizedMap(new HashMap<String, Gravatar>());
+ } else if (!cacheEnabled && avatars != null) {
+ avatars = null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#getRefreshTime()
+ */
+ public long getRefreshTime() {
+ return this.lastRefresh;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#containsGravatar(java.lang.String)
+ */
+ public boolean containsGravatar(String hash) {
+ return hash != null && avatars != null ? this.avatars.containsKey(hash) : false;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#scheduleRefresh()
+ */
+ public GravatarStore scheduleRefresh() {
+ Job refresh = new Job(Messages.GravatarStore_RefreshJobName) {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ refresh(monitor);
+ return Status.OK_STATUS;
+ }
+ };
+ refresh.setRule(this);
+ refresh.schedule();
+ return this;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#refresh(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public GravatarStore refresh(IProgressMonitor monitor) {
+ if (this.avatars == null) {
+ return this;
+ }
+ if (monitor == null) {
+ monitor = new NullProgressMonitor();
+ }
+ String[] entries = null;
+ synchronized (this.avatars) {
+ entries = new String[this.avatars.size()];
+ entries = this.avatars.keySet().toArray(entries);
+ }
+ monitor.beginTask("", entries.length); //$NON-NLS-1$
+ for (String entry : entries) {
+ if (monitor.isCanceled()) {
+ break;
+ }
+ monitor.setTaskName(MessageFormat.format(Messages.GravatarStore_LoadingAvatar, entry));
+ try {
+ loadGravatarByHash(entry);
+ } catch (IOException ignore) {
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+ this.lastRefresh = System.currentTimeMillis();
+ return this;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByHash(java.lang.String,
+ * org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarCallback)
+ */
+ public GravatarStore loadGravatarByHash(final String hash, final IGravatarCallback callback) {
+ String title = MessageFormat.format(Messages.GravatarStore_LoadingAvatar, hash);
+ Job job = new Job(title) {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ Gravatar avatar = loadGravatarByHash(hash);
+ if (avatar != null && callback != null) {
+ callback.loaded(avatar);
+ }
+ } catch (IOException e) {
+ if (callback != null) {
+ callback.error(e);
+ }
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(this);
+ job.schedule();
+ return this;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByEmail(java.lang.String,
+ * org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarCallback)
+ */
+ public GravatarStore loadGravatarByEmail(String email, IGravatarCallback callback) {
+ loadGravatarByHash(GravatarUtils.getHash(email), callback);
+ return this;
+ }
+
+ public Gravatar loadGravatarByHash(String hash) throws IOException {
+ return loadGravatarByHash(hash, -1, null);
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByHash(java.lang.String)
+ */
+ public Gravatar loadGravatarByHash(String hash, int size, Rating rating) throws IOException {
+ Assert.isLegal(size == -1 || (size >= 1 && size <= 512), "size must have a value of -1 or between 1 and 512"); //$NON-NLS-1$
+ if (!GravatarUtils.isValidHash(hash)) {
+ return null;
+ }
+
+ Gravatar avatar = null;
+ String location = this.url + hash + "?d=404"; //$NON-NLS-1$
+ if (size != -1) {
+ location += "&s=" + size; //$NON-NLS-1$
+ }
+ if (rating != null) {
+ location += "&r=" + rating.name().toLowerCase(); //$NON-NLS-1$
+ }
+ HttpURLConnection connection = (HttpURLConnection) new URL(location).openConnection();
+ connection.setConnectTimeout(TIMEOUT);
+ connection.setUseCaches(false);
+ connection.connect();
+
+ if (connection.getResponseCode() != 200) {
+ return null;
+ }
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ InputStream input = connection.getInputStream();
+ try {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int read = -1;
+ while ((read = input.read(buffer)) != -1) {
+ output.write(buffer, 0, read);
+ }
+ } finally {
+ try {
+ input.close();
+ } catch (IOException ignore) {
+ }
+ }
+ avatar = new Gravatar(hash, System.currentTimeMillis(), output.toByteArray());
+ if (this.avatars != null) {
+ this.avatars.put(hash, avatar);
+ }
+ return avatar;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByEmail(java.lang.String)
+ */
+ public Gravatar loadGravatarByEmail(String email) throws IOException {
+ return loadGravatarByHash(GravatarUtils.getHash(email));
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#getGravatarByHash(java.lang.String)
+ */
+ public Gravatar getGravatarByHash(String hash) {
+ return hash != null && avatars != null ? this.avatars.get(hash) : null;
+ }
+
+ /**
+ * @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#getGravatarByEmail(java.lang.String)
+ */
+ public Gravatar getGravatarByEmail(String email) {
+ return getGravatarByHash(GravatarUtils.getHash(email));
+ }
+
+ /**
+ * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
+ */
+ public boolean contains(ISchedulingRule rule) {
+ return this == rule;
+ }
+
+ /**
+ * @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
+ */
+ public boolean isConflicting(ISchedulingRule rule) {
+ return this == rule;
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarUtils.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarUtils.java
new file mode 100644
index 0000000..c6d0f4b
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/GravatarUtils.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ * Tasktop Technologies - improvements
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Locale;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Gravatar utililites.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public abstract class GravatarUtils {
+
+ private static String digest(String value) {
+ String hashed = null;
+ try {
+ byte[] input = value.getBytes(IGravatarConstants.CHARSET);
+ byte[] digested = MessageDigest.getInstance(IGravatarConstants.HASH_ALGORITHM).digest(input);
+ hashed = new BigInteger(1, digested).toString(16);
+ int padding = IGravatarConstants.HASH_LENGTH - hashed.length();
+ if (padding > 0) {
+ char[] zeros = new char[padding];
+ Arrays.fill(zeros, '0');
+ hashed = new String(zeros) + hashed;
+ }
+ } catch (NoSuchAlgorithmException e) {
+ hashed = null;
+ } catch (UnsupportedEncodingException e) {
+ hashed = null;
+ }
+ return hashed;
+ }
+
+ /**
+ * Get hash for object by attempting to adapt it to an {@link IGravatarHashProvider} and fall back on
+ * {@link Object#toString()} value if adaptation fails and {@link Object#toString()} is or can be transformed into a
+ * valid hash.
+ *
+ * @param element
+ * @return hash
+ */
+ public String getAdaptedHash(Object element) {
+ if (element == null) {
+ return null;
+ }
+
+ String hash = null;
+ IGravatarHashProvider provider = null;
+ if (element instanceof IGravatarHashProvider) {
+ provider = (IGravatarHashProvider) element;
+ } else if (element instanceof IAdaptable) {
+ provider = (IGravatarHashProvider) ((IAdaptable) element).getAdapter(IGravatarHashProvider.class);
+ }
+ if (provider != null) {
+ hash = provider.getGravatarHash();
+ } else {
+ String potentialHash = element.toString();
+ if (isValidHash(potentialHash)) {
+ hash = potentialHash;
+ } else {
+ hash = getHash(potentialHash);
+ }
+ }
+ return hash;
+ }
+
+ /**
+ * Is the specified string a valid graavatar hash?
+ *
+ * @param hash
+ * @return true if valid hash, false otherwise
+ */
+ public static boolean isValidHash(String hash) {
+ return hash != null && hash.length() == IGravatarConstants.HASH_LENGTH
+ && IGravatarConstants.HASH_PATTERN.matcher(hash).matches();
+ }
+
+ /**
+ * Get gravatar hash for specified e-mail address
+ *
+ * @param email
+ * @return hash
+ */
+ public static String getHash(String email) {
+ String hash = null;
+ if (email != null) {
+ email = email.trim().toLowerCase(Locale.US);
+ if (email.length() > 0) {
+ hash = digest(email);
+ }
+ }
+ return hash;
+ }
+
+ public static boolean isValidEmail(String alias) {
+ return alias != null && alias.contains("@");
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarCallback.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarCallback.java
new file mode 100644
index 0000000..9ae9438
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarCallback.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+/**
+ * Callback interface for when gravatar loading completes or fails.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public interface IGravatarCallback {
+
+ /**
+ * Gravatar loaded successfully
+ *
+ * @param avatar
+ */
+ void loaded(Gravatar avatar);
+
+ /**
+ * Gravatar loading failed
+ *
+ * @param exception
+ */
+ void error(Exception exception);
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarConstants.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarConstants.java
new file mode 100644
index 0000000..40bdaa3
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarConstants.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+import java.util.regex.Pattern;
+
+/**
+ * Gravatar constants.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public interface IGravatarConstants {
+
+ /**
+ * URL
+ */
+ String URL = "http://www.gravatar.com/avatar/"; //$NON-NLS-1$
+
+ /**
+ * HASH_REGEX
+ */
+ String HASH_REGEX = "[0-9a-f]{32}"; //$NON-NLS-1$
+
+ /**
+ * HASH_PATTERN
+ */
+ Pattern HASH_PATTERN = Pattern.compile(HASH_REGEX);
+
+ /**
+ * HASH_LENGTH
+ */
+ int HASH_LENGTH = 32;
+
+ /**
+ * HASH_ALGORITHM
+ */
+ String HASH_ALGORITHM = "MD5"; //$NON-NLS-1$
+
+ /**
+ * Charset used for hashing
+ */
+ String CHARSET = "CP1252"; //$NON-NLS-1$
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarHashProvider.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarHashProvider.java
new file mode 100644
index 0000000..332a4a9
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/IGravatarHashProvider.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+/**
+ * Interface for providing a gravatar hash.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public interface IGravatarHashProvider {
+
+ /**
+ * Get hash for gravatar lookup
+ *
+ * @return gravatar hash
+ */
+ String getGravatarHash();
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Messages.java b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Messages.java
new file mode 100644
index 0000000..2bb7909
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/Messages.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.identity.gravatar;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * NLS
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.commons.identity.gravatar.messages"; //$NON-NLS-1$
+
+ /**
+ * GravatarStore_LoadingAvatar
+ */
+ public static String GravatarStore_LoadingAvatar;
+
+ /**
+ * GravatarStore_RefreshJobName
+ */
+ public static String GravatarStore_RefreshJobName;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/messages.properties b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/messages.properties
new file mode 100644
index 0000000..1ac24af
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.identity/src/org/eclipse/mylyn/internal/commons/identity/gravatar/messages.properties
@@ -0,0 +1,2 @@
+GravatarStore_LoadingAvatar=Loading gravatar for {0}
+GravatarStore_RefreshJobName=Refreshing gravatars
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/.project b/stubs/org.eclipse.mylyn.commons.notifications/.project
index d899a29..1250d04 100644
--- a/stubs/org.eclipse.mylyn.commons.notifications/.project
+++ b/stubs/org.eclipse.mylyn.commons.notifications/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.mylyn.commons.notifications</name>
+ <name>org.eclipse.mylyn.commons.notifications-stub</name>
<comment></comment>
<projects>
</projects>
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/META-INF/MANIFEST.MF b/stubs/org.eclipse.mylyn.commons.notifications/META-INF/MANIFEST.MF
index ecebc28..929b4d1 100644
--- a/stubs/org.eclipse.mylyn.commons.notifications/META-INF/MANIFEST.MF
+++ b/stubs/org.eclipse.mylyn.commons.notifications/META-INF/MANIFEST.MF
@@ -2,8 +2,20 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.mylyn.commons.notifications;singleton:=true
-Bundle-Version: 0.9.0.v20111206-0100
+Bundle-Version: 0.9.0.v20120225-0100
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: org.eclipse.mylyn.commons.ui.notifications;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.ui.notifications;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.ui.notifications.popup;x-internal:=true
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.jface,
+ org.eclipse.ui,
+ org.eclipse.ui.workbench,
+ org.eclipse.mylyn.commons.core;bundle-version="3.5.0",
+ org.eclipse.mylyn.commons.ui;bundle-version="3.5.0",
+ org.eclipse.ui.forms
Bundle-ClassPath: .
Bundle-Localization: plugin
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.mylyn.internal.commons.ui.notifications.NotificationsPlugin
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/pom.xml b/stubs/org.eclipse.mylyn.commons.notifications/pom.xml
index e50f9b1..6a4403d 100644
--- a/stubs/org.eclipse.mylyn.commons.notifications/pom.xml
+++ b/stubs/org.eclipse.mylyn.commons.notifications/pom.xml
@@ -8,7 +8,7 @@
<version>3.7.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.mylyn.commons.notifications</artifactId>
- <version>0.9.0.v20111206-0100</version>
+ <version>0.9.0.v20120225-0100</version>
<packaging>eclipse-plugin</packaging>
<build>
<plugins>
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/.placeholder b/stubs/org.eclipse.mylyn.commons.notifications/src/.placeholder
deleted file mode 100644
index e69de29..0000000
--- a/stubs/org.eclipse.mylyn.commons.notifications/src/.placeholder
+++ /dev/null
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/AbstractNotification.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/AbstractNotification.java
new file mode 100644
index 0000000..e933ccb
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/AbstractNotification.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.notifications;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * @author Rob Elves
+ * @author Mik Kersten
+ */
+public abstract class AbstractNotification implements Comparable<AbstractNotification>, IAdaptable {
+
+ private final String eventId;
+
+ public AbstractNotification(String eventId) {
+ Assert.isNotNull(eventId);
+ this.eventId = eventId;
+ }
+
+ public String getEventId() {
+ return eventId;
+ }
+
+ public abstract void open();
+
+ public abstract String getDescription();
+
+ public abstract String getLabel();
+
+ public abstract Image getNotificationImage();
+
+ public abstract Image getNotificationKindImage();
+
+ public Object getToken() {
+ return null;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/INotificationService.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/INotificationService.java
new file mode 100644
index 0000000..dc607a7
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/INotificationService.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.notifications;
+
+import java.util.List;
+
+/**
+ * @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 {
+
+ public void notify(List<? extends AbstractNotification> notifications);
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSink.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSink.java
new file mode 100644
index 0000000..3694ff2
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSink.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.notifications;
+
+/**
+ * @author Steffen Pingel
+ */
+public abstract class NotificationSink {
+
+ public abstract void notify(NotificationSinkEvent event);
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSinkEvent.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSinkEvent.java
new file mode 100644
index 0000000..a328eaa
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/NotificationSinkEvent.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/Notifications.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/Notifications.java
new file mode 100644
index 0000000..d955c81
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/commons/ui/notifications/Notifications.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.notifications;
+
+import org.eclipse.mylyn.internal.commons.ui.notifications.NotificationsPlugin;
+
+/**
+ * @author Steffen Pingel
+ */
+public final class Notifications {
+
+ private Notifications() {
+ // do not instantiate
+ }
+
+ public static INotificationService getService() {
+ return NotificationsPlugin.getDefault().getService();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/Messages.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/Messages.java
new file mode 100644
index 0000000..7a5f257
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/Messages.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.commons.ui.notifications.messages"; //$NON-NLS-1$
+
+ public static String NotificationsPreferencesPage_Descriptions_Label;
+
+ public static String NotificationsPreferencesPage_Enable_Notifications_Text;
+
+ public static String NotificationsPreferencesPage_Events_Label;
+
+ public static String NotificationsPreferencesPage_Notifiers_Label;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationAction.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationAction.java
new file mode 100644
index 0000000..9876076
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationAction.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.mylyn.commons.ui.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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationCategory.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationCategory.java
new file mode 100644
index 0000000..a6c5797
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationCategory.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationElement.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationElement.java
new file mode 100644
index 0000000..795e32a
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationElement.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+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.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, NotificationsPlugin.ID_PLUGIN, NLS.bind(
+ "Extension {0} contributed by {1} does not specify id attribute", element.getNamespaceIdentifier(), //$NON-NLS-1$
+ getPluginId())); //NON-NLS-1$
+ } else if (label == null) {
+ return new Status(IStatus.ERROR, NotificationsPlugin.ID_PLUGIN, NLS.bind(
+ "Extension {0} contributed by {1} does not specify label attribute", //$NON-NLS-1$
+ element.getNamespaceIdentifier(), getPluginId())); //NON-NLS-1$
+ }
+ return Status.OK_STATUS;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationEvent.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationEvent.java
new file mode 100644
index 0000000..92527ed
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationEvent.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+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.mylyn.commons.ui.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.mylyn.commons.notifications.notifications"; //$NON-NLS-1$
+
+ private NotificationCategory category;
+
+ private boolean selected;
+
+ 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;
+ }
+
+ @Deprecated
+ public boolean isSelected() {
+ return selected;
+ }
+
+ @Deprecated
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationHandler.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationHandler.java
new file mode 100644
index 0000000..7aa94a7
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationHandler.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationModel.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationModel.java
new file mode 100644
index 0000000..4d10e90
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationModel.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.ui.IMemento;
+
+/**
+ * @author Steffen Pingel
+ * @author Torkild U. Resheim
+ */
+public class NotificationModel {
+
+ private boolean dirty;
+
+ private Map<String, NotificationHandler> handlerByEventId;
+
+ public NotificationModel(IMemento memento) {
+ initialize(memento);
+ }
+
+ void initialize(IMemento memento) {
+ 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);
+ }
+ }
+ if (memento != null) {
+ load(memento);
+ }
+ }
+
+ 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 isDirty() {
+ return dirty;
+ }
+
+ public boolean isSelected(NotificationEvent event) {
+ NotificationHandler handler = getOrCreateNotificationHandler(event);
+ for (NotificationAction action : handler.getActions()) {
+ if (action.isSelected()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Stores the selected state of events and sinks.
+ *
+ * @param memento
+ * the memento to store in.
+ */
+ public void save(IMemento memento) {
+ for (Entry<String, NotificationHandler> entry : handlerByEventId.entrySet()) {
+ IMemento event = memento.createChild("event"); //$NON-NLS-1$
+ event.putString("id", entry.getKey()); //$NON-NLS-1$
+ List<NotificationAction> actions = entry.getValue().getActions();
+ for (NotificationAction notificationAction : actions) {
+ IMemento action = event.createChild("action"); //$NON-NLS-1$
+ action.putBoolean("selected", notificationAction.isSelected()); //$NON-NLS-1$
+ action.putString("sink", notificationAction.getSinkDescriptor().getId()); //$NON-NLS-1$
+ }
+ }
+ setDirty(false);
+ }
+
+ /**
+ * Updates the notification model with selected states from the memento instance.
+ *
+ * @param memento
+ */
+ private void load(IMemento memento) {
+ Assert.isNotNull(memento);
+ for (IMemento mEvent : memento.getChildren("event")) { //$NON-NLS-1$
+ for (NotificationCategory category : getCategories()) {
+ for (NotificationEvent event : category.getEvents()) {
+ if (event.getId().equals(mEvent.getString("id"))) { //$NON-NLS-1$
+ NotificationHandler handler = getOrCreateNotificationHandler(event);
+ List<NotificationAction> actions = handler.getActions();
+ for (NotificationAction notificationAction : actions) {
+ IMemento[] mActions = mEvent.getChildren("action"); //$NON-NLS-1$
+ for (IMemento mAction : mActions) {
+ if (notificationAction.getSinkDescriptor().getId().equals(mAction.getString("sink"))) { //$NON-NLS-1$
+ notificationAction.setSelected(mAction.getBoolean("selected")); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
+ /**
+ * Updates the state of the notification handlers depending on their child notification action states.
+ */
+ @Deprecated
+ public void updateStates() {
+ Collection<NotificationHandler> handlers = handlerByEventId.values();
+ for (NotificationHandler notificationHandler : handlers) {
+ List<NotificationAction> actions = notificationHandler.getActions();
+ boolean selected = false;
+ for (NotificationAction notificationAction : actions) {
+ if (notificationAction.isSelected()) {
+ selected = true;
+ break;
+ }
+ }
+ notificationHandler.getEvent().setSelected(selected);
+ }
+ }
+
+ public void setNotificationHandler(String eventId, NotificationHandler handler) {
+ handlerByEventId.put(eventId, handler);
+ setDirty(true);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationService.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationService.java
new file mode 100644
index 0000000..3e57558
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationService.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+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.mylyn.commons.core.StatusHandler;
+import org.eclipse.mylyn.commons.ui.notifications.AbstractNotification;
+import org.eclipse.mylyn.commons.ui.notifications.INotificationService;
+import org.eclipse.mylyn.commons.ui.notifications.NotificationSink;
+import org.eclipse.mylyn.commons.ui.notifications.NotificationSinkEvent;
+
+/**
+ * @author Steffen Pingel
+ * @author Torkild U. Resheim
+ */
+public class NotificationService implements INotificationService {
+
+ public NotificationService() {
+ }
+
+ /**
+ * Notify sinks about the.
+ */
+ public void notify(List<? extends AbstractNotification> notifications) {
+ // Return if notifications are not globally enabled.
+ if (!NotificationsPlugin.getDefault()
+ .getPreferenceStore()
+ .getBoolean(NotificationsPlugin.PREF_NOTICATIONS_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 = NotificationsPlugin.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() {
+ public void handleException(Throwable e) {
+ StatusHandler.log(new Status(IStatus.WARNING, NotificationsPlugin.ID_PLUGIN, "Sink failed: " //$NON-NLS-1$
+ + sink.getClass(), e));
+ }
+
+ public void run() throws Exception {
+ sink.notify(event);
+ }
+ });
+ }
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationSinkDescriptor.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationSinkDescriptor.java
new file mode 100644
index 0000000..0678424
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationSinkDescriptor.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.commons.ui.notifications.NotificationSink;
+import org.eclipse.osgi.util.NLS;
+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;
+ } else {
+ status = new Status(IStatus.ERROR, NotificationsPlugin.ID_PLUGIN, 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, NotificationsPlugin.ID_PLUGIN, 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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsExtensionReader.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsExtensionReader.java
new file mode 100644
index 0000000..b0b1a0a
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsExtensionReader.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+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.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(NotificationsPlugin.ID_PLUGIN, 0,
+ "Notifcation extensions failed to load", null); //$NON-NLS-1$
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint repositoriesExtensionPoint = registry.getExtensionPoint(NotificationsPlugin.ID_PLUGIN
+ + ".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,
+ NotificationsPlugin.ID_PLUGIN,
+ 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(NotificationsPlugin.ID_PLUGIN, 0,
+ "Notifcation extensions failed to load", null); //$NON-NLS-1$
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint repositoriesExtensionPoint = registry.getExtensionPoint(NotificationsPlugin.ID_PLUGIN
+ + ".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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPlugin.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPlugin.java
new file mode 100644
index 0000000..4325346
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPlugin.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NotificationsPlugin extends AbstractUIPlugin {
+
+ public static final String ID_PLUGIN = "org.eclipse.mylyn.commons.notifications"; //$NON-NLS-1$
+
+ public static final String PREF_NOTICATIONS_ENABLED = "notifications.enabled"; //$NON-NLS-1$
+
+ private static NotificationsPlugin instance;
+
+ public static NotificationsPlugin getDefault() {
+ return instance;
+ }
+
+ private NotificationModel model;
+
+ private NotificationService service;
+
+ public NotificationModel createModelWorkingCopy() {
+ IMemento memento = null;
+ File file = getModelFile().toFile();
+ if (file.exists()) {
+ try {
+ FileReader reader = new FileReader(file);
+ try {
+ memento = XMLMemento.createReadRoot(reader);
+ } finally {
+ reader.close();
+ }
+ } catch (IOException e) {
+ getLog().log(new Status(IStatus.ERROR, ID_PLUGIN, "Unexpected error restoring notification state", e)); //$NON-NLS-1$
+ } catch (WorkbenchException e) {
+ getLog().log(new Status(IStatus.ERROR, ID_PLUGIN, "Unexpected error restoring notification state", e)); //$NON-NLS-1$
+ }
+ }
+ return new NotificationModel(memento);
+ }
+
+ public NotificationModel getModel() {
+ if (model == null) {
+ model = createModelWorkingCopy();
+ }
+ return model;
+ }
+
+ public NotificationService getService() {
+ if (service == null) {
+ service = new NotificationService();
+ }
+ return service;
+ }
+
+ public void saveModel() {
+ if (model != null && model.isDirty()) {
+ save(model);
+ }
+ }
+
+ public void saveWorkingCopy(NotificationModel workingCopy) {
+ XMLMemento memento = save(workingCopy);
+ if (this.model != null) {
+ // reload model
+ this.model.initialize(memento);
+ }
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ instance = this;
+ super.start(context);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ instance = null;
+ }
+
+ private XMLMemento save(NotificationModel model) {
+ XMLMemento memento = XMLMemento.createWriteRoot("notifications"); //$NON-NLS-1$
+ model.save(memento);
+ FileWriter writer;
+ try {
+ writer = new FileWriter(getModelFile().toFile());
+ try {
+ memento.save(writer);
+ } finally {
+ writer.close();
+ }
+ } catch (IOException e) {
+ getLog().log(new Status(IStatus.ERROR, ID_PLUGIN, "Unexpected error saving notification state", e)); //$NON-NLS-1$
+ }
+ return memento;
+ }
+
+ protected IPath getModelFile() {
+ IPath stateLocation = Platform.getStateLocation(getBundle());
+ IPath cacheFile = stateLocation.append("notifications.xml"); //$NON-NLS-1$
+ return cacheFile;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesInitializer.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesInitializer.java
new file mode 100644
index 0000000..299a202
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesInitializer.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NotificationsPreferencesInitializer extends AbstractPreferenceInitializer {
+
+ public NotificationsPreferencesInitializer() {
+ // ignore
+ }
+
+ @Override
+ public void initializeDefaultPreferences() {
+ IPreferenceStore preferencesStore = NotificationsPlugin.getDefault().getPreferenceStore();
+ preferencesStore.setDefault(NotificationsPlugin.PREF_NOTICATIONS_ENABLED, true);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesPage.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesPage.java
new file mode 100644
index 0000000..82d4e54
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/NotificationsPreferencesPage.java
@@ -0,0 +1,406 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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 329897 select event type on open if available
+ * Itema AS - bug 330064 notification filtering and model persistence
+ * Itema AS - bug 331424 handle default event-sink action associations
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.commons.ui.notifications;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.IElementComparer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages;
+import org.eclipse.mylyn.internal.provisional.commons.ui.SubstringPatternFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.dialogs.FilteredTree;
+
+/**
+ * @author Steffen Pingel
+ * @author Torkild Ulvøy Resheim
+ */
+public class NotificationsPreferencesPage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ /**
+ * We need this in order to make sure that the correct element is selected in the {@link TreeViewer} when the
+ * selection is set.
+ *
+ * @author Torkild Ulvøy Resheim
+ */
+ public class NotificationEventComparer implements IElementComparer {
+
+ public boolean equals(Object a, Object b) {
+ if (a instanceof NotificationEvent && b instanceof NotificationEvent) {
+ String idA = ((NotificationEvent) a).getId();
+ String idB = ((NotificationEvent) b).getId();
+ return (idA.equals(idB));
+ }
+ return a.equals(b);
+ }
+
+ public int hashCode(Object element) {
+ return element.hashCode();
+ }
+
+ }
+
+ private static final Object[] EMPTY = new Object[0];
+
+ private final class EventContentProvider implements ITreeContentProvider {
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // ignore
+ }
+
+ public void dispose() {
+ // ignore
+ }
+
+ public boolean hasChildren(Object element) {
+ if (element instanceof NotificationCategory) {
+ return ((NotificationCategory) element).getEvents().size() > 0;
+ }
+ return false;
+ }
+
+ public Object getParent(Object element) {
+ if (element instanceof NotificationEvent) {
+ return ((NotificationEvent) element).getCategory();
+ }
+ return null;
+ }
+
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof Object[]) {
+ return (Object[]) inputElement;
+ } else {
+ return EMPTY;
+ }
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof NotificationCategory) {
+ return ((NotificationCategory) parentElement).getEvents().toArray();
+ }
+ return EMPTY;
+ }
+
+ }
+
+ private final class NotifiersContentProvider implements IStructuredContentProvider {
+
+ private NotificationHandler handler;
+
+ public void dispose() {
+ // ignore
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ if (newInput instanceof NotificationHandler) {
+ handler = (NotificationHandler) newInput;
+ } else {
+ handler = null;
+ }
+ }
+
+ public Object[] getElements(Object inputElement) {
+ if (handler != null) {
+ return handler.getActions().toArray();
+ } else {
+ return EMPTY;
+ }
+ }
+
+ }
+
+ public final class EventLabelProvider extends LabelProvider {
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof NotificationElement) {
+ NotificationElement item = (NotificationElement) element;
+ return item.getLabel();
+ }
+ return super.getText(element);
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ if (element instanceof NotificationEvent) {
+ NotificationEvent item = (NotificationEvent) element;
+ if (model.isSelected(item)) {
+ return CommonImages.getImage(CommonImages.CHECKED);
+ } else {
+ return null;
+ }
+ }
+ if (element instanceof NotificationElement) {
+ NotificationElement item = (NotificationElement) element;
+ ImageDescriptor imageDescriptor = item.getImageDescriptor();
+ if (imageDescriptor != null) {
+ return CommonImages.getImage(imageDescriptor);
+ }
+ }
+ return super.getImage(element);
+ }
+ }
+
+ private TreeViewer eventsViewer;
+
+ private CheckboxTableViewer notifiersViewer;
+
+ private Button enableNotificationsButton;
+
+ private NotificationModel model;
+
+ private Text descriptionText;
+
+ public NotificationsPreferencesPage() {
+ }
+
+ @Override
+ public IPreferenceStore getPreferenceStore() {
+ return NotificationsPlugin.getDefault().getPreferenceStore();
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ model = NotificationsPlugin.getDefault().createModelWorkingCopy();
+
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+
+ enableNotificationsButton = new Button(composite, SWT.CHECK);
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(enableNotificationsButton);
+ enableNotificationsButton.setText(Messages.NotificationsPreferencesPage_Enable_Notifications_Text);
+ enableNotificationsButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateEnablement();
+ }
+ });
+
+ Label label = new Label(composite, SWT.NONE);
+ label.setText(" "); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(label);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.NotificationsPreferencesPage_Events_Label);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.NotificationsPreferencesPage_Notifiers_Label);
+ // Create the tree showing all the various notification types
+ FilteredTree tree = new FilteredTree(composite, SWT.BORDER, new SubstringPatternFilter(), true);
+ eventsViewer = tree.getViewer();
+ GridDataFactory.fillDefaults().span(1, 2).grab(false, true).applyTo(tree);
+ eventsViewer.setComparer(new NotificationEventComparer());
+ eventsViewer.setContentProvider(new EventContentProvider());
+ eventsViewer.setLabelProvider(new EventLabelProvider());
+ eventsViewer.setInput(model.getCategories().toArray());
+ eventsViewer.expandAll();
+ eventsViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ Object input = getDetailsInput((IStructuredSelection) event.getSelection());
+ notifiersViewer.setInput(input);
+
+ Object item = ((IStructuredSelection) event.getSelection()).getFirstElement();
+ if (item instanceof NotificationEvent) {
+ descriptionText.setText(((NotificationEvent) item).getDescription());
+ notifiersViewer.getControl().setEnabled(true);
+ } else {
+ descriptionText.setText(" "); //$NON-NLS-1$
+ notifiersViewer.getControl().setEnabled(false);
+ }
+ }
+
+ private Object getDetailsInput(IStructuredSelection selection) {
+ Object item = selection.getFirstElement();
+ if (item instanceof NotificationEvent) {
+ return model.getOrCreateNotificationHandler((NotificationEvent) item);
+ }
+ return null;
+ }
+ });
+ // Create the table listing all notification sinks available for the selected event type.
+ notifiersViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(notifiersViewer.getControl());
+ notifiersViewer.setContentProvider(new NotifiersContentProvider());
+ notifiersViewer.setLabelProvider(new EventLabelProvider());
+ notifiersViewer.addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ NotificationAction action = (NotificationAction) event.getElement();
+ action.setSelected(event.getChecked());
+ model.setDirty(true);
+ eventsViewer.refresh();
+ }
+ });
+ notifiersViewer.setCheckStateProvider(new ICheckStateProvider() {
+ public boolean isChecked(Object element) {
+ return ((NotificationAction) element).isSelected();
+ }
+
+ public boolean isGrayed(Object element) {
+ return false;
+ }
+ });
+ notifiersViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ Object item = ((IStructuredSelection) event.getSelection()).getFirstElement();
+ if (item instanceof NotificationAction) {
+ // TODO show configuration pane
+ }
+ }
+ });
+
+ Group group = new Group(composite, SWT.NONE);
+ GridDataFactory.fillDefaults().hint(150, SWT.DEFAULT).grab(true, true).applyTo(group);
+ group.setText(Messages.NotificationsPreferencesPage_Descriptions_Label);
+ FillLayout layout = new FillLayout();
+ layout.marginHeight = 5;
+ layout.marginWidth = 5;
+ group.setLayout(layout);
+
+ descriptionText = new Text(group, SWT.WRAP);
+ descriptionText.setBackground(group.getBackground());
+
+// Button testButton = new Button(composite, SWT.NONE);
+// testButton.setText("Test");
+// testButton.addSelectionListener(new SelectionAdapter() {
+// @Override
+// public void widgetSelected(SelectionEvent e) {
+// ISelection selection = eventsViewer.getSelection();
+// if (selection instanceof IStructuredSelection) {
+// Object object = ((IStructuredSelection) selection).getFirstElement();
+// if (object instanceof NotificationEvent) {
+// final NotificationEvent event = (NotificationEvent) object;
+// getControl().getDisplay().asyncExec(new Runnable() {
+// public void run() {
+// Notifications.getService().notify(
+// Collections.singletonList(new TestNotification(event)));
+// }
+// });
+// }
+// }
+// }
+//
+// });
+
+ reset();
+ Dialog.applyDialogFont(composite);
+ return composite;
+ }
+
+ @Override
+ public void applyData(Object data) {
+ // We may or may not have a NotificationEvent supplied when this
+ // preference dialog is opened. If we do have this data we want to
+ // highlight the appropriate instance.
+ if (data instanceof String) {
+ String selectedEventId = (String) data;
+ Collection<NotificationCategory> items = model.getCategories();
+ NotificationEvent selectedEvent = null;
+ for (NotificationCategory notificationCategory : items) {
+ List<NotificationEvent> event = notificationCategory.getEvents();
+ for (NotificationEvent notificationEvent : event) {
+ if (notificationEvent.getId().equals(selectedEventId)) {
+ selectedEvent = notificationEvent;
+ break;
+ }
+ }
+ }
+ if (selectedEvent != null) {
+ eventsViewer.setSelection(new StructuredSelection(selectedEvent), true);
+ }
+ }
+ }
+
+ private void updateEnablement() {
+ boolean enabled = enableNotificationsButton.getSelection();
+ eventsViewer.getControl().setEnabled(enabled);
+ notifiersViewer.getControl().setEnabled(enabled);// FIXME enabled && notifiersViewer.getInput() != null);
+ descriptionText.setEnabled(enabled);
+ if (!enabled) {
+ eventsViewer.setSelection(StructuredSelection.EMPTY);
+ }
+ }
+
+ public void init(IWorkbench workbench) {
+ // ignore
+ }
+
+ public void reset() {
+ enableNotificationsButton.setSelection(getPreferenceStore().getBoolean(
+ NotificationsPlugin.PREF_NOTICATIONS_ENABLED));
+ updateEnablement();
+ }
+
+ @Override
+ public boolean performOk() {
+ getPreferenceStore().setValue(NotificationsPlugin.PREF_NOTICATIONS_ENABLED,
+ enableNotificationsButton.getSelection());
+ if (model.isDirty()) {
+ NotificationsPlugin.getDefault().saveWorkingCopy(model);
+ model.setDirty(false);
+ }
+ return super.performOk();
+ }
+
+ @Override
+ protected void performDefaults() {
+ enableNotificationsButton.setSelection(getPreferenceStore().getDefaultBoolean(
+ NotificationsPlugin.PREF_NOTICATIONS_ENABLED));
+ for (NotificationCategory category : model.getCategories()) {
+ for (NotificationEvent event : category.getEvents()) {
+ NotificationHandler handler = model.getOrCreateNotificationHandler(event);
+ for (NotificationAction action : handler.getActions()) {
+ action.setSelected(event.defaultHandledBySink(action.getSinkDescriptor().getId()));
+ }
+ }
+ }
+ // assume that the model has become dirty
+ model.setDirty(true);
+ // refresh UI
+ eventsViewer.refresh();
+ notifiersViewer.refresh();
+ updateEnablement();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/messages.properties b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/messages.properties
new file mode 100644
index 0000000..1b85c3c
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/messages.properties
@@ -0,0 +1,4 @@
+NotificationsPreferencesPage_Descriptions_Label=Description
+NotificationsPreferencesPage_Enable_Notifications_Text=&Enable notifications
+NotificationsPreferencesPage_Events_Label=Events:
+NotificationsPreferencesPage_Notifiers_Label=Notifiers:
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/Messages.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/Messages.java
new file mode 100644
index 0000000..f82bf60
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/Messages.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications.popup;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.commons.ui.notifications.popup.messages"; //$NON-NLS-1$
+
+ public static String PopupNotificationSink_Popup_Noifier_Job_Label;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/NotificationPopup.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/NotificationPopup.java
new file mode 100644
index 0000000..b16d44b
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/NotificationPopup.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications.popup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.mylyn.commons.ui.notifications.AbstractNotification;
+import org.eclipse.mylyn.internal.commons.ui.CommonsUiPlugin;
+import org.eclipse.mylyn.internal.provisional.commons.ui.AbstractNotificationPopup;
+import org.eclipse.mylyn.internal.provisional.commons.ui.CommonColors;
+import org.eclipse.mylyn.internal.provisional.commons.ui.CommonUiUtil;
+import org.eclipse.mylyn.internal.provisional.commons.ui.ScalingHyperlink;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+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;
+
+ private List<AbstractNotification> notifications;
+
+ public NotificationPopup(Shell parent) {
+ super(parent.getDisplay());
+ }
+
+ @Override
+ protected void createContentArea(Composite parent) {
+ 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());
+ notificationLabelIcon.setImage(notification.getNotificationKindImage());
+ // FIXME
+// if (!(notification instanceof TaskListNotificationReminder)) {
+// final AbstractTask task = (AbstractTask) notification.getAdapter(AbstractTask.class);
+// if (task != null) {
+// notificationLabelIcon.addMouseListener(new MouseAdapter() {
+// @Override
+// public void mouseUp(MouseEvent e) {
+// TasksUiPlugin.getTaskDataManager().setTaskRead(task, true);
+// notificationLabelIcon.setImage(null);
+// notificationLabelIcon.setToolTipText(null);
+// }
+// });
+// notificationLabelIcon.setToolTipText(Messages.TaskListNotificationPopup_Mark_Task_Read);
+// }
+// }
+
+ // FIXME
+// final TaskScalingHyperlink itemLink = new TaskScalingHyperlink(notificationComposite, SWT.BEGINNING
+// | SWT.NO_FOCUS);
+
+ 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(CommonColors.HYPERLINK_WIDGET);
+ itemLink.registerMouseTrackListener();
+ itemLink.setText(CommonUiUtil.toLabel(notification.getLabel()));
+ itemLink.setImage(notification.getNotificationImage());
+ itemLink.setBackground(parent.getBackground());
+ itemLink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ 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(CommonUiUtil.toLabel(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(CommonColors.HYPERLINK_WIDGET);
+ remainingLink.registerMouseTrackListener();
+ remainingLink.setBackground(parent.getBackground());
+
+ remainingLink.setText(NLS.bind("{0} more", numNotificationsRemain)); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().span(2, SWT.DEFAULT).applyTo(remainingLink);
+ remainingLink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ // FIXME
+ // TasksUiUtil.openTasksViewInActivePerspective().setFocus();
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ Shell windowShell = window.getShell();
+ if (windowShell != null) {
+ windowShell.setMaximized(true);
+ windowShell.open();
+ }
+ }
+ }
+ });
+ break;
+ }
+ count++;
+ }
+ }
+
+ @Override
+ protected void createTitleArea(Composite parent) {
+ super.createTitleArea(parent);
+ }
+
+ public List<AbstractNotification> getNotifications() {
+ return new ArrayList<AbstractNotification>(notifications);
+ }
+
+ @Override
+ protected Color getTitleForeground() {
+ return CommonsUiPlugin.getDefault().getFormColors(Display.getDefault()).getColor(IFormColors.TITLE);
+
+ }
+
+ public void setContents(List<AbstractNotification> notifications) {
+ this.notifications = notifications;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/PopupNotificationSink.java b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/PopupNotificationSink.java
new file mode 100644
index 0000000..785ba85
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/PopupNotificationSink.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.notifications.popup;
+
+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.mylyn.commons.ui.notifications.AbstractNotification;
+import org.eclipse.mylyn.commons.ui.notifications.NotificationSink;
+import org.eclipse.mylyn.commons.ui.notifications.NotificationSinkEvent;
+import org.eclipse.swt.widgets.Shell;
+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;
+
+ private final WeakHashMap<Object, Object> cancelledTokens = new WeakHashMap<Object, Object>();
+
+ private final Set<AbstractNotification> notifications = new HashSet<AbstractNotification>();
+
+ private final Set<AbstractNotification> currentlyNotifying = Collections.synchronizedSet(notifications);
+
+ private final Job openJob = new Job(Messages.PopupNotificationSink_Popup_Noifier_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() {
+
+ 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) {
+// popup.close();
+ showPopup();
+ }
+ }
+ }
+ });
+ }
+ } finally {
+ if (popup != null) {
+ schedule(popup.getDelayClose() / 2);
+ }
+ }
+
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ };
+
+ private NotificationPopup popup;
+
+ public PopupNotificationSink() {
+ }
+
+ 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.setSystem(runSystem);
+ 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/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/messages.properties b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/messages.properties
new file mode 100644
index 0000000..5ac2c06
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.notifications/src/org/eclipse/mylyn/internal/commons/ui/notifications/popup/messages.properties
@@ -0,0 +1 @@
+PopupNotificationSink_Popup_Noifier_Job_Label=Popup Notifier
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/.project b/stubs/org.eclipse.mylyn.commons.repositories/.project
index 7a9c8a1..143c958 100644
--- a/stubs/org.eclipse.mylyn.commons.repositories/.project
+++ b/stubs/org.eclipse.mylyn.commons.repositories/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.mylyn.commons.repositories</name>
+ <name>org.eclipse.mylyn.commons.repositories-stub</name>
<comment></comment>
<projects>
</projects>
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/META-INF/MANIFEST.MF b/stubs/org.eclipse.mylyn.commons.repositories/META-INF/MANIFEST.MF
index 5153187..795dc26 100644
--- a/stubs/org.eclipse.mylyn.commons.repositories/META-INF/MANIFEST.MF
+++ b/stubs/org.eclipse.mylyn.commons.repositories/META-INF/MANIFEST.MF
@@ -2,8 +2,15 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.mylyn.commons.repositories;singleton:=true
-Bundle-Version: 0.9.0.v20111206-0100
+Bundle-Version: 0.9.0.v20120225-0100
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: org.eclipse.mylyn.commons.repositories;x-internal:=true,
+ org.eclipse.mylyn.commons.repositories.auth;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.repositories;x-internal:=true
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.equinox.security,
+ org.eclipse.mylyn.commons.core,
+ org.eclipse.mylyn.commons.net;bundle-version="3.5.0"
Bundle-ClassPath: .
Bundle-Localization: plugin
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/pom.xml b/stubs/org.eclipse.mylyn.commons.repositories/pom.xml
index d8643b6..54f135e 100644
--- a/stubs/org.eclipse.mylyn.commons.repositories/pom.xml
+++ b/stubs/org.eclipse.mylyn.commons.repositories/pom.xml
@@ -8,7 +8,7 @@
<version>3.7.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.mylyn.commons.repositories</artifactId>
- <version>0.9.0.v20111206-0100</version>
+ <version>0.9.0.v20120225-0100</version>
<packaging>eclipse-plugin</packaging>
<build>
<plugins>
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/.placehoder b/stubs/org.eclipse.mylyn.commons.repositories/src/.placehoder
deleted file mode 100644
index e69de29..0000000
--- a/stubs/org.eclipse.mylyn.commons.repositories/src/.placehoder
+++ /dev/null
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/ILocationService.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/ILocationService.java
new file mode 100644
index 0000000..1988c03
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/ILocationService.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories;
+
+import java.net.Proxy;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationType;
+import org.eclipse.mylyn.commons.repositories.auth.ICredentialsStore;
+
+/**
+ * @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 ILocationService {
+
+ // FIXME replace with 3.5 proxy API
+ public abstract Proxy getProxyForHost(String host, String proxyType);
+
+ public abstract X509TrustManager getTrustManager();
+
+ public abstract <T extends AuthenticationCredentials> T requestCredentials(AuthenticationType type,
+ Class<T> credentialsKind, String message, IProgressMonitor monitor);
+
+ public ICredentialsStore getCredentialsStore(String id);
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryCategory.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryCategory.java
new file mode 100644
index 0000000..0aa6bb0
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryCategory.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories;
+
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Categories to group repositories of the same kind, e.g. Tasks, Builds or Reviews.
+ *
+ * @author Robert Elves
+ */
+public class RepositoryCategory extends PlatformObject {
+
+ private final String id;
+
+ private final String label;
+
+ private final int rank;
+
+ public static final String ID_CATEGORY_BUGS = "org.eclipse.mylyn.category.bugs"; //$NON-NLS-1$
+
+ public static final String ID_CATEGORY_BUILDS = "org.eclipse.mylyn.category.build"; //$NON-NLS-1$
+
+ public static final String ID_CATEGORY_OTHER = "org.eclipse.mylyn.category.other"; //$NON-NLS-1$
+
+ public static final String ID_CATEGORY_REVIEWS = "org.eclipse.mylyn.category.review"; //$NON-NLS-1$
+
+ public static final String ID_CATEGORY_TASKS = "org.eclipse.mylyn.category.tasks"; //$NON-NLS-1$
+
+ public static final String ID_CATEGORY_ALL = "org.eclipse.mylyn.category.all"; //$NON-NLS-1$
+
+ public static final String ID_CATEGORY_ROOT = "org.eclipse.mylyn.category.root"; //$NON-NLS-1$
+
+ public RepositoryCategory(String id, String label, int rank) {
+ this.id = id;
+ this.label = label;
+ this.rank = rank;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int compareTo(Object arg0) {
+ if (arg0 instanceof RepositoryCategory) {
+ return this.getRank() - ((RepositoryCategory) arg0).getRank();
+ }
+ return 0;
+ }
+
+ public int getRank() {
+ return rank;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ @Override
+ public String toString() {
+ return getLabel();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryLocation.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryLocation.java
new file mode 100644
index 0000000..fbe7c71
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryLocation.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationType;
+import org.eclipse.mylyn.commons.repositories.auth.ICredentialsStore;
+import org.eclipse.mylyn.internal.commons.repositories.CredentialsFactory;
+import org.eclipse.mylyn.internal.commons.repositories.InMemoryCredentialsStore;
+import org.eclipse.mylyn.internal.commons.repositories.LocationService;
+
+/**
+ * @author Steffen Pingel
+ */
+public class RepositoryLocation extends PlatformObject {
+
+ private static final String AUTH_HTTP = "org.eclipse.mylyn.tasklist.repositories.httpauth"; //$NON-NLS-1$
+
+ private static final String AUTH_PROXY = "org.eclipse.mylyn.tasklist.repositories.proxy"; //$NON-NLS-1$
+
+ private static final String AUTH_REPOSITORY = "org.eclipse.mylyn.tasklist.repositories"; //$NON-NLS-1$
+
+ private static final String ENABLED = ".enabled"; //$NON-NLS-1$
+
+ private static final String ID_PLUGIN = "org.eclipse.mylyn.commons.repository"; //$NON-NLS-1$
+
+ public static final String PROPERTY_CATEGORY = "category"; //$NON-NLS-1$
+
+ public static final String PROPERTY_ENCODING = "encoding"; //$NON-NLS-1$
+
+ public static final String PROPERTY_ID = "id"; //$NON-NLS-1$
+
+ public static final String PROPERTY_LABEL = "label"; //$NON-NLS-1$
+
+ public static final String PROPERTY_OFFLINE = "org.eclipse.mylyn.tasklist.repositories.offline"; //$NON-NLS-1$
+
+ public static final String PROPERTY_TIMEZONE = "timezone"; //$NON-NLS-1$
+
+ public static final String PROPERTY_URL = "url"; //$NON-NLS-1$
+
+ public static final String PROPERTY_USERNAME = "org.eclipse.mylyn.repositories.username"; //$NON-NLS-1$
+
+ public static final String PROPERTY_PROXY_HOST = "org.eclipse.mylyn.repositories.proxy.host"; //$NON-NLS-1$
+
+ public static final String PROPERTY_PROXY_PORT = "org.eclipse.mylyn.repositories.proxy.port"; //$NON-NLS-1$
+
+ public static final String PROPERTY_PROXY_USEDEFAULT = "org.eclipse.mylyn.repositories.proxy.usedefault"; //$NON-NLS-1$
+
+ private static final String SAVE_PASSWORD = ".savePassword"; //$NON-NLS-1$
+
+ private static final String USERNAME = ".username"; //$NON-NLS-1$
+
+ private static String getKeyPrefix(AuthenticationType type) {
+ switch (type) {
+ case HTTP:
+ return AUTH_HTTP;
+ case PROXY:
+ return AUTH_PROXY;
+ case REPOSITORY:
+ return AUTH_REPOSITORY;
+ }
+ throw new IllegalArgumentException("Unknown authentication type: " + type); //$NON-NLS-1$
+ }
+
+ private String cachedUserName;
+
+ private ICredentialsStore credentialsStore;
+
+ // transient
+ private IStatus errorStatus = null;
+
+ private boolean isCachedUserName;
+
+ private final Map<String, String> properties = new LinkedHashMap<String, String>();
+
+ private final Set<PropertyChangeListener> propertyChangeListeners = new HashSet<PropertyChangeListener>();
+
+ private ILocationService service;
+
+ private boolean workingCopy;
+
+ public RepositoryLocation() {
+ this.service = LocationService.getDefault();
+ }
+
+ public RepositoryLocation(Map<String, String> properties) {
+ this.properties.putAll(properties);
+ this.workingCopy = true;
+ this.service = LocationService.getDefault();
+ }
+
+ public RepositoryLocation(RepositoryLocation source) {
+ this.properties.putAll(source.properties);
+ this.workingCopy = true;
+ this.service = source.getService();
+ }
+
+ public void addChangeListener(PropertyChangeListener listener) {
+ propertyChangeListeners.add(listener);
+ }
+
+ public void clearCredentials() {
+ getCredentialsStore().clear();
+ }
+
+ public <T extends AuthenticationCredentials> T getCredentials(AuthenticationType authType, Class<T> credentialsKind) {
+ String prefix = getKeyPrefix(authType);
+ if (getBooleanPropery(prefix + ENABLED)) {
+ if (getId() == null) {
+ // can't determine location of credentials
+ return null;
+ }
+ try {
+ return CredentialsFactory.create(credentialsKind, getCredentialsStore(), prefix);
+ } catch (StorageException e) {
+ // FIXME
+ }
+ }
+ return null;
+ }
+
+ public ICredentialsStore getCredentialsStore() {
+ if (credentialsStore == null) {
+ return getService().getCredentialsStore(getId());
+ }
+ return credentialsStore;
+ }
+
+ public String getId() {
+ String id = getProperty(PROPERTY_ID);
+ if (id == null) {
+ throw new IllegalStateException("Repository ID is not set"); //$NON-NLS-1$
+ }
+ return id;
+ }
+
+ public Map<String, String> getProperties() {
+ return new LinkedHashMap<String, String>(this.properties);
+ }
+
+ public String getProperty(String name) {
+ return this.properties.get(name);
+ }
+
+ /**
+ * @return the URL if the label property is not set
+ */
+ public String getLabel() {
+ String label = properties.get(PROPERTY_LABEL);
+ if (label != null && label.length() > 0) {
+ return label;
+ } else {
+ return getUrl();
+ }
+ }
+
+ /**
+ * @since 3.0
+ */
+ public boolean getSavePassword(AuthenticationType authType) {
+ return getBooleanPropery(getKeyPrefix(authType) + SAVE_PASSWORD);
+ }
+
+ public boolean getBooleanPropery(String key) {
+ String value = getProperty(key);
+ return value != null && Boolean.parseBoolean(value);
+ }
+
+ public ILocationService getService() {
+ return service;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public IStatus getStatus() {
+ return errorStatus;
+ }
+
+ public String getUrl() {
+ return getProperty(PROPERTY_URL);
+ }
+
+ /**
+ * The username is cached since it needs to be retrieved frequently (e.g. for Task List decoration).
+ */
+ public String getUserName() {
+ return getProperty(PROPERTY_USERNAME);
+ }
+
+ public void setUserName(String userName) {
+ setProperty(PROPERTY_USERNAME, userName);
+ }
+
+ private void handlePropertyChange(String key, Object old, Object value) {
+ if (PROPERTY_ID.equals(key)) {
+ credentialsStore = null;
+ }
+
+ PropertyChangeEvent event = new PropertyChangeEvent(this, key, old, value);
+ for (PropertyChangeListener listener : propertyChangeListeners) {
+ listener.propertyChange(event);
+ }
+ }
+
+ private boolean hasChanged(Object oldValue, Object newValue) {
+ return oldValue != null && !oldValue.equals(newValue) || oldValue == null && newValue != null;
+ }
+
+ public boolean hasProperty(String name) {
+ String value = getProperty(name);
+ return value != null && value.trim().length() > 0;
+ }
+
+ public boolean isOffline() {
+ return Boolean.parseBoolean(getProperty(PROPERTY_OFFLINE));
+ }
+
+ public boolean isWorkingCopy() {
+ return workingCopy;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void removeChangeListener(PropertyChangeListener listener) {
+ propertyChangeListeners.remove(listener);
+ }
+
+ public void removeProperty(String key) {
+ setProperty(key, null);
+ }
+
+ public <T extends AuthenticationCredentials> void setCredentials(AuthenticationType authType, T credentials) {
+ String prefix = getKeyPrefix(authType);
+
+ if (credentials == null) {
+ if (authType == AuthenticationType.REPOSITORY) {
+ cachedUserName = null;
+ }
+ setProperty(prefix + ENABLED, String.valueOf(false));
+ } else {
+ setProperty(prefix + ENABLED, String.valueOf(true));
+ try {
+ credentials.save(getCredentialsStore(), prefix);
+ } catch (StorageException e) {
+ // FIXME
+ }
+ }
+ }
+
+ public void setCredentialsStore(ICredentialsStore credentialsStore) {
+ this.credentialsStore = credentialsStore;
+ }
+
+ public void setLabel(String label) {
+ setProperty(PROPERTY_LABEL, label);
+ }
+
+ public void setOffline(boolean offline) {
+ properties.put(PROPERTY_OFFLINE, String.valueOf(offline));
+ }
+
+ public void setProperty(String key, String newValue) {
+ Assert.isNotNull(key);
+ String oldValue = this.properties.get(key);
+ if (hasChanged(oldValue, newValue)) {
+ this.properties.put(key.intern(), (newValue != null) ? newValue.intern() : null);
+ handlePropertyChange(key, oldValue, newValue);
+ }
+ }
+
+ public void setService(ILocationService service) {
+ this.service = service;
+ }
+
+ public void setStatus(IStatus errorStatus) {
+ this.errorStatus = errorStatus;
+ }
+
+ @Override
+ public String toString() {
+ return getLabel();
+ }
+
+ public void apply(RepositoryLocation location) {
+ String oldId = getProperty(PROPERTY_ID);
+ ICredentialsStore oldCredentialsStore = null;
+ if (oldId != null) {
+ oldCredentialsStore = getCredentialsStore();
+ }
+
+ // merge properties
+ HashSet<String> removed = new HashSet<String>(properties.keySet());
+ removed.removeAll(location.properties.keySet());
+ for (Map.Entry<String, String> entry : location.properties.entrySet()) {
+ setProperty(entry.getKey(), entry.getValue());
+ }
+ for (String key : removed) {
+ setProperty(key, null);
+ }
+
+ String newId = getProperty(PROPERTY_ID);
+ if (newId != null) {
+ // migrate credentials if url has changed
+ ICredentialsStore newCredentialsStore = getCredentialsStore();
+ if (!newId.equals(oldId)) {
+ if (oldCredentialsStore != null) {
+ try {
+ oldCredentialsStore.copyTo(newCredentialsStore);
+ oldCredentialsStore.clear();
+ } catch (StorageException e) {
+ // FIXME
+ }
+ }
+ }
+
+ // merge credentials
+ if (location.getCredentialsStore() instanceof InMemoryCredentialsStore) {
+ try {
+ ((InMemoryCredentialsStore) location.getCredentialsStore()).copyTo(newCredentialsStore);
+ } catch (StorageException e) {
+ // FIXME
+ }
+ }
+ }
+
+ }
+
+ public void setIdPreservingCredentialsStore(String id) {
+ ICredentialsStore store = getCredentialsStore();
+ setProperty(RepositoryLocation.PROPERTY_ID, id);
+ if (this.credentialsStore == null) {
+ setCredentialsStore(store);
+ }
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryValidator.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryValidator.java
new file mode 100644
index 0000000..905caaa
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/RepositoryValidator.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * @author Steffen Pingel
+ */
+public abstract class RepositoryValidator {
+
+ private final RepositoryLocation location;
+
+ private IStatus result;
+
+ public RepositoryValidator(RepositoryLocation location) {
+ this.location = location;
+ }
+
+ public RepositoryLocation getLocation() {
+ return location;
+ }
+
+ public IStatus getResult() {
+ return result;
+ }
+
+ public abstract IStatus run(IProgressMonitor monitor);
+
+ public void setResult(IStatus result) {
+ this.result = result;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationCredentials.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationCredentials.java
new file mode 100644
index 0000000..d2ab0a4
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationCredentials.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories.auth;
+
+import org.eclipse.equinox.security.storage.StorageException;
+
+/**
+ * @author Steffen Pingel
+ */
+public abstract class AuthenticationCredentials {
+
+ public abstract void save(ICredentialsStore store, String prefix) throws StorageException;
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationType.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationType.java
new file mode 100644
index 0000000..05d3330
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/AuthenticationType.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories.auth;
+
+/**
+ * An enum of supported authentication types.
+ *
+ * @author Steffen Pingel
+ */
+public enum AuthenticationType {
+ /**
+ * HTTP authentication, this is typically basic authentication but other methods such as digest or NTLM are used as
+ * well.
+ */
+ HTTP,
+ /** Proxy authentication. */
+ PROXY,
+ /** Task repository authentication. */
+ REPOSITORY
+} \ No newline at end of file
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/ICredentialsStore.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/ICredentialsStore.java
new file mode 100644
index 0000000..05962ff
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/ICredentialsStore.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories.auth;
+
+import java.io.IOException;
+
+import org.eclipse.equinox.security.storage.StorageException;
+
+/**
+ * @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 ICredentialsStore {
+
+ public void clear();
+
+ public void flush() throws IOException;
+
+ public String get(String key, String def) throws StorageException;
+
+ public byte[] getByteArray(String key, byte[] def) throws StorageException;
+
+ public String[] keys();
+
+ public void put(String key, String value, boolean encrypt) throws StorageException;
+
+ public void putByteArray(String key, byte[] value, boolean encrypt) throws StorageException;
+
+ public void remove(String key);
+
+ public void copyTo(ICredentialsStore target) throws StorageException;
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/UsernamePasswordCredentials.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/UsernamePasswordCredentials.java
new file mode 100644
index 0000000..27b85bf
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/commons/repositories/auth/UsernamePasswordCredentials.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.repositories.auth;
+
+import org.eclipse.equinox.security.storage.StorageException;
+
+/**
+ * Provides a user name and password.
+ *
+ * @author Steffen Pingel
+ * @since 2.2
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class UsernamePasswordCredentials extends AuthenticationCredentials {
+
+ private final String userName;
+
+ private final String password;
+
+ /**
+ * @param userName
+ * the user name, must not be null
+ * @param password
+ * the password, must not be null
+ */
+ public UsernamePasswordCredentials(String userName, String password) {
+ if (userName == null) {
+ throw new IllegalArgumentException();
+ }
+ if (password == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.userName = userName;
+ this.password = password;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((password == null) ? 0 : password.hashCode());
+ result = prime * result + ((userName == null) ? 0 : userName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final UsernamePasswordCredentials other = (UsernamePasswordCredentials) obj;
+ if (password == null) {
+ if (other.password != null) {
+ return false;
+ }
+ } else if (!password.equals(other.password)) {
+ return false;
+ }
+ if (userName == null) {
+ if (other.userName != null) {
+ return false;
+ }
+ } else if (!userName.equals(other.userName)) {
+ return false;
+ }
+ return true;
+ }
+
+ public static UsernamePasswordCredentials create(ICredentialsStore store, String prefix) throws StorageException {
+ String userName = store.get(prefix + ".user", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ String password = store.get(prefix + ".password", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ return new UsernamePasswordCredentials(userName, password);
+ }
+
+ @Override
+ public void save(ICredentialsStore store, String prefix) throws StorageException {
+ store.put(prefix + ".user", userName, false); //$NON-NLS-1$
+ store.put(prefix + ".password", password, true); //$NON-NLS-1$
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/CredentialsFactory.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/CredentialsFactory.java
new file mode 100644
index 0000000..7412b63
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/CredentialsFactory.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.repositories;
+
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.repositories.auth.ICredentialsStore;
+import org.eclipse.mylyn.commons.repositories.auth.UsernamePasswordCredentials;
+
+/**
+ * Simple factory that creates {@link AuthenticationCredentials} objects.
+ *
+ * @author Steffen Pingel
+ */
+public class CredentialsFactory {
+
+ public static <T extends AuthenticationCredentials> T create(Class<T> credentialsKind,
+ ICredentialsStore credentialsStore, String key) throws StorageException {
+ if (credentialsKind == UsernamePasswordCredentials.class) {
+ return (T) UsernamePasswordCredentials.create(credentialsStore, key);
+ }
+ throw new IllegalArgumentException("Unknown credentials type: " + credentialsKind); //$NON-NLS-1$
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/InMemoryCredentialsStore.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/InMemoryCredentialsStore.java
new file mode 100644
index 0000000..69c692e
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/InMemoryCredentialsStore.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.repositories;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.mylyn.commons.repositories.auth.ICredentialsStore;
+
+/**
+ * @author Steffen Pingel
+ */
+public class InMemoryCredentialsStore implements ICredentialsStore {
+
+ private final ConcurrentHashMap<String, Object> store;
+
+ private final ICredentialsStore parent;
+
+ public InMemoryCredentialsStore(ICredentialsStore parent) {
+ this.parent = parent;
+ store = new ConcurrentHashMap<String, Object>();
+ }
+
+ public void clear() {
+ store.clear();
+ }
+
+ public void flush() throws IOException {
+ // does nothing
+ }
+
+ public String get(String key, String def) throws StorageException {
+ String value = (String) store.get(key);
+ if (value == null && parent != null) {
+ return parent.get(key, def);
+ }
+ return (value != null) ? value : def;
+ }
+
+ public byte[] getByteArray(String key, byte[] def) throws StorageException {
+ byte[] value = (byte[]) store.get(key);
+ if (value == null && parent != null) {
+ return parent.getByteArray(key, def);
+ }
+ return (value != null) ? value : def;
+ }
+
+ public String[] keys() {
+ return store.keySet().toArray(new String[0]);
+ }
+
+ public void put(String key, String value, boolean encrypt) throws StorageException {
+ store.put(key, value);
+ }
+
+ public void putByteArray(String key, byte[] value, boolean encrypt) throws StorageException {
+ store.put(key, value);
+ }
+
+ public void remove(String key) {
+ store.remove(key);
+ }
+
+ public void copyTo(ICredentialsStore target) throws StorageException {
+ for (Map.Entry<String, Object> entry : store.entrySet()) {
+ if (entry.getValue() instanceof String) {
+ target.put(entry.getKey(), (String) entry.getValue(), true);
+ } else if (entry.getValue() instanceof byte[]) {
+ target.putByteArray(entry.getKey(), (byte[]) entry.getValue(), true);
+ }
+ }
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/LocationService.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/LocationService.java
new file mode 100644
index 0000000..b6bc8f9
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/LocationService.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.repositories;
+
+import java.net.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylyn.commons.net.IProxyProvider;
+import org.eclipse.mylyn.commons.net.WebUtil;
+import org.eclipse.mylyn.commons.repositories.ILocationService;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationType;
+import org.eclipse.mylyn.commons.repositories.auth.ICredentialsStore;
+import org.eclipse.mylyn.commons.repositories.auth.UsernamePasswordCredentials;
+
+/**
+ * @author Steffen Pingel
+ */
+public class LocationService implements ILocationService {
+
+ public static final String ID_PLUGIN = "org.eclipse.mylyn.commons.repository"; //$NON-NLS-1$
+
+ private static LocationService instance = new LocationService(null, null, new PlatformProxyProvider());
+
+ public static LocationService getDefault() {
+ return instance;
+ }
+
+ private static class PlatformProxyProvider implements IProxyProvider {
+
+ public Proxy getProxyForHost(String host, String proxyType) {
+ return WebUtil.getProxy(host, proxyType);
+ }
+
+ }
+
+ private final Map<AuthenticationType, UsernamePasswordCredentials> credentialsByType;
+
+ private final IProxyProvider proxyProvider;
+
+ public LocationService(String username, String password, IProxyProvider proxyProvider) {
+ this.credentialsByType = new HashMap<AuthenticationType, UsernamePasswordCredentials>();
+ this.proxyProvider = proxyProvider;
+
+ if (username != null && password != null) {
+ setCredentials(AuthenticationType.REPOSITORY, username, password);
+ }
+ }
+
+// public LocationService(String url, String username, String password) {
+// this(url, username, password, new PlatformProxyProvider());
+// }
+//
+// public LocationService(String url) {
+// this(url, null, null, new PlatformProxyProvider());
+// }
+
+ public UsernamePasswordCredentials getCredentials(AuthenticationType authType) {
+ return credentialsByType.get(authType);
+ }
+
+ public Proxy getProxyForHost(String host, String proxyType) {
+ if (proxyProvider != null) {
+ return proxyProvider.getProxyForHost(host, proxyType);
+ }
+ return null;
+ }
+
+ public void setCredentials(AuthenticationType authType, String username, String password) {
+ credentialsByType.put(authType, new UsernamePasswordCredentials(username, password));
+ }
+
+ public X509TrustManager getTrustManager() {
+ // ignore
+ return null;
+ }
+
+ public <T extends AuthenticationCredentials> T requestCredentials(AuthenticationType type,
+ Class<T> credentialsKind, String message, IProgressMonitor monitor) {
+ throw new UnsupportedOperationException();
+ }
+
+ public ICredentialsStore getCredentialsStore(String id) {
+ return new SecureCredentialsStore(id);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/SecureCredentialsStore.java b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/SecureCredentialsStore.java
new file mode 100644
index 0000000..8b8d4ae
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.repositories/src/org/eclipse/mylyn/internal/commons/repositories/SecureCredentialsStore.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.repositories;
+
+import java.io.IOException;
+
+import org.eclipse.equinox.security.storage.EncodingUtils;
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.mylyn.commons.repositories.auth.ICredentialsStore;
+
+/**
+ * @author Steffen Pingel
+ */
+public class SecureCredentialsStore implements ICredentialsStore {
+
+ private static final String ID_PLUGIN = "org.eclipse.mylyn.commons.repository"; //$NON-NLS-1$
+
+ private final String url;
+
+ public SecureCredentialsStore(String url) {
+ this.url = url;
+ }
+
+ public void clear() {
+ //getSecurePreferences().clear();
+ getSecurePreferences().removeNode();
+ }
+
+ public void flush() throws IOException {
+ getSecurePreferences().flush();
+ }
+
+ public String get(String key, String def) throws StorageException {
+ return getSecurePreferences().get(key, def);
+ }
+
+ public byte[] getByteArray(String key, byte[] def) throws StorageException {
+ return getSecurePreferences().getByteArray(key, def);
+ }
+
+ private ISecurePreferences getSecurePreferences() {
+ ISecurePreferences securePreferences = SecurePreferencesFactory.getDefault().node(ID_PLUGIN);
+ securePreferences = securePreferences.node(EncodingUtils.encodeSlashes(getUrl()));
+ return securePreferences;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String[] keys() {
+ return getSecurePreferences().keys();
+ }
+
+ public void put(String key, String value, boolean encrypt) throws StorageException {
+ getSecurePreferences().put(key, value, encrypt);
+ }
+
+ public void putByteArray(String key, byte[] value, boolean encrypt) throws StorageException {
+ getSecurePreferences().putByteArray(key, value, encrypt);
+ }
+
+ public void remove(String key) {
+ getSecurePreferences().remove(key);
+ }
+
+ public void copyTo(ICredentialsStore target) throws StorageException {
+ ISecurePreferences preferences = getSecurePreferences();
+ for (String key : preferences.keys()) {
+ target.put(key, preferences.get(key, null), preferences.isEncrypted(key));
+ }
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/.project b/stubs/org.eclipse.mylyn.commons.team/.project
index fea2210..66ea0a7 100644
--- a/stubs/org.eclipse.mylyn.commons.team/.project
+++ b/stubs/org.eclipse.mylyn.commons.team/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.mylyn.commons.team</name>
+ <name>org.eclipse.mylyn.commons.team-stub</name>
<comment></comment>
<projects>
</projects>
diff --git a/stubs/org.eclipse.mylyn.commons.team/META-INF/MANIFEST.MF b/stubs/org.eclipse.mylyn.commons.team/META-INF/MANIFEST.MF
index 6e6bcf6..9ceca73 100644
--- a/stubs/org.eclipse.mylyn.commons.team/META-INF/MANIFEST.MF
+++ b/stubs/org.eclipse.mylyn.commons.team/META-INF/MANIFEST.MF
@@ -2,8 +2,23 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.mylyn.commons.team;singleton:=true
-Bundle-Version: 0.9.0.v20111206-0100
+Bundle-Version: 0.9.0.v20120225-0100
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ClassPath: .
Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.ui.forms,
+ org.eclipse.ui.navigator,
+ org.eclipse.ui.navigator.resources,
+ org.eclipse.core.databinding,
+ org.eclipse.core.databinding.beans,
+ org.eclipse.core.databinding.property;resolution:=optional,
+ org.eclipse.jface.databinding,
+ org.eclipse.mylyn.commons.repositories;bundle-version="0.1.0",
+ org.eclipse.mylyn.commons.ui;bundle-version="3.5.0"
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.mylyn.commons.ui.team;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.ui.team;x-internal:=true,
+ org.eclipse.mylyn.internal.commons.ui.team.wizards;x-internal:=true
diff --git a/stubs/org.eclipse.mylyn.commons.team/pom.xml b/stubs/org.eclipse.mylyn.commons.team/pom.xml
index 1cf415a..14af928 100644
--- a/stubs/org.eclipse.mylyn.commons.team/pom.xml
+++ b/stubs/org.eclipse.mylyn.commons.team/pom.xml
@@ -8,7 +8,7 @@
<version>3.7.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.mylyn.commons.team</artifactId>
- <version>0.9.0.v20111206-0100</version>
+ <version>0.9.0.v20120225-0100</version>
<packaging>eclipse-plugin</packaging>
<build>
<plugins>
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/.placehoder b/stubs/org.eclipse.mylyn.commons.team/src/.placehoder
deleted file mode 100644
index e69de29..0000000
--- a/stubs/org.eclipse.mylyn.commons.team/src/.placehoder
+++ /dev/null
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/IPartContainer.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/IPartContainer.java
new file mode 100644
index 0000000..9f2f7e4
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/IPartContainer.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.team;
+
+import org.eclipse.jface.operation.IRunnableContext;
+
+/**
+ * @author Steffen Pingel
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface IPartContainer extends IRunnableContext {
+
+ public void setMessage(String message, int messageType);
+
+ public void updateButtons();
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/Messages.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/Messages.java
new file mode 100644
index 0000000..c71361e
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/Messages.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.team;
+
+import org.eclipse.osgi.util.NLS;
+
+class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.commons.ui.team.messages"; //$NON-NLS-1$
+
+ public static String RepositoryLocationPart_Anonymous;
+
+ public static String RepositoryLocationPart_Change_Settings;
+
+ public static String RepositoryLocationPart_Disconnected;
+
+ public static String RepositoryLocationPart_Enable_HTTP_Authentication;
+
+ public static String RepositoryLocationPart_Enable_Proxy_Authentication;
+
+ public static String RepositoryLocationPart_Enter_a_valid_server_url;
+
+ public static String RepositoryLocationPart_HTTP_Authentication;
+
+ public static String RepositoryLocationPart_Label;
+
+ public static String RepositoryLocationPart_Password;
+
+ public static String RepositoryLocationPart_Proxy_Host;
+
+ public static String RepositoryLocationPart_Proxy_Port;
+
+ public static String RepositoryLocationPart_Proxy_Server_Configuration;
+
+ public static String RepositoryLocationPart_Repository_is_valid;
+
+ public static String RepositoryLocationPart_Save_Password;
+
+ public static String RepositoryLocationPart_Server;
+
+ public static String RepositoryLocationPart_Unexpected_error_during_repository_validation;
+
+ public static String RepositoryLocationPart_Use_global_Network_Connections_preferences;
+
+ public static String RepositoryLocationPart_User;
+
+ public static String RepositoryLocationPart_Validating_repository;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryLocationPart.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryLocationPart.java
new file mode 100644
index 0000000..ae2e89f
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryLocationPart.java
@@ -0,0 +1,613 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.team;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.databinding.dialog.DialogPageSupport;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.wizard.WizardPageSupport;
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.mylyn.commons.repositories.RepositoryLocation;
+import org.eclipse.mylyn.commons.repositories.RepositoryValidator;
+import org.eclipse.mylyn.commons.repositories.auth.AuthenticationType;
+import org.eclipse.mylyn.commons.repositories.auth.UsernamePasswordCredentials;
+import org.eclipse.mylyn.internal.commons.ui.SectionComposite;
+import org.eclipse.mylyn.internal.commons.ui.team.RepositoryLocationValueProperty;
+import org.eclipse.mylyn.internal.commons.ui.team.TeamUiPlugin;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @author Steffen Pingel
+ * @since 3.5
+ */
+public class RepositoryLocationPart {
+
+ public class UrlValidator implements IValidator {
+
+ public IStatus validate(Object value) {
+ if (!isValidUrl(value.toString())) {
+ return new Status(IStatus.ERROR, TeamUiPlugin.ID_PLUGIN,
+ Messages.RepositoryLocationPart_Enter_a_valid_server_url);
+ }
+ return Status.OK_STATUS;
+ }
+
+ }
+
+ private class UsernamePasswordListener implements ModifyListener, SelectionListener {
+
+ private final AuthenticationType authenticationType;
+
+ private final Button enabledButton;
+
+ private boolean enablementReversed;
+
+ private final Text passwordText;
+
+ private final Button savePasswordButton;
+
+ private boolean updating;
+
+ private final Text userText;
+
+ public UsernamePasswordListener(AuthenticationType authenticationType, Button enabledButton, Text userText,
+ Text passwordText, Button savePasswordButton) {
+ this.authenticationType = authenticationType;
+ this.enabledButton = enabledButton;
+ this.userText = userText;
+ this.passwordText = passwordText;
+ this.savePasswordButton = savePasswordButton;
+ init();
+ }
+
+ private void apply() {
+ if (updating) {
+ return;
+ }
+ if (isEnabled()) {
+ UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(userText.getText(),
+ passwordText.getText());
+ getWorkingCopy().setCredentials(authenticationType, credentials);
+ } else {
+ getWorkingCopy().setCredentials(authenticationType, null);
+ }
+ }
+
+ protected void init() {
+ enabledButton.addSelectionListener(this);
+ userText.addModifyListener(this);
+ passwordText.addModifyListener(this);
+ savePasswordButton.addSelectionListener(this);
+ }
+
+ protected boolean isEnabled() {
+ return enabledButton.getSelection() != isEnablementReversed();
+ }
+
+ public boolean isEnablementReversed() {
+ return enablementReversed;
+ }
+
+ public void modifyText(ModifyEvent event) {
+ apply();
+ }
+
+ private void restore() {
+ try {
+ updating = true;
+ UsernamePasswordCredentials credentials = getWorkingCopy().getCredentials(authenticationType,
+ UsernamePasswordCredentials.class);
+ if (credentials != null) {
+ enabledButton.setSelection(!isEnablementReversed());
+ userText.setText(credentials.getUserName());
+ passwordText.setText(credentials.getUserName());
+ savePasswordButton.setSelection(true);
+ } else {
+ enabledButton.setSelection(isEnablementReversed());
+ userText.setText(""); //$NON-NLS-1$
+ passwordText.setText(""); //$NON-NLS-1$
+ savePasswordButton.setSelection(true);
+ }
+ } finally {
+ updating = false;
+ }
+ updateWidgetEnablement();
+ }
+
+ public void setEnablementReversed(boolean enablementReversed) {
+ this.enablementReversed = enablementReversed;
+ }
+
+ private void updateWidgetEnablement() {
+ boolean enabled = isEnabled();
+ userText.setEnabled(enabled);
+ passwordText.setEnabled(enabled);
+ savePasswordButton.setEnabled(enabled);
+ }
+
+ public void widgetDefaultSelected(SelectionEvent event) {
+ apply();
+
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ apply();
+ if (event.widget == enabledButton) {
+ updateWidgetEnablement();
+ }
+ }
+
+ }
+
+ protected static final String PREFS_PAGE_ID_NET_PROXY = "org.eclipse.ui.net.NetPreferences"; //$NON-NLS-1$
+
+ private DataBindingContext bindingContext;
+
+ private boolean needsAdditionalSections;
+
+ private boolean needsAnonymousLogin;
+
+ private boolean needsHttpAuth;
+
+ private boolean needsProxy;
+
+ private boolean needsValidation;
+
+ private IAdaptable serviceLocator;
+
+ private final RepositoryLocation workingCopy;
+
+ public RepositoryLocationPart(RepositoryLocation workingCopy) {
+ this.workingCopy = workingCopy;
+ setNeedsProxy(false);
+ setNeedsHttpAuth(false);
+ setNeedsValidation(true);
+ }
+
+ protected void applyValidatorResult(RepositoryValidator validator) {
+ IStatus status = validator.getResult();
+ String message = status.getMessage();
+ if (message == null || message.length() == 0) {
+ message = null;
+ }
+ switch (status.getSeverity()) {
+ case IStatus.OK:
+ if (status == Status.OK_STATUS) {
+// if (getUserName().length() > 0) {
+// message = "Credentials are valid.";
+// } else {
+ message = Messages.RepositoryLocationPart_Repository_is_valid;
+// }
+ }
+ getPartContainer().setMessage(message, IMessageProvider.INFORMATION);
+ break;
+ case IStatus.INFO:
+ getPartContainer().setMessage(message, IMessageProvider.INFORMATION);
+ break;
+ case IStatus.WARNING:
+ getPartContainer().setMessage(message, IMessageProvider.WARNING);
+ break;
+ default:
+ getPartContainer().setMessage(message, IMessageProvider.ERROR);
+ break;
+ }
+ }
+
+ private void bind(AuthenticationType authType, Button anonymousButton, Text userText, Text passwordText,
+ Button savePasswordButton, boolean reverseEnablement) {
+ UsernamePasswordListener listener = new UsernamePasswordListener(authType, anonymousButton, userText,
+ passwordText, savePasswordButton);
+ listener.setEnablementReversed(reverseEnablement);
+ listener.restore();
+ }
+
+ protected void bind(Button button, String property) {
+ ISWTObservableValue uiElement = SWTObservables.observeSelection(button);
+ IObservableValue modelElement = new RepositoryLocationValueProperty(property, Boolean.FALSE.toString()).observe(workingCopy);
+ bindingContext.bindValue(uiElement, modelElement, null, null);
+ }
+
+ protected void bind(Text text, String property) {
+ bind(text, property, null, null);
+ }
+
+ protected void bind(Text text, String property, UpdateValueStrategy targetObservableValue,
+ UpdateValueStrategy modelObservableValue) {
+ ISWTObservableValue uiElement = SWTObservables.observeText(text, SWT.Modify);
+ IObservableValue modelElement = new RepositoryLocationValueProperty(property, null).observe(workingCopy);
+ bindingContext.bindValue(uiElement, modelElement, targetObservableValue, modelObservableValue);
+ }
+
+ /**
+ * Returns whether this page can be validated or not.
+ * <p>
+ * This information is typically used by the wizard to set the enablement of the validation UI affordance.
+ * </p>
+ *
+ * @return <code>true</code> if this page can be validated, and <code>false</code> otherwise
+ * @see #needsValidation()
+ * @see IWizardContainer#updateButtons()
+ */
+ public boolean canValidate() {
+ return getValidator() != null;
+ }
+
+ protected Control createAdditionalContents(Composite composite) {
+ return null;
+ }
+
+ public Control createContents(Composite parent) {
+ bindingContext = new DataBindingContext();
+ WizardPage wizardPage = getContainer(WizardPage.class);
+ if (wizardPage != null) {
+ WizardPageSupport.create(wizardPage, bindingContext);
+ } else {
+ DialogPage page = getContainer(DialogPage.class);
+ if (page != null) {
+ DialogPageSupport.create(page, bindingContext);
+ }
+ }
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayoutFactory.swtDefaults().numColumns(3).applyTo(composite);
+
+// Composite this = new Composite(parent, SWT.NULL);
+// Layout layout = new FillLayout();
+// this.setLayout(layout);
+
+ createServerSection(composite);
+ createUserSection(composite);
+
+ Control control = createAdditionalContents(composite);
+ if (control != null) {
+ GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(control);
+ }
+
+ if (needsHttpAuth() || needsProxy() || needsAdditionalSections()) {
+ SectionComposite sectionComposite = new SectionComposite(composite, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(sectionComposite);
+
+ if (needsHttpAuth()) {
+ createHttpAuthSection(sectionComposite);
+ }
+ if (needsProxy()) {
+ createProxySection(sectionComposite);
+ }
+ createSections(sectionComposite);
+ }
+
+// Button validateButton = new Button(composite, SWT.PUSH);
+// validateButton.setText("Validate");
+// validateButton.addSelectionListener(new SelectionAdapter() {
+// @Override
+// public void widgetSelected(SelectionEvent e) {
+// validate();
+// }
+// });
+
+ return composite;
+ }
+
+ private void createHttpAuthSection(SectionComposite parent) {
+ int style = SWT.NONE;
+ if (getWorkingCopy().getCredentials(AuthenticationType.HTTP, UsernamePasswordCredentials.class) != null) {
+ style |= ExpandableComposite.EXPANDED;
+ }
+ ExpandableComposite section = parent.createSection(Messages.RepositoryLocationPart_HTTP_Authentication, style);
+ section.clientVerticalSpacing = 5;
+
+ Composite composite = new Composite(section, SWT.NONE);
+ section.setClient(composite);
+ GridLayoutFactory.fillDefaults().numColumns(3).applyTo(composite);
+
+ Label label;
+
+ Button enableButton = new Button(composite, SWT.CHECK);
+ GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(enableButton);
+ enableButton.setText(Messages.RepositoryLocationPart_Enable_HTTP_Authentication);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_User);
+
+ Text userText = new Text(composite, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(userText);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Password);
+
+ Text passwordText = new Text(composite, SWT.BORDER | SWT.PASSWORD);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(passwordText);
+
+ Button savePasswordButton = new Button(composite, SWT.CHECK);
+ savePasswordButton.setText(Messages.RepositoryLocationPart_Save_Password);
+
+ bind(AuthenticationType.HTTP, enableButton, userText, passwordText, savePasswordButton, false);
+ }
+
+ private void createProxySection(final SectionComposite parent) {
+ ExpandableComposite section = parent.createSection(Messages.RepositoryLocationPart_Proxy_Server_Configuration);
+
+ Composite composite = new Composite(section, SWT.NONE);
+ section.setClient(composite);
+ GridLayoutFactory.fillDefaults().numColumns(3).applyTo(composite);
+
+ Label label;
+
+ Button systemProxyButton = new Button(composite, SWT.CHECK);
+ GridDataFactory.fillDefaults().span(2, SWT.DEFAULT).applyTo(systemProxyButton);
+ systemProxyButton.setText(Messages.RepositoryLocationPart_Use_global_Network_Connections_preferences);
+// systemProxyButton.addSelectionListener(new SelectionAdapter() {
+// @Override
+// public void widgetSelected(SelectionEvent e) {
+// updateProxyEnablement(systemProxyButton.getSelection());
+// }
+// });
+ bind(systemProxyButton, RepositoryLocation.PROPERTY_PROXY_USEDEFAULT);
+
+ Link changeProxySettingsLink = new Link(composite, SWT.NONE);
+ changeProxySettingsLink.setText(Messages.RepositoryLocationPart_Change_Settings);
+ changeProxySettingsLink.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ PreferenceDialog dlg = PreferencesUtil.createPreferenceDialogOn(parent.getShell(),
+ PREFS_PAGE_ID_NET_PROXY, new String[] { PREFS_PAGE_ID_NET_PROXY }, null);
+ dlg.open();
+ }
+ });
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Proxy_Host);
+
+ Text proxyHostText = new Text(composite, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(proxyHostText);
+ bind(proxyHostText, RepositoryLocation.PROPERTY_PROXY_HOST);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Proxy_Port);
+
+ Text proxyPortText = new Text(composite, SWT.BORDER | SWT.PASSWORD);
+ GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(proxyPortText);
+ bind(proxyPortText, RepositoryLocation.PROPERTY_PROXY_PORT);
+
+ // authentication
+
+ Button enableButton = new Button(composite, SWT.CHECK);
+ GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(enableButton);
+ enableButton.setText(Messages.RepositoryLocationPart_Enable_Proxy_Authentication);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_User);
+
+ Text userText = new Text(composite, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(userText);
+
+ label = new Label(composite, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Password);
+
+ Text passwordText = new Text(composite, SWT.BORDER | SWT.PASSWORD);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(passwordText);
+
+ Button savePasswordButton = new Button(composite, SWT.CHECK);
+ savePasswordButton.setText(Messages.RepositoryLocationPart_Save_Password);
+
+ bind(AuthenticationType.PROXY, enableButton, userText, passwordText, savePasswordButton, false);
+ }
+
+ protected void createSections(SectionComposite sectionComposite) {
+ }
+
+ private void createServerSection(Composite parent) {
+ Label label;
+
+ label = new Label(parent, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Server);
+
+ Text urlText = new Text(parent, SWT.BORDER);
+ GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(urlText);
+ bind(urlText, RepositoryLocation.PROPERTY_URL, getUrlUpdateValueStrategy(), null);
+
+ label = new Label(parent, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Label);
+
+ Text labelText = new Text(parent, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(labelText);
+ bind(labelText, RepositoryLocation.PROPERTY_LABEL);
+
+ Button disconnectedButton = new Button(parent, SWT.CHECK);
+ disconnectedButton.setText(Messages.RepositoryLocationPart_Disconnected);
+ bind(disconnectedButton, RepositoryLocation.PROPERTY_OFFLINE);
+ }
+
+ protected UpdateValueStrategy getUrlUpdateValueStrategy() {
+ return new UpdateValueStrategy().setAfterConvertValidator(new UrlValidator());
+ }
+
+ private void createUserSection(Composite parent) {
+ Label label;
+
+ label = new Label(parent, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_User);
+
+ Text userText = new Text(parent, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(userText);
+ bind(userText, RepositoryLocation.PROPERTY_USERNAME);
+
+ Button anonymousButton = new Button(parent, SWT.CHECK);
+ anonymousButton.setText(Messages.RepositoryLocationPart_Anonymous);
+
+ label = new Label(parent, SWT.NONE);
+ label.setText(Messages.RepositoryLocationPart_Password);
+
+ Text passwordText = new Text(parent, SWT.BORDER | SWT.PASSWORD);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(passwordText);
+
+ Button savePasswordButton = new Button(parent, SWT.CHECK);
+ savePasswordButton.setText(Messages.RepositoryLocationPart_Save_Password);
+
+ bind(AuthenticationType.REPOSITORY, anonymousButton, userText, passwordText, savePasswordButton, true);
+ }
+
+ public <T> T getContainer(Class<T> clazz) {
+ return (T) getServiceLocator().getAdapter(clazz);
+ }
+
+ public IPartContainer getPartContainer() {
+ return getContainer(IPartContainer.class);
+ }
+
+ private IAdaptable getServiceLocator() {
+ return serviceLocator;
+ }
+
+ protected RepositoryValidator getValidator() {
+ return null;
+ }
+
+ protected RepositoryLocation getWorkingCopy() {
+ return workingCopy;
+ }
+
+ public boolean isValidUrl(String url) {
+ if (url.startsWith("https://") || url.startsWith("http://")) { //$NON-NLS-1$//$NON-NLS-2$
+ try {
+ new URI(url);
+ return true;
+ } catch (Exception e) {
+ // fall through
+ }
+ }
+ return false;
+ }
+
+ public boolean needsAdditionalSections() {
+ return needsAdditionalSections;
+ }
+
+ public boolean needsAnonymousLogin() {
+ return needsAnonymousLogin;
+ }
+
+ public boolean needsHttpAuth() {
+ return this.needsHttpAuth;
+ }
+
+ public boolean needsProxy() {
+ return this.needsProxy;
+ }
+
+ public boolean needsValidation() {
+ return needsValidation;
+ }
+
+ public void setNeedsAdditionalSections(boolean needsAdditionalSections) {
+ this.needsAdditionalSections = needsAdditionalSections;
+ }
+
+ public void setNeedsAnonymousLogin(boolean needsAnonymousLogin) {
+ this.needsAnonymousLogin = needsAnonymousLogin;
+ }
+
+ public void setNeedsHttpAuth(boolean needsHttpAuth) {
+ this.needsHttpAuth = needsHttpAuth;
+ }
+
+ public void setNeedsProxy(boolean needsProxy) {
+ this.needsProxy = needsProxy;
+ }
+
+ public void setNeedsValidation(boolean needsValidation) {
+ this.needsValidation = needsValidation;
+ }
+
+ public void setServiceLocator(IAdaptable container) {
+ this.serviceLocator = container;
+ }
+
+ /**
+ * Validate settings provided by the {@link #getValidator() validator}, typically the server settings.
+ */
+ public void validate() {
+ final RepositoryValidator validator = getValidator();
+ if (validator == null) {
+ return;
+ }
+
+ final AtomicReference<IStatus> result = new AtomicReference<IStatus>();
+ try {
+ getContainer(IPartContainer.class).run(true, true, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ monitor.beginTask(Messages.RepositoryLocationPart_Validating_repository, IProgressMonitor.UNKNOWN);
+ try {
+ result.set(validator.run(monitor));
+ } catch (OperationCanceledException e) {
+ result.set(Status.CANCEL_STATUS);
+ throw new InterruptedException();
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+ });
+ } catch (InvocationTargetException e) {
+ StatusManager.getManager().handle(
+ new Status(IStatus.ERROR, TeamUiPlugin.ID_PLUGIN,
+ Messages.RepositoryLocationPart_Unexpected_error_during_repository_validation, e),
+ StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
+ return;
+ } catch (InterruptedException e) {
+ // canceled
+ return;
+ }
+ if (result.get() == null) {
+ validator.setResult(Status.OK_STATUS);
+ } else {
+ validator.setResult(result.get());
+ }
+ getPartContainer().updateButtons();
+ applyValidatorResult(validator);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryPropertyPage.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryPropertyPage.java
new file mode 100644
index 0000000..36e1e87
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryPropertyPage.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.team;
+
+import java.util.UUID;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.mylyn.commons.repositories.RepositoryLocation;
+import org.eclipse.mylyn.internal.commons.repositories.InMemoryCredentialsStore;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+/**
+ * @author Steffen Pingel
+ */
+public class RepositoryPropertyPage extends PropertyPage implements IAdaptable {
+
+ private RepositoryLocationPart part;
+
+ private RepositoryLocation workingCopy;
+
+ public RepositoryPropertyPage() {
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ initializeDialogUnits(parent);
+
+ part = new RepositoryLocationPart(getWorkingCopy());
+ part.setServiceLocator(this);
+ setControl(part.createContents(parent));
+ Dialog.applyDialogFont(parent);
+ return getControl();
+ }
+
+ RepositoryLocation getWorkingCopy() {
+ if (workingCopy == null) {
+ RepositoryLocation element = (RepositoryLocation) getElement().getAdapter(RepositoryLocation.class);
+ workingCopy = new RepositoryLocation(element);
+ if (workingCopy.getId() == null) {
+ workingCopy.setProperty(RepositoryLocation.PROPERTY_ID, UUID.randomUUID().toString());
+ }
+ workingCopy.setCredentialsStore(new InMemoryCredentialsStore(workingCopy.getCredentialsStore()));
+ }
+ return workingCopy;
+ }
+
+ public Object getAdapter(Class adapter) {
+ if (adapter == DialogPage.class) {
+ return this;
+ }
+ if (adapter == IPartContainer.class) {
+ return this;
+ }
+ return null;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryUi.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryUi.java
new file mode 100644
index 0000000..572cdb9
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryUi.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.team;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.mylyn.internal.commons.ui.team.Messages;
+import org.eclipse.mylyn.internal.commons.ui.team.TeamUiPlugin;
+import org.eclipse.mylyn.internal.commons.ui.team.wizards.NewRepositoryWizard;
+import org.eclipse.mylyn.internal.provisional.commons.ui.dialogs.ValidatableWizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * @author Steffen Pingel
+ */
+public final class RepositoryUi {
+
+ /**
+ * The wizard dialog width.
+ */
+ private static final int SIZING_WIZARD_WIDTH = 500;
+
+ /**
+ * The wizard dialog height.
+ */
+ private static final int SIZING_WIZARD_HEIGHT = 500;
+
+ public static final String ID_VIEW_REPOSITORIES = "org.eclipse.mylyn.commons.team.navigator.Repositories"; //$NON-NLS-1$
+
+ private RepositoryUi() {
+ }
+
+ public static int openNewRepositoryDialog(IWorkbenchWindow workbenchWindow, String categoryId) {
+ NewRepositoryWizard wizard = new NewRepositoryWizard();
+ wizard.setCategoryId(categoryId);
+ wizard.setWindowTitle(Messages.NewRepositoryHandler_New_Repository);
+
+ ISelection selection = workbenchWindow.getSelectionService().getSelection();
+ IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
+ if (selection instanceof IStructuredSelection) {
+ selectionToPass = (IStructuredSelection) selection;
+ } else {
+ // @issue the following is resource-specific legacy code
+ // Build the selection from the IFile of the editor
+ Class resourceClass = LegacyResourceSupport.getResourceClass();
+ if (resourceClass != null) {
+ IWorkbenchPart part = workbenchWindow.getPartService().getActivePart();
+ if (part instanceof IEditorPart) {
+ IEditorInput input = ((IEditorPart) part).getEditorInput();
+ Object resource = Util.getAdapter(input, resourceClass);
+ if (resource != null) {
+ selectionToPass = new StructuredSelection(resource);
+ }
+ }
+ }
+ }
+
+ wizard.init(workbenchWindow.getWorkbench(), selectionToPass);
+
+ IDialogSettings workbenchSettings = TeamUiPlugin.getDefault().getDialogSettings();
+ IDialogSettings wizardSettings = workbenchSettings.getSection("NewWizardAction"); //$NON-NLS-1$
+ if (wizardSettings == null) {
+ wizardSettings = workbenchSettings.addNewSection("NewWizardAction"); //$NON-NLS-1$
+ }
+ wizard.setDialogSettings(wizardSettings);
+ wizard.setForcePreviousAndNextButtons(true);
+
+ Shell parent = workbenchWindow.getShell();
+ ValidatableWizardDialog dialog = new ValidatableWizardDialog(parent, wizard);
+ dialog.create();
+ dialog.getShell().setSize(Math.max(SIZING_WIZARD_WIDTH, dialog.getShell().getSize().x), SIZING_WIZARD_HEIGHT);
+ //PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(), IWorkbenchHelpContextIds.NEW_WIZARD);
+ return dialog.open();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryWizardPage.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryWizardPage.java
new file mode 100644
index 0000000..f2845ae
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/RepositoryWizardPage.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui.team;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.mylyn.commons.repositories.RepositoryLocation;
+import org.eclipse.mylyn.internal.provisional.commons.ui.dialogs.IValidatable;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * @author Steffen Pingel
+ */
+public class RepositoryWizardPage extends WizardPage implements IPartContainer, IAdaptable, IValidatable {
+
+ private IAdaptable element;
+
+ private RepositoryLocationPart part;
+
+ private RepositoryLocation workingCopy;
+
+ public RepositoryWizardPage(String pageName) {
+ super(pageName);
+ setPageComplete(false);
+ }
+
+ public boolean canValidate() {
+ return part.canValidate();
+ }
+
+ public void createControl(Composite parent) {
+ initializeDialogUnits(parent);
+
+ String message = getMessage();
+
+ part = doCreateRepositoryPart();
+ part.setServiceLocator(this);
+ setControl(part.createContents(parent));
+ Dialog.applyDialogFont(parent);
+
+ setMessage(message);
+ }
+
+ protected RepositoryLocationPart doCreateRepositoryPart() {
+ return new RepositoryLocationPart(getWorkingCopy());
+ }
+
+ public Object getAdapter(Class adapter) {
+ if (adapter == WizardPage.class) {
+ return this;
+ }
+ if (adapter == DialogPage.class) {
+ return this;
+ }
+ if (adapter == IPartContainer.class) {
+ return this;
+ }
+ return null;
+ }
+
+ public IAdaptable getElement() {
+ return element;
+ }
+
+ public RepositoryLocationPart getPart() {
+ return part;
+ }
+
+ protected RepositoryLocation getWorkingCopy() {
+ if (workingCopy == null) {
+ workingCopy = (RepositoryLocation) getElement().getAdapter(RepositoryLocation.class);
+ }
+ return workingCopy;
+ }
+
+ public boolean needsValidation() {
+ return part.needsValidation();
+ }
+
+ public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException,
+ InterruptedException {
+ getContainer().run(fork, cancelable, runnable);
+ }
+
+ /**
+ * Sets the element that owns properties shown on this page.
+ *
+ * @param element
+ * the element
+ */
+ public void setElement(IAdaptable element) {
+ this.element = element;
+ }
+
+ public void updateButtons() {
+ getContainer().updateButtons();
+ }
+
+ public void validate() {
+ part.validate();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/messages.properties b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/messages.properties
new file mode 100644
index 0000000..f5362b5
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/commons/ui/team/messages.properties
@@ -0,0 +1,19 @@
+RepositoryLocationPart_Anonymous=Anonymous
+RepositoryLocationPart_Change_Settings=<a>Change Settings</a>
+RepositoryLocationPart_Disconnected=Disconnected
+RepositoryLocationPart_Enable_HTTP_Authentication=Enable HTTP Authentication
+RepositoryLocationPart_Enable_Proxy_Authentication=Enable Proxy Authentication
+RepositoryLocationPart_Enter_a_valid_server_url=Enter a valid server url.
+RepositoryLocationPart_HTTP_Authentication=HTTP Authentication
+RepositoryLocationPart_Label=&Label:
+RepositoryLocationPart_Password=&Password:
+RepositoryLocationPart_Proxy_Host=Proxy &Host:
+RepositoryLocationPart_Proxy_Port=Proxy &Port:
+RepositoryLocationPart_Proxy_Server_Configuration=Proxy Server Configuration
+RepositoryLocationPart_Repository_is_valid=Repository is valid.
+RepositoryLocationPart_Save_Password=Save Password
+RepositoryLocationPart_Server=&Server:
+RepositoryLocationPart_Unexpected_error_during_repository_validation=Unexpected error during repository validation.
+RepositoryLocationPart_Use_global_Network_Connections_preferences=Use global Network Connections preferences
+RepositoryLocationPart_User=&User:
+RepositoryLocationPart_Validating_repository=Validating repository
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/EmptyRepositoryCategoriesFilter.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/EmptyRepositoryCategoriesFilter.java
new file mode 100644
index 0000000..4000856
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/EmptyRepositoryCategoriesFilter.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.mylyn.commons.repositories.RepositoryCategory;
+
+/**
+ * @author Robert Elves
+ * @author Steffen Pingel
+ */
+public class EmptyRepositoryCategoriesFilter extends ViewerFilter {
+
+ public EmptyRepositoryCategoriesFilter() {
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof RepositoryCategory) {
+ return ((ITreeContentProvider) ((StructuredViewer) viewer).getContentProvider()).getChildren(element).length > 0;
+ }
+ return true;
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/Messages.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/Messages.java
new file mode 100644
index 0000000..4a5c385
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/Messages.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.commons.ui.team.messages"; //$NON-NLS-1$
+
+ public static String NewRepositoryHandler_New_Repository;
+
+ public static String RepositoriesView_Root;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/NewRepositoryHandler.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/NewRepositoryHandler.java
new file mode 100644
index 0000000..507eca3
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/NewRepositoryHandler.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.mylyn.commons.ui.team.RepositoryUi;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * @author Steffen Pingel
+ */
+public class NewRepositoryHandler extends AbstractHandler implements IHandler {
+
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IWorkbenchWindow workbenchWindow = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+ return RepositoryUi.openNewRepositoryDialog(workbenchWindow, null);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoriesView.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoriesView.java
new file mode 100644
index 0000000..94152ad
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoriesView.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.mylyn.commons.repositories.RepositoryCategory;
+import org.eclipse.mylyn.internal.provisional.commons.ui.GradientDrawer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.navigator.CommonNavigator;
+import org.eclipse.ui.navigator.CommonViewer;
+import org.eclipse.ui.part.IShowInTargetList;
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * @author Steffen Pingel
+ */
+public class RepositoriesView extends CommonNavigator {
+
+ private final RepositoryCategory rootCategory;
+
+ public RepositoriesView() {
+ rootCategory = new RepositoryCategory(RepositoryCategory.ID_CATEGORY_ROOT, Messages.RepositoriesView_Root, 0);
+ }
+
+ @Override
+ protected Object getInitialInput() {
+ return rootCategory;
+ }
+
+ @Override
+ public void createPartControl(Composite aParent) {
+ super.createPartControl(aParent);
+ getCommonViewer().expandAll();
+ }
+
+ @Override
+ protected CommonViewer createCommonViewer(Composite aParent) {
+ CommonViewer viewer = super.createCommonViewer(aParent);
+ IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
+ new GradientDrawer(themeManager, viewer) {
+ @Override
+ protected boolean shouldApplyGradient(org.eclipse.swt.widgets.Event event) {
+ return event.item.getData() instanceof RepositoryCategory;
+ }
+ };
+ return viewer;
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes")
+ Class adapter) {
+ // FIXME read targets from extension point?
+ if (adapter == IShowInTargetList.class) {
+ return new IShowInTargetList() {
+ public String[] getShowInTargetIds() {
+ return new String[] { "org.eclipse.mylyn.builds.navigator.builds" }; //$NON-NLS-1$
+ }
+
+ };
+ }
+ return super.getAdapter(adapter);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategoryContentProvider.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategoryContentProvider.java
new file mode 100644
index 0000000..4200a62
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategoryContentProvider.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylyn.commons.repositories.RepositoryCategory;
+
+public class RepositoryCategoryContentProvider implements ITreeContentProvider {
+
+ private static final Map<String, RepositoryCategory> repositoryCategories = new HashMap<String, RepositoryCategory>();
+
+ public RepositoryCategoryContentProvider() {
+ RepositoryCategory catTasks = new RepositoryCategory(RepositoryCategory.ID_CATEGORY_TASKS, "Tasks", 0); //$NON-NLS-1$
+ repositoryCategories.put(catTasks.getId(), catTasks);
+ RepositoryCategory catBugs = new RepositoryCategory(RepositoryCategory.ID_CATEGORY_BUGS, "Bugs", 100); //$NON-NLS-1$
+ repositoryCategories.put(catBugs.getId(), catBugs);
+ RepositoryCategory catBuild = new RepositoryCategory(RepositoryCategory.ID_CATEGORY_BUILDS, "Builds", 200); //$NON-NLS-1$
+ repositoryCategories.put(catBuild.getId(), catBuild);
+ RepositoryCategory catReview = new RepositoryCategory(RepositoryCategory.ID_CATEGORY_REVIEWS, "Reviews", 300); //$NON-NLS-1$
+ repositoryCategories.put(catReview.getId(), catReview);
+ RepositoryCategory catOther = new RepositoryCategory(RepositoryCategory.ID_CATEGORY_OTHER, "Other", 400); //$NON-NLS-1$
+ repositoryCategories.put(catOther.getId(), catOther);
+ }
+
+ public void dispose() {
+ // ignore
+
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // ignore
+
+ }
+
+ public Object[] getElements(Object inputElement) {
+ return repositoryCategories.values().toArray();
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ // ignore
+ return null;
+ }
+
+ public Object getParent(Object element) {
+ // ignore
+ return null;
+ }
+
+ public boolean hasChildren(Object element) {
+ // ignore
+ return false;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategorySorter.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategorySorter.java
new file mode 100644
index 0000000..fb69a24
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryCategorySorter.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import java.text.Collator;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.mylyn.commons.repositories.RepositoryCategory;
+
+public class RepositoryCategorySorter extends ViewerSorter {
+
+ public RepositoryCategorySorter() {
+ }
+
+ public RepositoryCategorySorter(Collator collator) {
+ super(collator);
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if (e1 instanceof RepositoryCategory && e2 instanceof RepositoryCategory) {
+ RepositoryCategory category1 = (RepositoryCategory) e1;
+ RepositoryCategory category2 = (RepositoryCategory) e2;
+ int result = category1.getRank() - category2.getRank();
+ if (result != 0) {
+ return result;
+ }
+ }
+ // fall back to comparing by label
+ return super.compare(viewer, e1, e2);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLabelProvider.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLabelProvider.java
new file mode 100644
index 0000000..e384c66
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLabelProvider.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.mylyn.commons.repositories.RepositoryCategory;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * @author Steffen Pingel
+ */
+public class RepositoryLabelProvider extends LabelProvider {
+
+ @Override
+ public Image getImage(Object object) {
+ if (object instanceof RepositoryCategory) {
+ return WorkbenchImages.getImage(ISharedImages.IMG_OBJ_FOLDER);
+ }
+ return null;
+ }
+
+ @Override
+ public String getText(Object object) {
+ if (object instanceof RepositoryCategory) {
+ return ((RepositoryCategory) object).getLabel();
+ }
+ return null;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLocationValueProperty.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLocationValueProperty.java
new file mode 100644
index 0000000..1c36dd8
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/RepositoryLocationValueProperty.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.IDiff;
+import org.eclipse.core.databinding.property.INativePropertyListener;
+import org.eclipse.core.databinding.property.IProperty;
+import org.eclipse.core.databinding.property.ISimplePropertyListener;
+import org.eclipse.core.databinding.property.NativePropertyListener;
+import org.eclipse.core.databinding.property.value.SimpleValueProperty;
+import org.eclipse.mylyn.commons.repositories.RepositoryLocation;
+
+/**
+ * @author Steffen Pingel
+ */
+public class RepositoryLocationValueProperty extends SimpleValueProperty {
+
+ private class PrivatePropertyChangeListener extends NativePropertyListener implements PropertyChangeListener {
+
+ public PrivatePropertyChangeListener(IProperty property, ISimplePropertyListener listener) {
+ super(property, listener);
+ }
+
+ @Override
+ protected void doAddTo(Object source) {
+ ((RepositoryLocation) source).addChangeListener(this);
+ }
+
+ @Override
+ protected void doRemoveFrom(Object source) {
+ ((RepositoryLocation) source).removeChangeListener(this);
+ }
+
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getPropertyName() == null || key.equals(evt.getPropertyName())) {
+ Object oldValue = evt.getOldValue();
+ Object newValue = evt.getNewValue();
+ IDiff diff;
+ if (evt.getPropertyName() == null || oldValue == null || newValue == null) {
+ diff = null;
+ } else {
+ diff = Diffs.createValueDiff(oldValue, newValue);
+ }
+ fireChange(evt.getSource(), diff);
+ }
+ }
+
+ }
+
+ private final String key;
+
+ private final String defaultValue;
+
+ public RepositoryLocationValueProperty(String key, String defaultValue) {
+ this.key = key;
+ this.defaultValue = defaultValue;
+ }
+
+ public Object getValueType() {
+ return String.class;
+ }
+
+ @Override
+ protected Object doGetValue(Object source) {
+// if ("uri".equals(key)) {
+// URI uri = ((RepositoryLocation) source).getUri();
+// return (uri != null) ? uri.toString() : uri;
+// }
+ String value = ((RepositoryLocation) source).getProperty(key);
+ return (value != null) ? value : defaultValue;
+ }
+
+ @Override
+ protected void doSetValue(Object source, Object value) {
+// if ("uri".equals(key)) {
+// try {
+// ((RepositoryLocation) source).setUri(new URI((String) value));
+// } catch (URISyntaxException e) {
+// // ignore
+// }
+// } else {
+ ((RepositoryLocation) source).setProperty(key, (value != null) ? value.toString() : null);
+// }
+ }
+
+ @Override
+ public INativePropertyListener adaptListener(final ISimplePropertyListener listener) {
+ return new PrivatePropertyChangeListener(this, listener);
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/ShowInMenuContribution.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/ShowInMenuContribution.java
new file mode 100644
index 0000000..a4e42ed
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/ShowInMenuContribution.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ContributionItemFactory;
+
+/**
+ * @author Steffen Pingel
+ */
+public class ShowInMenuContribution extends ContributionItem {
+
+ private IContributionItem item;
+
+ public ShowInMenuContribution() {
+ }
+
+ public ShowInMenuContribution(String id) {
+ super(id);
+ }
+
+ @Override
+ public void fill(Menu menu, int index) {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ if (item != null) {
+ item.dispose();
+ }
+ item = ContributionItemFactory.VIEWS_SHOW_IN.create(window);
+ item.fill(menu, index);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (item != null) {
+ item.dispose();
+ item = null;
+ }
+ super.dispose();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/TeamUiPlugin.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/TeamUiPlugin.java
new file mode 100644
index 0000000..007d865
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/TeamUiPlugin.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.commons.ui.team;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TeamUiPlugin extends AbstractUIPlugin {
+
+ public static final String ID_PLUGIN = "org.eclipse.mylyn.commons.team"; //$NON-NLS-1$
+
+ private static TeamUiPlugin plugin;
+
+ /**
+ * The constructor
+ */
+ public TeamUiPlugin() {
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static TeamUiPlugin getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/messages.properties b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/messages.properties
new file mode 100644
index 0000000..4395872
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/messages.properties
@@ -0,0 +1,2 @@
+NewRepositoryHandler_New_Repository=New Repository
+RepositoriesView_Root=Root
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizard.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizard.java
new file mode 100644
index 0000000..557b65b
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizard.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.commons.ui.team.wizards;
+
+import java.util.StringTokenizer;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * The new wizard is responsible for allowing the user to choose which new (nested) wizard to run. The set of available
+ * new wizards comes from the new extension point.
+ */
+public class NewRepositoryWizard extends Wizard {
+
+ private static final String CATEGORY_SEPARATOR = "/"; //$NON-NLS-1$
+
+ private String categoryId = null;
+
+ private NewRepositoryWizardSelectionPage mainPage;
+
+ private boolean projectsOnly = false;
+
+ private IStructuredSelection selection;
+
+ private IWorkbench workbench;
+
+ /**
+ * Create the wizard pages
+ */
+ @Override
+ public void addPages() {
+ IWizardCategory root = NewRepositoryWizardRegistry.getInstance().getRootCategory();
+ IWizardDescriptor[] primary = NewRepositoryWizardRegistry.getInstance().getPrimaryWizards();
+
+ if (categoryId != null) {
+ IWizardCategory categories = root;
+ StringTokenizer familyTokenizer = new StringTokenizer(categoryId, CATEGORY_SEPARATOR);
+ while (familyTokenizer.hasMoreElements()) {
+ categories = getChildWithID(categories, familyTokenizer.nextToken());
+ if (categories == null) {
+ break;
+ }
+ }
+ if (categories != null) {
+ root = categories;
+ }
+ }
+
+ mainPage = new NewRepositoryWizardSelectionPage(workbench, selection, root, primary, projectsOnly);
+ addPage(mainPage);
+ }
+
+ /**
+ * Returns the id of the category of wizards to show or <code>null</code> to show all categories. If no entries can
+ * be found with this id then all categories are shown.
+ *
+ * @return String or <code>null</code>.
+ */
+ public String getCategoryId() {
+ return categoryId;
+ }
+
+ /**
+ * Returns the child collection element for the given id
+ */
+ private IWizardCategory getChildWithID(IWizardCategory parent, String id) {
+ IWizardCategory[] children = parent.getCategories();
+ for (int i = 0; i < children.length; ++i) {
+ IWizardCategory currentChild = children[i];
+ if (currentChild.getId().equals(id)) {
+ return currentChild;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Lazily create the wizards pages
+ *
+ * @param aWorkbench
+ * the workbench
+ * @param currentSelection
+ * the current selection
+ */
+ public void init(IWorkbench aWorkbench, IStructuredSelection currentSelection) {
+ this.workbench = aWorkbench;
+ this.selection = currentSelection;
+
+ if (getWindowTitle() == null) {
+ // No title supplied. Set the default title
+ if (projectsOnly) {
+ setWindowTitle(WorkbenchMessages.NewProject_title);
+ } else {
+ setWindowTitle(WorkbenchMessages.NewWizard_title);
+ }
+ }
+ setDefaultPageImageDescriptor(WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_NEW_WIZ));
+ setNeedsProgressMonitor(true);
+ }
+
+ /**
+ * The user has pressed Finish. Instruct self's pages to finish, and answer a boolean indicating success.
+ *
+ * @return boolean
+ */
+ @Override
+ public boolean performFinish() {
+ //save our selection state
+ mainPage.saveWidgetValues();
+ // if we're finishing from the main page then perform finish on the selected wizard.
+ if (getContainer().getCurrentPage() == mainPage) {
+ if (mainPage.canFinishEarly()) {
+ IWizard wizard = mainPage.getSelectedNode().getWizard();
+ wizard.setContainer(getContainer());
+ return wizard.performFinish();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Sets the id of the category of wizards to show or <code>null</code> to show all categories. If no entries can be
+ * found with this id then all categories are shown.
+ *
+ * @param id
+ * may be <code>null</code>.
+ */
+ public void setCategoryId(String id) {
+ categoryId = id;
+ }
+
+ /**
+ * Sets the projects only flag. If <code>true</code> only projects will be shown in this wizard.
+ *
+ * @param b
+ * if only projects should be shown
+ */
+ public void setProjectsOnly(boolean b) {
+ projectsOnly = b;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.IWizard#canFinish()
+ */
+ @Override
+ public boolean canFinish() {
+ // we can finish if the first page is current and the the page can finish early.
+ if (getContainer().getCurrentPage() == mainPage) {
+ if (mainPage.canFinishEarly()) {
+ return true;
+ }
+ }
+ return super.canFinish();
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardCollectionComparator.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardCollectionComparator.java
new file mode 100644
index 0000000..82bbfb0
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardCollectionComparator.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team.wizards;
+
+import org.eclipse.jface.viewers.IBasicPropertyConstants;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.ui.internal.dialogs.WizardCollectionElement;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+
+/**
+ * A Viewer element sorter that sorts Elements by their name attribute. Note that capitalization differences are not
+ * considered by this sorter, so a < B < c. NOTE one exception to the above: an element with the system's reserved name
+ * for base Wizards will always be sorted such that it will ultimately be placed at the beginning of the sorted result.
+ */
+class NewWizardCollectionComparator extends ViewerComparator {
+ /**
+ * Static instance of this class.
+ */
+ public final static NewWizardCollectionComparator INSTANCE = new NewWizardCollectionComparator();
+
+ /**
+ * Creates an instance of <code>NewWizardCollectionSorter</code>. Since this is a stateless sorter, it is only
+ * accessible as a singleton; the private visibility of this constructor ensures this.
+ */
+ private NewWizardCollectionComparator() {
+ super();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ViewerSorter#category(java.lang.Object)
+ */
+ @Override
+ public int category(Object element) {
+ if (element instanceof WorkbenchWizardElement) {
+ return -1;
+ }
+ if (element instanceof WizardCollectionElement) {
+ String id = ((WizardCollectionElement) element).getId();
+ if (WizardsRegistryReader.GENERAL_WIZARD_CATEGORY.equals(id)) {
+ return 1;
+ }
+ if (WizardsRegistryReader.UNCATEGORIZED_WIZARD_CATEGORY.equals(id)) {
+ return 3;
+ }
+ if (WizardsRegistryReader.FULL_EXAMPLES_WIZARD_CATEGORY.equals(id)) {
+ return 4;
+ }
+ return 2;
+ }
+ return super.category(element);
+ }
+
+ /**
+ * Return true if this sorter is affected by a property change of propertyName on the specified element.
+ */
+ @Override
+ public boolean isSorterProperty(Object object, String propertyId) {
+ return propertyId.equals(IBasicPropertyConstants.P_TEXT);
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardNewPage.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardNewPage.java
new file mode 100644
index 0000000..e93ff36
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardNewPage.java
@@ -0,0 +1,727 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.commons.ui.team.wizards;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.jface.wizard.IWizardContainer2;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.dialogs.DialogUtil;
+import org.eclipse.ui.internal.dialogs.WizardActivityFilter;
+import org.eclipse.ui.internal.dialogs.WizardContentProvider;
+import org.eclipse.ui.internal.dialogs.WizardPatternFilter;
+import org.eclipse.ui.internal.dialogs.WizardTagFilter;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardNode;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * New wizard selection tab that allows the user to select a registered 'New' wizard to be launched.
+ */
+class NewRepositoryWizardNewPage implements ISelectionChangedListener {
+
+ // id constants
+ private static final String DIALOG_SETTING_SECTION_NAME = "NewWizardSelectionPage."; //$NON-NLS-1$
+
+ private final static int SIZING_LISTS_HEIGHT = 200;
+
+ private final static int SIZING_VIEWER_WIDTH = 300;
+
+ private final static String STORE_EXPANDED_CATEGORIES_ID = DIALOG_SETTING_SECTION_NAME
+ + "STORE_EXPANDED_CATEGORIES_ID"; //$NON-NLS-1$
+
+ private final static String STORE_SELECTED_ID = DIALOG_SETTING_SECTION_NAME + "STORE_SELECTED_ID"; //$NON-NLS-1$
+
+ private final NewRepositoryWizardSelectionPage page;
+
+ private FilteredTree filteredTree;
+
+ private WizardPatternFilter filteredTreeFilter;
+
+ //Keep track of the wizards we have previously selected
+ private final Hashtable selectedWizards = new Hashtable();
+
+ private IDialogSettings settings;
+
+ private Button showAllCheck;
+
+ private IWizardCategory wizardCategories;
+
+ private IWizardDescriptor[] primaryWizards;
+
+ private CLabel descImageCanvas;
+
+ private final Map imageTable = new HashMap();
+
+ private IWizardDescriptor selectedElement;
+
+ private final WizardActivityFilter filter = new WizardActivityFilter();
+
+ private boolean needShowAll;
+
+ private final boolean projectsOnly;
+
+ private final ViewerFilter projectFilter = new WizardTagFilter(new String[] { WorkbenchWizardElement.TAG_PROJECT });
+
+ /**
+ * Create an instance of this class
+ *
+ * @param mainPage
+ * @param wizardCategories
+ * @param primaryWizards
+ * @param projectsOnly
+ */
+ public NewRepositoryWizardNewPage(NewRepositoryWizardSelectionPage mainPage, IWizardCategory wizardCategories,
+ IWizardDescriptor[] primaryWizards, boolean projectsOnly) {
+ this.page = mainPage;
+ this.wizardCategories = wizardCategories;
+ this.primaryWizards = primaryWizards;
+ this.projectsOnly = projectsOnly;
+
+ trimPrimaryWizards();
+
+ if (this.primaryWizards.length > 0) {
+ if (allPrimary(wizardCategories)) {
+ this.wizardCategories = null; // dont bother considering the categories as all wizards are primary
+ needShowAll = false;
+ } else {
+ needShowAll = !allActivityEnabled(wizardCategories);
+ }
+ } else {
+ needShowAll = !allActivityEnabled(wizardCategories);
+ }
+ }
+
+ /**
+ * @param category
+ * the wizard category
+ * @return whether all of the wizards in the category are enabled via activity filtering
+ */
+ private boolean allActivityEnabled(IWizardCategory category) {
+ IWizardDescriptor[] wizards = category.getWizards();
+ for (IWizardDescriptor wizard : wizards) {
+ if (WorkbenchActivityHelper.filterItem(wizard)) {
+ return false;
+ }
+ }
+
+ IWizardCategory[] children = category.getCategories();
+ for (int i = 0; i < children.length; i++) {
+ if (!allActivityEnabled(children[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Remove all primary wizards that are not in the wizard collection
+ */
+ private void trimPrimaryWizards() {
+ ArrayList newPrimaryWizards = new ArrayList(primaryWizards.length);
+
+ if (wizardCategories == null) {
+ return;//No categories so nothing to trim
+ }
+
+ for (IWizardDescriptor primaryWizard : primaryWizards) {
+ if (wizardCategories.findWizard(primaryWizard.getId()) != null) {
+ newPrimaryWizards.add(primaryWizard);
+ }
+ }
+
+ primaryWizards = (WorkbenchWizardElement[]) newPrimaryWizards.toArray(new WorkbenchWizardElement[newPrimaryWizards.size()]);
+ }
+
+ /**
+ * @param category
+ * the wizard category
+ * @return whether all wizards in the category are considered primary
+ */
+ private boolean allPrimary(IWizardCategory category) {
+ IWizardDescriptor[] wizards = category.getWizards();
+ for (IWizardDescriptor wizard2 : wizards) {
+ IWizardDescriptor wizard = wizard2;
+ if (!isPrimary(wizard)) {
+ return false;
+ }
+ }
+
+ IWizardCategory[] children = category.getCategories();
+ for (int i = 0; i < children.length; i++) {
+ if (!allPrimary(children[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param wizard
+ * @return whether the given wizard is primary
+ */
+ private boolean isPrimary(IWizardDescriptor wizard) {
+ for (IWizardDescriptor primaryWizard : primaryWizards) {
+ if (primaryWizard.equals(wizard)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void activate() {
+ page.setDescription(WorkbenchMessages.NewWizardNewPage_description);
+ }
+
+ /**
+ * Create this tab's visual components
+ *
+ * @param parent
+ * Composite
+ * @return Control
+ */
+ protected Control createControl(Composite parent) {
+
+ Font wizardFont = parent.getFont();
+ // top level group
+ Composite outerContainer = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ outerContainer.setLayout(layout);
+
+ Label wizardLabel = new Label(outerContainer, SWT.NONE);
+ GridData data = new GridData(SWT.BEGINNING, SWT.FILL, false, true);
+ outerContainer.setLayoutData(data);
+ wizardLabel.setFont(wizardFont);
+ wizardLabel.setText(WorkbenchMessages.NewWizardNewPage_wizardsLabel);
+
+ Composite innerContainer = new Composite(outerContainer, SWT.NONE);
+ layout = new GridLayout(2, false);
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ innerContainer.setLayout(layout);
+ innerContainer.setFont(wizardFont);
+ data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ innerContainer.setLayoutData(data);
+
+ filteredTree = createFilteredTree(innerContainer);
+ createOptionsButtons(innerContainer);
+
+ createImage(innerContainer);
+
+ updateDescription(null);
+
+ // wizard actions pane...create SWT table directly to
+ // get single selection mode instead of multi selection.
+ restoreWidgetValues();
+
+ return outerContainer;
+ }
+
+ /**
+ * Create a new FilteredTree in the parent.
+ *
+ * @param parent
+ * the parent <code>Composite</code>.
+ * @since 3.0
+ */
+ protected FilteredTree createFilteredTree(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ composite.setLayout(layout);
+
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.widthHint = SIZING_VIEWER_WIDTH;
+ data.horizontalSpan = 2;
+ data.grabExcessHorizontalSpace = true;
+ data.grabExcessVerticalSpace = true;
+
+ boolean needsHint = DialogUtil.inRegularFontMode(parent);
+
+ //Only give a height hint if the dialog is going to be too small
+ if (needsHint) {
+ data.heightHint = SIZING_LISTS_HEIGHT;
+ }
+ composite.setLayoutData(data);
+
+ filteredTreeFilter = new WizardPatternFilter();
+ FilteredTree filterTree = new FilteredTree(composite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER,
+ filteredTreeFilter, true);
+
+ final TreeViewer treeViewer = filterTree.getViewer();
+ treeViewer.setContentProvider(new WizardContentProvider());
+ treeViewer.setLabelProvider(new WorkbenchLabelProvider());
+ treeViewer.setComparator(NewWizardCollectionComparator.INSTANCE);
+ treeViewer.addSelectionChangedListener(this);
+
+ ArrayList inputArray = new ArrayList();
+
+ for (IWizardDescriptor primaryWizard : primaryWizards) {
+ inputArray.add(primaryWizard);
+ }
+
+ boolean expandTop = false;
+
+ if (wizardCategories != null) {
+ if (wizardCategories.getParent() == null) {
+ IWizardCategory[] children = wizardCategories.getCategories();
+ for (IWizardCategory element : children) {
+ inputArray.add(element);
+ }
+ } else {
+ expandTop = true;
+ inputArray.add(wizardCategories);
+ }
+ }
+
+ // ensure the category is expanded. If there is a remembered expansion it will be set later.
+ if (expandTop) {
+ treeViewer.setAutoExpandLevel(2);
+ }
+
+ AdaptableList input = new AdaptableList(inputArray);
+
+ treeViewer.setInput(input);
+
+ filterTree.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+
+ treeViewer.getTree().setFont(parent.getFont());
+
+ treeViewer.addDoubleClickListener(new IDoubleClickListener() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
+ */
+ public void doubleClick(DoubleClickEvent event) {
+ IStructuredSelection s = (IStructuredSelection) event.getSelection();
+ selectionChanged(new SelectionChangedEvent(event.getViewer(), s));
+
+ Object element = s.getFirstElement();
+ if (treeViewer.isExpandable(element)) {
+ treeViewer.setExpandedState(element, !treeViewer.getExpandedState(element));
+ } else if (element instanceof WorkbenchWizardElement) {
+ page.advanceToNextPageOrFinish();
+ }
+ }
+ });
+
+ treeViewer.addFilter(filter);
+
+ if (projectsOnly) {
+ treeViewer.addFilter(projectFilter);
+ }
+
+ Dialog.applyDialogFont(filterTree);
+ return filterTree;
+ }
+
+ /**
+ * Create the Show All and help buttons at the bottom of the page.
+ *
+ * @param parent
+ * the parent composite on which to create the widgets
+ */
+ private void createOptionsButtons(Composite parent) {
+ if (needShowAll) {
+ showAllCheck = new Button(parent, SWT.CHECK);
+ GridData data = new GridData();
+ showAllCheck.setLayoutData(data);
+ showAllCheck.setFont(parent.getFont());
+ showAllCheck.setText(WorkbenchMessages.NewWizardNewPage_showAll);
+ showAllCheck.setSelection(false);
+
+ // flipping tabs updates the selected node
+ showAllCheck.addSelectionListener(new SelectionAdapter() {
+
+ // the delta of expanded elements between the last 'show all'
+ // and the current 'no show all'
+ private Object[] delta = new Object[0];
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean showAll = showAllCheck.getSelection();
+
+ if (showAll) {
+ filteredTree.getViewer().getControl().setRedraw(false);
+ } else {
+ // get the inital expanded elements when going from show
+ // all-> no show all.
+ // this isnt really the delta yet, we're just reusing
+ // the variable.
+ delta = filteredTree.getViewer().getExpandedElements();
+ }
+
+ try {
+ if (showAll) {
+ filteredTree.getViewer().resetFilters();
+ filteredTree.getViewer().addFilter(filteredTreeFilter);
+ if (projectsOnly) {
+ filteredTree.getViewer().addFilter(projectFilter);
+ }
+
+ // restore the expanded elements that were present
+ // in the last show all state but not in the 'no
+ // show all' state.
+ Object[] currentExpanded = filteredTree.getViewer().getExpandedElements();
+ Object[] expanded = new Object[delta.length + currentExpanded.length];
+ System.arraycopy(currentExpanded, 0, expanded, 0, currentExpanded.length);
+ System.arraycopy(delta, 0, expanded, currentExpanded.length, delta.length);
+ filteredTree.getViewer().setExpandedElements(expanded);
+ } else {
+ filteredTree.getViewer().addFilter(filter);
+ if (projectsOnly) {
+ filteredTree.getViewer().addFilter(projectFilter);
+ }
+ }
+ filteredTree.getViewer().refresh(false);
+
+ if (!showAll) {
+ // if we're going from show all -> no show all
+ // record the elements that were expanded in the
+ // 'show all' state but not the 'no show all' state
+ // (because they didnt exist).
+ Object[] newExpanded = filteredTree.getViewer().getExpandedElements();
+ List deltaList = new ArrayList(Arrays.asList(delta));
+ deltaList.removeAll(Arrays.asList(newExpanded));
+ }
+ } finally {
+ if (showAll) {
+ filteredTree.getViewer().getControl().setRedraw(true);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Create the image controls.
+ *
+ * @param parent
+ * the parent <code>Composite</code>.
+ * @since 3.0
+ */
+ private void createImage(Composite parent) {
+ descImageCanvas = new CLabel(parent, SWT.NONE);
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING);
+ data.widthHint = 0;
+ data.heightHint = 0;
+ descImageCanvas.setLayoutData(data);
+
+ // hook a listener to get rid of cached images.
+ descImageCanvas.addDisposeListener(new DisposeListener() {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
+ */
+ public void widgetDisposed(DisposeEvent e) {
+ for (Iterator i = imageTable.values().iterator(); i.hasNext();) {
+ ((Image) i.next()).dispose();
+ }
+ imageTable.clear();
+ }
+ });
+ }
+
+ /**
+ * Expands the wizard categories in this page's category viewer that were expanded last time this page was used. If
+ * a category that was previously expanded no longer exists then it is ignored.
+ */
+ protected void expandPreviouslyExpandedCategories() {
+ String[] expandedCategoryPaths = settings.getArray(STORE_EXPANDED_CATEGORIES_ID);
+ if (expandedCategoryPaths == null || expandedCategoryPaths.length == 0) {
+ return;
+ }
+
+ List categoriesToExpand = new ArrayList(expandedCategoryPaths.length);
+
+ if (wizardCategories != null) {
+ for (String expandedCategoryPath : expandedCategoryPaths) {
+ IWizardCategory category = wizardCategories.findCategory(new Path(expandedCategoryPath));
+ if (category != null) {
+ categoriesToExpand.add(category);
+ }
+ }
+ }
+
+ if (!categoriesToExpand.isEmpty()) {
+ filteredTree.getViewer().setExpandedElements(categoriesToExpand.toArray());
+ }
+
+ }
+
+ /**
+ * Returns the single selected object contained in the passed selectionEvent, or <code>null</code> if the
+ * selectionEvent contains either 0 or 2+ selected objects.
+ */
+ protected Object getSingleSelection(IStructuredSelection selection) {
+ return selection.size() == 1 ? selection.getFirstElement() : null;
+ }
+
+ /**
+ * Set self's widgets to the values that they held last time this page was open
+ */
+ protected void restoreWidgetValues() {
+ expandPreviouslyExpandedCategories();
+ selectPreviouslySelected();
+ }
+
+ /**
+ * Store the current values of self's widgets so that they can be restored in the next instance of self
+ */
+ public void saveWidgetValues() {
+ storeExpandedCategories();
+ storeSelectedCategoryAndWizard();
+ }
+
+ /**
+ * The user selected either new wizard category(s) or wizard element(s). Proceed accordingly.
+ *
+ * @param selectionEvent
+ * ISelection
+ */
+ public void selectionChanged(SelectionChangedEvent selectionEvent) {
+ page.setErrorMessage(null);
+ page.setMessage(null);
+
+ Object selectedObject = getSingleSelection((IStructuredSelection) selectionEvent.getSelection());
+
+ if (selectedObject instanceof IWizardDescriptor) {
+ if (selectedObject == selectedElement) {
+ return;
+ }
+ updateWizardSelection((IWizardDescriptor) selectedObject);
+ } else {
+ selectedElement = null;
+ page.setHasPages(false);
+ page.setCanFinishEarly(false);
+ page.selectWizardNode(null);
+ updateDescription(null);
+ }
+ }
+
+ /**
+ * Selects the wizard category and wizard in this page that were selected last time this page was used. If a
+ * category or wizard that was previously selected no longer exists then it is ignored.
+ */
+ protected void selectPreviouslySelected() {
+ String selectedId = settings.get(STORE_SELECTED_ID);
+ if (selectedId == null) {
+ return;
+ }
+
+ if (wizardCategories == null) {
+ return;
+ }
+
+ Object selected = wizardCategories.findCategory(new Path(selectedId));
+
+ if (selected == null) {
+ selected = wizardCategories.findWizard(selectedId);
+
+ if (selected == null) {
+ // if we cant find either a category or a wizard, abort.
+ return;
+ }
+ }
+
+ //work around for 62039
+ final StructuredSelection selection = new StructuredSelection(selected);
+ filteredTree.getViewer().getControl().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ filteredTree.getViewer().setSelection(selection, true);
+ }
+ });
+ }
+
+ /**
+ * Set the dialog store to use for widget value storage and retrieval
+ *
+ * @param settings
+ * IDialogSettings
+ */
+ public void setDialogSettings(IDialogSettings settings) {
+ this.settings = settings;
+ }
+
+ /**
+ * Stores the collection of currently-expanded categories in this page's dialog store, in order to recreate this
+ * page's state in the next instance of this page.
+ */
+ protected void storeExpandedCategories() {
+ Object[] expandedElements = filteredTree.getViewer().getExpandedElements();
+ List expandedElementPaths = new ArrayList(expandedElements.length);
+ for (int i = 0; i < expandedElements.length; ++i) {
+ if (expandedElements[i] instanceof IWizardCategory) {
+ expandedElementPaths.add(((IWizardCategory) expandedElements[i]).getPath().toString());
+ }
+ }
+ settings.put(STORE_EXPANDED_CATEGORIES_ID,
+ (String[]) expandedElementPaths.toArray(new String[expandedElementPaths.size()]));
+ }
+
+ /**
+ * Stores the currently-selected element in this page's dialog store, in order to recreate this page's state in the
+ * next instance of this page.
+ */
+ protected void storeSelectedCategoryAndWizard() {
+ Object selected = getSingleSelection((IStructuredSelection) filteredTree.getViewer().getSelection());
+
+ if (selected != null) {
+ if (selected instanceof IWizardCategory) {
+ settings.put(STORE_SELECTED_ID, ((IWizardCategory) selected).getPath().toString());
+ } else {
+ // else its a wizard
+ settings.put(STORE_SELECTED_ID, ((IWizardDescriptor) selected).getId());
+ }
+ }
+ }
+
+ /**
+ * Update the current description controls.
+ *
+ * @param selectedObject
+ * the new wizard
+ * @since 3.0
+ */
+ private void updateDescription(IWizardDescriptor selectedObject) {
+ String string = ""; //$NON-NLS-1$
+ if (selectedObject != null) {
+ string = selectedObject.getDescription();
+ }
+
+ page.setDescription(string);
+
+ if (hasImage(selectedObject)) {
+ ImageDescriptor descriptor = null;
+ if (selectedObject != null) {
+ descriptor = selectedObject.getDescriptionImage();
+ }
+
+ if (descriptor != null) {
+ GridData data = (GridData) descImageCanvas.getLayoutData();
+ data.widthHint = SWT.DEFAULT;
+ data.heightHint = SWT.DEFAULT;
+ Image image = (Image) imageTable.get(descriptor);
+ if (image == null) {
+ image = descriptor.createImage(false);
+ imageTable.put(descriptor, image);
+ }
+ descImageCanvas.setImage(image);
+ }
+ } else {
+ GridData data = (GridData) descImageCanvas.getLayoutData();
+ data.widthHint = 0;
+ data.heightHint = 0;
+ descImageCanvas.setImage(null);
+ }
+
+ descImageCanvas.getParent().layout(true);
+ filteredTree.getViewer().getTree().showSelection();
+
+ IWizardContainer container = page.getWizard().getContainer();
+ if (container instanceof IWizardContainer2) {
+ ((IWizardContainer2) container).updateSize();
+ }
+ }
+
+ /**
+ * Tests whether the given wizard has an associated image.
+ *
+ * @param selectedObject
+ * the wizard to test
+ * @return whether the given wizard has an associated image
+ */
+ private boolean hasImage(IWizardDescriptor selectedObject) {
+ if (selectedObject == null) {
+ return false;
+ }
+
+ if (selectedObject.getDescriptionImage() != null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param selectedObject
+ */
+ private void updateWizardSelection(IWizardDescriptor selectedObject) {
+ selectedElement = selectedObject;
+ WorkbenchWizardNode selectedNode;
+ if (selectedWizards.containsKey(selectedObject)) {
+ selectedNode = (WorkbenchWizardNode) selectedWizards.get(selectedObject);
+ } else {
+ selectedNode = new WorkbenchWizardNode(page, selectedObject) {
+ @Override
+ public IWorkbenchWizard createWizard() throws CoreException {
+ return wizardElement.createWizard();
+ }
+ };
+ selectedWizards.put(selectedObject, selectedNode);
+ }
+
+ page.setCanFinishEarly(selectedObject.canFinishEarly());
+ page.setHasPages(selectedObject.hasPages());
+ page.selectWizardNode(selectedNode);
+
+ updateDescription(selectedObject);
+ }
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardRegistry.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardRegistry.java
new file mode 100644
index 0000000..2f8be74
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardRegistry.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ * Tasktop Technologies - improvements for Mylyn
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.commons.ui.team.wizards;
+
+import org.eclipse.mylyn.internal.commons.ui.team.TeamUiPlugin;
+import org.eclipse.ui.internal.wizards.AbstractExtensionWizardRegistry;
+import org.eclipse.ui.internal.wizards.NewWizardRegistry;
+
+/**
+ * Based on {@link NewWizardRegistry}.
+ *
+ * @author Steffen Pingel
+ */
+public final class NewRepositoryWizardRegistry extends AbstractExtensionWizardRegistry {
+
+ private static NewRepositoryWizardRegistry singleton;
+
+ /**
+ * Return the singleton instance of this class.
+ *
+ * @return the singleton instance of this class
+ */
+ public static synchronized NewRepositoryWizardRegistry getInstance() {
+ if (singleton == null) {
+ singleton = new NewRepositoryWizardRegistry();
+ }
+ return singleton;
+ }
+
+ /**
+ * Private constructor.
+ */
+ private NewRepositoryWizardRegistry() {
+ }
+
+ @Override
+ protected String getExtensionPoint() {
+ return "newWizards"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected String getPlugin() {
+ return TeamUiPlugin.ID_PLUGIN;
+ }
+
+}
diff --git a/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardSelectionPage.java b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardSelectionPage.java
new file mode 100644
index 0000000..9383354
--- /dev/null
+++ b/stubs/org.eclipse.mylyn.commons.team/src/org/eclipse/mylyn/internal/commons/ui/team/wizards/NewRepositoryWizardSelectionPage.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.commons.ui.team.wizards;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardSelectionPage;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * New wizard selection tab that allows the user to either select a registered 'New' wizard to be launched, or to select
+ * a solution or projects to be retrieved from an available server. This page contains two visual tabs that allow the
+ * user to perform these tasks. Temporarily has two inner pages. The new format page is used if the system is currently
+ * aware of activity categories.
+ */
+class NewRepositoryWizardSelectionPage extends WorkbenchWizardSelectionPage {
+
+ private final IWizardCategory wizardCategories;
+
+ // widgets
+ private NewRepositoryWizardNewPage newResourcePage;
+
+ private final IWizardDescriptor[] primaryWizards;
+
+ private final boolean projectsOnly;
+
+ private boolean canFinishEarly = false, hasPages = true;
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param workbench
+ * the workbench
+ * @param selection
+ * the current selection
+ * @param root
+ * the wizard root element
+ * @param primary
+ * the primary wizard elements
+ * @param projectsOnly
+ * if only projects should be shown
+ */
+ public NewRepositoryWizardSelectionPage(IWorkbench workbench, IStructuredSelection selection, IWizardCategory root,
+ IWizardDescriptor[] primary, boolean projectsOnly) {
+ super("newWizardSelectionPage", workbench, selection, null, WorkbenchTriggerPoints.NEW_WIZARDS);//$NON-NLS-1$
+
+ setTitle(WorkbenchMessages.NewWizardSelectionPage_description);
+ wizardCategories = root;
+ primaryWizards = primary;
+ this.projectsOnly = projectsOnly;
+ }
+
+ /**
+ * Makes the next page visible.
+ */
+ public void advanceToNextPageOrFinish() {
+ if (canFlipToNextPage()) {
+ getContainer().showPage(getNextPage());
+ } else if (canFinishEarly()) {
+ if (getWizard().performFinish()) {
+ ((WizardDialog) getContainer()).close();
+ }
+ }
+ }
+
+ /**
+ * (non-Javadoc) Method declared on IDialogPage.
+ */
+ public void createControl(Composite parent) {
+ IDialogSettings settings = getDialogSettings();
+ newResourcePage = new NewRepositoryWizardNewPage(this, wizardCategories, primaryWizards, projectsOnly);
+ newResourcePage.setDialogSettings(settings);
+
+ Control control = newResourcePage.createControl(parent);
+ getWorkbench().getHelpSystem().setHelp(control, IWorkbenchHelpContextIds.NEW_WIZARD_SELECTION_WIZARD_PAGE);
+ setControl(control);
+ }
+
+ /**
+ * Since Finish was pressed, write widget values to the dialog store so that they will persist into the next
+ * invocation of this wizard page
+ */
+ protected void saveWidgetValues() {
+ newResourcePage.saveWidgetValues();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.IWizardPage#canFlipToNextPage()
+ */
+ @Override
+ public boolean canFlipToNextPage() {
+ // if the current page advertises that it does have pages then ask it via the super call
+ if (hasPages) {
+ return super.canFlipToNextPage();
+ }
+ return false;
+ }
+
+ /**
+ * Sets whether the selected wizard advertises that it does provide pages.
+ *
+ * @param newValue
+ * whether the selected wizard has pages
+ * @since 3.1
+ */
+ public void setHasPages(boolean newValue) {
+ hasPages = newValue;
+ }
+
+ /**
+ * Sets whether the selected wizard advertises that it can finish early.
+ *
+ * @param newValue
+ * whether the selected wizard can finish early
+ * @since 3.1
+ */
+ public void setCanFinishEarly(boolean newValue) {
+ canFinishEarly = newValue;
+ }
+
+ /**
+ * Answers whether the currently selected page, if any, advertises that it may finish early.
+ *
+ * @return whether the page can finish early
+ * @since 3.1
+ */
+ public boolean canFinishEarly() {
+ return canFinishEarly;
+ }
+}