| /* |
| * Copyright 2000-2012 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. |
| */ |
| |
| /* |
| * Created by IntelliJ IDEA. |
| * User: yole |
| * Date: 28.11.2006 |
| * Time: 14:15:18 |
| */ |
| package com.intellij.openapi.vcs.changes.ui; |
| |
| import com.intellij.icons.AllIcons; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.actionSystem.*; |
| import com.intellij.openapi.actionSystem.ex.AnActionListener; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.application.ModalityState; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.DialogWrapper; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.vcs.AbstractVcs; |
| import com.intellij.openapi.vcs.ProjectLevelVcsManager; |
| import com.intellij.openapi.vcs.VcsBundle; |
| import com.intellij.openapi.vcs.changes.*; |
| import com.intellij.openapi.vcs.changes.actions.MoveChangesToAnotherListAction; |
| import com.intellij.openapi.vcs.changes.actions.RollbackDialogAction; |
| import com.intellij.ui.ColoredListCellRendererWrapper; |
| import com.intellij.ui.SimpleTextAttributes; |
| import com.intellij.util.EventDispatcher; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.event.ItemEvent; |
| import java.awt.event.ItemListener; |
| import java.util.*; |
| import java.util.List; |
| |
| public class MultipleChangeListBrowser extends ChangesBrowser { |
| private final ChangeListChooser myChangeListChooser; |
| private final ChangeListListener myChangeListListener = new MyChangeListListener(); |
| private final boolean myShowingAllChangeLists; |
| private final EventDispatcher<SelectedListChangeListener> myDispatcher = EventDispatcher.create(SelectedListChangeListener.class); |
| private Collection<Change> myAllChanges; |
| private Map<Change, LocalChangeList> myChangeListsMap; |
| |
| private final ChangesBrowserExtender myExtender; |
| private final Disposable myParentDisposable; |
| private final Runnable myRebuildListListener; |
| |
| // todo terrible constructor |
| public MultipleChangeListBrowser(final Project project, final List<? extends ChangeList> changeLists, final List<Change> changes, |
| Disposable parentDisposable, |
| final ChangeList initialListSelection, |
| final boolean capableOfExcludingChanges, |
| final boolean highlightProblems, final Runnable rebuildListListener, @Nullable final Runnable inclusionListener, |
| final AnAction... additionalActions) { |
| super(project, changeLists, changes, initialListSelection, capableOfExcludingChanges, highlightProblems, inclusionListener, MyUseCase.LOCAL_CHANGES, null); |
| myParentDisposable = parentDisposable; |
| myRebuildListListener = rebuildListListener; |
| |
| myChangeListChooser = new ChangeListChooser(changeLists); |
| myHeaderPanel.add(myChangeListChooser, BorderLayout.EAST); |
| myShowingAllChangeLists = Comparing.haveEqualElements((List<LocalChangeList>) changeLists, ChangeListManager.getInstance(project).getChangeLists()); |
| ChangeListManager.getInstance(myProject).addChangeListListener(myChangeListListener); |
| |
| myExtender = new Extender(project, this, additionalActions); |
| |
| ActionManager actionManager = ActionManager.getInstance(); |
| final AnAction moveAction = actionManager.getAction(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST); |
| actionManager.addAnActionListener(new AnActionListener.Adapter() { |
| @Override |
| public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { |
| if (moveAction.equals(action)) { |
| rebuildList(); |
| } |
| } |
| }, myParentDisposable); |
| |
| } |
| |
| @Override |
| protected void setInitialSelection(final List<? extends ChangeList> changeLists, final List<Change> changes, final ChangeList initialListSelection) { |
| myAllChanges = new ArrayList<Change>(); |
| mySelectedChangeList = initialListSelection; |
| |
| for (ChangeList list : changeLists) { |
| if (list instanceof LocalChangeList) { |
| myAllChanges.addAll(list.getChanges()); |
| if (initialListSelection == null) { |
| for(Change c: list.getChanges()) { |
| if (changes.contains(c)) { |
| mySelectedChangeList = list; |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| if (mySelectedChangeList == null) { |
| for(ChangeList list: changeLists) { |
| if (list instanceof LocalChangeList && ((LocalChangeList) list).isDefault()) { |
| mySelectedChangeList = list; |
| break; |
| } |
| } |
| if (mySelectedChangeList == null && !changeLists.isEmpty()) { |
| mySelectedChangeList = changeLists.get(0); |
| } |
| } |
| } |
| |
| @Override |
| public void dispose() { |
| ChangeListManager.getInstance(myProject).removeChangeListListener(myChangeListListener); |
| } |
| |
| public Collection<Change> getAllChanges() { |
| return myAllChanges; |
| } |
| |
| public ChangesBrowserExtender getExtender() { |
| return myExtender; |
| } |
| |
| public void addSelectedListChangeListener(SelectedListChangeListener listener) { |
| myDispatcher.addListener(listener); |
| } |
| |
| public void removeSelectedListChangeListener(SelectedListChangeListener listener) { |
| myDispatcher.removeListener(listener); |
| } |
| |
| private void setSelectedList(final ChangeList list) { |
| mySelectedChangeList = list; |
| rebuildList(); |
| myDispatcher.getMulticaster().selectedListChanged(); |
| } |
| |
| private boolean myInRebuildList; |
| |
| @Override |
| public void rebuildList() { |
| if (myInRebuildList) return; |
| try { |
| myInRebuildList = true; |
| if (myChangesToDisplay == null) { |
| // changes set not fixed === local changes |
| final ChangeListManager manager = ChangeListManager.getInstance(myProject); |
| myChangeListsMap = new HashMap<Change, LocalChangeList>(); |
| final List<LocalChangeList> lists = manager.getChangeListsCopy(); |
| Collection<Change> allChanges = new ArrayList<Change>(); |
| for (LocalChangeList list : lists) { |
| final Collection<Change> changes = list.getChanges(); |
| allChanges.addAll(changes); |
| for (Change change : changes) { |
| myChangeListsMap.put(change, list); |
| } |
| } |
| myAllChanges = allChanges; |
| // refresh selected list also |
| updateListsInChooser(); |
| } |
| |
| super.rebuildList(); |
| if (myRebuildListListener != null) { |
| myRebuildListListener.run(); |
| } |
| } finally { |
| myInRebuildList = false; |
| } |
| } |
| |
| @Override |
| public List<Change> getCurrentDisplayedChanges() { |
| if (myChangesToDisplay == null) { |
| return sortChanges(filterBySelectedChangeList(myAllChanges)); |
| } |
| return super.getCurrentDisplayedChanges(); |
| } |
| |
| @NotNull |
| public List<Change> getCurrentIncludedChanges() { |
| return filterBySelectedChangeList(myViewer.getIncludedChanges()); |
| } |
| |
| @NotNull |
| public Collection<Change> getChangesIncludedInAllLists() { |
| return myViewer.getIncludedChanges(); |
| } |
| |
| private List<Change> filterBySelectedChangeList(final Collection<Change> changes) { |
| List<Change> filtered = new ArrayList<Change>(); |
| for (Change change : changes) { |
| if (Comparing.equal(getList(change), mySelectedChangeList)) { |
| filtered.add(change); |
| } |
| } |
| return filtered; |
| } |
| |
| private ChangeList getList(final Change change) { |
| return myChangeListsMap.get(change); |
| } |
| |
| @Override |
| protected void buildToolBar(final DefaultActionGroup toolBarGroup) { |
| super.buildToolBar(toolBarGroup); |
| |
| ActionManager actionManager = ActionManager.getInstance(); |
| final AnAction moveAction = actionManager.getAction(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST); |
| moveAction.registerCustomShortcutSet(CommonShortcuts.getMove(), myViewer); |
| toolBarGroup.add(moveAction); |
| } |
| |
| @Override |
| protected List<AnAction> createDiffActions(final Change change) { |
| List<AnAction> actions = super.createDiffActions(change); |
| actions.add(new MoveAction(change)); |
| return actions; |
| } |
| |
| private class ChangeListChooser extends JPanel { |
| private final JComboBox myChooser; |
| private final static int MAX_LEN = 35; |
| |
| public ChangeListChooser(List<? extends ChangeList> lists) { |
| super(new BorderLayout(4, 2)); |
| myChooser = new JComboBox(); |
| myChooser.setRenderer(new ColoredListCellRendererWrapper<LocalChangeList>() { |
| @Override |
| protected void doCustomize(JList list, LocalChangeList value, int index, boolean selected, boolean hasFocus) { |
| if (value != null) { |
| String name = value.getName().trim(); |
| if (name.length() > MAX_LEN) { |
| name = name.substring(0, MAX_LEN - 3) + "..."; |
| } |
| append(name, value.isDefault() ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); |
| } |
| } |
| }); |
| |
| myChooser.addItemListener(new ItemListener() { |
| public void itemStateChanged(ItemEvent e) { |
| if (e.getStateChange() == ItemEvent.SELECTED) { |
| final LocalChangeList changeList = (LocalChangeList)myChooser.getSelectedItem(); |
| setSelectedList(changeList); |
| myChooser.setToolTipText(changeList == null ? "" : (changeList.getName())); |
| } |
| } |
| }); |
| |
| updateLists(lists); |
| myChooser.setEditable(false); |
| add(myChooser, BorderLayout.CENTER); |
| |
| JLabel label = new JLabel(VcsBundle.message("commit.dialog.changelist.label")); |
| label.setLabelFor(myChooser); |
| add(label, BorderLayout.WEST); |
| } |
| |
| public void updateLists(List<? extends ChangeList> lists) { |
| myChooser.setModel(new DefaultComboBoxModel(lists.toArray())); |
| myChooser.setEnabled(lists.size() > 1); |
| if (lists.contains(mySelectedChangeList)) { |
| myChooser.setSelectedItem(mySelectedChangeList); |
| } else { |
| if (myChooser.getItemCount() > 0) { |
| myChooser.setSelectedIndex(0); |
| } |
| } |
| mySelectedChangeList = (ChangeList) myChooser.getSelectedItem(); |
| } |
| } |
| |
| private class MyChangeListListener extends ChangeListAdapter { |
| public void changeListAdded(ChangeList list) { |
| updateListsInChooser(); |
| } |
| } |
| |
| private void updateListsInChooser() { |
| Runnable runnable = new Runnable() { |
| public void run() { |
| if (myChangeListChooser != null && myShowingAllChangeLists) { |
| myChangeListChooser.updateLists(ChangeListManager.getInstance(myProject).getChangeListsCopy()); |
| } |
| } |
| }; |
| if (SwingUtilities.isEventDispatchThread()) { |
| runnable.run(); |
| } |
| else { |
| ApplicationManager.getApplication().invokeLater(runnable, ModalityState.stateForComponent(MultipleChangeListBrowser.this)); |
| } |
| } |
| |
| private class MoveAction extends MoveChangesToAnotherListAction { |
| private final Change myChange; |
| |
| public MoveAction(final Change change) { |
| myChange = change; |
| } |
| |
| public void actionPerformed(AnActionEvent e) { |
| askAndMove(myProject, Collections.singletonList(myChange), null); |
| } |
| } |
| |
| private static class Extender implements ChangesBrowserExtender { |
| private final Project myProject; |
| private final MultipleChangeListBrowser myBrowser; |
| private final AnAction[] myAdditionalActions; |
| |
| private Extender(final Project project, final MultipleChangeListBrowser browser, AnAction[] additionalActions) { |
| myProject = project; |
| myBrowser = browser; |
| myAdditionalActions = additionalActions; |
| } |
| |
| public void addToolbarActions(final DialogWrapper dialogWrapper) { |
| final Icon icon = AllIcons.Actions.Refresh; |
| if (myBrowser.myChangesToDisplay == null) { |
| myBrowser.addToolbarAction(new AnAction("Refresh Changes") { |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| myBrowser.rebuildList(); |
| } |
| |
| @Override |
| public void update(AnActionEvent e) { |
| e.getPresentation().setIcon(icon); |
| } |
| }); |
| } |
| RollbackDialogAction rollback = new RollbackDialogAction(); |
| EmptyAction.setupAction(rollback, IdeActions.CHANGES_VIEW_ROLLBACK, myBrowser); |
| myBrowser.addToolbarAction(rollback); |
| |
| final EditSourceInCommitAction editSourceAction = new EditSourceInCommitAction(dialogWrapper); |
| editSourceAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), myBrowser); |
| myBrowser.addToolbarAction(editSourceAction); |
| |
| myBrowser.addToolbarAction(ActionManager.getInstance().getAction("Vcs.CheckinProjectToolbar")); |
| |
| final List<AnAction> actions = AdditionalLocalChangeActionsInstaller.calculateActions(myProject, myBrowser.getAllChanges()); |
| if (actions != null) { |
| for (AnAction action : actions) { |
| myBrowser.addToolbarAction(action); |
| } |
| } |
| if (myAdditionalActions != null && myAdditionalActions.length > 0) { |
| for (int i = 0; i < myAdditionalActions.length; i++) { |
| final AnAction action = myAdditionalActions[i]; |
| myBrowser.addToolbarAction(action); |
| } |
| } |
| } |
| |
| public void addSelectedListChangeListener(final SelectedListChangeListener listener) { |
| myBrowser.addSelectedListChangeListener(listener); |
| } |
| |
| public Collection<AbstractVcs> getAffectedVcses() { |
| final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); |
| final Set<AbstractVcs> vcses = new HashSet<AbstractVcs>(Arrays.asList(vcsManager.getAllActiveVcss())); |
| final Set<AbstractVcs> result = new HashSet<AbstractVcs>(); |
| for (Change change : myBrowser.myAllChanges) { |
| if (vcses.isEmpty()) break; |
| final AbstractVcs vcs = ChangesUtil.getVcsForChange(change, myBrowser.myProject); |
| if (vcs != null) { |
| result.add(vcs); |
| vcses.remove(vcs); |
| } |
| } |
| return result; |
| } |
| |
| public List<Change> getCurrentIncludedChanges() { |
| return myBrowser.getCurrentIncludedChanges(); |
| } |
| } |
| } |