VCS: shelved changes: navigatable show diff
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / ui / ChangesBrowser.java
blobf873de6745f524cc65739ed2bc091f343fef3f7c
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.ArrayList;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.List;
40 /**
41 * @author max
43 public class ChangesBrowser extends JPanel implements TypeSafeDataProvider {
44 protected final ChangesTreeList<Change> myViewer;
45 protected ChangeList mySelectedChangeList;
46 protected Collection<Change> myChangesToDisplay;
47 protected final Project myProject;
48 private final boolean myCapableOfExcludingChanges;
49 protected final JPanel myHeaderPanel;
50 private DefaultActionGroup myToolBarGroup;
51 private final JPanel myListPanel;
52 private ShowDiffAction.DiffExtendUIFactory myDiffExtendUIFactory = new DiffToolbarActionsFactory();
53 private String myToggleActionTitle = VcsBundle.message("commit.dialog.include.action.name");
55 public static DataKey<ChangesBrowser> DATA_KEY = DataKey.create("com.intellij.openapi.vcs.changes.ui.ChangesBrowser");
56 private ShowDiffAction myDiffAction;
58 public void setChangesToDisplay(final List<Change> changes) {
59 myChangesToDisplay = changes;
60 myViewer.setChangesToDisplay(changes);
63 public ChangesBrowser(final Project project, List<? extends ChangeList> changeLists, final List<Change> changes,
64 ChangeList initialListSelection, final boolean capableOfExcludingChanges, final boolean highlightProblems,
65 @Nullable final Runnable inclusionListener, final MyUseCase useCase) {
66 super(new BorderLayout());
68 myProject = project;
69 myCapableOfExcludingChanges = capableOfExcludingChanges;
71 final ChangeNodeDecorator decorator = MyUseCase.LOCAL_CHANGES.equals(useCase) ?
72 RemoteRevisionsCache.getInstance(myProject).getChangesNodeDecorator() : null;
74 myViewer = new ChangesTreeList<Change>(myProject, changes, capableOfExcludingChanges, highlightProblems, inclusionListener, decorator) {
75 protected DefaultTreeModel buildTreeModel(final List<Change> changes, ChangeNodeDecorator changeNodeDecorator) {
76 TreeModelBuilder builder = new TreeModelBuilder(myProject, false);
77 return builder.buildModel(changes, changeNodeDecorator);
80 protected List<Change> getSelectedObjects(final ChangesBrowserNode<Change> node) {
81 return node.getAllChangesUnder();
84 @Nullable
85 protected Change getLeadSelectedObject(final ChangesBrowserNode node) {
86 final Object o = node.getUserObject();
87 if (o instanceof Change) {
88 return (Change) o;
90 return null;
94 myViewer.setDoubleClickHandler(new Runnable() {
95 public void run() {
96 showDiff();
98 });
100 setInitialSelection(changeLists, changes, initialListSelection);
101 rebuildList();
103 myListPanel = new JPanel(new BorderLayout());
104 myListPanel.add(myViewer, BorderLayout.CENTER);
106 JComponent separator = SeparatorFactory.createSeparator(VcsBundle.message("commit.dialog.changed.files.label"), myViewer);
107 myListPanel.add(separator, BorderLayout.NORTH);
108 add(myListPanel, BorderLayout.CENTER);
110 myHeaderPanel = new JPanel(new BorderLayout());
111 myHeaderPanel.add(createToolbar(), BorderLayout.CENTER);
112 add(myHeaderPanel, BorderLayout.NORTH);
114 myViewer.installPopupHandler(myToolBarGroup);
117 protected void setInitialSelection(final List<? extends ChangeList> changeLists, final List<Change> changes, final ChangeList initialListSelection) {
118 mySelectedChangeList = initialListSelection;
121 public void dispose() {
124 public void addToolbarAction(AnAction action) {
125 myToolBarGroup.add(action);
128 public void addToolbarActions(ActionGroup group) {
129 myToolBarGroup.addSeparator();
130 myToolBarGroup.add(group);
133 public ShowDiffAction.DiffExtendUIFactory getDiffExtendUIFactory() {
134 return myDiffExtendUIFactory;
137 public void setDiffExtendUIFactory(final ShowDiffAction.DiffExtendUIFactory diffExtendUIFactory) {
138 myDiffExtendUIFactory = diffExtendUIFactory;
141 public void setToggleActionTitle(final String toggleActionTitle) {
142 myToggleActionTitle = toggleActionTitle;
145 public JPanel getHeaderPanel() {
146 return myHeaderPanel;
149 public JPanel getListPanel() {
150 return myListPanel;
153 public void calcData(DataKey key, DataSink sink) {
154 if (key == VcsDataKeys.CHANGES) {
155 final List<Change> list = myViewer.getSelectedChanges();
156 sink.put(VcsDataKeys.CHANGES, list.toArray(new Change [list.size()]));
158 else if (key == VcsDataKeys.CHANGE_LISTS) {
159 sink.put(VcsDataKeys.CHANGE_LISTS, getSelectedChangeLists());
161 else if (key == VcsDataKeys.CHANGE_LEAD_SELECTION) {
162 final Change highestSelection = myViewer.getHighestLeadSelection();
163 sink.put(VcsDataKeys.CHANGE_LEAD_SELECTION, (highestSelection == null) ? new Change[]{} : new Change[] {highestSelection});
164 } else if (key == PlatformDataKeys.VIRTUAL_FILE_ARRAY) {
165 sink.put(PlatformDataKeys.VIRTUAL_FILE_ARRAY, getSelectedFiles());
167 else if (key == PlatformDataKeys.NAVIGATABLE_ARRAY) {
168 sink.put(PlatformDataKeys.NAVIGATABLE_ARRAY, ChangesUtil.getNavigatableArray(myProject, getSelectedFiles()));
169 } else if (VcsDataKeys.IO_FILE_ARRAY.equals(key)) {
170 sink.put(VcsDataKeys.IO_FILE_ARRAY, getSelectedIoFiles());
172 else if (key == DATA_KEY) {
173 sink.put(DATA_KEY, this);
174 } else if (VcsDataKeys.SELECTED_CHANGES_IN_DETAILS.equals(key)) {
175 final List<Change> selectedChanges = getSelectedChanges();
176 sink.put(VcsDataKeys.SELECTED_CHANGES_IN_DETAILS, selectedChanges.toArray(new Change[selectedChanges.size()]));
180 private class ToggleChangeAction extends CheckboxAction {
181 private final Change myChange;
183 public ToggleChangeAction(final Change change) {
184 super(myToggleActionTitle);
185 myChange = change;
188 public boolean isSelected(AnActionEvent e) {
189 return myViewer.isIncluded(myChange);
192 public void setSelected(AnActionEvent e, boolean state) {
193 if (state) {
194 myViewer.includeChange(myChange);
196 else {
197 myViewer.excludeChange(myChange);
202 protected void showDiffForChanges(Change[] changesArray, final int indexInSelection) {
203 ShowDiffAction.showDiffForChange(changesArray, indexInSelection, myProject, myDiffExtendUIFactory, isInFrame());
206 private void showDiff() {
207 final Change leadSelection = myViewer.getLeadSelection();
208 List<Change> changes = myViewer.getSelectedChanges();
210 if (changes.size() < 2) {
211 final Collection<Change> displayedChanges = getCurrentDisplayedChanges();
212 changes = new ArrayList<Change>(displayedChanges);
215 int indexInSelection = changes.indexOf(leadSelection);
216 if (indexInSelection >= 0) {
217 Change[] changesArray = changes.toArray(new Change[changes.size()]);
218 showDiffForChanges(changesArray, indexInSelection);
220 else if ((leadSelection == null && changes.size() > 0)) {
221 Change[] changesArray = changes.toArray(new Change[changes.size()]);
222 showDiffForChanges(changesArray, 0);
224 else if (leadSelection != null) {
225 showDiffForChanges(new Change[]{leadSelection}, 0);
229 private static boolean isInFrame() {
230 return ModalityState.current().equals(ModalityState.NON_MODAL);
233 private class DiffToolbarActionsFactory implements ShowDiffAction.DiffExtendUIFactory {
234 public List<? extends AnAction> createActions(Change change) {
235 return createDiffActions(change);
238 @Nullable
239 public JComponent createBottomComponent() {
240 return null;
244 protected List<AnAction> createDiffActions(final Change change) {
245 List<AnAction> actions = new ArrayList<AnAction>();
246 if (myCapableOfExcludingChanges) {
247 actions.add(new ToggleChangeAction(change));
249 return actions;
252 public void rebuildList() {
253 myViewer.setChangesToDisplay(getCurrentDisplayedChanges());
256 private JComponent createToolbar() {
257 DefaultActionGroup toolbarGroups = new DefaultActionGroup();
258 myToolBarGroup = new DefaultActionGroup();
259 toolbarGroups.add(myToolBarGroup);
260 buildToolBar(myToolBarGroup);
262 toolbarGroups.addSeparator();
263 DefaultActionGroup treeActionsGroup = new DefaultActionGroup();
264 toolbarGroups.add(treeActionsGroup);
265 for(AnAction action: myViewer.getTreeActions()) {
266 treeActionsGroup.add(action);
269 return ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarGroups, true).getComponent();
272 protected void buildToolBar(final DefaultActionGroup toolBarGroup) {
273 myDiffAction = new ShowDiffAction() {
274 public void actionPerformed(AnActionEvent e) {
275 showDiff();
278 myDiffAction.registerCustomShortcutSet(CommonShortcuts.getDiff(), myViewer);
279 toolBarGroup.add(myDiffAction);
282 public List<Change> getCurrentDisplayedChanges() {
283 final List<Change> list;
284 if (myChangesToDisplay != null) {
285 list = new ArrayList<Change>(myChangesToDisplay);
287 else if (mySelectedChangeList != null) {
288 list = new ArrayList<Change>(mySelectedChangeList.getChanges());
290 else {
291 list = Collections.emptyList();
293 return sortChanges(list);
296 protected static List<Change> sortChanges(final List<Change> list) {
297 Collections.sort(list, ChangesComparator.getInstance());
298 return list;
301 public ChangeList getSelectedChangeList() {
302 return mySelectedChangeList;
305 public JComponent getPrefferedFocusComponent() {
306 return myViewer;
309 private ChangeList[] getSelectedChangeLists() {
310 if (mySelectedChangeList != null) {
311 return new ChangeList[]{mySelectedChangeList};
313 return null;
316 private File[] getSelectedIoFiles() {
317 final List<Change> changes = myViewer.getSelectedChanges();
318 final List<File> files = new ArrayList<File>();
319 for (Change change : changes) {
320 final ContentRevision afterRevision = change.getAfterRevision();
321 if (afterRevision != null) {
322 final FilePath file = afterRevision.getFile();
323 final File ioFile = file.getIOFile();
324 files.add(ioFile);
327 return files.toArray(new File[files.size()]);
330 public List<Change> getSelectedChanges() {
331 return myViewer.getSelectedChanges();
334 private VirtualFile[] getSelectedFiles() {
335 final List<Change> changes = myViewer.getSelectedChanges();
336 return ChangesUtil.getFilesFromChanges(changes);
339 public ShowDiffAction getDiffAction() {
340 return myDiffAction;
343 protected static enum MyUseCase {
344 LOCAL_CHANGES,
345 COMMITTED_CHANGES