2 * Copyright 2000-2008 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.
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.openapi
.ui
.DialogWrapper
;
21 import com
.intellij
.openapi
.vfs
.VirtualFile
;
22 import com
.intellij
.ui
.CheckboxTree
;
23 import com
.intellij
.ui
.CheckedTreeNode
;
24 import com
.intellij
.ui
.ColoredTreeCellRenderer
;
25 import com
.intellij
.ui
.SimpleTextAttributes
;
26 import com
.intellij
.ui
.treeStructure
.Tree
;
27 import com
.intellij
.util
.Icons
;
28 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
29 import git4idea
.GitBranch
;
30 import git4idea
.GitTag
;
31 import git4idea
.commands
.GitHandler
;
32 import git4idea
.commands
.GitHandlerUtil
;
33 import git4idea
.commands
.GitSimpleHandler
;
34 import git4idea
.commands
.StringScanner
;
35 import git4idea
.i18n
.GitBundle
;
36 import org
.jetbrains
.annotations
.Nls
;
37 import org
.jetbrains
.annotations
.NotNull
;
40 import java
.awt
.event
.ActionEvent
;
41 import java
.awt
.event
.ActionListener
;
42 import java
.util
.HashSet
;
43 import java
.util
.SortedSet
;
44 import java
.util
.TreeSet
;
47 * This dialog allows adding selected tag and branches are references.
49 public class GitRefspecAddRefsDialog
extends DialogWrapper
{
51 * Get references button
53 private JButton myGetRefsButton
;
55 * If selected, the branches are fetched by {@link #myGetRefsButton}
57 private JCheckBox myIncludeBranchesCheckBox
;
59 * If selected, the tags are fetched by {@link #myGetRefsButton}
61 private JCheckBox myIncludeTagsCheckBox
;
63 * The selector for tags and branches
65 private CheckboxTree myReferenceChooser
;
67 * The root panel of the dialog
69 private JPanel myPanel
;
73 private final Project myProject
;
77 private CheckedTreeNode myTreeRoot
;
79 * The git root of the repository
81 private final VirtualFile myRoot
;
83 * The name of the remote
85 private final String myRemote
;
89 private final SortedSet
<String
> myTags
;
93 private final SortedSet
<String
> myBranches
;
95 * The logger for the class
97 private static final Logger log
= Logger
.getInstance(GitRefspecAddRefsDialog
.class.getName());
102 * @param project the project
103 * @param root the git repository root
104 * @param remote the remote name or url of remote repository
105 * @param tags the set of tags (might be modified if update button is pressed)
106 * @param branches the set of branches (might be modified if update button is pressed)
108 protected GitRefspecAddRefsDialog(@NotNull Project project
,
109 @NotNull VirtualFile root
,
110 @NotNull String remote
,
111 @NotNull SortedSet
<String
> tags
,
112 @NotNull SortedSet
<String
> branches
) {
113 super(project
, true);
114 setTitle(GitBundle
.getString("addrefspec.title"));
115 setOKButtonText(GitBundle
.getString("addrefspec.button"));
120 myBranches
= branches
;
122 setupGetReferences();
124 setOKActionEnabled(false);
129 * Set up action listener for {@link #myGetRefsButton}
131 private void setupGetReferences() {
132 // setup enabled state
133 final ActionListener enabledListener
= new ActionListener() {
134 public void actionPerformed(final ActionEvent e
) {
135 myGetRefsButton
.setEnabled(myIncludeBranchesCheckBox
.isSelected() || myIncludeTagsCheckBox
.isSelected());
138 myIncludeBranchesCheckBox
.addActionListener(enabledListener
);
139 myIncludeTagsCheckBox
.addActionListener(enabledListener
);
141 myGetRefsButton
.addActionListener(new ActionListener() {
142 public void actionPerformed(final ActionEvent e
) {
143 GitSimpleHandler handler
= new GitSimpleHandler(myProject
, myRoot
, GitHandler
.LS_REMOTE
);
144 if (myIncludeBranchesCheckBox
.isSelected()) {
145 handler
.addParameters("--heads");
148 if (myIncludeTagsCheckBox
.isSelected()) {
149 handler
.addParameters("--tags");
152 handler
.addParameters(myRemote
);
153 String result
= GitHandlerUtil
154 .doSynchronously(handler
, GitBundle
.message("addrefspec.getting.references.title", myRemote
), handler
.printableCommandLine());
155 if (result
!= null) {
156 StringScanner s
= new StringScanner(result
);
157 while (s
.hasMoreData()) {
158 s
.tabToken(); // skip last commit hash
159 String ref
= s
.line();
160 if (ref
.startsWith(GitBranch
.REFS_HEADS_PREFIX
)) {
163 else if (ref
.startsWith(GitTag
.REFS_TAGS_PREFIX
)) {
167 log
.warn("Unknwon reference type from ls-remote \"" + myRemote
+ "\" :" + ref
);
177 * Update checkbox tree basing on the current state of the tag and branches set. The checkbox state is preserved. New items are created
178 * in unselected state.
180 private void updateTree() {
181 // save the previous selection
182 HashSet
<String
> oldTags
= new HashSet
<String
>();
183 HashSet
<String
> oldBranches
= new HashSet
<String
>();
184 for (Reference ref
: myReferenceChooser
.getCheckedNodes(Reference
.class, null)) {
185 (ref
.isTag ? oldTags
: oldBranches
).add(ref
.name
);
188 myTreeRoot
.removeAllChildren();
189 // fill tags and branches
190 addReferences(false, oldBranches
, myBranches
, GitBundle
.getString("addrefspec.node.branches"));
191 addReferences(true, oldTags
, myTags
, GitBundle
.getString("addrefspec.node.tags"));
192 TreeUtil
.expandAll(myReferenceChooser
);
193 myReferenceChooser
.treeDidChange();
197 * Add references to the tree along with category node
199 * @param isTag if true tag nodes are added
200 * @param old the set of old elements (used to select
201 * @param current the current set of elements (after update)
202 * @param name the name of the set
204 private void addReferences(final boolean isTag
, final HashSet
<String
> old
, final SortedSet
<String
> current
, @Nls final String name
) {
205 if (!current
.isEmpty()) {
206 final CheckedTreeNode tagsRoot
= new CheckedTreeNode(name
);
207 for (String t
: current
) {
208 final CheckedTreeNode node
= new CheckedTreeNode(new Reference(isTag
, t
));
209 node
.setChecked(old
.contains(t
));
212 myTreeRoot
.add(tagsRoot
);
220 protected String
getDimensionServiceKey() {
221 return GitRefspecAddRefsDialog
.class.getName();
227 protected JComponent
createCenterPanel() {
232 * Create UI components that require custom creation: {@link #myReferenceChooser}
234 private void createUIComponents() {
235 myTreeRoot
= new CheckedTreeNode("");
236 myReferenceChooser
= new CheckboxTree(new CheckboxTree
.CheckboxTreeCellRenderer() {
238 public void customizeCellRenderer(final JTree tree
,
240 final boolean selected
,
241 final boolean expanded
,
244 final boolean hasFocus
) {
245 final CheckedTreeNode node
= (CheckedTreeNode
)value
;
246 final Object userObject
= node
.getUserObject();
248 SimpleTextAttributes attributes
;
250 if (userObject
== null) {
251 // invisible root (do nothing)
252 //noinspection HardCodedStringLiteral
253 text
= "INVISBLE ROOT";
254 attributes
= SimpleTextAttributes
.ERROR_ATTRIBUTES
;
257 else if (userObject
instanceof String
) {
258 // category node (render as bold)
259 text
= (String
)userObject
;
260 attributes
= SimpleTextAttributes
.REGULAR_BOLD_ATTRIBUTES
;
261 icon
= expanded ? Icons
.DIRECTORY_OPEN_ICON
: Icons
.DIRECTORY_CLOSED_ICON
;
265 text
= ((Reference
)userObject
).name
;
266 attributes
= node
.isChecked() ? SimpleTextAttributes
.REGULAR_BOLD_ATTRIBUTES
: SimpleTextAttributes
.REGULAR_ATTRIBUTES
;
269 final ColoredTreeCellRenderer textRenderer
= getTextRenderer();
271 textRenderer
.setIcon(icon
);
274 textRenderer
.append(text
, attributes
);
279 protected void onNodeStateChanged(final CheckedTreeNode node
) {
280 boolean flag
= node
.isChecked() || myReferenceChooser
.getCheckedNodes(Reference
.class, null).length
!= 0;
281 setOKActionEnabled(flag
);
282 super.onNodeStateChanged(node
);
288 * Get selected elements
290 * @param isTag if true tags are returned, heads otherwise
291 * @return a collection of selected reference of the specified type
293 public SortedSet
<String
> getSelected(final boolean isTag
) {
294 TreeSet
<String
> rc
= new TreeSet
<String
>();
295 final Reference
[] checked
= myReferenceChooser
.getCheckedNodes(Reference
.class, new Tree
.NodeFilter
<Reference
>() {
296 public boolean accept(final Reference node
) {
297 return node
.isTag
== isTag
;
300 for (Reference r
: checked
) {
310 protected String
getHelpId() {
311 return "reference.VersionControl.Git.Fetch.AddReference";
318 static final class Reference
{
320 * If true, the name represents a tag. if false, the name represents the branch name.
324 * Name of the reference
329 * A constructor from fields
331 * @param tag the value for {@link #isTag}
332 * @param name the value for {@link #name}
334 public Reference(final boolean tag
, final String name
) {