diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index 025bbfbe206b..fe90cf55f562 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -62,7 +62,9 @@ import org.jetbrains.jps.server.Server; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.RunnableFuture; @@ -73,8 +75,10 @@ import java.util.concurrent.TimeUnit; * Date: 9/6/11 */ public class CompileServerManager implements ApplicationComponent{ - private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.JpsServerManager"); + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompileServerManager"); private static final String COMPILE_SERVER_SYSTEM_ROOT = "compile-server"; + private static final String LOGGER_CONFIG = "log.xml"; + private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml"; private volatile OSProcessHandler myProcessHandler; private final File mySystemDirectory; private volatile CompileServerClient myClient = new CompileServerClient(); @@ -272,7 +276,7 @@ public class CompileServerManager implements ApplicationComponent{ return true; } }; - final Ref serverStartMessage = new Ref(null); + final StringBuilder serverStartMessage = new StringBuilder(); final Semaphore semaphore = new Semaphore(); semaphore.down(); processHandler.addProcessListener(new ProcessAdapter() { @@ -298,8 +302,11 @@ public class CompileServerManager implements ApplicationComponent{ if (text != null) { if (text.contains(Server.SERVER_SUCCESS_START_MESSAGE) || text.contains(Server.SERVER_ERROR_START_MESSAGE)) { processHandler.removeProcessListener(this); - serverStartMessage.set(text); } + if (serverStartMessage.length() > 0) { + serverStartMessage.append("\n"); + } + serverStartMessage.append(text); } } finally { @@ -311,8 +318,8 @@ public class CompileServerManager implements ApplicationComponent{ processHandler.startNotify(); semaphore.waitFor(); - final String startupMsg = serverStartMessage.get(); - if (startupMsg == null || !startupMsg.contains(Server.SERVER_SUCCESS_START_MESSAGE)) { + final String startupMsg = serverStartMessage.toString(); + if (!startupMsg.contains(Server.SERVER_SUCCESS_START_MESSAGE)) { throw new Exception("Server startup failed: " + startupMsg); } @@ -462,14 +469,43 @@ public class CompileServerManager implements ApplicationComponent{ final File workDirectory = new File(mySystemDirectory, COMPILE_SERVER_SYSTEM_ROOT); workDirectory.mkdirs(); + ensureLogConfigExists(workDirectory); cmdLine.addParameter(FileUtil.toSystemIndependentName(workDirectory.getPath())); cmdLine.setWorkDirectory(workDirectory); + return cmdLine.createProcess(); } + private static void ensureLogConfigExists(File workDirectory) { + final File logConfig = new File(workDirectory, LOGGER_CONFIG); + if (!logConfig.exists()) { + FileUtil.createIfDoesntExist(logConfig); + try { + final InputStream in = Server.class.getResourceAsStream("/" + DEFAULT_LOGGER_CONFIG); + if (in != null) { + try { + final FileOutputStream out = new FileOutputStream(logConfig); + try { + FileUtil.copy(in, out); + } + finally { + out.close(); + } + } + finally { + in.close(); + } + } + } + catch (IOException e) { + LOG.error(e); + } + } + } + public void shutdownServer() { shutdownServer(myClient, myProcessHandler); } diff --git a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java index 3239824d4ada..5097256ac559 100644 --- a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java +++ b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java @@ -140,6 +140,7 @@ public class JavaExecutionUtil { @Nullable public static PsiClass findMainClass(final Project project, final String mainClassName, final GlobalSearchScope scope) { + if (project.isDefault()) return null; final PsiManager psiManager = PsiManager.getInstance(project); final String shortName = StringUtil.getShortName(mainClassName); final String packageName = StringUtil.getPackageName(mainClassName); diff --git a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java index 91f0f6be7c79..0c0abdce08d1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java @@ -16,14 +16,16 @@ package com.intellij.psi.impl.file; import com.intellij.ide.projectView.ProjectView; -import com.intellij.ide.projectView.impl.PackageViewPane; -import com.intellij.ide.projectView.impl.ProjectRootsUtil; -import com.intellij.ide.projectView.impl.nodes.PackageElement; +import com.intellij.ide.projectView.impl.ProjectViewPane; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.undo.GlobalUndoableAction; import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.vfs.VfsUtil; @@ -31,9 +33,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.psi.NonClasspathClassFinder; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiPackage; +import com.intellij.psi.*; import com.intellij.psi.impl.PackagePrefixElementFinder; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiModificationTracker; @@ -137,18 +137,36 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation @Override public void run() { final ProjectView projectView = ProjectView.getInstance(project); - projectView.changeView(PackageViewPane.ID); - final PsiDirectory[] directories = psiPackage.getDirectories(); - final VirtualFile firstDir = directories[0].getVirtualFile(); - final boolean isLibraryRoot = ProjectRootsUtil.isLibraryRoot(firstDir, project); - - final Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(firstDir); - final PackageElement packageElement = new PackageElement(module, psiPackage, isLibraryRoot); - projectView.getProjectViewPaneById(PackageViewPane.ID).select(packageElement, firstDir, requestFocus); + PsiDirectory[] directories = suggestMostAppropriateDirectories(psiPackage); + if (directories.length == 0) return; + projectView.getProjectViewPaneById(ProjectViewPane.ID).select(directories[0], directories[0].getVirtualFile(), requestFocus); } }); } + private static PsiDirectory[] suggestMostAppropriateDirectories(PsiPackage psiPackage) { + final Project project = psiPackage.getProject(); + PsiDirectory[] directories = null; + final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); + if (editor != null) { + final Document document = editor.getDocument(); + final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); + if (psiFile != null) { + final Module module = ModuleUtil.findModuleForPsiElement(psiFile); + if (module != null) { + directories = psiPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module)); + } else { + directories = psiPackage.getDirectories(GlobalSearchScope.notScope(GlobalSearchScope.projectScope(project))); + } + } + } + + if (directories == null || directories.length == 0) { + directories = psiPackage.getDirectories(); + } + return directories; + } + @Override public boolean packagePrefixExists(PsiPackage psiPackage) { return PackagePrefixElementFinder.getInstance(psiPackage.getProject()).packagePrefixExists(psiPackage.getQualifiedName()); diff --git a/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java b/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java index 4ad2f7edc851..517f2a226ff4 100644 --- a/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java +++ b/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java @@ -131,11 +131,13 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText } }); + myAddPatternButton.setEnabled(!myProject.isDefault()); myAddPatternButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { addPatternFilter(); } }); + myAddClassButton.setEnabled(!myProject.isDefault()); myAddClassButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { addClassFilter(); diff --git a/jps/jps-builders/src/defaultLogConfig.xml b/jps/jps-builders/src/defaultLogConfig.xml new file mode 100644 index 000000000000..c57f244f5c1c --- /dev/null +++ b/jps/jps-builders/src/defaultLogConfig.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java index a5c2d64754c0..8cdde853f06c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java @@ -34,6 +34,7 @@ public class Server { private static final int MAX_SIMULTANEOUS_BUILD_SESSIONS = Math.max(2, Runtime.getRuntime().availableProcessors()); public static final String SERVER_SUCCESS_START_MESSAGE = "Compile Server started successfully. Listening on port: "; public static final String SERVER_ERROR_START_MESSAGE = "Error starting Compile Server: "; + private static final String LOG_FILE_NAME = "log.xml"; private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("compile-server"); private final ChannelFactory myChannelFactory; @@ -98,70 +99,14 @@ public class Server { } final Server server = new Server(systemDir); - - DOMConfigurator.configure("log.xml"); - - Logger.setFactory(new Logger.Factory() { - @Override - public Logger getLoggerInstance(String category) { - final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(category); - - return new Logger(){ - @Override - public boolean isDebugEnabled() { - return logger.isDebugEnabled(); - } - - @Override - public void debug(@NonNls String message) { - logger.debug(message); - } - - @Override - public void debug(@Nullable Throwable t) { - logger.debug("", t); - } - - @Override - public void debug(@NonNls String message, @Nullable Throwable t) { - logger.debug(message, t); - } - - @Override - public void error(@NonNls String message, @Nullable Throwable t, @NonNls String... details) { - logger.debug(message, t); - } - - @Override - public void info(@NonNls String message) { - logger.info(message); - } - - @Override - public void info(@NonNls String message, @Nullable Throwable t) { - logger.info(message, t); - } - - @Override - public void warn(@NonNls String message, @Nullable Throwable t) { - logger.warn(message, t); - } - - @Override - public void setLevel(Level level) { - logger.setLevel(level); - } - }; - } - }); - - server.start(port); Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") { public void run() { server.stop(); } }); + initLoggers(); + server.start(port); ServerState.getInstance().setKeepTempCachesInMemory(System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null); System.out.println("Server classpath: " + System.getProperty("java.class.path")); @@ -174,6 +119,66 @@ public class Server { } } + private static void initLoggers() { + if (new File(LOG_FILE_NAME).exists()) { + DOMConfigurator.configure(LOG_FILE_NAME); + } + + Logger.setFactory(new Logger.Factory() { + @Override + public Logger getLoggerInstance(String category) { + final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(category); + + return new Logger() { + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public void debug(@NonNls String message) { + logger.debug(message); + } + + @Override + public void debug(@Nullable Throwable t) { + logger.debug("", t); + } + + @Override + public void debug(@NonNls String message, @Nullable Throwable t) { + logger.debug(message, t); + } + + @Override + public void error(@NonNls String message, @Nullable Throwable t, @NonNls String... details) { + logger.debug(message, t); + } + + @Override + public void info(@NonNls String message) { + logger.info(message); + } + + @Override + public void info(@NonNls String message, @Nullable Throwable t) { + logger.info(message, t); + } + + @Override + public void warn(@NonNls String message, @Nullable Throwable t) { + logger.warn(message, t); + } + + @Override + public void setLevel(Level level) { + logger.setLevel(level); + } + }; + } + }); + } + private class ChannelRegistrar extends SimpleChannelUpstreamHandler { public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { myAllOpenChannels.add(e.getChannel()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java index ee1818ffa845..179f975b6ee9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java @@ -112,6 +112,7 @@ public class AutoPopupController implements Disposable { Runnable request = new Runnable() { @Override public void run() { + if (myProject.isDefault()) return; CompletionAutoPopupHandler.runLaterWithCommitted(myProject, editor.getDocument(), new Runnable() { @Override public void run() { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java b/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java index fde61b0ec370..0fc43b2ee49a 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java @@ -15,7 +15,6 @@ */ package com.intellij.ide.actions; -import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -26,8 +25,6 @@ import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.annotations.Nullable; public abstract class UndoRedoAction extends DumbAwareAction { public UndoRedoAction() { @@ -56,7 +53,7 @@ public abstract class UndoRedoAction extends DumbAwareAction { } UndoManager undoManager = getUndoManager(editor, dataContext); - presentation.setEnabled(isAvailable(editor, undoManager)); + presentation.setEnabled(undoManager != null && isAvailable(editor, undoManager)); Pair pair = getActionNameAndDescription(editor, undoManager); diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index feeabc285a35..88e5bf57d91c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -50,6 +50,7 @@ import com.intellij.openapi.project.impl.ProjectManagerImpl; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.ProgressIndicatorEx; @@ -78,6 +79,7 @@ import java.lang.reflect.Method; import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"}) public class ApplicationImpl extends ComponentManagerImpl implements ApplicationEx { @@ -117,6 +119,8 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application private final AtomicBoolean mySaveSettingsIsInProgress = new AtomicBoolean(false); @SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"}) private static final int ourDumpThreadsOnLongWriteActionWaiting = Integer.getInteger("dump.threads.on.long.write.action.waiting", 0); + private final AtomicInteger myAliveThreads = new AtomicInteger(0); + private static final int ourReasonableThreadPoolSize = Registry.intValue("core.pooled.threads"); private final ExecutorService ourThreadExecutorsService = new ThreadPoolExecutor( 3, @@ -127,6 +131,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application new ThreadFactory() { int i; public Thread newThread(Runnable r) { + final int count = myAliveThreads.incrementAndGet(); final Thread thread = new Thread(r, "ApplicationImpl pooled thread "+i++) { public void interrupt() { if (LOG.isDebugEnabled()) { @@ -144,9 +149,10 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application LOG.debug("Worker exits due to exception", t); } } + myAliveThreads.decrementAndGet(); } }; - if (ApplicationInfoImpl.getShadowInstance().isEAP() && i > 10) { + if (ApplicationInfoImpl.getShadowInstance().isEAP() && count > ourReasonableThreadPoolSize) { LOG.info("Not enough pooled threads; creating one at:", new Throwable()); } thread.setPriority(Thread.NORM_PRIORITY - 1); diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index f27367c763ef..7cd59ea6ff8e 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -181,6 +181,7 @@ dump.threads.on.empty.lookup.description=Whether IDEA should issue a thread dump file.structure.tree.mode=true -python.new.style.resolve=false disable.toolwindow.overlayed=true -disable.toolwindow.overlayed.description=Disable transparent toolwindow stripes \ No newline at end of file +disable.toolwindow.overlayed.description=Disable transparent toolwindow stripes + +core.pooled.threads=20 diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index df8c93c5bafa..cba4acd503cf 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -128,10 +128,18 @@ - - + + + + diff --git a/plugins/git4idea/src/git4idea/MessageManager.java b/plugins/git4idea/src/git4idea/MessageManager.java new file mode 100644 index 000000000000..02d9f4b1efa4 --- /dev/null +++ b/plugins/git4idea/src/git4idea/MessageManager.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Kirill Likhodedov + */ +public class MessageManager { + + public static MessageManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, MessageManager.class); + } + + public static int showYesNoDialog(Project project, String description, String title, String yesText, String noText, @Nullable Icon icon) { + return getInstance(project).doShowYesNoDialog(project, description, title, yesText, noText, icon); + } + + @SuppressWarnings("MethodMayBeStatic") + protected int doShowYesNoDialog(Project project, String description, String title, String yesText, String noText, @Nullable Icon icon) { + return Messages.showYesNoDialog(project, description, title, yesText, noText, icon); + } +} diff --git a/plugins/git4idea/src/git4idea/NotificationManager.java b/plugins/git4idea/src/git4idea/NotificationManager.java new file mode 100644 index 000000000000..93ad28e5b8cd --- /dev/null +++ b/plugins/git4idea/src/git4idea/NotificationManager.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Kirill Likhodedov + */ +public class NotificationManager { + + @NotNull private final Project myProject; + + public NotificationManager(@NotNull Project project) { + myProject = project; + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, + @NotNull NotificationType type, @Nullable NotificationListener listener) { + createNotification(notificationGroup, title, message, type, listener).notify(myProject); + } + + public static NotificationManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, NotificationManager.class); + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type) { + notify(notificationGroup, title, message, type, null); + } + + protected static Notification createNotification(NotificationGroup notificationGroup, String title, String message, + NotificationType type, NotificationListener listener) { + return notificationGroup.createNotification(title, message, type, listener); + } + +} diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java b/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java index 6fdd7bd4dce9..74d90b17b641 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java @@ -21,6 +21,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.components.JBLabel; import com.intellij.util.ArrayUtil; +import git4idea.DialogManager; import git4idea.GitBranch; import git4idea.history.browser.GitCommit; import git4idea.i18n.GitBundle; @@ -76,7 +77,7 @@ public class GitBranchIsNotFullyMergedDialog extends DialogWrapper { @NotNull List mergedToBranches, @Nullable String currentBranch) { GitBranchIsNotFullyMergedDialog dialog = new GitBranchIsNotFullyMergedDialog(project, commits, branchToDelete, currentBranch, mergedToBranches); - dialog.show(); + DialogManager.getInstance(project).showDialog(dialog); return dialog.isOK(); } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index ae3b8a239dab..3a4177a529d2 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -24,10 +24,12 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; +import git4idea.GitUtil; import git4idea.GitVcs; +import git4idea.MessageManager; +import git4idea.NotificationManager; import git4idea.merge.GitConflictResolver; import git4idea.repo.GitRepository; -import git4idea.GitUtil; import org.jetbrains.annotations.NotNull; import javax.swing.event.HyperlinkEvent; @@ -43,7 +45,10 @@ import java.util.concurrent.atomic.AtomicBoolean; */ abstract class GitBranchOperation { - private static final String UNMERGED_FILES_ERROR_TITLE = "Can't checkout because of unmerged files"; + static final String UNMERGED_FILES_ERROR_TITLE = "Can't checkout because of unmerged files"; + static final String UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION = + "You have to resolve all merge conflicts before checkout.
" + + "After resolving conflicts you also probably would want to commit your files to the current branch."; @NotNull protected final Project myProject; @NotNull private final Collection myRepositories; @@ -129,7 +134,7 @@ abstract class GitBranchOperation { } protected void notifySuccess() { - GitVcs.NOTIFICATION_GROUP_ID.createNotification(getSuccessMessage(), NotificationType.INFORMATION).notify(myProject); + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", getSuccessMessage(), NotificationType.INFORMATION); } /** @@ -151,7 +156,7 @@ abstract class GitBranchOperation { public void run() { String description = message + getRollbackProposal(); ok.set(Messages.OK == - Messages.showYesNoDialog(myProject, description, title, "Rollback", "Don't rollback", Messages.getErrorIcon())); + MessageManager.showYesNoDialog(myProject, description, title, "Rollback", "Don't rollback", Messages.getErrorIcon())); } }); if (ok.get()) { @@ -164,7 +169,7 @@ abstract class GitBranchOperation { } protected void notifyError(@NotNull String title, @NotNull String message) { - GitVcs.IMPORTANT_ERROR_NOTIFICATION.createNotification(title, message, NotificationType.ERROR, null).notify(myProject); + NotificationManager.getInstance(myProject).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, title, message, NotificationType.ERROR); } @NotNull @@ -192,8 +197,7 @@ abstract class GitBranchOperation { String description = "You have to resolve all merge conflicts before checkout.
" + getRollbackProposal(); // suppressing: this message looks ugly if capitalized by words //noinspection DialogTitleCapitalization - ok.set(Messages.OK == Messages.showYesNoDialog(myProject, description, UNMERGED_FILES_ERROR_TITLE, "Rollback", "Don't rollback", - Messages.getErrorIcon())); + ok.set(Messages.OK == MessageManager.showYesNoDialog(myProject, description, UNMERGED_FILES_ERROR_TITLE, "Rollback", "Don't rollback", Messages.getErrorIcon())); } }); if (ok.get()) { @@ -203,9 +207,8 @@ abstract class GitBranchOperation { private void showUnmergedFilesNotification() { String title = UNMERGED_FILES_ERROR_TITLE; - String description = "You have to resolve all merge conflicts before checkout.
" + - "After resolving conflicts you also probably would want to commit your files to the current branch."; - GitVcs.IMPORTANT_ERROR_NOTIFICATION.createNotification(title, description, NotificationType.ERROR, new NotificationListener() { + String description = UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION; + NotificationManager.getInstance(myProject).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, title, description, NotificationType.ERROR, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equals("resolve")) { GitConflictResolver.Params params = new GitConflictResolver.Params(). @@ -214,7 +217,7 @@ abstract class GitBranchOperation { new GitConflictResolver(myProject, GitUtil.getRoots(getRepositories()), params).merge(); } } - }).notify(myProject); + }); } } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index c9bc96210729..392554efbcf8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -23,14 +23,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ui.UIUtil; import git4idea.GitExecutionException; import git4idea.GitVcs; import git4idea.commands.Git; import git4idea.history.GitHistoryUtils; import git4idea.history.browser.GitCommit; -import git4idea.merge.GitConflictResolver; import git4idea.repo.GitRepository; import git4idea.ui.branch.GitBranchUiUtil; import git4idea.ui.branch.GitCompareBranchesDialog; @@ -125,15 +123,6 @@ public final class GitBranchOperationsProcessor { new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranch(), indicator).execute(); } - - @NotNull - static GitConflictResolver prepareConflictResolverForUnmergedFilesBeforeCheckout(Project project, Collection roots) { - GitConflictResolver.Params params = new GitConflictResolver.Params(). - setMergeDescription("The following files have unresolved conflicts. You need to resolve them before checking out."). - setErrorNotificationTitle("Can't create new branch"); - return new GitConflictResolver(project, roots, params); - } - /** * Creates and checks out a new local branch starting from the given reference: * {@code git checkout -b }.
diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index b0c3403070f0..53fbe2b7397d 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -38,6 +38,7 @@ import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcsUtil.VcsUtil; +import git4idea.DialogManager; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.commands.*; @@ -206,7 +207,7 @@ public class GitCheckoutOperation extends GitBranchOperation { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - dialog.show(); + DialogManager.getInstance(myProject).showDialog(dialog); } }); @@ -274,7 +275,7 @@ public class GitCheckoutOperation extends GitBranchOperation { catch (VcsException e) { // ignoring the exception: this is not fatal if we won't collect such a diff from other repositories. // At worst, use will get double dialog proposing the smart checkout. - LOG.warn(String.format("Couldn't collect diff between %s and %s in %s", myPreviousBranch, myStartPointReference, repository.getRoot())); + LOG.warn(String.format("Couldn't collect diff between %s and %s in %s", myPreviousBranch, myStartPointReference, repository.getRoot()), e); } } return changes; diff --git a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java index de968d2f59b8..f281e4a1f718 100644 --- a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java @@ -22,6 +22,7 @@ import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.components.JBLabel; import com.intellij.util.ui.UIUtil; +import git4idea.DialogManager; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -49,7 +50,7 @@ class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { @Override public void run() { GitWouldBeOverwrittenByCheckoutDialog dialog = new GitWouldBeOverwrittenByCheckoutDialog(project, changes); - dialog.show(); + DialogManager.getInstance(project).showDialog(dialog); ok.set(dialog.isOK()); } }); diff --git a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties index 28c376b41430..241557ad2493 100644 --- a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties +++ b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties @@ -493,7 +493,7 @@ executable.error.title = Git executable problem executable.error.description = Git couldn't be started. Probably the path to Git executable is not valid. Fix it. git.commit.message.empty=Please specify commit message -git.commit.message.empty.title=Commit message is empty +git.commit.message.empty.title=Commit Message Is Empty git.executable.notification.title=Can't start Git git.executable.notification.description=Probably the path to Git executable is not valid. Fix it. diff --git a/plugins/git4idea/src/git4idea/repo/GitRepository.java b/plugins/git4idea/src/git4idea/repo/GitRepository.java index 95213930b1b6..b3d88b4b5efc 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepository.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepository.java @@ -201,7 +201,7 @@ public final class GitRepository implements Disposable { * Returns the full-functional instance of GitRepository - with UntrackedFilesHolder and GitRepositoryUpdater. * This is used for repositories registered in project, and should be optained via {@link GitRepositoryManager}. */ - static GitRepository getFullInstance(@NotNull VirtualFile root, @NotNull Project project, @NotNull Disposable parentDisposable) { + public static GitRepository getFullInstance(@NotNull VirtualFile root, @NotNull Project project, @NotNull Disposable parentDisposable) { GitRepository repository = new GitRepository(root, project, parentDisposable); repository.myUntrackedFilesHolder.setupVfsListener(project); repository.setupUpdater(); diff --git a/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java b/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java index 99ab54cb9525..1ddab094a1fd 100644 --- a/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java +++ b/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitVcs; +import git4idea.NotificationManager; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -48,7 +49,7 @@ public class UntrackedFilesNotifier { final String notificationDesc = createUntrackedFilesOverwrittenDescription(operation, false); final String dialogDesc = createUntrackedFilesOverwrittenDescription(operation, true); - GitVcs.IMPORTANT_ERROR_NOTIFICATION.createNotification(notificationTitle, notificationDesc, NotificationType.ERROR, new NotificationListener() { + NotificationManager.getInstance(project).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, notificationTitle, notificationDesc, NotificationType.ERROR, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { SelectFilesDialog dlg = new SelectFilesDialog(project, new ArrayList(untrackedFiles), dialogDesc, null, false, false) { @Override protected Action[] createActions() { @@ -58,8 +59,7 @@ public class UntrackedFilesNotifier { dlg.setTitle("Untracked Files Preventing " + StringUtil.capitalize(operation)); dlg.show(); } - }).notify(project); - + }); } public static String createUntrackedFilesOverwrittenDescription(@NotNull final String operation, boolean filesAreShown) { diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java new file mode 100644 index 000000000000..d9b6bc5a21d3 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -0,0 +1,549 @@ +package git4idea.branch; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsConfiguration; +import com.intellij.openapi.vcs.VcsShowConfirmationOption; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.AbstractVcsTestCase; +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; +import com.intellij.testFramework.fixtures.TempDirTestFixture; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcsUtil.VcsUtil; +import git4idea.GitBranch; +import git4idea.GitVcs; +import git4idea.repo.GitRepository; +import git4idea.test.GitTestScenarioGenerator; +import git4idea.test.GitTestUtil; +import git4idea.test.TestMessageManager; +import git4idea.test.TestNotificationManager; +import git4idea.tests.TestDialogHandler; +import git4idea.tests.TestDialogManager; +import git4idea.util.UntrackedFilesNotifier; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; + +import static git4idea.test.GitExec.*; +import static org.testng.Assert.*; + +/** + * @author Kirill Likhodedov + */ +public class GitBranchOperationsTest extends AbstractVcsTestCase { + + private static final String NEW_BRANCH = "new_branch"; + private static final String MASTER = "master"; + + private Collection myRepositories; + private GitRepository myUltimate; + private GitRepository myCommunity; + private GitRepository myContrib; + + private TestMessageManager myMessageManager; + private TestNotificationManager myNotificationManager; + private TestDialogManager myDialogManager; + + private TempDirTestFixture myTempDirFixture; + + @BeforeMethod + public void setup() throws Exception { + final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory(); + myTempDirFixture = fixtureFactory.createTempDirTestFixture(); + myTempDirFixture.setUp(); + + final File projectDir = new File(myTempDirFixture.getTempDirPath(), "ultimate"); + assertTrue(projectDir.mkdir()); + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + try { + initProject(projectDir); + initRepositories(VcsUtil.getVirtualFile(projectDir)); + } + catch (Exception e) { + throw new RuntimeException("Exception initializing the test", e); + } + } + }); + + GitVcs vcs = GitVcs.getInstance(myProject); + assertNotNull(vcs); + myTraceClient = true; + doActionSilently(VcsConfiguration.StandardConfirmation.ADD); + doActionSilently(VcsConfiguration.StandardConfirmation.REMOVE); + + myDialogManager = GitTestUtil.registerDialogManager(myProject); + myNotificationManager = GitTestUtil.registerNotificationManager(myProject); + myMessageManager = GitTestUtil.registerMessageManager(myProject); + + createAddCommit(myUltimate, "a"); + createAddCommit(myCommunity, "a"); + createAddCommit(myContrib, "a"); + + myUltimate.getRoot().refresh(false, true); + } + + protected void doActionSilently(final VcsConfiguration.StandardConfirmation op) { + setStandardConfirmation(GitVcs.NAME, op, VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY); + } + + @AfterMethod + public void tearDown() throws Exception { + if (myTempDirFixture != null) { + myTempDirFixture.tearDown(); + myTempDirFixture = null; + } + } + + private void initRepositories(VirtualFile projectDir) throws IOException { + myUltimate = init(myProject, projectDir); + VirtualFile communityDir = createDirInCommand(projectDir, "community"); + VirtualFile contribDir = createDirInCommand(projectDir, "contrib"); + myCommunity = init(myProject, communityDir); + myContrib = init(myProject, contribDir); + + addProjectRoots(); + myRepositories = Arrays.asList(myUltimate, myCommunity, myContrib); + } + + private void addProjectRoots() { + ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); + vcsManager.setDirectoryMapping(myUltimate.getRoot().getPath(), GitVcs.NAME); + vcsManager.setDirectoryMapping(myCommunity.getRoot().getPath(), GitVcs.NAME); + vcsManager.setDirectoryMapping(myContrib.getRoot().getPath(), GitVcs.NAME); + } + + @Test + public void create_new_branch_without_problems() throws Exception { + doCheckoutNewBranch(); + assertNotify(NotificationType.INFORMATION, "Branch new_branch was created"); + } + + @Test + public void create_new_branch_with_unmerged_files_in_first_repo_should_show_notification() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myUltimate); + doCheckoutNewBranch(); + assertNotify(NotificationType.ERROR, GitBranchOperation.UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION); + } + + @Test + public void create_new_branch_with_unmerged_files_in_second_repo_should_propose_to_rollback() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); + doCheckoutNewBranch(); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + } + + @Test + public void rollback_create_new_branch_should_delete_branch() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); + myMessageManager.nextAnswer(Messages.OK); + doCheckoutNewBranch(); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch("master"); + assertTrue(!branch(myUltimate).contains(NEW_BRANCH)); + } + + @Test + public void deny_rollback_create_new_branch() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); + myMessageManager.nextAnswer(Messages.CANCEL); + doCheckoutNewBranch(); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + + assertBranch(myUltimate, NEW_BRANCH); + assertBranch(myCommunity, MASTER); + assertBranch(myContrib, MASTER); + } + + @Test + public void checkout_without_problems() throws Exception { + prepareBranchForSimpleCheckout(); + doCheckout("feature", null); + assertNotify(NotificationType.INFORMATION, "Checked out feature"); + } + + @Test + public void checkout_with_unmerged_files_in_first_repo_should_show_notification() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myUltimate); + doCheckout("feature", null); + assertNotify(NotificationType.ERROR, GitBranchOperation.UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION); + } + + @Test + public void checkout_with_unmerged_file_in_second_repo_should_propose_to_rollback() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); + doCheckout("feature", null); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + } + + @Test + public void rollback_checkout_should_return_to_previous_branch() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); + myMessageManager.nextAnswer(Messages.OK); + doCheckout("feature", null); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch("master"); + } + + @Test + public void deny_rollback_checkout_should_do_nothing() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); + myMessageManager.nextAnswer(Messages.CANCEL); + doCheckout("feature", null); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch(myUltimate, "feature"); + assertBranch(myCommunity, "master"); + assertBranch(myContrib, "master"); + } + + @Test + public void checkout_with_untracked_files_overwritten_by_checkout_in_first_repo_should_show_notification() throws Exception { + prepareUntrackedFilesAndBranchWithSameTrackedFiles(myUltimate); + branch(myCommunity, "feature"); + branch(myContrib, "feature"); + + doCheckout("feature", null); + assertNotify(NotificationType.ERROR, UntrackedFilesNotifier.createUntrackedFilesOverwrittenDescription("checkout", false)); + } + + @Test + public void checkout_with_untracked_files_overwritten_by_checkout_in_second_repo_should_show_rollback_proposal_with_file_list() throws Exception { + prepareUntrackedFilesAndBranchWithSameTrackedFiles(myCommunity); + branch(myUltimate, "feature"); + branch(myContrib, "feature"); + + Class gitCheckoutOperationClass = Class.forName("git4idea.branch.GitCheckoutOperation"); + Class[] classes = gitCheckoutOperationClass.getDeclaredClasses(); + Class untrackedFilesDialogClass = null; + for (Class aClass : classes) { + if (aClass.getName().endsWith("UntrackedFilesDialog")) { + untrackedFilesDialogClass = aClass; + } + } + assertNotNull(untrackedFilesDialogClass); + + final AtomicBoolean dialogShown = new AtomicBoolean(); + final Class finalUntrackedFilesDialogClass = untrackedFilesDialogClass; + myDialogManager.registerDialogHandler(untrackedFilesDialogClass, new TestDialogHandler() { + @Override + public int handleDialog(Object dialog) { + if (dialog.getClass().equals(finalUntrackedFilesDialogClass)) { + dialogShown.set(true); + } + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertTrue(dialogShown.get()); + } + + @Test + public void checkout_with_local_changes_overwritten_by_checkout_should_show_smart_checkout_dialog() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myUltimate); + branch(myCommunity, "feature"); + branch(myContrib, "feature"); + + final AtomicBoolean dialogShown = new AtomicBoolean(); + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + dialogShown.set(true); + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertTrue(dialogShown.get()); + } + + @Test + public void agree_to_smart_checkout_should_smart_checkout() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myUltimate); + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myCommunity); + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myContrib); + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, + new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + return DialogWrapper.OK_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertBranch("feature"); + for (GitRepository repository : myRepositories) { + refresh(repository); + assertBranch(repository, "feature"); + assertEquals(read(repository, "local.txt"), "master\ninitial content\nfeature content\n"); + } + } + + @Test + public void deny_to_smart_checkout_in_first_repo_should_show_notification() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myUltimate); + branch(myCommunity, "feature"); + branch(myContrib, "feature"); + + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertNotify(NotificationType.ERROR, "Couldn't checkout feature", stripHtmlAndBreaks("Local changes would be overwritten by checkout." + + "Stash or commit them before checking out a branch.")); + assertBranch("master"); + } + + @Test + public void deny_to_smart_checkout_in_second_repo_should_show_rollback_proposal() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myCommunity); + branch(myUltimate, "feature"); + branch(myContrib, "feature"); + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertMessage("Couldn't checkout feature", + "Local changes would be overwritten by checkout.
Stash or commit them before checking out a branch.
" + + "However checkout has succeeded for the following repositories:
" + + myUltimate.getPresentableUrl() + + "
You may rollback (checkout back to master) not to let branches diverge.", + "Rollback", "Don't rollback"); + } + + private static void prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(GitRepository repository) throws IOException { + create(repository, "local.txt", "initial content\n"); + addCommit(repository); + checkout(repository, "-b", "feature"); + edit(repository, "local.txt", "initial content\nfeature content\n"); + addCommit(repository); + checkout(repository, "master"); + edit(repository, "local.txt", "master\ninitial content\n"); + } + + private static void prepareUntrackedFilesAndBranchWithSameTrackedFiles(GitRepository repository) throws IOException { + checkout(repository, "-b", "feature"); + createAddCommit(repository, "untracked.txt"); + checkout(repository, "master"); + create(repository, "untracked.txt"); + } + + private void prepareBranchForSimpleCheckout() throws IOException { + for (GitRepository repository : myRepositories) { + checkout(repository, "-b", "feature"); + createAddCommit(repository, "feature_file.txt"); + checkout(repository, "master"); + } + } + + @Test + public void delete_branch_without_problems() throws Exception { + for (GitRepository repository : myRepositories) { + branch(repository, "master1"); + refresh(repository); + } + doDeleteBranch("master1"); + assertNotify(NotificationType.INFORMATION, "Deleted branch master1"); + } + + @Test + public void delete_unmerged_branch_should_show_dialog() throws Exception { + prepareUnmergedBranch(myUltimate, myCommunity, myContrib); + + final AtomicBoolean dialogShown = new AtomicBoolean(); + myDialogManager.registerDialogHandler(GitBranchIsNotFullyMergedDialog.class, new TestDialogHandler() { + @Override public int handleDialog(GitBranchIsNotFullyMergedDialog dialog) { + dialogShown.set(true); + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doDeleteBranch("unmerged_branch"); + assertTrue(dialogShown.get()); + } + + @Test + public void ok_in_unmerged_branch_dialog_should_force_delete_branch() throws Exception { + prepareUnmergedBranch(myUltimate, myCommunity, myContrib); + registerNotFullyMergedDialog(DialogWrapper.OK_EXIT_CODE); + doDeleteBranch("unmerged_branch"); + for (GitRepository repository : myRepositories) { + assertTrue(!branch(repository).contains("unmerged_branch")); + } + } + + @Test + public void cancel_in_unmerged_branch_dialog_in_first_repository_should_show_notification() throws Exception { + prepareUnmergedBranch(myUltimate, myContrib); + branch(myCommunity, "unmerged_branch"); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + doDeleteBranch("unmerged_branch"); + assertNotify(NotificationType.ERROR, "Branch unmerged_branch wasn't deleted", "This branch is not fully merged to master"); + } + + @Test + public void cancel_in_unmerged_branch_dialog_in_not_first_repository_should_show_rollback_proposal() throws Exception { + branch(myUltimate, "unmerged_branch"); + prepareUnmergedBranch(myCommunity, myContrib); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + doDeleteBranch("unmerged_branch"); + assertMessage(String.format("Branch %s wasn't deleted", "unmerged_branch")); + } + + @Test + public void rollback_delete_branch_should_recreate_branches() throws Exception { + branch(myUltimate, "unmerged_branch"); + prepareUnmergedBranch(myCommunity); + branch(myContrib, "unmerged_branch"); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + myMessageManager.nextAnswer(Messages.OK); + doDeleteBranch("unmerged_branch"); + + for (GitRepository repository : myRepositories) { + assertTrue(branch(repository).contains("unmerged_branch")); + } + } + + @Test + public void deny_rollback_delete_branch_should_do_nothing() throws Exception { + branch(myUltimate, "unmerged_branch"); + prepareUnmergedBranch(myCommunity); + branch(myContrib, "unmerged_branch"); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + myMessageManager.nextAnswer(Messages.CANCEL); + doDeleteBranch("unmerged_branch"); + + assertTrue(branch(myCommunity).contains("unmerged_branch")); + assertTrue(branch(myContrib).contains("unmerged_branch")); + assertTrue(!branch(myUltimate).contains("unmerged_branch")); + } + + private void registerNotFullyMergedDialog(final int answer) { + myDialogManager.registerDialogHandler(GitBranchIsNotFullyMergedDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitBranchIsNotFullyMergedDialog dialog) { + return answer; + } + }); + } + + private static void prepareUnmergedBranch(GitRepository... repositories) throws IOException { + for (GitRepository repository : repositories) { + checkout(repository, "-b", "unmerged_branch"); + createAddCommit(repository, "unmerged_branch_file"); + checkout(repository, "master"); + refresh(repository); + } + } + + private void doCheckoutNewBranch() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + callPrivateBranchOperationsProcessorMethod("doCheckoutNewBranch", NEW_BRANCH); + } + + private void callPrivateBranchOperationsProcessorMethod(String methodName, String branchName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + // call private doCheckoutNewBranch instead of public checkoutNewBranch to avoid dealing with background process creation + // same for other branch operations + GitBranchOperationsProcessor processor = new GitBranchOperationsProcessor(myProject, myRepositories, myCommunity); + Method method = GitBranchOperationsProcessor.class.getDeclaredMethod(methodName, String.class, ProgressIndicator.class); + method.setAccessible(true); + method.invoke(processor, branchName, new EmptyProgressIndicator()); + } + + private void doDeleteBranch(@NotNull String branchName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + callPrivateBranchOperationsProcessorMethod("doDelete", branchName); + } + + private void doCheckout(@NotNull String branchName, @Nullable String newBranch) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + GitBranchOperationsProcessor processor = new GitBranchOperationsProcessor(myProject, myRepositories, myCommunity); + Method doCheckout = GitBranchOperationsProcessor.class.getDeclaredMethod("doCheckout", ProgressIndicator.class, String.class, String.class); + doCheckout.setAccessible(true); + doCheckout.invoke(processor, new EmptyProgressIndicator(), branchName, newBranch); + } + + private void assertBranch(String branch) { + for (GitRepository repository : myRepositories) { + assertBranch(repository, branch); + } + } + + private static void assertBranch(GitRepository repository, String branchName) { + GitBranch currentBranch = repository.getCurrentBranch(); + assertNotNull(currentBranch); + assertEquals(currentBranch.getName(), branchName); + } + + private void assertNotify(NotificationType type, String content) { + assertNotify(type, null, content); + } + + private void assertNotify(NotificationType type, @Nullable String title, String content) { + Notification notification = myNotificationManager.getLastNotification(); + assertNotNull(notification); + assertEquals(stripHtmlAndBreaks(notification.getContent()), stripHtmlAndBreaks(content)); + assertEquals(notification.getType(), type); + if (title != null) { + assertEquals(stripHtmlAndBreaks(notification.getTitle()), stripHtmlAndBreaks(title)); + } + } + + @NotNull + private static String stripHtmlAndBreaks(@NotNull String text) { + return StringUtil.stripHtml(text, true).replace("\n", ""); + } + + private void assertMessage(String title) { + assertMessage(title, null, null, null); + } + + private void assertMessage(@Nullable String title, @Nullable String description, @Nullable String yesButton, @Nullable String noButton) { + TestMessageManager.Message message = myMessageManager.getLastMessage(); + assertNotNull(message); + if (title != null) { + assertEquals(message.getTitle(), title); + } + if (description != null) { + assertEquals(message.getDescription(), description); + } + if (yesButton != null) { + assertEquals(message.getYesText(), yesButton); + } + if (noButton != null) { + assertEquals(message.getNoText(), noButton); + } + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/GitExec.java b/plugins/git4idea/tests/git4idea/test/GitExec.java new file mode 100644 index 000000000000..cacf79de5907 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/GitExec.java @@ -0,0 +1,117 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.test; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.AbstractVcsTestCase; +import com.intellij.testFramework.VfsTestUtil; +import com.intellij.util.ui.UIUtil; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +/** + * @author Kirill Likhodedov + */ +public class GitExec { + + public static void refresh(@NotNull GitRepository repository) { + repository.getRoot().refresh(false, true); + } + + public static GitRepository init(@NotNull Project project, @NotNull VirtualFile root) throws IOException { + new GitTestRunEnv(new File(root.getPath())).run("init"); + root.refresh(false, true); + return GitRepository.getFullInstance(root, project, project); + } + + public static void create(@NotNull GitRepository repository, @NotNull String filePath) { + create(repository, filePath, "content"); + } + + public static void create(final GitRepository repository, final String filePath, @NotNull final String content) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override public void run() { + VfsTestUtil.createFile(repository.getRoot(), filePath, content); + } + }); + } + + public static void edit(final GitRepository repository, String filePath, final String newContent) { + final VirtualFile file = repository.getRoot().findFileByRelativePath(filePath); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override public void run() { + AbstractVcsTestCase.editFileInCommand(repository.getProject(), file, newContent); + } + }); + } + + @NotNull + public static String read(final @NotNull GitRepository repository, @NotNull String filePath) throws IOException { + final VirtualFile file = repository.getRoot().findFileByRelativePath(filePath); + assert file != null; + return new String(file.contentsToByteArray()); + } + + public static void add(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { + run(repository, "add", filePath); + } + + public static void add(@NotNull GitRepository repository) throws IOException { + run(repository, "add", "."); + } + + public static void commit(@NotNull GitRepository repository) throws IOException { + run(repository, "commit", "-m", "message"); + } + + public static void addCommit(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { + add(repository, filePath); + commit(repository); + } + + public static void addCommit(@NotNull GitRepository repository) throws IOException { + add(repository); + commit(repository); + } + + public static void createAddCommit(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { + create(repository, filePath); + addCommit(repository, filePath); + } + + @NotNull + public static String branch(@NotNull GitRepository repository, String... params) throws IOException { + return run(repository, "branch", params); + } + + public static void checkout(@NotNull GitRepository repository, String... params) throws IOException { + run(repository, "checkout", params); + } + + public static void merge(@NotNull GitRepository repository, @NotNull String branch) throws IOException { + run(repository, "merge", branch); + } + + @NotNull + private static String run(@NotNull GitRepository repository, @NotNull String command, String... params) throws IOException { + return new GitTestRunEnv(new File(repository.getRoot().getPath())).run(command, params); + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java b/plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java new file mode 100644 index 000000000000..021535ebad9e --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.test; + +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +import static git4idea.test.GitExec.*; + +/** + * @author Kirill Likhodedov + */ +public class GitTestScenarioGenerator { + + public static void prepareUnmergedFiles(@NotNull GitRepository... repositories) throws IOException { + for (GitRepository repository : repositories) { + String unmergedFile = "unmerged"; + create(repository, unmergedFile, "master content"); + addCommit(repository, unmergedFile); + + checkoutFeatureBranch(repository); + edit(repository, unmergedFile, "feature content"); + addCommit(repository, unmergedFile); + + checkout(repository, "master"); + edit(repository, unmergedFile, "master feature"); + addCommit(repository, unmergedFile); + + merge(repository, "feature"); + refresh(repository); + } + } + + private static void checkoutFeatureBranch(GitRepository repository) throws IOException { + String branches = branch(repository); + if (!branches.contains("feature")) { + checkout(repository, "-b", "feature"); + } else { + checkout(repository, "feature"); + } + } +} diff --git a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java index 97944322e044..0e6d3e3be5ba 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java +++ b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java @@ -22,9 +22,14 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.DialogManager; +import git4idea.MessageManager; +import git4idea.NotificationManager; import git4idea.tests.GitTestRepository; +import git4idea.tests.TestDialogManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.picocontainer.MutablePicoContainer; import java.io.File; import java.io.FilenameFilter; @@ -227,4 +232,33 @@ public class GitTestUtil { public static String stringifyActualExpected(@NotNull Object actual, @NotNull Object expected) { return "\nExpected:\n" + expected + "\nActual:\n" + actual; } + + /** + * Registers {@link git4idea.tests.TestDialogManager} as the {@link git4idea.DialogManager} implementation. + * @param project + */ + public static TestDialogManager registerDialogManager(@NotNull Project project) { + final String key = "git4idea.DialogManager"; + final MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); + picoContainer.unregisterComponent(key); + picoContainer.registerComponentImplementation(key, TestDialogManager.class); + return (TestDialogManager)DialogManager.getInstance(project); + } + + public static TestMessageManager registerMessageManager(@NotNull Project project) { + final String key = "git4idea.MessageManager"; + final MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); + picoContainer.unregisterComponent(key); + picoContainer.registerComponentImplementation(key, TestMessageManager.class); + return (TestMessageManager)MessageManager.getInstance(project); + } + + public static TestNotificationManager registerNotificationManager(Project project) { + final String key = "git4idea.NotificationManager"; + final MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); + picoContainer.unregisterComponent(key); + picoContainer.registerComponentImplementation(key, TestNotificationManager.class); + return (TestNotificationManager)NotificationManager.getInstance(project); + } + } diff --git a/plugins/git4idea/tests/git4idea/test/TestMessageManager.java b/plugins/git4idea/tests/git4idea/test/TestMessageManager.java new file mode 100644 index 000000000000..fed1d7160f9d --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/TestMessageManager.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.test; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import git4idea.MessageManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Kirill Likhodedov + */ +public class TestMessageManager extends MessageManager { + + private Message myLastMessage; + private int myNextAnswer = DEFAULT_ANSWER; + private static final int DEFAULT_ANSWER = Messages.CANCEL; + + public static class Message { + @NotNull private final String myTitle; + @NotNull private final String myDescription; + @NotNull private final String myYesText; + @NotNull private final String myNoText; + + public Message(@NotNull String title, @NotNull String description, @NotNull String yesText, @NotNull String noText) { + myTitle = title; + myDescription = description; + myYesText = yesText; + myNoText = noText; + } + + @NotNull + public String getTitle() { + return myTitle; + } + + @NotNull + public String getDescription() { + return myDescription; + } + + @NotNull + public String getYesText() { + return myYesText; + } + + @NotNull + public String getNoText() { + return myNoText; + } + } + + @Nullable + public Message getLastMessage() { + return myLastMessage; + } + + public void nextAnswer(int answer) { + myNextAnswer = answer; + } + + @Override + protected int doShowYesNoDialog(Project project, String description, String title, String yesText, String noText, @Nullable Icon icon) { + myLastMessage = new Message(title, description, yesText, noText); + return myNextAnswer; + } + + +} diff --git a/plugins/git4idea/tests/git4idea/test/TestNotificationManager.java b/plugins/git4idea/tests/git4idea/test/TestNotificationManager.java new file mode 100644 index 000000000000..f7aa39522924 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/TestNotificationManager.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.test; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.project.Project; +import git4idea.NotificationManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Kirill Likhodedov + */ +public class TestNotificationManager extends NotificationManager { + + private Notification myLastNotification; + + public TestNotificationManager(@NotNull Project project) { + super(project); + } + + public Notification getLastNotification() { + return myLastNotification; + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type) { + notify(notificationGroup, title, message, type, null); + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, + @NotNull NotificationType type, @Nullable NotificationListener listener) { + myLastNotification = createNotification(notificationGroup, title, message, type, listener); + } + +} diff --git a/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java b/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java index e0990266e473..9236026f245a 100644 --- a/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java +++ b/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java @@ -23,11 +23,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CheckboxTreeBase; import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.GuiUtils; -import git4idea.DialogManager; import git4idea.config.GitVcsSettings; +import git4idea.test.GitTestUtil; import git4idea.ui.GitConvertFilesDialog; import org.jetbrains.annotations.Nullable; -import org.picocontainer.MutablePicoContainer; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -63,7 +62,7 @@ public class GitLineSeparatorsConverterTest extends GitTest { myChangeListManager = ChangeListManagerImpl.getInstanceImpl(myProject); mySettings = GitVcsSettings.getInstance(myProject); myCodeStyleSeparator = CodeStyleFacade.getInstance(myProject).getLineSeparator(); - myDialogManager = registerDialogManager(); + myDialogManager = GitTestUtil.registerDialogManager(myProject); unixFile = createFileInCommand("unix_file.txt", "Unix File\n"); winFile = createFileInCommand("win_file.txt", "Windows File\r\n"); @@ -193,17 +192,6 @@ public class GitLineSeparatorsConverterTest extends GitTest { return null; } - /** - * Registers {@link TestDialogManager} as the {@link DialogManager} implementation. - */ - private TestDialogManager registerDialogManager() { - final String key = "git4idea.DialogManager"; - final MutablePicoContainer picoContainer = (MutablePicoContainer) myProject.getPicoContainer(); - picoContainer.unregisterComponent(key); - picoContainer.registerComponentImplementation(key, TestDialogManager.class); - return (TestDialogManager)DialogManager.getInstance(myProject); - } - /** * Commits via the ChangeListManager. */ diff --git a/plugins/git4idea/tests/testng.xml b/plugins/git4idea/tests/testng.xml index eeb43f3bd5e3..c60b4e99afd5 100644 --- a/plugins/git4idea/tests/testng.xml +++ b/plugins/git4idea/tests/testng.xml @@ -2,6 +2,7 @@ + diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java index fb8c5ef9b5e2..e1a709993f97 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java @@ -210,6 +210,7 @@ public class TestNGConfigurationEditor extends SettingsEditor - + - + diff --git a/plugins/ui-designer/src/messages/UIDesignerBundle.properties b/plugins/ui-designer/src/messages/UIDesignerBundle.properties index 91dcb96c7bed..cd0ead7837a8 100644 --- a/plugins/ui-designer/src/messages/UIDesignerBundle.properties +++ b/plugins/ui-designer/src/messages/UIDesignerBundle.properties @@ -546,7 +546,7 @@ action.GuiDesigner.ReloadCustomComponents.text=Reload Custom Components action.GuiDesigner.ReloadCustomComponents.description=Reload modified custom component classes and recreate forms action.NewDialog.text=Dialog action.NewForm.text=GUI Form -default.field.accessibility=Default accessibility for UI-bound fields: +default.field.accessibility=Default accessibility &for UI-bound fields\: plugin.com.intellij.uiDesigner.description=Provides visual editing support for Swing UI forms group.GuiDesigner.MainToolbarActions.text=UI Designer Toolbar Actions group.GuiDesigner.NewActions.text=New GUI Designer Actions