mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
VCS: short diff to be loaded in background through generic loader
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+6
-4
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
+138
-24
@@ -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);
|
||||
}
|
||||
+1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user