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
;
32 import javax
.swing
.tree
.DefaultTreeModel
;
35 import java
.util
.ArrayList
;
36 import java
.util
.Collection
;
37 import java
.util
.Collections
;
38 import java
.util
.List
;
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());
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();
85 protected Change
getLeadSelectedObject(final ChangesBrowserNode node
) {
86 final Object o
= node
.getUserObject();
87 if (o
instanceof Change
) {
94 myViewer
.setDoubleClickHandler(new Runnable() {
100 setInitialSelection(changeLists
, changes
, initialListSelection
);
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() {
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
);
188 public boolean isSelected(AnActionEvent e
) {
189 return myViewer
.isIncluded(myChange
);
192 public void setSelected(AnActionEvent e
, boolean state
) {
194 myViewer
.includeChange(myChange
);
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
);
239 public JComponent
createBottomComponent() {
244 protected List
<AnAction
> createDiffActions(final Change change
) {
245 List
<AnAction
> actions
= new ArrayList
<AnAction
>();
246 if (myCapableOfExcludingChanges
) {
247 actions
.add(new ToggleChangeAction(change
));
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
) {
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());
291 list
= Collections
.emptyList();
293 return sortChanges(list
);
296 protected static List
<Change
> sortChanges(final List
<Change
> list
) {
297 Collections
.sort(list
, ChangesComparator
.getInstance());
301 public ChangeList
getSelectedChangeList() {
302 return mySelectedChangeList
;
305 public JComponent
getPrefferedFocusComponent() {
309 private ChangeList
[] getSelectedChangeLists() {
310 if (mySelectedChangeList
!= null) {
311 return new ChangeList
[]{mySelectedChangeList
};
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();
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() {
343 protected static enum MyUseCase
{