From b7bef1230524b1e64b864a7688dd35db1975e50f Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 5 Jul 2011 19:48:40 +0400 Subject: [PATCH] VCS: short diff to be loaded in background through generic loader --- .../src/com/intellij/openapi/vcs/Details.java | 26 +++ .../openapi/vcs/GenericDetailsLoader.java | 14 +- .../intellij/openapi/vcs/ValueConsumer.java | 13 +- .../changes/BinaryDiffRequestFromChange.java | 10 +- .../vcs/changes/ChangesViewManager.java | 196 ++++++++++++++---- .../FragmentedDiffRequestFromChange.java | 14 +- .../vcs/changes/TransparentlyFailedValue.java | 39 ++++ .../vcs/changes/VcsChangeDetailsManager.java | 162 ++++++++++++--- .../vcs/changes/VcsChangeDetailsProvider.java | 38 ++++ .../actions/DiffRequestFromChange.java | 1 + .../git4idea/history/wholeTree/GitLogUI.java | 18 +- 11 files changed, 438 insertions(+), 93 deletions(-) create mode 100644 platform/vcs-api/src/com/intellij/openapi/vcs/Details.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/TransparentlyFailedValue.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsProvider.java diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/Details.java b/platform/vcs-api/src/com/intellij/openapi/vcs/Details.java new file mode 100644 index 000000000000..06ea73bc8d23 --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/Details.java @@ -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 { + void take(Id id, Data data); + Id getCurrentlySelected(); +} diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/GenericDetailsLoader.java b/platform/vcs-api/src/com/intellij/openapi/vcs/GenericDetailsLoader.java index 838dc375406c..590fd22a0ea6 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/GenericDetailsLoader.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/GenericDetailsLoader.java @@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicReference; * Date: 6/29/11 * Time: 11:38 PM */ -public class GenericDetailsLoader implements PairConsumer { +public class GenericDetailsLoader implements Details { private final Consumer myLoader; private final ValueConsumer myValueConsumer; private final AtomicReference myCurrentlySelected; @@ -39,21 +39,27 @@ public class GenericDetailsLoader implements PairConsumer { myCurrentlySelected = new AtomicReference(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 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(); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ValueConsumer.java b/platform/vcs-api/src/com/intellij/openapi/vcs/ValueConsumer.java index 368cc53462d7..b6f6283c07c0 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/ValueConsumer.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/ValueConsumer.java @@ -26,14 +26,23 @@ public class ValueConsumer { private Id myId; private Id mySetId; private final PairConsumer myConsumer; + private PairConsumer myCacheConsumer; protected ValueConsumer(PairConsumer consumer) { myConsumer = consumer; } + public void setCacheConsumer(PairConsumer 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); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java index 4845bfc7fbd0..d101e9147ce1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java @@ -37,11 +37,13 @@ public class BinaryDiffRequestFromChange implements DiffRequestFromChange> 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)); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java index 6bd689dbdf25..8cc7029c590e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewManager.java @@ -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> myDetailsLoader; private boolean myDetailsOn; private ChangesViewManager.MyFileListener myFileListener; private final SLRUMap> myDetailsCache; @@ -111,6 +111,8 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro private Runnable myUpdateDetails; private MessageBusConnection myConnection; private ChangesViewManager.ToggleDetailsAction myToggleDetailsAction; + private PairConsumer> 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> cacheConsumer = new PairConsumer>() { + @Override + public void consume(Change change, Pair pair) { + final FilePath filePath = ChangesUtil.getFilePath(change); + final Pair old = myDetailsCache.get(filePath); + if (old == null) { + myDetailsCache.put(filePath, pair); + } else if (old != pair) { + Disposer.dispose(pair.getSecond()); + } + } + }; + myDetailsConsumer = new PairConsumer>() { + @Override + public void consume(Change change, Pair pair) { + cacheConsumer.consume(change, pair); + myDetailsPanel.data(pair.getFirst()); + myDetailsPanel.layout(); + } + }; + myDetailsLoader = new GenericDetailsLoader>(new Consumer() { + @Override + public void consume(Change change) { + final FilePath filePath = ChangesUtil.getFilePath(change); + Pair 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 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, + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java index 3f97ae57b160..64dd0efce1a4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java @@ -64,11 +64,17 @@ public class FragmentedDiffRequestFromChange implements DiffRequestFromChange> 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 { + 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; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java index 48f683863833..f1ba72f08ec6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java @@ -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>> myProviderMap = new HashMap>>(); - private final List>> myDedicatedList; + private final Map myProviderMap = new HashMap(); + private final List myDedicatedList; // todo also check for size private final LinkedList myDiffPanelCache; private final Project myProject; + private Details> myDetails; + private final BackgroundTaskQueue myQueue; public VcsChangeDetailsManager(final Project project) { myProject = project; - myDedicatedList = new ArrayList>>(); + myQueue = new BackgroundTaskQueue(myProject, "Loading change details"); + myDedicatedList = new ArrayList(); myDiffPanelCache = new LinkedList(); 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> details) { + myDetails = details; + } + + public boolean canComment(final Change change) { + return getProvider(change) != null; + } + @Nullable - public Pair getPanel(final Change change) { - // text details - for (Convertor> convertor : myDedicatedList) { - final Pair 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> { + // 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 extends Task.Backgroundable { + private T myResult; + private final VcsChangeDetailsProvider myProvider; + private final Change myChange; + private final Details> myDetails; + + private LoaderTask(@Nullable Project project, final VcsChangeDetailsProvider provider, final Change change, + final Details> 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 pair = myProvider.comment(myChange, myResult); + myDetails.take(myChange, pair); + } + // todo else? + } + } + + private static class BinaryDiffDetailsProvider implements VcsChangeDetailsProvider>>> { private final BinaryDiffRequestFromChange myRequestFromChange; private final Project myProject; private DiffPanelHolder myDiffPanelHolder; @@ -97,15 +154,26 @@ public class VcsChangeDetailsManager { } @Override - public Pair convert(Change o) { + public String getProgressTitle() { + return "Loading change content"; + } + + @Override + public boolean canComment(Change change) { + return myRequestFromChange.canCreateRequest(change); + } + + @Override + public Pair comment(Change change, ValueWithVcsException>> value) { final List> 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(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>> load(final Change change) { + return new ValueWithVcsException>>() { + @Override + protected List> computeImpl() throws VcsException { + return myRequestFromChange.createRequestForChange(change, 0); + } + }; + } } - private static class FragmentedDiffDetailsProvider implements Convertor> { + private abstract static class ValueWithVcsException extends TransparentlyFailedValue { + protected ValueWithVcsException() { + try { + set(computeImpl()); + } + catch (VcsException e) { + fail(e); + } + } + + protected abstract T computeImpl() throws VcsException; + } + + private static Pair noDifferences() { + return new Pair( + UIVcsUtil.errorPanel(DiffBundle.message("diff.contents.have.differences.only.in.line.separators.message.text"), false), null); + } + + private static class FragmentedDiffDetailsProvider implements VcsChangeDetailsProvider>>> { private final DiffRequestFromChange myRequestFromChange; private final Project myProject; private final LinkedList myDiffPanelCache; @@ -147,14 +243,33 @@ public class VcsChangeDetailsManager { } @Override - public Pair convert(Change o) { + public String getProgressTitle() { + return "Loading change content"; + } + + @Override + public boolean canComment(Change change) { + return myRequestFromChange.canCreateRequest(change); + } + + @Override + public ValueWithVcsException>> load(final Change change) { + return new ValueWithVcsException>>() { + @Override + protected List> computeImpl() throws VcsException { + return myRequestFromChange.createRequestForChange(change, extraLines); + } + }; + } + + @Override + public Pair comment(Change change, ValueWithVcsException>> value) { final List> 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( - 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(panel.getPanel(), panel); } - } private static String changeDescription(Change o) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsProvider.java new file mode 100644 index 000000000000..3170995c3d6e --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsProvider.java @@ -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 { + String getProgressTitle(); + @CalledInAwt + boolean canComment(final Change change); + @CalledInBackground + T load(final Change change); + @CalledInAwt + Pair comment(final Change change, final T t); +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java index d8a0b278810e..70257d4f2d06 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java @@ -29,6 +29,7 @@ import java.util.List; * Time: 6:39 PM */ public interface DiffRequestFromChange { + boolean canCreateRequest(final Change change); @Nullable List> createRequestForChange(final Change change, int extraLines) throws VcsException; } diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java b/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java index 470b7d3acedf..c9946bd0bace 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/GitLogUI.java @@ -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 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 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); } }