/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java

https://bitbucket.org/nbargnesi/idea · Java · 274 lines · 217 code · 42 blank · 15 comment · 4 complexity · 81df4d7029383a45fc4c982363d505be MD5 · raw file

  1. /*
  2. * Copyright 2000-2009 JetBrains s.r.o.
  3. *
  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
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  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.
  15. */
  16. package com.intellij.history.integration.ui.views;
  17. import com.intellij.history.core.LocalHistoryFacade;
  18. import com.intellij.history.core.revisions.Difference;
  19. import com.intellij.history.integration.IdeaGateway;
  20. import com.intellij.history.integration.ui.models.DirectoryHistoryDialogModel;
  21. import com.intellij.openapi.actionSystem.*;
  22. import com.intellij.openapi.project.Project;
  23. import com.intellij.openapi.util.Condition;
  24. import com.intellij.openapi.util.IconLoader;
  25. import com.intellij.openapi.util.Pair;
  26. import com.intellij.openapi.vcs.changes.Change;
  27. import com.intellij.openapi.vcs.changes.actions.ShowDiffAction;
  28. import com.intellij.openapi.vcs.changes.actions.ShowDiffUIContext;
  29. import com.intellij.openapi.vcs.changes.ui.ChangeNodeDecorator;
  30. import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode;
  31. import com.intellij.openapi.vcs.changes.ui.ChangesTreeList;
  32. import com.intellij.openapi.vcs.changes.ui.TreeModelBuilder;
  33. import com.intellij.openapi.vfs.VirtualFile;
  34. import com.intellij.ui.DocumentAdapter;
  35. import com.intellij.ui.ExcludingTraversalPolicy;
  36. import com.intellij.ui.SearchTextField;
  37. import com.intellij.ui.SearchTextFieldWithStoredHistory;
  38. import com.intellij.util.Consumer;
  39. import com.intellij.util.containers.ContainerUtil;
  40. import gnu.trove.THashSet;
  41. import org.jetbrains.annotations.NotNull;
  42. import javax.swing.*;
  43. import javax.swing.border.Border;
  44. import javax.swing.event.DocumentEvent;
  45. import javax.swing.tree.DefaultTreeModel;
  46. import java.awt.*;
  47. import java.util.ArrayList;
  48. import java.util.Collections;
  49. import java.util.List;
  50. import java.util.Set;
  51. import static com.intellij.history.integration.LocalHistoryBundle.message;
  52. public class DirectoryHistoryDialog extends HistoryDialog<DirectoryHistoryDialogModel> {
  53. private ChangesTreeList<Change> myChangesTree;
  54. private ActionToolbar myToolBar;
  55. public DirectoryHistoryDialog(Project p, IdeaGateway gw, VirtualFile f) {
  56. this(p, gw, f, true);
  57. }
  58. protected DirectoryHistoryDialog(@NotNull Project p, IdeaGateway gw, VirtualFile f, boolean doInit) {
  59. super(p, gw, f, doInit);
  60. }
  61. @Override
  62. protected DirectoryHistoryDialogModel createModel(LocalHistoryFacade vcs) {
  63. return new DirectoryHistoryDialogModel(myProject, myGateway, vcs, myFile);
  64. }
  65. @Override
  66. protected Pair<JComponent, Dimension> createDiffPanel(JPanel root, ExcludingTraversalPolicy traversalPolicy) {
  67. initChangesTree(root);
  68. JPanel p = new JPanel(new BorderLayout());
  69. myToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, createChangesTreeActions(root), true);
  70. JPanel toolBarPanel = new JPanel(new BorderLayout());
  71. toolBarPanel.add(myToolBar.getComponent(), BorderLayout.CENTER);
  72. if (showSearchField()) {
  73. SearchTextField search = createSearchBox(root);
  74. toolBarPanel.add(search, BorderLayout.EAST);
  75. traversalPolicy.exclude(search.getTextEditor());
  76. }
  77. p.add(toolBarPanel, BorderLayout.NORTH);
  78. p.add(myChangesTree, BorderLayout.CENTER);
  79. return Pair.create((JComponent)p, toolBarPanel.getPreferredSize());
  80. }
  81. protected boolean showSearchField() {
  82. return true;
  83. }
  84. @Override
  85. protected void setDiffBorder(Border border) {
  86. myChangesTree.setScrollPaneBorder(border);
  87. }
  88. private SearchTextField createSearchBox(JPanel root) {
  89. final SearchTextFieldWithStoredHistory field = new SearchTextFieldWithStoredHistory(getPropertiesKey() + ".searchHistory");
  90. field.addDocumentListener(new DocumentAdapter() {
  91. @Override
  92. protected void textChanged(DocumentEvent e) {
  93. scheduleRevisionsUpdate(new Consumer<DirectoryHistoryDialogModel>() {
  94. public void consume(DirectoryHistoryDialogModel m) {
  95. m.setFilter(field.getText());
  96. field.addCurrentTextToHistory();
  97. }
  98. });
  99. }
  100. });
  101. new AnAction() {
  102. @Override
  103. public void actionPerformed(AnActionEvent e) {
  104. field.requestFocusInWindow();
  105. }
  106. }.registerCustomShortcutSet(CommonShortcuts.getFind(), root, this);
  107. return field;
  108. }
  109. private void initChangesTree(JComponent root) {
  110. myChangesTree = createChangesTree();
  111. myChangesTree.setDoubleClickHandler(new Runnable() {
  112. public void run() {
  113. new ShowDifferenceAction().performIfEnabled();
  114. }
  115. });
  116. myChangesTree.installPopupHandler(createChangesTreeActions(root));
  117. }
  118. private ChangesTreeList<Change> createChangesTree() {
  119. return new ChangesTreeList<Change>(myProject, Collections.<Change>emptyList(), false, false, null, null) {
  120. @Override
  121. protected DefaultTreeModel buildTreeModel(List<Change> cc, ChangeNodeDecorator changeNodeDecorator) {
  122. return new TreeModelBuilder(myProject, false).buildModel(cc, changeNodeDecorator);
  123. }
  124. @Override
  125. protected List<Change> getSelectedObjects(ChangesBrowserNode node) {
  126. return node.getAllChangesUnder();
  127. }
  128. protected Change getLeadSelectedObject(final ChangesBrowserNode node) {
  129. final Object o = node.getUserObject();
  130. if (o instanceof Change) {
  131. return (Change)o;
  132. }
  133. return null;
  134. }
  135. };
  136. }
  137. private ActionGroup createChangesTreeActions(JComponent root) {
  138. DefaultActionGroup result = new DefaultActionGroup();
  139. ShowDifferenceAction a = new ShowDifferenceAction();
  140. a.registerCustomShortcutSet(CommonShortcuts.getDiff(), root);
  141. result.add(a);
  142. result.add(new RevertSelectionAction());
  143. result.addSeparator();
  144. result.addAll(myChangesTree.getTreeActions());
  145. return result;
  146. }
  147. @Override
  148. protected void updateActions() {
  149. super.updateActions();
  150. myToolBar.updateActionsImmediately();
  151. }
  152. @Override
  153. protected Runnable doUpdateDiffs(DirectoryHistoryDialogModel model) {
  154. final List<Change> changes = model.getChanges();
  155. return new Runnable() {
  156. public void run() {
  157. myChangesTree.setChangesToDisplay(changes);
  158. }
  159. };
  160. }
  161. @Override
  162. protected String getHelpId() {
  163. return "reference.dialogs.localHistory.show.folder";
  164. }
  165. private List<DirectoryChange> getChanges() {
  166. return (List)myChangesTree.getChanges();
  167. }
  168. private List<DirectoryChange> getSelectedChanges() {
  169. return (List)myChangesTree.getSelectedChanges();
  170. }
  171. private class ShowDifferenceAction extends ActionOnSelection {
  172. public ShowDifferenceAction() {
  173. super(message("action.show.difference"), "/actions/diff.png");
  174. }
  175. @Override
  176. protected void doPerform(DirectoryHistoryDialogModel model, List<DirectoryChange> selected) {
  177. final Set<DirectoryChange> selectedSet = new THashSet<DirectoryChange>(selected);
  178. ShowDiffAction.showDiffForChange((Iterable)iterFileChanges(), new Condition<Change>() {
  179. public boolean value(Change change) {
  180. return selectedSet.contains(change);
  181. }
  182. }, myProject, new ShowDiffUIContext(true));
  183. }
  184. private Iterable<DirectoryChange> iterFileChanges() {
  185. return ContainerUtil.iterate(getChanges(), new Condition<DirectoryChange>() {
  186. public boolean value(DirectoryChange each) {
  187. return each.canShowFileDifference();
  188. }
  189. });
  190. }
  191. @Override
  192. protected boolean isEnabledFor(DirectoryHistoryDialogModel model, List<DirectoryChange> changes) {
  193. return iterFileChanges().iterator().hasNext();
  194. }
  195. }
  196. private class RevertSelectionAction extends ActionOnSelection {
  197. public RevertSelectionAction() {
  198. super(message("action.revert.selection"), "/actions/rollback.png");
  199. }
  200. @Override
  201. protected void doPerform(DirectoryHistoryDialogModel model, List<DirectoryChange> selected) {
  202. List<Difference> diffs = new ArrayList<Difference>();
  203. for (DirectoryChange each : selected) {
  204. diffs.add(each.getModel().getDifference());
  205. }
  206. revert(model.createRevisionReverter(diffs));
  207. }
  208. @Override
  209. protected boolean isEnabledFor(DirectoryHistoryDialogModel model, List<DirectoryChange> changes) {
  210. return model.isRevertEnabled();
  211. }
  212. }
  213. private abstract class ActionOnSelection extends MyAction {
  214. public ActionOnSelection(String name, String iconName) {
  215. super(name, null, IconLoader.getIcon(iconName));
  216. }
  217. @Override
  218. protected void doPerform(DirectoryHistoryDialogModel model) {
  219. doPerform(model, getSelectedChanges());
  220. }
  221. protected abstract void doPerform(DirectoryHistoryDialogModel model, List<DirectoryChange> selected);
  222. @Override
  223. protected boolean isEnabled(DirectoryHistoryDialogModel model) {
  224. final List<DirectoryChange> changes = getSelectedChanges();
  225. if (changes.isEmpty()) return false;
  226. return isEnabledFor(model, changes);
  227. }
  228. protected boolean isEnabledFor(DirectoryHistoryDialogModel model, List<DirectoryChange> changes) {
  229. return true;
  230. }
  231. }
  232. }