Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2014-11-07 00:53:01 +01:00
6 changed files with 124 additions and 27 deletions
@@ -19,6 +19,7 @@ package com.intellij.history.core.changes;
import com.intellij.history.core.Content;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.utils.LocalHistoryLog;
import com.intellij.openapi.util.Ref;
import com.intellij.util.Producer;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
@@ -60,15 +61,27 @@ public class ChangeSet {
isLocked = true;
}
public void write(DataOutput out) throws IOException {
public void write(final DataOutput out) throws IOException {
out.writeLong(myId);
StreamUtil.writeStringOrNull(out, myName);
out.writeLong(myTimestamp);
out.writeInt(myChanges.size());
for (Change c : myChanges) {
StreamUtil.writeChange(out, c);
}
final Ref<IOException> ref = new Ref<IOException>();
accessChanges(new Runnable() {
@Override
public void run() {
try {
out.writeInt(myChanges.size());
for (Change c : myChanges) {
StreamUtil.writeChange(out, c);
}
}
catch (IOException e) {
ref.set(e);
}
}
});
if (ref.get() != null) throw ref.get();
}
public void setName(@Nullable String name) {
@@ -0,0 +1,49 @@
/*
* Copyright 2000-2014 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.command.impl;
import com.intellij.openapi.command.undo.DocumentReference;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightVirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class DocumentReferenceByLightVirtualFile implements DocumentReference {
private LightVirtualFile myFile;
DocumentReferenceByLightVirtualFile(@NotNull LightVirtualFile file) {
myFile = file;
}
@Override
@Nullable
public Document getDocument() {
return FileDocumentManager.getInstance().getDocument(myFile);
}
@Override
@NotNull
public VirtualFile getFile() {
return myFile;
}
@Override
public String toString() {
return myFile.toString();
}
}
@@ -19,7 +19,6 @@ import com.intellij.openapi.command.undo.DocumentReference;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightVirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,7 +32,7 @@ public class DocumentReferenceByVirtualFile implements DocumentReference {
@Override
@Nullable
public Document getDocument() {
assert myFile.isValid() || myFile instanceof LightVirtualFile : "should not be called on references to deleted file: " + myFile;
assert myFile.isValid() : "should not be called on references to deleted file: " + myFile;
return FileDocumentManager.getInstance().getDocument(myFile);
}
@@ -46,6 +46,7 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple
private final Map<Document, DocumentReference> myDocToRef = new WeakKeyWeakValueHashMap<Document, DocumentReference>();
private static final Key<Reference<DocumentReference>> FILE_TO_REF_KEY = Key.create("FILE_TO_REF_KEY");
private static final Key<DocumentReference> FILE_TO_STRONG_REF_KEY = Key.create("FILE_TO_STRONG_REF_KEY");
private final Map<FilePath, DocumentReference> myDeletedFilePathToRef = new WeakValueHashMap<FilePath, DocumentReference>();
@Override
@@ -132,7 +133,16 @@ public class DocumentReferenceManagerImpl extends DocumentReferenceManager imple
@Override
public DocumentReference create(@NotNull VirtualFile file) {
assertInDispatchThread();
assert file.isValid() || file instanceof LightVirtualFile : "file is invalid: " + file;
if (file instanceof LightVirtualFile) {
DocumentReference reference = file.getUserData(FILE_TO_STRONG_REF_KEY);
if (reference == null) {
file.putUserData(FILE_TO_STRONG_REF_KEY, reference = new DocumentReferenceByLightVirtualFile((LightVirtualFile)file));
}
return reference;
}
assert file.isValid() : "file is invalid: " + file;
DocumentReference result = SoftReference.dereference(file.getUserData(FILE_TO_REF_KEY));
if (result == null) {
@@ -19,6 +19,7 @@ import com.intellij.openapi.command.undo.DocumentReference;
import com.intellij.openapi.command.undo.DocumentReferenceManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.containers.HashMap;
@@ -35,7 +36,8 @@ class UndoRedoStacksHolder {
private final LinkedList<UndoableGroup> myGlobalStack = new LinkedList<UndoableGroup>();
private final Map<DocumentReference, LinkedList<UndoableGroup>> myDocumentStacks = new HashMap<DocumentReference, LinkedList<UndoableGroup>>();
private final List<Document> myDocumentsWithStacks = new WeakList<Document>();
private final WeakList<Document> myDocumentsWithStacks = new WeakList<Document>();
private final WeakList<LightVirtualFile> myLightVirtualFilesWithStacks = new WeakList<LightVirtualFile>();
public UndoRedoStacksHolder(boolean isUndo) {
myUndo = isUndo;
@@ -43,17 +45,25 @@ class UndoRedoStacksHolder {
@NotNull
LinkedList<UndoableGroup> getStack(@NotNull DocumentReference r) {
VirtualFile file = r.getFile();
return file != null && !(file instanceof LightVirtualFile) ? doGetStackForFile(r) : doGetStackForDocument(r);
return r.getFile() != null ? doGetStackForFile(r) : doGetStackForDocument(r);
}
@NotNull
private LinkedList<UndoableGroup> doGetStackForFile(@NotNull DocumentReference r) {
LinkedList<UndoableGroup> result = myDocumentStacks.get(r);
if (result == null) {
result = new LinkedList<UndoableGroup>();
myDocumentStacks.put(r, result);
LinkedList<UndoableGroup> result;
VirtualFile file = r.getFile();
if (file instanceof LightVirtualFile) {
result = addWeaklyTrackedEmptyStack((LightVirtualFile)file, myLightVirtualFilesWithStacks);
}
else {
result = myDocumentStacks.get(r);
if (result == null) {
result = new LinkedList<UndoableGroup>();
myDocumentStacks.put(r, result);
}
}
return result;
}
@@ -63,12 +73,15 @@ class UndoRedoStacksHolder {
// itself to avoid memory leaks caused by holding stacks of all documents, ever created, here.
// And to know, what documents do exist now, we have to maintain weak reference list of them.
Document d = r.getDocument();
LinkedList<UndoableGroup> result = d.getUserData(STACK_IN_DOCUMENT_KEY);
return addWeaklyTrackedEmptyStack(r.getDocument(), myDocumentsWithStacks);
}
private <T extends UserDataHolder> LinkedList<UndoableGroup> addWeaklyTrackedEmptyStack(T holder, WeakList<T> allHolders) {
LinkedList<UndoableGroup> result;
result = holder.getUserData(STACK_IN_DOCUMENT_KEY);
if (result == null) {
result = new LinkedList<UndoableGroup>();
d.putUserData(STACK_IN_DOCUMENT_KEY, result);
myDocumentsWithStacks.add(d);
holder.putUserData(STACK_IN_DOCUMENT_KEY, result = new LinkedList<UndoableGroup>());
allHolders.add(holder);
}
return result;
}
@@ -164,15 +177,20 @@ class UndoRedoStacksHolder {
}
Set<Document> docsToDrop = new THashSet<Document>();
for (Document each : myDocumentsWithStacks) {
LinkedList<UndoableGroup> stack = each.getUserData(STACK_IN_DOCUMENT_KEY);
cleanWeaklyTrackedEmptyStacks(myDocumentsWithStacks);
cleanWeaklyTrackedEmptyStacks(myLightVirtualFilesWithStacks);
}
private <T extends UserDataHolder> void cleanWeaklyTrackedEmptyStacks(WeakList<T> stackHolders) {
Set<T> holdersToDrop = new THashSet<T>();
for (T holder : stackHolders) {
LinkedList<UndoableGroup> stack = holder.getUserData(STACK_IN_DOCUMENT_KEY);
if (stack != null && stack.isEmpty()) {
each.putUserData(STACK_IN_DOCUMENT_KEY, null);
docsToDrop.add(each);
holder.putUserData(STACK_IN_DOCUMENT_KEY, null);
holdersToDrop.add(holder);
}
}
myDocumentsWithStacks.removeAll(docsToDrop);
stackHolders.removeAll(holdersToDrop);
}
private void clearStacksFrom(@NotNull UndoableGroup from) {
@@ -217,8 +235,13 @@ class UndoRedoStacksHolder {
private void collectLocalAffectedDocuments(@NotNull Collection<DocumentReference> result) {
result.addAll(myDocumentStacks.keySet());
DocumentReferenceManager documentReferenceManager = DocumentReferenceManager.getInstance();
for (Document each : myDocumentsWithStacks) {
result.add(DocumentReferenceManager.getInstance().create(each));
result.add(documentReferenceManager.create(each));
}
for (LightVirtualFile each : myLightVirtualFilesWithStacks) {
result.add(documentReferenceManager.create(each));
}
}
@@ -40,6 +40,7 @@ import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.ui.Gray;
import com.intellij.ui.TabbedPaneWrapper;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
@@ -414,6 +415,8 @@ public class InfoAndProgressPanel extends JPanel implements CustomStatusBarWidge
@NotNull
private static Component getAnchor(@NotNull JRootPane pane) {
Component tabWrapper = UIUtil.findComponentOfType(pane, TabbedPaneWrapper.TabWrapper.class);
if (tabWrapper != null) return tabWrapper;
Component splitters = UIUtil.findComponentOfType(pane, EditorsSplitters.class);
if (splitters != null) return splitters;
FileEditorManagerEx ex = FileEditorManagerEx.getInstanceEx(ProjectUtil.guessCurrentProject(pane));