blob: 34394ab5c9ccce0ac2b9b816c5b30575d7958024 [file] [log] [blame]
/*
* 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();
}
}
}