diff --git a/platform/platform-resources/src/componentSets/VCS.xml b/platform/platform-resources/src/componentSets/VCS.xml
index e0c79f9198d1..4d3c97aa1ab8 100644
--- a/platform/platform-resources/src/componentSets/VCS.xml
+++ b/platform/platform-resources/src/componentSets/VCS.xml
@@ -27,6 +27,7 @@
com.intellij.openapi.vcs.impl.VcsDirectoryMappingStorage
+ com.intellij.openapi.vcs.impl.LineStatusTrackerManagerI
com.intellij.openapi.vcs.impl.LineStatusTrackerManager
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java
index ffd9d5e87984..113762962af4 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ex.LineStatusTracker;
+import com.intellij.openapi.vcs.ex.LineStatusTrackerDrawing;
import com.intellij.openapi.vcs.ex.Range;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
@@ -92,7 +93,8 @@ public abstract class ShowChangeMarkerAction extends AbstractVcsAction {
LineStatusTracker lineStatusTracker = myChangeMarkerContext.getLineStatusTracker(context);
Range range = myChangeMarkerContext.getRange(context);
- lineStatusTracker.moveToRange(range, editor);
+
+ LineStatusTrackerDrawing.moveToRange(range, editor, lineStatusTracker);
}
protected interface ChangeMarkerContext {
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java
new file mode 100644
index 000000000000..aaa16af64ebd
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2010 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.vcs.ex;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.DumbAware;
+
+import javax.swing.*;
+
+/**
+* @author irengrig
+*/
+public abstract class BaseLineStatusRangeAction extends AnAction implements DumbAware {
+ protected final LineStatusTracker myLineStatusTracker;
+ protected final Range myRange;
+
+ BaseLineStatusRangeAction(final String text, final Icon icon, final LineStatusTracker lineStatusTracker, final Range range) {
+ super(text, null, icon);
+ myLineStatusTracker = lineStatusTracker;
+ myRange = range;
+ }
+
+ public void update(final AnActionEvent e) {
+ e.getPresentation().setEnabled(isEnabled());
+ }
+
+ public abstract boolean isEnabled();
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java
new file mode 100644
index 000000000000..b26db069df84
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2010 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.vcs.ex;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.vcs.VcsBundle;
+
+import java.awt.datatransfer.StringSelection;
+
+/**
+* @author irengrig
+*/
+public class CopyLineStatusRangeAction extends BaseLineStatusRangeAction {
+ CopyLineStatusRangeAction(final LineStatusTracker lineStatusTracker, final Range range) {
+ super(VcsBundle.message("action.name.copy.old.text"), IconLoader.getIcon("/actions/copy.png"), lineStatusTracker, range);
+ }
+
+ public boolean isEnabled() {
+ return Range.DELETED == myRange.getType() || Range.MODIFIED == myRange.getType();
+ }
+
+ public void actionPerformed(final AnActionEvent e) {
+ final String content = myLineStatusTracker.getUpToDateContent(myRange);
+ CopyPasteManager.getInstance().setContents(new StringSelection(content));
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java
index 3e10ad1be452..c74188166afe 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java
@@ -16,6 +16,7 @@
package com.intellij.openapi.vcs.ex;
import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.util.TextRange;
import java.util.ArrayList;
import java.util.List;
@@ -53,10 +54,8 @@ public class DocumentWrapper {
return result;
}
- private String getLine(int i) {
- int lineStartOffset = myDocument.getLineStartOffset(i);
- String line = myDocument.getCharsSequence().subSequence(lineStartOffset, myDocument.getLineEndOffset(i)).toString();
- return line;
+ private String getLine(final int i) {
+ return myDocument.getText(new TextRange(myDocument.getLineStartOffset(i), myDocument.getLineEndOffset(i)));
}
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java
index 4218942fe8a6..3e7d1125997f 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java
@@ -15,135 +15,111 @@
*/
package com.intellij.openapi.vcs.ex;
-import com.intellij.codeInsight.hint.EditorFragmentComponent;
-import com.intellij.codeInsight.hint.HintManagerImpl;
-import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.diff.*;
import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
-import com.intellij.openapi.editor.ScrollType;
-import com.intellij.openapi.editor.colors.EditorColors;
-import com.intellij.openapi.editor.colors.EditorColorsManager;
-import com.intellij.openapi.editor.colors.EditorColorsScheme;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
-import com.intellij.openapi.editor.ex.DocumentEx;
-import com.intellij.openapi.editor.ex.EditorEx;
-import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
-import com.intellij.openapi.editor.highlighter.EditorHighlighter;
-import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.fileEditor.FileDocumentManager;
-import com.intellij.openapi.ide.CopyPasteManager;
-import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsBundle;
-import com.intellij.openapi.vcs.actions.ShowNextChangeMarkerAction;
-import com.intellij.openapi.vcs.actions.ShowPrevChangeMarkerAction;
-import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.ColoredSideBorder;
-import com.intellij.ui.HintListener;
-import com.intellij.ui.LightweightHint;
-import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.datatransfer.StringSelection;
-import java.awt.event.MouseEvent;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
/**
+ * @author irengrig
* author: lesya
*/
public class LineStatusTracker {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.LineStatusTracker");
+ // true -> have contents
+ private boolean myBaseLoaded;
+
private final Document myDocument;
private final Document myUpToDateDocument;
- @SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private List myRanges = new ArrayList();
+
+ private List myRanges;
+
private final Project myProject;
- @SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private int myHighlighterCount = 0;
private MyDocumentListener myDocumentListener;
- private boolean myIsReleased = false;
- private boolean myIsInitialized = false;
private boolean myBulkUpdate;
+ private final Application myApplication;
- public LineStatusTracker(Document document, Document upToDateDocument, Project project) {
+ private LineStatusTracker(final Document document, final Document upToDateDocument, final Project project) {
+ myApplication = ApplicationManager.getApplication();
myDocument = document;
myUpToDateDocument = upToDateDocument;
myUpToDateDocument.putUserData(UndoManager.DONT_RECORD_UNDO, Boolean.TRUE);
myProject = project;
+ myBaseLoaded = false;
+ myRanges = new ArrayList();
}
- public synchronized void initialize(@NotNull final String upToDateContent) {
- if (myIsReleased) return;
- LOG.assertTrue(!myIsInitialized);
- try {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- public void run() {
+ public void initialize(@NotNull final String upToDateContent) {
+ ApplicationManager.getApplication().isReadAccessAllowed();
+ LOG.assertTrue(!myBaseLoaded);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ try {
+ myUpToDateDocument.setReadOnly(false);
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), StringUtil.convertLineSeparators(upToDateContent));
+ myUpToDateDocument.setReadOnly(true);
+ reinstallRanges();
+
+ if (myDocumentListener == null) {
+ myDocumentListener = new MyDocumentListener();
+ myDocument.addDocumentListener(myDocumentListener);
+ }
}
- });
-
- myUpToDateDocument.setReadOnly(true);
- reinstallRanges();
-
- myDocumentListener = new MyDocumentListener();
- myDocument.addDocumentListener(myDocumentListener);
- }
- finally {
- myIsInitialized = true;
- }
+ finally {
+ myBaseLoaded = true;
+ }
+ }
+ });
}
- private synchronized void reinstallRanges() {
- reinstallRanges(new RangesBuilder(myDocument, myUpToDateDocument).getRanges());
- }
+ private void reinstallRanges() {
+ myApplication.assertWriteAccessAllowed();
- private void reinstallRanges(List ranges) {
- removeHighlighters();
- myRanges = ranges;
- addHighlighters();
- }
-
- private void addHighlighters() {
- for (Range range : myRanges) {
- if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
+ removeHighlightersFromMarkupModel();
+ myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges();
+ for (final Range range : myRanges) {
+ range.setHighlighter(createHighlighter(range));
}
}
@SuppressWarnings({"AutoBoxing"})
- synchronized private RangeHighlighter createHighlighter(Range range) {
+ private RangeHighlighter createHighlighter(final Range range) {
int first =
range.getOffset1() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset1());
int second =
range.getOffset2() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset2());
-
- RangeHighlighter highlighter = myDocument.getMarkupModel(myProject)
+ final RangeHighlighter highlighter = myDocument.getMarkupModel(myProject)
.addRangeHighlighter(first, second, HighlighterLayer.FIRST - 1, null, HighlighterTargetArea.LINES_IN_RANGE);
- myHighlighterCount++;
- TextAttributes attr = getAttributesFor(range);
+ final TextAttributes attr = LineStatusTrackerDrawing.getAttributesFor(range);
highlighter.setErrorStripeMarkColor(attr.getErrorStripeColor());
highlighter.setThinErrorStripeMark(true);
highlighter.setGreedyToLeft(true);
highlighter.setGreedyToRight(true);
- highlighter.setLineMarkerRenderer(createRenderer(range));
+ highlighter.setLineMarkerRenderer(LineStatusTrackerDrawing.createRenderer(range, this));
highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter());
final int line1 = myDocument.getLineNumber(first);
final int line2 = myDocument.getLineNumber(second);
@@ -159,141 +135,17 @@ public class LineStatusTracker {
return highlighter;
}
-
- private void removeHighlighters() {
- for (Range oldRange : myRanges) {
- removeHighlighter(oldRange.getHighlighter());
- oldRange.setHighlighter(null);
- }
- }
-
- synchronized void removeHighlighter(RangeHighlighter highlighter) {
- if (highlighter == null) return;
- MarkupModel markupModel = myDocument.getMarkupModel(myProject);
- //noinspection ConstantConditions
- if (markupModel == null) return;
- markupModel.removeHighlighter(highlighter);
- myHighlighterCount--;
- }
-
- private static TextAttributesKey getDiffColor(Range range) {
- switch (range.getType()) {
- case Range.INSERTED:
- return DiffColors.DIFF_INSERTED;
- case Range.DELETED:
- return DiffColors.DIFF_DELETED;
- case Range.MODIFIED:
- return DiffColors.DIFF_MODIFIED;
- default:
- assert false;
- return null;
- }
- }
-
- private static TextAttributesKey getEditorColorNameFor(Range range) {
- switch (range.getType()) {
- case Range.MODIFIED:
- return DiffColors.DIFF_MODIFIED;
- case Range.DELETED:
- return DiffColors.DIFF_DELETED;
- default:
- return DiffColors.DIFF_INSERTED;
- }
- }
-
- private static TextAttributes getAttributesFor(Range range) {
- final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme();
- final Color stripeColor = globalScheme.getAttributes(getEditorColorNameFor(range)).getErrorStripeColor();
- final TextAttributes textAttributes = new TextAttributes(null, stripeColor, null, EffectType.BOXED, Font.PLAIN);
- textAttributes.setErrorStripeColor(stripeColor);
- return textAttributes;
- }
-
- private static void paintGutterFragment(Editor editor, Graphics g, Rectangle r, TextAttributesKey diffAttributeKey) {
- final EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
- final Color stripeColor = editor.getColorsScheme().getAttributes(diffAttributeKey).getErrorStripeColor();
- g.setColor(brighter(stripeColor));
-
- int endX = gutter.getWhitespaceSeparatorOffset();
- int x = r.x + r.width - 2;
- int width = endX - x;
- if (r.height > 0) {
- g.fillRect(x, r.y + 2, width, r.height - 4);
- g.setColor(gutter.getOutlineColor(false));
- UIUtil.drawLine(g, x, r.y + 2, x + width, r.y + 2);
- UIUtil.drawLine(g, x, r.y + 2, x, r.y + r.height - 3);
- UIUtil.drawLine(g, x, r.y + r.height - 3, x + width, r.y + r.height - 3);
- }
- else {
- int[] xPoints = new int[]{x,
- x,
- x + width - 1};
- int[] yPoints = new int[]{r.y - 4,
- r.y + 4,
- r.y};
- g.fillPolygon(xPoints, yPoints, 3);
-
- g.setColor(gutter.getOutlineColor(false));
- g.drawPolygon(xPoints, yPoints, 3);
- }
- }
-
- @Nullable
- private static Color brighter(final Color color) {
- if (color == null) {
- return null;
- }
-
- final float[] hsbStripeColor = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
-
- if (hsbStripeColor[1] < 0.02f) {
- // color is grey
- hsbStripeColor[2] = Math.min(1.0f, hsbStripeColor[2] * 1.3f);
- } else {
- // let's decrease color saturation
- hsbStripeColor[1] *= 0.3;
-
- // max brightness
- hsbStripeColor[2] = 1.0f;
- }
- return Color.getHSBColor(hsbStripeColor[0], hsbStripeColor[1], hsbStripeColor[2]);
- }
-
- private LineMarkerRenderer createRenderer(final Range range) {
- return new ActiveGutterRenderer() {
- public void paint(Editor editor, Graphics g, Rectangle r) {
- paintGutterFragment(editor, g, r, getDiffColor(range));
+ public void release() {
+ myApplication.runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ if (myDocumentListener != null) {
+ myDocument.removeDocumentListener(myDocumentListener);
+ }
+ removeHighlightersFromMarkupModel();
+ myRanges.clear();
}
-
- public void doAction(Editor editor, MouseEvent e) {
- e.consume();
- JComponent comp = (JComponent)e.getComponent(); // shall be EditorGutterComponent, cast is safe.
- JLayeredPane layeredPane = comp.getRootPane().getLayeredPane();
- Point point = SwingUtilities.convertPoint(comp, ((EditorEx)editor).getGutterComponentEx().getWidth(), e.getY(), layeredPane);
- showActiveHint(range, editor, point);
- }
-
- public boolean canDoAction(final MouseEvent e) {
- final EditorGutterComponentEx gutter = (EditorGutterComponentEx)e.getComponent();
- return e.getX() > gutter.getLineMarkerAreaOffset() + gutter.getIconsAreaWidth();
- }
- };
- }
-
- public synchronized void release() {
- try {
- if (!myIsInitialized) return;
- LOG.assertTrue(!myIsReleased);
-
- removeHighlighters();
- if (myDocumentListener != null) {
- myDocument.removeDocumentListener(myDocumentListener);
- myDocumentListener = null;
- }
- }
- finally {
- myIsReleased = true;
- }
+ });
}
public Document getDocument() {
@@ -305,6 +157,8 @@ public class LineStatusTracker {
}
public List getRanges() {
+ myApplication.assertReadAccessAllowed();
+
return myRanges;
}
@@ -313,19 +167,56 @@ public class LineStatusTracker {
}
public void startBulkUpdate() {
- myBulkUpdate = true;
- for (Range oldRange : myRanges) {
- removeHighlighter(oldRange.getHighlighter());
- oldRange.setHighlighter(null);
+ myApplication.runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ myBulkUpdate = true;
+ removeHighlightersFromMarkupModel();
+ myRanges.clear();
+ }
+ });
+ }
+
+ private void removeHighlightersFromMarkupModel() {
+ final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
+ for (Range range : myRanges) {
+ markupModel.removeHighlighter(range.getHighlighter());
}
- myRanges.clear();
}
public void finishBulkUpdate() {
- if (myBulkUpdate) {
- myBulkUpdate = false;
- reinstallRanges();
- }
+ myApplication.runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ myBulkUpdate = false;
+ reinstallRanges();
+ }
+ });
+ }
+
+ /**
+ * @return true if was cleared and base revision contents load should be started
+ * false -> load was already started; after contents is loaded,
+ */
+ public boolean resetForBaseRevisionLoad() {
+ return myApplication.runReadAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ if (!myBaseLoaded) return false;
+ return myApplication.runWriteAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ myUpToDateDocument.setReadOnly(false);
+ myUpToDateDocument.setText("");
+ myUpToDateDocument.setReadOnly(true);
+ removeHighlightersFromMarkupModel();
+ myRanges.clear();
+ myBaseLoaded = false;
+ return true;
+ }
+ });
+ }
+ });
}
private class MyDocumentListener extends DocumentAdapter {
@@ -336,7 +227,9 @@ public class LineStatusTracker {
private int myLinesBeforeChange;
public void beforeDocumentChange(DocumentEvent e) {
- if (myBulkUpdate) return;
+ if (myBulkUpdate || (! myBaseLoaded)) return;
+ myApplication.assertWriteAccessAllowed();
+
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
@@ -382,14 +275,15 @@ public class LineStatusTracker {
}
public void documentChanged(DocumentEvent e) {
- if (myBulkUpdate) return;
+ if (myBulkUpdate || (! myBaseLoaded)) return;
+ myApplication.assertWriteAccessAllowed();
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
int linesShift = linesAfterChange - myLinesBeforeChange;
- List rangesAfterChange = getRangesAfter(myLastChangedLine);
- List rangesBeforeChange = getRangesBefore(myFirstChangedLine);
+ List rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine);
+ List rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine);
List changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
@@ -416,19 +310,10 @@ public class LineStatusTracker {
myRanges.addAll(newChangedRanges);
myRanges.addAll(rangesAfterChange);
- if (myHighlighterCount != myRanges.size()) {
- LOG.error("Highlighters: " + myHighlighterCount + ", ranges: " + myRanges.size());
- }
-
myRanges = mergeRanges(myRanges);
for (Range range : myRanges) {
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
-
- }
-
- if (myHighlighterCount != myRanges.size()) {
- LOG.error("Highlighters: " + myHighlighterCount + ", ranges: " + myRanges.size());
}
}
@@ -442,6 +327,8 @@ public class LineStatusTracker {
}
private List mergeRanges(List ranges) {
+ final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
+
ArrayList result = new ArrayList();
Iterator iterator = ranges.iterator();
if (!iterator.hasNext()) return result;
@@ -449,6 +336,8 @@ public class LineStatusTracker {
while (iterator.hasNext()) {
Range range = iterator.next();
if (prev.canBeMergedWith(range)) {
+ markupModel.removeHighlighter(range.getHighlighter());
+ markupModel.removeHighlighter(prev.getHighlighter());
prev = prev.mergeWith(range, LineStatusTracker.this);
}
else {
@@ -461,8 +350,10 @@ public class LineStatusTracker {
}
private void replaceRanges(List rangesInChange, List newRangesInChange) {
+ final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
+
for (Range range : rangesInChange) {
- removeHighlighter(range.getHighlighter());
+ markupModel.removeHighlighter(range.getHighlighter());
range.setHighlighter(null);
}
for (Range range : newRangesInChange) {
@@ -491,9 +382,51 @@ public class LineStatusTracker {
return result;
}
- private List getRangesBefore(int line) {
- return getRangesBefore(myRanges, line);
+ @Nullable
+ Range getNextRange(final Range range) {
+ final int index = myRanges.indexOf(range);
+ if (index == myRanges.size() - 1) return null;
+ return myRanges.get(index + 1);
+ }
+ @Nullable
+ Range getPrevRange(final Range range) {
+ final int index = myRanges.indexOf(range);
+ if (index <= 0) return null;
+ return myRanges.get(index - 1);
+ }
+
+ @Nullable
+ public Range getNextRange(final int line) {
+ final Range currentRange = getRangeForLine(line);
+ if (currentRange != null) {
+ return getNextRange(currentRange);
+ }
+
+ for (final Range range : myRanges) {
+ if (line > range.getOffset1() || line > range.getOffset2()) {
+ continue;
+ }
+ return range;
+ }
+ return null;
+ }
+
+ @Nullable
+ public Range getPrevRange(final int line) {
+ final Range currentRange = getRangeForLine(line);
+ if (currentRange != null) {
+ return getPrevRange(currentRange);
+ }
+
+ for (ListIterator iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
+ final Range range = iterator.previous();
+ if (range.getOffset1() > line) {
+ continue;
+ }
+ return range;
+ }
+ return null;
}
public static List getRangesBefore(List ranges, int line) {
@@ -506,10 +439,6 @@ public class LineStatusTracker {
return result;
}
- private List getRangesAfter(int line) {
- return getRangesAfter(myRanges, line);
- }
-
public static List getRangesAfter(List ranges, int line) {
ArrayList result = new ArrayList();
for (Range range : ranges) {
@@ -518,69 +447,6 @@ public class LineStatusTracker {
return result;
}
- public void moveToRange(final Range range, final Editor editor) {
- final int firstOffset = myDocument.getLineStartOffset(Math.min(range.getOffset1(), myDocument.getLineCount() - 1));
- editor.getCaretModel().moveToOffset(firstOffset);
- editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
-
- editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
- public void run() {
- Point p = editor.visualPositionToXY(editor.offsetToVisualPosition(firstOffset));
- JComponent editorComponent = editor.getContentComponent();
- JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
- p = SwingUtilities.convertPoint(editorComponent, 0, p.y, layeredPane);
- showActiveHint(range, editor, p);
- }
- });
- }
-
- @Nullable
- private Range getNextRange(Range range) {
- int index = myRanges.indexOf(range);
- if (index == myRanges.size() - 1) return null;
- return myRanges.get(index + 1);
- }
-
- @Nullable
- private Range getPrevRange(Range range) {
- int index = myRanges.indexOf(range);
- if (index <= 0) return null;
- return myRanges.get(index - 1);
- }
-
- @Nullable
- public Range getNextRange(int line) {
- final Range currentRange = getRangeForLine(line);
- if (currentRange != null) {
- return getNextRange(currentRange);
- }
-
- for (Range range : myRanges) {
- if (line > range.getOffset1() || line > range.getOffset2()) {
- continue;
- }
- return range;
- }
- return null;
- }
-
- @Nullable
- public Range getPrevRange(int line) {
- final Range currentRange = getRangeForLine(line);
- if (currentRange != null) {
- return getPrevRange(currentRange);
- }
-
- for (ListIterator iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
- Range range = iterator.previous();
- if (range.getOffset1() > line) {
- continue;
- }
- return range;
- }
- return null;
- }
-
@Nullable
public Range getRangeForLine(final int line) {
for (final Range range : myRanges) {
@@ -594,63 +460,9 @@ public class LineStatusTracker {
return null;
}
- public static abstract class MyAction extends AnAction implements DumbAware {
- protected final LineStatusTracker myLineStatusTracker;
- protected final Range myRange;
+ public void rollbackChanges(final Range range) {
+ myApplication.assertWriteAccessAllowed();
- protected MyAction(String text, Icon icon, LineStatusTracker lineStatusTracker, Range range) {
- super(text, null, icon);
- myLineStatusTracker = lineStatusTracker;
- myRange = range;
- }
-
- public void update(AnActionEvent e) {
- e.getPresentation().setEnabled(isEnabled());
- }
-
- public abstract boolean isEnabled();
-
- protected int getMyRangeIndex() {
- List ranges = myLineStatusTracker.getRanges();
- for (int i = 0; i < ranges.size(); i++) {
- Range range = ranges.get(i);
- if (range.getOffset1() == myRange.getOffset1() && range.getOffset2() == myRange.getOffset2()) {
- return i;
- }
- }
- return -1;
- }
- }
-
- public static class RollbackAction extends LineStatusTracker.MyAction {
- public RollbackAction(LineStatusTracker lineStatusTracker, Range range, Editor editor) {
- super(VcsBundle.message("action.name.rollback"), IconLoader.getIcon("/actions/reset.png"), lineStatusTracker, range);
- }
-
- public boolean isEnabled() {
- return true;
- }
-
- public void actionPerformed(AnActionEvent e) {
- CommandProcessor.getInstance().executeCommand(myLineStatusTracker.getProject(), new Runnable() {
- public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- public void run() {
- if (!myLineStatusTracker.getDocument().isWritable()) {
- final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler
- .getInstance(myLineStatusTracker.getProject()).ensureFilesWritable(myLineStatusTracker.getVirtualFile());
- if (operationStatus.hasReadonlyFiles()) return;
- }
- myLineStatusTracker.rollbackChanges(myRange);
- }
- });
- }
- }, VcsBundle.message("command.name.rollback.change"), null);
-
- }
- }
-
- public void rollbackChanges(Range range) {
TextRange currentTextRange = getCurrentTextRange(range);
if (range.getType() == Range.INSERTED) {
@@ -676,81 +488,25 @@ public class LineStatusTracker {
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
}
- private Project getProject() {
+ Project getProject() {
return myProject;
}
- public class ShowDiffAction extends LineStatusTracker.MyAction {
- public ShowDiffAction(LineStatusTracker lineStatusTracker, Range range, Editor editor) {
- super(VcsBundle.message("action.name.show.difference"), IconLoader.getIcon("/actions/diff.png"), lineStatusTracker, range);
- }
-
- public boolean isEnabled() {
- return isModifiedRange() || isDeletedRange();
- }
-
- private boolean isDeletedRange() {
- return myRange.getType() == Range.DELETED;
- }
-
- private boolean isModifiedRange() {
- return myRange.getType() == Range.MODIFIED;
- }
-
- public void actionPerformed(AnActionEvent e) {
- DiffManager.getInstance().getDiffTool().show(createDiffData());
- }
-
- private DiffRequest createDiffData() {
- return new DiffRequest(myLineStatusTracker.getProject()) {
- public DiffContent[] getContents() {
- return new DiffContent[]{createDiffContent(myLineStatusTracker.getUpToDateDocument(),
- myLineStatusTracker.getUpToDateRange(myRange), null),
- createDiffContent(myLineStatusTracker.getDocument(), myLineStatusTracker.getCurrentTextRange(myRange),
- myLineStatusTracker.getVirtualFile())};
- }
-
- public String[] getContentTitles() {
- return new String[]{VcsBundle.message("diff.content.title.up.to.date"),
- VcsBundle.message("diff.content.title.current.range")};
- }
-
- public String getWindowTitle() {
- return VcsBundle.message("dialog.title.diff.for.range");
- }
- };
- }
-
- private DiffContent createDiffContent(final Document uDocument, TextRange textRange, VirtualFile file) {
- DiffContent diffContent = new DocumentContent(myProject, uDocument);
- return new FragmentContent(diffContent, textRange, myLineStatusTracker.getProject(), file);
- }
+ TextRange getCurrentTextRange(Range range) {
+ return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument, false);
}
- public class CopyAction extends MyAction {
- protected CopyAction(LineStatusTracker lineStatusTracker, Range range) {
- super(VcsBundle.message("action.name.copy.old.text"), IconLoader.getIcon("/actions/copy.png"), lineStatusTracker, range);
- }
-
- public boolean isEnabled() {
- return myRange.getType() == Range.DELETED || myRange.getType() == Range.MODIFIED;
- }
-
- public void actionPerformed(final AnActionEvent e) {
- final String content = myLineStatusTracker.getUpToDateContent(myRange);
- CopyPasteManager.getInstance().setContents(new StringSelection(content));
- }
+ TextRange getUpToDateRange(Range range) {
+ return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, false);
}
- private TextRange getCurrentTextRange(Range range) {
- return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument);
+ // a hack
+ TextRange getUpToDateRangeWithEndSymbol(Range range) {
+ return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, true);
}
- private TextRange getUpToDateRange(Range range) {
- return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument);
- }
-
- private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) {
+ private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document,
+ final boolean keepEnd) {
if (rangeType == emptyRangeCondition) {
int lineStartOffset;
if (offset1 == 0) {
@@ -767,104 +523,28 @@ public class LineStatusTracker {
int startOffset = document.getLineStartOffset(offset1);
int endOffset = document.getLineEndOffset(offset2 - 1);
if (startOffset > 0) {
- startOffset--;
- endOffset--;
+ -- startOffset;
+ if (! keepEnd) {
+ -- endOffset;
+ }
}
return new TextRange(startOffset, endOffset);
}
}
-
- public void showActiveHint(Range range, final Editor editor, Point point) {
-
- DefaultActionGroup group = new DefaultActionGroup();
-
- final AnAction globalShowNextAction = ActionManager.getInstance().getAction("VcsShowNextChangeMarker");
- final AnAction globalShowPrevAction = ActionManager.getInstance().getAction("VcsShowPrevChangeMarker");
-
- final ShowPrevChangeMarkerAction localShowPrevAction = new ShowPrevChangeMarkerAction(getPrevRange(range), this, editor);
- final ShowNextChangeMarkerAction localShowNextAction = new ShowNextChangeMarkerAction(getNextRange(range), this, editor);
-
- JComponent editorComponent = editor.getComponent();
-
- localShowNextAction.registerCustomShortcutSet(localShowNextAction.getShortcutSet(), editorComponent);
- localShowPrevAction.registerCustomShortcutSet(localShowPrevAction.getShortcutSet(), editorComponent);
-
- group.add(localShowPrevAction);
- group.add(localShowNextAction);
-
- localShowNextAction.copyFrom(globalShowNextAction);
- localShowPrevAction.copyFrom(globalShowPrevAction);
-
- group.add(new RollbackAction(this, range, editor));
- group.add(new ShowDiffAction(this, range, editor));
- group.add(new CopyAction(this, range));
-
- final List actionList = (List)editorComponent.getClientProperty(AnAction.ourClientProperty);
-
- actionList.remove(globalShowPrevAction);
- actionList.remove(globalShowNextAction);
-
- JComponent toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true).getComponent();
-
- final Color background = ((EditorEx)editor).getBackgroundColor();
- final Color foreground = editor.getColorsScheme().getColor(EditorColors.CARET_COLOR);
- toolbar.setBackground(background);
-
- toolbar.setBorder(new ColoredSideBorder(foreground, foreground, range.getType() != Range.INSERTED ? null : foreground, foreground, 1));
-
- JPanel component = new JPanel(new BorderLayout());
- component.setOpaque(false);
-
- JPanel toolbarPanel = new JPanel(new BorderLayout());
- toolbarPanel.setOpaque(false);
- toolbarPanel.add(toolbar, BorderLayout.WEST);
- component.add(toolbarPanel, BorderLayout.NORTH);
-
- if (range.getType() != Range.INSERTED) {
- DocumentEx doc = (DocumentEx)myUpToDateDocument;
- EditorEx uEditor = (EditorEx)EditorFactory.getInstance().createViewer(doc, myProject);
- EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(myProject, getFileName());
- uEditor.setHighlighter(highlighter);
-
- EditorFragmentComponent editorFragmentComponent =
- EditorFragmentComponent.createEditorFragmentComponent(uEditor, range.getUOffset1(), range.getUOffset2(), false, false);
-
- component.add(editorFragmentComponent, BorderLayout.CENTER);
- EditorFactory.getInstance().releaseEditor(uEditor);
- }
-
- LightweightHint lightweightHint = new LightweightHint(component);
- lightweightHint.addHintListener(new HintListener() {
- public void hintHidden(EventObject event) {
- actionList.remove(localShowPrevAction);
- actionList.remove(localShowNextAction);
- actionList.add(globalShowPrevAction);
- actionList.add(globalShowNextAction);
- }
- });
-
- HintManagerImpl.getInstanceImpl().showEditorHint(lightweightHint, editor, point, HintManagerImpl.HIDE_BY_ANY_KEY | HintManagerImpl.HIDE_BY_TEXT_CHANGE |
- HintManagerImpl.HIDE_BY_OTHER_HINT | HintManagerImpl.HIDE_BY_SCROLLING,
- -1, false);
- }
-
- private String getFileName() {
- VirtualFile file = FileDocumentManager.getInstance().getFile(myDocument);
- if (file == null) return "";
- return file.getName();
- }
-
- public static LineStatusTracker createOn(Document doc, String upToDateContent, Project project) {
- Document document = EditorFactory.getInstance().createDocument(StringUtil.convertLineSeparators(upToDateContent));
+ public static LineStatusTracker createOn(final Document doc, final String upToDateContent, final Project project) {
+ final Document document = EditorFactory.getInstance().createDocument(StringUtil.convertLineSeparators(upToDateContent));
final LineStatusTracker tracker = new LineStatusTracker(doc, document, project);
tracker.initialize(upToDateContent);
return tracker;
}
- public static LineStatusTracker createOn(Document doc, Project project) {
- Document document = EditorFactory.getInstance().createDocument("");
+ public static LineStatusTracker createOn(final Document doc, final Project project) {
+ final Document document = EditorFactory.getInstance().createDocument("");
return new LineStatusTracker(doc, document, project);
}
+ public boolean isBaseLoaded() {
+ return myBaseLoaded;
+ }
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java
new file mode 100644
index 000000000000..53d50e986dc3
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2000-2010 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.vcs.ex;
+
+import com.intellij.codeInsight.hint.EditorFragmentComponent;
+import com.intellij.codeInsight.hint.HintManagerImpl;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.ActionPlaces;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.diff.DiffColors;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.editor.colors.EditorColors;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.editor.ex.DocumentEx;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
+import com.intellij.openapi.editor.highlighter.EditorHighlighter;
+import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
+import com.intellij.openapi.editor.markup.ActiveGutterRenderer;
+import com.intellij.openapi.editor.markup.EffectType;
+import com.intellij.openapi.editor.markup.LineMarkerRenderer;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vcs.actions.ShowNextChangeMarkerAction;
+import com.intellij.openapi.vcs.actions.ShowPrevChangeMarkerAction;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.ColoredSideBorder;
+import com.intellij.ui.HintListener;
+import com.intellij.ui.LightweightHint;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.util.EventObject;
+
+/**
+ * @author irengrig
+ */
+public class LineStatusTrackerDrawing {
+ private LineStatusTrackerDrawing() {
+ }
+
+ static TextAttributes getAttributesFor(final Range range) {
+ final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme();
+ final Color stripeColor = globalScheme.getAttributes(getDiffColor(range)).getErrorStripeColor();
+ final TextAttributes textAttributes = new TextAttributes(null, stripeColor, null, EffectType.BOXED, Font.PLAIN);
+ textAttributes.setErrorStripeColor(stripeColor);
+ return textAttributes;
+ }
+
+ private static void paintGutterFragment(final Editor editor, final Graphics g, final Rectangle r, final TextAttributesKey diffAttributeKey) {
+ final EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
+ final Color stripeColor = editor.getColorsScheme().getAttributes(diffAttributeKey).getErrorStripeColor();
+ g.setColor(brighter(stripeColor));
+
+ final int endX = gutter.getWhitespaceSeparatorOffset();
+ final int x = r.x + r.width - 2;
+ final int width = endX - x;
+ if (r.height > 0) {
+ g.fillRect(x, r.y + 2, width, r.height - 4);
+ g.setColor(gutter.getOutlineColor(false));
+ UIUtil.drawLine(g, x, r.y + 2, x + width, r.y + 2);
+ UIUtil.drawLine(g, x, r.y + 2, x, r.y + r.height - 3);
+ UIUtil.drawLine(g, x, r.y + r.height - 3, x + width, r.y + r.height - 3);
+ }
+ else {
+ final int[] xPoints = new int[]{x,
+ x,
+ x + width - 1};
+ final int[] yPoints = new int[]{r.y - 4,
+ r.y + 4,
+ r.y};
+ g.fillPolygon(xPoints, yPoints, 3);
+
+ g.setColor(gutter.getOutlineColor(false));
+ g.drawPolygon(xPoints, yPoints, 3);
+ }
+ }
+
+ @Nullable
+ private static Color brighter(final Color color) {
+ if (color == null) {
+ return null;
+ }
+
+ final float[] hsbStripeColor = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
+
+ if (hsbStripeColor[1] < 0.02f) {
+ // color is grey
+ hsbStripeColor[2] = Math.min(1.0f, hsbStripeColor[2] * 1.3f);
+ } else {
+ // let's decrease color saturation
+ hsbStripeColor[1] *= 0.3;
+
+ // max brightness
+ hsbStripeColor[2] = 1.0f;
+ }
+ return Color.getHSBColor(hsbStripeColor[0], hsbStripeColor[1], hsbStripeColor[2]);
+ }
+
+ public static LineMarkerRenderer createRenderer(final Range range, final LineStatusTracker tracker) {
+ return new ActiveGutterRenderer() {
+ public void paint(final Editor editor, final Graphics g, final Rectangle r) {
+ paintGutterFragment(editor, g, r, getDiffColor(range));
+ }
+
+ public void doAction(final Editor editor, final MouseEvent e) {
+ e.consume();
+ final JComponent comp = (JComponent)e.getComponent(); // shall be EditorGutterComponent, cast is safe.
+ final JLayeredPane layeredPane = comp.getRootPane().getLayeredPane();
+ final Point point = SwingUtilities.convertPoint(comp, ((EditorEx)editor).getGutterComponentEx().getWidth(), e.getY(), layeredPane);
+ showActiveHint(range, editor, point, tracker);
+ }
+
+ public boolean canDoAction(final MouseEvent e) {
+ final EditorGutterComponentEx gutter = (EditorGutterComponentEx)e.getComponent();
+ return e.getX() > gutter.getLineMarkerAreaOffset() + gutter.getIconsAreaWidth();
+ }
+ };
+ }
+
+ public static void showActiveHint(final Range range, final Editor editor, final Point point, final LineStatusTracker tracker) {
+
+ final DefaultActionGroup group = new DefaultActionGroup();
+
+ final AnAction globalShowNextAction = ActionManager.getInstance().getAction("VcsShowNextChangeMarker");
+ final AnAction globalShowPrevAction = ActionManager.getInstance().getAction("VcsShowPrevChangeMarker");
+
+ final ShowPrevChangeMarkerAction localShowPrevAction = new ShowPrevChangeMarkerAction(tracker.getPrevRange(range), tracker, editor);
+ final ShowNextChangeMarkerAction localShowNextAction = new ShowNextChangeMarkerAction(tracker.getNextRange(range), tracker, editor);
+
+ final JComponent editorComponent = editor.getComponent();
+
+ localShowNextAction.registerCustomShortcutSet(localShowNextAction.getShortcutSet(), editorComponent);
+ localShowPrevAction.registerCustomShortcutSet(localShowPrevAction.getShortcutSet(), editorComponent);
+
+ group.add(localShowPrevAction);
+ group.add(localShowNextAction);
+
+ localShowNextAction.copyFrom(globalShowNextAction);
+ localShowPrevAction.copyFrom(globalShowPrevAction);
+
+ group.add(new RollbackLineStatusRangeAction(tracker, range, editor));
+ group.add(new ShowLineStatusRangeDiffAction(tracker, range, editor));
+ group.add(new CopyLineStatusRangeAction(tracker, range));
+
+ final java.util.List actionList = (java.util.List)editorComponent.getClientProperty(AnAction.ourClientProperty);
+
+ actionList.remove(globalShowPrevAction);
+ actionList.remove(globalShowNextAction);
+
+ final JComponent toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true).getComponent();
+
+ final Color background = ((EditorEx)editor).getBackgroundColor();
+ final Color foreground = editor.getColorsScheme().getColor(EditorColors.CARET_COLOR);
+ toolbar.setBackground(background);
+
+ toolbar.setBorder(new ColoredSideBorder(foreground, foreground, (range.getType() != Range.INSERTED) ? null : foreground, foreground, 1));
+
+ final JPanel component = new JPanel(new BorderLayout());
+ component.setOpaque(false);
+
+ final JPanel toolbarPanel = new JPanel(new BorderLayout());
+ toolbarPanel.setOpaque(false);
+ toolbarPanel.add(toolbar, BorderLayout.WEST);
+ component.add(toolbarPanel, BorderLayout.NORTH);
+
+ if (range.getType() != Range.INSERTED) {
+ final DocumentEx doc = (DocumentEx) tracker.getUpToDateDocument();
+ final EditorEx uEditor = (EditorEx)EditorFactory.getInstance().createViewer(doc, tracker.getProject());
+ final EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(tracker.getProject(), getFileName(tracker.getDocument()));
+ uEditor.setHighlighter(highlighter);
+
+ final EditorFragmentComponent editorFragmentComponent =
+ EditorFragmentComponent.createEditorFragmentComponent(uEditor, range.getUOffset1(), range.getUOffset2(), false, false);
+
+ component.add(editorFragmentComponent, BorderLayout.CENTER);
+ EditorFactory.getInstance().releaseEditor(uEditor);
+ }
+
+ final LightweightHint lightweightHint = new LightweightHint(component);
+ lightweightHint.addHintListener(new HintListener() {
+ public void hintHidden(final EventObject event) {
+ actionList.remove(localShowPrevAction);
+ actionList.remove(localShowNextAction);
+ actionList.add(globalShowPrevAction);
+ actionList.add(globalShowNextAction);
+ }
+ });
+
+ HintManagerImpl.getInstanceImpl().showEditorHint(lightweightHint, editor, point, HintManagerImpl.HIDE_BY_ANY_KEY | HintManagerImpl.HIDE_BY_TEXT_CHANGE |
+ HintManagerImpl.HIDE_BY_OTHER_HINT | HintManagerImpl.HIDE_BY_SCROLLING,
+ -1, false);
+ }
+
+ private static String getFileName(final Document document) {
+ final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
+ if (file == null) return "";
+ return file.getName();
+ }
+
+ public static void moveToRange(final Range range, final Editor editor, final LineStatusTracker tracker) {
+ final Document document = tracker.getDocument();
+ final int firstOffset = document.getLineStartOffset(Math.min(range.getOffset1(), document.getLineCount() - 1));
+ editor.getCaretModel().moveToOffset(firstOffset);
+ editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
+
+ editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
+ public void run() {
+ Point p = editor.visualPositionToXY(editor.offsetToVisualPosition(firstOffset));
+ final JComponent editorComponent = editor.getContentComponent();
+ final JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
+ p = SwingUtilities.convertPoint(editorComponent, 0, p.y, layeredPane);
+ showActiveHint(range, editor, p, tracker);
+ }
+ });
+ }
+
+ private static TextAttributesKey getDiffColor(Range range) {
+ switch (range.getType()) {
+ case Range.INSERTED:
+ return DiffColors.DIFF_INSERTED;
+ case Range.DELETED:
+ return DiffColors.DIFF_DELETED;
+ case Range.MODIFIED:
+ return DiffColors.DIFF_MODIFIED;
+ default:
+ assert false;
+ return null;
+ }
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java
index eba9acb089a3..219e330f679b 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java
@@ -154,12 +154,7 @@ public class Range {
}
public Range mergeWith(Range range, LineStatusTracker tracker) {
- tracker.removeHighlighter(getHighlighter());
- setHighlighter(null);
- tracker.removeHighlighter(range.getHighlighter());
- range.setHighlighter(null);
- Range result = new Range(myOffset1, range.myOffset2, myUpToDateOffset1, range.myUpToDateOffset2, mergedStatusWith(range));
- return result;
+ return new Range(myOffset1, range.myOffset2, myUpToDateOffset1, range.myUpToDateOffset2, mergedStatusWith(range));
}
private byte mergedStatusWith(Range range) {
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java
index f64ea80bf5fd..594b125f9aa6 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java
@@ -16,11 +16,10 @@
package com.intellij.openapi.vcs.ex;
import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.EditorFactory;
import com.intellij.util.ArrayUtil;
import com.intellij.util.diff.Diff;
-import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -30,16 +29,12 @@ import java.util.List;
public class RangesBuilder {
private List myRanges;
- public RangesBuilder(String current, String upToDate) {
- this(EditorFactory.getInstance().createDocument(current), EditorFactory.getInstance().createDocument(upToDate));
- }
-
public RangesBuilder(Document current, Document upToDate) {
this(new DocumentWrapper(current).getLines(), new DocumentWrapper(upToDate).getLines(), 0, 0);
}
public RangesBuilder(List current, List upToDate, int shift, int uShift) {
- myRanges = new ArrayList();
+ myRanges = new LinkedList();
int shiftBefore = 0;
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java
new file mode 100644
index 000000000000..07c6190c707d
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2010 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.vcs.ex;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.vcs.VcsBundle;
+import com.intellij.openapi.vfs.ReadonlyStatusHandler;
+
+/**
+* @author irengrig
+*/
+public class RollbackLineStatusRangeAction extends BaseLineStatusRangeAction {
+ public RollbackLineStatusRangeAction(final LineStatusTracker lineStatusTracker, final Range range, final Editor editor) {
+ super(VcsBundle.message("action.name.rollback"), IconLoader.getIcon("/actions/reset.png"), lineStatusTracker, range);
+ }
+
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public void actionPerformed(final AnActionEvent e) {
+ CommandProcessor.getInstance().executeCommand(myLineStatusTracker.getProject(), new Runnable() {
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ if (!myLineStatusTracker.getDocument().isWritable()) {
+ final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler
+ .getInstance(myLineStatusTracker.getProject()).ensureFilesWritable(myLineStatusTracker.getVirtualFile());
+ if (operationStatus.hasReadonlyFiles()) return;
+ }
+ myLineStatusTracker.rollbackChanges(myRange);
+ }
+ });
+ }
+ }, VcsBundle.message("command.name.rollback.change"), null);
+
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java
new file mode 100644
index 000000000000..8f9fee4eab25
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2010 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.vcs.ex;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.diff.*;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vcs.VcsBundle;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/**
+* @author irengrig
+*/
+public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction {
+ public ShowLineStatusRangeDiffAction(final LineStatusTracker lineStatusTracker, final Range range, final Editor editor) {
+ super(VcsBundle.message("action.name.show.difference"), IconLoader.getIcon("/actions/diff.png"), lineStatusTracker, range);
+ }
+
+ public boolean isEnabled() {
+ return isModifiedRange() || isDeletedRange();
+ }
+
+ private boolean isDeletedRange() {
+ return Range.DELETED == myRange.getType();
+ }
+
+ private boolean isModifiedRange() {
+ return Range.MODIFIED == myRange.getType();
+ }
+
+ public void actionPerformed(final AnActionEvent e) {
+ DiffManager.getInstance().getDiffTool().show(createDiffData());
+ }
+
+ private DiffRequest createDiffData() {
+ return new DiffRequest(myLineStatusTracker.getProject()) {
+ public DiffContent[] getContents() {
+ return new DiffContent[]{createDiffContent(myLineStatusTracker.getUpToDateDocument(),
+ myLineStatusTracker.getUpToDateRangeWithEndSymbol(myRange), null),
+ createDiffContent(myLineStatusTracker.getDocument(), myLineStatusTracker.getCurrentTextRange(myRange),
+ myLineStatusTracker.getVirtualFile())};
+ }
+
+ public String[] getContentTitles() {
+ return new String[]{VcsBundle.message("diff.content.title.up.to.date"),
+ VcsBundle.message("diff.content.title.current.range")};
+ }
+
+ public String getWindowTitle() {
+ return VcsBundle.message("dialog.title.diff.for.range");
+ }
+ };
+ }
+
+ private DiffContent createDiffContent(final Document uDocument, final TextRange textRange, final VirtualFile file) {
+ final Project project = myLineStatusTracker.getProject();
+ final DiffContent diffContent = new DocumentContent(project, uDocument);
+ return new FragmentContent(diffContent, textRange, project, file);
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java
index 5bd61146daad..d2842e40cfd7 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java
@@ -24,7 +24,9 @@ package com.intellij.openapi.vcs.impl;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -40,11 +42,14 @@ import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusListener;
import com.intellij.openapi.vcs.FileStatusManager;
+import com.intellij.openapi.vcs.changes.committed.AbstractCalledLater;
import com.intellij.openapi.vcs.ex.LineStatusTracker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
@@ -56,50 +61,79 @@ import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
-public class LineStatusTrackerManager implements ProjectComponent {
+public class LineStatusTrackerManager implements ProjectComponent, LineStatusTrackerManagerI {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.LineStatusTrackerManager");
- public static LineStatusTrackerManager getInstance(Project project) {
- return PeriodicalTasksCloser.getInstance().safeGetComponent(project, LineStatusTrackerManager.class);
+ public static LineStatusTrackerManagerI getInstance(final Project project) {
+ if (System.getProperty(IGNORE_CHANGEMARKERS_KEY) != null) {
+ return Dummy.getInstance();
+ }
+ return PeriodicalTasksCloser.getInstance().safeGetComponent(project, LineStatusTrackerManagerI.class);
}
private final Project myProject;
- private HashMap myLineStatusTrackers =
- new HashMap();
+ private final Map myLineStatusTrackers;
+ // !!! no state queries and self lock for add/remove
+ // removal from here - not under write action
+ private final Map myLineStatusUpdateAlarms;
- private final HashMap myLineStatusUpdateAlarms =
- new HashMap();
-
- private final Object TRACKERS_LOCK = new Object();
- private boolean myIsDisposed = false;
@NonNls protected static final String IGNORE_CHANGEMARKERS_KEY = "idea.ignore.changemarkers";
+
private final ProjectLevelVcsManagerImpl myVcsManager;
private final VcsFileStatusProvider myStatusProvider;
+ private final Application myApplication;
+ private final FileEditorManager myFileEditorManager;
+ private final Disposable myDisposable;
- public LineStatusTrackerManager(final Project project, final ProjectLevelVcsManagerImpl vcsManager, final VcsFileStatusProvider statusProvider) {
+ public LineStatusTrackerManager(final Project project, final ProjectLevelVcsManagerImpl vcsManager, final VcsFileStatusProvider statusProvider,
+ final Application application, final FileEditorManager fileEditorManager) {
myProject = project;
myVcsManager = vcsManager;
myStatusProvider = statusProvider;
+ myApplication = application;
+ myFileEditorManager = fileEditorManager;
+ myLineStatusTrackers = new HashMap();
+ myLineStatusUpdateAlarms = Collections.synchronizedMap(new HashMap());
project.getMessageBus().connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() {
public void updateStarted(final Document doc) {
+ myApplication.assertWriteAccessAllowed(); // can remove after some testing
+
final LineStatusTracker tracker = getLineStatusTracker(doc);
if (tracker != null) tracker.startBulkUpdate();
}
public void updateFinished(final Document doc) {
+ myApplication.assertWriteAccessAllowed(); // can remove after some testing
+
final LineStatusTracker tracker = getLineStatusTracker(doc);
if (tracker != null) tracker.finishBulkUpdate();
}
});
+
+ myDisposable = new Disposable() {
+ @Override
+ public void dispose() {
+ final Collection trackers = myLineStatusTrackers.values();
+ final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
+ for (final LineStatusTracker tracker : lineStatusTrackers) {
+ releaseTracker(tracker.getDocument());
+ }
+
+ myLineStatusTrackers.clear();
+ assert myLineStatusUpdateAlarms.isEmpty();
+ myLineStatusUpdateAlarms.clear();
+ }
+ };
+ Disposer.register(myProject, myDisposable);
}
public void projectOpened() {
- trackAwtThread();
final MyFileStatusListener fileStatusListener = new MyFileStatusListener();
final EditorFactoryListener editorFactoryListener = new MyEditorFactoryListener();
final MyVirtualFileListener virtualFileListener = new MyVirtualFileListener();
@@ -109,7 +143,6 @@ public class LineStatusTrackerManager implements ProjectComponent {
}
};
- myLineStatusTrackers = new HashMap();
final FileStatusManager fsManager = FileStatusManager.getInstance(myProject);
fsManager.addFileStatusListener(fileStatusListener, myProject);
@@ -122,9 +155,8 @@ public class LineStatusTrackerManager implements ProjectComponent {
final EditorColorsManager editorColorsManager = EditorColorsManager.getInstance();
editorColorsManager.addEditorColorsListener(editorColorsListener);
- Disposer.register(myProject, new Disposable() {
+ Disposer.register(myDisposable, new Disposable() {
public void dispose() {
- trackAwtThread();
fsManager.removeFileStatusListener(fileStatusListener);
virtualFileManager.removeVirtualFileListener(virtualFileListener);
editorColorsManager.removeEditorColorsListener(editorColorsListener);
@@ -133,13 +165,6 @@ public class LineStatusTrackerManager implements ProjectComponent {
}
public void projectClosed() {
- try {
- trackAwtThread();
- dispose();
- }
- finally {
- myIsDisposed = true;
- }
}
@NonNls @NotNull
@@ -153,213 +178,212 @@ public class LineStatusTrackerManager implements ProjectComponent {
public void disposeComponent() {
}
- private void dispose() {
- final Collection trackers = myLineStatusTrackers.values();
- final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
- for (LineStatusTracker tracker : lineStatusTrackers) {
- releaseTracker(tracker.getDocument());
- }
+ @Override
+ public LineStatusTracker getLineStatusTracker(final Document document) {
+ myApplication.assertReadAccessAllowed();
- myLineStatusTrackers = null;
-}
-
- public LineStatusTracker getLineStatusTracker(Document document) {
- trackAwtThread();
- if (myLineStatusTrackers == null) return null;
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return null;
return myLineStatusTrackers.get(document);
}
-
- public LineStatusTracker setUpToDateContent(final Document document, final String lastUpToDateContent) {
- trackAwtThread();
- LineStatusTracker result = myLineStatusTrackers.get(document);
- if (result == null) {
- result = LineStatusTracker.createOn(document, lastUpToDateContent, myProject);
- myLineStatusTrackers.put(document, result);
- }
- return result;
- }
-
- private LineStatusTracker createTrackerForDocument(Document document, VirtualFile vf) {
- LOG.assertTrue(!myLineStatusTrackers.containsKey(document));
- LineStatusTracker result = LineStatusTracker.createOn(document, myProject);
- myLineStatusTrackers.put(document, result);
- return result;
- }
-
- private void resetTracker(final VirtualFile virtualFile) {
- if (System.getProperty(IGNORE_CHANGEMARKERS_KEY) != null) return;
+ private void resetTracker(@NotNull final VirtualFile virtualFile) {
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return;
final Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
if (document == null) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Skipping resetTracker() because no cached document for " + virtualFile.getPath());
- }
+ log("Skipping resetTracker() because no cached document for " + virtualFile.getPath());
return;
}
- if (LOG.isDebugEnabled()) {
- LOG.debug("resetting tracker for file " + virtualFile.getPath());
- }
- synchronized (TRACKERS_LOCK) {
- final LineStatusTracker tracker = myLineStatusTrackers.get(document);
- if (tracker != null) {
- resetTracker(tracker);
- }
- else {
- if (Arrays.asList(FileEditorManager.getInstance(myProject).getOpenFiles()).contains(virtualFile)) {
+ log("resetting tracker for file " + virtualFile.getPath());
+
+ final LineStatusTracker tracker = myLineStatusTrackers.get(document);
+ final boolean editorOpened = myFileEditorManager.isFileOpen(virtualFile);
+ final boolean shouldBeInstalled = shouldBeInstalled(virtualFile) && editorOpened;
+
+ if (tracker == null && (! shouldBeInstalled)) return;
+
+ myApplication.runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ // remove ?
+ if (tracker != null) {
+ if (! shouldBeInstalled) {
+ releaseTracker(document);
+ return;
+ } else if ((! tracker.isBaseLoaded())) {
+ return; // will be recalculated
+ } else {
+ tracker.resetForBaseRevisionLoad();
+ startAlarm(document, virtualFile);
+ }
+ } else if (shouldBeInstalled) {
installTracker(virtualFile, document);
}
}
- }
+ });
}
- private boolean releaseTracker(Document document) {
- synchronized (TRACKERS_LOCK) {
- releaseUpdateAlarms(document);
- if (myLineStatusTrackers == null) return false;
- if (!myLineStatusTrackers.containsKey(document)) return false;
- LineStatusTracker tracker = myLineStatusTrackers.remove(document);
- tracker.release();
- return true;
- }
- }
+ private void releaseTracker(final Document document) {
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return;
- private void releaseUpdateAlarms(final Document document) {
- if (myLineStatusUpdateAlarms.containsKey(document)) {
- final Alarm alarm = myLineStatusUpdateAlarms.get(document);
- if (alarm != null) {
- alarm.cancelAllRequests();
+ myApplication.runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ final Alarm alarm = myLineStatusUpdateAlarms.remove(document);
+ if (alarm != null) {
+ alarm.cancelAllRequests();
+ }
+ final LineStatusTracker tracker = myLineStatusTrackers.remove(document);
+ if (tracker != null) {
+ tracker.release();
+ }
}
- myLineStatusUpdateAlarms.remove(document);
- }
+ });
}
- public void resetTracker(final LineStatusTracker tracker) {
- trackAwtThread();
- if (tracker != null) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
+ private boolean shouldBeInstalled(final VirtualFile virtualFile) {
+ ApplicationManager.getApplication().assertIsDispatchThread();
+
+ if (virtualFile == null || virtualFile instanceof LightVirtualFile) return false;
+ if (! virtualFile.isInLocalFileSystem()) return false;
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return false;
+ final FileStatusManager statusManager = FileStatusManager.getInstance(myProject);
+ if (statusManager == null) return false;
+ final AbstractVcs activeVcs = myVcsManager.getVcsFor(virtualFile);
+ if (activeVcs == null) {
+ log("installTracker() for file " + virtualFile.getPath() + " failed: no active VCS");
+ return false;
+ }
+ final FileStatus status = statusManager.getStatus(virtualFile);
+ if (status == FileStatus.NOT_CHANGED || status == FileStatus.ADDED || status == FileStatus.UNKNOWN || status == FileStatus.IGNORED) {
+ log("installTracker() for file " + virtualFile.getPath() + " failed: status=" + status);
+ return false;
+ }
+ return true;
+ }
+
+ private void installTracker(final VirtualFile virtualFile, final Document document) {
+ /*ApplicationManager.getApplication().assertIsDispatchThread();
+
+ if (virtualFile == null || virtualFile instanceof LightVirtualFile) return;
+ if (! virtualFile.isInLocalFileSystem()) return;
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return;
+ final FileStatusManager statusManager = FileStatusManager.getInstance(myProject);
+ if (statusManager == null) return;
+ final AbstractVcs activeVcs = myVcsManager.getVcsFor(virtualFile);
+ if (activeVcs == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.info("installTracker() for file " + virtualFile.getPath() + " failed: no active VCS");
+ }
+ return;
+ }
+ final FileStatus status = statusManager.getStatus(virtualFile);
+ if (status == FileStatus.NOT_CHANGED || status == FileStatus.ADDED || status == FileStatus.UNKNOWN || status == FileStatus.IGNORED) {
+ if (LOG.isDebugEnabled()) {
+ LOG.info("installTracker() for file " + virtualFile.getPath() + " failed: status=" + status);
+ System.out.println("installTracker() for file " + virtualFile.getPath() + " failed: status=" + status);
+ }
+ return;
+ } */
+
+ myApplication.runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ if (myLineStatusTrackers.containsKey(document)) return;
+ assert !myLineStatusUpdateAlarms.containsKey(document);
+
+ final LineStatusTracker tracker = LineStatusTracker.createOn(document, myProject);
+ myLineStatusTrackers.put(document, tracker);
+
+ startAlarm(document, virtualFile);
+ }
+ });
+ }
+
+ private void startAlarm(final Document document, final VirtualFile virtualFile) {
+ myApplication.assertWriteAccessAllowed();
+
+ final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
+ myLineStatusUpdateAlarms.put(document, alarm);
+ alarm.addRequest(new BaseRevisionLoader(alarm, document, virtualFile), 10);
+ }
+
+ private class BaseRevisionLoader implements Runnable {
+ private final Alarm myAlarm;
+ private final VirtualFile myVirtualFile;
+ private final Document myDocument;
+
+ private BaseRevisionLoader(final Alarm alarm, final Document document, final VirtualFile virtualFile) {
+ myAlarm = alarm;
+ myDocument = document;
+ myVirtualFile = virtualFile;
+ }
+
+ @Override
+ public void run() {
+ myAlarm.cancelAllRequests();
+ final Boolean removed = myApplication.runReadAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ final Alarm removed = myLineStatusUpdateAlarms.remove(myDocument);
+ return removed != null;
+ }
+ });
+ if (! Boolean.TRUE.equals(removed)) return;
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return;
+
+ if (! myVirtualFile.isValid()) {
+ log("installTracker() for file " + myVirtualFile.getPath() + " failed: virtual file not valid");
+ return;
+ }
+
+ final String lastUpToDateContent = myStatusProvider.getBaseVersionContent(myVirtualFile);
+ if (lastUpToDateContent == null) {
+ log("installTracker() for file " + myVirtualFile.getPath() + " failed: no up to date content");
+ return;
+ }
+
+ myApplication.invokeLater(new Runnable() {
public void run() {
- if (myIsDisposed) return;
- if (releaseTracker(tracker.getDocument())) {
- installTracker(tracker.getVirtualFile(), tracker.getDocument());
- }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ log("initializing tracker for file " + myVirtualFile.getPath());
+ final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument);
+ if (tracker != null) {
+ tracker.initialize(lastUpToDateContent);
+ }
+ }
+ });
+ }
+ }, new Condition() {
+ @Override
+ public boolean value(final Object ignore) {
+ return (! myProject.isOpen()) || myProject.isDisposed();
}
});
}
}
- private void installTracker(final VirtualFile virtualFile, final Document document) {
- if (virtualFile == null || virtualFile instanceof LightVirtualFile) return;
- ApplicationManager.getApplication().assertIsDispatchThread();
-
- if (myProject.isDisposed() || myLineStatusTrackers == null) return;
- final FileStatusManager statusManager = FileStatusManager.getInstance(myProject);
- if (statusManager == null) return;
- final FileStatus status = statusManager.getStatus(virtualFile);
-
- synchronized (TRACKERS_LOCK) {
- if (myLineStatusTrackers.containsKey(document)) return;
-
- if (status == FileStatus.NOT_CHANGED ||
- status == FileStatus.ADDED ||
- status == FileStatus.UNKNOWN ||
- status == FileStatus.IGNORED) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("installTracker() for file " + virtualFile.getPath() + " failed: status=" + status);
- }
- return;
- }
-
- AbstractVcs activeVcs = myVcsManager.getVcsFor(virtualFile);
-
- if (activeVcs == null) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("installTracker() for file " + virtualFile.getPath() + " failed: no active VCS");
- }
- return;
- }
-
- if (!virtualFile.isInLocalFileSystem()) return;
-
- if (System.getProperty(IGNORE_CHANGEMARKERS_KEY) != null) return;
-
- final Alarm alarm;
-
- if (myLineStatusUpdateAlarms.containsKey(document)) {
- alarm = myLineStatusUpdateAlarms.get(document);
- alarm.cancelAllRequests();
- }
- else {
- alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
- myLineStatusUpdateAlarms.put(document, alarm);
- }
-
- final LineStatusTracker tracker = createTrackerForDocument(document, virtualFile);
-
- alarm.addRequest(new Runnable() {
- public void run() {
- try {
- alarm.cancelAllRequests();
- if (!virtualFile.isValid()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("installTracker() for file " + virtualFile.getPath() + " failed: virtual file not valid");
- }
- return;
- }
- final String lastUpToDateContent = myStatusProvider.getBaseVersionContent(virtualFile);
- if (lastUpToDateContent == null) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("installTracker() for file " + virtualFile.getPath() + " failed: no up to date content");
- }
- return;
- }
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- public void run() {
- if (!myProject.isDisposed()) {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- public void run() {
- if (LOG.isDebugEnabled()) {
- LOG.debug("initializing tracker for file " + virtualFile.getPath());
- }
- synchronized (TRACKERS_LOCK) {
- tracker.initialize(lastUpToDateContent);
- }
- }
- });
- }
- }
- });
- }
- finally {
- // todo guard alarms!!!
- myLineStatusUpdateAlarms.remove(document);
- }
- }
- }, 10);
- }
-
- }
-
private void resetTrackersForOpenFiles() {
- final VirtualFile[] openFiles = FileEditorManager.getInstance(myProject).getOpenFiles();
- synchronized (TRACKERS_LOCK) {
- for(VirtualFile openFile: openFiles) {
- resetTracker(openFile);
- }
+ myApplication.assertReadAccessAllowed();
+ if ((! myProject.isOpen()) || myProject.isDisposed()) return;
+
+ final VirtualFile[] openFiles = myFileEditorManager.getOpenFiles();
+ for(final VirtualFile openFile: openFiles) {
+ // write action inside is sufficient level
+ resetTracker(openFile);
}
}
private class MyFileStatusListener implements FileStatusListener {
public void fileStatusesChanged() {
if (myProject.isDisposed()) return;
- LOG.debug("LineStatusTrackerManager: fileStatusesChanged");
- trackAwtThread();
+ log("LineStatusTrackerManager: fileStatusesChanged");
resetTrackersForOpenFiles();
}
public void fileStatusChanged(@NotNull VirtualFile virtualFile) {
- trackAwtThread();
resetTracker(virtualFile);
}
}
@@ -370,33 +394,46 @@ public class LineStatusTrackerManager implements ProjectComponent {
// outside of EDT, so the EDT check mustn't be done here
Editor editor = event.getEditor();
if (editor.getProject() != null && editor.getProject() != myProject) return;
- Document document = editor.getDocument();
- VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
- installTracker(virtualFile, document);
+ final Document document = editor.getDocument();
+ final VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
+
+ new AbstractCalledLater(myProject, ModalityState.NON_MODAL) {
+ @Override
+ public void run() {
+ if (shouldBeInstalled(virtualFile)) {
+ installTracker(virtualFile, document);
+ }
+ }
+ }.callMe();
}
public void editorReleased(EditorFactoryEvent event) {
- trackAwtThread();
final Editor editor = event.getEditor();
if (editor.getProject() != null && editor.getProject() != myProject) return;
final Document doc = editor.getDocument();
final Editor[] editors = event.getFactory().getEditors(doc, myProject);
if (editors.length == 0) {
- releaseTracker(doc);
+ new AbstractCalledLater(myProject, ModalityState.NON_MODAL) {
+ @Override
+ public void run() {
+ releaseTracker(doc);
+ }
+ }.callMe();
}
}
}
private class MyVirtualFileListener extends VirtualFileAdapter {
public void beforeContentsChange(VirtualFileEvent event) {
- trackAwtThread();
if (event.isFromRefresh()) {
resetTracker(event.getFile());
}
}
}
- private static void trackAwtThread() {
- ApplicationManager.getApplication().assertIsDispatchThread();
+ private static void log(final String s) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(s);
+ }
}
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManagerI.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManagerI.java
new file mode 100644
index 000000000000..d6dcdc3ee1aa
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManagerI.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2010 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.vcs.impl;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.vcs.ex.LineStatusTracker;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author irengrig
+ */
+public interface LineStatusTrackerManagerI {
+ @Nullable
+ LineStatusTracker getLineStatusTracker(Document document);
+
+ class Dummy implements LineStatusTrackerManagerI {
+ private final static Dummy ourInstance = new Dummy();
+
+ public static Dummy getInstance() {
+ return ourInstance;
+ }
+
+ @Override
+ public LineStatusTracker getLineStatusTracker(final Document document) {
+ return null;
+ }
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java
index 14d668f06285..857437149d69 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java
@@ -40,7 +40,7 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide
public int getLineNumber(int currentNumber) {
LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument);
if (tracker == null) {
- tracker = LineStatusTrackerManager.getInstance(myProject).setUpToDateContent(myDocument, myUpToDateContent);
+ return currentNumber;
}
return calcLineNumber(tracker, currentNumber);
}