/* * Copyright 2000-2015 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.filter; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.impl.SingletonRefGroup; import com.intellij.vcs.log.impl.VcsLogUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; public abstract class BranchPopupBuilder { @NotNull private final VcsLogDataPack myDataPack; @Nullable private final Collection<VirtualFile> myVisibleRoots; @Nullable private final List<List<String>> myRecentItems; protected BranchPopupBuilder(@NotNull VcsLogDataPack dataPack, @Nullable Collection<VirtualFile> visibleRoots, @Nullable List<List<String>> recentItems) { myDataPack = dataPack; myVisibleRoots = visibleRoots; myRecentItems = recentItems; } @NotNull protected abstract AnAction createAction(@NotNull String name); protected void createRecentAction(@NotNull DefaultActionGroup actionGroup, @NotNull List<String> recentItem) { assert myRecentItems == null; } @NotNull protected AnAction createCollapsedAction(String actionName) { return createAction(actionName); } public ActionGroup build() { return createActions(prepareGroups(myDataPack, myVisibleRoots, myRecentItems)); } private static Groups prepareGroups(@NotNull VcsLogDataPack dataPack, @Nullable Collection<VirtualFile> visibleRoots, @Nullable List<List<String>> recentItems) { Groups filteredGroups = new Groups(); Collection<VcsRef> allRefs = dataPack.getRefs().getBranches(); for (Map.Entry<VirtualFile, Set<VcsRef>> entry : VcsLogUtil.groupRefsByRoot(allRefs).entrySet()) { VirtualFile root = entry.getKey(); if (visibleRoots != null && !visibleRoots.contains(root)) continue; Collection<VcsRef> refs = entry.getValue(); VcsLogProvider provider = dataPack.getLogProviders().get(root); VcsLogRefManager refManager = provider.getReferenceManager(); List<RefGroup> refGroups = refManager.groupForBranchFilter(refs); putActionsForReferences(refGroups, filteredGroups); } if (recentItems != null) { for (List<String> recentItem : recentItems) { if (recentItem.size() == 1) { final String item = ContainerUtil.getFirstItem(recentItem); if (filteredGroups.singletonGroups.contains(item) || ContainerUtil.find(filteredGroups.expandedGroups.values(), strings -> strings.contains(item)) != null) { continue; } } filteredGroups.recentGroups.add(recentItem); } } return filteredGroups; } private DefaultActionGroup createActions(@NotNull Groups groups) { DefaultActionGroup actionGroup = new DefaultActionGroup(); for (String actionName : groups.singletonGroups) { actionGroup.add(createAction(actionName)); } if (!groups.recentGroups.isEmpty()) { actionGroup.addSeparator("Recent"); for (List<String> recentItem : groups.recentGroups) { createRecentAction(actionGroup, recentItem); } } for (Map.Entry<String, TreeSet<String>> group : groups.expandedGroups.entrySet()) { actionGroup.addSeparator(group.getKey()); for (String actionName : group.getValue()) { actionGroup.add(createAction(actionName)); } } actionGroup.addSeparator(); for (Map.Entry<String, TreeSet<String>> group : groups.collapsedGroups.entrySet()) { DefaultActionGroup popupGroup = new DefaultActionGroup(group.getKey(), true); for (String actionName : group.getValue()) { popupGroup.add(createCollapsedAction(actionName)); } actionGroup.add(popupGroup); } return actionGroup; } private static class Groups { private final TreeSet<String> singletonGroups = ContainerUtil.newTreeSet(); private final List<List<String>> recentGroups = ContainerUtil.newArrayList(); private final TreeMap<String, TreeSet<String>> expandedGroups = ContainerUtil.newTreeMap(); private final TreeMap<String, TreeSet<String>> collapsedGroups = ContainerUtil.newTreeMap(); } private static void putActionsForReferences(List<RefGroup> references, Groups actions) { for (final RefGroup refGroup : references) { if (refGroup instanceof SingletonRefGroup) { actions.singletonGroups.add(refGroup.getName()); } else if (refGroup.isExpanded()) { addToGroup(refGroup, actions.expandedGroups); } else { addToGroup(refGroup, actions.collapsedGroups); } } } private static void addToGroup(final RefGroup refGroup, TreeMap<String, TreeSet<String>> groupToAdd) { TreeSet<String> groupActions = groupToAdd.computeIfAbsent(refGroup.getName(), key -> new TreeSet<>()); for (VcsRef ref : refGroup.getRefs()) { groupActions.add(ref.getName()); } } }