Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Kirill Kalishev
2011-04-13 19:09:44 +04:00
16 changed files with 241 additions and 17 deletions
@@ -21,14 +21,49 @@ package com.intellij.openapi.project;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFilePathWrapper;
import com.intellij.util.SystemProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
public class ProjectUtil {
private ProjectUtil() {
}
@Nullable
public static String getProjectLocationString(@NotNull final Project project) {
String projectPath = project.getLocation();
return getLocationRelativeToUserHome(projectPath);
}
@Nullable
public static String getLocationRelativeToUserHome(final String path) {
if (path == null) return null;
String _path = path;
if ((SystemInfo.isLinux || SystemInfo.isMac)) {
final File projectDir = new File(path);
final File userHomeDir = new File(SystemProperties.getUserHome());
try {
if (FileUtil.isAncestor(userHomeDir, projectDir, true)) {
_path = "~/" + FileUtil.getRelativePath(userHomeDir, projectDir);
}
}
catch (IOException e) {
// nothing
}
}
return _path;
}
public static String calcRelativeToProjectPath(final VirtualFile file, final Project project) {
if (file instanceof VirtualFilePathWrapper) {
return ((VirtualFilePathWrapper)file).getPresentablePath();
@@ -27,6 +27,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
@@ -81,7 +82,11 @@ public class PsiDirectoryNode extends BasePsiNode<PsiDirectory> implements Navig
}
if (parentValue instanceof Project || parentValue instanceof Module) {
data.addText(" (" + directoryFile.getPresentableUrl() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
if (parentValue instanceof Project) {
data.addText(" (" + ProjectUtil.getLocationRelativeToUserHome(directoryFile.getPresentableUrl()) + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
} else {
data.addText(" (" + directoryFile.getPresentableUrl() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
}
else if (ProjectRootsUtil.isSourceOrTestRoot(directoryFile, project)) {
if (ProjectRootsUtil.isInTestSource(directoryFile, project)) {
@@ -0,0 +1,45 @@
/*
* Copyright 2000-2011 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 com.intellij.psi.impl.smartPointers;
import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public class MultiRootSelfElementInfo extends SelfElementInfo {
private final Language myLanguage;
public MultiRootSelfElementInfo(@NotNull Project project,
@NotNull TextRange anchor,
@NotNull Class anchorClass,
@NotNull PsiFile containingFile,
@NotNull Language language) {
super(project, anchor, anchorClass, containingFile);
myLanguage = language;
}
@Override
protected PsiFile restoreFile() {
PsiFile mainRoot = super.restoreFile();
if (mainRoot == null) return null;
return mainRoot.getViewProvider().getPsi(myLanguage);
}
}
@@ -151,7 +151,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
public PsiElement restoreElement() {
if (!mySyncMarkerIsValid) return null;
PsiFile file = restoreFileFromVirtual(myVirtualFile, myProject);
PsiFile file = restoreFile();
if (file == null || !file.isValid()) return null;
final int syncStartOffset = getSyncStartOffset();
@@ -160,6 +160,10 @@ public class SelfElementInfo implements SmartPointerElementInfo {
return findElementInside(file, syncStartOffset, syncEndOffset, myType);
}
protected PsiFile restoreFile() {
return restoreFileFromVirtual(myVirtualFile, myProject);
}
protected static PsiElement findElementInside(PsiFile file, int syncStartOffset, int syncEndOffset, Class type) {
PsiElement anchor = file.getViewProvider().findElementAt(syncStartOffset, file.getLanguage());
if (anchor == null) return null;
@@ -164,6 +164,12 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
LOG.assertTrue(element.isPhysical());
LOG.assertTrue(element.isValid());
boolean isMultiRoot = viewProvider.getAllFiles().size() > 1;
VirtualFile virtualFile = containingFile.getVirtualFile();
boolean isElementInMainRoot = virtualFile == null || containingFile.getManager().findFile(virtualFile) == containingFile;
if (isMultiRoot && !isElementInMainRoot) {
return new MultiRootSelfElementInfo(project, element.getTextRange(), element.getClass(), containingFile, containingFile.getLanguage());
}
return new SelfElementInfo(project, element.getTextRange(), element.getClass(), containingFile);
}
@@ -17,10 +17,13 @@ package com.intellij.openapi.progress;
import com.intellij.CommonBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.DumbModeAction;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.util.LocaleServiceProviderPool;
/**
* Intended to run tasks, both modal and non-modal (backgroundable)
@@ -39,7 +42,7 @@ import org.jetbrains.annotations.Nullable;
* @see com.intellij.openapi.progress.ProgressManager#run(Task)
*/
public abstract class Task implements TaskInfo, Progressive {
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.Task");
protected final Project myProject;
protected String myTitle;
private final boolean myCanBeCancelled;
@@ -134,6 +137,9 @@ public abstract class Task implements TaskInfo, Progressive {
public Backgroundable(@Nullable final Project project, @NotNull final String title, final boolean canBeCancelled, @Nullable final PerformInBackgroundOption backgroundOption) {
super(project, title, canBeCancelled);
myBackgroundOption = backgroundOption;
if (StringUtil.isEmptyOrSpaces(title)) {
LOG.warn("Empty title for backgroundable task.", new Throwable());
}
}
public Backgroundable(@Nullable final Project project, @NotNull final String title, final boolean canBeCancelled) {
@@ -27,6 +27,7 @@ import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.PairConsumer;
import com.intellij.util.PlusMinus;
import com.intellij.util.concurrency.QueueProcessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,21 +42,24 @@ import org.jetbrains.annotations.Nullable;
*/
@SomeQueue
public class BackgroundTaskQueue {
private final static String ourMonitorFlag = "monitor.background.queue.load";
private static final Logger LOG = Logger.getInstance(BackgroundTaskQueue.class.getName());
//private final Project myProject;
private final QueueProcessor<Pair<Task.Backgroundable, Getter<ProgressIndicator>>> myProcessor;
private Boolean myForcedTestMode;
private final PlusMinus<String> myMonitor;
public BackgroundTaskQueue(@Nullable Project project, @NotNull String title) {
this(project, title, null);
}
public BackgroundTaskQueue(@Nullable final Project project, @NotNull String title, final Boolean forcedHeadlessMode) {
myMonitor = Boolean.TRUE.equals(Boolean.getBoolean(ourMonitorFlag)) ? new BackgroundTasksMonitor(title) : new PlusMinus.Empty<String>();
final boolean headless = forcedHeadlessMode != null ? forcedHeadlessMode : ApplicationManager.getApplication().isHeadlessEnvironment();
final QueueProcessor.ThreadToUse threadToUse = headless ? QueueProcessor.ThreadToUse.POOLED : QueueProcessor.ThreadToUse.AWT;
final PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, Runnable> consumer
= headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project);
= headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project, myMonitor);
myProcessor = new QueueProcessor<Pair<Task.Backgroundable, Getter<ProgressIndicator>>>(consumer, true,
threadToUse, new Condition<Object>() {
@@ -83,6 +87,7 @@ public class BackgroundTaskQueue {
}
public void run(Task.Backgroundable task, final ModalityState state, final Getter<ProgressIndicator> pi) {
myMonitor.plus(task.getTitle());
if (isTestMode()) { // test tasks are executed in this thread without the progress manager
RunBackgroundable.runIfBackgroundThread(task, new EmptyProgressIndicator(), null);
} else {
@@ -103,14 +108,17 @@ public class BackgroundTaskQueue {
private static class BackgroundableUnderProgressRunner implements PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, Runnable> {
private final String myTitle;
private final Project myProject;
private final PlusMinus<String> myMonitor;
public BackgroundableUnderProgressRunner(String title, final Project project) {
public BackgroundableUnderProgressRunner(String title, final Project project, PlusMinus<String> monitor) {
myTitle = title;
myProject = project;
myMonitor = monitor;
}
@Override
public void consume(final Pair<Task.Backgroundable, Getter<ProgressIndicator>> pair, final Runnable runnable) {
myMonitor.minus(pair.getFirst().getTitle());
final Task.Backgroundable backgroundable = pair.getFirst();
final ProgressIndicator[] pi = new ProgressIndicator[1];
final boolean taskTitleIsEmpty = StringUtil.isEmptyOrSpaces(backgroundable.getTitle());
@@ -133,11 +141,11 @@ public class BackgroundTaskQueue {
pi[0] = pair.getSecond().get();
}
if (pi[0] == null) {
if (taskTitleIsEmpty) {
backgroundable.setTitle(myTitle);
}
pi[0] = new BackgroundableProcessIndicator(backgroundable);
}
if (taskTitleIsEmpty) {
((BackgroundableProcessIndicator) pi[0]).setTitle(myTitle);
}
ProgressManagerImpl.runProcessWithProgressAsynchronously(backgroundable, pi[0], runnable);
}
@@ -0,0 +1,92 @@
/*
* Copyright 2000-2011 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 com.intellij.openapi.progress;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.PlusMinus;
import java.util.HashMap;
import java.util.Map;
/**
* @author irengrig
* Date: 4/13/11
* Time: 5:32 PM
*/
public class BackgroundTasksMonitor implements PlusMinus<String> {
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.BackgroundTasksMonitor");
private static final long ourStatInterval = 300000;
private long myRecentTime;
private final Map<String, Integer> myMap;
private final Map<String, Integer> myMaxMap;
private final Object myLock;
private final String myQueueTitle;
public BackgroundTasksMonitor(final String queueTitle) {
myQueueTitle = queueTitle;
myMap = new HashMap<String, Integer>();
myMaxMap = new HashMap<String, Integer>();
myLock = new Object();
myRecentTime = 0;
}
@Override
public void plus(String title) {
synchronized (myLock) {
final Integer previous = myMap.get(title);
final int newVal = previous == null ? 1 : (previous + 1);
myMap.put(title, newVal);
final Integer max = myMaxMap.get(title);
if (max == null || max < newVal) {
myMaxMap.put(title, newVal);
}
reportStatistics();
}
}
@Override
public void minus(String title) {
synchronized (myLock) {
final Integer integer = myMap.get(title);
assert integer != null;
if (integer == 1) {
myMap.remove(title);
} else {
myMap.put(title, integer - 1);
}
reportStatistics();
}
}
private void reportStatistics() {
final long time = System.currentTimeMillis();
if (time - ourStatInterval < myRecentTime) return;
final StringBuilder sb = new StringBuilder("BackgroundTaskQueue '" + myQueueTitle + "' usage statistics\n");
sb.append("----------------------------------------------------\n");
sb.append("Current Values:");
for (Map.Entry<String, Integer> entry : myMap.entrySet()) {
sb.append(entry.getKey()).append(": ").append(entry.getValue());
}
sb.append("\nMaximum Values:");
for (Map.Entry<String, Integer> entry : myMaxMap.entrySet()) {
sb.append('\n').append(entry.getKey()).append(": ").append(entry.getValue());
}
sb.append("----------------------------------------------------\n");
LOG.info(sb.toString());
myRecentTime = time;
}
}
@@ -16,6 +16,7 @@
package com.intellij.openapi.wm.impl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFilePathWrapper;
import com.intellij.platform.ProjectBaseDirectory;
@@ -27,7 +28,7 @@ public class PlatformFrameTitleBuilder extends FrameTitleBuilder {
public String getProjectTitle(final Project project) {
final VirtualFile baseDir = project.getBaseDir();
if (baseDir != null) {
return project.getName() + " - [" + baseDir.getPresentableUrl() + "]";
return project.getName() + " - [" + ProjectUtil.getLocationRelativeToUserHome(baseDir.getPresentableUrl()) + "]";
}
return project.getName();
}
@@ -13,9 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes;
package com.intellij.util;
public interface PlusMinus<T> {
class Empty<T> implements PlusMinus<T> {
@Override
public void plus(T t) {
}
@Override
public void minus(T t) {
}
}
void plus(final T t);
void minus(final T t);
}
@@ -44,10 +44,7 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.EditorNotifications;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.Consumer;
import com.intellij.util.EventDispatcher;
import com.intellij.util.NullableFunction;
import com.intellij.util.*;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.messages.Topic;
import com.intellij.vcsUtil.Rethrow;
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlusMinus;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -20,7 +20,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vcs.impl.CollectionsDelta;
import com.intellij.util.PlusMinus;
import java.util.Collection;
import java.util.HashSet;
@@ -19,6 +19,7 @@ import com.intellij.lifecycle.AtomicSectionsAware;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.VcsListener;
import com.intellij.util.PlusMinus;
import java.util.Collection;
@@ -30,6 +30,7 @@ import com.intellij.openapi.vcs.impl.VcsInitObject;
import com.intellij.openapi.vcs.update.UpdateFilesHelper;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.util.Consumer;
import com.intellij.util.PlusMinus;
import com.intellij.util.messages.Topic;
import java.util.Collection;
@@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Container and tracker of git branches information.
@@ -55,11 +56,13 @@ public class GitBranches implements GitReferenceListener {
private final Object myCurrentBranchesLock = new Object();
private ChangeListManager myChangeListManager;
private GitVcs myVcs;
private final AtomicBoolean mySoleUseControl;
public GitBranches(Project project, ChangeListManager changeListManager, ProjectLevelVcsManager vcsManager) {
myProject = project;
myChangeListManager = changeListManager;
myVcsManager = vcsManager;
mySoleUseControl = new AtomicBoolean(false);
}
public static GitBranches getInstance(Project project) {
@@ -121,8 +124,10 @@ public class GitBranches implements GitReferenceListener {
return;
}
final Task.Backgroundable task = new Task.Backgroundable(myProject, "") {
final Task.Backgroundable task = new Task.Backgroundable(myProject, "Git: refresh current branch") {
@Override public void run(@NotNull ProgressIndicator indicator) {
assert ! mySoleUseControl.get();
mySoleUseControl.set(true);
try {
GitBranch currentBranch = GitBranch.current(myProject, root);
synchronized (myCurrentBranchesLock) {
@@ -132,6 +137,8 @@ public class GitBranches implements GitReferenceListener {
} catch (VcsException e) {
LOG.info("Exception while trying to get current branch for root " + root, e);
// doing nothing - null will be set to myCurrentBranchName
} finally {
mySoleUseControl.set(false);
}
}
};
@@ -140,8 +147,11 @@ public class GitBranches implements GitReferenceListener {
private void fullyUpdateBranchesInfo(final Collection<VirtualFile> roots) {
if (roots == null) { return; }
final Task.Backgroundable task = new Task.Backgroundable(myProject, "") {
final Task.Backgroundable task = new Task.Backgroundable(myProject, "Git: refresh current branches") {
@Override public void run(@NotNull ProgressIndicator indicator) {
assert ! mySoleUseControl.get();
mySoleUseControl.set(true);
try {
Map<VirtualFile, GitBranch> currentBranches = new HashMap<VirtualFile, GitBranch>();
for (VirtualFile root : roots) {
try {
@@ -156,6 +166,9 @@ public class GitBranches implements GitReferenceListener {
synchronized (myCurrentBranchesLock) {
myCurrentBranches = currentBranches;
}
} finally {
mySoleUseControl.set(false);
}
}
};
GitVcs.runInBackground(task);