diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ui/VcsBalloonProblemNotifier.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ui/VcsBalloonProblemNotifier.java
index 8adad110695a..e9d5c2e90bd7 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ui/VcsBalloonProblemNotifier.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ui/VcsBalloonProblemNotifier.java
@@ -15,7 +15,10 @@
*/
package com.intellij.openapi.vcs.ui;
+import com.intellij.notification.Notification;
import com.intellij.notification.NotificationGroup;
+import com.intellij.notification.NotificationListener;
+import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
@@ -23,11 +26,14 @@ import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.NamedRunnable;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.ui.awt.RelativePoint;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.util.concurrent.TimeUnit;
@@ -43,32 +49,37 @@ public class VcsBalloonProblemNotifier implements Runnable {
private final String myMessage;
private final MessageType myMessageType;
private final boolean myShowOverChangesView;
+ @Nullable private final NamedRunnable[] myNotificationListener;
public VcsBalloonProblemNotifier(@NotNull final Project project, @NotNull final String message, final MessageType messageType) {
- this(project, message, messageType, true);
+ this(project, message, messageType, true, null);
}
- public VcsBalloonProblemNotifier(@NotNull final Project project, @NotNull final String message, final MessageType messageType, boolean showOverChangesView) {
+ public VcsBalloonProblemNotifier(@NotNull final Project project, @NotNull final String message, final MessageType messageType, boolean showOverChangesView,
+ @Nullable final NamedRunnable[] notificationListener) {
myProject = project;
myMessage = message;
myMessageType = messageType;
myShowOverChangesView = showOverChangesView;
+ myNotificationListener = notificationListener;
}
- public static void showOverChangesView(@NotNull final Project project, @NotNull final String message, final MessageType type) {
- show(project, message, type, true);
+ public static void showOverChangesView(@NotNull final Project project, @NotNull final String message, final MessageType type,
+ final NamedRunnable... notificationListener) {
+ show(project, message, type, true, notificationListener);
}
public static void showOverVersionControlView(@NotNull final Project project, @NotNull final String message, final MessageType type) {
- show(project, message, type, false);
+ show(project, message, type, false, null);
}
- private static void show(final Project project, final String message, final MessageType type, final boolean showOverChangesView) {
+ private static void show(final Project project, final String message, final MessageType type, final boolean showOverChangesView,
+ @Nullable final NamedRunnable[] notificationListener) {
final Application application = ApplicationManager.getApplication();
if (application.isHeadlessEnvironment()) return;
final Runnable showErrorAction = new Runnable() {
public void run() {
- new VcsBalloonProblemNotifier(project, message, type, showOverChangesView).run();
+ new VcsBalloonProblemNotifier(project, message, type, showOverChangesView, notificationListener).run();
}
};
if (application.isDispatchThread()) {
@@ -80,7 +91,40 @@ public class VcsBalloonProblemNotifier implements Runnable {
}
public void run() {
- NOTIFICATION_GROUP.createNotification(myMessage, myMessageType).notify(myProject.isDefault() ? null : myProject);
+ final Notification notification;
+ if (myNotificationListener != null && myNotificationListener.length > 0) {
+ final NotificationType type = myMessageType.toNotificationType();
+ final StringBuilder sb = new StringBuilder(myMessage);
+ for (NamedRunnable runnable : myNotificationListener) {
+ final String name = runnable.toString();
+ sb.append("
").append(name).append("");
+ }
+ notification = NOTIFICATION_GROUP.createNotification(type.name(), sb.toString(), myMessageType.toNotificationType(),
+ new NotificationListener() {
+ @Override
+ public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
+ if (HyperlinkEvent.EventType.ACTIVATED.equals(event.getEventType())) {
+ if (myNotificationListener.length == 1) {
+ myNotificationListener[0].run();
+ } else {
+ final String description = event.getDescription();
+ if (description != null) {
+ for (NamedRunnable runnable : myNotificationListener) {
+ if (description.equals(runnable.toString())) {
+ runnable.run();
+ break;
+ }
+ }
+ }
+ }
+ notification.expire();
+ }
+ }
+ });
+ } else {
+ notification = NOTIFICATION_GROUP.createNotification(myMessage, myMessageType);
+ }
+ notification.notify(myProject.isDefault() ? null : myProject);
}
public static void showBalloonForComponent(@NotNull JComponent component, @NotNull final String message, final MessageType type,
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java
index 70fff2d294f6..1e823136398f 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.NamedRunnable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.impl.GenericNotifierImpl;
@@ -33,6 +34,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.ui.awt.RelativePoint;
+import com.intellij.util.Consumer;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -321,14 +323,37 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl() {
+ @Override
+ public void consume(String s) {
+ configuration.setConfigurationDirectory(s);
+ }
+ }, project, null);
+ }
+ });
+ }
+ }, ModalityState.NON_MODAL, project.getDisposed());
}
return false; /// !!!! any exception means user should be notified that authorization failed
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties
index 9db0ae7d40f8..ba6e615f19ff 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties
@@ -154,6 +154,7 @@ status.group.name.locked=Locked
checkbox.configure.use.system.default.configuration.directory=&Use system default Subversion configuration directory
label.configuration.configuration.directory=Subversion configuration &directory:
dialog.title.select.configuration.directory=Select Configuration Directory
+action.title.select.configuration.directory=Change Configuration Directory
dialog.description.select.configuration.directory=Select Subversion configuration directory or create new one
button.text.clear.authentication.cache=&Clear Auth Cache
label.text.delete.stored.credentials=Delete all stored credentials for 'http', 'svn' and 'svn+ssh' protocols
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java
index f2eff8947c0e..2a07a18bccd1 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java
@@ -32,8 +32,11 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.ui.MultiLineTooltipUI;
+import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.config.ConfigureProxiesListener;
import javax.swing.*;
@@ -93,37 +96,21 @@ public class SvnConfigurable implements Configurable {
myClearAuthButton.addActionListener(new ActionListener(){
public void actionPerformed(final ActionEvent e) {
- String path = myConfigurationDirectoryText.getText();
- if (path != null) {
- int result = Messages.showYesNoDialog(myComponent, SvnBundle.message("confirmation.text.delete.stored.authentication.information"),
- SvnBundle.message("confirmation.title.clear.authentication.cache"),
- Messages.getWarningIcon());
- if (result == 0) {
- SvnConfiguration.RUNTIME_AUTH_CACHE.clear();
- SvnConfiguration.getInstance(myProject).clearAuthenticationDirectory(myProject);
- }
- }
-
+ clearAuthenticationCache(myProject, myComponent, myConfigurationDirectoryText.getText());
}
});
- final FileChooserDescriptor descriptor = createFileDescriptor();
myConfigurationDirectoryText.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@NonNls String path = myConfigurationDirectoryText.getText().trim();
- path = "file://" + path.replace(File.separatorChar, '/');
- VirtualFile root = VirtualFileManager.getInstance().findFileByUrl(path);
-
- String oldValue = PropertiesComponent.getInstance().getValue("FileChooser.showHiddens");
- PropertiesComponent.getInstance().setValue("FileChooser.showHiddens", Boolean.TRUE.toString());
- VirtualFile file = FileChooser.chooseFile(descriptor, myComponent, myProject, root);
- PropertiesComponent.getInstance().setValue("FileChooser.showHiddens", oldValue);
- if (file == null) {
- return;
- }
- myConfigurationDirectoryText.setText(file.getPath().replace('/', File.separatorChar));
+ selectConfigirationDirectory(path, new Consumer() {
+ @Override
+ public void consume(String s) {
+ myConfigurationDirectoryText.setText(s);
+ }
+ }, myProject, myComponent);
}
});
myConfigurationDirectoryText.setEditable(false);
@@ -150,6 +137,42 @@ public class SvnConfigurable implements Configurable {
myJavaHLInfo.setVisible(internal);
}
+ public static void selectConfigirationDirectory(@NotNull String path, @NotNull final Consumer dirConsumer,
+ final Project project, @Nullable final Component component) {
+ final FileChooserDescriptor descriptor = createFileDescriptor();
+ path = "file://" + path.replace(File.separatorChar, '/');
+ VirtualFile root = VirtualFileManager.getInstance().findFileByUrl(path);
+
+ String oldValue = PropertiesComponent.getInstance().getValue("FileChooser.showHiddens");
+ PropertiesComponent.getInstance().setValue("FileChooser.showHiddens", Boolean.TRUE.toString());
+ VirtualFile file = FileChooser.chooseFile(descriptor, component, project, root);
+ PropertiesComponent.getInstance().setValue("FileChooser.showHiddens", oldValue);
+ if (file == null) {
+ return;
+ }
+ final String resultPath = file.getPath().replace('/', File.separatorChar);
+ dirConsumer.consume(resultPath);
+ }
+
+ public static void clearAuthenticationCache(@NotNull final Project project, final Component component, final String configDirPath) {
+ if (configDirPath != null) {
+ int result;
+ if (component == null) {
+ result = Messages.showYesNoDialog(project, SvnBundle.message("confirmation.text.delete.stored.authentication.information"),
+ SvnBundle.message("confirmation.title.clear.authentication.cache"),
+ Messages.getWarningIcon());
+ } else {
+ result = Messages.showYesNoDialog(component, SvnBundle.message("confirmation.text.delete.stored.authentication.information"),
+ SvnBundle.message("confirmation.title.clear.authentication.cache"),
+ Messages.getWarningIcon());
+ }
+ if (result == 0) {
+ SvnConfiguration.RUNTIME_AUTH_CACHE.clear();
+ SvnConfiguration.getInstance(project).clearAuthenticationDirectory(project);
+ }
+ }
+ }
+
private static FileChooserDescriptor createFileDescriptor() {
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
descriptor.setShowFileSystemRoots(true);
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java
index 4a2d3639c9cb..e4e98fde84aa 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java
@@ -488,7 +488,7 @@ public class SvnConfiguration implements PersistentStateComponent {
public static class AuthStorage implements ISVNAuthenticationStorage {
- private final Map myStorage = new Hashtable();
+ private final Map myStorage = Collections.synchronizedMap(new HashMap());
public void clear() {
myStorage.clear();