Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Batkovich
2015-10-16 16:02:18 +03:00
13 changed files with 129 additions and 85 deletions
-1
View File
@@ -84,7 +84,6 @@
<orderEntry type="module" module-name="github" />
<orderEntry type="module" module-name="hg4idea" />
<orderEntry type="module" module-name="relaxng" />
<orderEntry type="module" module-name="gradle" />
<orderEntry type="module" module-name="remote-servers-impl" />
<orderEntry type="module" module-name="dom-tests" />
<orderEntry type="module" module-name="colorSchemes" />
@@ -31,6 +31,8 @@ com.android.tools.idea.rendering.RenderErrorPanelTest
com.android.tools.idea.sdk.VersionCheckTest
org.jetbrains.android.sdk.AndroidSdkUtilsTest
org.jetbrains.android.sdk.AndroidSdkDataTest
com.android.tools.idea.gradle.AndroidGradleModelTest
com.android.tools.idea.gradle.InternalAndroidModelViewTest
com.android.tools.idea.gradle.project.GradleProjectImporterTest
com.android.tools.idea.gradle.compiler.AndroidGradleBuildProcessParametersProviderTest
com.android.tools.idea.sdk.JdksTest
@@ -59,7 +59,8 @@ public class ManualRangeMarker {
if (mySurviveOnExternalChange && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, myRange)) {
PersistentRangeMarker.LinesCols linesCols = myLinesCols != null ? myLinesCols
: PersistentRangeMarker.storeLinesAndCols(myRange, documentBefore);
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair = PersistentRangeMarker.translateViaDiff((DocumentEventImpl)event, linesCols);
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair =
linesCols == null ? null : PersistentRangeMarker.translateViaDiff((DocumentEventImpl)event, linesCols);
if (pair != null) {
return new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, true, pair.second);
}
@@ -79,7 +79,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
}
@Nullable
static Pair<ProperTextRange, LinesCols> translateViaDiff(final DocumentEventImpl event, LinesCols linesCols) {
static Pair<ProperTextRange, LinesCols> translateViaDiff(@NotNull final DocumentEventImpl event, @NotNull LinesCols linesCols) {
try {
int myStartLine = event.translateLineViaDiffStrict(linesCols.myStartLine);
Document document = event.getDocument();
@@ -24,6 +24,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.project.Project;
@@ -202,7 +203,13 @@ public class QuickDocOnMouseOverManager {
return;
}
VisualPosition visualPosition = editor.xyToVisualPosition(e.getMouseEvent().getPoint());
Point point = e.getMouseEvent().getPoint();
if (editor instanceof EditorEx && ((EditorEx)editor).getFoldingModel().getFoldingPlaceholderAt(point) != null) {
closeQuickDocIfPossible();
return;
}
VisualPosition visualPosition = editor.xyToVisualPosition(point);
if (editor.getSoftWrapModel().isInsideOrBeforeSoftWrap(visualPosition)) {
closeQuickDocIfPossible();
return;
@@ -28,7 +28,8 @@ import java.util.List;
* @author dslomov
*/
public abstract class PluggableFileWatcher {
public static final ExtensionPointName<PluggableFileWatcher> EP_NAME = ExtensionPointName.create("com.intellij.vfs.local.pluggableFileWatcher");
public static final ExtensionPointName<PluggableFileWatcher> EP_NAME =
ExtensionPointName.create("com.intellij.vfs.local.pluggableFileWatcher");
public abstract void initialize(@NotNull ManagingFS managingFS, @NotNull FileWatcherNotificationSink notificationSink);
@@ -45,11 +46,11 @@ public abstract class PluggableFileWatcher {
public abstract boolean isWatched(@NotNull VirtualFile file);
public abstract void resetChangedPaths();
public void resetChangedPaths() { }
@TestOnly
public abstract void startup() throws IOException;
@TestOnly
public abstract void shutdown() throws InterruptedException;
}
}
@@ -51,6 +51,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -277,7 +278,7 @@ public class StartupManagerImpl extends StartupManagerEx {
if (!(fs instanceof LocalFileSystemImpl)) return;
FileWatcher watcher = ((LocalFileSystemImpl)fs).getFileWatcher();
if (!watcher.isOperational()) return;
List<String> manualWatchRoots = watcher.getManualWatchRoots();
Collection<String> manualWatchRoots = watcher.getManualWatchRoots();
if (manualWatchRoots.isEmpty()) return;
VirtualFile[] roots = ProjectRootManager.getInstance(myProject).getContentRoots();
if (roots.length == 0) return;
@@ -53,6 +53,7 @@ import com.intellij.openapi.util.ScalableIcon;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.impl.IdeBackgroundUtil;
import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
import com.intellij.ui.HintHint;
import com.intellij.ui.JBColor;
import com.intellij.ui.awt.RelativePoint;
@@ -1362,26 +1363,24 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
void validateMousePointer(@NotNull MouseEvent e) {
Cursor cursor = getCursor();//Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
if (IdeGlassPaneImpl.hasPreProcessedCursor(this)) return;
Cursor cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
FoldRegion foldingAtCursor = findFoldingAnchorAt(e.getX(), e.getY());
setActiveFoldRegion(foldingAtCursor);
boolean updated = false;
if (foldingAtCursor != null) {
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
updated = true;
}
GutterIconRenderer renderer = getGutterRenderer(e);
if (renderer != null) {
if (renderer.isNavigateAction()) {
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
updated = true;
}
}
else {
ActiveGutterRenderer lineRenderer = getActiveRendererByMouseEvent(e);
if (lineRenderer != null) {
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
updated = true;
}
else {
TextAnnotationGutterProvider provider = getProviderAtPoint(e.getPoint());
@@ -1391,15 +1390,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
if (action != null) {
int line = getLineNumAtPoint(e.getPoint());
cursor = action.getCursor(line);
updated = true;
}
}
}
}
}
if (!updated && cursor == Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)) {
cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
}
setCursor(cursor);
}
@@ -119,7 +119,7 @@ public final class UpdateChecker {
ProgressManager.getInstance().run(new Task.Backgroundable(project, IdeBundle.message("updates.checking.progress"), true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
doUpdateAndShowResult(getProject(), !fromSettings, true, settings, indicator, null);
doUpdateAndShowResult(getProject(), fromSettings, true, settings, indicator, null);
}
@Override
@@ -135,7 +135,7 @@ public final class UpdateChecker {
}
private static void doUpdateAndShowResult(@Nullable final Project project,
final boolean enableLink,
final boolean fromSettings,
final boolean manualCheck,
@NotNull final UpdateSettings updateSettings,
@Nullable ProgressIndicator indicator,
@@ -186,7 +186,13 @@ public final class UpdateChecker {
}
incompatiblePlugins = buildNumber != null ? new HashSet<IdeaPluginDescriptor>() : null;
updatedPlugins = checkPluginsUpdate(manualCheck, updateSettings, indicator, incompatiblePlugins, buildNumber);
try {
updatedPlugins = checkPluginsUpdate(updateSettings, indicator, incompatiblePlugins, buildNumber);
}
catch (IOException e) {
showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed", e.getMessage()));
return;
}
}
// show result
@@ -194,12 +200,12 @@ public final class UpdateChecker {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
showUpdateResult(project, result, updateSettings, updatedPlugins, incompatiblePlugins, enableLink, manualCheck);
showUpdateResult(project, result, updateSettings, updatedPlugins, incompatiblePlugins, !fromSettings, manualCheck);
if (callback != null) {
callback.setDone();
}
}
}, ModalityState.NON_MODAL);
}, fromSettings ? ModalityState.any() : ModalityState.NON_MODAL);
}
@NotNull
@@ -244,11 +250,10 @@ public final class UpdateChecker {
return strategy.checkForUpdates();
}
private static Collection<PluginDownloader> checkPluginsUpdate(boolean manualCheck,
@NotNull UpdateSettings updateSettings,
private static Collection<PluginDownloader> checkPluginsUpdate(@NotNull UpdateSettings updateSettings,
@Nullable ProgressIndicator indicator,
@Nullable Collection<IdeaPluginDescriptor> incompatiblePlugins,
@Nullable BuildNumber buildNumber) {
@Nullable BuildNumber buildNumber) throws IOException {
// collect installed plugins and plugins imported from a previous installation
Map<PluginId, IdeaPluginDescriptor> updateable = ContainerUtil.newTroveMap();
@@ -309,7 +314,7 @@ public final class UpdateChecker {
LOG.info("failed to load plugin descriptions from " + host + ": " + e.getMessage());
}
else {
showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed", e.getMessage()));
throw e;
}
}
}
@@ -35,9 +35,9 @@ import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.intellij.util.containers.ContainerUtil.emptyList;
import static com.intellij.util.containers.ContainerUtil.newArrayList;
/**
@@ -54,9 +54,6 @@ public class FileWatcher {
}
};
private final Object myLock = new Object();
private final PluggableFileWatcher[] myWatchers;
public static class DirtyPaths {
public final List<String> dirtyPaths = newArrayList();
public final List<String> dirtyPathsRecursive = newArrayList();
@@ -69,14 +66,15 @@ public class FileWatcher {
}
}
private DirtyPaths myDirtyPaths = new DirtyPaths();
private final AtomicBoolean myFailureShownToTheUser = new AtomicBoolean(false);
private final MyFileWatcherNotificationSink myNotificationSink;
private final PluggableFileWatcher[] myWatchers;
private final AtomicBoolean myFailureShown = new AtomicBoolean(false);
FileWatcher(@NotNull ManagingFS managingFS) {
MyFileWatcherNotificationSink notificationSink = new MyFileWatcherNotificationSink();
myNotificationSink = new MyFileWatcherNotificationSink();
myWatchers = PluggableFileWatcher.EP_NAME.getExtensions();
for (PluggableFileWatcher watcher : myWatchers) {
watcher.initialize(managingFS, notificationSink);
watcher.initialize(managingFS, myNotificationSink);
}
}
@@ -102,37 +100,29 @@ public class FileWatcher {
@NotNull
public DirtyPaths getDirtyPaths() {
synchronized (myLock) {
if (!myDirtyPaths.isEmpty()) {
DirtyPaths dirtyPaths = myDirtyPaths;
myDirtyPaths = new DirtyPaths();
for (PluggableFileWatcher watcher : myWatchers) {
watcher.resetChangedPaths();
}
return dirtyPaths;
}
else {
return DirtyPaths.EMPTY;
}
}
return myNotificationSink.getDirtyPaths();
}
@NotNull
public List<String> getManualWatchRoots() {
public Collection<String> getManualWatchRoots() {
if (myWatchers.length == 1) {
return myWatchers[0].getManualWatchRoots();
}
HashSet<String> result = null;
Set<String> result = null;
for (PluggableFileWatcher watcher : myWatchers) {
List<String> roots = watcher.getManualWatchRoots();
if (result == null) {
result = new HashSet<String>(roots);
} else {
result.retainAll(roots);
Collection<String> roots = watcher.getManualWatchRoots();
if (!roots.isEmpty()) {
if (result == null) {
result = new HashSet<String>(roots);
}
else {
result.retainAll(roots);
}
}
}
if (result == null) return emptyList();
return Collections.list(Collections.enumeration(result));
return result != null ? result : Collections.<String>emptyList();
}
public void setWatchRoots(@NotNull List<String> recursive, @NotNull List<String> flat) {
@@ -151,16 +141,37 @@ public class FileWatcher {
public void notifyOnFailure(final String cause, @Nullable final NotificationListener listener) {
LOG.warn(cause);
if (myFailureShownToTheUser.compareAndSet(false, true)) ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
String title = ApplicationBundle.message("watcher.slow.sync");
Notifications.Bus.notify(NOTIFICATION_GROUP.getValue().createNotification(title, cause, NotificationType.WARNING, listener));
}
}, ModalityState.NON_MODAL);
if (myFailureShown.compareAndSet(false, true)) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
String title = ApplicationBundle.message("watcher.slow.sync");
Notifications.Bus.notify(NOTIFICATION_GROUP.getValue().createNotification(title, cause, NotificationType.WARNING, listener));
}
}, ModalityState.NON_MODAL);
}
}
private class MyFileWatcherNotificationSink implements FileWatcherNotificationSink {
private final Object myLock = new Object();
private DirtyPaths myDirtyPaths = new DirtyPaths();
private DirtyPaths getDirtyPaths() {
synchronized (myLock) {
if (!myDirtyPaths.isEmpty()) {
DirtyPaths dirtyPaths = myDirtyPaths;
myDirtyPaths = new DirtyPaths();
for (PluggableFileWatcher watcher : myWatchers) {
watcher.resetChangedPaths();
}
return dirtyPaths;
}
else {
return DirtyPaths.EMPTY;
}
}
}
@Override
public void notifyDirtyPaths(Collection<String> paths) {
synchronized (myLock) {
@@ -32,6 +32,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ShutDownTracker;
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.VirtualFile;
import com.intellij.openapi.vfs.local.FileWatcherNotificationSink;
@@ -66,13 +67,13 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
private static final int MAX_PROCESS_LAUNCH_ATTEMPT_COUNT = 10;
private ManagingFS myManagingFS;
private FileWatcherNotificationSink myNotificationSink;
private File myExecutable;
private volatile MyProcessHandler myProcessHandler;
private volatile int myStartAttemptCount = 0;
private volatile boolean myIsShuttingDown = false;
private final AtomicInteger mySettingRoots = new AtomicInteger(0);
private final Object myLock = new Object();
private FileWatcherNotificationSink myNotificationSink;
private volatile List<String> myRecursiveWatchRoots = emptyList();
private volatile List<String> myFlatWatchRoots = emptyList();
@@ -280,7 +281,7 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
@Override
public void resetChangedPaths() {
synchronized (myLock) {
synchronized (myLastChangedPaths) {
myLastChangedPathIndex = 0;
for (int i = 0; i < myLastChangedPaths.length; ++i) myLastChangedPaths[i] = null;
}
@@ -375,7 +376,8 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
@Override
public void processTerminated(ProcessEvent event) {
LOG.warn("Watcher terminated with exit code " + event.getExitCode());
String message = "Watcher terminated with exit code " + event.getExitCode();
if (myIsShuttingDown) LOG.info(message); else LOG.warn(message);
myProcessHandler = null;
@@ -444,7 +446,7 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
}
}
else {
String path = line.replace('\0', '\n'); // unescape
String path = StringUtil.trimEnd(line.replace('\0', '\n'), File.separator); // unescape
processChange(path, myLastOp);
myLastOp = null;
}
@@ -482,7 +484,7 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
}
private void processChange(String path, WatcherOp op) {
if (SystemInfo.isWindows && op == WatcherOp.RECDIRTY && path.length() == 3 && Character.isLetter(path.charAt(0))) {
if (SystemInfo.isWindows && op == WatcherOp.RECDIRTY) {
VirtualFile root = LocalFileSystem.getInstance().findFileByPath(path);
if (root != null) {
myNotificationSink.notifyPathsRecursive(list(root.getPresentableUrl()));
@@ -491,25 +493,13 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
return;
}
if (op == WatcherOp.CHANGE) {
// collapse subsequent change file change notifications that happen once we copy large file,
// this allows reduction of path checks at least 20% for Windows
synchronized (myLock) {
for (int i = 0; i < myLastChangedPaths.length; ++i) {
int last = myLastChangedPathIndex - i - 1;
if (last < 0) last += myLastChangedPaths.length;
String lastChangedPath = myLastChangedPaths[last];
if (lastChangedPath != null && lastChangedPath.equals(path)) {
return;
}
}
myLastChangedPaths[myLastChangedPathIndex++] = path;
if (myLastChangedPathIndex == myLastChangedPaths.length) myLastChangedPathIndex = 0;
if ((op == WatcherOp.CHANGE || op == WatcherOp.STATS) && isRepetition(path)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Repetition: " + path);
}
return;
}
int length = path.length();
if (length > 1 && path.charAt(length - 1) == '/') path = path.substring(0, length - 1);
boolean exactPath = op != WatcherOp.DIRTY && op != WatcherOp.RECDIRTY;
Collection<String> paths = checkWatchable(path, exactPath, false);
@@ -547,6 +537,26 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
}
}
private boolean isRepetition(String path) {
// collapse subsequent change file change notifications that happen once we copy large file,
// this allows reduction of path checks at least 20% for Windows
synchronized (myLastChangedPaths) {
for (int i = 0; i < myLastChangedPaths.length; ++i) {
int last = myLastChangedPathIndex - i - 1;
if (last < 0) last += myLastChangedPaths.length;
String lastChangedPath = myLastChangedPaths[last];
if (lastChangedPath != null && lastChangedPath.equals(path)) {
return true;
}
}
myLastChangedPaths[myLastChangedPathIndex++] = path;
if (myLastChangedPathIndex == myLastChangedPaths.length) myLastChangedPathIndex = 0;
}
return false;
}
@SuppressWarnings("TestOnlyProblems")
private void notifyOnAnyEvent() {
myNotificationSink.notifyOnAnyEvent();
@@ -48,6 +48,7 @@ import java.util.List;
public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEventQueue.EventDispatcher {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.IdeGlassPaneImpl");
private static final String PREPROCESSED_CURSOR_KEY = "SuperCursor";
private final List<EventListener> myMouseListeners = new ArrayList<EventListener>();
private final Set<EventListener> mySortedMouseListeners = new TreeSet<EventListener>(new Comparator<EventListener>() {
@@ -345,6 +346,9 @@ public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEvent
}
if (cursor != null && !cursor.equals(target.getCursor())) {
if (target instanceof JComponent) {
((JComponent)target).putClientProperty(PREPROCESSED_CURSOR_KEY, Boolean.TRUE);
}
target.setCursor(cursor);
}
}
@@ -393,9 +397,15 @@ public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEvent
private void restoreLastComponent(Component newC) {
if (myLastCursorComponent != null && myLastCursorComponent != newC) {
myLastCursorComponent.setCursor(myLastOriginalCursor);
if (myLastCursorComponent instanceof JComponent) {
((JComponent)myLastCursorComponent).putClientProperty(PREPROCESSED_CURSOR_KEY, null);
}
}
}
public static boolean hasPreProcessedCursor(@NotNull JComponent component) {
return component.getClientProperty(PREPROCESSED_CURSOR_KEY) != null;
}
public void setCursor(Cursor cursor, @NotNull Object requestor) {
if (cursor == null) {
@@ -123,6 +123,8 @@ format.file.size.bytes={0}b
format.file.size.kbytes={0}Kb
format.file.size.mbytes={0}Mb
profiling.capture.snapshot.progress=Capturing Memory Snapshot
profiling.compress.snapshot.progress=Compressing Memory Snapshot
profiling.capture.snapshot.success=Captured snapshot ''{0}'' is placed in user home directory. <a href="{1}">Show in {2}</a>.
profiling.capture.snapshot.error=Failed to capture snapshot: {0}