mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-06 06:21:16 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
Binary file not shown.
@@ -20,10 +20,10 @@ import com.intellij.codeInsight.completion.JavaSmartCompletionParameters;
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -31,19 +31,15 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ClassLiteralGetter {
|
||||
private static final Logger LOG = Logger.getInstance("com.intellij.psi.filters.getters.ClassLiteralGetter");
|
||||
|
||||
public static void addCompletions(@NotNull final JavaSmartCompletionParameters parameters,
|
||||
@NotNull Consumer<LookupElement> result, final PrefixMatcher matcher) {
|
||||
PsiType expectedType = parameters.getExpectedType();
|
||||
if (!InheritanceUtil.isInheritor(expectedType, CommonClassNames.JAVA_LANG_CLASS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Condition<String> shortNameCondition = new Condition<String>() {
|
||||
@Override
|
||||
public boolean value(String s) {
|
||||
return matcher.prefixMatches(s);
|
||||
}
|
||||
};
|
||||
|
||||
PsiType classParameter = PsiUtil.substituteTypeParameter(parameters.getExpectedType(), CommonClassNames.JAVA_LANG_CLASS, 0, false);
|
||||
PsiType classParameter = PsiUtil.substituteTypeParameter(expectedType, CommonClassNames.JAVA_LANG_CLASS, 0, false);
|
||||
|
||||
boolean addInheritors = false;
|
||||
PsiElement position = parameters.getPosition();
|
||||
@@ -59,7 +55,12 @@ public class ClassLiteralGetter {
|
||||
PsiFile file = position.getContainingFile();
|
||||
addClassLiteralLookupElement(classParameter, result, file);
|
||||
if (addInheritors) {
|
||||
addInheritorClassLiterals(file, shortNameCondition, classParameter, result, matcher);
|
||||
addInheritorClassLiterals(file, new Condition<String>() {
|
||||
@Override
|
||||
public boolean value(String s) {
|
||||
return matcher.prefixMatches(s);
|
||||
}
|
||||
}, classParameter, result, matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
<val name="intValues" val="{java.util.Calendar.JANUARY, java.util.Calendar.FEBRUARY, java.util.Calendar.MARCH, java.util.Calendar.APRIL, java.util.Calendar.MAY, java.util.Calendar.JUNE, java.util.Calendar.JULY, java.util.Calendar.AUGUST, java.util.Calendar.SEPTEMBER, java.util.Calendar.OCTOBER, java.util.Calendar.NOVEMBER, java.util.Calendar.DECEMBER}"/>
|
||||
</annotation>
|
||||
</item>
|
||||
<item name='java.util.Calendar int get(int) 0'>
|
||||
<annotation name='org.intellij.lang.annotations.MagicConstant'>
|
||||
<val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}"/>
|
||||
</annotation>
|
||||
</item>
|
||||
<item name='java.util.Calendar void set(int, int, int, int, int) 1'>
|
||||
<annotation name='org.intellij.lang.annotations.MagicConstant'>
|
||||
<val name="intValues" val="{java.util.Calendar.JANUARY, java.util.Calendar.FEBRUARY, java.util.Calendar.MARCH, java.util.Calendar.APRIL, java.util.Calendar.MAY, java.util.Calendar.JUNE, java.util.Calendar.JULY, java.util.Calendar.AUGUST, java.util.Calendar.SEPTEMBER, java.util.Calendar.OCTOBER, java.util.Calendar.NOVEMBER, java.util.Calendar.DECEMBER}"/>
|
||||
|
||||
@@ -217,6 +217,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
|
||||
|
||||
void onChunkBuildComplete(@NotNull ModuleChunk chunk) throws IOException {
|
||||
myDataManager.closeSourceToOutputStorages(chunk, isCompilingTests());
|
||||
myDataManager.flush(true);
|
||||
myFsState.clearContextRoundData();
|
||||
myFsState.clearContextChunk();
|
||||
|
||||
|
||||
@@ -509,16 +509,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
urls[index++] = getResourcePath(GridConstraints.class).toURI().toURL(); // forms_rt.jar
|
||||
//urls.add(getResourcePath(CellConstraints.class).toURI().toURL()); // jgoodies-forms
|
||||
|
||||
final Map<String, byte[]> compiled = new HashMap<String, byte[]>();
|
||||
for (OutputFileObject fileObject : outputSink.getFileObjects()) {
|
||||
final String name = fileObject.getClassName();
|
||||
if (name != null) {
|
||||
final OutputFileObject.Content content = fileObject.getContent();
|
||||
if (content != null) {
|
||||
compiled.put(name, content.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new InstrumentationClassFinder(platformUrls, urls, outputSink);
|
||||
}
|
||||
|
||||
|
||||
@@ -1836,10 +1836,8 @@ public class Mappings {
|
||||
// flush if you own the context
|
||||
final DependencyContext context = myContext;
|
||||
if (context != null) {
|
||||
if (memoryCachesOnly) {
|
||||
context.clearMemoryCaches();
|
||||
}
|
||||
else {
|
||||
context.clearMemoryCaches();
|
||||
if (!memoryCachesOnly) {
|
||||
context.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include <jni.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_intellij_util_ui_MacUIUtil_doHideCursor
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
CGDisplayHideCursor(kCGDirectMainDisplay);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_intellij_util_ui_MacUIUtil_doShowCursor
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
gcc -arch i386 -arch x86_64 -mmacosx-version-min=10.5 -framework ApplicationServices -I/System/Library/Frameworks/JavaVM.framework/Headers/ cursorHider.c -shared -fPIC -o cursorHider.jnilib
|
||||
@@ -205,13 +205,15 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
|
||||
/**
|
||||
* Checks whether this file is a symbolic link.
|
||||
*
|
||||
* @since 11.0
|
||||
* @return <code>true</code> if this file is a symbolic link, <code>false</code> otherwise
|
||||
* @since 11.0
|
||||
*/
|
||||
public boolean isSymLink() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @deprecated use {@linkplain #getCanonicalFile()} (to remove in IDEA 12) */
|
||||
@SuppressWarnings({"MethodMayBeStatic", "UnusedDeclaration"})
|
||||
@Nullable
|
||||
public String resolveSymLink() {
|
||||
return null;
|
||||
@@ -220,23 +222,42 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
|
||||
/**
|
||||
* Checks whether this file is a special (e.g. FIFO or device) file.
|
||||
*
|
||||
* @since 11.0
|
||||
* @return <code>true</code> if the file exists and is a special one, <code>false</code> otherwise
|
||||
* @since 11.0
|
||||
*/
|
||||
public boolean isSpecialFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @deprecated use {@linkplain #getCanonicalFile()} (to remove in IDEA 12) */
|
||||
@Nullable
|
||||
public VirtualFile getRealFile() {
|
||||
return isSymLink() ? getCanonicalFile() : this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve a symbolic link represented by this file and returns link target.
|
||||
* Resolves all symbolic links containing in a path to this file and returns a path to a link target.
|
||||
*
|
||||
* @since 11.0
|
||||
* @return <code>this</code> if the file isn't a symbolic link;
|
||||
* @since 11.1
|
||||
* @return <code>getPath()</code> if there are no symbolic links in a file's path;
|
||||
* <code>getCanonicalFile().getPath()</code> if the link was successfully resolved;
|
||||
* <code>null</code> otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public String getCanonicalPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all symbolic links containing in a path to this file and returns a link target.
|
||||
*
|
||||
* @since 11.1
|
||||
* @return <code>this</code> if there are no symbolic links in a file's path;
|
||||
* instance of <code>VirtualFile</code> if the link was successfully resolved;
|
||||
* <code>null</code> otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public VirtualFile getRealFile() {
|
||||
public VirtualFile getCanonicalFile() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -452,11 +473,6 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public final void setBinaryContent(byte[] content) throws IOException {
|
||||
setBinaryContent(content, -1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Retrieve the charset file has been loaded with (if loaded) and would be saved with (if would).
|
||||
*/
|
||||
@@ -489,9 +505,14 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
|
||||
return getUserData(CHARSET_KEY) != null;
|
||||
}
|
||||
|
||||
public final void setBinaryContent(byte[] content) throws IOException {
|
||||
setBinaryContent(content, -1, -1);
|
||||
}
|
||||
|
||||
public void setBinaryContent(final byte[] content, long newModificationStamp, long newTimeStamp) throws IOException {
|
||||
setBinaryContent(content, newModificationStamp, newTimeStamp, this);
|
||||
}
|
||||
|
||||
public void setBinaryContent(final byte[] content, long newModificationStamp, long newTimeStamp, Object requestor) throws IOException {
|
||||
OutputStream outputStream = null;
|
||||
try {
|
||||
|
||||
@@ -191,16 +191,16 @@ public class PsiFileFactoryImpl extends PsiFileFactory {
|
||||
public PsiElement createElementFromText(@Nullable final String text,
|
||||
@NotNull final Language language,
|
||||
@NotNull final IElementType type,
|
||||
@NotNull final PsiElement context) {
|
||||
@Nullable final PsiElement context) {
|
||||
if (text == null) return null;
|
||||
final DummyHolder result = DummyHolderFactory.createHolder(context.getManager(), language, context);
|
||||
final DummyHolder result = DummyHolderFactory.createHolder(myManager, language, context);
|
||||
final FileElement holder = result.getTreeElement();
|
||||
|
||||
final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
|
||||
if (parserDefinition == null) {
|
||||
throw new AssertionError("No parser definition for " + language);
|
||||
}
|
||||
final Project project = context.getProject();
|
||||
final Project project = myManager.getProject();
|
||||
final Lexer lexer = parserDefinition.createLexer(project);
|
||||
final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, holder, lexer, language, text);
|
||||
final ASTNode node = parserDefinition.createParser(project).parse(type, builder);
|
||||
|
||||
+5
-2
@@ -564,8 +564,11 @@ public class DocumentationManager {
|
||||
LookupElement item = activeLookup.getCurrentItem();
|
||||
if (item != null) {
|
||||
|
||||
final PsiElement contextElement = file != null ? file.findElementAt(editor.getCaretModel().getOffset()) : null;
|
||||
final PsiReference ref = TargetElementUtilBase.findReference(editor, editor.getCaretModel().getOffset());
|
||||
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset > 0 && offset == editor.getDocument().getTextLength()) offset--;
|
||||
final PsiElement contextElement = file == null? null : file.findElementAt(offset);
|
||||
final PsiReference ref = TargetElementUtilBase.findReference(editor, offset);
|
||||
|
||||
final DocumentationProvider documentationProvider = getProviderFromElement(file);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ContentEntryImpl extends RootModelComponentBase implements ContentE
|
||||
private final TreeSet<ExcludedOutputFolder> myExcludedOutputFolders = new TreeSet<ExcludedOutputFolder>(ContentFolderComparator.INSTANCE);
|
||||
@NonNls public static final String URL_ATTRIBUTE = "url";
|
||||
|
||||
ContentEntryImpl(VirtualFile file, RootModelImpl m) {
|
||||
ContentEntryImpl(@NotNull VirtualFile file, RootModelImpl m) {
|
||||
this(file.getUrl(), m);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -534,7 +534,7 @@ public class RootModelImpl implements ModifiableRootModel {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ContentEntry addContentEntry(VirtualFile file) {
|
||||
public ContentEntry addContentEntry(@NotNull VirtualFile file) {
|
||||
return addContentEntry(new ContentEntryImpl(file, this));
|
||||
}
|
||||
|
||||
|
||||
+1
-17
@@ -91,12 +91,7 @@ public class InjectedLanguageUtil {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
}
|
||||
return result.isEmpty() ? null : result;
|
||||
}
|
||||
|
||||
public static List<Trinity<IElementType, PsiLanguageInjectionHost, TextRange>> getHighlightTokens(PsiFile file) {
|
||||
@@ -206,7 +201,6 @@ public class InjectedLanguageUtil {
|
||||
|
||||
private static final InjectedPsiCachedValueProvider INJECTED_PSI_PROVIDER = new InjectedPsiCachedValueProvider();
|
||||
private static final Key<ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>> INJECTED_PSI = Key.create("INJECTED_PSI");
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static MultiHostRegistrarImpl probeElementsUp(@NotNull PsiElement element, @NotNull PsiFile hostPsiFile, boolean probeUp) {
|
||||
PsiManager psiManager = hostPsiFile.getManager();
|
||||
@@ -228,7 +222,6 @@ public class InjectedLanguageUtil {
|
||||
else {
|
||||
registrar = data.getValue(current);
|
||||
}
|
||||
if (DEBUG) log(current, (registrar == null ? "!": "")+" computed result="+registrar);
|
||||
|
||||
current = current.getParent(); // cache no injection for current
|
||||
|
||||
@@ -256,7 +249,6 @@ public class InjectedLanguageUtil {
|
||||
ProgressManager.checkCanceled();
|
||||
if (registrar == null) {
|
||||
e.putUserData(INJECTED_PSI, null);
|
||||
if (DEBUG) log(e, "Cache .INJECTED_PSI=null");
|
||||
}
|
||||
else {
|
||||
ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> cachedValue =
|
||||
@@ -266,20 +258,12 @@ public class InjectedLanguageUtil {
|
||||
((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>)cachedValue).setValue(result);
|
||||
|
||||
e.putUserData(INJECTED_PSI, cachedValue);
|
||||
|
||||
if (DEBUG) log(e, "Cache .INJECTED_PSI="+result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return registrar;
|
||||
}
|
||||
|
||||
private static void log(PsiElement e, String msg) {
|
||||
//if (e.getClass().getName().equals("com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl")) {
|
||||
// System.out.println(e+": "+ msg + " ("+Thread.currentThread()+")");
|
||||
//}
|
||||
}
|
||||
|
||||
public static PsiElement findInjectedElementNoCommit(@NotNull PsiFile hostFile, final int offset) {
|
||||
if (hostFile instanceof PsiCompiledElement) return null;
|
||||
Project project = hostFile.getProject();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -115,7 +115,8 @@ public class FileBasedIndex implements ApplicationComponent {
|
||||
private final ConcurrentHashSet<ID<?, ?>> myUpToDateIndices = new ConcurrentHashSet<ID<?, ?>>();
|
||||
private final Map<Document, PsiFile> myTransactionMap = new THashMap<Document, PsiFile>();
|
||||
|
||||
private static final int ALREADY_PROCESSED = 0x02;
|
||||
private static final int ALREADY_PROCESSED = 0x04;
|
||||
|
||||
@Nullable private final String myConfigPath;
|
||||
@Nullable private final String mySystemPath;
|
||||
private final boolean myIsUnitTestMode;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -64,15 +64,7 @@ public abstract class LocalFileSystem extends NewVirtualFileSystem {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve a symbolic link represented by given file and returns link target.
|
||||
*
|
||||
* @since 11.0
|
||||
* @param file a file to resolve.
|
||||
* @return <code>this</code> if the file isn't a symbolic link;
|
||||
* instance of <code>VirtualFile</code> if the link was successfully resolved;
|
||||
* <code>null</code> otherwise
|
||||
*/
|
||||
/** @deprecated use {@linkplain com.intellij.openapi.vfs.VirtualFile#getCanonicalFile()} (to remove in IDEA 12) */
|
||||
@Nullable
|
||||
public VirtualFile getRealFile(@NotNull final VirtualFile file) {
|
||||
return file;
|
||||
|
||||
@@ -117,7 +117,7 @@ public class EventLog implements Notifications {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Pair<Notification, Long> getStatusMessage(@Nullable Project project) {
|
||||
public static Trinity<Notification, String, Long> getStatusMessage(@Nullable Project project) {
|
||||
return getLogModel(project).getStatusMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.wm.StatusBar;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -36,8 +36,7 @@ import java.util.*;
|
||||
public class LogModel implements Disposable {
|
||||
private final List<Notification> myNotifications = new ArrayList<Notification>();
|
||||
private final Map<Notification, Long> myStamps = Collections.synchronizedMap(new WeakHashMap<Notification, Long>());
|
||||
private Notification myStatusMessage;
|
||||
private long myStatusTime;
|
||||
private Trinity<Notification, String, Long> myStatusMessage;
|
||||
private final Project myProject;
|
||||
final Map<Notification, Runnable> removeHandlers = new THashMap<Notification, Runnable>();
|
||||
|
||||
@@ -68,18 +67,17 @@ public class LogModel implements Disposable {
|
||||
|
||||
void setStatusMessage(@Nullable Notification statusMessage, long stamp) {
|
||||
synchronized (myNotifications) {
|
||||
if (myStatusMessage == statusMessage) return;
|
||||
if (myStatusMessage != null && myStatusMessage.first == statusMessage) return;
|
||||
|
||||
myStatusMessage = statusMessage;
|
||||
myStatusTime = stamp;
|
||||
myStatusMessage = statusMessage == null ? null : Trinity.create(statusMessage, EventLog.formatForLog(statusMessage, "").status, stamp);
|
||||
}
|
||||
StatusBar.Info.set("", myProject, EventLog.LOG_REQUESTOR);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Pair<Notification, Long> getStatusMessage() {
|
||||
Trinity<Notification, String, Long> getStatusMessage() {
|
||||
synchronized (myNotifications) {
|
||||
return myStatusMessage == null ? null : Pair.create(myStatusMessage, myStatusTime);
|
||||
return myStatusMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +111,7 @@ public class LogModel implements Disposable {
|
||||
UIUtil.invokeLaterIfNeeded(handler);
|
||||
}
|
||||
|
||||
Pair<Notification, Long> oldStatus = getStatusMessage();
|
||||
Trinity<Notification, String, Long> oldStatus = getStatusMessage();
|
||||
if (oldStatus != null && notification == oldStatus.first) {
|
||||
setStatusToImportant();
|
||||
}
|
||||
|
||||
+5
@@ -205,6 +205,11 @@ public class NotificationsManagerImpl extends NotificationsManager implements No
|
||||
final boolean sticky = NotificationDisplayType.STICKY_BALLOON == displayType || noProjects;
|
||||
final Balloon balloon = createBalloon(notification, false, false);
|
||||
Disposer.register(project != null ? project : ApplicationManager.getApplication(), balloon);
|
||||
|
||||
if (notification.isExpired()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
((IdeFrameImpl)window).getBalloonLayout().add(balloon);
|
||||
if (NotificationDisplayType.BALLOON == displayType) {
|
||||
FrameStateManager.getInstance().getApplicationActive().doWhenDone(new Runnable() {
|
||||
|
||||
+16
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -344,37 +344,45 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
|
||||
private static class FileTypeDetectorHolder {
|
||||
private static final FileTypeDetector[] FILE_TYPE_DETECTORS = Extensions.getExtensions(FileTypeDetector.EP_NAME);
|
||||
}
|
||||
|
||||
private static final AtomicInteger DETECTED_COUNT = new AtomicInteger();
|
||||
private static final int DETECT_BUFFER_SIZE = 8192;
|
||||
|
||||
@NotNull
|
||||
private static FileType detectFromContent(@NotNull final VirtualFile file) {
|
||||
try {
|
||||
final long length = file.getLength();
|
||||
final VirtualFile canonicalFile = file.getCanonicalFile();
|
||||
if (canonicalFile == null) {
|
||||
return UnknownFileType.INSTANCE;
|
||||
}
|
||||
|
||||
final long length = canonicalFile.getLength();
|
||||
if (length == 0) {
|
||||
return UnknownFileType.INSTANCE;
|
||||
}
|
||||
VirtualFileSystem fileSystem = file.getFileSystem();
|
||||
|
||||
final VirtualFileSystem fileSystem = canonicalFile.getFileSystem();
|
||||
if (!(fileSystem instanceof FileSystemInterface)) return UnknownFileType.INSTANCE;
|
||||
|
||||
InputStream inputStream = ((FileSystemInterface)fileSystem).getInputStream(file);
|
||||
final InputStream inputStream = ((FileSystemInterface)fileSystem).getInputStream(canonicalFile);
|
||||
final Ref<FileType> result;
|
||||
try {
|
||||
result = new Ref<FileType>(UnknownFileType.INSTANCE);
|
||||
FileUtil.processFirstBytes(inputStream, DETECT_BUFFER_SIZE, new Processor<ByteSequence>() {
|
||||
@Override
|
||||
public boolean process(ByteSequence byteSequence) {
|
||||
boolean isText = guessIfText(file, byteSequence);
|
||||
boolean isText = guessIfText(canonicalFile, byteSequence);
|
||||
CharSequence text;
|
||||
if (isText) {
|
||||
byte[] bytes = Arrays.copyOf(byteSequence.getBytes(), byteSequence.getLength());
|
||||
text = LoadTextUtil.getTextByBinaryPresentation(bytes, file);
|
||||
text = LoadTextUtil.getTextByBinaryPresentation(bytes, canonicalFile);
|
||||
}
|
||||
else {
|
||||
text = null;
|
||||
}
|
||||
FileType detected = null;
|
||||
for (FileTypeDetector detector : FileTypeDetectorHolder.FILE_TYPE_DETECTORS) {
|
||||
detected = detector.detect(file, byteSequence, text);
|
||||
detected = detector.detect(canonicalFile, byteSequence, text);
|
||||
if (detected != null) break;
|
||||
}
|
||||
|
||||
@@ -392,7 +400,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
|
||||
FileType fileType = result.get();
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(file + "; type=" + fileType.getDescription() + "; " + DETECTED_COUNT.incrementAndGet());
|
||||
LOG.debug(canonicalFile + "; type=" + fileType.getDescription() + "; " + DETECTED_COUNT.incrementAndGet());
|
||||
}
|
||||
return fileType;
|
||||
}
|
||||
|
||||
+1
-2
@@ -166,8 +166,7 @@ public final class IdeKeyEventDispatcher implements Disposable {
|
||||
if (focusOwner instanceof ShortcutTextField) {
|
||||
return false;
|
||||
}
|
||||
if (Registry.is("ide.mac.hide.cursor.when.typing") &&
|
||||
(focusOwner instanceof TypingTarget ||
|
||||
if ((focusOwner instanceof TypingTarget ||
|
||||
(focusOwner instanceof JTextComponent && ((JTextComponent)focusOwner).isEditable()))) {
|
||||
if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED && e.getKeyChar() != KeyEvent.VK_ESCAPE) {
|
||||
MacUIUtil.hideCursor();
|
||||
|
||||
-3
@@ -26,7 +26,6 @@ import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.MacUIUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -130,8 +129,6 @@ public final class IdeMouseEventDispatcher {
|
||||
resetPopupTrigger(e);
|
||||
}
|
||||
|
||||
MacUIUtil.showCursor();
|
||||
|
||||
if (!(e.getID() == MouseEvent.MOUSE_PRESSED ||
|
||||
e.getID() == MouseEvent.MOUSE_RELEASED ||
|
||||
e.getID() == MOUSE_CLICKED)) {
|
||||
|
||||
+3
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.components.ApplicationComponent;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileSystemUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
@@ -32,6 +31,7 @@ import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import com.intellij.util.TimeoutUtil;
|
||||
import com.intellij.util.concurrency.JBLock;
|
||||
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
|
||||
import com.intellij.util.concurrency.LockFactory;
|
||||
@@ -324,12 +324,7 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
|
||||
if (application == null || application.isDisposed()) break;
|
||||
|
||||
storeRefreshStatusToFiles();
|
||||
try {
|
||||
sleep(PERIOD);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
//normal situation
|
||||
}
|
||||
TimeoutUtil.sleep(PERIOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,12 +516,6 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
|
||||
else return myNativeFileSystem.isDirectory(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getRealFile(@NotNull final VirtualFile file) {
|
||||
final String realPath = FileSystemUtil.resolveSymLink(file.getPath());
|
||||
return realPath != null ? findFileByPath(realPath) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(@NotNull final VirtualFile file) {
|
||||
if (myNativeFileSystem == null) return super.isWritable(file);
|
||||
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* 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 com.intellij.openapi.vfs.newvfs.impl;
|
||||
|
||||
import com.intellij.openapi.util.NullableComputable;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
|
||||
import com.intellij.openapi.vfs.newvfs.VfsImplUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
* @since 31.10.2011
|
||||
*/
|
||||
@SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod")
|
||||
public class SymlinkDirectory extends VirtualDirectoryImpl {
|
||||
private static final VirtualFileSystemEntry BAD_LINK = new VirtualFileImpl("*BAD_LINK*", null, -1) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
private final String myTargetPath;
|
||||
private VirtualFileSystemEntry myTargetDir;
|
||||
|
||||
public SymlinkDirectory(@NotNull final String name, final VirtualDirectoryImpl parent, @NotNull final NewVirtualFileSystem fs, final int id) {
|
||||
super(name, parent, fs, id);
|
||||
myTargetPath = getFileSystem().resolveSymLink(this);
|
||||
if (myTargetPath == null) {
|
||||
myTargetDir = BAD_LINK;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTargetPath() {
|
||||
return myTargetPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualDirectoryImpl getRealFile() {
|
||||
if (myTargetDir == BAD_LINK) return null;
|
||||
if (myTargetDir != null) return (VirtualDirectoryImpl)myTargetDir;
|
||||
|
||||
final VirtualFile file = findFile(myTargetPath, false);
|
||||
if (!(file instanceof VirtualDirectoryImpl) ||
|
||||
file == this ||
|
||||
FileUtil.isAncestor(new File(file.getPath()), new File(getPath()), true)) {
|
||||
myTargetDir = BAD_LINK;
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
myTargetDir = (VirtualDirectoryImpl)file;
|
||||
}
|
||||
|
||||
return (VirtualDirectoryImpl)myTargetDir;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile findFile(final String path, final boolean refresh) {
|
||||
return RecursionManager.doPreventingRecursion(this, false, new NullableComputable<VirtualFile>() {
|
||||
@Override
|
||||
public VirtualFile compute() {
|
||||
return refresh ? VfsImplUtil.refreshAndFindFileByPath(getFileSystem(), path) : VfsImplUtil.findFileByPath(getFileSystem(), path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFileSystemEntry findChild(@NotNull final String name) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target == null ? null : target.findChild(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildIfCached(@NotNull final String name) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target == null ? null : target.findChildIfCached(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildById(final int id) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target == null ? null : target.findChildById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildByIdIfCached(final int id) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target == null ? null : target.findChildByIdIfCached(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile refreshAndFindChild(@NotNull final String name) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target == null ? null : target.refreshAndFindChild(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VirtualFile[] getChildren() {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target != null ? target.getChildren() : VirtualFile.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VirtualFile> getCachedChildren() {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target != null ? target.getCachedChildren() : Collections.<VirtualFile>emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChild(@NotNull final VirtualFileSystemEntry file) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
if (target != null) {
|
||||
target.addChild(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChild(@NotNull final VirtualFile file) {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
if (target != null) {
|
||||
target.removeChild(file);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<VirtualFile> iterInDbChildren() {
|
||||
final VirtualDirectoryImpl target = getRealFile();
|
||||
return target != null ? target.iterInDbChildren() : Collections.<VirtualFile>emptyList();
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -64,8 +64,6 @@ import java.util.*;
|
||||
* @author max
|
||||
*/
|
||||
public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
public static final boolean ALT_SYMLINK_HANDLING = "true".equalsIgnoreCase(System.getProperty("idea.io.alt.symlink"));
|
||||
|
||||
private static final VirtualFileSystemEntry NULL_VIRTUAL_FILE = new VirtualFileImpl("*?;%NULL", null, -42) {
|
||||
public String toString() {
|
||||
return "NULL";
|
||||
@@ -171,8 +169,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
final VirtualFileSystemEntry child;
|
||||
final NewVirtualFileSystem fs = getFileSystem();
|
||||
if (PersistentFS.isDirectory(id)) {
|
||||
child = ALT_SYMLINK_HANDLING && PersistentFS.isSymLink(id) ? new SymlinkDirectory(name, this, fs, id)
|
||||
: new VirtualDirectoryImpl(name, this, fs, id);
|
||||
child = new VirtualDirectoryImpl(name, this, fs, id);
|
||||
}
|
||||
else {
|
||||
child = new VirtualFileImpl(name, this, id);
|
||||
@@ -207,8 +204,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
if (IS_UNIT_TESTS &&
|
||||
IS_UNDER_TEAMCITY &&
|
||||
ApplicationManager.getApplication() instanceof ApplicationImpl &&
|
||||
((ApplicationImpl)ApplicationManager.getApplication()).isComponentsCreated()
|
||||
&&
|
||||
((ApplicationImpl)ApplicationManager.getApplication()).isComponentsCreated() &&
|
||||
SHOULD_PERFORM_ACCESS_CHECK) {
|
||||
NewVirtualFileSystem fileSystem = child.getFileSystem();
|
||||
if (fileSystem != LocalFileSystem.getInstance() && fileSystem != JarFileSystem.getInstance()) {
|
||||
|
||||
+13
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -60,7 +60,6 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
public NewVirtualFileSystem getFileSystem() {
|
||||
final VirtualFileSystemEntry parent = getParent();
|
||||
assert parent != null;
|
||||
|
||||
return parent.getFileSystem();
|
||||
}
|
||||
|
||||
@@ -76,6 +75,16 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildById(final int id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildByIdIfCached(final int id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile[] getChildren() {
|
||||
return EMPTY_ARRAY;
|
||||
@@ -89,7 +98,7 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
@Override
|
||||
@NotNull
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return VfsUtilCore.inputStreamSkippingBOM(ourPersistence.getInputStream(this),this);
|
||||
return VfsUtilCore.inputStreamSkippingBOM(ourPersistence.getInputStream(this), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,16 +116,6 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
@Override
|
||||
@NotNull
|
||||
public OutputStream getOutputStream(final Object requestor, final long modStamp, final long timeStamp) throws IOException {
|
||||
return VfsUtilCore.outputStreamAddingBOM(ourPersistence.getOutputStream(this, requestor, modStamp, timeStamp),this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildById(int id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewVirtualFile findChildByIdIfCached(int id) {
|
||||
return null;
|
||||
return VfsUtilCore.outputStreamAddingBOM(ourPersistence.getOutputStream(this, requestor, modStamp, timeStamp), this);
|
||||
}
|
||||
}
|
||||
|
||||
+75
-35
@@ -18,6 +18,7 @@ package com.intellij.openapi.vfs.newvfs.impl;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.FileSystemUtil;
|
||||
import com.intellij.openapi.util.io.FileTooBigException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
@@ -27,7 +28,6 @@ import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingRegistry;
|
||||
import com.intellij.openapi.vfs.newvfs.ManagingFS;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -47,19 +47,47 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
|
||||
protected static final PersistentFS ourPersistence = (PersistentFS)ManagingFS.getInstance();
|
||||
|
||||
private static final byte DIRTY_FLAG = 0x01;
|
||||
private static final String EMPTY = "";
|
||||
private static final byte HAS_SYMLINK_FLAG = 0x02;
|
||||
private static final int INT_FLAGS_MASK = 0xe3; // 0b11100011
|
||||
|
||||
@NonNls private static final String EMPTY = "";
|
||||
@NonNls private static final String[] wellKnownSuffixes = {"$1.class", "$2.class", ".class", ".java", ".html", ".txt", ".xml"};
|
||||
|
||||
/** Either a String or byte[]. Possibly should be concatenated with one of the entries in the {@link #wellKnownSuffixes}. */
|
||||
private volatile Object myName;
|
||||
private volatile VirtualDirectoryImpl myParent;
|
||||
private volatile String mySymlinkTarget;
|
||||
/** Also, high three bits are used as an index into the {@link #wellKnownSuffixes} array. */
|
||||
private volatile byte myFlags = 0;
|
||||
private volatile int myId;
|
||||
|
||||
public VirtualFileSystemEntry(@NotNull String name, final VirtualDirectoryImpl parent, int id) {
|
||||
storeName(name);
|
||||
myParent = parent;
|
||||
myId = id;
|
||||
storeName(name);
|
||||
if (parent != null) {
|
||||
calcLinkStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void storeName(@NotNull String name) {
|
||||
myFlags &= 0x1f;
|
||||
for (int i = 0; i < wellKnownSuffixes.length; i++) {
|
||||
String suffix = wellKnownSuffixes[i];
|
||||
if (name.endsWith(suffix)) {
|
||||
name = StringUtil.trimEnd(name, suffix);
|
||||
int mask = (i+1) << 5;
|
||||
myFlags |= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
myName = encodeName(name.replace('\\', '/')); // note: on Unix-style FS names may contain backslashes
|
||||
}
|
||||
|
||||
private void calcLinkStatus() {
|
||||
mySymlinkTarget = isSymLink() ? FileSystemUtil.resolveSymLink(getPath()) : null;
|
||||
setFlagInt(HAS_SYMLINK_FLAG, isSymLink() || ((VirtualFileSystemEntry)myParent).getFlagInt(HAS_SYMLINK_FLAG));
|
||||
}
|
||||
|
||||
private static Object encodeName(@NotNull String name) {
|
||||
@@ -77,22 +105,6 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@NonNls private static final String[] wellKnownSuffixes = { "$1.class", "$2.class", ".class", ".java", ".html", ".txt", ".xml",};
|
||||
private void storeName(@NotNull String name) {
|
||||
myFlags &= 0x1f;
|
||||
for (int i = 0; i < wellKnownSuffixes.length; i++) {
|
||||
String suffix = wellKnownSuffixes[i];
|
||||
if (name.endsWith(suffix)) {
|
||||
name = StringUtil.trimEnd(name, suffix);
|
||||
int mask = (i+1) << 5;
|
||||
myFlags |= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
myName = encodeName(name.replace('\\', '/')); // note: on Unix-style FS names may contain backslashes
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getEncodedSuffix() {
|
||||
int index = (myFlags >> 5) & 0x07;
|
||||
@@ -160,31 +172,39 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlag(int flag_mask, boolean value) {
|
||||
assert (flag_mask & 0xe0) == 0 : "Mask '"+ Integer.toBinaryString(flag_mask)+"' is not supported. High three bits are reserved.";
|
||||
if (value) {
|
||||
myFlags |= flag_mask;
|
||||
}
|
||||
else {
|
||||
myFlags &= ~flag_mask;
|
||||
}
|
||||
public boolean getFlag(int mask) {
|
||||
assert (mask & INT_FLAGS_MASK) == 0 : "Mask '" + Integer.toBinaryString(mask) + "' is in reserved range.";
|
||||
return getFlagInt(mask);
|
||||
}
|
||||
|
||||
private boolean getFlagInt(int mask) {
|
||||
return (myFlags & mask) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFlag(int flag_mask) {
|
||||
assert (flag_mask & 0xe0) == 0 : "Mask '"+ Integer.toBinaryString(flag_mask)+"' is not supported. High three bits are reserved.";
|
||||
return (myFlags & flag_mask) != 0;
|
||||
public void setFlag(int mask, boolean value) {
|
||||
assert (mask & INT_FLAGS_MASK) == 0 : "Mask '" + Integer.toBinaryString(mask) + "' is in reserved range.";
|
||||
setFlagInt(mask, value);
|
||||
}
|
||||
|
||||
private void setFlagInt(int mask, boolean value) {
|
||||
if (value) {
|
||||
myFlags |= mask;
|
||||
}
|
||||
else {
|
||||
myFlags &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markClean() {
|
||||
setFlag(DIRTY_FLAG, false);
|
||||
setFlagInt(DIRTY_FLAG, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
if (!isDirty()) {
|
||||
setFlag(DIRTY_FLAG, true);
|
||||
setFlagInt(DIRTY_FLAG, true);
|
||||
if (myParent != null) myParent.markDirty();
|
||||
}
|
||||
}
|
||||
@@ -396,6 +416,7 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
|
||||
myParent.removeChild(this);
|
||||
myParent = (VirtualDirectoryImpl)newParent;
|
||||
myParent.addChild(this);
|
||||
calcLinkStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -462,8 +483,27 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getRealFile() {
|
||||
final NewVirtualFileSystem fs = getFileSystem();
|
||||
return fs instanceof LocalFileSystem ? ((LocalFileSystem)fs).getRealFile(this) : super.getRealFile();
|
||||
public String getCanonicalPath() {
|
||||
if (getFlagInt(HAS_SYMLINK_FLAG)) {
|
||||
if (isSymLink()) {
|
||||
return mySymlinkTarget;
|
||||
}
|
||||
else if (myParent != null) {
|
||||
return myParent.getCanonicalPath() + "/" + getName();
|
||||
}
|
||||
else {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
return getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getCanonicalFile() {
|
||||
if (getFlagInt(HAS_SYMLINK_FLAG)) {
|
||||
final String path = getCanonicalPath();
|
||||
return path != null ? getFileSystem().findFileByPath(path) : null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+46
-33
@@ -21,6 +21,7 @@ package com.intellij.openapi.vfs.newvfs.persistent;
|
||||
|
||||
import com.intellij.openapi.Forceable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
@@ -52,7 +53,7 @@ import java.util.concurrent.ScheduledFuture;
|
||||
public class FSRecords implements Forceable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.vfs.persistent.FSRecords");
|
||||
|
||||
private static final int VERSION = 13;
|
||||
private static final int VERSION = 14;
|
||||
|
||||
private static final int PARENT_OFFSET = 0;
|
||||
private static final int PARENT_SIZE = 4;
|
||||
@@ -60,15 +61,15 @@ public class FSRecords implements Forceable {
|
||||
private static final int NAME_SIZE = 4;
|
||||
private static final int FLAGS_OFFSET = NAME_OFFSET + NAME_SIZE;
|
||||
private static final int FLAGS_SIZE = 4;
|
||||
private static final int ATTREF_OFFSET = FLAGS_OFFSET + FLAGS_SIZE;
|
||||
private static final int ATTREF_SIZE = 4;
|
||||
private static final int CONTENT_OFFSET = ATTREF_OFFSET + ATTREF_SIZE;
|
||||
private static final int ATTR_REF_OFFSET = FLAGS_OFFSET + FLAGS_SIZE;
|
||||
private static final int ATTR_REF_SIZE = 4;
|
||||
private static final int CONTENT_OFFSET = ATTR_REF_OFFSET + ATTR_REF_SIZE;
|
||||
private static final int CONTENT_SIZE = 4;
|
||||
private static final int TIMESTAMP_OFFSET = CONTENT_OFFSET + CONTENT_SIZE;
|
||||
private static final int TIMESTAMP_SIZE = 8;
|
||||
private static final int MODCOUNT_OFFSET = TIMESTAMP_OFFSET + TIMESTAMP_SIZE;
|
||||
private static final int MODCOUNT_SIZE = 4;
|
||||
private static final int LENGTH_OFFSET = MODCOUNT_OFFSET + MODCOUNT_SIZE;
|
||||
private static final int MOD_COUNT_OFFSET = TIMESTAMP_OFFSET + TIMESTAMP_SIZE;
|
||||
private static final int MOD_COUNT_SIZE = 4;
|
||||
private static final int LENGTH_OFFSET = MOD_COUNT_OFFSET + MOD_COUNT_SIZE;
|
||||
private static final int LENGTH_SIZE = 8;
|
||||
|
||||
private static final int RECORD_SIZE = LENGTH_OFFSET + LENGTH_SIZE;
|
||||
@@ -76,8 +77,8 @@ public class FSRecords implements Forceable {
|
||||
private static final byte[] ZEROES = new byte[RECORD_SIZE];
|
||||
|
||||
private static final int HEADER_VERSION_OFFSET = 0;
|
||||
private static final int HEADER_RESERVED_4BYTES_OFFSET = 4; // Reserved
|
||||
private static final int HEADER_GLOBAL_MODCOUNT_OFFSET = 8;
|
||||
//private static final int HEADER_RESERVED_4BYTES_OFFSET = 4; // reserved
|
||||
private static final int HEADER_GLOBAL_MOD_COUNT_OFFSET = 8;
|
||||
private static final int HEADER_CONNECTION_STATUS_OFFSET = 12;
|
||||
private static final int HEADER_TIMESTAMP_OFFSET = 16;
|
||||
private static final int HEADER_SIZE = HEADER_TIMESTAMP_OFFSET + 8;
|
||||
@@ -143,22 +144,30 @@ public class FSRecords implements Forceable {
|
||||
}
|
||||
|
||||
private static void createBrokenMarkerFile(@Nullable Throwable reason) {
|
||||
File brokenMarker = getCorruptionMarkerFile();
|
||||
final File brokenMarker = getCorruptionMarkerFile();
|
||||
|
||||
try {
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
final PrintStream stream = new PrintStream(out);
|
||||
new Exception().printStackTrace(stream);
|
||||
if (reason != null) {
|
||||
stream.print("\nReason:\n");
|
||||
reason.printStackTrace(stream);
|
||||
try {
|
||||
new Exception().printStackTrace(stream);
|
||||
if (reason != null) {
|
||||
stream.print("\nReason:\n");
|
||||
reason.printStackTrace(stream);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
stream.close();
|
||||
LOG.info("Creating VFS corruption marker; Trace=\n" + out.toString());
|
||||
|
||||
final FileWriter writer = new FileWriter(brokenMarker);
|
||||
writer.write("These files are corrupted and must be rebuilt from the scratch on next startup");
|
||||
writer.close();
|
||||
try {
|
||||
writer.write("These files are corrupted and must be rebuilt from the scratch on next startup");
|
||||
}
|
||||
finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// No luck.
|
||||
@@ -216,8 +225,7 @@ public class FSRecords implements Forceable {
|
||||
try {
|
||||
closeFiles();
|
||||
|
||||
boolean deleted = true;
|
||||
deleted &= FileUtil.delete(getCorruptionMarkerFile());
|
||||
boolean deleted = FileUtil.delete(getCorruptionMarkerFile());
|
||||
deleted &= deleteWithSubordinates(namesFile);
|
||||
deleted &= AbstractStorage.deleteFiles(attributesFile.getCanonicalPath());
|
||||
deleted &= AbstractStorage.deleteFiles(contentsFile.getCanonicalPath());
|
||||
@@ -231,16 +239,21 @@ public class FSRecords implements Forceable {
|
||||
final Runnable warnAndShutdown = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
boolean unitTest = ApplicationManager.getApplication().isUnitTestMode();
|
||||
if (!(unitTest || ApplicationManager.getApplication().isHeadlessEnvironment())) {
|
||||
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
|
||||
"Files in " + basePath.getPath() + " are locked. IntelliJ IDEA will not be able to start up",
|
||||
"Fatal Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
if (unitTest) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
e1.printStackTrace();
|
||||
}
|
||||
else {
|
||||
final String message = "Files in " + basePath.getPath() + " are locked.\n" +
|
||||
ApplicationNamesInfo.getInstance().getProductName() + " will not be able to start up.";
|
||||
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
|
||||
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), message, "Fatal Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
else {
|
||||
//noinspection UseOfSystemOutOrSystemErr
|
||||
System.err.println(message);
|
||||
}
|
||||
}
|
||||
Runtime.getRuntime().halt(1);
|
||||
}
|
||||
};
|
||||
@@ -772,7 +785,7 @@ public class FSRecords implements Forceable {
|
||||
DbConnection.markDirty();
|
||||
ourLocalModificationCount++;
|
||||
final int count = getModCount() + 1;
|
||||
getRecords().putInt(HEADER_GLOBAL_MODCOUNT_OFFSET, count);
|
||||
getRecords().putInt(HEADER_GLOBAL_MOD_COUNT_OFFSET, count);
|
||||
|
||||
int parent = id;
|
||||
while (parent != 0) {
|
||||
@@ -787,7 +800,7 @@ public class FSRecords implements Forceable {
|
||||
|
||||
public static int getModCount() {
|
||||
synchronized (lock) {
|
||||
return getRecords().getInt(HEADER_GLOBAL_MODCOUNT_OFFSET);
|
||||
return getRecords().getInt(HEADER_GLOBAL_MOD_COUNT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,12 +920,12 @@ public class FSRecords implements Forceable {
|
||||
|
||||
public static int getModCount(int id) {
|
||||
synchronized (lock) {
|
||||
return getRecordInt(id, MODCOUNT_OFFSET);
|
||||
return getRecordInt(id, MOD_COUNT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setModCount(int id, int value) {
|
||||
putRecordInt(id, MODCOUNT_OFFSET, value);
|
||||
putRecordInt(id, MOD_COUNT_OFFSET, value);
|
||||
}
|
||||
|
||||
private static int getContentRecordId(int fileId) {
|
||||
@@ -924,11 +937,11 @@ public class FSRecords implements Forceable {
|
||||
}
|
||||
|
||||
private static int getAttributeRecordId(int id) {
|
||||
return getRecordInt(id, ATTREF_OFFSET);
|
||||
return getRecordInt(id, ATTR_REF_OFFSET);
|
||||
}
|
||||
|
||||
private static void setAttributeRecordId(int id, int value) {
|
||||
putRecordInt(id, ATTREF_OFFSET, value);
|
||||
putRecordInt(id, ATTR_REF_OFFSET, value);
|
||||
}
|
||||
|
||||
private static int getRecordInt(int id, int offset) {
|
||||
|
||||
+42
-23
@@ -419,11 +419,14 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
|
||||
@Override
|
||||
public long getLength(@NotNull final VirtualFile file) {
|
||||
final int id = getFileId(file);
|
||||
final VirtualFile canonicalFile = file.getCanonicalFile();
|
||||
if (canonicalFile == null) return 0;
|
||||
|
||||
final int id = getFileId(canonicalFile);
|
||||
|
||||
long len = FSRecords.getLength(id);
|
||||
if (len == -1) {
|
||||
len = (int)getDelegate(file).getLength(file);
|
||||
len = (int)getDelegate(canonicalFile).getLength(canonicalFile);
|
||||
FSRecords.setLength(id, len);
|
||||
}
|
||||
|
||||
@@ -491,16 +494,18 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
|
||||
@NotNull
|
||||
public byte[] contentsToByteArray(@NotNull final VirtualFile file, boolean cacheContent) throws IOException {
|
||||
final VirtualFile canonicalFile = getCanonicalFile(file);
|
||||
|
||||
InputStream contentStream = null;
|
||||
boolean reloadFromDelegate;
|
||||
synchronized (INPUT_LOCK) {
|
||||
reloadFromDelegate = mustReloadContent(file) || (contentStream = readContent(file)) == null;
|
||||
reloadFromDelegate = mustReloadContent(canonicalFile) || (contentStream = readContent(canonicalFile)) == null;
|
||||
}
|
||||
|
||||
if (reloadFromDelegate) {
|
||||
final NewVirtualFileSystem delegate = getDelegate(file);
|
||||
FSRecords.setLength(getFileId(file), delegate.getLength(file));
|
||||
final byte[] content = delegate.contentsToByteArray(file);
|
||||
final NewVirtualFileSystem delegate = getDelegate(canonicalFile);
|
||||
FSRecords.setLength(getFileId(canonicalFile), delegate.getLength(canonicalFile));
|
||||
final byte[] content = delegate.contentsToByteArray(canonicalFile);
|
||||
|
||||
ApplicationEx application = (ApplicationEx)ApplicationManager.getApplication();
|
||||
// we should cache every local files content
|
||||
@@ -509,8 +514,8 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
if ((!delegate.isReadOnly() || !application.isInternal() && !application.isUnitTestMode()) &&
|
||||
content.length <= PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) {
|
||||
synchronized (INPUT_LOCK) {
|
||||
writeContent(file, new ByteSequence(content), delegate.isReadOnly());
|
||||
setFlag(file, MUST_RELOAD_CONTENT, false);
|
||||
writeContent(canonicalFile, new ByteSequence(content), delegate.isReadOnly());
|
||||
setFlag(canonicalFile, MUST_RELOAD_CONTENT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,8 +523,8 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
final int length = (int)file.getLength();
|
||||
assert length >= 0 : file;
|
||||
final int length = (int)canonicalFile.getLength();
|
||||
assert length >= 0 : canonicalFile;
|
||||
return FileUtil.loadBytes(contentStream, length);
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -536,16 +541,17 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
@Override
|
||||
@NotNull
|
||||
public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException {
|
||||
final VirtualFile canonicalFile = getCanonicalFile(file);
|
||||
synchronized (INPUT_LOCK) {
|
||||
InputStream contentStream;
|
||||
if (mustReloadContent(file) || (contentStream = readContent(file)) == null) {
|
||||
final NewVirtualFileSystem delegate = getDelegate(file);
|
||||
final long len = delegate.getLength(file);
|
||||
FSRecords.setLength(getFileId(file), len);
|
||||
final InputStream nativeStream = delegate.getInputStream(file);
|
||||
if (mustReloadContent(canonicalFile) || (contentStream = readContent(canonicalFile)) == null) {
|
||||
final NewVirtualFileSystem delegate = getDelegate(canonicalFile);
|
||||
final long len = delegate.getLength(canonicalFile);
|
||||
FSRecords.setLength(getFileId(canonicalFile), len);
|
||||
final InputStream nativeStream = delegate.getInputStream(canonicalFile);
|
||||
|
||||
if (len > PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD) return nativeStream;
|
||||
return createReplicator(file, nativeStream, len, delegate.isReadOnly());
|
||||
return createReplicator(canonicalFile, nativeStream, len, delegate.isReadOnly());
|
||||
}
|
||||
else {
|
||||
return contentStream;
|
||||
@@ -553,6 +559,15 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static VirtualFile getCanonicalFile(@NotNull final VirtualFile file) throws IOException {
|
||||
final VirtualFile canonicalFile = file.getCanonicalFile();
|
||||
if (canonicalFile == null) {
|
||||
throw new IOException("Broken link: " + file);
|
||||
}
|
||||
return canonicalFile;
|
||||
}
|
||||
|
||||
private InputStream createReplicator(@NotNull final VirtualFile file, final InputStream nativeStream, final long fileLength, final boolean readOnly)
|
||||
throws IOException {
|
||||
if (nativeStream instanceof BufferExposingByteArrayInputStream) {
|
||||
@@ -593,9 +608,13 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public OutputStream getOutputStream(@NotNull final VirtualFile file, final Object requestor, final long modStamp, final long timeStamp)
|
||||
throws IOException {
|
||||
final VFileContentChangeEvent event = new VFileContentChangeEvent(requestor, file, file.getModificationStamp(), modStamp, false);
|
||||
public OutputStream getOutputStream(@NotNull final VirtualFile file,
|
||||
final Object requestor,
|
||||
final long modStamp,
|
||||
final long timeStamp) throws IOException {
|
||||
final VirtualFile canonicalFile = getCanonicalFile(file);
|
||||
|
||||
final VFileContentChangeEvent event = new VFileContentChangeEvent(requestor, canonicalFile, canonicalFile.getModificationStamp(), modStamp, false);
|
||||
|
||||
final List<VFileContentChangeEvent> events = Collections.singletonList(event);
|
||||
|
||||
@@ -607,18 +626,18 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
|
||||
NewVirtualFileSystem delegate = getDelegate(file);
|
||||
final OutputStream outputStream = delegate.getOutputStream(file, requestor, modStamp, timeStamp);
|
||||
NewVirtualFileSystem delegate = getDelegate(canonicalFile);
|
||||
final OutputStream outputStream = delegate.getOutputStream(canonicalFile, requestor, modStamp, timeStamp);
|
||||
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
final DupOutputStream sink = new DupOutputStream(new BufferedOutputStream(writeContent(file, delegate.isReadOnly())), outputStream) {
|
||||
final DupOutputStream sink = new DupOutputStream(new BufferedOutputStream(writeContent(canonicalFile, delegate.isReadOnly())), outputStream) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
super.close();
|
||||
}
|
||||
finally {
|
||||
executeTouch(file, false, event.getModificationStamp());
|
||||
executeTouch(canonicalFile, false, event.getModificationStamp());
|
||||
publisher.after(events);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-11
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs.newvfs.persistent;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
@@ -25,7 +24,6 @@ import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
|
||||
import com.intellij.openapi.vfs.newvfs.events.*;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.SymlinkDirectory;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
|
||||
import com.intellij.util.containers.Queue;
|
||||
@@ -69,11 +67,7 @@ public class RefreshWorker {
|
||||
final VirtualFileSystemEntry file = (VirtualFileSystemEntry)myRefreshQueue.pullFirst();
|
||||
if (!file.isDirty()) continue;
|
||||
|
||||
if (file instanceof SymlinkDirectory) {
|
||||
final int attributes = delegate.getBooleanAttributes(file, -1);
|
||||
scheduleChildRefresh(file.getParent(), file, delegate, attributes);
|
||||
}
|
||||
else if (file.isDirectory()) {
|
||||
if (file.isDirectory()) {
|
||||
final VirtualDirectoryImpl dir = (VirtualDirectoryImpl)file;
|
||||
final boolean fullSync = dir.allChildrenLoaded();
|
||||
if (fullSync) {
|
||||
@@ -159,16 +153,16 @@ public class RefreshWorker {
|
||||
final boolean currentIsDirectory = child.isDirectory();
|
||||
final boolean currentIsSymlink = child.isSymLink();
|
||||
final boolean currentIsSpecial = child.isSpecialFile();
|
||||
final String currentLinkTarget = child instanceof SymlinkDirectory ? ((SymlinkDirectory)child).getTargetPath() : null;
|
||||
//final String currentLinkTarget = child instanceof SymlinkDirectory ? ((SymlinkDirectory)child).getTargetPath() : null;
|
||||
final boolean upToDateIsDirectory = (childAttributes & FileUtil.BA_DIRECTORY) != 0;
|
||||
final boolean upToDateIsSymlink = delegate.isSymLink(child);
|
||||
final boolean upToDateIsSpecial = (childAttributes & SPECIAL_MASK) == FileUtil.BA_EXISTS;
|
||||
final String upToDateLinkTarget = currentLinkTarget != null ? delegate.resolveSymLink(child) : null;
|
||||
//final String upToDateLinkTarget = currentLinkTarget != null ? delegate.resolveSymLink(child) : null;
|
||||
|
||||
if (currentIsDirectory != upToDateIsDirectory ||
|
||||
currentIsSymlink != upToDateIsSymlink ||
|
||||
currentIsSpecial != upToDateIsSpecial ||
|
||||
!Comparing.equal(currentLinkTarget, upToDateLinkTarget)) {
|
||||
currentIsSpecial != upToDateIsSpecial /*||
|
||||
!Comparing.equal(currentLinkTarget, upToDateLinkTarget)*/) {
|
||||
scheduleDeletion(child);
|
||||
scheduleReCreation(parent, child.getName(), upToDateIsDirectory);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEvent
|
||||
if (e instanceof MouseEvent) {
|
||||
MouseEvent me = (MouseEvent)e;
|
||||
Window eventWindow = me.getComponent() instanceof Window ? (Window)me.getComponent() : SwingUtilities.getWindowAncestor(me.getComponent());
|
||||
|
||||
if (isContextMenu(eventWindow)) return false;
|
||||
|
||||
final Window thisGlassWindow = SwingUtilities.getWindowAncestor(myRootPane);
|
||||
|
||||
if (eventWindow instanceof JWindow) {
|
||||
@@ -241,6 +244,18 @@ public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEvent
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
private static boolean isContextMenu(Window window) {
|
||||
if (window != null) {
|
||||
for (Component component : window.getComponents()) {
|
||||
if (component instanceof JComponent
|
||||
&& UIUtil.findComponentOfType((JComponent)component, JPopupMenu.class) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean preprocess(final MouseEvent e, final boolean motion, JRootPane eventRootPane) {
|
||||
try {
|
||||
final MouseEvent event = convertEvent(e, eventRootPane);
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
@@ -152,7 +152,7 @@ class StatusPanel extends JPanel {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
final Project project = getActiveProject();
|
||||
final Pair<Notification, Long> statusMessage = EventLog.getStatusMessage(project);
|
||||
final Trinity<Notification, String, Long> statusMessage = EventLog.getStatusMessage(project);
|
||||
final Alarm alarm = getAlarm();
|
||||
myLogMode = StringUtil.isEmpty(nonLogText) && statusMessage != null && alarm != null;
|
||||
|
||||
@@ -166,10 +166,10 @@ class StatusPanel extends JPanel {
|
||||
@Override
|
||||
public void run() {
|
||||
assert statusMessage != null;
|
||||
String text = EventLog.formatForLog(statusMessage.first, "").status;
|
||||
if (myDirty || System.currentTimeMillis() - statusMessage.second >= DateFormatUtil.MINUTE) {
|
||||
String text = statusMessage.second;
|
||||
if (myDirty || System.currentTimeMillis() - statusMessage.third >= DateFormatUtil.MINUTE) {
|
||||
myTimeStart = text.length() + 1;
|
||||
text += " (" + StringUtil.decapitalize(DateFormatUtil.formatPrettyDateTime(statusMessage.second)) + ")";
|
||||
text += " (" + StringUtil.decapitalize(DateFormatUtil.formatPrettyDateTime(statusMessage.third)) + ")";
|
||||
} else {
|
||||
myTimeStart = -1;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ public class VfsUtilTest extends PlatformLangTestCase {
|
||||
for (int i=0;i< N;i++) {
|
||||
File file = new File(temp, i + ".txt");
|
||||
FileUtil.writeToFile(file, "xxx".getBytes());
|
||||
VirtualFile child = fs.findFileByIoFile(file);
|
||||
VirtualFile child = fs.refreshAndFindFileByIoFile(file);
|
||||
assertNotNull(child);
|
||||
children[i] = child;
|
||||
timestamp[i] = file.lastModified();
|
||||
|
||||
+45
-19
@@ -23,8 +23,8 @@ import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
|
||||
import com.intellij.testFramework.LightPlatformLangTestCase;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -45,12 +45,17 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testBadLinksAreIgnored() throws Exception {
|
||||
if (!SystemInfo.areSymLinksSupported) {
|
||||
System.out.println("Test not passed");
|
||||
return;
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
if (SystemInfo.areSymLinksSupported) {
|
||||
super.runTest();
|
||||
}
|
||||
else {
|
||||
System.err.println("Skipped: " + getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void testBadLinksAreIgnored() throws Exception {
|
||||
final File missingFile = new File(FileUtil.getTempDirectory(), "missing_file");
|
||||
assertTrue(missingFile.getAbsolutePath(), !missingFile.exists() || missingFile.delete());
|
||||
final File missingLinkFile = createTempLink(missingFile.getAbsolutePath(), "missing_link");
|
||||
@@ -76,16 +81,11 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
assertNotNull(circularLink2VFile);
|
||||
assertEquals(1, circularLink1VFile.getChildren().length);
|
||||
assertEquals(1, circularLink2VFile.getChildren().length);
|
||||
if (!VirtualDirectoryImpl.ALT_SYMLINK_HANDLING) {
|
||||
// todo[r.sh] deal with cross-circular links
|
||||
assertEquals(0, circularLink1VFile.getChildren()[0].getChildren().length);
|
||||
assertEquals(0, circularLink2VFile.getChildren()[0].getChildren().length);
|
||||
}
|
||||
assertEquals(0, circularLink1VFile.getChildren()[0].getChildren().length);
|
||||
assertEquals(0, circularLink2VFile.getChildren()[0].getChildren().length);
|
||||
}
|
||||
|
||||
public void testTargetIsWritable() throws Exception {
|
||||
if (!SystemInfo.areSymLinksSupported) return;
|
||||
|
||||
final File targetFile = FileUtil.createTempFile("target", "");
|
||||
final File linkFile = createTempLink(targetFile.getAbsolutePath(), "link");
|
||||
final VirtualFile linkVFile = refreshAndFind(linkFile);
|
||||
@@ -117,8 +117,6 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
}
|
||||
|
||||
public void testLinkDeleteIsSafe() throws Exception {
|
||||
if (!SystemInfo.areSymLinksSupported) return;
|
||||
|
||||
final File targetFile = FileUtil.createTempFile("target", "");
|
||||
final File linkFile = createTempLink(targetFile.getAbsolutePath(), "link");
|
||||
final VirtualFile linkVFile = refreshAndFind(linkFile);
|
||||
@@ -157,8 +155,6 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
}
|
||||
|
||||
public void testTransGenderRefresh() throws Exception {
|
||||
if (!SystemInfo.areSymLinksSupported) return;
|
||||
|
||||
final File targetFile = FileUtil.createTempFile("target", "");
|
||||
final File targetDir = FileUtil.createTempDirectory("targetDir", "");
|
||||
|
||||
@@ -196,8 +192,6 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
}
|
||||
|
||||
public void testLinkSwitch() throws Exception {
|
||||
if (!SystemInfo.areSymLinksSupported) return;
|
||||
|
||||
final File targetDir1 = FileUtil.createTempDirectory("targetDir1", "");
|
||||
final File targetDir2 = FileUtil.createTempDirectory("targetDir2", "");
|
||||
assertTrue(new File(targetDir1, "child1.txt").createNewFile());
|
||||
@@ -219,10 +213,42 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
assertEquals(2, vLink.getChildren().length);
|
||||
}
|
||||
|
||||
public void testContentSynchronization() throws Exception {
|
||||
final File file = FileUtil.createTempFile("file.", ".txt");
|
||||
final VirtualFile vFile = refreshAndFind(file);
|
||||
assertNotNull(file.getPath(), vFile);
|
||||
assertTrue(file.getPath(), vFile.isValid());
|
||||
|
||||
final File link1 = createTempLink(file.getPath(), "link1-" + file.getName());
|
||||
final File link2 = createTempLink(file.getPath(), "link2-" + link1.getName());
|
||||
final VirtualFile vLink = refreshAndFind(link2);
|
||||
assertNotNull(link2.getPath(), vLink);
|
||||
assertTrue(link2.getPath(), vLink.isValid());
|
||||
|
||||
String fileContent = VfsUtilCore.loadText(vFile);
|
||||
assertEquals("", fileContent);
|
||||
String linkContent = VfsUtilCore.loadText(vLink);
|
||||
assertEquals("", linkContent);
|
||||
|
||||
fileContent = "new content";
|
||||
vFile.setBinaryContent(fileContent.getBytes());
|
||||
assertEquals(fileContent.length(), vLink.getLength());
|
||||
assertEquals(fileContent.length(), vFile.getLength());
|
||||
linkContent = VfsUtilCore.loadText(vLink);
|
||||
assertEquals(fileContent, linkContent);
|
||||
|
||||
linkContent = "newer content";
|
||||
vLink.setBinaryContent(linkContent.getBytes());
|
||||
assertEquals(linkContent.length(), vLink.getLength());
|
||||
assertEquals(linkContent.length(), vFile.getLength());
|
||||
fileContent = VfsUtilCore.loadText(vFile);
|
||||
assertEquals(linkContent, fileContent);
|
||||
}
|
||||
|
||||
// todo[r.sh] use NIO2 API after migration to JDK 7
|
||||
private static File createTempLink(final String target, final String link) throws InterruptedException, ExecutionException {
|
||||
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||
|
||||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:.*$");
|
||||
SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$");
|
||||
final File linkFile = isAbsolute ? new File(link) : new File(FileUtil.getTempDirectory(), link);
|
||||
assertTrue(link, !linkFile.exists() || linkFile.delete());
|
||||
final File parentDir = linkFile.getParentFile();
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSchemes;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.impl.DocumentCommitThread;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerImpl;
|
||||
import com.intellij.psi.impl.PsiManagerEx;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl;
|
||||
@@ -188,6 +189,8 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
CodeStyleSettingsManager.getInstance(myProject).setTemporarySettings(new CodeStyleSettings());
|
||||
((InjectedLanguageManagerImpl)InjectedLanguageManager.getInstance(myProject)).pushInjectors();
|
||||
}
|
||||
|
||||
DocumentCommitThread.getInstance().clearQueue();
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
@@ -265,7 +268,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
}
|
||||
|
||||
protected File getIprFile() throws IOException {
|
||||
File tempFile = FileUtil.createTempFile("tmp_" + getName()+"_", ProjectFileType.DOT_DEFAULT_EXTENSION);
|
||||
File tempFile = FileUtil.createTempFile(getName()+"_", ProjectFileType.DOT_DEFAULT_EXTENSION);
|
||||
myFilesToDelete.add(tempFile);
|
||||
return tempFile;
|
||||
}
|
||||
@@ -470,6 +473,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
|
||||
private void disposeProject(@NotNull CompositeException result) /* throws nothing */ {
|
||||
try {
|
||||
DocumentCommitThread.getInstance().clearQueue();
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -478,6 +482,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
try {
|
||||
if (myProject != null) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Disposer.dispose(myProject);
|
||||
ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx();
|
||||
@@ -717,6 +722,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
public static File createTempDir(@NonNls final String prefix) throws IOException {
|
||||
final File tempDirectory = FileUtil.createTempDirectory(TEST_DIR_PREFIX + prefix, null);
|
||||
myFilesToDelete.add(tempDirectory);
|
||||
getVirtualFile(tempDirectory);
|
||||
return tempDirectory;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -42,6 +42,7 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import junit.framework.Assert;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -130,11 +131,11 @@ import java.util.Collection;
|
||||
}.execute().throwException();
|
||||
}
|
||||
|
||||
public static void addSourceContentToRoots(Module module, VirtualFile vDir) {
|
||||
public static void addSourceContentToRoots(Module module, @NotNull VirtualFile vDir) {
|
||||
addSourceContentToRoots(module, vDir, false);
|
||||
}
|
||||
|
||||
public static void addSourceContentToRoots(final Module module, final VirtualFile vDir, final boolean testSource) {
|
||||
public static void addSourceContentToRoots(final Module module, @NotNull final VirtualFile vDir, final boolean testSource) {
|
||||
new WriteCommandAction.Simple(module.getProject()) {
|
||||
@Override
|
||||
protected void run() throws Throwable {
|
||||
|
||||
@@ -20,8 +20,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public final class TimeoutUtil {
|
||||
@@ -54,4 +52,11 @@ public final class TimeoutUtil {
|
||||
public static void executeWithTimeout(long timeout, @NotNull final Runnable run) {
|
||||
executeWithTimeout(timeout, 50, run);
|
||||
}
|
||||
|
||||
public static void sleep(final long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
}
|
||||
catch (InterruptedException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
package com.intellij.util.ui;
|
||||
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -27,7 +28,6 @@ import javax.swing.plaf.TreeUI;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
@@ -39,33 +39,15 @@ public class MacUIUtil {
|
||||
public static final String MAC_FILL_BORDER = "MAC_FILL_BORDER";
|
||||
public static final int MAC_COMBO_BORDER_V_OFFSET = SystemInfo.isMacOSLion ? 1 : 0;
|
||||
private static Cursor INVERTED_TEXT_CURSOR;
|
||||
private static boolean CURSOR_HIDER_LOADED = false;
|
||||
|
||||
static {
|
||||
if (SystemInfo.isMac) {
|
||||
try {
|
||||
System.load(PathManager.getBinPath() + File.separatorChar + "cursorHider.jnilib");
|
||||
CURSOR_HIDER_LOADED = true;
|
||||
} catch (UnsatisfiedLinkError ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private MacUIUtil() {
|
||||
}
|
||||
|
||||
public static void hideCursor() {
|
||||
if (CURSOR_HIDER_LOADED) {
|
||||
doHideCursor();
|
||||
if (SystemInfo.isMac && Registry.is("ide.mac.hide.cursor.when.typing")) {
|
||||
Foundation.invoke("NSCursor", "setHiddenUntilMouseMoves:", true);
|
||||
}
|
||||
}
|
||||
private static native void doHideCursor();
|
||||
|
||||
public static void showCursor() {
|
||||
if (CURSOR_HIDER_LOADED) {
|
||||
doShowCursor();
|
||||
}
|
||||
}
|
||||
private static native void doShowCursor();
|
||||
|
||||
public static class EditorTextFieldBorder implements Border {
|
||||
private JComponent myEnabledComponent;
|
||||
|
||||
@@ -128,6 +128,8 @@
|
||||
serviceImplementation="git4idea.Notificator"/>
|
||||
<projectService serviceInterface="git4idea.history.wholeTree.GitLogSettings"
|
||||
serviceImplementation="git4idea.history.wholeTree.GitLogSettings"/>
|
||||
<projectService serviceInterface="git4idea.roots.GitRootProblemNotifier"
|
||||
serviceImplementation="git4idea.roots.GitRootProblemNotifier"/>
|
||||
|
||||
<applicationService serviceImplementation="git4idea.history.wholeTree.GitCommitsSequentialIndex"
|
||||
serviceInterface="git4idea.history.wholeTree.GitCommitsSequentially"/>
|
||||
|
||||
@@ -28,30 +28,42 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public class Notificator {
|
||||
public class Notificator {
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
private final @NotNull Project myProject;
|
||||
|
||||
public static Notificator getInstance(@NotNull Project project) {
|
||||
return ServiceManager.getService(project, Notificator.class);
|
||||
}
|
||||
|
||||
public Notificator(@NotNull Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message,
|
||||
@NotNull NotificationType type, @Nullable NotificationListener listener) {
|
||||
@NotNull
|
||||
public static Notification createNotification(@NotNull NotificationGroup notificationGroup,
|
||||
@NotNull String title, @NotNull String message, @NotNull NotificationType type,
|
||||
@Nullable NotificationListener listener) {
|
||||
// title can be empty; description can't be neither null, nor empty
|
||||
if (StringUtil.isEmptyOrSpaces(message)) {
|
||||
message = title;
|
||||
title = "";
|
||||
}
|
||||
// if both title and description were empty, then it is a problem in the calling code => Notifications engine assertion will notify.
|
||||
return notificationGroup.createNotification(title, message, type, listener);
|
||||
}
|
||||
|
||||
public void notify(@NotNull Notification notification) {
|
||||
notification.notify(myProject);
|
||||
}
|
||||
|
||||
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 Notificator getInstance(@NotNull Project project) {
|
||||
return ServiceManager.getService(project, Notificator.class);
|
||||
}
|
||||
|
||||
public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type) {
|
||||
public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message,
|
||||
@NotNull NotificationType type) {
|
||||
notify(notificationGroup, title, message, type, null);
|
||||
}
|
||||
|
||||
@@ -63,9 +75,4 @@ import org.jetbrains.annotations.Nullable;
|
||||
notify(GitVcs.NOTIFICATION_GROUP_ID, title, message, NotificationType.INFORMATION, null);
|
||||
}
|
||||
|
||||
protected static Notification createNotification(NotificationGroup notificationGroup, String title, String message,
|
||||
NotificationType type, NotificationListener listener) {
|
||||
return notificationGroup.createNotification(title, message, type, listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme
|
||||
}
|
||||
}
|
||||
|
||||
GitRootProblemNotifier.getInstance(myProject, myPlatformFacade).rescanAndNotifyIfNeeded();
|
||||
GitRootProblemNotifier.getInstance(myProject).rescanAndNotifyIfNeeded();
|
||||
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -18,7 +18,7 @@ package git4idea.roots;
|
||||
import com.intellij.idea.ActionsBundle;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationListener;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -26,15 +26,18 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsRootError;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.PlatformFacade;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import static com.intellij.notification.NotificationType.ERROR;
|
||||
import static com.intellij.openapi.util.text.StringUtil.pluralize;
|
||||
import static git4idea.GitVcs.IMPORTANT_ERROR_NOTIFICATION;
|
||||
import static git4idea.Notificator.createNotification;
|
||||
|
||||
/**
|
||||
* Searches for Git roots problems via {@link GitRootErrorsFinder} and notifies about them.
|
||||
@@ -46,11 +49,16 @@ public class GitRootProblemNotifier {
|
||||
private final @NotNull Project myProject;
|
||||
private final @NotNull PlatformFacade myPlatformFacade;
|
||||
|
||||
public static GitRootProblemNotifier getInstance(@NotNull Project project, @NotNull PlatformFacade platformFacade) {
|
||||
return new GitRootProblemNotifier(project, platformFacade);
|
||||
private @Nullable Notification myNotification;
|
||||
private final @NotNull Object NOTIFICATION_LOCK = new Object();
|
||||
|
||||
public static GitRootProblemNotifier getInstance(@NotNull Project project) {
|
||||
return ServiceManager.getService(project, GitRootProblemNotifier.class);
|
||||
}
|
||||
|
||||
public GitRootProblemNotifier(@NotNull Project project, @NotNull PlatformFacade platformFacade) {
|
||||
// registered as a project service
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private GitRootProblemNotifier(@NotNull Project project, @NotNull PlatformFacade platformFacade) {
|
||||
myProject = project;
|
||||
myPlatformFacade = platformFacade;
|
||||
}
|
||||
@@ -58,6 +66,9 @@ public class GitRootProblemNotifier {
|
||||
public void rescanAndNotifyIfNeeded() {
|
||||
Collection<VcsRootError> errors = scan();
|
||||
if (errors.isEmpty()) {
|
||||
synchronized (NOTIFICATION_LOCK) {
|
||||
expireNotification();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,19 +78,18 @@ public class GitRootProblemNotifier {
|
||||
String title = makeTitle(unregisteredRoots, invalidRoots);
|
||||
String description = makeDescription(unregisteredRoots, invalidRoots);
|
||||
|
||||
myPlatformFacade.getNotificator(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("configure")) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(myProject, ActionsBundle.message("group.VcsGroup.text"));
|
||||
Collection<VcsRootError> errorsAfterPossibleFix = scan();
|
||||
if (errorsAfterPossibleFix.isEmpty() && !notification.isExpired()) {
|
||||
notification.expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
synchronized (NOTIFICATION_LOCK) {
|
||||
expireNotification();
|
||||
myNotification = createNotification(IMPORTANT_ERROR_NOTIFICATION, title, description, ERROR, new MyNotificationListener(myProject));
|
||||
myPlatformFacade.getNotificator(myProject).notify(myNotification);
|
||||
}
|
||||
}
|
||||
|
||||
private void expireNotification() {
|
||||
if (myNotification != null) {
|
||||
myNotification.expire();
|
||||
myNotification = null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -88,7 +98,7 @@ public class GitRootProblemNotifier {
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
|
||||
private static String makeDescription(Collection<VirtualFile> unregisteredRoots, Collection<VirtualFile> invalidRoots) {
|
||||
private static String makeDescription(@NotNull Collection<VirtualFile> unregisteredRoots, @NotNull Collection<VirtualFile> invalidRoots) {
|
||||
Function<VirtualFile, String> rootToString = new Function<VirtualFile, String>() {
|
||||
@Override
|
||||
public String fun(VirtualFile virtualFile) {
|
||||
@@ -126,7 +136,8 @@ public class GitRootProblemNotifier {
|
||||
return description.toString();
|
||||
}
|
||||
|
||||
private static String makeTitle(Collection<VirtualFile> unregisteredRoots, Collection<VirtualFile> invalidRoots) {
|
||||
@NotNull
|
||||
private static String makeTitle(@NotNull Collection<VirtualFile> unregisteredRoots, @NotNull Collection<VirtualFile> invalidRoots) {
|
||||
String title;
|
||||
if (unregisteredRoots.isEmpty()) {
|
||||
title = "Invalid Git " + pluralize("root", invalidRoots.size());
|
||||
@@ -161,4 +172,23 @@ public class GitRootProblemNotifier {
|
||||
return roots;
|
||||
}
|
||||
|
||||
private static class MyNotificationListener implements NotificationListener {
|
||||
|
||||
private final @NotNull Project myProject;
|
||||
|
||||
private MyNotificationListener(@NotNull Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
|
||||
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equals("configure")) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(myProject, ActionsBundle.message("group.VcsGroup.text"));
|
||||
Collection<VcsRootError> errorsAfterPossibleFix = GitRootProblemNotifier.getInstance(myProject).scan();
|
||||
if (errorsAfterPossibleFix.isEmpty() && !notification.isExpired()) {
|
||||
notification.expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user