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.
18 import com
.intellij
.openapi
.project
.Project
;
19 import com
.intellij
.openapi
.ui
.Messages
;
20 import com
.intellij
.openapi
.vcs
.VcsException
;
21 import com
.intellij
.openapi
.vfs
.VirtualFile
;
22 import git4idea
.GitBranch
;
23 import git4idea
.GitRemote
;
24 import git4idea
.GitVcs
;
25 import git4idea
.config
.GitConfigUtil
;
26 import git4idea
.i18n
.GitBundle
;
27 import org
.jetbrains
.annotations
.NonNls
;
28 import org
.jetbrains
.annotations
.NotNull
;
29 import org
.jetbrains
.annotations
.Nullable
;
33 import java
.awt
.event
.ActionEvent
;
34 import java
.awt
.event
.ActionListener
;
35 import java
.util
.Collection
;
36 import java
.util
.Collections
;
37 import java
.util
.List
;
40 * Utilities for git plugin user interface
42 public class GitUIUtil
{
44 * Text containing in the label when there is no current branch
46 public static final String NO_CURRENT_BRANCH
= GitBundle
.getString("common.no.active.branch");
49 * A private constructor for utility class
55 * @return a list cell renderer for virtual files (it renders presentable URL)
57 public static ListCellRenderer
getVirtualFileListCellRenderer() {
58 return new DefaultListCellRenderer() {
59 public Component
getListCellRendererComponent(final JList list
,
62 final boolean isSelected
,
63 final boolean cellHasFocus
) {
64 VirtualFile file
= (VirtualFile
)value
;
65 String text
= file
== null || !file
.isValid() ?
"(invalid)" : file
.getPresentableUrl();
66 return super.getListCellRendererComponent(list
, text
, index
, isSelected
, cellHasFocus
);
73 * Get text field from combobox
75 * @param comboBox a combobox to examine
76 * @return the text field reference
78 public static JTextField
getTextField(JComboBox comboBox
) {
79 return (JTextField
)comboBox
.getEditor().getEditorComponent();
83 * Create list cell renderer for remotes. It shows both name and url and highlights the default
84 * remote for the branch with bold.
86 * @param defaultRemote a default remote
87 * @param fetchUrl if true, the fetch url is shown
88 * @return a list cell renderer for virtual files (it renders presentable URL
90 public static ListCellRenderer
getGitRemoteListCellRenderer(final String defaultRemote
, final boolean fetchUrl
) {
91 return new DefaultListCellRenderer() {
92 public Component
getListCellRendererComponent(final JList list
,
95 final boolean isSelected
,
96 final boolean cellHasFocus
) {
97 final GitRemote remote
= (GitRemote
)value
;
100 text
= GitBundle
.getString("util.remote.renderer.none");
102 else if (".".equals(remote
.name())) {
103 text
= GitBundle
.getString("util.remote.renderer.self");
107 if (defaultRemote
!= null && defaultRemote
.equals(remote
.name())) {
108 key
= "util.remote.renderer.default";
111 key
= "util.remote.renderer.normal";
113 text
= GitBundle
.message(key
, remote
.name(), fetchUrl ? remote
.fetchUrl() : remote
.pushUrl());
115 return super.getListCellRendererComponent(list
, text
, index
, isSelected
, cellHasFocus
);
123 * Setup root chooser with specified elements and link selection to the current branch label.
125 * @param project a context project
126 * @param roots git roots for the project
127 * @param defaultRoot a default root
128 * @param gitRootChooser git root selector
129 * @param currentBranchLabel current branch label (might be null)
131 public static void setupRootChooser(@NotNull final Project project
,
132 @NotNull final List
<VirtualFile
> roots
,
133 @Nullable final VirtualFile defaultRoot
,
134 @NotNull final JComboBox gitRootChooser
,
135 @Nullable final JLabel currentBranchLabel
) {
136 for (VirtualFile root
: roots
) {
137 gitRootChooser
.addItem(root
);
139 gitRootChooser
.setRenderer(getVirtualFileListCellRenderer());
140 if (defaultRoot
!= null) {
141 gitRootChooser
.setSelectedItem(defaultRoot
);
143 if (currentBranchLabel
!= null) {
144 final ActionListener listener
= new ActionListener() {
145 public void actionPerformed(final ActionEvent e
) {
147 VirtualFile root
= (VirtualFile
)gitRootChooser
.getSelectedItem();
148 assert root
!= null : "The root must not be null";
149 GitBranch current
= GitBranch
.current(project
, root
);
150 if (current
== null) {
151 currentBranchLabel
.setText(NO_CURRENT_BRANCH
);
154 currentBranchLabel
.setText(current
.getName());
157 catch (VcsException ex
) {
158 GitVcs
.getInstance(project
).showErrors(Collections
.singletonList(ex
), GitBundle
.getString("merge.retrieving.branches"));
162 listener
.actionPerformed(null);
163 gitRootChooser
.addActionListener(listener
);
168 * Get root from the chooser
170 * @param gitRootChooser the chooser constructed with {@link #setupRootChooser(Project, List, VirtualFile, JComboBox, JLabel)}.
171 * @return the current selection
173 public static VirtualFile
getRootFromRootChooser(JComboBox gitRootChooser
) {
174 return (VirtualFile
)gitRootChooser
.getSelectedItem();
178 * Show error associated with the specified operation
180 * @param project the project
181 * @param ex the exception
182 * @param operation the operation name
184 public static void showOperationError(final Project project
, final VcsException ex
, @NonNls @NotNull final String operation
) {
185 showOperationError(project
, operation
, ex
.getMessage());
189 * Show errors associated with the specified operation
191 * @param project the project
192 * @param exs the exceptions to show
193 * @param operation the operation name
195 public static void showOperationErrors(final Project project
,
196 final Collection
<VcsException
> exs
,
197 @NonNls @NotNull final String operation
) {
198 if (exs
.size() == 1) {
199 //noinspection ThrowableResultOfMethodCallIgnored
200 showOperationError(project
, operation
, exs
.iterator().next().getMessage());
202 else if (exs
.size() > 1) {
203 // TODO use dialog in order to show big messages
204 StringBuilder b
= new StringBuilder();
205 for (VcsException ex
: exs
) {
206 b
.append(GitBundle
.message("errors.message.item", ex
.getMessage()));
208 showOperationError(project
, operation
, GitBundle
.message("errors.message", b
.toString()));
213 * Show error associated with the specified operation
215 * @param project the project
216 * @param message the error description
217 * @param operation the operation name
219 public static void showOperationError(final Project project
, final String operation
, final String message
) {
220 Messages
.showErrorDialog(project
, message
, GitBundle
.message("error.occurred.during", operation
));
224 * Setup remotes combobox. The default remote for the current branch is selected by default.
225 * This method gets current branch for the project.
227 * @param project the project
228 * @param root the git root
229 * @param remoteCombobox the combobox to update
230 * @param fetchUrl if true, the fetch url is shown instead of push url
232 public static void setupRemotes(final Project project
, final VirtualFile root
, final JComboBox remoteCombobox
, final boolean fetchUrl
) {
233 GitBranch gitBranch
= null;
235 gitBranch
= GitBranch
.current(project
, root
);
237 catch (VcsException ex
) {
240 final String branch
= gitBranch
!= null ? gitBranch
.getName() : null;
241 setupRemotes(project
, root
, branch
, remoteCombobox
, fetchUrl
);
247 * Setup remotes combobox. The default remote for the current branch is selected by default.
249 * @param project the project
250 * @param root the git root
251 * @param currentBranch the current branch
252 * @param remoteCombobox the combobox to update
253 * @param fetchUrl if true, the fetch url is shown for remotes, push otherwise
255 public static void setupRemotes(final Project project
,
256 final VirtualFile root
,
257 final String currentBranch
,
258 final JComboBox remoteCombobox
,
259 final boolean fetchUrl
) {
261 List
<GitRemote
> remotes
= GitRemote
.list(project
, root
);
262 String remote
= null;
263 if (currentBranch
!= null) {
264 remote
= GitConfigUtil
.getValue(project
, root
, "branch." + currentBranch
+ ".remote");
266 remoteCombobox
.setRenderer(getGitRemoteListCellRenderer(remote
, fetchUrl
));
267 GitRemote toSelect
= null;
268 remoteCombobox
.removeAllItems();
269 for (GitRemote r
: remotes
) {
270 remoteCombobox
.addItem(r
);
271 if (r
.name().equals(remote
)) {
275 if (toSelect
!= null) {
276 remoteCombobox
.setSelectedItem(toSelect
);
279 catch (VcsException e
) {
280 GitVcs
.getInstance(project
).showErrors(Collections
.singletonList(e
), GitBundle
.getString("pull.retrieving.remotes"));
285 * Checks state of the {@code checked} checkbox and if state is {@code checkedState} than to disable {@code changed}
286 * checkbox and change its state to {@code impliedState}. When the {@code checked} checkbox changes states to other state,
287 * than enable {@code changed} and restore its state. Note that the each checkbox should be implied by only one other checkbox.
289 * @param checked the checkbox to monitor
290 * @param checkedState the state that triggers disabling changed state
291 * @param changed the checkbox to change
292 * @param impliedState the implied state of checkbox
294 public static void imply(final JCheckBox checked
, final boolean checkedState
, final JCheckBox changed
, final boolean impliedState
) {
295 ActionListener l
= new ActionListener() {
296 Boolean previousState
;
298 public void actionPerformed(ActionEvent e
) {
299 if (checked
.isSelected() == checkedState
) {
300 if (previousState
== null) {
301 previousState
= changed
.isSelected();
303 changed
.setEnabled(false);
304 changed
.setSelected(impliedState
);
307 changed
.setEnabled(true);
308 if (previousState
!= null) {
309 changed
.setSelected(previousState
);
310 previousState
= null;
315 checked
.addActionListener(l
);
316 l
.actionPerformed(null);
320 * Declares states for two checkboxes to be mutually exclusive. When one of the checkboxes goes to the specified state, other is
321 * disabled and forced into reverse of the state (to prevent very fast users from selecting incorrect state or incorrect
322 * initial configuration).
324 * @param first the first checkbox
325 * @param firstState the state of the first checkbox
326 * @param second the second checkbox
327 * @param secondState the state of the second checkbox
329 public static void exclusive(final JCheckBox first
, final boolean firstState
, final JCheckBox second
, final boolean secondState
) {
330 ActionListener l
= new ActionListener() {
332 * One way check for the condition
333 * @param checked the first to check
334 * @param checkedState the state to match
335 * @param changed the changed control
336 * @param impliedState the implied state
338 private void check(final JCheckBox checked
, final boolean checkedState
, final JCheckBox changed
, final boolean impliedState
) {
339 if (checked
.isSelected() == checkedState
) {
340 changed
.setSelected(impliedState
);
341 changed
.setEnabled(false);
344 changed
.setEnabled(true);
351 public void actionPerformed(ActionEvent e
) {
352 check(first
, firstState
, second
, !secondState
);
353 check(second
, secondState
, first
, !firstState
);
356 first
.addActionListener(l
);
357 second
.addActionListener(l
);
358 l
.actionPerformed(null);
362 * Checks state of the {@code checked} checkbox and if state is {@code checkedState} than to disable {@code changed}
363 * text field and clean it. When the {@code checked} checkbox changes states to other state,
364 * than enable {@code changed} and restore its state. Note that the each text field should be implied by
365 * only one other checkbox.
367 * @param checked the checkbox to monitor
368 * @param checkedState the state that triggers disabling changed state
369 * @param changed the checkbox to change
371 public static void implyDisabled(final JCheckBox checked
, final boolean checkedState
, final JTextField changed
) {
372 ActionListener l
= new ActionListener() {
373 String previousState
;
375 public void actionPerformed(ActionEvent e
) {
376 if (checked
.isSelected() == checkedState
) {
377 if (previousState
== null) {
378 previousState
= changed
.getText();
380 changed
.setEnabled(false);
384 changed
.setEnabled(true);
385 if (previousState
!= null) {
386 changed
.setText(previousState
);
387 previousState
= null;
392 checked
.addActionListener(l
);
393 l
.actionPerformed(null);