mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
VCS: line status tracker installing/removing fix. All changes to line status trackers model (that in LineStatusTrackerManager) will be done under write action. + dummy implementation if lst is forbidden. + just translate into current line in VCS annotation, no false tracker creation. + fix for "Diff for change" when last symbol in line is added
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
<implementation-class>com.intellij.openapi.vcs.impl.VcsDirectoryMappingStorage</implementation-class>
|
<implementation-class>com.intellij.openapi.vcs.impl.VcsDirectoryMappingStorage</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
<component>
|
<component>
|
||||||
|
<interface-class>com.intellij.openapi.vcs.impl.LineStatusTrackerManagerI</interface-class>
|
||||||
<implementation-class>com.intellij.openapi.vcs.impl.LineStatusTrackerManager</implementation-class>
|
<implementation-class>com.intellij.openapi.vcs.impl.LineStatusTrackerManager</implementation-class>
|
||||||
<option name="workspace" value="true"/>
|
<option name="workspace" value="true"/>
|
||||||
<skipForDefaultProject/>
|
<skipForDefaultProject/>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.Presentation;
|
|||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.vcs.ex.LineStatusTracker;
|
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.ex.Range;
|
||||||
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
|
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
|
||||||
|
|
||||||
@@ -92,7 +93,8 @@ public abstract class ShowChangeMarkerAction extends AbstractVcsAction {
|
|||||||
LineStatusTracker lineStatusTracker = myChangeMarkerContext.getLineStatusTracker(context);
|
LineStatusTracker lineStatusTracker = myChangeMarkerContext.getLineStatusTracker(context);
|
||||||
Range range = myChangeMarkerContext.getRange(context);
|
Range range = myChangeMarkerContext.getRange(context);
|
||||||
|
|
||||||
lineStatusTracker.moveToRange(range, editor);
|
|
||||||
|
LineStatusTrackerDrawing.moveToRange(range, editor, lineStatusTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface ChangeMarkerContext {
|
protected interface ChangeMarkerContext {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package com.intellij.openapi.vcs.ex;
|
package com.intellij.openapi.vcs.ex;
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Document;
|
import com.intellij.openapi.editor.Document;
|
||||||
|
import com.intellij.openapi.util.TextRange;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -53,10 +54,8 @@ public class DocumentWrapper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLine(int i) {
|
private String getLine(final int i) {
|
||||||
int lineStartOffset = myDocument.getLineStartOffset(i);
|
return myDocument.getText(new TextRange(myDocument.getLineStartOffset(i), myDocument.getLineEndOffset(i)));
|
||||||
String line = myDocument.getCharsSequence().subSequence(lineStartOffset, myDocument.getLineEndOffset(i)).toString();
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,135 +15,111 @@
|
|||||||
*/
|
*/
|
||||||
package com.intellij.openapi.vcs.ex;
|
package com.intellij.openapi.vcs.ex;
|
||||||
|
|
||||||
import com.intellij.codeInsight.hint.EditorFragmentComponent;
|
import com.intellij.openapi.application.Application;
|
||||||
import com.intellij.codeInsight.hint.HintManagerImpl;
|
|
||||||
import com.intellij.openapi.actionSystem.*;
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.command.CommandProcessor;
|
|
||||||
import com.intellij.openapi.command.undo.UndoManager;
|
import com.intellij.openapi.command.undo.UndoManager;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.diff.*;
|
|
||||||
import com.intellij.openapi.editor.Document;
|
import com.intellij.openapi.editor.Document;
|
||||||
import com.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.editor.EditorFactory;
|
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.DocumentAdapter;
|
||||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
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.editor.markup.*;
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
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.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.TextRange;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vcs.VcsBundle;
|
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.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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.swing.*;
|
import java.util.ArrayList;
|
||||||
import java.awt.*;
|
import java.util.Iterator;
|
||||||
import java.awt.datatransfer.StringSelection;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @author irengrig
|
||||||
* author: lesya
|
* author: lesya
|
||||||
*/
|
*/
|
||||||
public class LineStatusTracker {
|
public class LineStatusTracker {
|
||||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.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 myDocument;
|
||||||
private final Document myUpToDateDocument;
|
private final Document myUpToDateDocument;
|
||||||
@SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private List<Range> myRanges = new ArrayList<Range>();
|
|
||||||
|
private List<Range> myRanges;
|
||||||
|
|
||||||
private final Project myProject;
|
private final Project myProject;
|
||||||
@SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private int myHighlighterCount = 0;
|
|
||||||
|
|
||||||
private MyDocumentListener myDocumentListener;
|
private MyDocumentListener myDocumentListener;
|
||||||
|
|
||||||
private boolean myIsReleased = false;
|
|
||||||
private boolean myIsInitialized = false;
|
|
||||||
private boolean myBulkUpdate;
|
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;
|
myDocument = document;
|
||||||
myUpToDateDocument = upToDateDocument;
|
myUpToDateDocument = upToDateDocument;
|
||||||
myUpToDateDocument.putUserData(UndoManager.DONT_RECORD_UNDO, Boolean.TRUE);
|
myUpToDateDocument.putUserData(UndoManager.DONT_RECORD_UNDO, Boolean.TRUE);
|
||||||
myProject = project;
|
myProject = project;
|
||||||
|
myBaseLoaded = false;
|
||||||
|
myRanges = new ArrayList<Range>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void initialize(@NotNull final String upToDateContent) {
|
public void initialize(@NotNull final String upToDateContent) {
|
||||||
if (myIsReleased) return;
|
ApplicationManager.getApplication().isReadAccessAllowed();
|
||||||
LOG.assertTrue(!myIsInitialized);
|
LOG.assertTrue(!myBaseLoaded);
|
||||||
try {
|
|
||||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
try {
|
||||||
|
myUpToDateDocument.setReadOnly(false);
|
||||||
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), StringUtil.convertLineSeparators(upToDateContent));
|
myUpToDateDocument.replaceString(0, myUpToDateDocument.getTextLength(), StringUtil.convertLineSeparators(upToDateContent));
|
||||||
|
myUpToDateDocument.setReadOnly(true);
|
||||||
|
reinstallRanges();
|
||||||
|
|
||||||
|
if (myDocumentListener == null) {
|
||||||
|
myDocumentListener = new MyDocumentListener();
|
||||||
|
myDocument.addDocumentListener(myDocumentListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
finally {
|
||||||
|
myBaseLoaded = true;
|
||||||
myUpToDateDocument.setReadOnly(true);
|
}
|
||||||
reinstallRanges();
|
}
|
||||||
|
});
|
||||||
myDocumentListener = new MyDocumentListener();
|
|
||||||
myDocument.addDocumentListener(myDocumentListener);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
myIsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void reinstallRanges() {
|
private void reinstallRanges() {
|
||||||
reinstallRanges(new RangesBuilder(myDocument, myUpToDateDocument).getRanges());
|
myApplication.assertWriteAccessAllowed();
|
||||||
}
|
|
||||||
|
|
||||||
private void reinstallRanges(List<Range> ranges) {
|
removeHighlightersFromMarkupModel();
|
||||||
removeHighlighters();
|
myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges();
|
||||||
myRanges = ranges;
|
for (final Range range : myRanges) {
|
||||||
addHighlighters();
|
range.setHighlighter(createHighlighter(range));
|
||||||
}
|
|
||||||
|
|
||||||
private void addHighlighters() {
|
|
||||||
for (Range range : myRanges) {
|
|
||||||
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"AutoBoxing"})
|
@SuppressWarnings({"AutoBoxing"})
|
||||||
synchronized private RangeHighlighter createHighlighter(Range range) {
|
private RangeHighlighter createHighlighter(final Range range) {
|
||||||
int first =
|
int first =
|
||||||
range.getOffset1() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset1());
|
range.getOffset1() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset1());
|
||||||
|
|
||||||
int second =
|
int second =
|
||||||
range.getOffset2() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset2());
|
range.getOffset2() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset2());
|
||||||
|
|
||||||
|
final RangeHighlighter highlighter = myDocument.getMarkupModel(myProject)
|
||||||
RangeHighlighter highlighter = myDocument.getMarkupModel(myProject)
|
|
||||||
.addRangeHighlighter(first, second, HighlighterLayer.FIRST - 1, null, HighlighterTargetArea.LINES_IN_RANGE);
|
.addRangeHighlighter(first, second, HighlighterLayer.FIRST - 1, null, HighlighterTargetArea.LINES_IN_RANGE);
|
||||||
myHighlighterCount++;
|
final TextAttributes attr = LineStatusTrackerDrawing.getAttributesFor(range);
|
||||||
TextAttributes attr = getAttributesFor(range);
|
|
||||||
highlighter.setErrorStripeMarkColor(attr.getErrorStripeColor());
|
highlighter.setErrorStripeMarkColor(attr.getErrorStripeColor());
|
||||||
highlighter.setThinErrorStripeMark(true);
|
highlighter.setThinErrorStripeMark(true);
|
||||||
highlighter.setGreedyToLeft(true);
|
highlighter.setGreedyToLeft(true);
|
||||||
highlighter.setGreedyToRight(true);
|
highlighter.setGreedyToRight(true);
|
||||||
highlighter.setLineMarkerRenderer(createRenderer(range));
|
highlighter.setLineMarkerRenderer(LineStatusTrackerDrawing.createRenderer(range, this));
|
||||||
highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter());
|
highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter());
|
||||||
final int line1 = myDocument.getLineNumber(first);
|
final int line1 = myDocument.getLineNumber(first);
|
||||||
final int line2 = myDocument.getLineNumber(second);
|
final int line2 = myDocument.getLineNumber(second);
|
||||||
@@ -159,141 +135,17 @@ public class LineStatusTracker {
|
|||||||
return highlighter;
|
return highlighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
private void removeHighlighters() {
|
myApplication.runWriteAction(new Runnable() {
|
||||||
for (Range oldRange : myRanges) {
|
@Override
|
||||||
removeHighlighter(oldRange.getHighlighter());
|
public void run() {
|
||||||
oldRange.setHighlighter(null);
|
if (myDocumentListener != null) {
|
||||||
}
|
myDocument.removeDocumentListener(myDocumentListener);
|
||||||
}
|
}
|
||||||
|
removeHighlightersFromMarkupModel();
|
||||||
synchronized void removeHighlighter(RangeHighlighter highlighter) {
|
myRanges.clear();
|
||||||
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 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() {
|
public Document getDocument() {
|
||||||
@@ -305,6 +157,8 @@ public class LineStatusTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Range> getRanges() {
|
public List<Range> getRanges() {
|
||||||
|
myApplication.assertReadAccessAllowed();
|
||||||
|
|
||||||
return myRanges;
|
return myRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,19 +167,56 @@ public class LineStatusTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startBulkUpdate() {
|
public void startBulkUpdate() {
|
||||||
myBulkUpdate = true;
|
myApplication.runWriteAction(new Runnable() {
|
||||||
for (Range oldRange : myRanges) {
|
@Override
|
||||||
removeHighlighter(oldRange.getHighlighter());
|
public void run() {
|
||||||
oldRange.setHighlighter(null);
|
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() {
|
public void finishBulkUpdate() {
|
||||||
if (myBulkUpdate) {
|
myApplication.runWriteAction(new Runnable() {
|
||||||
myBulkUpdate = false;
|
@Override
|
||||||
reinstallRanges();
|
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<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean compute() {
|
||||||
|
if (!myBaseLoaded) return false;
|
||||||
|
return myApplication.runWriteAction(new Computable<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean compute() {
|
||||||
|
myUpToDateDocument.setReadOnly(false);
|
||||||
|
myUpToDateDocument.setText("");
|
||||||
|
myUpToDateDocument.setReadOnly(true);
|
||||||
|
removeHighlightersFromMarkupModel();
|
||||||
|
myRanges.clear();
|
||||||
|
myBaseLoaded = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyDocumentListener extends DocumentAdapter {
|
private class MyDocumentListener extends DocumentAdapter {
|
||||||
@@ -336,7 +227,9 @@ public class LineStatusTracker {
|
|||||||
private int myLinesBeforeChange;
|
private int myLinesBeforeChange;
|
||||||
|
|
||||||
public void beforeDocumentChange(DocumentEvent e) {
|
public void beforeDocumentChange(DocumentEvent e) {
|
||||||
if (myBulkUpdate) return;
|
if (myBulkUpdate || (! myBaseLoaded)) return;
|
||||||
|
myApplication.assertWriteAccessAllowed();
|
||||||
|
|
||||||
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
|
myFirstChangedLine = myDocument.getLineNumber(e.getOffset());
|
||||||
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
|
myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
|
||||||
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
|
if (StringUtil.endsWithChar(e.getOldFragment(), '\n')) myLastChangedLine++;
|
||||||
@@ -382,14 +275,15 @@ public class LineStatusTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void documentChanged(DocumentEvent e) {
|
public void documentChanged(DocumentEvent e) {
|
||||||
if (myBulkUpdate) return;
|
if (myBulkUpdate || (! myBaseLoaded)) return;
|
||||||
|
myApplication.assertWriteAccessAllowed();
|
||||||
|
|
||||||
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
|
int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
|
||||||
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
|
int linesAfterChange = line - myDocument.getLineNumber(e.getOffset());
|
||||||
int linesShift = linesAfterChange - myLinesBeforeChange;
|
int linesShift = linesAfterChange - myLinesBeforeChange;
|
||||||
|
|
||||||
List<Range> rangesAfterChange = getRangesAfter(myLastChangedLine);
|
List<Range> rangesAfterChange = getRangesAfter(myRanges, myLastChangedLine);
|
||||||
List<Range> rangesBeforeChange = getRangesBefore(myFirstChangedLine);
|
List<Range> rangesBeforeChange = getRangesBefore(myRanges, myFirstChangedLine);
|
||||||
|
|
||||||
List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
|
List<Range> changedRanges = getChangedRanges(myFirstChangedLine, myLastChangedLine);
|
||||||
|
|
||||||
@@ -416,19 +310,10 @@ public class LineStatusTracker {
|
|||||||
myRanges.addAll(newChangedRanges);
|
myRanges.addAll(newChangedRanges);
|
||||||
myRanges.addAll(rangesAfterChange);
|
myRanges.addAll(rangesAfterChange);
|
||||||
|
|
||||||
if (myHighlighterCount != myRanges.size()) {
|
|
||||||
LOG.error("Highlighters: " + myHighlighterCount + ", ranges: " + myRanges.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
myRanges = mergeRanges(myRanges);
|
myRanges = mergeRanges(myRanges);
|
||||||
|
|
||||||
for (Range range : myRanges) {
|
for (Range range : myRanges) {
|
||||||
if (!range.hasHighlighter()) range.setHighlighter(createHighlighter(range));
|
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<Range> mergeRanges(List<Range> ranges) {
|
private List<Range> mergeRanges(List<Range> ranges) {
|
||||||
|
final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
|
||||||
|
|
||||||
ArrayList<Range> result = new ArrayList<Range>();
|
ArrayList<Range> result = new ArrayList<Range>();
|
||||||
Iterator<Range> iterator = ranges.iterator();
|
Iterator<Range> iterator = ranges.iterator();
|
||||||
if (!iterator.hasNext()) return result;
|
if (!iterator.hasNext()) return result;
|
||||||
@@ -449,6 +336,8 @@ public class LineStatusTracker {
|
|||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Range range = iterator.next();
|
Range range = iterator.next();
|
||||||
if (prev.canBeMergedWith(range)) {
|
if (prev.canBeMergedWith(range)) {
|
||||||
|
markupModel.removeHighlighter(range.getHighlighter());
|
||||||
|
markupModel.removeHighlighter(prev.getHighlighter());
|
||||||
prev = prev.mergeWith(range, LineStatusTracker.this);
|
prev = prev.mergeWith(range, LineStatusTracker.this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -461,8 +350,10 @@ public class LineStatusTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void replaceRanges(List<Range> rangesInChange, List<Range> newRangesInChange) {
|
private void replaceRanges(List<Range> rangesInChange, List<Range> newRangesInChange) {
|
||||||
|
final MarkupModel markupModel = myDocument.getMarkupModel(myProject);
|
||||||
|
|
||||||
for (Range range : rangesInChange) {
|
for (Range range : rangesInChange) {
|
||||||
removeHighlighter(range.getHighlighter());
|
markupModel.removeHighlighter(range.getHighlighter());
|
||||||
range.setHighlighter(null);
|
range.setHighlighter(null);
|
||||||
}
|
}
|
||||||
for (Range range : newRangesInChange) {
|
for (Range range : newRangesInChange) {
|
||||||
@@ -491,9 +382,51 @@ public class LineStatusTracker {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Range> getRangesBefore(int line) {
|
@Nullable
|
||||||
return getRangesBefore(myRanges, line);
|
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<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
|
||||||
|
final Range range = iterator.previous();
|
||||||
|
if (range.getOffset1() > line) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Range> getRangesBefore(List<Range> ranges, int line) {
|
public static List<Range> getRangesBefore(List<Range> ranges, int line) {
|
||||||
@@ -506,10 +439,6 @@ public class LineStatusTracker {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Range> getRangesAfter(int line) {
|
|
||||||
return getRangesAfter(myRanges, line);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Range> getRangesAfter(List<Range> ranges, int line) {
|
public static List<Range> getRangesAfter(List<Range> ranges, int line) {
|
||||||
ArrayList<Range> result = new ArrayList<Range>();
|
ArrayList<Range> result = new ArrayList<Range>();
|
||||||
for (Range range : ranges) {
|
for (Range range : ranges) {
|
||||||
@@ -518,69 +447,6 @@ public class LineStatusTracker {
|
|||||||
return result;
|
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<Range> iterator = myRanges.listIterator(myRanges.size()); iterator.hasPrevious();) {
|
|
||||||
Range range = iterator.previous();
|
|
||||||
if (range.getOffset1() > line) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return range;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Range getRangeForLine(final int line) {
|
public Range getRangeForLine(final int line) {
|
||||||
for (final Range range : myRanges) {
|
for (final Range range : myRanges) {
|
||||||
@@ -594,63 +460,9 @@ public class LineStatusTracker {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class MyAction extends AnAction implements DumbAware {
|
public void rollbackChanges(final Range range) {
|
||||||
protected final LineStatusTracker myLineStatusTracker;
|
myApplication.assertWriteAccessAllowed();
|
||||||
protected final Range myRange;
|
|
||||||
|
|
||||||
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<Range> 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);
|
TextRange currentTextRange = getCurrentTextRange(range);
|
||||||
|
|
||||||
if (range.getType() == Range.INSERTED) {
|
if (range.getType() == Range.INSERTED) {
|
||||||
@@ -676,81 +488,25 @@ public class LineStatusTracker {
|
|||||||
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
|
return myUpToDateDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Project getProject() {
|
Project getProject() {
|
||||||
return myProject;
|
return myProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ShowDiffAction extends LineStatusTracker.MyAction {
|
TextRange getCurrentTextRange(Range range) {
|
||||||
public ShowDiffAction(LineStatusTracker lineStatusTracker, Range range, Editor editor) {
|
return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument, false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CopyAction extends MyAction {
|
TextRange getUpToDateRange(Range range) {
|
||||||
protected CopyAction(LineStatusTracker lineStatusTracker, Range range) {
|
return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, false);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextRange getCurrentTextRange(Range range) {
|
// a hack
|
||||||
return getRange(range.getType(), range.getOffset1(), range.getOffset2(), Range.DELETED, myDocument);
|
TextRange getUpToDateRangeWithEndSymbol(Range range) {
|
||||||
|
return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextRange getUpToDateRange(Range range) {
|
private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document,
|
||||||
return getRange(range.getType(), range.getUOffset1(), range.getUOffset2(), Range.INSERTED, myUpToDateDocument);
|
final boolean keepEnd) {
|
||||||
}
|
|
||||||
|
|
||||||
private static TextRange getRange(byte rangeType, int offset1, int offset2, byte emptyRangeCondition, Document document) {
|
|
||||||
if (rangeType == emptyRangeCondition) {
|
if (rangeType == emptyRangeCondition) {
|
||||||
int lineStartOffset;
|
int lineStartOffset;
|
||||||
if (offset1 == 0) {
|
if (offset1 == 0) {
|
||||||
@@ -767,104 +523,28 @@ public class LineStatusTracker {
|
|||||||
int startOffset = document.getLineStartOffset(offset1);
|
int startOffset = document.getLineStartOffset(offset1);
|
||||||
int endOffset = document.getLineEndOffset(offset2 - 1);
|
int endOffset = document.getLineEndOffset(offset2 - 1);
|
||||||
if (startOffset > 0) {
|
if (startOffset > 0) {
|
||||||
startOffset--;
|
-- startOffset;
|
||||||
endOffset--;
|
if (! keepEnd) {
|
||||||
|
-- endOffset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new TextRange(startOffset, endOffset);
|
return new TextRange(startOffset, endOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LineStatusTracker createOn(final Document doc, final String upToDateContent, final Project project) {
|
||||||
public void showActiveHint(Range range, final Editor editor, Point point) {
|
final Document document = EditorFactory.getInstance().createDocument(StringUtil.convertLineSeparators(upToDateContent));
|
||||||
|
|
||||||
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<AnAction> actionList = (List<AnAction>)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));
|
|
||||||
final LineStatusTracker tracker = new LineStatusTracker(doc, document, project);
|
final LineStatusTracker tracker = new LineStatusTracker(doc, document, project);
|
||||||
tracker.initialize(upToDateContent);
|
tracker.initialize(upToDateContent);
|
||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LineStatusTracker createOn(Document doc, Project project) {
|
public static LineStatusTracker createOn(final Document doc, final Project project) {
|
||||||
Document document = EditorFactory.getInstance().createDocument("");
|
final Document document = EditorFactory.getInstance().createDocument("");
|
||||||
return new LineStatusTracker(doc, document, project);
|
return new LineStatusTracker(doc, document, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBaseLoaded() {
|
||||||
|
return myBaseLoaded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<AnAction> actionList = (java.util.List<AnAction>)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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -154,12 +154,7 @@ public class Range {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Range mergeWith(Range range, LineStatusTracker tracker) {
|
public Range mergeWith(Range range, LineStatusTracker tracker) {
|
||||||
tracker.removeHighlighter(getHighlighter());
|
return new Range(myOffset1, range.myOffset2, myUpToDateOffset1, range.myUpToDateOffset2, mergedStatusWith(range));
|
||||||
setHighlighter(null);
|
|
||||||
tracker.removeHighlighter(range.getHighlighter());
|
|
||||||
range.setHighlighter(null);
|
|
||||||
Range result = new Range(myOffset1, range.myOffset2, myUpToDateOffset1, range.myUpToDateOffset2, mergedStatusWith(range));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte mergedStatusWith(Range range) {
|
private byte mergedStatusWith(Range range) {
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
package com.intellij.openapi.vcs.ex;
|
package com.intellij.openapi.vcs.ex;
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Document;
|
import com.intellij.openapi.editor.Document;
|
||||||
import com.intellij.openapi.editor.EditorFactory;
|
|
||||||
import com.intellij.util.ArrayUtil;
|
import com.intellij.util.ArrayUtil;
|
||||||
import com.intellij.util.diff.Diff;
|
import com.intellij.util.diff.Diff;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,16 +29,12 @@ import java.util.List;
|
|||||||
public class RangesBuilder {
|
public class RangesBuilder {
|
||||||
private List<Range> myRanges;
|
private List<Range> myRanges;
|
||||||
|
|
||||||
public RangesBuilder(String current, String upToDate) {
|
|
||||||
this(EditorFactory.getInstance().createDocument(current), EditorFactory.getInstance().createDocument(upToDate));
|
|
||||||
}
|
|
||||||
|
|
||||||
public RangesBuilder(Document current, Document upToDate) {
|
public RangesBuilder(Document current, Document upToDate) {
|
||||||
this(new DocumentWrapper(current).getLines(), new DocumentWrapper(upToDate).getLines(), 0, 0);
|
this(new DocumentWrapper(current).getLines(), new DocumentWrapper(upToDate).getLines(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RangesBuilder(List<String> current, List<String> upToDate, int shift, int uShift) {
|
public RangesBuilder(List<String> current, List<String> upToDate, int shift, int uShift) {
|
||||||
myRanges = new ArrayList<Range>();
|
myRanges = new LinkedList<Range>();
|
||||||
|
|
||||||
int shiftBefore = 0;
|
int shiftBefore = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+239
-202
@@ -24,7 +24,9 @@ package com.intellij.openapi.vcs.impl;
|
|||||||
|
|
||||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||||
import com.intellij.openapi.Disposable;
|
import com.intellij.openapi.Disposable;
|
||||||
|
import com.intellij.openapi.application.Application;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.application.ModalityState;
|
||||||
import com.intellij.openapi.components.ProjectComponent;
|
import com.intellij.openapi.components.ProjectComponent;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.editor.Document;
|
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.FileDocumentManager;
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||||
import com.intellij.openapi.project.Project;
|
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.util.Disposer;
|
||||||
import com.intellij.openapi.vcs.AbstractVcs;
|
import com.intellij.openapi.vcs.AbstractVcs;
|
||||||
import com.intellij.openapi.vcs.FileStatus;
|
import com.intellij.openapi.vcs.FileStatus;
|
||||||
import com.intellij.openapi.vcs.FileStatusListener;
|
import com.intellij.openapi.vcs.FileStatusListener;
|
||||||
import com.intellij.openapi.vcs.FileStatusManager;
|
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.vcs.ex.LineStatusTracker;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.openapi.vfs.VirtualFileAdapter;
|
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.NonNls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
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");
|
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.LineStatusTrackerManager");
|
||||||
|
|
||||||
public static LineStatusTrackerManager getInstance(Project project) {
|
public static LineStatusTrackerManagerI getInstance(final Project project) {
|
||||||
return PeriodicalTasksCloser.getInstance().safeGetComponent(project, LineStatusTrackerManager.class);
|
if (System.getProperty(IGNORE_CHANGEMARKERS_KEY) != null) {
|
||||||
|
return Dummy.getInstance();
|
||||||
|
}
|
||||||
|
return PeriodicalTasksCloser.getInstance().safeGetComponent(project, LineStatusTrackerManagerI.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Project myProject;
|
private final Project myProject;
|
||||||
|
|
||||||
private HashMap<Document, LineStatusTracker> myLineStatusTrackers =
|
private final Map<Document, LineStatusTracker> myLineStatusTrackers;
|
||||||
new HashMap<Document, LineStatusTracker>();
|
// !!! no state queries and self lock for add/remove
|
||||||
|
// removal from here - not under write action
|
||||||
|
private final Map<Document, Alarm> myLineStatusUpdateAlarms;
|
||||||
|
|
||||||
private final HashMap<Document, Alarm> myLineStatusUpdateAlarms =
|
|
||||||
new HashMap<Document, Alarm>();
|
|
||||||
|
|
||||||
private final Object TRACKERS_LOCK = new Object();
|
|
||||||
private boolean myIsDisposed = false;
|
|
||||||
@NonNls protected static final String IGNORE_CHANGEMARKERS_KEY = "idea.ignore.changemarkers";
|
@NonNls protected static final String IGNORE_CHANGEMARKERS_KEY = "idea.ignore.changemarkers";
|
||||||
|
|
||||||
private final ProjectLevelVcsManagerImpl myVcsManager;
|
private final ProjectLevelVcsManagerImpl myVcsManager;
|
||||||
private final VcsFileStatusProvider myStatusProvider;
|
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;
|
myProject = project;
|
||||||
myVcsManager = vcsManager;
|
myVcsManager = vcsManager;
|
||||||
myStatusProvider = statusProvider;
|
myStatusProvider = statusProvider;
|
||||||
|
myApplication = application;
|
||||||
|
myFileEditorManager = fileEditorManager;
|
||||||
|
myLineStatusTrackers = new HashMap<Document, LineStatusTracker>();
|
||||||
|
myLineStatusUpdateAlarms = Collections.synchronizedMap(new HashMap<Document, Alarm>());
|
||||||
|
|
||||||
project.getMessageBus().connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() {
|
project.getMessageBus().connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() {
|
||||||
public void updateStarted(final Document doc) {
|
public void updateStarted(final Document doc) {
|
||||||
|
myApplication.assertWriteAccessAllowed(); // can remove after some testing
|
||||||
|
|
||||||
final LineStatusTracker tracker = getLineStatusTracker(doc);
|
final LineStatusTracker tracker = getLineStatusTracker(doc);
|
||||||
if (tracker != null) tracker.startBulkUpdate();
|
if (tracker != null) tracker.startBulkUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateFinished(final Document doc) {
|
public void updateFinished(final Document doc) {
|
||||||
|
myApplication.assertWriteAccessAllowed(); // can remove after some testing
|
||||||
|
|
||||||
final LineStatusTracker tracker = getLineStatusTracker(doc);
|
final LineStatusTracker tracker = getLineStatusTracker(doc);
|
||||||
if (tracker != null) tracker.finishBulkUpdate();
|
if (tracker != null) tracker.finishBulkUpdate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
myDisposable = new Disposable() {
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
final Collection<LineStatusTracker> 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() {
|
public void projectOpened() {
|
||||||
trackAwtThread();
|
|
||||||
final MyFileStatusListener fileStatusListener = new MyFileStatusListener();
|
final MyFileStatusListener fileStatusListener = new MyFileStatusListener();
|
||||||
final EditorFactoryListener editorFactoryListener = new MyEditorFactoryListener();
|
final EditorFactoryListener editorFactoryListener = new MyEditorFactoryListener();
|
||||||
final MyVirtualFileListener virtualFileListener = new MyVirtualFileListener();
|
final MyVirtualFileListener virtualFileListener = new MyVirtualFileListener();
|
||||||
@@ -109,7 +143,6 @@ public class LineStatusTrackerManager implements ProjectComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
myLineStatusTrackers = new HashMap<Document, LineStatusTracker>();
|
|
||||||
final FileStatusManager fsManager = FileStatusManager.getInstance(myProject);
|
final FileStatusManager fsManager = FileStatusManager.getInstance(myProject);
|
||||||
fsManager.addFileStatusListener(fileStatusListener, myProject);
|
fsManager.addFileStatusListener(fileStatusListener, myProject);
|
||||||
|
|
||||||
@@ -122,9 +155,8 @@ public class LineStatusTrackerManager implements ProjectComponent {
|
|||||||
final EditorColorsManager editorColorsManager = EditorColorsManager.getInstance();
|
final EditorColorsManager editorColorsManager = EditorColorsManager.getInstance();
|
||||||
editorColorsManager.addEditorColorsListener(editorColorsListener);
|
editorColorsManager.addEditorColorsListener(editorColorsListener);
|
||||||
|
|
||||||
Disposer.register(myProject, new Disposable() {
|
Disposer.register(myDisposable, new Disposable() {
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
trackAwtThread();
|
|
||||||
fsManager.removeFileStatusListener(fileStatusListener);
|
fsManager.removeFileStatusListener(fileStatusListener);
|
||||||
virtualFileManager.removeVirtualFileListener(virtualFileListener);
|
virtualFileManager.removeVirtualFileListener(virtualFileListener);
|
||||||
editorColorsManager.removeEditorColorsListener(editorColorsListener);
|
editorColorsManager.removeEditorColorsListener(editorColorsListener);
|
||||||
@@ -133,13 +165,6 @@ public class LineStatusTrackerManager implements ProjectComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void projectClosed() {
|
public void projectClosed() {
|
||||||
try {
|
|
||||||
trackAwtThread();
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
myIsDisposed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNls @NotNull
|
@NonNls @NotNull
|
||||||
@@ -153,213 +178,212 @@ public class LineStatusTrackerManager implements ProjectComponent {
|
|||||||
public void disposeComponent() {
|
public void disposeComponent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispose() {
|
@Override
|
||||||
final Collection<LineStatusTracker> trackers = myLineStatusTrackers.values();
|
public LineStatusTracker getLineStatusTracker(final Document document) {
|
||||||
final LineStatusTracker[] lineStatusTrackers = trackers.toArray(new LineStatusTracker[trackers.size()]);
|
myApplication.assertReadAccessAllowed();
|
||||||
for (LineStatusTracker tracker : lineStatusTrackers) {
|
|
||||||
releaseTracker(tracker.getDocument());
|
|
||||||
}
|
|
||||||
|
|
||||||
myLineStatusTrackers = null;
|
if ((! myProject.isOpen()) || myProject.isDisposed()) return null;
|
||||||
}
|
|
||||||
|
|
||||||
public LineStatusTracker getLineStatusTracker(Document document) {
|
|
||||||
trackAwtThread();
|
|
||||||
if (myLineStatusTrackers == null) return null;
|
|
||||||
return myLineStatusTrackers.get(document);
|
return myLineStatusTrackers.get(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetTracker(@NotNull final VirtualFile virtualFile) {
|
||||||
public LineStatusTracker setUpToDateContent(final Document document, final String lastUpToDateContent) {
|
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
|
||||||
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;
|
|
||||||
|
|
||||||
final Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
|
final Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
|
||||||
if (document == null) {
|
if (document == null) {
|
||||||
if (LOG.isDebugEnabled()) {
|
log("Skipping resetTracker() because no cached document for " + virtualFile.getPath());
|
||||||
LOG.debug("Skipping resetTracker() because no cached document for " + virtualFile.getPath());
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled()) {
|
log("resetting tracker for file " + virtualFile.getPath());
|
||||||
LOG.debug("resetting tracker for file " + virtualFile.getPath());
|
|
||||||
}
|
final LineStatusTracker tracker = myLineStatusTrackers.get(document);
|
||||||
synchronized (TRACKERS_LOCK) {
|
final boolean editorOpened = myFileEditorManager.isFileOpen(virtualFile);
|
||||||
final LineStatusTracker tracker = myLineStatusTrackers.get(document);
|
final boolean shouldBeInstalled = shouldBeInstalled(virtualFile) && editorOpened;
|
||||||
if (tracker != null) {
|
|
||||||
resetTracker(tracker);
|
if (tracker == null && (! shouldBeInstalled)) return;
|
||||||
}
|
|
||||||
else {
|
myApplication.runWriteAction(new Runnable() {
|
||||||
if (Arrays.asList(FileEditorManager.getInstance(myProject).getOpenFiles()).contains(virtualFile)) {
|
@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);
|
installTracker(virtualFile, document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean releaseTracker(Document document) {
|
private void releaseTracker(final Document document) {
|
||||||
synchronized (TRACKERS_LOCK) {
|
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
|
||||||
releaseUpdateAlarms(document);
|
|
||||||
if (myLineStatusTrackers == null) return false;
|
|
||||||
if (!myLineStatusTrackers.containsKey(document)) return false;
|
|
||||||
LineStatusTracker tracker = myLineStatusTrackers.remove(document);
|
|
||||||
tracker.release();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void releaseUpdateAlarms(final Document document) {
|
myApplication.runWriteAction(new Runnable() {
|
||||||
if (myLineStatusUpdateAlarms.containsKey(document)) {
|
@Override
|
||||||
final Alarm alarm = myLineStatusUpdateAlarms.get(document);
|
public void run() {
|
||||||
if (alarm != null) {
|
final Alarm alarm = myLineStatusUpdateAlarms.remove(document);
|
||||||
alarm.cancelAllRequests();
|
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) {
|
private boolean shouldBeInstalled(final VirtualFile virtualFile) {
|
||||||
trackAwtThread();
|
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||||
if (tracker != null) {
|
|
||||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
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<Boolean>() {
|
||||||
|
@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() {
|
public void run() {
|
||||||
if (myIsDisposed) return;
|
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||||
if (releaseTracker(tracker.getDocument())) {
|
public void run() {
|
||||||
installTracker(tracker.getVirtualFile(), tracker.getDocument());
|
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() {
|
private void resetTrackersForOpenFiles() {
|
||||||
final VirtualFile[] openFiles = FileEditorManager.getInstance(myProject).getOpenFiles();
|
myApplication.assertReadAccessAllowed();
|
||||||
synchronized (TRACKERS_LOCK) {
|
if ((! myProject.isOpen()) || myProject.isDisposed()) return;
|
||||||
for(VirtualFile openFile: openFiles) {
|
|
||||||
resetTracker(openFile);
|
final VirtualFile[] openFiles = myFileEditorManager.getOpenFiles();
|
||||||
}
|
for(final VirtualFile openFile: openFiles) {
|
||||||
|
// write action inside is sufficient level
|
||||||
|
resetTracker(openFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyFileStatusListener implements FileStatusListener {
|
private class MyFileStatusListener implements FileStatusListener {
|
||||||
public void fileStatusesChanged() {
|
public void fileStatusesChanged() {
|
||||||
if (myProject.isDisposed()) return;
|
if (myProject.isDisposed()) return;
|
||||||
LOG.debug("LineStatusTrackerManager: fileStatusesChanged");
|
log("LineStatusTrackerManager: fileStatusesChanged");
|
||||||
trackAwtThread();
|
|
||||||
resetTrackersForOpenFiles();
|
resetTrackersForOpenFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fileStatusChanged(@NotNull VirtualFile virtualFile) {
|
public void fileStatusChanged(@NotNull VirtualFile virtualFile) {
|
||||||
trackAwtThread();
|
|
||||||
resetTracker(virtualFile);
|
resetTracker(virtualFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,33 +394,46 @@ public class LineStatusTrackerManager implements ProjectComponent {
|
|||||||
// outside of EDT, so the EDT check mustn't be done here
|
// outside of EDT, so the EDT check mustn't be done here
|
||||||
Editor editor = event.getEditor();
|
Editor editor = event.getEditor();
|
||||||
if (editor.getProject() != null && editor.getProject() != myProject) return;
|
if (editor.getProject() != null && editor.getProject() != myProject) return;
|
||||||
Document document = editor.getDocument();
|
final Document document = editor.getDocument();
|
||||||
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
|
final VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
|
||||||
installTracker(virtualFile, document);
|
|
||||||
|
new AbstractCalledLater(myProject, ModalityState.NON_MODAL) {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (shouldBeInstalled(virtualFile)) {
|
||||||
|
installTracker(virtualFile, document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.callMe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void editorReleased(EditorFactoryEvent event) {
|
public void editorReleased(EditorFactoryEvent event) {
|
||||||
trackAwtThread();
|
|
||||||
final Editor editor = event.getEditor();
|
final Editor editor = event.getEditor();
|
||||||
if (editor.getProject() != null && editor.getProject() != myProject) return;
|
if (editor.getProject() != null && editor.getProject() != myProject) return;
|
||||||
final Document doc = editor.getDocument();
|
final Document doc = editor.getDocument();
|
||||||
final Editor[] editors = event.getFactory().getEditors(doc, myProject);
|
final Editor[] editors = event.getFactory().getEditors(doc, myProject);
|
||||||
if (editors.length == 0) {
|
if (editors.length == 0) {
|
||||||
releaseTracker(doc);
|
new AbstractCalledLater(myProject, ModalityState.NON_MODAL) {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
releaseTracker(doc);
|
||||||
|
}
|
||||||
|
}.callMe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyVirtualFileListener extends VirtualFileAdapter {
|
private class MyVirtualFileListener extends VirtualFileAdapter {
|
||||||
public void beforeContentsChange(VirtualFileEvent event) {
|
public void beforeContentsChange(VirtualFileEvent event) {
|
||||||
trackAwtThread();
|
|
||||||
if (event.isFromRefresh()) {
|
if (event.isFromRefresh()) {
|
||||||
resetTracker(event.getFile());
|
resetTracker(event.getFile());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void trackAwtThread() {
|
private static void log(final String s) {
|
||||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -40,7 +40,7 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide
|
|||||||
public int getLineNumber(int currentNumber) {
|
public int getLineNumber(int currentNumber) {
|
||||||
LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument);
|
LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument);
|
||||||
if (tracker == null) {
|
if (tracker == null) {
|
||||||
tracker = LineStatusTrackerManager.getInstance(myProject).setUpToDateContent(myDocument, myUpToDateContent);
|
return currentNumber;
|
||||||
}
|
}
|
||||||
return calcLineNumber(tracker, currentNumber);
|
return calcLineNumber(tracker, currentNumber);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user