From aaeeaf421fa875568c48bad464bff356f554dc8c Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 1 Oct 2014 17:10:04 +0400 Subject: [PATCH] [log] Rewrite filtering & migrate from GraphFacade to VisibleGraph New VcsLogFilterer to use SingleTaskController to make a single visible graph update even for multiple refresh/change filters/request more commits actions. Instead of delegating to the GraphFacade of the DataPack send the updated VisiblePack (containing the VisibleGraph and the reference to the actual DataPack) to the UI. Merge GraphTableModel with AbstractVcsLogTableModel; GraphCellRenderer with AbstractCellRenderer since there is only 1 implementation now. This fixes the following issues: IDEA-125278, IDEA-119054, IDEA-124822, IDEA-115917, IDEA-123885, IDEA-123426, IDEA-115486, IDEA-115479 --- .../util/containers/ContainerUtil.java | 38 +++ .../log/graph/ChangeCursorActionRequest.java | 33 -- .../vcs/log/graph/ClickGraphAction.java | 41 --- .../intellij/vcs/log/graph/GraphAction.java | 19 -- .../vcs/log/graph/GraphActionRequest.java | 24 -- .../intellij/vcs/log/graph/GraphAnswer.java | 40 --- .../intellij/vcs/log/graph/GraphChange.java | 24 -- .../intellij/vcs/log/graph/GraphFacade.java | 87 ------ .../vcs/log/graph/GraphInfoProvider.java | 43 --- .../JumpToNotLoadCommitActionRequest.java | 29 -- .../vcs/log/graph/JumpToRowActionRequest.java | 30 -- .../graph/LinearBranchesExpansionAction.java | 32 -- .../vcs/log/graph/LongEdgesAction.java | 37 --- .../vcs/log/graph/MouseOverAction.java | 41 --- .../com/intellij/vcs/log/graph/PaintInfo.java | 37 --- .../graph/SelectAllRelativeCommitsAction.java | 31 -- .../intellij/vcs/log/DelegateGraphFacade.java | 275 ----------------- .../vcs/log/data/CommitCountStage.java} | 24 +- .../com/intellij/vcs/log/data/DataGetter.java | 8 +- .../com/intellij/vcs/log/data/DataPack.java | 40 +-- .../intellij/vcs/log/data/EmptyDataPack.java | 2 +- .../vcs/log/data/EmptyGraphFacade.java | 109 ------- .../intellij/vcs/log/data/LoadMoreStage.java | 33 -- .../vcs/log/data/SingleTaskController.java | 10 +- .../vcs/log/data/VcsLogDataHolder.java | 97 ++---- .../intellij/vcs/log/data/VcsLogFilterer.java | 283 ++---------------- .../vcs/log/data/VcsLogFiltererImpl.java | 169 +++++++++++ .../intellij/vcs/log/data/VcsLogHashMap.java | 17 ++ .../intellij/vcs/log/data/VisiblePack.java | 67 +++++ .../vcs/log/data/VisiblePackBuilder.java | 228 ++++++++++++++ .../com/intellij/vcs/log/impl/VcsLogImpl.java | 6 +- .../intellij/vcs/log/impl/VcsLogManager.java | 23 +- .../com/intellij/vcs/log/impl/VcsLogUtil.java | 8 +- .../com/intellij/vcs/log/ui/VcsLogUiImpl.java | 193 +++++------- .../ui/filter/BranchFilterPopupComponent.java | 3 +- .../log/ui/filter/VcsLogClassicFilterUi.java | 5 +- .../vcs/log/ui/frame/DetailsPanel.java | 12 +- .../intellij/vcs/log/ui/frame/MainFrame.java | 8 +- .../vcs/log/ui/frame/VcsLogGraphTable.java | 109 ++++--- .../ui/render/AbstractPaddingCellRender.java | 147 --------- .../log/ui/render/GraphCommitCellRender.java | 209 +++++++++++-- .../ui/tables/AbstractVcsLogTableModel.java | 185 ------------ .../vcs/log/ui/tables/EmptyTableModel.java | 78 ----- .../vcs/log/ui/tables/GraphTableModel.java | 174 ++++++++--- .../vcs/log/data/VcsLogRefresherTest.java | 3 +- 45 files changed, 1090 insertions(+), 2021 deletions(-) delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java delete mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java delete mode 100644 platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java rename platform/vcs-log/{api/src/com/intellij/vcs/log/graph/BekGraphAction.java => impl/src/com/intellij/vcs/log/data/CommitCountStage.java} (62%) delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 35612c80f3d0..d61dc2424be3 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -2101,6 +2101,30 @@ public class ContainerUtil extends ContainerUtilRt { return -1; } + @Contract(pure=true) + public static int lastIndexOf(@NotNull List list, @NotNull Condition condition) { + for (int i = list.size() - 1; i >= 0; i--) { + T t = list.get(i); + if (condition.value(t)) { + return i; + } + } + return -1; + } + + @Nullable + @Contract(pure = true) + public static U findLastInstance(@NotNull List list, @NotNull final Class clazz) { + int i = lastIndexOf(list, new Condition() { + @Override + public boolean value(T t) { + return clazz.isInstance(t); + } + }); + //noinspection unchecked + return i < 0 ? null : (U)list.get(i); + } + @Contract(pure=true) public static int indexOf(@NotNull List list, @NotNull final T object) { return indexOf(list, new Condition() { @@ -2243,6 +2267,20 @@ public class ContainerUtil extends ContainerUtilRt { return ContainerUtilRt.map2Set(collection, mapper); } + @NotNull + @Contract(pure=true) + public static Set map2SetNotNull(@NotNull Collection collection, @NotNull Function mapper) { + if (collection.isEmpty()) return Collections.emptySet(); + Set set = new HashSet(collection.size()); + for (T t : collection) { + V value = mapper.fun(t); + if (value != null) { + set.add(value); + } + } + return set.isEmpty() ? Collections.emptySet() : set; + } + @NotNull @Contract(pure=true) public static T[] toArray(@NotNull List collection, @NotNull T[] array) { diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java deleted file mode 100644 index ec7908295875..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public class ChangeCursorActionRequest implements GraphActionRequest { - @NotNull private final Cursor myCursor; - - public ChangeCursorActionRequest(@NotNull Cursor cursor) { - myCursor = cursor; - } - - @NotNull - public Cursor getCursor() { - return myCursor; - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java deleted file mode 100644 index fc037f701855..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import org.jetbrains.annotations.Nullable; - -import java.awt.*; - -public class ClickGraphAction implements GraphAction { - - private final int myVisibleRow; - @Nullable private final Point myRelativePoint; - - public ClickGraphAction(int visibleRow, @Nullable Point relativePoint) { - myVisibleRow = visibleRow; - myRelativePoint = relativePoint; - } - - public int getRow() { - return myVisibleRow; - } - - @Nullable - public Point getRelativePoint() { - return myRelativePoint; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java deleted file mode 100644 index a08aaaf928c7..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -public interface GraphAction { -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java deleted file mode 100644 index a963da2a5ae5..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -/** - * Action which should be executed by the code which called {@link GraphFacade#performAction(com.intellij.vcs.log.graph.GraphAction)}. - * E.g. when user clicks to the arrow to go to the parent/child commit, the table should jump to concrete row. - */ -public interface GraphActionRequest { - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java deleted file mode 100644 index 57c985155e89..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import org.jetbrains.annotations.Nullable; - -/** - * The graph returns an instance of the GraphAnswer as a reaction to {@link #performAction(com.intellij.vcs.log.graph.GraphAction)}. - */ -public interface GraphAnswer { - - /** - * Tells how graph was changed after performing action
- * {@code null} means that graph didn't change (e.g. when user clicks on the arrow to go to the parent/child commit). - */ - @Nullable - GraphChange getGraphChange(); - - /** - * Tells which action should be execute by the client code.
- * {@code null} means that the graph doesn't expect the client code to execute anything special - * (although of course it can react somehow on the returned {@link #getGraphChange() GraphChange}. - */ - @Nullable - GraphActionRequest getActionRequest(); - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java deleted file mode 100644 index 41cdaa1f14a6..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -/** - * Describes how graph was changed after {@link GraphFacade#performAction(GraphAction) executing some action on it} - * (e.g. a linear branch was collapsed). - */ -public interface GraphChange { - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java deleted file mode 100644 index b48e70266f50..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import com.intellij.openapi.util.Condition; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.List; - -/** - * The only point of interaction with the Graph. - *

- * Any access to the methods of this class must be performed from the EDT. - */ -public interface GraphFacade { - - /** - * Paints the given row. - */ - @NotNull - PaintInfo paint(int visibleRow); - - /** - * Performs some user action on the graph, which can be a click, hover, drag, changing view parameters, etc.
- * Changes are applied to the graph immediately, and the method returns the result of such action.
- * In some cases the action might take significant time (say, 1 second) - clients of this method take care of it themselves: by showing - * some modal progress or else. - */ - @Nullable - GraphAnswer performAction(@NotNull GraphAction action); - - /** - * Returns all commits in the graph without considering commits visibility. - * To get visible commits use {@link #getVisibleCommitCount} & {@link #getCommitAtRow}. - */ - @NotNull - List> getAllCommits(); - - /** - * A shorthand to getVisibleCommits().get(visibleRow), but may be faster. - */ - int getCommitAtRow(int visibleRow); - - /** - * A shorthand to {@code getVisibleCommits().size()}, but is faster. - */ - int getVisibleCommitCount(); - - /** - * Set branches which should be visible in the log, all others will be hidden. - * Pass {@code null} to show all branches, i.e. reset this branch filter. - * - * @param heads branches represented by commit indices of commits they point to; or {@code null} if all branches should be shown. - * @see #setFilter(Condition) - */ - void setVisibleBranches(@Nullable Collection heads); - - /** - * Set filter to the commits displayed by the log. - * - * @param visibilityPredicate check if the given commit should be shown or not. null means no filter. - * @see #setVisibleBranches(Collection) - */ - void setFilter(@Nullable Condition visibilityPredicate); - - /** - * Returns the provider of some information about the graph. - */ - @NotNull - GraphInfoProvider getInfoProvider(); - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java deleted file mode 100644 index 308a4c6ec0c8..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -/** - * Use this provider to get information from the Graph.
- * An instance of GraphInfoProvider is obtained via {@link GraphFacade#getInfoProvider()}. - */ -public interface GraphInfoProvider { - - @NotNull - Set getContainingBranches(int visibleRow); // this requires graph iteration => can take some time - - @NotNull - RowInfo getRowInfo(int visibleRow); - - boolean areLongEdgesHidden(); - - /** - * Some information about row highlighting etc. TBD - */ - interface RowInfo { - int getOneOfHeads(); - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java deleted file mode 100644 index c4348f3e6b1c..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -public class JumpToNotLoadCommitActionRequest implements GraphActionRequest { - private final int commitHashIndex; - - public JumpToNotLoadCommitActionRequest(int commitHashIndex) { - this.commitHashIndex = commitHashIndex; - } - - public int getCommitHashIndex() { - return commitHashIndex; - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java deleted file mode 100644 index 5b2518b26f8a..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -public class JumpToRowActionRequest implements GraphActionRequest { - - private final int myRow; - - public JumpToRowActionRequest(int row) { - myRow = row; - } - - public int getRow() { - return myRow; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java deleted file mode 100644 index dbfd046cf0b6..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -public class LinearBranchesExpansionAction implements GraphAction { - - public static LinearBranchesExpansionAction EXPAND = new LinearBranchesExpansionAction(true); - public static LinearBranchesExpansionAction COLLAPSE = new LinearBranchesExpansionAction(false); - - private final boolean myExpand; - - private LinearBranchesExpansionAction(boolean expand) { - myExpand = expand; - } - - public boolean shouldExpand() { - return myExpand; - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java deleted file mode 100644 index 4824f0b13c65..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -public class LongEdgesAction implements GraphAction { - - private static LongEdgesAction SHOW = new LongEdgesAction(true); - private static LongEdgesAction HIDE = new LongEdgesAction(false); - - private final boolean myShowLongEdges; - - public static LongEdgesAction valueOf(boolean showLongEdges) { - return showLongEdges ? SHOW : HIDE; - } - - private LongEdgesAction(boolean show) { - myShowLongEdges = show; - } - - public boolean shouldShowLongEdges() { - return myShowLongEdges; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java deleted file mode 100644 index ca619c6e55f3..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public class MouseOverAction implements GraphAction { - - private final int myVisibleRow; - @NotNull private final Point myRelativePoint; - - public MouseOverAction(int visibleRow, @NotNull Point relativePoint) { - myVisibleRow = visibleRow; - myRelativePoint = relativePoint; - } - - public int getRow() { - return myVisibleRow; - } - - @NotNull - public Point getRelativePoint() { - return myRelativePoint; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java deleted file mode 100644 index 42e56042756e..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public interface PaintInfo { - - /** - * Returns the image to actually paint. - */ - @NotNull - Image getImage(); - - /** - * Returns the "interesting" width of the painted image, i.e. the width which the text in the table should be offset by.
- * It can be smaller than the width of {@link #getImage() the image}, because we allow the text to cover part of the graph - * (some diagonal edges, etc.) - */ - int getWidth(); - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java deleted file mode 100644 index f35d226692c4..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.graph; - -public class SelectAllRelativeCommitsAction implements GraphAction { - public static final SelectAllRelativeCommitsAction DESELECT_ALL = new SelectAllRelativeCommitsAction(-1); - - private final int visibleRowIndex; - - public SelectAllRelativeCommitsAction(int visibleRowIndex) { - this.visibleRowIndex = visibleRowIndex; - } - - public int getVisibleRowIndex() { - return visibleRowIndex; - } -} diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java deleted file mode 100644 index 7e723580afaf..000000000000 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log; - -import com.intellij.openapi.util.Condition; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.graph.*; -import com.intellij.vcs.log.graph.actions.ActionController; -import com.intellij.vcs.log.graph.actions.GraphMouseAction; -import com.intellij.vcs.log.printer.idea.ColorGenerator; -import com.intellij.vcs.log.printer.idea.GraphCellPainter; -import com.intellij.vcs.log.printer.idea.PrintParameters; -import com.intellij.vcs.log.printer.idea.SimpleGraphCellPainter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class DelegateGraphFacade implements GraphFacade { - @NotNull - public static final GraphAnswer JUMP_TO_0_GRAPH_ANSWER = new GraphAnswer() { - @Nullable - @Override - public GraphChange getGraphChange() { - return new GraphChange() { - }; - } - - @Nullable - @Override - public GraphActionRequest getActionRequest() { - return new JumpToRowActionRequest(0); - } - }; - - @NotNull - private final PermanentGraph myPermanentGraph; - private final GraphCellPainter myGraphCellPainter; - - @NotNull - private PermanentGraph.SortType mySortType = PermanentGraph.SortType.Normal; - - @NotNull - private VisibleGraph myVisibleGraph; - - @Nullable - private Set myHeads = null; - - @Nullable - private Condition myVisibilityPredicate = null; - - public DelegateGraphFacade(@NotNull PermanentGraph permanentGraph, @NotNull ColorGenerator colorGenerator) { - myPermanentGraph = permanentGraph; - myGraphCellPainter = new SimpleGraphCellPainter(colorGenerator); - updateVisibleGraph(); - } - - private void updateVisibleGraph() { - myVisibleGraph = myPermanentGraph.createVisibleGraph(mySortType, myHeads, myVisibilityPredicate); - } - - @NotNull - @Override - public PaintInfo paint(int visibleRow) { - Collection printElements = myVisibleGraph.getRowInfo(visibleRow).getPrintElements(); - int maxIndex = 0; - for (PrintElement printElement : printElements) { - maxIndex = Math.max(maxIndex, printElement.getPositionInCurrentRow()); - } - maxIndex++; - final BufferedImage image = - UIUtil.createImage(PrintParameters.WIDTH_NODE * (maxIndex + 4), PrintParameters.HEIGHT_CELL, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2 = image.createGraphics(); - myGraphCellPainter.draw(g2, printElements); - - final int width = maxIndex * PrintParameters.WIDTH_NODE; - return new PaintInfo() { - @NotNull - @Override - public Image getImage() { - return image; - } - - @Override - public int getWidth() { - return width; - } - }; - } - - @Nullable - @Override - public GraphAnswer performAction(@NotNull GraphAction action) { - ActionController actionController = myVisibleGraph.getActionController(); - if (action instanceof ClickGraphAction) { - ClickGraphAction clickGraphAction = (ClickGraphAction)action; - Point relativePoint = clickGraphAction.getRelativePoint(); - PrintElement printElement = null; - if (relativePoint != null) { - Collection printElements = myVisibleGraph.getRowInfo(clickGraphAction.getRow()).getPrintElements(); - printElement = myGraphCellPainter.mouseOver(printElements, relativePoint.x, relativePoint.y); - } - return convert(actionController.performMouseAction(new GraphMouseActionImpl(printElement, GraphMouseAction.Type.CLICK))); - } - - if (action instanceof MouseOverAction) { - MouseOverAction mouseOverAction = (MouseOverAction)action; - Point relativePoint = mouseOverAction.getRelativePoint(); - Collection printElements = myVisibleGraph.getRowInfo(mouseOverAction.getRow()).getPrintElements(); - PrintElement printElement = myGraphCellPainter.mouseOver(printElements, relativePoint.x, relativePoint.y); - - return convert(actionController.performMouseAction(new GraphMouseActionImpl(printElement, GraphMouseAction.Type.OVER))); - } - - if (action instanceof LongEdgesAction) { - boolean shouldShowLongEdges = ((LongEdgesAction)action).shouldShowLongEdges(); - actionController.setLongEdgesHidden(!shouldShowLongEdges); - } - - if (action instanceof LinearBranchesExpansionAction) { - boolean shouldExpand = ((LinearBranchesExpansionAction)action).shouldExpand(); - actionController.setLinearBranchesExpansion(!shouldExpand); - return JUMP_TO_0_GRAPH_ANSWER; - } - - if (action instanceof BekGraphAction) { - mySortType = ((BekGraphAction)action).getSortType(); - updateVisibleGraph(); - return JUMP_TO_0_GRAPH_ANSWER; - } - - return null; - } - - @NotNull - private GraphAnswer convert(@NotNull com.intellij.vcs.log.graph.actions.GraphAnswer graphAnswer) { - final Integer commitToJump = graphAnswer.getCommitToJump(); - final Cursor cursorToSet = graphAnswer.getCursorToSet(); - return new GraphAnswer() { - @Nullable - @Override - public GraphChange getGraphChange() { - if (commitToJump != null) { - return new GraphChange() {}; - } - return null; - } - - @Nullable - @Override - public GraphActionRequest getActionRequest() { - if (cursorToSet != null) - return new ChangeCursorActionRequest(cursorToSet); - if (commitToJump != null) { - int visibleRowIndex = myVisibleGraph.getVisibleRowIndex(commitToJump); - if (visibleRowIndex == -1) - return new JumpToNotLoadCommitActionRequest(commitToJump); - return new JumpToRowActionRequest(visibleRowIndex); - } - return null; - } - }; - } - - @NotNull - @Override - public List> getAllCommits() { - return myPermanentGraph.getAllCommits(); - } - - @Override - public int getCommitAtRow(int visibleRow) { - return myVisibleGraph.getRowInfo(visibleRow).getCommit(); - } - - @Override - public int getVisibleCommitCount() { - return myVisibleGraph.getVisibleCommitCount(); - } - - @Override - public void setVisibleBranches(@Nullable Collection heads) { - boolean needUpdate; - if (heads == null) { - needUpdate = myHeads != null; - myHeads = null; - } else { - needUpdate = true; - myHeads = new HashSet(heads); - } - if (needUpdate) - updateVisibleGraph(); - } - - @Override - public void setFilter(@Nullable Condition visibilityPredicate) { - boolean needUpdate = !(visibilityPredicate == myVisibilityPredicate); - - myVisibilityPredicate = visibilityPredicate; - if (needUpdate) - updateVisibleGraph(); - } - - @NotNull - @Override - public GraphInfoProvider getInfoProvider() { - return new GraphInfoProvider() { - @NotNull - @Override - public Set getContainingBranches(int visibleRow) { - return myPermanentGraph.getContainingBranches(getCommitAtRow(visibleRow)); - } - - @NotNull - @Override - public RowInfo getRowInfo(int visibleRow) { - final Integer oneOfHeads = myVisibleGraph.getRowInfo(visibleRow).getOneOfHeads(); - return new RowInfo() { - @Override - public int getOneOfHeads() { - return oneOfHeads; - } - }; - } - - @Override - public boolean areLongEdgesHidden() { - return myVisibleGraph.getActionController().areLongEdgesHidden(); - } - }; - } - - private static class GraphMouseActionImpl implements GraphMouseAction { - @Nullable - private final PrintElement myAffectedElement; - @NotNull - private final Type myType; - - private GraphMouseActionImpl(@Nullable PrintElement affectedElement, @NotNull Type type) { - myAffectedElement = affectedElement; - myType = type; - } - - @Nullable - @Override - public PrintElement getAffectedElement() { - return myAffectedElement; - } - - @NotNull - @Override - public Type getType() { - return myType; - } - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/BekGraphAction.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CommitCountStage.java similarity index 62% rename from platform/vcs-log/api/src/com/intellij/vcs/log/graph/BekGraphAction.java rename to platform/vcs-log/impl/src/com/intellij/vcs/log/data/CommitCountStage.java index 1deb51f6632b..574a098a1e90 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/BekGraphAction.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CommitCountStage.java @@ -13,21 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.vcs.log.graph; +package com.intellij.vcs.log.data; import org.jetbrains.annotations.NotNull; -public class BekGraphAction implements GraphAction { +enum CommitCountStage { - @NotNull - private final PermanentGraph.SortType mySortType; + INITIAL(5), + FIRST_STEP(2000), + ALL(Integer.MAX_VALUE); - public BekGraphAction(@NotNull PermanentGraph.SortType sortType) { - mySortType = sortType; + private final int myCount; + + CommitCountStage(int count) { + myCount = count; } @NotNull - public PermanentGraph.SortType getSortType() { - return mySortType; + CommitCountStage next() { + CommitCountStage[] values = values(); + return ordinal() == values.length - 1 ? this : values[ordinal() + 1]; + } + + public int getCount() { + return myCount; } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java index c31db3894f53..532073437f28 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java @@ -12,7 +12,7 @@ import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogProvider; import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import com.intellij.vcs.log.util.SequentialLimitedLifoExecutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -81,7 +81,7 @@ public abstract class DataGetter implements Dis } @Nullable - public T getCommitData(int row, @NotNull AbstractVcsLogTableModel tableModel) { + public T getCommitData(int row, @NotNull GraphTableModel tableModel) { assert EventQueue.isDispatchThread(); Hash hash = tableModel.getHashAtRow(row); if (hash == null) { @@ -122,7 +122,7 @@ public abstract class DataGetter implements Dis @Nullable protected abstract T getFromAdditionalCache(@NotNull Hash hash); - private void runLoadAroundCommitData(int row, @NotNull AbstractVcsLogTableModel tableModel) { + private void runLoadAroundCommitData(int row, @NotNull GraphTableModel tableModel) { long taskNumber = myCurrentTaskIndex++; MultiMap commits = getCommitsAround(row, tableModel, UP_PRELOAD_COUNT, DOWN_PRELOAD_COUNT); for (Map.Entry> hashesByRoots : commits.entrySet()) { @@ -143,7 +143,7 @@ public abstract class DataGetter implements Dis } @NotNull - private static MultiMap getCommitsAround(int selectedRow, @NotNull AbstractVcsLogTableModel model, + private static MultiMap getCommitsAround(int selectedRow, @NotNull GraphTableModel model, int above, int below) { MultiMap commits = MultiMap.create(); for (int row = Math.max(0, selectedRow - above); row < selectedRow + below && row < model.getRowCount(); row++) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java index 975808611ed4..c884649c0820 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java @@ -6,22 +6,18 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.graph.GraphColorManagerImpl; import com.intellij.vcs.log.graph.GraphCommit; -import com.intellij.vcs.log.graph.GraphFacade; import com.intellij.vcs.log.graph.PermanentGraph; import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl; -import com.intellij.vcs.log.printer.idea.ColorGenerator; import com.intellij.vcs.log.util.StopWatch; import org.jetbrains.annotations.NotNull; -import java.awt.*; import java.util.*; import java.util.List; -public class DataPack implements VcsLogDataPack { +public class DataPack { @NotNull private final RefsModel myRefsModel; @NotNull private final PermanentGraph myPermanentGraph; - @NotNull private final GraphFacade myGraphFacade; @NotNull private final Map myLogProviders; private boolean myFull; @@ -33,25 +29,7 @@ public class DataPack implements VcsLogDataPack { boolean full) { RefsModel refsModel = new RefsModel(refs, hashMap.asIndexGetter()); PermanentGraph graph = buildPermanentGraph(commits, refsModel, hashMap.asIndexGetter(), hashMap.asHashGetter(), providers); - return new DataPack(refsModel, graph, createGraphFacade(graph), providers, full); - } - - @NotNull - private static GraphFacade createGraphFacade(@NotNull PermanentGraph permanentGraph) { - GraphFacade facade; - if (!permanentGraph.getAllCommits().isEmpty()) { - ColorGenerator colorGenerator = new ColorGenerator() { - @Override - public Color getColor(int colorId) { - return com.intellij.vcs.log.graph.ColorGenerator.getColor(colorId); - } - }; - facade = new DelegateGraphFacade(permanentGraph, colorGenerator); - } - else { - facade = new EmptyGraphFacade(); - } - return facade; + return new DataPack(refsModel, graph, providers, full); } @NotNull @@ -91,22 +69,17 @@ public class DataPack implements VcsLogDataPack { return map; } - DataPack(@NotNull RefsModel refsModel, @NotNull PermanentGraph permanentGraph, @NotNull GraphFacade graphFacade, - @NotNull Map providers, boolean full) { + DataPack(@NotNull RefsModel refsModel, + @NotNull PermanentGraph permanentGraph, + @NotNull Map providers, + boolean full) { myRefsModel = refsModel; myPermanentGraph = permanentGraph; - myGraphFacade = graphFacade; myLogProviders = providers; myFull = full; } @NotNull - public GraphFacade getGraphFacade() { - return myGraphFacade; - } - - @NotNull - @Override public VcsLogRefs getRefs() { return myRefsModel; } @@ -117,7 +90,6 @@ public class DataPack implements VcsLogDataPack { } @NotNull - @Override public Map getLogProviders() { return myLogProviders; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java index 54140afb3940..66a9cadd6745 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java @@ -30,7 +30,7 @@ public class EmptyDataPack { @NotNull public static DataPack getInstance() { RefsModel emptyModel = new RefsModel(Collections.>emptyMap(), new ConstantFunction(0)); - return new DataPack(emptyModel, EmptyPermanentGraph.getInstance(), new EmptyGraphFacade(), Collections.emptyMap(), false); + return new DataPack(emptyModel, EmptyPermanentGraph.getInstance(), Collections.emptyMap(), false); } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java deleted file mode 100644 index cf52495938bf..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.data; - -import com.intellij.openapi.util.Condition; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.graph.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -class EmptyGraphFacade implements GraphFacade { - - public static final BufferedImage EMPTY_IMAGE = UIUtil.createImage(1, 1, Transparency.TRANSLUCENT); - - @NotNull - @Override - public PaintInfo paint(int visibleRow) { - return new PaintInfo() { - @NotNull - @Override - public Image getImage() { - return EMPTY_IMAGE; - } - - @Override - public int getWidth() { - return 0; - } - }; - } - - @Nullable - @Override - public GraphAnswer performAction(@NotNull GraphAction action) { - return null; - } - - @NotNull - @Override - public List> getAllCommits() { - return Collections.emptyList(); - } - - @Override - public int getCommitAtRow(int visibleRow) { - return -1; - } - - @Override - public int getVisibleCommitCount() { - return 0; - } - - @Override - public void setVisibleBranches(@Nullable Collection heads) { - } - - @Override - public void setFilter(@Nullable Condition visibilityPredicate) { - } - - @NotNull - @Override - public GraphInfoProvider getInfoProvider() { - return new GraphInfoProvider() { - @NotNull - @Override - public Set getContainingBranches(int visibleRow) { - return Collections.emptySet(); - } - - @NotNull - @Override - public RowInfo getRowInfo(int visibleRow) { - return new RowInfo() { - @Override - public int getOneOfHeads() { - return -1; - } - }; - } - - @Override - public boolean areLongEdgesHidden() { - return false; - } - }; - } -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java deleted file mode 100644 index 1ca383ccbe1c..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2000-2013 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.vcs.log.data; - -public enum LoadMoreStage { - /** - * Initial table view; "load more" was not requested yet. - */ - INITIAL, - - /** - * "Load more" was once requested with a limited number of commits. - */ - LOADED_MORE, - - /** - * All commits matching the given filters were requested from the VCS, requesting more won't cause any effect. - */ - ALL_REQUESTED -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java index 24b2d2e2f3a8..7d535982cfd0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java @@ -18,6 +18,7 @@ package com.intellij.vcs.log.data; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -82,10 +83,13 @@ public abstract class SingleTaskController { /** * The underlying currently active task should use this method to inform that it has completed the execution.
- * The result is immediately passed to the result handler specified in the constructor. + * If the result is not null, it is immediately passed to the result handler specified in the constructor. + * Otherwise result handler is not called, the task just completes. */ - protected final void taskCompleted(@NotNull Result result) { - myResultHandler.consume(result); + protected final void taskCompleted(@Nullable Result result) { + if (result != null) { + myResultHandler.consume(result); + } synchronized (LOCK) { if (myAwaitingRequests.isEmpty()) { myActive = false; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java index 91385926cd93..80d351204cba 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java @@ -22,7 +22,6 @@ 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.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; @@ -30,8 +29,8 @@ import com.intellij.util.Consumer; import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.Topic; -import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.*; +import com.intellij.vcs.log.graph.PermanentGraph; import com.intellij.vcs.log.util.StopWatch; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,13 +60,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { private final Map myCurrentUser = ContainerUtil.newHashMap(); private final Consumer myDataPackUpdateHandler; - /** - * Indicates if user wants the whole log graph to be shown. - * Initially we show only the top of the log (even after we've loaded the whole log structure) for performance reasons. - * However, if user once navigates to some old commit, we build the whole graph and show it until the next full refresh or project reload. - */ - private volatile boolean myFullLogShowing; - /** * Cached details of the latest commits. * We store them separately from the cache of {@link DataGetter}, to make sure that they are always available, @@ -82,11 +74,14 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { private final ContainingBranchesGetter myContainingBranchesGetter; @NotNull private final VcsLogRefresher myRefresher; + private final VcsLogFiltererImpl myFilterer; public VcsLogDataHolder(@NotNull Project project, @NotNull Disposable parentDisposable, @NotNull Map logProviders, - @NotNull VcsLogSettings settings, Consumer dataPackUpdateHandler) { + @NotNull VcsLogSettings settings, + @NotNull VcsLogUiProperties uiProperties, + @NotNull Consumer visiblePackConsumer) { Disposer.register(parentDisposable, this); myProject = project; myLogProviders = logProviders; @@ -94,7 +89,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { myMiniDetailsGetter = new MiniDetailsGetter(this, logProviders); myDetailsGetter = new CommitDetailsGetter(this, logProviders); mySettings = settings; - myDataPackUpdateHandler = dataPackUpdateHandler; myUserRegistry = (VcsUserRegistryImpl)ServiceManager.getService(project, VcsUserRegistry.class); try { @@ -105,8 +99,20 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { } myContainingBranchesGetter = new ContainingBranchesGetter(project, this, this); + myFilterer = new VcsLogFiltererImpl(myProject, myLogProviders, myHashMap, myTopCommitsDetailsCache, myDetailsGetter, + uiProperties.isBek() ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal, + visiblePackConsumer); + + myDataPackUpdateHandler = new Consumer() { + @Override + public void consume(DataPack dataPack) { + myFilterer.onRefresh(dataPack); + myProject.getMessageBus().syncPublisher(REFRESH_COMPLETED).refresh(dataPack); + } + }; + myRefresher = new VcsLogRefresherImpl(myProject, myHashMap, myLogProviders, myUserRegistry, myTopCommitsDetailsCache, - dataPackUpdateHandler, new Consumer() { + myDataPackUpdateHandler, new Consumer() { @Override public void consume(Exception e) { LOG.error(e); @@ -114,6 +120,11 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { }, mySettings.getRecentCommitsCount()); } + @NotNull + public VcsLogFilterer getFilterer() { + return myFilterer; + } + @Override @NotNull public Hash getHash(int commitIndex) { @@ -167,54 +178,9 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { } private void resetState() { - myFullLogShowing = false; myTopCommitsDetailsCache.clear(); } - /** - * Show the full log tree to the user. - * Initially only the top part of the log is shown to avoid memory and performance problems. - * However, if user wants to navigate to something in the past, we rebuild the log and show it. - *

- * Method returns immediately, log building is executed in the background. - *

- * TODO: in most cases, users don't need to go to such deep past even if they need to go deeper than to 1000 most recent commits. - * Therefore optimize: Add a hash parameter, and build only the necessary part of the log + some commits below. - * - * @param onSuccess Invoked in the EDT after the log DataPack is built. - */ - public void showFullLog(@NotNull final Runnable onSuccess) { - if (myFullLogShowing) { - return; - } - - runInBackground(new ThrowableConsumer() { - @Override - public void consume(ProgressIndicator indicator) throws VcsException { - if (myFullLogShowing) { - return; - } - - // TODO - - myFullLogShowing = true; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - if (!Disposer.isDisposed(VcsLogDataHolder.this)) { - onSuccess.run(); - } - } - }); - } - }, "Building full log..."); - } - - - public boolean isFullLogShowing() { - return myFullLogShowing; - } - @NotNull public Set getAllUsers() { return myUserRegistry.getUsers(); @@ -253,23 +219,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { return myContainingBranchesGetter; } - @Nullable - public Hash findHashByString(@NotNull String string) { - final String pHash = string.toLowerCase(); - try { - return myHashMap.findHash(new Condition() { - @Override - public boolean value(@NotNull Hash hash) { - return hash.toString().toLowerCase().startsWith(pHash); - } - }); - } - catch (IOException e) { - LOG.error(e); - return null; - } - } - void runInBackground(final ThrowableConsumer task, final String title) { myDataLoaderQueue.run(new Task.Backgroundable(myProject, title) { @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java index f0bf75c08dcf..e1e5f9411bbe 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java @@ -1,269 +1,34 @@ +/* + * Copyright 2000-2014 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.vcs.log.data; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; -import com.intellij.util.Function; -import com.intellij.util.ThrowableConsumer; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashSet; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.*; -import com.intellij.vcs.log.graph.GraphFacade; -import com.intellij.vcs.log.impl.VcsLogUtil; -import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; -import com.intellij.vcs.log.ui.tables.EmptyTableModel; -import com.intellij.vcs.log.ui.tables.GraphTableModel; -import gnu.trove.TIntHashSet; +import com.intellij.vcs.log.VcsLogFilterCollection; +import com.intellij.vcs.log.graph.PermanentGraph; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +/** + */ +public interface VcsLogFilterer { -public class VcsLogFilterer { + void onRefresh(@NotNull DataPack dataPack); - private static final Logger LOG = Logger.getInstance(VcsLogFilterer.class); + void onFiltersChange(@NotNull VcsLogFilterCollection filters); - private static final int LOAD_MORE_COMMITS_FIRST_STEP_LIMIT = 2000; + void onSortTypeChange(@NotNull PermanentGraph.SortType sortType); - @NotNull private final VcsLogDataHolder myLogDataHolder; - @NotNull private final VcsLogUiImpl myUI; - - public VcsLogFilterer(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiImpl ui) { - myLogDataHolder = logDataHolder; - myUI = ui; - } - - @NotNull - public AbstractVcsLogTableModel applyFiltersAndUpdateUi(@NotNull DataPack dataPack, @NotNull VcsLogFilterCollection filters) { - resetFilters(dataPack); - VcsLogHashFilter hashFilter = filters.getHashFilter(); - if (hashFilter != null && !hashFilter.getHashes().isEmpty()) { // hashes should be shown, no matter if they match other filters or not - return applyHashFilter(dataPack, hashFilter.getHashes()); - } - List detailsFilters = filters.getDetailsFilters(); - applyGraphFilters(dataPack, filters.getBranchFilter()); - return applyDetailsFilter(dataPack, detailsFilters); - } - - private GraphTableModel applyHashFilter(@NotNull DataPack dataPack, @NotNull Collection hashes) { - final List indices = ContainerUtil.mapNotNull(hashes, new Function() { - @Override - public Integer fun(String partOfHash) { - Hash hash = myLogDataHolder.findHashByString(partOfHash); - return hash != null ? myLogDataHolder.getCommitIndex(hash) : null; - } - }); - dataPack.getGraphFacade().setVisibleBranches(null); - dataPack.getGraphFacade().setFilter(new Condition() { - @Override - public boolean value(Integer integer) { - return indices.contains(integer); - } - }); - return new GraphTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.ALL_REQUESTED); - } - - private static void resetFilters(@NotNull DataPack dataPack) { - GraphFacade facade = dataPack.getGraphFacade(); - facade.setVisibleBranches(null); - facade.setFilter(null); - } - - private AbstractVcsLogTableModel applyDetailsFilter(DataPack dataPack, List detailsFilters) { - if (!detailsFilters.isEmpty()) { - List filteredCommits = filterInMemory(dataPack, detailsFilters); - if (filteredCommits.isEmpty()) { - return new EmptyTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.INITIAL); - } - else{ - Condition filter = getFilterFromCommits(filteredCommits); - dataPack.getGraphFacade().setFilter(filter); - } - } - else { - dataPack.getGraphFacade().setFilter(null); - } - return new GraphTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.INITIAL); - } - - private Condition getFilterFromCommits(List filteredCommits) { - final Set commitSet = ContainerUtil.map2Set(filteredCommits, new Function() { - @Override - public Integer fun(Hash hash) { - return myLogDataHolder.getCommitIndex(hash); - } - }); - return new Condition() { - @Override - public boolean value(Integer integer) { - return commitSet.contains(integer); - } - }; - } - - public void requestVcs(@NotNull final DataPack dataPack, @NotNull VcsLogFilterCollection filters, - @NotNull final LoadMoreStage loadMoreStage, @NotNull final Runnable onSuccess) { - ApplicationManager.getApplication().assertIsDispatchThread(); - int maxCount = loadMoreStage == LoadMoreStage.INITIAL ? LOAD_MORE_COMMITS_FIRST_STEP_LIMIT : -1; - getFilteredDetailsFromTheVcs(dataPack.getLogProviders(), filters, new Consumer>() { - @Override - public void consume(List hashes) { - LoadMoreStage newLoadMoreStage = advanceLoadMoreStage(loadMoreStage); - TIntHashSet previouslySelected = myUI.getSelectedCommits(); - AbstractVcsLogTableModel model; - if (hashes.isEmpty()) { - model = new EmptyTableModel(dataPack, myLogDataHolder, myUI, newLoadMoreStage); - } - else { - dataPack.getGraphFacade().setFilter(getFilterFromCommits(hashes)); - model = new GraphTableModel(dataPack, myLogDataHolder, myUI, newLoadMoreStage); - } - myUI.setModel(model, dataPack, previouslySelected); - myUI.repaintUI(); - onSuccess.run(); - } - }, maxCount); - } - - @NotNull - private static LoadMoreStage advanceLoadMoreStage(@NotNull LoadMoreStage loadMoreStage) { - LoadMoreStage newLoadMoreStage; - if (loadMoreStage == LoadMoreStage.INITIAL) { - newLoadMoreStage = LoadMoreStage.LOADED_MORE; - } - else if (loadMoreStage == LoadMoreStage.LOADED_MORE) { - newLoadMoreStage = LoadMoreStage.ALL_REQUESTED; - } - else { - LOG.warn("Incorrect previous load more stage: " + loadMoreStage); - newLoadMoreStage = LoadMoreStage.ALL_REQUESTED; - } - return newLoadMoreStage; - } - - private void applyGraphFilters(@NotNull final DataPack dataPack, @Nullable final VcsLogBranchFilter branchFilter) { - try { - dataPack.getGraphFacade().setVisibleBranches(branchFilter != null ? getMatchingHeads(dataPack, branchFilter) : null); - } - catch (InvalidRequestException e) { - if (!myLogDataHolder.isFullLogShowing()) { - myLogDataHolder.showFullLog(EmptyRunnable.getInstance()); - throw new ProcessCanceledException(); - } - else { - throw e; - } - } - } - - @NotNull - private Collection getMatchingHeads(@NotNull DataPack dataPack, @NotNull VcsLogBranchFilter branchFilter) { - final Collection branchNames = new HashSet(branchFilter.getBranchNames()); - return ContainerUtil.mapNotNull(dataPack.getRefsModel().getAllRefs(), new Function() { - @Override - public Integer fun(VcsRef ref) { - if (branchNames.contains(ref.getName())) { - return myLogDataHolder.getCommitIndex(ref.getCommitHash()); - } - return null; - } - }); - } - - @NotNull - private List filterInMemory(@NotNull DataPack dataPack, @NotNull List detailsFilters) { - List result = ContainerUtil.newArrayList(); - for (int visibleCommit : VcsLogUtil.getVisibleCommits(dataPack.getGraphFacade())) { - VcsCommitMetadata data = getDetailsFromCache(visibleCommit); - if (data == null) { - // no more continuous details in the cache - break; - } - if (matchesAllFilters(data, detailsFilters)) { - result.add(data.getId()); - } - } - return result; - } - - private static boolean matchesAllFilters(@NotNull final VcsCommitMetadata commit, @NotNull List detailsFilters) { - return !ContainerUtil.exists(detailsFilters, new Condition() { - @Override - public boolean value(VcsLogDetailsFilter filter) { - return !filter.matches(commit); - } - }); - } - - @Nullable - private VcsCommitMetadata getDetailsFromCache(final int commitIndex) { - final Hash hash = myLogDataHolder.getHash(commitIndex); - VcsCommitMetadata details = myLogDataHolder.getTopCommitDetails(hash); - if (details != null) { - return details; - } - final Ref ref = Ref.create(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - ref.set(myLogDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash)); - } - }); - return ref.get(); - } - - public void getFilteredDetailsFromTheVcs(@NotNull final Map providers, - @NotNull final VcsLogFilterCollection filterCollection, - @NotNull final Consumer> success, - final int maxCount) { - myLogDataHolder.runInBackground(new ThrowableConsumer() { - @Override - public void consume(ProgressIndicator indicator) throws VcsException { - Collection> logs = ContainerUtil.newArrayList(); - for (Map.Entry entry : providers.entrySet()) { - final VirtualFile root = entry.getKey(); - - if (filterCollection.getStructureFilter() != null && filterCollection.getStructureFilter().getFiles(root).isEmpty() - || filterCollection.getUserFilter() != null && filterCollection.getUserFilter().getUserNames(root).isEmpty()) { - // there is a structure or user filter, but it doesn't match this root - continue; - } - - List matchingCommits = entry.getValue().getCommitsMatchingFilter(root, filterCollection, maxCount); - logs.add(matchingCommits); - } - - final List compoundLog = new VcsLogMultiRepoJoiner().join(logs); - - final List list = ContainerUtil.map(compoundLog, new Function() { - @Override - public Hash fun(TimedVcsCommit commit) { - return commit.getId(); - } - }); - - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - if (!myLogDataHolder.getProject().isDisposed()) { - success.consume(list); - } - } - }); - } - }, "Looking for more results..."); - } + void moreCommitsNeeded(@NotNull Runnable onLoaded); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java new file mode 100644 index 000000000000..3b03333064f4 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java @@ -0,0 +1,169 @@ +/* + * Copyright 2000-2014 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.vcs.log.data; + +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.progress.impl.ProgressManagerImpl; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsCommitMetadata; +import com.intellij.vcs.log.VcsLogFilterCollection; +import com.intellij.vcs.log.VcsLogProvider; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class VcsLogFiltererImpl implements VcsLogFilterer { + + @NotNull private final SingleTaskController myTaskController; + @NotNull private final VisiblePackBuilder myVisiblePackBuilder; + + @NotNull private VcsLogFilterCollection myFilters; + @NotNull private PermanentGraph.SortType mySortType; + @NotNull private CommitCountStage myCommitCount = CommitCountStage.INITIAL; + @Nullable private DataPack myDataPack; + + VcsLogFiltererImpl(@NotNull final Project project, + @NotNull Map providers, + @NotNull VcsLogHashMap hashMap, + @NotNull Map topCommitsDetailsCache, + @NotNull CommitDetailsGetter detailsGetter, + @NotNull final PermanentGraph.SortType initialSortType, + @NotNull final Consumer visiblePackConsumer) { + myVisiblePackBuilder = new VisiblePackBuilder(providers, hashMap, topCommitsDetailsCache, detailsGetter); + myFilters = new VcsLogFilterCollectionImpl(null, null, null, null, null, null); + mySortType = initialSortType; + + myTaskController = new SingleTaskController(visiblePackConsumer) { + @Override + protected void startNewBackgroundTask() { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + ProgressManagerImpl.runProcessWithProgressAsynchronously(new MyTask(project, "Applying filters...")); + } + }); + } + }; + } + + @Override + public void onRefresh(@NotNull DataPack dataPack) { + myTaskController.request(new RefreshRequest(dataPack)); + } + + @Override + public void onFiltersChange(@NotNull VcsLogFilterCollection newFilters) { + myTaskController.request(new FilterRequest(newFilters)); + } + + @Override + public void onSortTypeChange(@NotNull PermanentGraph.SortType sortType) { + myTaskController.request(new SortTypeRequest(sortType)); + } + + @Override + public void moreCommitsNeeded(@NotNull Runnable onLoaded) { + myTaskController.request(new MoreCommitsRequest(onLoaded)); + } + + private class MyTask extends Task.Backgroundable { + + public MyTask(@Nullable Project project, @NotNull String title) { + super(project, title); + } + + @Override + public void run(@NotNull ProgressIndicator indicator) { + VisiblePack visiblePack = null; + List requests; + while (!(requests = myTaskController.popRequests()).isEmpty()) { + RefreshRequest refreshRequest = ContainerUtil.findLastInstance(requests, RefreshRequest.class); + FilterRequest filterRequest = ContainerUtil.findLastInstance(requests, FilterRequest.class); + SortTypeRequest sortTypeRequest = ContainerUtil.findLastInstance(requests, SortTypeRequest.class); + + if (refreshRequest != null) { + myDataPack = refreshRequest.dataPack; + } + if (filterRequest != null) { + myFilters = filterRequest.filters; + } + if (sortTypeRequest != null) { + mySortType = sortTypeRequest.sortType; + } + + if (myDataPack == null) { // when filter is set during initialization, just remember filters + continue; + } + + if (filterRequest != null) { // "more commits needed" has no effect if filter changes; it also can't come after filter change request + myCommitCount = CommitCountStage.INITIAL; + } + else if (ContainerUtil.findInstance(requests, MoreCommitsRequest.class) != null) { + myCommitCount = myCommitCount.next(); + } + + Pair pair = myVisiblePackBuilder.build(myDataPack, mySortType, myFilters, myCommitCount); + visiblePack = pair.first; + myCommitCount = pair.second; + } + + // visible pack can be null (e.g. when filter is set during initialization) => we just remember filters set by user + myTaskController.taskCompleted(visiblePack); + } + } + + private interface Request { + } + + private static final class RefreshRequest implements Request { + private final DataPack dataPack; + RefreshRequest(DataPack dataPack) { + this.dataPack = dataPack; + } + } + + private static final class FilterRequest implements Request { + private final VcsLogFilterCollection filters; + FilterRequest(VcsLogFilterCollection filters) { + this.filters = filters; + } + } + + private static final class SortTypeRequest implements Request { + private final PermanentGraph.SortType sortType; + SortTypeRequest(PermanentGraph.SortType sortType) { + this.sortType = sortType; + } + } + + private static final class MoreCommitsRequest implements Request { + private final Runnable onLoaded; + MoreCommitsRequest(Runnable onLoaded) { + this.onLoaded = onLoaded; + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java index e67f8f91e22a..638337a64f36 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java @@ -92,6 +92,23 @@ public class VcsLogHashMap implements Disposable { } } + @Nullable + public Hash findHashByString(@NotNull String string) { + final String pHash = string.toLowerCase(); + try { + return findHash(new Condition() { + @Override + public boolean value(@NotNull Hash hash) { + return hash.toString().toLowerCase().startsWith(pHash); + } + }); + } + catch (IOException e) { + LOG.error(e); + return null; + } + } + @NotNull public NotNullFunction asIndexGetter() { return new NotNullFunction() { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java new file mode 100644 index 000000000000..99945460e41d --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2014 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.vcs.log.data; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.VcsLogDataPack; +import com.intellij.vcs.log.VcsLogProvider; +import com.intellij.vcs.log.VcsLogRefs; +import com.intellij.vcs.log.graph.VisibleGraph; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class VisiblePack implements VcsLogDataPack { + + public static final VisiblePack EMPTY = new VisiblePack(EmptyDataPack.getInstance(), EmptyVisibleGraph.getInstance(), false); + + @NotNull private final DataPack myDataPack; + @NotNull private final VisibleGraph myVisibleGraph; + private final boolean myCanRequestMore; + + VisiblePack(@NotNull DataPack dataPack, @NotNull VisibleGraph graph, boolean canRequestMore) { + myDataPack = dataPack; + myVisibleGraph = graph; + myCanRequestMore = canRequestMore; + } + + @NotNull + public VisibleGraph getVisibleGraph() { + return myVisibleGraph; + } + + public boolean canRequestMore() { + return myCanRequestMore; + } + + @NotNull + @Override + public Map getLogProviders() { + return myDataPack.getLogProviders(); + } + + @NotNull + @Override + public VcsLogRefs getRefs() { + return myDataPack.getRefs(); + } + + @NotNull + public RefsModel getRefsModel() { + return myDataPack.getRefsModel(); + } + +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java new file mode 100644 index 000000000000..54be3ea5ae33 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java @@ -0,0 +1,228 @@ +/* + * Copyright 2000-2014 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.vcs.log.data; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.*; +import com.intellij.vcs.log.graph.GraphCommit; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.graph.VisibleGraph; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +class VisiblePackBuilder { + + private static final Logger LOG = Logger.getInstance(VisiblePackBuilder.class); + + @NotNull private final VcsLogHashMap myHashMap; + @NotNull private final Map myTopCommitsDetailsCache; + @NotNull private final CommitDetailsGetter myCommitDetailsGetter; + @NotNull private final Map myLogProviders; + + VisiblePackBuilder(@NotNull Map providers, + @NotNull VcsLogHashMap hashMap, + @NotNull Map topCommitsDetailsCache, + @NotNull CommitDetailsGetter detailsGetter) { + myHashMap = hashMap; + myTopCommitsDetailsCache = topCommitsDetailsCache; + myCommitDetailsGetter = detailsGetter; + myLogProviders = providers; + } + + @NotNull + Pair build(@NotNull DataPack dataPack, + @NotNull PermanentGraph.SortType sortType, + @NotNull VcsLogFilterCollection filters, + @NotNull CommitCountStage commitCount) { + VcsLogHashFilter hashFilter = filters.getHashFilter(); + if (hashFilter != null && !hashFilter.getHashes().isEmpty()) { // hashes should be shown, no matter if they match other filters or not + return Pair.create(applyHashFilter(dataPack, hashFilter.getHashes(), sortType), commitCount); + } + + List detailsFilters = filters.getDetailsFilters(); + Condition filter; + boolean canRequestMore; + if (!detailsFilters.isEmpty()) { + List matchingCommits = null; + if (commitCount == CommitCountStage.INITIAL) { + matchingCommits = filterInMemory(dataPack.getPermanentGraph(), detailsFilters); + if (matchingCommits.size() < commitCount.getCount()) { + commitCount = commitCount.next(); + matchingCommits = null; + } + } + + if (matchingCommits == null) { + try { + matchingCommits = getFilteredDetailsFromTheVcs(myLogProviders, filters, commitCount.getCount()); + } + catch (VcsException e) { + // TODO show an error balloon or something else for non-ea guys. + matchingCommits = Collections.emptyList(); + LOG.error(e); + } + } + + filter = getFilterFromCommits(matchingCommits); + canRequestMore = matchingCommits.size() >= commitCount.getCount(); // from VCS: only "==", but from memory can be ">" + } + else { + filter = null; + canRequestMore = false; + } + + Set heads = getMatchingHeads(dataPack.getRefs(), filters); + VisibleGraph visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, heads, filter); + return Pair.create(new VisiblePack(dataPack, visibleGraph, canRequestMore), commitCount); + } + + private VisiblePack applyHashFilter(@NotNull DataPack dataPack, + @NotNull Collection hashes, + @NotNull PermanentGraph.SortType sortType) { + final Set indices = ContainerUtil.map2SetNotNull(hashes, new Function() { + @Override + public Integer fun(String partOfHash) { + Hash hash = myHashMap.findHashByString(partOfHash); + return hash != null ? myHashMap.getCommitIndex(hash) : null; + } + }); + VisibleGraph visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, null, new Condition() { + @Override + public boolean value(Integer integer) { + return indices.contains(integer); + } + }); + return new VisiblePack(dataPack, visibleGraph, false); + } + + @Nullable + private Set getMatchingHeads(@NotNull VcsLogRefs refs, @NotNull VcsLogFilterCollection filters) { + VcsLogBranchFilter branchFilter = filters.getBranchFilter(); + if (branchFilter == null) { + return null; + } + + final Collection branchNames = new HashSet(branchFilter.getBranchNames()); + return new HashSet(ContainerUtil.mapNotNull(refs.getBranches(), new Function() { + @Override + public Integer fun(VcsRef ref) { + if (branchNames.contains(ref.getName())) { + return myHashMap.getCommitIndex(ref.getCommitHash()); + } + return null; + } + })); + } + + @NotNull + private List filterInMemory(@NotNull PermanentGraph permanentGraph, @NotNull List detailsFilters) { + List result = ContainerUtil.newArrayList(); + for (GraphCommit commit : permanentGraph.getAllCommits()) { + VcsCommitMetadata data = getDetailsFromCache(commit.getId()); + if (data == null) { + // no more continuous details in the cache + break; + } + if (matchesAllFilters(data, detailsFilters)) { + result.add(data.getId()); + } + } + return result; + } + + private static boolean matchesAllFilters(@NotNull final VcsCommitMetadata commit, @NotNull List detailsFilters) { + return ContainerUtil.and(detailsFilters, new Condition() { + @Override + public boolean value(VcsLogDetailsFilter filter) { + return filter.matches(commit); + } + }); + } + + @Nullable + private VcsCommitMetadata getDetailsFromCache(final int commitIndex) { + final Hash hash = myHashMap.getHash(commitIndex); + VcsCommitMetadata details = myTopCommitsDetailsCache.get(hash); + if (details != null) { + return details; + } + return UIUtil.invokeAndWaitIfNeeded(new Computable() { + @Override + public VcsCommitMetadata compute() { + return myCommitDetailsGetter.getCommitDataIfAvailable(hash); + } + }); + } + + @NotNull + private static List getFilteredDetailsFromTheVcs(@NotNull Map providers, + @NotNull VcsLogFilterCollection filterCollection, + int maxCount) throws VcsException { + Collection> logs = ContainerUtil.newArrayList(); + for (Map.Entry entry : providers.entrySet()) { + VirtualFile root = entry.getKey(); + + if (filterCollection.getStructureFilter() != null && filterCollection.getStructureFilter().getFiles(root).isEmpty() + || filterCollection.getUserFilter() != null && filterCollection.getUserFilter().getUserNames(root).isEmpty()) { + // there is a structure or user filter, but it doesn't match this root + continue; + } + + List matchingCommits = entry.getValue().getCommitsMatchingFilter(root, filterCollection, maxCount); + logs.add(matchingCommits); + } + + List compoundLog = new VcsLogMultiRepoJoiner().join(logs); + return ContainerUtil.map(compoundLog, new Function() { + @Override + public Hash fun(TimedVcsCommit commit) { + return commit.getId(); + } + }); + } + + @Nullable + private Condition getFilterFromCommits(@Nullable List filteredCommits) { + if (filteredCommits == null) { + return null; + } + + final Set commitSet = ContainerUtil.map2Set(filteredCommits, new Function() { + @Override + public Integer fun(Hash hash) { + return myHashMap.getCommitIndex(hash); + } + }); + return new Condition() { + @Override + public boolean value(Integer integer) { + return commitSet.contains(integer); + } + }; + } + +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java index 6abda6ae2c54..7219749676b2 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java @@ -21,7 +21,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,7 +48,7 @@ public class VcsLogImpl implements VcsLog { List hashes = ContainerUtil.newArrayList(); JBTable table = myUi.getTable(); for (int row : table.getSelectedRows()) { - Hash hash = ((AbstractVcsLogTableModel)table.getModel()).getHashAtRow(row); + Hash hash = ((GraphTableModel)table.getModel()).getHashAtRow(row); if (hash != null) { hashes.add(hash); } @@ -62,7 +62,7 @@ public class VcsLogImpl implements VcsLog { List details = ContainerUtil.newArrayList(); JBTable table = myUi.getTable(); for (int row : table.getSelectedRows()) { - AbstractVcsLogTableModel model = (AbstractVcsLogTableModel)table.getModel(); + GraphTableModel model = (GraphTableModel)table.getModel(); VcsFullCommitDetails commitDetails = model.getFullCommitDetails(row); if (commitDetails == null) { return ContainerUtil.emptyList(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java index 77401fdb32f5..8a6ad1dd1d9b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java @@ -64,23 +64,22 @@ public class VcsLogManager implements Disposable { public JComponent initContent() { final Map logProviders = findLogProviders(); - Consumer dataPackUpdateHandler = new Consumer() { + Consumer visiblePackConsumer = new Consumer() { @Override - public void consume(final DataPack dataPack) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (!Disposer.isDisposed(myUi)) { - myUi.setDataPack(dataPack); - myProject.getMessageBus().syncPublisher(VcsLogDataHolder.REFRESH_COMPLETED).refresh(dataPack); + public void consume(final VisiblePack pack) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (!Disposer.isDisposed(myUi)) { + myUi.setVisiblePack(pack); + } } - } - }); + }); } }; - VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, dataPackUpdateHandler); + VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, myUiProperties, visiblePackConsumer); myUi = new VcsLogUiImpl(logDataHolder, myProject, mySettings, - new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties, EmptyDataPack.getInstance()); + new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties, logDataHolder.getFilterer()); myLogRefresher = new PostponeableLogRefresher(myProject, logDataHolder); refreshLogOnVcsEvents(logProviders); logDataHolder.initialize(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java index ad610c45c01a..17c3d2bc6eec 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java @@ -18,7 +18,7 @@ package com.intellij.vcs.log.impl; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.MultiMap; import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.graph.GraphFacade; +import com.intellij.vcs.log.graph.VisibleGraph; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -45,16 +45,16 @@ public class VcsLogUtil { } @NotNull - public static List getVisibleCommits(@NotNull final GraphFacade facade) { + public static List getVisibleCommits(@NotNull final VisibleGraph visibleGraph) { return new AbstractList() { @Override public Integer get(int index) { - return facade.getCommitAtRow(index); + return visibleGraph.getRowInfo(index).getCommit(); } @Override public int size() { - return facade.getVisibleCommitCount(); + return visibleGraph.getVisibleCommitCount(); } }; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java index b96611dd0f25..8f7b10b33363 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java @@ -7,20 +7,19 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.*; -import com.intellij.vcs.log.graph.ChangeCursorActionRequest; -import com.intellij.vcs.log.graph.ClickGraphAction; -import com.intellij.vcs.log.graph.*; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.graph.VisibleGraph; +import com.intellij.vcs.log.graph.actions.GraphAnswer; import com.intellij.vcs.log.impl.VcsLogImpl; import com.intellij.vcs.log.ui.frame.MainFrame; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; @@ -40,27 +39,44 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { private static final Logger LOG = Logger.getInstance(VcsLogUiImpl.class); @NotNull private final MainFrame myMainFrame; + @NotNull private final VcsLogDataHolder myLogDataHolder; @NotNull private final Project myProject; @NotNull private final VcsLogColorManager myColorManager; - @NotNull private final VcsLogFilterer myFilterer; @NotNull private final VcsLog myLog; @NotNull private final VcsLogUiProperties myUiProperties; + @NotNull private final VcsLogFilterer myFilterer; @NotNull private final Collection myFilterChangeListeners = ContainerUtil.newArrayList(); - @NotNull private DataPack myDataPack; + @NotNull private VisiblePack myVisiblePack; public VcsLogUiImpl(@NotNull VcsLogDataHolder logDataHolder, @NotNull Project project, @NotNull VcsLogSettings settings, - @NotNull VcsLogColorManager manager, @NotNull VcsLogUiProperties uiProperties, @NotNull DataPack initialDataPack) { + @NotNull VcsLogColorManager manager, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLogFilterer filterer) { + myLogDataHolder = logDataHolder; myProject = project; myColorManager = manager; myUiProperties = uiProperties; - myDataPack = initialDataPack; Disposer.register(logDataHolder, this); - myFilterer = new VcsLogFilterer(logDataHolder, this); + myFilterer = filterer; myLog = new VcsLogImpl(logDataHolder, this); - myMainFrame = new MainFrame(logDataHolder, this, project, settings, uiProperties, myLog, initialDataPack); + myVisiblePack = VisiblePack.EMPTY; + myMainFrame = new MainFrame(logDataHolder, this, project, settings, uiProperties, myLog, myVisiblePack); + } + + public void setVisiblePack(@NotNull VisiblePack pack) { + ApplicationManager.getApplication().assertIsDispatchThread(); + + TIntHashSet previouslySelected = getSelectedCommits(); + + myVisiblePack = pack; + + GraphTableModel newModel = new GraphTableModel(myVisiblePack, myLogDataHolder, this); + setModel(newModel, myVisiblePack.getVisibleGraph(), previouslySelected); + myMainFrame.updateDataPack(myVisiblePack); + setLongEdgeVisibility(myUiProperties.areLongEdgesVisible()); + fireFilterChangeEvent(); + repaintUI(); } @NotNull @@ -77,19 +93,20 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { }); } - public void setModel(@NotNull AbstractVcsLogTableModel newModel, @NotNull DataPack newDataPack, - @NotNull TIntHashSet previouslySelectedCommits) { + private void setModel(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph newVisibleGraph, + @NotNull TIntHashSet previouslySelectedCommits) { final VcsLogGraphTable table = getTable(); table.setModel(newModel); - restoreSelection(newModel, newDataPack, previouslySelectedCommits, table); + restoreSelection(newModel, newVisibleGraph, previouslySelectedCommits, table); table.setPaintBusy(false); } - private static void restoreSelection(@NotNull AbstractVcsLogTableModel newModel, - @NotNull DataPack newDataPack, + private static void restoreSelection(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph newVisibleGraph, @NotNull TIntHashSet previouslySelectedCommits, @NotNull final VcsLogGraphTable table) { - TIntHashSet rowsToSelect = findNewRowsToSelect(newModel, newDataPack, previouslySelectedCommits); + TIntHashSet rowsToSelect = findNewRowsToSelect(newModel, newVisibleGraph, previouslySelectedCommits); rowsToSelect.forEach(new TIntProcedure() { @Override public boolean execute(int row) { @@ -100,8 +117,8 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } @NotNull - private static TIntHashSet findNewRowsToSelect(@NotNull AbstractVcsLogTableModel newModel, - @NotNull DataPack dataPack, + private static TIntHashSet findNewRowsToSelect(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph visibleGraph, @NotNull TIntHashSet selectedHashes) { TIntHashSet rowsToSelect = new TIntHashSet(); if (newModel.getRowCount() == 0) { @@ -110,10 +127,9 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { // => it has previous values set. return rowsToSelect; } - GraphFacade facade = dataPack.getGraphFacade(); - for (int row = 0; row < facade.getVisibleCommitCount() + for (int row = 0; row < visibleGraph.getVisibleCommitCount() && rowsToSelect.size() < selectedHashes.size(); row++) { //stop iterating if found all hashes - int commit = facade.getCommitAtRow(row); + int commit = visibleGraph.getRowInfo(row).getCommit(); if (selectedHashes.contains(commit)) { rowsToSelect.add(row); } @@ -129,11 +145,11 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { runUnderModalProgress("Expanding linear branches...", new Runnable() { @Override public void run() { - final GraphAnswer answer = myDataPack.getGraphFacade().performAction(LinearBranchesExpansionAction.EXPAND); + myVisiblePack.getVisibleGraph().getActionController().setLinearBranchesExpansion(false); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - handleAnswer(answer); + handleAnswer(null, true); } }); } @@ -144,11 +160,11 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { runUnderModalProgress("Collapsing linear branches...", new Runnable() { @Override public void run() { - final GraphAnswer answer = myDataPack.getGraphFacade().performAction(LinearBranchesExpansionAction.COLLAPSE); + myVisiblePack.getVisibleGraph().getActionController().setLinearBranchesExpansion(true); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - handleAnswer(answer); + handleAnswer(null, true); } }); } @@ -156,80 +172,64 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } public void setLongEdgeVisibility(boolean visibility) { - handleAnswer(myDataPack.getGraphFacade().performAction(LongEdgesAction.valueOf(visibility))); + myVisiblePack.getVisibleGraph().getActionController().setLongEdgesHidden(!visibility); myUiProperties.setLongEdgesVisibility(visibility); } - public boolean areLongEdgesHidden() { - return myDataPack.getGraphFacade().getInfoProvider().areLongEdgesHidden(); - } - public void setBek(boolean bek) { myUiProperties.setBek(bek); - final BekGraphAction bekGraphAction = new BekGraphAction(bek ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal); - runUnderModalProgress("Apply sort type...", new Runnable() { - @Override - public void run() { - final GraphAnswer answer = myDataPack.getGraphFacade().performAction(bekGraphAction); - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - handleAnswer(answer); - } - }); - } - }); + myFilterer.onSortTypeChange(bek ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal); } public boolean isBek() { return myUiProperties.isBek(); } - public void click(int rowIndex) { - handleAnswer(myDataPack.getGraphFacade().performAction(new ClickGraphAction(rowIndex, null))); - } - public void jumpToCommit(@NotNull Hash commitHash) { - jumpTo(commitHash, new PairFunction() { + jumpTo(commitHash, new PairFunction() { @Override - public Integer fun(AbstractVcsLogTableModel model, Hash hash) { + public Integer fun(GraphTableModel model, Hash hash) { return model.getRowOfCommit(hash); } }); } public void jumpToCommitByPartOfHash(@NotNull String commitHash) { - jumpTo(commitHash, new PairFunction() { + jumpTo(commitHash, new PairFunction() { @Override - public Integer fun(AbstractVcsLogTableModel model, String hash) { + public Integer fun(GraphTableModel model, String hash) { return model.getRowOfCommitByPartOfHash(hash); } }); } - public void handleAnswer(@Nullable GraphAnswer answer) { + public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange) { + if (dataCouldChange) { + ((AbstractTableModel)(getTable().getModel())).fireTableDataChanged(); + } + repaintUI(); if (answer == null) { return; } - GraphChange graphChange = answer.getGraphChange(); - if (graphChange != null) { - ((AbstractTableModel)(getTable().getModel())).fireTableStructureChanged(); - } - GraphActionRequest actionRequest = answer.getActionRequest(); - if (actionRequest instanceof JumpToRowActionRequest) { - int row = ((JumpToRowActionRequest)actionRequest).getRow(); - jumpToRow(row); + if (answer.getCursorToSet() != null) { + myMainFrame.getGraphTable().setCursor(answer.getCursorToSet()); } - else if (actionRequest instanceof ChangeCursorActionRequest) { - myMainFrame.getGraphTable().setCursor(((ChangeCursorActionRequest)actionRequest).getCursor()); + if (answer.getCommitToJump() != null) { + int row = myVisiblePack.getVisibleGraph().getVisibleRowIndex(answer.getCommitToJump()); + if (row >= 0) { + jumpToRow(row); + } + else { + // TODO wait for the full log and then jump + } } } - private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter) { - AbstractVcsLogTableModel model = getModel(); + private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter) { + GraphTableModel model = getModel(); if (model == null) { return; } @@ -252,10 +252,10 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } @Nullable - private AbstractVcsLogTableModel getModel() { + private GraphTableModel getModel() { TableModel model = getTable().getModel(); - if (model instanceof AbstractVcsLogTableModel) { - return (AbstractVcsLogTableModel)model; + if (model instanceof GraphTableModel) { + return (GraphTableModel)model; } showMessage(MessageType.WARNING, "The log is not ready to search yet"); return null; @@ -281,61 +281,29 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } @NotNull - public VcsLogFilterer getFilterer() { - return myFilterer; - } - - @NotNull public TIntHashSet getSelectedCommits() { int[] selectedRows = getTable().getSelectedRows(); - return getCommitsAtRows(myDataPack.getGraphFacade(), selectedRows); + return getCommitsAtRows(myVisiblePack.getVisibleGraph(), selectedRows); } @NotNull - private static TIntHashSet getCommitsAtRows(@NotNull GraphFacade facade, int[] rows) { + private static TIntHashSet getCommitsAtRows(@NotNull VisibleGraph graph, int[] rows) { TIntHashSet commits = new TIntHashSet(); for (int row : rows) { - int commit = facade.getCommitAtRow(row); - if (commit > 0) { - commits.add(commit); + if (row < graph.getVisibleCommitCount()) { + commits.add(graph.getRowInfo(row).getCommit()); } } return commits; } - public void setDataPack(@NotNull DataPack dataPack) { - applyFiltersAndUpdateUi(dataPack); - } - - private void applyFiltersAndUpdateUi(@NotNull final DataPack dataPack) { - runUnderModalProgress("Applying filters...", new Runnable() { - public void run() { - final TIntHashSet previouslySelected = getSelectedCommits(); - final AbstractVcsLogTableModel newModel = myFilterer.applyFiltersAndUpdateUi(dataPack, getFilters()); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - myDataPack = dataPack; - setModel(newModel, myDataPack, previouslySelected); - myMainFrame.updateDataPack(myDataPack); - setLongEdgeVisibility(myUiProperties.areLongEdgesVisible()); - myDataPack.getGraphFacade().performAction(new BekGraphAction(myUiProperties.isBek() ? - PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal)); - fireFilterChangeEvent(); - repaintUI(); - - if (newModel.getRowCount() == 0) { // getValueAt won't be called for empty model => need to explicitly request to load more - newModel.requestToLoadMore(EmptyRunnable.INSTANCE); - } - } - }); - } - }); - } - public void applyFiltersAndUpdateUi() { - ApplicationManager.getApplication().assertIsDispatchThread(); - applyFiltersAndUpdateUi(myDataPack); + myFilterer.onFiltersChange(getFilters()); + } + + @NotNull + public VcsLogFilterer getFilterer() { + return myFilterer; } @NotNull @@ -358,7 +326,6 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, task, false, null, getMainFrame().getMainComponent()); } }); - repaintUI(); } public void setBranchesPanelVisible(boolean visible) { @@ -382,9 +349,9 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { @Override @NotNull - public DataPack getDataPack() { + public VisiblePack getDataPack() { ApplicationManager.getApplication().assertIsDispatchThread(); - return myDataPack; + return myVisiblePack; } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java index d358e86c2a40..c70595bf7d1b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java @@ -22,7 +22,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogBranchFilterImpl; import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.impl.VcsLogUtil; @@ -44,7 +43,7 @@ public class BranchFilterPopupComponent extends MultipleValueFilterPopupComponen myUiProperties = uiProperties; } - void updateDataPack(@NotNull DataPack dataPack) { + void updateDataPack(@NotNull VcsLogDataPack dataPack) { myDataPack = dataPack; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java index 9a44f320f040..8bc71682ad70 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java @@ -29,7 +29,6 @@ import com.intellij.ui.SearchTextFieldWithStoredHistory; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.*; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl; @@ -61,7 +60,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi { @NotNull private final StructureFilterPopupComponent myStructureFilterComponent; public VcsLogClassicFilterUi(@NotNull VcsLogUiImpl ui, @NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiProperties uiProperties, - @NotNull DataPack initialDataPack) { + @NotNull VcsLogDataPack initialDataPack) { myUi = ui; myTextFilter = new SearchTextFieldWithStoredHistory("Vcs.Log.Text.Filter.History") { @@ -91,7 +90,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi { myActionGroup.add(new FilterActionComponent(myStructureFilterComponent)); } - public void updateDataPack(@NotNull DataPack dataPack) { + public void updateDataPack(@NotNull VcsLogDataPack dataPack) { myBranchFilterComponent.updateDataPack(dataPack); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 2328c9fe3b20..8a978929a165 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -33,13 +33,13 @@ import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.VcsLogDataHolder; +import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.printer.idea.PrintParameters; import com.intellij.vcs.log.ui.VcsLogColorManager; import com.intellij.vcs.log.ui.render.RefPainter; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import net.miginfocom.swing.MigLayout; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -71,10 +71,10 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @NotNull private final MessagePanel myMessagePanel; @NotNull private final JBLoadingPanel myLoadingPanel; - @NotNull private DataPack myDataPack; + @NotNull private VisiblePack myDataPack; DetailsPanel(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogGraphTable graphTable, @NotNull VcsLogColorManager colorManager, - @NotNull DataPack initialDataPack) { + @NotNull VisiblePack initialDataPack) { super(new CardLayout()); myLogDataHolder = logDataHolder; myGraphTable = graphTable; @@ -111,7 +111,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { showMessage("No commits selected"); } - void updateDataPack(@NotNull DataPack dataPack) { + void updateDataPack(@NotNull VisiblePack dataPack) { myDataPack = dataPack; } @@ -127,7 +127,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { else { ((CardLayout)getLayout()).show(this, STANDARD_LAYER); int row = rows[0]; - AbstractVcsLogTableModel tableModel = (AbstractVcsLogTableModel)myGraphTable.getModel(); + GraphTableModel tableModel = (GraphTableModel)myGraphTable.getModel(); Hash hash = tableModel.getHashAtRow(row); VcsFullCommitDetails commitData = myLogDataHolder.getCommitDetailsGetter().getCommitData(row, tableModel); if (commitData == null || hash == null) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index 6765c7c394c7..780b720f696f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -22,9 +22,9 @@ import com.intellij.vcs.log.VcsLog; import com.intellij.vcs.log.VcsLogDataKeys; import com.intellij.vcs.log.VcsLogFilterUi; import com.intellij.vcs.log.VcsLogSettings; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VcsLogUiProperties; +import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.graph.impl.facade.bek.BekSorter; import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.filter.VcsLogClassicFilterUi; @@ -60,7 +60,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { public MainFrame(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiImpl vcsLogUI, @NotNull Project project, @NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLog log, - @NotNull DataPack initialDataPack) { + @NotNull VisiblePack initialDataPack) { // collect info myLogDataHolder = logDataHolder; myUI = vcsLogUI; @@ -124,7 +124,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { * Components may want to update their fields and/or rebuild. * @param dataPack new data pack. */ - public void updateDataPack(@NotNull DataPack dataPack) { + public void updateDataPack(@NotNull VisiblePack dataPack) { myFilterUi.updateDataPack(dataPack); myDetailsPanel.updateDataPack(dataPack); myGraphTable.updateDataPack(dataPack); @@ -336,7 +336,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { @Override public boolean isSelected(AnActionEvent e) { - return !myUI.areLongEdgesHidden(); + return !myUI.getDataPack().getVisibleGraph().getActionController().areLongEdgesHidden(); } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index f033f752e1ec..f1d1eba2bc35 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -27,26 +27,28 @@ import com.intellij.ui.ColoredTableCellRenderer; import com.intellij.ui.PopupHandler; import com.intellij.ui.TableScrollingUtil; import com.intellij.ui.table.JBTable; -import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogHighlighter; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.graph.*; +import com.intellij.vcs.log.data.VisiblePack; +import com.intellij.vcs.log.graph.ColorGenerator; +import com.intellij.vcs.log.graph.PrintElement; +import com.intellij.vcs.log.graph.actions.GraphAnswer; +import com.intellij.vcs.log.graph.actions.GraphMouseAction; +import com.intellij.vcs.log.printer.idea.GraphCellPainter; import com.intellij.vcs.log.printer.idea.PositionUtil; +import com.intellij.vcs.log.printer.idea.SimpleGraphCellPainter; import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.render.GraphCommitCell; import com.intellij.vcs.log.ui.render.GraphCommitCellRender; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; @@ -78,14 +80,22 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C @NotNull private final Collection myHighlighters = ContainerUtil.newArrayList(); - @NotNull private DataPack myDataPack; + private final GraphCellPainter myGraphCellPainter = new SimpleGraphCellPainter(new com.intellij.vcs.log.printer.idea.ColorGenerator() { + @Override + public Color getColor(int colorId) { + return ColorGenerator.getColor(colorId); + } + }); - public VcsLogGraphTable(@NotNull VcsLogUiImpl UI, @NotNull final VcsLogDataHolder logDataHolder, @NotNull DataPack initialDataPack) { + @NotNull private VisiblePack myDataPack; + + public VcsLogGraphTable(@NotNull VcsLogUiImpl UI, @NotNull final VcsLogDataHolder logDataHolder, @NotNull VisiblePack initialDataPack) { super(); myUI = UI; myLogDataHolder = logDataHolder; myDataPack = initialDataPack; - myGraphCommitCellRender = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myDataPack.getGraphFacade(), this); + myGraphCommitCellRender = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, + myDataPack.getVisibleGraph(), this); setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI, myLogDataHolder.isMultiRoot())); setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRender); @@ -95,16 +105,6 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C setShowHorizontalLines(false); setIntercellSpacing(new Dimension(0, 0)); - getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - int selectedRow = getSelectedRow(); - if (selectedRow >= 0) { - myUI.click(selectedRow); - } - } - }); - MouseAdapter mouseAdapter = new MyMouseAdapter(); addMouseMotionListener(mouseAdapter); addMouseListener(mouseAdapter); @@ -127,17 +127,17 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C private void setColumnPreferredSize() { for (int i = 0; i < getColumnCount(); i++) { TableColumn column = getColumnModel().getColumn(i); - if (i == AbstractVcsLogTableModel.ROOT_COLUMN) { // thin stripe or nothing + if (i == GraphTableModel.ROOT_COLUMN) { // thin stripe or nothing int rootWidth = myUI.getColorManager().isMultipleRoots() ? ROOT_INDICATOR_WIDTH : 0; // NB: all further instructions and their order are important, otherwise the minimum size which is less than 15 won't be applied column.setMinWidth(rootWidth); column.setMaxWidth(rootWidth); column.setPreferredWidth(rootWidth); } - else if (i == AbstractVcsLogTableModel.COMMIT_COLUMN) { // let commit message occupy as much as possible + else if (i == GraphTableModel.COMMIT_COLUMN) { // let commit message occupy as much as possible column.setPreferredWidth(Short.MAX_VALUE); } - else if (i == AbstractVcsLogTableModel.AUTHOR_COLUMN) { // detect author with the longest name + else if (i == GraphTableModel.AUTHOR_COLUMN) { // detect author with the longest name // to avoid querying the last row (it would lead to full graph loading) int maxRowsToCheck = Math.min(MAX_ROWS_TO_CALC_WIDTH, getRowCount() - MAX_ROWS_TO_CALC_OFFSET); if (maxRowsToCheck < 0) { // but if the log is small, check all of them @@ -147,7 +147,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C column.setMinWidth(Math.min(contentWidth, MAX_DEFAULT_AUTHOR_COLUMN_WIDTH)); column.setWidth(column.getMinWidth()); } - else if (i == AbstractVcsLogTableModel.DATE_COLUMN) { // all dates have nearly equal sizes + else if (i == GraphTableModel.DATE_COLUMN) { // all dates have nearly equal sizes Font tableFont = UIManager.getFont("Table.font"); column.setMinWidth(getFontMetrics(tableFont).stringWidth("mm" + DateFormatUtil.formatDateTime(new Date()))); column.setWidth(column.getMinWidth()); @@ -172,7 +172,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C if (column < 0 || row < 0) { return null; } - if (column == AbstractVcsLogTableModel.ROOT_COLUMN) { + if (column == GraphTableModel.ROOT_COLUMN) { Object at = getValueAt(row, column); if (at instanceof VirtualFile) { return ((VirtualFile)at).getPresentableUrl(); @@ -213,10 +213,10 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C @Nullable public List getSelectedChanges() { TableModel model = getModel(); - if (!(model instanceof AbstractVcsLogTableModel)) { + if (!(model instanceof GraphTableModel)) { return null; } - List changes = ((AbstractVcsLogTableModel)model).getSelectedChanges(sortSelectedRows()); + List changes = ((GraphTableModel)model).getSelectedChanges(sortSelectedRows()); return changes == null ? null : CommittedChangesTreeBrowser.zipChanges(changes); } @@ -241,7 +241,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C public void performCopy(@NotNull DataContext dataContext) { List hashes = ContainerUtil.newArrayList(); for (int row : getSelectedRows()) { - Hash hash = ((AbstractVcsLogTableModel)getModel()).getHashAtRow(row); + Hash hash = ((GraphTableModel)getModel()).getHashAtRow(row); if (hash != null) { hashes.add(hash.asString()); } @@ -261,9 +261,9 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C return true; } - public void updateDataPack(@NotNull DataPack dataPack) { + public void updateDataPack(@NotNull VisiblePack dataPack) { myDataPack = dataPack; - myGraphCommitCellRender.updateGraphFacade(dataPack.getGraphFacade()); + myGraphCommitCellRender.updateVisibleGraph(dataPack.getVisibleGraph()); } public void addHighlighter(@NotNull VcsLogHighlighter highlighter) { @@ -281,7 +281,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C public void applyHighlighters(@NotNull Component rendererComponent, int row, boolean selected) { boolean fgUpdated = false; for (VcsLogHighlighter highlighter : myHighlighters) { - Color color = highlighter.getForeground(myDataPack.getGraphFacade().getCommitAtRow(row), selected); + Color color = highlighter.getForeground(myDataPack.getVisibleGraph().getRowInfo(row).getCommit(), selected); if (color != null) { rendererComponent.setForeground(color); fgUpdated = true; @@ -306,12 +306,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } if (e.getClickCount() == 1) { - performAction(e, new PairFunction() { - @Override - public GraphAction fun(Integer row, Point point) { - return new ClickGraphAction(row, point); - } - }); + performAction(e, MyGraphMouseAction.Type.CLICK); } } @@ -321,24 +316,22 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else { - performAction(e, new PairFunction() { - @Override - public GraphAction fun(Integer row, Point point) { - return new MouseOverAction(row, point); - } - }); + performAction(e, MyGraphMouseAction.Type.OVER); } } - private void performAction(@NotNull MouseEvent e, @NotNull PairFunction actionConstructor) { + private void performAction(@NotNull MouseEvent e, @NotNull final MyGraphMouseAction.Type actionType) { int row = PositionUtil.getRowIndex(e.getPoint()); if (row > getRowCount() - 1) { return; } Point point = calcPoint4Graph(e.getPoint()); - GraphFacade graphFacade = myDataPack.getGraphFacade(); - GraphAnswer answer = graphFacade.performAction(actionConstructor.fun(row, point)); - myUI.handleAnswer(answer); + Collection printElements = myDataPack.getVisibleGraph().getRowInfo(row).getPrintElements(); + PrintElement printElement = myGraphCellPainter.mouseOver(printElements, point.x, point.y); + + GraphAnswer answer = myDataPack.getVisibleGraph().getActionController().performMouseAction( + new MyGraphMouseAction(printElement, actionType)); + myUI.handleAnswer(answer, actionType == MyGraphMouseAction.Type.CLICK && printElement != null); } private boolean isAboveLink(MouseEvent e) { @@ -354,6 +347,28 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C public void mouseExited(MouseEvent e) { // Do nothing } + + private class MyGraphMouseAction implements GraphMouseAction { + private final PrintElement myPrintElement; + private final Type myActionType; + + public MyGraphMouseAction(PrintElement printElement, Type actionType) { + myPrintElement = printElement; + myActionType = actionType; + } + + @Nullable + @Override + public PrintElement getAffectedElement() { + return myPrintElement; + } + + @NotNull + @Override + public Type getType() { + return myActionType; + } + } } @NotNull @@ -362,7 +377,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } private int getXOffset() { - TableColumn rootColumn = getColumnModel().getColumn(AbstractVcsLogTableModel.ROOT_COLUMN); + TableColumn rootColumn = getColumnModel().getColumn(GraphTableModel.ROOT_COLUMN); return myLogDataHolder.isMultiRoot() ? rootColumn.getWidth() : 0; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java deleted file mode 100644 index 23c736b4420b..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.intellij.vcs.log.ui.render; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.ColoredTableCellRenderer; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.graph.PaintInfo; -import com.intellij.vcs.log.ui.VcsLogColorManager; -import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public abstract class AbstractPaddingCellRender extends ColoredTableCellRenderer { - - private static final Logger LOG = Logger.getInstance(AbstractPaddingCellRender.class); - - @NotNull private final VcsLogDataHolder myDataHolder; - @NotNull private final VcsLogGraphTable myGraphTable; - - @NotNull private final RefPainter myRefPainter; - @NotNull private final IssueLinkRenderer myIssueLinkRenderer; - - @Nullable private PaintInfo myGraphImage; - @Nullable private Collection myRefs; - - protected AbstractPaddingCellRender(@NotNull VcsLogColorManager colorManager, @NotNull VcsLogDataHolder dataHolder, - @NotNull VcsLogGraphTable table) { - myDataHolder = dataHolder; - myGraphTable = table; - myRefPainter = new RefPainter(colorManager, false); - myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); - } - - @Nullable - protected abstract PaintInfo getGraphImage(int row); - - @Override - protected void customizeCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (value == null) { - return; - } - - GraphCommitCell cell = getAssertCommitCell(value); - myGraphImage = getGraphImage(row); - myRefs = cell.getRefsToThisCommit(); - - int graphPadding; - if (myGraphImage != null) { - graphPadding = myGraphImage.getWidth(); - if (graphPadding < 2) { // TODO temporary diagnostics: why does graph sometimes disappear - LOG.error("Too small image width: " + graphPadding); - } - } - else { - graphPadding = 0; - } - int textPadding = graphPadding + calcRefsPadding(myRefs); - - setBorder(null); - append(""); - appendFixedTextFragmentWidth(textPadding); - myGraphTable.applyHighlighters(this, row, isSelected); - myIssueLinkRenderer.appendTextWithLinks(cell.getText()); - } - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - if (myRefs != null) { - int graphPadding = myGraphImage != null ? myGraphImage.getWidth() : 0; - drawRefs((Graphics2D)g, myRefs, graphPadding); - } - - if (myGraphImage != null) { - UIUtil.drawImage(g, myGraphImage.getImage(), 0, 0, null); - } - else { // TODO temporary diagnostics: why does graph sometimes disappear - LOG.error("Image is null"); - } - } - - private static GraphCommitCell getAssertCommitCell(Object value) { - assert value instanceof GraphCommitCell : "Value of incorrect class was supplied: " + value; - return (GraphCommitCell)value; - } - - protected void drawRefs(@NotNull Graphics2D g2, @NotNull Collection refs, int padding) { - myRefPainter.drawLabels(g2, collectLabelsForRefs(refs), padding); - } - - @NotNull - private Map collectLabelsForRefs(@NotNull Collection refs) { - if (refs.isEmpty()) { - return Collections.emptyMap(); - } - VirtualFile root = refs.iterator().next().getRoot(); // all refs are from the same commit => they have the same root - refs = ContainerUtil.sorted(refs, myDataHolder.getLogProvider(root).getReferenceManager().getComparator()); - List branches = getBranches(refs); - Collection tags = ContainerUtil.subtract(refs, branches); - return getLabelsForRefs(branches, tags); - } - - protected int calcRefsPadding(@NotNull Collection refs) { - return myRefPainter.padding(collectLabelsForRefs(refs).keySet(), this.getFontMetrics(RefPainter.DEFAULT_FONT)); - } - - @NotNull - private static Map getLabelsForRefs(@NotNull List branches, @NotNull Collection tags) { - Map labels = ContainerUtil.newLinkedHashMap(); - for (VcsRef branch : branches) { - labels.put(branch.getName(), branch.getType().getBackgroundColor()); - } - if (!tags.isEmpty()) { - VcsRef firstTag = tags.iterator().next(); - Color color = firstTag.getType().getBackgroundColor(); - if (tags.size() > 1) { - labels.put(firstTag.getName() + " +", color); - } - else { - labels.put(firstTag.getName(), color); - } - } - return labels; - } - - private static List getBranches(Collection refs) { - return ContainerUtil.filter(refs, new Condition() { - @Override - public boolean value(VcsRef ref) { - return ref.getType().isBranch(); - } - }); - } -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index d2698e87a4fd..07e0ee412b4e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -1,46 +1,199 @@ -/* - * Copyright 2000-2013 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.vcs.log.ui.render; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.ColoredTableCellRenderer; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.VcsRef; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.graph.GraphFacade; -import com.intellij.vcs.log.graph.PaintInfo; +import com.intellij.vcs.log.graph.PrintElement; +import com.intellij.vcs.log.graph.VisibleGraph; +import com.intellij.vcs.log.printer.idea.GraphCellPainter; +import com.intellij.vcs.log.printer.idea.PrintParameters; import com.intellij.vcs.log.ui.VcsLogColorManager; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class GraphCommitCellRender extends AbstractPaddingCellRender { +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; - @NotNull private GraphFacade myGraphFacade; +public class GraphCommitCellRender extends ColoredTableCellRenderer { - public GraphCommitCellRender(@NotNull VcsLogColorManager colorManager, @NotNull VcsLogDataHolder dataHolder, - @NotNull GraphFacade graphFacade, @NotNull VcsLogGraphTable table) { - super(colorManager, dataHolder, table); - myGraphFacade = graphFacade; + private static final Logger LOG = Logger.getInstance(GraphCommitCellRender.class); + + @NotNull private final VcsLogDataHolder myDataHolder; + @NotNull private final GraphCellPainter myPainter; + @NotNull private final VcsLogGraphTable myGraphTable; + @NotNull private final RefPainter myRefPainter; + @NotNull private final IssueLinkRenderer myIssueLinkRenderer; + + @NotNull private VisibleGraph myVisibleGraph; + @Nullable private PaintInfo myGraphImage; + @Nullable private Collection myRefs; + + public GraphCommitCellRender(@NotNull VcsLogColorManager colorManager, + @NotNull VcsLogDataHolder dataHolder, + @NotNull GraphCellPainter painter, + @NotNull VisibleGraph graph, + @NotNull VcsLogGraphTable table) { + myDataHolder = dataHolder; + myPainter = painter; + myVisibleGraph = graph; + myGraphTable = table; + myRefPainter = new RefPainter(colorManager, false); + myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); + } + + public void updateVisibleGraph(@NotNull VisibleGraph visibleGraph) { + myVisibleGraph = visibleGraph; + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + if (myRefs != null) { + int graphPadding = myGraphImage != null ? myGraphImage.getWidth() : 0; + drawRefs((Graphics2D)g, myRefs, graphPadding); + } + + if (myGraphImage != null) { + UIUtil.drawImage(g, myGraphImage.getImage(), 0, 0, null); + } + else { // TODO temporary diagnostics: why does graph sometimes disappear + LOG.error("Image is null"); + } + } + + @Override + protected void customizeCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value == null) { + return; + } + + GraphCommitCell cell = getAssertCommitCell(value); + myGraphImage = getGraphImage(row); + myRefs = cell.getRefsToThisCommit(); + + int graphPadding; + if (myGraphImage != null) { + graphPadding = myGraphImage.getWidth(); + if (graphPadding < 2) { // TODO temporary diagnostics: why does graph sometimes disappear + LOG.error("Too small image width: " + graphPadding); + } + } + else { + graphPadding = 0; + } + int textPadding = graphPadding + calcRefsPadding(myRefs); + + setBorder(null); + append(""); + appendFixedTextFragmentWidth(textPadding); + myGraphTable.applyHighlighters(this, row, isSelected); + myIssueLinkRenderer.appendTextWithLinks(cell.getText()); } @Nullable - @Override - protected PaintInfo getGraphImage(int row) { - return myGraphFacade.paint(row); + private PaintInfo getGraphImage(int row) { + Collection printElements = myVisibleGraph.getRowInfo(row).getPrintElements(); + int maxIndex = 0; + for (PrintElement printElement : printElements) { + maxIndex = Math.max(maxIndex, printElement.getPositionInCurrentRow()); + } + maxIndex++; + final BufferedImage image = + UIUtil.createImage(PrintParameters.WIDTH_NODE * (maxIndex + 4), PrintParameters.HEIGHT_CELL, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = image.createGraphics(); + myPainter.draw(g2, printElements); + + final int width = maxIndex * PrintParameters.WIDTH_NODE; + return new PaintInfo(image, width); } - public void updateGraphFacade(@NotNull GraphFacade graphFacade) { - myGraphFacade = graphFacade; + private static GraphCommitCell getAssertCommitCell(Object value) { + assert value instanceof GraphCommitCell : "Value of incorrect class was supplied: " + value; + return (GraphCommitCell)value; } + private void drawRefs(@NotNull Graphics2D g2, @NotNull Collection refs, int padding) { + myRefPainter.drawLabels(g2, collectLabelsForRefs(refs), padding); + } + + @NotNull + private Map collectLabelsForRefs(@NotNull Collection refs) { + if (refs.isEmpty()) { + return Collections.emptyMap(); + } + VirtualFile root = refs.iterator().next().getRoot(); // all refs are from the same commit => they have the same root + refs = ContainerUtil.sorted(refs, myDataHolder.getLogProvider(root).getReferenceManager().getComparator()); + List branches = getBranches(refs); + Collection tags = ContainerUtil.subtract(refs, branches); + return getLabelsForRefs(branches, tags); + } + + private int calcRefsPadding(@NotNull Collection refs) { + return myRefPainter.padding(collectLabelsForRefs(refs).keySet(), this.getFontMetrics(RefPainter.DEFAULT_FONT)); + } + + @NotNull + private static Map getLabelsForRefs(@NotNull List branches, @NotNull Collection tags) { + Map labels = ContainerUtil.newLinkedHashMap(); + for (VcsRef branch : branches) { + labels.put(branch.getName(), branch.getType().getBackgroundColor()); + } + if (!tags.isEmpty()) { + VcsRef firstTag = tags.iterator().next(); + Color color = firstTag.getType().getBackgroundColor(); + if (tags.size() > 1) { + labels.put(firstTag.getName() + " +", color); + } + else { + labels.put(firstTag.getName(), color); + } + } + return labels; + } + + private static List getBranches(Collection refs) { + return ContainerUtil.filter(refs, new Condition() { + @Override + public boolean value(VcsRef ref) { + return ref.getType().isBranch(); + } + }); + } + + private static class PaintInfo { + private int myWidth; + @NotNull private Image myImage; + + PaintInfo(@NotNull Image image, int width) { + myImage = image; + myWidth = width; + } + + @NotNull + Image getImage() { + return myImage; + } + + /** + * Returns the "interesting" width of the painted image, i.e. the width which the text in the table should be offset by.
+ * It can be smaller than the width of {@link #getImage() the image}, because we allow the text to cover part of the graph + * (some diagonal edges, etc.) + */ + int getWidth() { + return myWidth; + } + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java deleted file mode 100644 index e5f93eeb0235..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.intellij.vcs.log.ui.tables; - -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile; -import com.intellij.util.text.DateFormatUtil; -import com.intellij.vcs.log.Hash; -import com.intellij.vcs.log.VcsFullCommitDetails; -import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.data.DataPack; -import com.intellij.vcs.log.data.LoadMoreStage; -import com.intellij.vcs.log.data.LoadingDetails; -import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.VcsLogUiImpl; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.table.AbstractTableModel; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -public abstract class AbstractVcsLogTableModel extends AbstractTableModel { - - public static final int ROOT_COLUMN = 0; - public static final int COMMIT_COLUMN = 1; - public static final int AUTHOR_COLUMN = 2; - public static final int DATE_COLUMN = 3; - private static final int COLUMN_COUNT = DATE_COLUMN + 1; - - private static final String[] COLUMN_NAMES = {"", "Subject", "Author", "Date"}; - - @NotNull private final VcsLogDataHolder myLogDataHolder; - @NotNull protected final VcsLogUiImpl myUi; - @NotNull protected final DataPack myDataPack; - @NotNull private final LoadMoreStage myLoadMoreStage; - - @NotNull private final AtomicBoolean myLoadMoreWasRequested = new AtomicBoolean(); - - - protected AbstractVcsLogTableModel(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiImpl ui, @NotNull DataPack dataPack, - @NotNull LoadMoreStage loadMoreStage) { - myLogDataHolder = logDataHolder; - myUi = ui; - myDataPack = dataPack; - myLoadMoreStage = loadMoreStage; - } - - @Override - public final int getColumnCount() { - return COLUMN_COUNT; - } - - @Nullable - protected VcsShortCommitDetails getShortDetails(int rowIndex) { - return myLogDataHolder.getMiniDetailsGetter().getCommitData(rowIndex, this); - } - - @Nullable - public VcsFullCommitDetails getFullCommitDetails(int rowIndex) { - return myLogDataHolder.getCommitDetailsGetter().getCommitData(rowIndex, this); - } - - /** - * Requests the proper data provider to load more data from the log & recreate the model. - * @param onLoaded will be called upon task completion on the EDT. - */ - public void requestToLoadMore(@NotNull Runnable onLoaded) { - if (myLoadMoreWasRequested.compareAndSet(false, true) // Don't send the request to VCS twice - && myLoadMoreStage != LoadMoreStage.ALL_REQUESTED) { // or when everything possible is loaded - myUi.getTable().setPaintBusy(true); - myUi.getFilterer().requestVcs(myDataPack, myUi.getFilters(), myLoadMoreStage, onLoaded); - } - } - - @NotNull - @Override - public final Object getValueAt(int rowIndex, int columnIndex) { - if (rowIndex >= getRowCount() - 1) { - requestToLoadMore(EmptyRunnable.INSTANCE); - } - - VcsShortCommitDetails data = getShortDetails(rowIndex); - switch (columnIndex) { - case ROOT_COLUMN: - return getRoot(rowIndex); - case COMMIT_COLUMN: - return getCommitColumnCell(rowIndex, data); - case AUTHOR_COLUMN: - if (data == null) { - return ""; - } - else { - return data.getAuthor().getName(); - } - case DATE_COLUMN: - if (data == null || data.getTimestamp() < 0) { - return ""; - } - else { - return DateFormatUtil.formatDateTime(data.getTimestamp()); - } - default: - throw new IllegalArgumentException("columnIndex is " + columnIndex + " > " + (COLUMN_COUNT - 1)); - } - } - - /** - * Returns true if not all data has been loaded, i.e. there is sense to {@link #requestToLoadMore(Runnable) request more data}. - */ - public boolean canRequestMore() { - return !myUi.getFilters().isEmpty() && myLoadMoreStage != LoadMoreStage.ALL_REQUESTED; - } - - /** - * Returns Changes for commits at selected rows.
- * Rows are given in the order as they appear in the table, i. e. in reverse chronological order.
- * Changes can be returned as-is, i.e. with duplicate changes for a single file. - * @return Changes selected in all rows, or null if this data is not ready yet. - */ - @Nullable - public List getSelectedChanges(@NotNull List selectedRows) { - List changes = new ArrayList(); - for (int row : selectedRows) { - VcsFullCommitDetails commitData = getFullCommitDetails(row); - if (commitData == null || commitData instanceof LoadingDetails) { - return null; - } - changes.addAll(commitData.getChanges()); - } - return changes; - } - - @NotNull - public abstract VirtualFile getRoot(int rowIndex); - - @NotNull - protected abstract CommitColumnClass getCommitColumnCell(int index, @Nullable VcsShortCommitDetails details); - - @NotNull - protected abstract Class getCommitColumnClass(); - - /** - * Returns the Hash of the commit displayed in the given row. - * May be null if there is no commit in the row - * (such situations may appear, for example, if graph is filtered by branch, as described in IDEA-115442). - */ - @Nullable - public abstract Hash getHashAtRow(int row); - - /** - * Returns the row number containing the given commit, - * or -1 if the requested commit is not contained in this table model (possibly because not all data has been loaded). - */ - public abstract int getRowOfCommit(@NotNull Hash hash); - - /** - * Returns the number of the first row which contains a commit which hash starts with the given value, - * or -1 if no such commit was found (possibly because not all data has been loaded). - */ - public abstract int getRowOfCommitByPartOfHash(@NotNull String hash); - - @Override - public Class getColumnClass(int column) { - switch (column) { - case ROOT_COLUMN: - return VirtualFile.class; - case COMMIT_COLUMN: - return getCommitColumnClass(); - case AUTHOR_COLUMN: - return String.class; - case DATE_COLUMN: - return String.class; - default: - throw new IllegalArgumentException("columnIndex is " + column + " > " + (COLUMN_COUNT - 1)); - } - } - - @Override - public String getColumnName(int column) { - return COLUMN_NAMES[column]; - } - -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java deleted file mode 100644 index 575be9e5e183..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2000-2014 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.vcs.log.ui.tables; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.vcs.log.Hash; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.data.DataPack; -import com.intellij.vcs.log.data.LoadMoreStage; -import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.render.GraphCommitCell; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; - -public class EmptyTableModel extends AbstractVcsLogTableModel { - - public EmptyTableModel(@NotNull DataPack dataPack, @NotNull VcsLogDataHolder logDataHolder, - @NotNull VcsLogUiImpl ui, @NotNull LoadMoreStage loadMoreStage) { - super(logDataHolder, ui, dataPack, loadMoreStage); - } - - @Override - public int getRowCount() { - return 0; - } - - @NotNull - @Override - public VirtualFile getRoot(int rowIndex) { - throw new AssertionError("Root shouldn't be requested for empty table model. row: " + rowIndex); - } - - @NotNull - @Override - protected GraphCommitCell getCommitColumnCell(int index, @Nullable VcsShortCommitDetails details) { - return new GraphCommitCell("", Collections.emptyList()); - } - - @NotNull - @Override - protected Class getCommitColumnClass() { - return GraphCommitCell.class; - } - - @Nullable - @Override - public Hash getHashAtRow(int row) { - return null; - } - - @Override - public int getRowOfCommit(@NotNull Hash hash) { - return -1; - } - - @Override - public int getRowOfCommitByPartOfHash(@NotNull String hash) { - return -1; - } - -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index 80ed236cb330..5d9e06b91a22 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -2,62 +2,63 @@ package com.intellij.vcs.log.ui.tables; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.EmptyRunnable; +import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.DateFormatUtil; import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsRef; import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.data.DataPack; -import com.intellij.vcs.log.data.LoadMoreStage; +import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.render.GraphCommitCell; +import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.impl.VcsLogUtil; import com.intellij.vcs.log.ui.VcsLogUiImpl; +import com.intellij.vcs.log.ui.render.GraphCommitCell; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -public class GraphTableModel extends AbstractVcsLogTableModel { +public class GraphTableModel extends AbstractTableModel { private static final Logger LOG = Logger.getInstance(GraphTableModel.class); - @NotNull private final DataPack myDataPack; - @NotNull private final VcsLogDataHolder myDataHolder; + public static final int ROOT_COLUMN = 0; + public static final int COMMIT_COLUMN = 1; + public static final int AUTHOR_COLUMN = 2; + public static final int DATE_COLUMN = 3; + private static final int COLUMN_COUNT = DATE_COLUMN + 1; + private static final String[] COLUMN_NAMES = {"", "Subject", "Author", "Date"}; - public GraphTableModel(@NotNull DataPack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI, - @NotNull LoadMoreStage loadMoreStage) { - super(dataHolder, UI, dataPack, loadMoreStage); + @NotNull protected final VcsLogUiImpl myUi; + @NotNull protected final VisiblePack myDataPack; + @NotNull private final VcsLogDataHolder myDataHolder; + @NotNull private final VcsLogDataHolder myLogDataHolder; + + private boolean myMoreRequested; + + public GraphTableModel(@NotNull VisiblePack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI) { + myLogDataHolder = dataHolder; + myUi = UI; myDataPack = dataPack; myDataHolder = dataHolder; } @Override public int getRowCount() { - return myDataPack.getGraphFacade().getVisibleCommitCount(); - } - - @Override - public void requestToLoadMore(@NotNull Runnable onLoaded) { - if (!myDataHolder.isFullLogShowing()) { - myDataHolder.showFullLog(onLoaded); - } - else if (!myUi.getFilters().isEmpty()) { - super.requestToLoadMore(onLoaded); - } - } - - @Override - public boolean canRequestMore() { - return !myDataHolder.isFullLogShowing() || super.canRequestMore(); + return myDataPack.getVisibleGraph().getVisibleCommitCount(); } @NotNull - @Override public VirtualFile getRoot(int rowIndex) { - int head = myDataPack.getGraphFacade().getInfoProvider().getRowInfo(rowIndex).getOneOfHeads(); + int head = myDataPack.getVisibleGraph().getRowInfo(rowIndex).getOneOfHeads(); Collection refs = myDataPack.getRefsModel().refsToCommit(head); if (refs.isEmpty()) { LOG.error("No references pointing to head " + head + " identified for commit at row " + rowIndex); @@ -68,7 +69,6 @@ public class GraphTableModel extends AbstractVcsLogTableModel { } @NotNull - @Override protected GraphCommitCell getCommitColumnCell(int rowIndex, @Nullable VcsShortCommitDetails details) { String message = ""; List refs = Collections.emptyList(); @@ -79,22 +79,14 @@ public class GraphTableModel extends AbstractVcsLogTableModel { return new GraphCommitCell(message, refs); } - @NotNull - @Override - protected Class getCommitColumnClass() { - return GraphCommitCell.class; - } - @Nullable - @Override public Hash getHashAtRow(int row) { - return myDataHolder.getHash(myDataPack.getGraphFacade().getCommitAtRow(row)); + return myDataHolder.getHash(myDataPack.getVisibleGraph().getRowInfo(row).getCommit()); } - @Override public int getRowOfCommit(@NotNull final Hash hash) { final int commitIndex = myDataHolder.getCommitIndex(hash); - return ContainerUtil.indexOf(VcsLogUtil.getVisibleCommits(myDataPack.getGraphFacade()), new Condition() { + return ContainerUtil.indexOf(VcsLogUtil.getVisibleCommits(myDataPack.getVisibleGraph()), new Condition() { @Override public boolean value(Integer integer) { return integer == commitIndex; @@ -102,10 +94,112 @@ public class GraphTableModel extends AbstractVcsLogTableModel { }); } - @Override public int getRowOfCommitByPartOfHash(@NotNull String partialHash) { - Hash hash = myDataHolder.findHashByString(partialHash); + Hash hash = myDataHolder.getHashMap().findHashByString(partialHash); return hash != null ? getRowOfCommit(hash) : -1; } + @Override + public final int getColumnCount() { + return COLUMN_COUNT; + } + + @Nullable + private VcsShortCommitDetails getShortDetails(int rowIndex) { + return myLogDataHolder.getMiniDetailsGetter().getCommitData(rowIndex, this); + } + + @Nullable + public VcsFullCommitDetails getFullCommitDetails(int rowIndex) { + return myLogDataHolder.getCommitDetailsGetter().getCommitData(rowIndex, this); + } + + /** + * Requests the proper data provider to load more data from the log & recreate the model. + * @param onLoaded will be called upon task completion on the EDT. + */ + public void requestToLoadMore(@NotNull Runnable onLoaded) { + myMoreRequested = true; + myUi.getFilterer().moreCommitsNeeded(onLoaded); + myUi.getTable().setPaintBusy(true); + } + + @NotNull + @Override + public final Object getValueAt(int rowIndex, int columnIndex) { + if (rowIndex >= getRowCount() - 1 && canRequestMore()) { + requestToLoadMore(EmptyRunnable.INSTANCE); + } + + VcsShortCommitDetails data = getShortDetails(rowIndex); + switch (columnIndex) { + case ROOT_COLUMN: + return getRoot(rowIndex); + case COMMIT_COLUMN: + return getCommitColumnCell(rowIndex, data); + case AUTHOR_COLUMN: + if (data == null) { + return ""; + } + else { + return data.getAuthor().getName(); + } + case DATE_COLUMN: + if (data == null || data.getTimestamp() < 0) { + return ""; + } + else { + return DateFormatUtil.formatDateTime(data.getTimestamp()); + } + default: + throw new IllegalArgumentException("columnIndex is " + columnIndex + " > " + (COLUMN_COUNT - 1)); + } + } + + /** + * Returns true if not all data has been loaded, i.e. there is sense to {@link #requestToLoadMore(Runnable) request more data}. + */ + public boolean canRequestMore() { + return !myMoreRequested && myDataPack.canRequestMore(); + } + + /** + * Returns Changes for commits at selected rows.
+ * Rows are given in the order as they appear in the table, i. e. in reverse chronological order.
+ * Changes can be returned as-is, i.e. with duplicate changes for a single file. + * @return Changes selected in all rows, or null if this data is not ready yet. + */ + @Nullable + public List getSelectedChanges(@NotNull List selectedRows) { + List changes = new ArrayList(); + for (int row : selectedRows) { + VcsFullCommitDetails commitData = getFullCommitDetails(row); + if (commitData == null || commitData instanceof LoadingDetails) { + return null; + } + changes.addAll(commitData.getChanges()); + } + return changes; + } + + @Override + public Class getColumnClass(int column) { + switch (column) { + case ROOT_COLUMN: + return VirtualFile.class; + case COMMIT_COLUMN: + return GraphCommitCell.class; + case AUTHOR_COLUMN: + return String.class; + case DATE_COLUMN: + return String.class; + default: + throw new IllegalArgumentException("columnIndex is " + column + " > " + (COLUMN_COUNT - 1)); + } + } + + @Override + public String getColumnName(int column) { + return COLUMN_NAMES[column]; + } } diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java index 01705232a253..2e18a39cd69a 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java @@ -174,7 +174,8 @@ public class VcsLogRefresherTest extends VcsLogPlatformTest { private VcsLogRefresherImpl createLoader(DataWaiter dataWaiter) { myDataHolder = new VcsLogDataHolder(myProject, myProject, myLogProviders, - ServiceManager.getService(myProject, VcsLogSettings.class), dataWaiter); + ServiceManager.getService(myProject, VcsLogSettings.class), + ServiceManager.getService(myProject, VcsLogUiProperties.class), Consumer.EMPTY_CONSUMER); return new VcsLogRefresherImpl(myProject, myDataHolder.getHashMap(), myLogProviders, myDataHolder.getUserRegistry(), myTopDetailsCache, dataWaiter, FAILING_EXCEPTION_HANDLER, RECENT_COMMITS_COUNT); }