collect changes to revert in affected patch dialog
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / ui / ChangesBrowser.java
blobb0284ab55d6fd6c98ada9a67be6be7f8728f9aa0
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.openapi.vcs.changes.ui;
18 import com.intellij.openapi.actionSystem.*;
19 import com.intellij.openapi.actionSystem.ex.CheckboxAction;
20 import com.intellij.openapi.application.ModalityState;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.vcs.FilePath;
23 import com.intellij.openapi.vcs.VcsBundle;
24 import com.intellij.openapi.vcs.VcsDataKeys;
25 import com.intellij.openapi.vcs.changes.*;
26 import com.intellij.openapi.vcs.changes.actions.ShowDiffAction;
27 import com.intellij.openapi.vfs.VirtualFile;
28 import com.intellij.ui.SeparatorFactory;
29 import org.jetbrains.annotations.Nullable;
31 import javax.swing.*;
32 import javax.swing.tree.DefaultTreeModel;
33 import java.awt.*;
34 import java.io.File;
35 import java.util.*;
36 import java.util.List;
38 /**
39 * @author max
41 public class ChangesBrowser extends JPanel implements TypeSafeDataProvider {
42 protected final ChangesTreeList<Change> myViewer;
43 protected ChangeList mySelectedChangeList;
44 protected Collection<Change> myChangesToDisplay;
45 protected final Project myProject;
46 private final boolean myCapableOfExcludingChanges;
47 protected final JPanel myHeaderPanel;
48 private DefaultActionGroup myToolBarGroup;
49 private final JPanel myListPanel;
50 private ShowDiffAction.DiffExtendUIFactory myDiffExtendUIFactory = new DiffToolbarActionsFactory();
51 private String myToggleActionTitle = VcsBundle.message("commit.dialog.include.action.name");
53 public static DataKey<ChangesBrowser> DATA_KEY = DataKey.create("com.intellij.openapi.vcs.changes.ui.ChangesBrowser");
54 private ShowDiffAction myDiffAction;
56 public void setChangesToDisplay(final List<Change> changes) {
57 myChangesToDisplay = changes;
58 myViewer.setChangesToDisplay(changes);
61 public ChangesBrowser(final Project project, List<? extends ChangeList> changeLists, final List<Change> changes,
62 ChangeList initialListSelection, final boolean capableOfExcludingChanges, final boolean highlightProblems,
63 @Nullable final Runnable inclusionListener, final MyUseCase useCase) {
64 super(new BorderLayout());
66 myProject = project;
67 myCapableOfExcludingChanges = capableOfExcludingChanges;
69 final ChangeNodeDecorator decorator = MyUseCase.LOCAL_CHANGES.equals(useCase) ?
70 RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator() : null;
72 myViewer = new ChangesTreeList<Change>(myProject, changes, capableOfExcludingChanges, highlightProblems, inclusionListener, decorator) {
73 protected DefaultTreeModel buildTreeModel(final List<Change> changes, ChangeNodeDecorator changeNodeDecorator) {
74 TreeModelBuilder builder = new TreeModelBuilder(myProject, false);
75 return builder.buildModel(changes, changeNodeDecorator);
78 protected List<Change> getSelectedObjects(final ChangesBrowserNode<Change> node) {
79 return node.getAllChangesUnder();
82 @Nullable
83 protected Change getLeadSelectedObject(final ChangesBrowserNode node) {
84 final Object o = node.getUserObject();
85 if (o instanceof Change) {
86 return (Change) o;
88 return null;
92 myViewer.setDoubleClickHandler(new Runnable() {
93 public void run() {
94 showDiff();
96 });
98 setInitialSelection(changeLists, changes, initialListSelection);
99 rebuildList();
101 myListPanel = new JPanel(new BorderLayout());
102 myListPanel.add(myViewer, BorderLayout.CENTER);
104 JComponent separator = SeparatorFactory.createSeparator(VcsBundle.message("commit.dialog.changed.files.label"), myViewer);
105 myListPanel.add(separator, BorderLayout.NORTH);
106 add(myListPanel, BorderLayout.CENTER);
108 myHeaderPanel = new JPanel(new BorderLayout());
109 myHeaderPanel.add(createToolbar(), BorderLayout.CENTER);
110 add(myHeaderPanel, BorderLayout.NORTH);
112 myViewer.installPopupHandler(myToolBarGroup);
115 protected void setInitialSelection(final List<? extends ChangeList> changeLists, final List<Change> changes, final ChangeList initialListSelection) {
116 mySelectedChangeList = initialListSelection;
119 public void dispose() {
122 public void addToolbarAction(AnAction action) {
123 myToolBarGroup.add(action);
126 public void addToolbarActions(ActionGroup group) {
127 myToolBarGroup.addSeparator();
128 myToolBarGroup.add(group);
131 public ShowDiffAction.DiffExtendUIFactory getDiffExtendUIFactory() {
132 return myDiffExtendUIFactory;
135 public void setDiffExtendUIFactory(final ShowDiffAction.DiffExtendUIFactory diffExtendUIFactory) {
136 myDiffExtendUIFactory = diffExtendUIFactory;
139 public void setToggleActionTitle(final String toggleActionTitle) {
140 myToggleActionTitle = toggleActionTitle;
143 public JPanel getHeaderPanel() {
144 return myHeaderPanel;
147 public JPanel getListPanel() {
148 return myListPanel;
151 public void calcData(DataKey key, DataSink sink) {
152 if (key == VcsDataKeys.CHANGES) {
153 final List<Change> list = myViewer.getSelectedChanges();
154 sink.put(VcsDataKeys.CHANGES, list.toArray(new Change [list.size()]));
156 else if (key == VcsDataKeys.CHANGE_LISTS) {
157 sink.put(VcsDataKeys.CHANGE_LISTS, getSelectedChangeLists());
159 else if (key == VcsDataKeys.CHANGE_LEAD_SELECTION) {
160 final Change highestSelection = myViewer.getHighestLeadSelection();
161 sink.put(VcsDataKeys.CHANGE_LEAD_SELECTION, (highestSelection == null) ? new Change[]{} : new Change[] {highestSelection});
162 } else if (key == PlatformDataKeys.VIRTUAL_FILE_ARRAY) {
163 sink.put(PlatformDataKeys.VIRTUAL_FILE_ARRAY, getSelectedFiles());
165 else if (key == PlatformDataKeys.NAVIGATABLE_ARRAY) {
166 sink.put(PlatformDataKeys.NAVIGATABLE_ARRAY, ChangesUtil.getNavigatableArray(myProject, getSelectedFiles()));
167 } else if (VcsDataKeys.IO_FILE_ARRAY.equals(key)) {
168 sink.put(VcsDataKeys.IO_FILE_ARRAY, getSelectedIoFiles());
170 else if (key == DATA_KEY) {
171 sink.put(DATA_KEY, this);
172 } else if (VcsDataKeys.SELECTED_CHANGES_IN_DETAILS.equals(key)) {
173 final List<Change> selectedChanges = getSelectedChanges();
174 sink.put(VcsDataKeys.SELECTED_CHANGES_IN_DETAILS, selectedChanges.toArray(new Change[selectedChanges.size()]));
178 private class ToggleChangeAction extends CheckboxAction {
179 private final Change myChange;
181 public ToggleChangeAction(final Change change) {
182 super(myToggleActionTitle);
183 myChange = change;
186 public boolean isSelected(AnActionEvent e) {
187 return myViewer.isIncluded(myChange);
190 public void setSelected(AnActionEvent e, boolean state) {
191 if (state) {
192 myViewer.includeChange(myChange);
194 else {
195 myViewer.excludeChange(myChange);
200 protected void showDiffForChanges(Change[] changesArray, final int indexInSelection) {
201 ShowDiffAction.showDiffForChange(changesArray, indexInSelection, myProject, myDiffExtendUIFactory, isInFrame());
204 private void showDiff() {
205 final Change leadSelection = myViewer.getLeadSelection();
206 List<Change> changes = myViewer.getSelectedChanges();
208 if (changes.size() < 2) {
209 final Collection<Change> displayedChanges = getCurrentDisplayedChanges();
210 changes = new ArrayList<Change>(displayedChanges);
213 int indexInSelection = changes.indexOf(leadSelection);
214 if (indexInSelection >= 0) {
215 Change[] changesArray = changes.toArray(new Change[changes.size()]);
216 showDiffForChanges(changesArray, indexInSelection);
218 else if ((leadSelection == null && changes.size() > 0)) {
219 Change[] changesArray = changes.toArray(new Change[changes.size()]);
220 showDiffForChanges(changesArray, 0);
222 else if (leadSelection != null) {
223 showDiffForChanges(new Change[]{leadSelection}, 0);
227 private static boolean isInFrame() {
228 return ModalityState.current().equals(ModalityState.NON_MODAL);
231 private class DiffToolbarActionsFactory implements ShowDiffAction.DiffExtendUIFactory {
232 public List<? extends AnAction> createActions(Change change) {
233 return createDiffActions(change);
236 @Nullable
237 public JComponent createBottomComponent() {
238 return null;
242 protected List<AnAction> createDiffActions(final Change change) {
243 List<AnAction> actions = new ArrayList<AnAction>();
244 if (myCapableOfExcludingChanges) {
245 actions.add(new ToggleChangeAction(change));
247 return actions;
250 public void rebuildList() {
251 myViewer.setChangesToDisplay(getCurrentDisplayedChanges());
254 private JComponent createToolbar() {
255 DefaultActionGroup toolbarGroups = new DefaultActionGroup();
256 myToolBarGroup = new DefaultActionGroup();
257 toolbarGroups.add(myToolBarGroup);
258 buildToolBar(myToolBarGroup);
260 toolbarGroups.addSeparator();
261 DefaultActionGroup treeActionsGroup = new DefaultActionGroup();
262 toolbarGroups.add(treeActionsGroup);
263 for(AnAction action: myViewer.getTreeActions()) {
264 treeActionsGroup.add(action);
267 return ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarGroups, true).getComponent();
270 protected void buildToolBar(final DefaultActionGroup toolBarGroup) {
271 myDiffAction = new ShowDiffAction() {
272 public void actionPerformed(AnActionEvent e) {
273 showDiff();
276 myDiffAction.registerCustomShortcutSet(CommonShortcuts.getDiff(), myViewer);
277 toolBarGroup.add(myDiffAction);
280 public List<Change> getCurrentDisplayedChanges() {
281 final List<Change> list;
282 if (myChangesToDisplay != null) {
283 list = new ArrayList<Change>(myChangesToDisplay);
285 else if (mySelectedChangeList != null) {
286 list = new ArrayList<Change>(mySelectedChangeList.getChanges());
288 else {
289 list = Collections.emptyList();
291 return sortChanges(list);
294 protected static List<Change> sortChanges(final List<Change> list) {
295 Collections.sort(list, new Comparator<Change>() {
296 public int compare(final Change o1, final Change o2) {
297 return ChangesUtil.getFilePath(o1).getName().compareToIgnoreCase(ChangesUtil.getFilePath(o2).getName());
300 return list;
303 public ChangeList getSelectedChangeList() {
304 return mySelectedChangeList;
307 public JComponent getPrefferedFocusComponent() {
308 return myViewer;
311 private ChangeList[] getSelectedChangeLists() {
312 if (mySelectedChangeList != null) {
313 return new ChangeList[]{mySelectedChangeList};
315 return null;
318 private File[] getSelectedIoFiles() {
319 final List<Change> changes = myViewer.getSelectedChanges();
320 final List<File> files = new ArrayList<File>();
321 for (Change change : changes) {
322 final ContentRevision afterRevision = change.getAfterRevision();
323 if (afterRevision != null) {
324 final FilePath file = afterRevision.getFile();
325 final File ioFile = file.getIOFile();
326 files.add(ioFile);
329 return files.toArray(new File[files.size()]);
332 public List<Change> getSelectedChanges() {
333 return myViewer.getSelectedChanges();
336 private VirtualFile[] getSelectedFiles() {
337 final List<Change> changes = myViewer.getSelectedChanges();
338 return ChangesUtil.getFilesFromChanges(changes);
341 public ShowDiffAction getDiffAction() {
342 return myDiffAction;
345 protected static enum MyUseCase {
346 LOCAL_CHANGES,
347 COMMITTED_CHANGES