VCS: short diff to be loaded in background through generic loader

This commit is contained in:
irengrig
2011-07-05 19:51:11 +04:00
parent 0d04dd5051
commit b7bef12305
11 changed files with 438 additions and 93 deletions
@@ -0,0 +1,26 @@
/*
* Copyright 2000-2011 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;
/**
* @author irengrig
* Date: 7/5/11
* Time: 7:32 PM
*/
public interface Details<Id, Data> {
void take(Id id, Data data);
Id getCurrentlySelected();
}
@@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
* Date: 6/29/11
* Time: 11:38 PM
*/
public class GenericDetailsLoader<Id, Data> implements PairConsumer<Id, Data> {
public class GenericDetailsLoader<Id, Data> implements Details<Id,Data> {
private final Consumer<Id> myLoader;
private final ValueConsumer<Id, Data> myValueConsumer;
private final AtomicReference<Id> myCurrentlySelected;
@@ -39,21 +39,27 @@ public class GenericDetailsLoader<Id, Data> implements PairConsumer<Id, Data> {
myCurrentlySelected = new AtomicReference<Id>(null);
}
public void updateSelection(@Nullable final Id id) {
public void updateSelection(@Nullable final Id id, boolean force) {
ApplicationManager.getApplication().assertIsDispatchThread();
myValueConsumer.setId(id);
if (! Comparing.equal(id, myCurrentlySelected.getAndSet(id))) {
final Id wasId = myCurrentlySelected.getAndSet(id);
if (force || ! Comparing.equal(id, wasId)) {
myLoader.consume(id);
}
}
public void setCacheConsumer(final PairConsumer<Id, Data> cacheConsumer) {
myValueConsumer.setCacheConsumer(cacheConsumer);
}
@Override
public void consume(Id id, Data data) {
public void take(Id id, Data data) {
ApplicationManager.getApplication().assertIsDispatchThread();
myValueConsumer.consume(id, data);
}
@Override
public Id getCurrentlySelected() {
return myCurrentlySelected.get();
}
@@ -26,14 +26,23 @@ public class ValueConsumer<Id, Data> {
private Id myId;
private Id mySetId;
private final PairConsumer<Id, Data> myConsumer;
private PairConsumer<Id, Data> myCacheConsumer;
protected ValueConsumer(PairConsumer<Id, Data> consumer) {
myConsumer = consumer;
}
public void setCacheConsumer(PairConsumer<Id, Data> cacheConsumer) {
myCacheConsumer = cacheConsumer;
}
public void consume(final Id id, final Data data) {
if (id.equals(mySetId)) return; // already set
if (! id.equals(myId)) return;
if (id.equals(mySetId) || ! id.equals(myId)) {
if (myCacheConsumer != null) {
myCacheConsumer.consume(id, data);
}
return;
}
mySetId = id;
myConsumer.consume(id, data);
}
@@ -37,11 +37,13 @@ public class BinaryDiffRequestFromChange implements DiffRequestFromChange<DiffCo
myProject = project;
}
@Override
public boolean canCreateRequest(Change change) {
return ShowDiffAction.isBinaryChange(myProject, change);
}
@Override
public List<BeforeAfter<DiffContent>> createRequestForChange(Change change, int extraLines) throws VcsException {
if (ShowDiffAction.isBinaryChange(myProject, change)) {
return Collections.singletonList(ShowDiffAction.createBinaryDiffContents(myProject, change));
}
return null;
return Collections.singletonList(ShowDiffAction.createBinaryDiffContents(myProject, change));
}
}
@@ -54,6 +54,8 @@ import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.util.PairConsumer;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.SLRUMap;
import com.intellij.util.messages.MessageBusConnection;
@@ -98,10 +100,8 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
@NonNls private static final String ATT_SHOW_IGNORED = "show_ignored";
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.ChangesViewManager");
private Splitter mySplitter;
// todo group somewhere
private JPanel myNoDetailsPanel;
private JPanel myNothingSelected;
private JPanel myNotLoadedYet;
private DetailsPanel myDetailsPanel;
private GenericDetailsLoader<Change, Pair<JPanel, Disposable>> myDetailsLoader;
private boolean myDetailsOn;
private ChangesViewManager.MyFileListener myFileListener;
private final SLRUMap<FilePath, Pair<JPanel, Disposable>> myDetailsCache;
@@ -111,6 +111,8 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
private Runnable myUpdateDetails;
private MessageBusConnection myConnection;
private ChangesViewManager.ToggleDetailsAction myToggleDetailsAction;
private PairConsumer<Change,Pair<JPanel, Disposable>> myDetailsConsumer;
private final TreeSelectionListener myTsl;
public static ChangesViewI getInstance(Project project) {
return PeriodicalTasksCloser.getInstance().safeGetComponent(project, ChangesViewI.class);
@@ -121,9 +123,6 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
myContentManager = contentManager;
myVcsChangeDetailsManager = vcsChangeDetailsManager;
myView = new ChangesListView(project);
myNoDetailsPanel = UIVcsUtil.errorPanel("No details available", false);
myNothingSelected = UIVcsUtil.errorPanel("Nothing selected", false);
myNotLoadedYet = UIVcsUtil.errorPanel("Changes content is not loaded yet", false);
Disposer.register(project, myView);
myRepaintAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project);
@@ -144,6 +143,12 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
changeDetails();
}
};
myTsl = new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
changeDetails();
}
};
}
public void projectOpened() {
@@ -173,6 +178,12 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
}
public void projectClosed() {
if (myToggleDetailsAction.isSelected(null)) {
VirtualFileManager.getInstance().removeVirtualFileListener(myFileListener);
EditorFactory.getInstance().getEventMulticaster().removeDocumentListener(myDocumentListener);
}
myDetailsPanel.clear();
myView.removeTreeSelectionListener(myTsl);
myConnection.disconnect();
myDetailsCache.clear();
myDisposed = true;
@@ -244,56 +255,92 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
content.add(myProgressLabel, BorderLayout.SOUTH);
panel.setContent(content);
myDetailsPanel = new DetailsPanel();
initDetailsLoader();
myView.installDndSupport(ChangeListManagerImpl.getInstanceImpl(myProject));
myView.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
changeDetails();
}
});
myView.addTreeSelectionListener(myTsl);
return panel;
}
private void initDetailsLoader() {
final PairConsumer<Change, Pair<JPanel, Disposable>> cacheConsumer = new PairConsumer<Change, Pair<JPanel, Disposable>>() {
@Override
public void consume(Change change, Pair<JPanel, Disposable> pair) {
final FilePath filePath = ChangesUtil.getFilePath(change);
final Pair<JPanel, Disposable> old = myDetailsCache.get(filePath);
if (old == null) {
myDetailsCache.put(filePath, pair);
} else if (old != pair) {
Disposer.dispose(pair.getSecond());
}
}
};
myDetailsConsumer = new PairConsumer<Change, Pair<JPanel, Disposable>>() {
@Override
public void consume(Change change, Pair<JPanel, Disposable> pair) {
cacheConsumer.consume(change, pair);
myDetailsPanel.data(pair.getFirst());
myDetailsPanel.layout();
}
};
myDetailsLoader = new GenericDetailsLoader<Change, Pair<JPanel, Disposable>>(new Consumer<Change>() {
@Override
public void consume(Change change) {
final FilePath filePath = ChangesUtil.getFilePath(change);
Pair<JPanel, Disposable> details = myDetailsCache.get(filePath);
if (details != null) {
myDetailsConsumer.consume(change, details);
} else if (myVcsChangeDetailsManager.getPanel(change)) {
myDetailsPanel.loading();
myDetailsPanel.layout();
}
}
}, myDetailsConsumer);
myDetailsLoader.setCacheConsumer(cacheConsumer);
myVcsChangeDetailsManager.setDetails(myDetailsLoader);
}
private void changeDetails() {
if (! myDetailsOn) {
setChangeDetailsPanel(null);
if (mySplitter.getSecondComponent() != null) {
setChangeDetailsPanel(null);
}
} else {
final Change[] selectedChanges = myView.getSelectedChanges();
if (selectedChanges.length == 0) {
setChangeDetailsPanel(myNothingSelected);
} else {
final String freezed = ChangeListManager.getInstance(myProject).isFreezed();
if (freezed != null) {
setChangeDetailsPanel(UIVcsUtil.errorPanel(freezed, false));
setDetails();
myDetailsPanel.layout();
if (mySplitter.getSecondComponent() == null) {
setChangeDetailsPanel(myDetailsPanel.myPanel);
}
}
}
private void setDetails() {
final Change[] selectedChanges = myView.getSelectedChanges();
if (selectedChanges.length == 0) {
myDetailsPanel.nothingSelected();
} else {
final String freezed = ChangeListManager.getInstance(myProject).isFreezed();
if (freezed != null) {
myDetailsPanel.data(UIVcsUtil.errorPanel(freezed, false));
return;
}
myDetailsPanel.notAvailable();
for (Change change : selectedChanges) {
if (change.getBeforeRevision() instanceof FakeRevision || change.getAfterRevision() instanceof FakeRevision) {
myDetailsPanel.loadingInitial();
return;
}
Pair<JPanel, Disposable> details = null;
FilePath filePath = null;
for (Change change : selectedChanges) {
if (change.getBeforeRevision() instanceof FakeRevision || change.getAfterRevision() instanceof FakeRevision) {
setChangeDetailsPanel(myNotLoadedYet);
return;
}
filePath = ChangesUtil.getFilePath(change);
details = myDetailsCache.get(filePath);
if (details != null) break;
details = myVcsChangeDetailsManager.getPanel(change);
if (details != null) {
myDetailsCache.put(filePath, details);
break;
}
if (myVcsChangeDetailsManager.canComment(change)) {
myDetailsFilePath = ChangesUtil.getFilePath(change);
myDetailsLoader.updateSelection(change, true);
return;
}
final JPanel panel;
if (details == null) {
panel = myNoDetailsPanel;
}
else {
myDetailsFilePath = filePath;
panel = details.getFirst();
}
setChangeDetailsPanel(panel);
}
myDetailsPanel.notAvailable();
}
}
@@ -580,4 +627,61 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
}
}
}
private static class DetailsPanel {
private CardLayout myLayout;
private JPanel myPanel;
private JPanel myDataPanel;
private Layer myCurrentLayer;
private DetailsPanel() {
myPanel = new JPanel();
myLayout = new CardLayout();
myPanel.setLayout(myLayout);
myDataPanel = new JPanel(new BorderLayout());
myPanel.add(UIVcsUtil.errorPanel("No details available", false), Layer.notAvailable.name());
myPanel.add(UIVcsUtil.errorPanel("Nothing selected", false), Layer.nothingSelected.name());
myPanel.add(UIVcsUtil.errorPanel("Changes content is not loaded yet", false), Layer.notLoadedInitial.name());
myPanel.add(UIVcsUtil.errorPanel("Loading...", false), Layer.loading.name());
myPanel.add(myDataPanel, Layer.data.name());
}
public void nothingSelected() {
myCurrentLayer = Layer.nothingSelected;
}
public void notAvailable() {
myCurrentLayer = Layer.notAvailable;
}
public void loading() {
myCurrentLayer = Layer.loading;
}
public void loadingInitial() {
myCurrentLayer = Layer.notLoadedInitial;
}
public void data(final JPanel panel) {
myCurrentLayer = Layer.data;
myPanel.add(panel, Layer.data.name());
}
public void layout() {
myLayout.show(myPanel, myCurrentLayer.name());
}
public void clear() {
myPanel.removeAll();
}
private static enum Layer {
notAvailable,
nothingSelected,
notLoadedInitial,
loading,
data,
}
}
}
@@ -64,11 +64,17 @@ public class FragmentedDiffRequestFromChange implements DiffRequestFromChange<Sh
}
@Override
public boolean canCreateRequest(Change change) {
if (ChangesUtil.isTextConflictingChange(change)) return false;
if (ShowDiffAction.isBinaryChange(myProject, change)) return false;
final FilePath filePath = ChangesUtil.getFilePath(change);
if (filePath.isDirectory()) return false;
return true;
}
@Override
public List<BeforeAfter<ShiftedSimpleContent>> createRequestForChange(Change change, int extraLines) throws VcsException {
if (ChangesUtil.isTextConflictingChange(change)) return null;
if (ShowDiffAction.isBinaryChange(myProject, change)) return null;
final FilePath filePath = ChangesUtil.getFilePath(change);
if (filePath.isDirectory()) return null;
final RangesCalculator calculator = new RangesCalculator();
calculator.execute(change, filePath, myRangesCache, LineStatusTrackerManager.getInstance(myProject));
@@ -216,7 +222,7 @@ public class FragmentedDiffRequestFromChange implements DiffRequestFromChange<Sh
final Document oldDocument = new DocumentImpl(true);
// todo !!! a question how to show line separators in diff etc
// todo currently document doesn't allow to put \r as separator
oldDocument.setText(StringUtil.convertLineSeparators(notNullContentRevision(cr)));
oldDocument.replaceString(0, oldDocument.getTextLength(), StringUtil.convertLineSeparators(notNullContentRevision(cr)));
oldDocument.setReadOnly(true);
return oldDocument;
}
@@ -0,0 +1,39 @@
/*
* Copyright 2000-2011 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.changes;
/**
* @author irengrig
* Date: 7/5/11
* Time: 3:35 PM
*/
public class TransparentlyFailedValue<T, E extends Exception> {
private T t;
private E e;
public void set(final T t) {
this.t = t;
}
public void fail(final E e) {
this.e = e;
}
public T get() throws E {
if (this.e != null) throw this.e;
return this.t;
}
}
@@ -21,17 +21,22 @@ import com.intellij.openapi.diff.DiffContent;
import com.intellij.openapi.diff.DiffPanel;
import com.intellij.openapi.diff.ShiftedSimpleContent;
import com.intellij.openapi.diff.impl.DiffPanelImpl;
import com.intellij.openapi.progress.BackgroundTaskQueue;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.Details;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vcs.changes.actions.DiffRequestFromChange;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.BeforeAfter;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.HashMap;
import com.intellij.vcsUtil.UIVcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -49,15 +54,18 @@ import java.util.Map;
*/
public class VcsChangeDetailsManager {
private static final int extraLines = 2;
private final Map<VcsKey, Convertor<Change, Pair<JPanel, Disposable>>> myProviderMap = new HashMap<VcsKey, Convertor<Change, Pair<JPanel, Disposable>>>();
private final List<Convertor<Change, Pair<JPanel, Disposable>>> myDedicatedList;
private final Map<VcsKey, VcsChangeDetailsProvider> myProviderMap = new HashMap<VcsKey, VcsChangeDetailsProvider>();
private final List<VcsChangeDetailsProvider> myDedicatedList;
// todo also check for size
private final LinkedList<DiffPanel> myDiffPanelCache;
private final Project myProject;
private Details<Change, Pair<JPanel, Disposable>> myDetails;
private final BackgroundTaskQueue myQueue;
public VcsChangeDetailsManager(final Project project) {
myProject = project;
myDedicatedList = new ArrayList<Convertor<Change,Pair<JPanel, Disposable>>>();
myQueue = new BackgroundTaskQueue(myProject, "Loading change details");
myDedicatedList = new ArrayList<VcsChangeDetailsProvider>();
myDiffPanelCache = new LinkedList<DiffPanel>();
myDedicatedList.add(new BinaryDiffDetailsProvider(project, myDiffPanelCache));
@@ -66,6 +74,7 @@ public class VcsChangeDetailsManager {
Disposer.register(project, new Disposable() {
@Override
public void dispose() {
myQueue.clear();
for (DiffPanel diffPanel : myDiffPanelCache) {
Disposer.dispose(diffPanel);
}
@@ -73,19 +82,67 @@ public class VcsChangeDetailsManager {
});
}
public void setDetails(Details<Change, Pair<JPanel, Disposable>> details) {
myDetails = details;
}
public boolean canComment(final Change change) {
return getProvider(change) != null;
}
@Nullable
public Pair<JPanel, Disposable> getPanel(final Change change) {
// text details
for (Convertor<Change, Pair<JPanel, Disposable>> convertor : myDedicatedList) {
final Pair<JPanel, Disposable> pair = convertor.convert(change);
if (pair != null) {
return pair;
}
private VcsChangeDetailsProvider getProvider(final Change change) {
for (VcsChangeDetailsProvider provider : myDedicatedList) {
if (provider.canComment(change)) return provider;
}
return null;
}
private static class BinaryDiffDetailsProvider implements Convertor<Change,Pair<JPanel, Disposable>> {
// true -> loading
public boolean getPanel(final Change change) {
// text details
final VcsChangeDetailsProvider<?> provider = getProvider(change);
if (provider == null) {
return false;
}
myQueue.run(new LoaderTask(myProject, provider, change, myDetails));
return true;
}
private static class LoaderTask<T> extends Task.Backgroundable {
private T myResult;
private final VcsChangeDetailsProvider<T> myProvider;
private final Change myChange;
private final Details<Change, Pair<JPanel, Disposable>> myDetails;
private LoaderTask(@Nullable Project project, final VcsChangeDetailsProvider provider, final Change change,
final Details<Change, Pair<JPanel, Disposable>> consumer) {
super(project, provider.getProgressTitle(), false, BackgroundFromStartOption.getInstance());
myProvider = provider;
myChange = change;
myDetails = consumer;
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
if (myProject.isDisposed() || ! myProject.isOpen() || !Comparing.equal(myChange, myDetails.getCurrentlySelected())) return;
//if (! myProvider.canComment(myChange)) return;
myResult = myProvider.load(myChange);
}
@Override
public void onSuccess() {
if (myProject.isDisposed() || ! myProject.isOpen()) return;
if (myResult != null) {
final Pair<JPanel, Disposable> pair = myProvider.comment(myChange, myResult);
myDetails.take(myChange, pair);
}
// todo else?
}
}
private static class BinaryDiffDetailsProvider implements VcsChangeDetailsProvider<ValueWithVcsException<List<BeforeAfter<DiffContent>>>> {
private final BinaryDiffRequestFromChange myRequestFromChange;
private final Project myProject;
private DiffPanelHolder myDiffPanelHolder;
@@ -97,15 +154,26 @@ public class VcsChangeDetailsManager {
}
@Override
public Pair<JPanel, Disposable> convert(Change o) {
public String getProgressTitle() {
return "Loading change content";
}
@Override
public boolean canComment(Change change) {
return myRequestFromChange.canCreateRequest(change);
}
@Override
public Pair<JPanel, Disposable> comment(Change change, ValueWithVcsException<List<BeforeAfter<DiffContent>>> value) {
final List<BeforeAfter<DiffContent>> contents;
try {
contents = myRequestFromChange.createRequestForChange(o, 0);
contents = value.get();
if (contents == null) throw new VcsException("Can not load content");
}
catch (VcsException e) {
return new Pair<JPanel, Disposable>(UIVcsUtil.errorPanel(e.getMessage(), true), null);
}
if (contents == null || contents.isEmpty()) return null;
if (contents.isEmpty()) return noDifferences();
assert contents.size() == 1;
final DiffPanel panel = myDiffPanelHolder.getOrCreate();
panel.setContents(contents.get(0).getBefore(), contents.get(0).getAfter());
@@ -116,7 +184,7 @@ public class VcsChangeDetailsManager {
final JPanel wrapper = new JPanel();
final BoxLayout boxLayout = new BoxLayout(wrapper, BoxLayout.X_AXIS);
wrapper.setLayout(boxLayout);
final JLabel label = new JLabel(changeDescription(o));
final JLabel label = new JLabel(changeDescription(change));
label.setBorder(BorderFactory.createEmptyBorder(1,2,0,0));
wrapper.add(label);
topPanel.add(wrapper, BorderLayout.CENTER);
@@ -131,9 +199,37 @@ public class VcsChangeDetailsManager {
}
});
}
@Override
public ValueWithVcsException<List<BeforeAfter<DiffContent>>> load(final Change change) {
return new ValueWithVcsException<List<BeforeAfter<DiffContent>>>() {
@Override
protected List<BeforeAfter<DiffContent>> computeImpl() throws VcsException {
return myRequestFromChange.createRequestForChange(change, 0);
}
};
}
}
private static class FragmentedDiffDetailsProvider implements Convertor<Change,Pair<JPanel, Disposable>> {
private abstract static class ValueWithVcsException<T> extends TransparentlyFailedValue<T, VcsException> {
protected ValueWithVcsException() {
try {
set(computeImpl());
}
catch (VcsException e) {
fail(e);
}
}
protected abstract T computeImpl() throws VcsException;
}
private static Pair<JPanel, Disposable> noDifferences() {
return new Pair<JPanel, Disposable>(
UIVcsUtil.errorPanel(DiffBundle.message("diff.contents.have.differences.only.in.line.separators.message.text"), false), null);
}
private static class FragmentedDiffDetailsProvider implements VcsChangeDetailsProvider<ValueWithVcsException<List<BeforeAfter<ShiftedSimpleContent>>>> {
private final DiffRequestFromChange<ShiftedSimpleContent> myRequestFromChange;
private final Project myProject;
private final LinkedList<DiffPanel> myDiffPanelCache;
@@ -147,14 +243,33 @@ public class VcsChangeDetailsManager {
}
@Override
public Pair<JPanel, Disposable> convert(Change o) {
public String getProgressTitle() {
return "Loading change content";
}
@Override
public boolean canComment(Change change) {
return myRequestFromChange.canCreateRequest(change);
}
@Override
public ValueWithVcsException<List<BeforeAfter<ShiftedSimpleContent>>> load(final Change change) {
return new ValueWithVcsException<List<BeforeAfter<ShiftedSimpleContent>>>() {
@Override
protected List<BeforeAfter<ShiftedSimpleContent>> computeImpl() throws VcsException {
return myRequestFromChange.createRequestForChange(change, extraLines);
}
};
}
@Override
public Pair<JPanel, Disposable> comment(Change change, ValueWithVcsException<List<BeforeAfter<ShiftedSimpleContent>>> value) {
final List<BeforeAfter<ShiftedSimpleContent>> requestForChange;
try {
requestForChange = myRequestFromChange.createRequestForChange(o, extraLines);
if (requestForChange == null) return null;
requestForChange = value.get();
if (requestForChange == null) throw new VcsException("Can not load content");
if (requestForChange.isEmpty()) {
return new Pair<JPanel, Disposable>(
UIVcsUtil.errorPanel(DiffBundle.message("diff.contents.have.differences.only.in.line.separators.message.text"), false), null);
return noDifferences();
}
}
catch (VcsException e) {
@@ -162,11 +277,10 @@ public class VcsChangeDetailsManager {
}
final ChangesFragmentedDiffPanel panel =
new ChangesFragmentedDiffPanel(myProject, requestForChange, myDiffPanelCache, changeDescription(o));
new ChangesFragmentedDiffPanel(myProject, requestForChange, myDiffPanelCache, changeDescription(change));
panel.buildUi();
return new Pair<JPanel, Disposable>(panel.getPanel(), panel);
}
}
private static String changeDescription(Change o) {
@@ -0,0 +1,38 @@
/*
* Copyright 2000-2011 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.changes;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.CalledInAwt;
import com.intellij.openapi.vcs.CalledInBackground;
import javax.swing.*;
/**
* @author irengrig
* Date: 7/5/11
* Time: 2:49 PM
*/
public interface VcsChangeDetailsProvider<T> {
String getProgressTitle();
@CalledInAwt
boolean canComment(final Change change);
@CalledInBackground
T load(final Change change);
@CalledInAwt
Pair<JPanel, Disposable> comment(final Change change, final T t);
}
@@ -29,6 +29,7 @@ import java.util.List;
* Time: 6:39 PM
*/
public interface DiffRequestFromChange<T extends DiffContent> {
boolean canCreateRequest(final Change change);
@Nullable
List<BeforeAfter<T>> createRequestForChange(final Change change, int extraLines) throws VcsException;
}
@@ -312,7 +312,7 @@ public class GitLogUI implements Disposable {
question.putValue(commitI.selectRepository(myRootsUnderVcs), commitI.getHash());
myDetailsCache.acceptQuestion(question);
} else {
myDetailsLoader.consume(commitI, gitCommit);
myDetailsLoader.take(commitI, gitCommit);
}
}
};
@@ -342,7 +342,7 @@ public class GitLogUI implements Disposable {
final VirtualFile root = commitI.selectRepository(myRootsUnderVcs);
final List<String> branches = myDetailsCache.getBranches(root, commitI.getHash());
if (branches != null) {
myBranchesLoader.consume(commitI, branches);
myBranchesLoader.take(commitI, branches);
return;
}
@@ -350,7 +350,7 @@ public class GitLogUI implements Disposable {
@Override
public void consume(List<String> strings) {
if (myProject.isDisposed() || strings == null) return;
myBranchesLoader.consume(commitI, strings);
myBranchesLoader.take(commitI, strings);
}
}, myRecheck);
}
@@ -447,19 +447,19 @@ public class GitLogUI implements Disposable {
if (meaningfulRows == 0) {
myDetailsPanel.nothingSelected();
myDetailsLoader.updateSelection(null);
myBranchesLoader.updateSelection(null);
myDetailsLoader.updateSelection(null, false);
myBranchesLoader.updateSelection(null, false);
} else if (meaningfulRows == 1) {
final GitCommit commit = fullCommitPresentation(commitAt);
if (commit == null) {
myDetailsPanel.loading(commitAt.selectRepository(myRootsUnderVcs));
}
myDetailsLoader.updateSelection(commitAt);
myBranchesLoader.updateSelection(commitAt);
myDetailsLoader.updateSelection(commitAt, false);
myBranchesLoader.updateSelection(commitAt, false);
} else {
myDetailsPanel.severalSelected();
myDetailsLoader.updateSelection(null);
myBranchesLoader.updateSelection(null);
myDetailsLoader.updateSelection(null, false);
myBranchesLoader.updateSelection(null, false);
}
}