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
;
36 import java
.util
.List
;
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());
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();
83 protected Change
getLeadSelectedObject(final ChangesBrowserNode node
) {
84 final Object o
= node
.getUserObject();
85 if (o
instanceof Change
) {
92 myViewer
.setDoubleClickHandler(new Runnable() {
98 setInitialSelection(changeLists
, changes
, initialListSelection
);
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() {
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
);
186 public boolean isSelected(AnActionEvent e
) {
187 return myViewer
.isIncluded(myChange
);
190 public void setSelected(AnActionEvent e
, boolean state
) {
192 myViewer
.includeChange(myChange
);
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
);
237 public JComponent
createBottomComponent() {
242 protected List
<AnAction
> createDiffActions(final Change change
) {
243 List
<AnAction
> actions
= new ArrayList
<AnAction
>();
244 if (myCapableOfExcludingChanges
) {
245 actions
.add(new ToggleChangeAction(change
));
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
) {
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());
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());
303 public ChangeList
getSelectedChangeList() {
304 return mySelectedChangeList
;
307 public JComponent
getPrefferedFocusComponent() {
311 private ChangeList
[] getSelectedChangeLists() {
312 if (mySelectedChangeList
!= null) {
313 return new ChangeList
[]{mySelectedChangeList
};
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();
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() {
345 protected static enum MyUseCase
{