diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java index f23f72a3c633..8c6eb8d02d6b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java @@ -16,12 +16,10 @@ package com.intellij.openapi.vcs.changes; import com.intellij.diff.chains.DiffRequestProducerException; -import com.intellij.diff.impl.CacheDiffRequestProcessor; import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.requests.ErrorDiffRequest; import com.intellij.diff.requests.LoadingDiffRequest; import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -33,15 +31,10 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -public abstract class CacheChangeProcessor extends CacheDiffRequestProcessor { - private static final Logger LOG = Logger.getInstance(CacheChangeProcessor.class); +public abstract class CacheChangeProcessor extends CacheDiffRefreshableRequestProcessor { @Nullable private Change myCurrentChange; - public CacheChangeProcessor(@NotNull Project project) { - super(project); - } - public CacheChangeProcessor(@NotNull Project project, @NotNull String place) { super(project, place); } @@ -121,11 +114,14 @@ public abstract class CacheChangeProcessor extends CacheDiffRequestProcessor selectedChanges = getSelectedChanges(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheDiffRefreshableRequestProcessor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheDiffRefreshableRequestProcessor.java new file mode 100644 index 000000000000..e2e3548e541c --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheDiffRefreshableRequestProcessor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2017 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.diff.impl.CacheDiffRequestProcessor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.CalledInAwt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class CacheDiffRefreshableRequestProcessor extends CacheDiffRequestProcessor { + public CacheDiffRefreshableRequestProcessor(@Nullable Project project) { + super(project); + } + + public CacheDiffRefreshableRequestProcessor(@Nullable Project project, @NotNull String place) { + super(project, place); + } + + /** + * Notify currently shown diff that it's not needed now and cached values can be reset, a.e. before hiding preview panel + */ + @CalledInAwt + public abstract void clear(); + + /** + * Get newly requested element for diff and update/create new diff request for it + * a.e. get selection from some model and check if previously shown diff request need to be replaced or still valid for such selection + */ + @CalledInAwt + public abstract void refresh(); +} 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 06cdf881e9cf..fc0b3e000148 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 @@ -36,7 +36,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ProjectLevelVcsManager; @@ -48,7 +47,8 @@ import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.ui.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.DebugUtil; -import com.intellij.ui.*; +import com.intellij.ui.JBColor; +import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.content.Content; import com.intellij.util.Alarm; import com.intellij.util.FunctionUtil; @@ -72,6 +72,7 @@ import java.awt.event.KeyEvent; import java.util.Collection; import java.util.List; +import static com.intellij.util.ObjectUtils.assertNotNull; import static java.util.stream.Collectors.toList; @State( @@ -81,6 +82,7 @@ import static java.util.stream.Collectors.toList; public class ChangesViewManager implements ChangesViewI, ProjectComponent, PersistentStateComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.ChangesViewManager"); + public static final String CHANGES_VIEW_PREVIEW_SPLITTER_PROPORTION = "ChangesViewManager.DETAILS_SPLITTER_PROPORTION"; @NotNull private final ChangesListView myView; private JPanel myProgressLabel; @@ -95,16 +97,7 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi @NotNull private ChangesViewManager.State myState = new ChangesViewManager.State(); - private JBSplitter mySplitter; - - private boolean myDetailsOn; - @NotNull private final NotNullLazyValue myDiffDetails = new NotNullLazyValue() { - @NotNull - @Override - protected MyChangeProcessor compute() { - return new MyChangeProcessor(myProject); - } - }; + private PreviewDiffSplitterComponent mySplitterComponent; @NotNull private final TreeSelectionListener myTsl; private Content myContent; @@ -134,7 +127,7 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi LOG.debug(message); } } - SwingUtilities.invokeLater(() -> changeDetails()); + ApplicationManager.getApplication().invokeLater(() -> updatePreview()); } }; } @@ -157,9 +150,7 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi scheduleRefresh(); myProject.getMessageBus().connect().subscribe(RemoteRevisionsCache.REMOTE_VERSION_CHANGED, () -> ApplicationManager.getApplication().invokeLater(() -> refreshView(), ModalityState.NON_MODAL, myProject.getDisposed())); - - myDetailsOn = VcsConfiguration.getInstance(myProject).LOCAL_CHANGES_DETAILS_PREVIEW_SHOWN; - changeDetails(); + updatePreview(); } @Override @@ -219,13 +210,15 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi panel.setToolbar(toolbarPanel); final JPanel content = new JPanel(new BorderLayout()); - mySplitter = new JBSplitter(false, "ChangesViewManager.DETAILS_SPLITTER_PROPORTION", 0.5f); - mySplitter.setHonorComponentsMinimumSize(false); final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myView); final JPanel wrapper = new JPanel(new BorderLayout()); wrapper.add(scrollPane, BorderLayout.CENTER); - mySplitter.setFirstComponent(wrapper); - content.add(mySplitter, BorderLayout.CENTER); + MyChangeProcessor changeProcessor = new MyChangeProcessor(myProject); + mySplitterComponent = + new PreviewDiffSplitterComponent(wrapper, changeProcessor, CHANGES_VIEW_PREVIEW_SPLITTER_PROPORTION, + VcsConfiguration.getInstance(myProject).LOCAL_CHANGES_DETAILS_PREVIEW_SHOWN); + + content.add(mySplitterComponent, BorderLayout.CENTER); content.add(myProgressLabel, BorderLayout.SOUTH); panel.setContent(content); @@ -234,32 +227,6 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi return panel; } - private void changeDetails() { - if (!myDetailsOn) { - if (myDiffDetails.isComputed()) { - myDiffDetails.getValue().clear(); - - if (mySplitter.getSecondComponent() != null) { - setChangeDetailsPanel(null); - } - } - } - else { - myDiffDetails.getValue().refresh(); - - if (mySplitter.getSecondComponent() == null) { - setChangeDetailsPanel(myDiffDetails.getValue().getComponent()); - } - } - } - - private void setChangeDetailsPanel(@Nullable JComponent component) { - mySplitter.setSecondComponent(component); - mySplitter.getFirstComponent().setBorder(component == null ? null : IdeBorderFactory.createBorder(SideBorder.RIGHT)); - mySplitter.revalidate(); - mySplitter.repaint(); - } - @JdkConstants.InputEventMask private static int ctrlMask() { return SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK; @@ -330,7 +297,13 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi treeModelBuilder.build() ); - changeDetails(); + updatePreview(); + } + + private void updatePreview() { + if (mySplitterComponent != null) { + mySplitterComponent.updatePreview(); + } } @NotNull @@ -508,14 +481,19 @@ public class ChangesViewManager implements ChangesViewI, ProjectComponent, Persi @Override public boolean isSelected(AnActionEvent e) { - return myDetailsOn; + return assertNotNull(mySplitterComponent).isDetailsOn(); } @Override public void setSelected(AnActionEvent e, boolean state) { - myDetailsOn = state; - VcsConfiguration.getInstance(myProject).LOCAL_CHANGES_DETAILS_PREVIEW_SHOWN = myDetailsOn; - changeDetails(); + assertNotNull(mySplitterComponent).setDetailsOn(state); + VcsConfiguration.getInstance(myProject).LOCAL_CHANGES_DETAILS_PREVIEW_SHOWN = state; + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + e.getPresentation().setEnabled(mySplitterComponent != null); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreviewDiffSplitterComponent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreviewDiffSplitterComponent.java new file mode 100644 index 000000000000..fe5670c3840e --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PreviewDiffSplitterComponent.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2017 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.ui.IdeBorderFactory; +import com.intellij.ui.JBSplitter; +import com.intellij.ui.SideBorder; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class PreviewDiffSplitterComponent extends JBSplitter { + @NotNull private final JComponent myFirstComponent; + @NotNull private final CacheDiffRefreshableRequestProcessor myProcessor; + private boolean myDetailsOn; + + public PreviewDiffSplitterComponent(@NotNull JComponent firstComponent, + @NotNull CacheDiffRefreshableRequestProcessor processor, + @NotNull String splitterDimensionKey, boolean detailsOn) { + super(splitterDimensionKey, 0.5f); + myFirstComponent = firstComponent; + myProcessor = processor; + setHonorComponentsMinimumSize(false); + setFirstComponent(firstComponent); + setDetailsOn(detailsOn); + } + + public void updatePreview() { + if (isDetailsOn()) { + myProcessor.refresh(); + } + else { + myProcessor.clear(); + } + } + + private void updateVisibility() { + setSecondComponent(myDetailsOn ? myProcessor.getComponent() : null); + myFirstComponent.setBorder(myDetailsOn ? IdeBorderFactory.createBorder(SideBorder.RIGHT) : null); + revalidate(); + repaint(); + } + + + public boolean isDetailsOn() { + return myDetailsOn; + } + + public void setDetailsOn(boolean detailsOn) { + myDetailsOn = detailsOn; + updatePreview(); + if (myDetailsOn == (getSecondComponent() == null)) { + updateVisibility(); + } + } +}