VCS: asynch load of committed changes when do "Browse changes"
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / committed / StructureFilteringStrategy.java
blob08e33a978d26dcee63d83eeb43b523960a982608
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.committed;
18 import com.intellij.ide.util.treeView.TreeState;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.vcs.FilePath;
21 import com.intellij.openapi.vcs.VcsBundle;
22 import com.intellij.openapi.vcs.changes.Change;
23 import com.intellij.openapi.vcs.changes.ChangesUtil;
24 import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode;
25 import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNodeRenderer;
26 import com.intellij.openapi.vcs.changes.ui.TreeModelBuilder;
27 import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
28 import com.intellij.ui.treeStructure.Tree;
29 import com.intellij.util.containers.ContainerUtil;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
33 import javax.swing.*;
34 import javax.swing.event.ChangeEvent;
35 import javax.swing.event.ChangeListener;
36 import javax.swing.event.TreeSelectionEvent;
37 import javax.swing.event.TreeSelectionListener;
38 import javax.swing.tree.DefaultMutableTreeNode;
39 import javax.swing.tree.DefaultTreeModel;
40 import java.awt.*;
41 import java.util.*;
42 import java.util.List;
43 import java.util.concurrent.CopyOnWriteArrayList;
45 /**
46 * @author yole
48 public class StructureFilteringStrategy implements ChangeListFilteringStrategy {
49 private final CopyOnWriteArrayList<ChangeListener> myListeners = ContainerUtil.createEmptyCOWList();
50 private MyUI myUI;
51 private final Project myProject;
52 private final List<FilePath> mySelection = new ArrayList<FilePath>();
54 public StructureFilteringStrategy(final Project project) {
55 myProject = project;
58 public String toString() {
59 return VcsBundle.message("filter.structure.name");
62 @Nullable
63 public JComponent getFilterUI() {
64 if (myUI == null) {
65 myUI = new MyUI();
67 return myUI;
70 public void setFilterBase(List<CommittedChangeList> changeLists) {
71 if (myUI == null) {
72 myUI = new MyUI();
74 myUI.reset();
75 myUI.append(changeLists);
78 public void addChangeListener(ChangeListener listener) {
79 myListeners.add(listener);
82 public void removeChangeListener(ChangeListener listener) {
83 myListeners.remove(listener);
86 public void resetFilterBase() {
87 myUI.reset();
90 public void appendFilterBase(List<CommittedChangeList> changeLists) {
91 myUI.append(changeLists);
94 @NotNull
95 public List<CommittedChangeList> filterChangeLists(List<CommittedChangeList> changeLists) {
96 if (mySelection.size() == 0) {
97 return changeLists;
99 final ArrayList<CommittedChangeList> result = new ArrayList<CommittedChangeList>();
100 for(CommittedChangeList list: changeLists) {
101 if (listMatchesSelection(list)) {
102 result.add(list);
105 return result;
108 private boolean listMatchesSelection(final CommittedChangeList list) {
109 for(Change change: list.getChanges()) {
110 FilePath path = ChangesUtil.getFilePath(change);
111 for(FilePath selPath: mySelection) {
112 if (path.isUnder(selPath, false)) {
113 return true;
117 return false;
120 private class MyUI extends JPanel {
121 private final Tree myStructureTree;
122 private boolean myRendererInitialized;
123 private final TreeModelBuilder myBuilder;
124 private TreeState myState;
126 public MyUI() {
127 setLayout(new BorderLayout());
128 myStructureTree = new Tree();
129 myStructureTree.setRootVisible(false);
130 myStructureTree.setShowsRootHandles(true);
131 myStructureTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
132 public void valueChanged(final TreeSelectionEvent e) {
133 mySelection.clear();
134 ChangesBrowserNode node = (ChangesBrowserNode) e.getPath().getLastPathComponent();
135 Collections.addAll(mySelection, node.getFilePathsUnder());
137 for(ChangeListener listener: myListeners) {
138 listener.stateChanged(new ChangeEvent(this));
142 add(new JScrollPane(myStructureTree), BorderLayout.CENTER);
143 myBuilder = new TreeModelBuilder(myProject, false);
146 public void initRenderer() {
147 if (!myRendererInitialized) {
148 myRendererInitialized = true;
149 myStructureTree.setCellRenderer(new ChangesBrowserNodeRenderer(myProject, false, false));
153 public void reset() {
154 myState = TreeState.createOn(myStructureTree, (DefaultMutableTreeNode) myStructureTree.getModel().getRoot());
155 myStructureTree.setModel(myBuilder.clearAndGetModel());
158 public void append(final List<CommittedChangeList> changeLists) {
159 final TreeState localState = (myState != null) && myBuilder.isEmpty() ? myState : TreeState.createOn(myStructureTree, (DefaultMutableTreeNode) myStructureTree.getModel().getRoot());
161 final Set<FilePath> filePaths = new HashSet<FilePath>();
162 for(CommittedChangeList changeList: changeLists) {
163 for(Change change: changeList.getChanges()) {
164 final FilePath path = ChangesUtil.getFilePath(change);
165 if (path.getParentPath() != null) {
166 filePaths.add(path.getParentPath());
171 final DefaultTreeModel model = myBuilder.buildModelFromFilePaths(filePaths);
172 myStructureTree.setModel(model);
173 localState.applyTo(myStructureTree, (DefaultMutableTreeNode) myStructureTree.getModel().getRoot());
174 myStructureTree.revalidate();
175 myStructureTree.repaint();
176 initRenderer();