/* * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.openapi.vcs.changes.actions; import com.intellij.icons.AllIcons; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.ui.ChangeListChooser; import com.intellij.openapi.vcs.changes.ui.ChangesListView; import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import static com.intellij.util.containers.UtilKt.isEmpty; /** * @author max */ public class MoveChangesToAnotherListAction extends AnAction implements DumbAware { public MoveChangesToAnotherListAction() { super(ActionsBundle.actionText(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST), ActionsBundle.actionDescription(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST), AllIcons.Actions.MoveToAnotherChangelist); } public void update(@NotNull AnActionEvent e) { boolean isEnabled = isEnabled(e); if (ActionPlaces.isPopupPlace(e.getPlace())) { e.getPresentation().setEnabledAndVisible(isEnabled); } else { e.getPresentation().setEnabled(isEnabled); } } protected boolean isEnabled(@NotNull AnActionEvent e) { Project project = e.getData(CommonDataKeys.PROJECT); if (project == null || !ProjectLevelVcsManager.getInstance(project).hasActiveVcss()) { return false; } return !isEmpty(e.getData(ChangesListView.UNVERSIONED_FILES_DATA_KEY)) || !ArrayUtil.isEmpty(e.getData(VcsDataKeys.CHANGES)) || !ArrayUtil.isEmpty(e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)); } @NotNull private static List<Change> getChangesForSelectedFiles(@NotNull Project project, @NotNull VirtualFile[] selectedFiles, @NotNull List<VirtualFile> unversionedFiles, @NotNull List<VirtualFile> changedFiles) { List<Change> changes = new ArrayList<>(); ChangeListManager changeListManager = ChangeListManager.getInstance(project); for (VirtualFile vFile : selectedFiles) { Change change = changeListManager.getChange(vFile); if (change == null) { FileStatus status = changeListManager.getStatus(vFile); if (FileStatus.UNKNOWN.equals(status)) { unversionedFiles.add(vFile); changedFiles.add(vFile); } else if (FileStatus.NOT_CHANGED.equals(status) && vFile.isDirectory()) { addAllChangesUnderPath(changeListManager, VcsUtil.getFilePath(vFile), changes, changedFiles); } } else { FilePath afterPath = ChangesUtil.getAfterPath(change); if (afterPath != null && afterPath.isDirectory()) { addAllChangesUnderPath(changeListManager, afterPath, changes, changedFiles); } else { changes.add(change); changedFiles.add(vFile); } } } return changes; } private static void addAllChangesUnderPath(@NotNull ChangeListManager changeListManager, @NotNull FilePath file, @NotNull List<Change> changes, @NotNull List<VirtualFile> changedFiles) { for (Change change : changeListManager.getChangesIn(file)) { changes.add(change); FilePath path = ChangesUtil.getAfterPath(change); if (path != null && path.getVirtualFile() != null) { changedFiles.add(path.getVirtualFile()); } } } public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getRequiredData(CommonDataKeys.PROJECT); List<Change> changesList = ContainerUtil.newArrayList(); Change[] changes = e.getData(VcsDataKeys.CHANGES); if (changes != null) { ContainerUtil.addAll(changesList, changes); } List<VirtualFile> unversionedFiles = ContainerUtil.newArrayList(); final List<VirtualFile> changedFiles = ContainerUtil.newArrayList(); VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); if (files != null) { changesList.addAll(getChangesForSelectedFiles(project, files, unversionedFiles, changedFiles)); } if (changesList.isEmpty() && unversionedFiles.isEmpty()) { VcsBalloonProblemNotifier.showOverChangesView(project, "Nothing is selected that can be moved", MessageType.INFO); return; } if (!askAndMove(project, changesList, unversionedFiles)) return; if (!changedFiles.isEmpty()) { selectAndShowFile(project, changedFiles.get(0)); } } private static void selectAndShowFile(@NotNull final Project project, @NotNull final VirtualFile file) { ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ChangesViewContentManager.TOOLWINDOW_ID); if (!window.isVisible()) { window.activate(() -> ChangesViewManager.getInstance(project).selectFile(file)); } } public static boolean askAndMove(@NotNull Project project, @NotNull Collection<Change> changes, @NotNull List<VirtualFile> unversionedFiles) { if (changes.isEmpty() && unversionedFiles.isEmpty()) return false; LocalChangeList targetList = askTargetList(project, changes); if (targetList != null) { ChangeListManagerImpl listManager = ChangeListManagerImpl.getInstanceImpl(project); listManager.moveChangesTo(targetList, ArrayUtil.toObjectArray(changes, Change.class)); if (!unversionedFiles.isEmpty()) { listManager.addUnversionedFiles(targetList, unversionedFiles); } return true; } return false; } @Nullable private static LocalChangeList askTargetList(@NotNull Project project, @NotNull Collection<Change> changes) { ChangeListManagerImpl listManager = ChangeListManagerImpl.getInstanceImpl(project); List<LocalChangeList> preferredLists = getPreferredLists(listManager.getChangeListsCopy(), changes); List<LocalChangeList> listsForChooser = preferredLists.isEmpty() ? Collections.singletonList(listManager.getDefaultChangeList()) : preferredLists; ChangeListChooser chooser = new ChangeListChooser(project, listsForChooser, guessPreferredList(preferredLists), ActionsBundle.message("action.ChangesView.Move.text"), null); chooser.show(); return chooser.getSelectedList(); } @Nullable private static ChangeList guessPreferredList(@NotNull List<LocalChangeList> lists) { LocalChangeList activeChangeList = ContainerUtil.find(lists, LocalChangeList::isDefault); if (activeChangeList != null) return activeChangeList; LocalChangeList emptyList = ContainerUtil.find(lists, list -> list.getChanges().isEmpty()); return ObjectUtils.chooseNotNull(emptyList, ContainerUtil.getFirstItem(lists)); } @NotNull private static List<LocalChangeList> getPreferredLists(@NotNull List<LocalChangeList> lists, @NotNull Collection<Change> changes) { final Set<Change> changesSet = ContainerUtil.newHashSet(changes); return ContainerUtil.findAll(lists, list -> !ContainerUtil.intersects(changesSet, list.getChanges())); } }