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
.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
.Collections
;
36 import java
.util
.List
;
39 * Utilities for git plugin user interface
41 public class GitUIUtil
{
43 * Text containing in the label when there is no current branch
45 public static final String NO_CURRENT_BRANCH
= GitBundle
.getString("common.no.active.branch");
48 * A private constructor for utility class
54 * @return a list cell renderer for virtual files (it renders presentable URL)
56 public static ListCellRenderer
getVirtualFileListCellRenderer() {
57 return new DefaultListCellRenderer() {
58 public Component
getListCellRendererComponent(final JList list
,
61 final boolean isSelected
,
62 final boolean cellHasFocus
) {
63 String text
= ((VirtualFile
)value
).getPresentableUrl();
64 return super.getListCellRendererComponent(list
, text
, index
, isSelected
, cellHasFocus
);
71 * Get text field from combobox
73 * @param comboBox a combobox to examine
74 * @return the text field reference
76 public static JTextField
getTextField(JComboBox comboBox
) {
77 return (JTextField
)comboBox
.getEditor().getEditorComponent();
81 * Create list cell renderer for remotes. It shows both name and url and highlights the default
82 * remote for the branch with bold.
84 * @param defaultRemote a default remote
85 * @param fetchUrl if true, the fetch url is shown
86 * @return a list cell renderer for virtual files (it renders presentable URL
88 public static ListCellRenderer
getGitRemoteListCellRenderer(final String defaultRemote
, final boolean fetchUrl
) {
89 return new DefaultListCellRenderer() {
90 public Component
getListCellRendererComponent(final JList list
,
93 final boolean isSelected
,
94 final boolean cellHasFocus
) {
95 final GitRemote remote
= (GitRemote
)value
;
98 text
= GitBundle
.getString("util.remote.renderer.none");
100 else if (".".equals(remote
.name())) {
101 text
= GitBundle
.getString("util.remote.renderer.self");
105 if (defaultRemote
!= null && defaultRemote
.equals(remote
.name())) {
106 key
= "util.remote.renderer.default";
109 key
= "util.remote.renderer.normal";
111 text
= GitBundle
.message(key
, remote
.name(), fetchUrl ? remote
.fetchUrl() : remote
.pushUrl());
113 return super.getListCellRendererComponent(list
, text
, index
, isSelected
, cellHasFocus
);
121 * Setup root chooser with specified elements and link selection to the current branch label.
123 * @param project a context project
124 * @param roots git roots for the project
125 * @param defaultRoot a default root
126 * @param gitRootChooser git root selector
127 * @param currentBranchLabel current branch label (might be null)
129 public static void setupRootChooser(final Project project
,
130 final List
<VirtualFile
> roots
,
131 final VirtualFile defaultRoot
,
132 final JComboBox gitRootChooser
,
133 @Nullable final JLabel currentBranchLabel
) {
134 for (VirtualFile root
: roots
) {
135 gitRootChooser
.addItem(root
);
137 gitRootChooser
.setRenderer(getVirtualFileListCellRenderer());
138 gitRootChooser
.setSelectedItem(defaultRoot
);
139 if (currentBranchLabel
!= null) {
140 final ActionListener listener
= new ActionListener() {
141 public void actionPerformed(final ActionEvent e
) {
143 VirtualFile root
= (VirtualFile
)gitRootChooser
.getSelectedItem();
144 GitBranch current
= GitBranch
.current(project
, root
);
145 assert currentBranchLabel
!= null;
146 if (current
== null) {
147 currentBranchLabel
.setText(NO_CURRENT_BRANCH
);
150 currentBranchLabel
.setText(current
.getName());
153 catch (VcsException ex
) {
154 GitVcs
.getInstance(project
).showErrors(Collections
.singletonList(ex
), GitBundle
.getString("merge.retrieving.branches"));
158 listener
.actionPerformed(null);
159 gitRootChooser
.addActionListener(listener
);
164 * Get root from the chooser
166 * @param gitRootChooser the chooser constructed with {@link #setupRootChooser(Project, List, VirtualFile, JComboBox, JLabel)}.
167 * @return the current selection
169 public static VirtualFile
getRootFromRootChooser(JComboBox gitRootChooser
) {
170 return (VirtualFile
)gitRootChooser
.getSelectedItem();
174 * Show error associated with the specified operation
176 * @param project the project
177 * @param ex the exception
178 * @param operation the operation name
180 public static void showOperationError(final Project project
, final VcsException ex
, @NonNls @NotNull final String operation
) {
181 showOperationError(project
, operation
, ex
.getMessage());
185 * Show error associated with the specified operation
187 * @param project the project
188 * @param message the error description
189 * @param operation the operation name
191 public static void showOperationError(final Project project
, final String operation
, final String message
) {
192 Messages
.showErrorDialog(project
, message
, GitBundle
.message("error.occurred.during", operation
));
196 * Setup remotes combobox. The default remote for the current branch is selected by default.
197 * This method gets current branch for the project.
199 * @param project the project
200 * @param root the git root
201 * @param remoteCombobox the combobox to update
202 * @param fetchUrl if true, the fetch url is shown instead of push url
204 public static void setupRemotes(final Project project
, final VirtualFile root
, final JComboBox remoteCombobox
, final boolean fetchUrl
) {
205 GitBranch gitBranch
= null;
207 gitBranch
= GitBranch
.current(project
, root
);
209 catch (VcsException ex
) {
212 final String branch
= gitBranch
!= null ? gitBranch
.getName() : null;
213 setupRemotes(project
, root
, branch
, remoteCombobox
, fetchUrl
);
219 * Setup remotes combobox. The default remote for the current branch is selected by default.
221 * @param project the project
222 * @param root the git root
223 * @param currentBranch the current branch
224 * @param remoteCombobox the combobox to update
225 * @param fetchUrl if true, the fetch url is shown for remotes, push otherwise
227 public static void setupRemotes(final Project project
,
228 final VirtualFile root
,
229 final String currentBranch
,
230 final JComboBox remoteCombobox
,
231 final boolean fetchUrl
) {
233 List
<GitRemote
> remotes
= GitRemote
.list(project
, root
);
234 String remote
= null;
235 if (currentBranch
!= null) {
236 remote
= GitConfigUtil
.getValue(project
, root
, "branch." + currentBranch
+ ".remote");
238 remoteCombobox
.setRenderer(getGitRemoteListCellRenderer(remote
, fetchUrl
));
239 GitRemote toSelect
= null;
240 remoteCombobox
.removeAllItems();
241 for (GitRemote r
: remotes
) {
242 remoteCombobox
.addItem(r
);
243 if (r
.name().equals(remote
)) {
247 if (toSelect
!= null) {
248 remoteCombobox
.setSelectedItem(toSelect
);
251 catch (VcsException e
) {
252 GitVcs
.getInstance(project
).showErrors(Collections
.singletonList(e
), GitBundle
.getString("pull.retrieving.remotes"));
257 * Checks state of the {@code checked} checkbox and if state is {@code checkedState} than to disable {@code changed}
258 * checkbox and change its state to {@code impliedState}. When the {@code checked} checkbox changes states to other state,
259 * than enable {@code changed} and restore its state. Note that the each checkbox should be implied by only one other checkbox.
261 * @param checked the checkbox to monitor
262 * @param checkedState the state that triggers disabling changed state
263 * @param changed the checkbox to change
264 * @param impliedState the implied state of checkbox
266 public static void imply(final JCheckBox checked
, final boolean checkedState
, final JCheckBox changed
, final boolean impliedState
) {
267 ActionListener l
= new ActionListener() {
268 Boolean previousState
;
270 public void actionPerformed(ActionEvent e
) {
271 if (checked
.isSelected() == checkedState
) {
272 if (previousState
== null) {
273 previousState
= changed
.isSelected();
275 changed
.setEnabled(false);
276 changed
.setSelected(impliedState
);
279 changed
.setEnabled(true);
280 if (previousState
!= null) {
281 changed
.setSelected(previousState
);
282 previousState
= null;
287 checked
.addActionListener(l
);
288 l
.actionPerformed(null);
292 * Declares states for two checkboxes to be mutually exclusive. When one of the checkboxes goes to the specified state, other is
293 * disabled and forced into reverse of the state (to prevent very fast users from selecting incorrect state or incorrect
294 * initial configuration).
296 * @param first the first checkbox
297 * @param firstState the state of the first checkbox
298 * @param second the second checkbox
299 * @param secondState the state of the second checkbox
301 public static void exclusive(final JCheckBox first
, final boolean firstState
, final JCheckBox second
, final boolean secondState
) {
302 ActionListener l
= new ActionListener() {
304 * One way check for the condition
305 * @param checked the first to check
306 * @param checkedState the state to match
307 * @param changed the changed control
308 * @param impliedState the implied state
310 private void check(final JCheckBox checked
, final boolean checkedState
, final JCheckBox changed
, final boolean impliedState
) {
311 if (checked
.isSelected() == checkedState
) {
312 changed
.setSelected(impliedState
);
313 changed
.setEnabled(false);
316 changed
.setEnabled(true);
323 public void actionPerformed(ActionEvent e
) {
324 check(first
, firstState
, second
, !secondState
);
325 check(second
, secondState
, first
, !firstState
);
328 first
.addActionListener(l
);
329 second
.addActionListener(l
);
330 l
.actionPerformed(null);
334 * Checks state of the {@code checked} checkbox and if state is {@code checkedState} than to disable {@code changed}
335 * text field and clean it. When the {@code checked} checkbox changes states to other state,
336 * than enable {@code changed} and restore its state. Note that the each text field should be implied by
337 * only one other checkbox.
339 * @param checked the checkbox to monitor
340 * @param checkedState the state that triggers disabling changed state
341 * @param changed the checkbox to change
343 public static void implyDisabled(final JCheckBox checked
, final boolean checkedState
, final JTextField changed
) {
344 ActionListener l
= new ActionListener() {
345 String previousState
;
347 public void actionPerformed(ActionEvent e
) {
348 if (checked
.isSelected() == checkedState
) {
349 if (previousState
== null) {
350 previousState
= changed
.getText();
352 changed
.setEnabled(false);
356 changed
.setEnabled(true);
357 if (previousState
!= null) {
358 changed
.setText(previousState
);
359 previousState
= null;
364 checked
.addActionListener(l
);
365 l
.actionPerformed(null);