git4idea: added diagnostics for IAE in GitSimpleHandler
[fedora-idea.git] / plugins / git4idea / src / git4idea / ui / GitUIUtil.java
blobb679ed796b4f46ecb5148a6f764922769df8a66f
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 git4idea.ui;
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;
31 import javax.swing.*;
32 import java.awt.*;
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;
39 /**
40 * Utilities for git plugin user interface
42 public class GitUIUtil {
43 /**
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");
48 /**
49 * A private constructor for utility class
51 private GitUIUtil() {
54 /**
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,
60 final Object value,
61 final int index,
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);
72 /**
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();
82 /**
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,
93 final Object value,
94 final int index,
95 final boolean isSelected,
96 final boolean cellHasFocus) {
97 final GitRemote remote = (GitRemote)value;
98 String text;
99 if (value == null) {
100 text = GitBundle.getString("util.remote.renderer.none");
102 else if (".".equals(remote.name())) {
103 text = GitBundle.getString("util.remote.renderer.self");
105 else {
106 String key;
107 if (defaultRemote != null && defaultRemote.equals(remote.name())) {
108 key = "util.remote.renderer.default";
110 else {
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) {
146 try {
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);
153 else {
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;
234 try {
235 gitBranch = GitBranch.current(project, root);
237 catch (VcsException ex) {
238 // ignore error
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) {
260 try {
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)) {
272 toSelect = r;
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);
306 else {
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);
343 else {
344 changed.setEnabled(true);
349 * {@inheritDoc}
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);
381 changed.setText("");
383 else {
384 changed.setEnabled(true);
385 if (previousState != null) {
386 changed.setText(previousState);
387 previousState = null;
392 checked.addActionListener(l);
393 l.actionPerformed(null);