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
.DialogWrapper
;
20 import com
.intellij
.openapi
.util
.text
.StringUtil
;
21 import com
.intellij
.openapi
.vcs
.VcsException
;
22 import com
.intellij
.openapi
.vfs
.VirtualFile
;
23 import com
.intellij
.ui
.DocumentAdapter
;
24 import git4idea
.GitBranch
;
25 import git4idea
.GitRevisionNumber
;
26 import git4idea
.actions
.GitShowAllSubmittedFilesAction
;
27 import git4idea
.commands
.*;
28 import git4idea
.config
.GitConfigUtil
;
29 import git4idea
.i18n
.GitBundle
;
30 import git4idea
.validators
.GitBranchNameValidator
;
33 import javax
.swing
.event
.DocumentEvent
;
34 import javax
.swing
.event
.ListSelectionEvent
;
35 import javax
.swing
.event
.ListSelectionListener
;
36 import java
.awt
.event
.ActionEvent
;
37 import java
.awt
.event
.ActionListener
;
38 import java
.nio
.charset
.Charset
;
39 import java
.util
.HashSet
;
40 import java
.util
.List
;
45 public class GitUnstashDialog
extends DialogWrapper
{
49 private JComboBox myGitRootComboBox
;
51 * The current branch label
53 private JLabel myCurrentBranch
;
55 * The view stash button
57 private JButton myViewButton
;
59 * The drop stash button
61 private JButton myDropButton
;
63 * The clear stashes button
65 private JButton myClearButton
;
67 * The pop stash checkbox
69 private JCheckBox myPopStashCheckBox
;
71 * The branch text field
73 private JTextField myBranchTextField
;
75 * The root panel of the dialog
77 private JPanel myPanel
;
81 private JList myStashList
;
83 * If this checkbox is selected, the index is reinstated as well as working tree
85 private JCheckBox myReinstateIndexCheckBox
;
87 * Set of branches for the current root
89 private final HashSet
<String
> myBranches
= new HashSet
<String
>();
94 private final Project myProject
;
99 * @param project the project
100 * @param roots the list of the roots
101 * @param defaultRoot the default root to select
103 public GitUnstashDialog(final Project project
, final List
<VirtualFile
> roots
, final VirtualFile defaultRoot
) {
104 super(project
, true);
106 setTitle(GitBundle
.getString("unstash.title"));
107 setOKButtonText(GitBundle
.getString("unstash.button.apply"));
108 GitUIUtil
.setupRootChooser(project
, roots
, defaultRoot
, myGitRootComboBox
, myCurrentBranch
);
109 myStashList
.setModel(new DefaultListModel());
111 myGitRootComboBox
.addActionListener(new ActionListener() {
112 public void actionPerformed(final ActionEvent e
) {
117 myStashList
.addListSelectionListener(new ListSelectionListener() {
118 public void valueChanged(final ListSelectionEvent e
) {
122 myBranchTextField
.getDocument().addDocumentListener(new DocumentAdapter() {
123 protected void textChanged(final DocumentEvent e
) {
127 myPopStashCheckBox
.addActionListener(new ActionListener() {
128 public void actionPerformed(ActionEvent e
) {
132 myClearButton
.addActionListener(new ActionListener() {
133 public void actionPerformed(final ActionEvent e
) {
134 GitLineHandler h
= new GitLineHandler(myProject
, getGitRoot(), GitHandler
.STASH
);
136 h
.addParameters("clear");
137 GitHandlerUtil
.doSynchronously(h
, GitBundle
.getString("unstash.clearing.stashes"), h
.printableCommandLine());
142 myDropButton
.addActionListener(new ActionListener() {
143 public void actionPerformed(final ActionEvent e
) {
144 final String stash
= getSelectedStash();
145 GitSimpleHandler h
= dropHandler(stash
);
151 catch (VcsException ex
) {
153 //noinspection HardCodedStringLiteral
154 if (ex
.getMessage().startsWith("fatal: Needed a single revision")) {
155 h
= dropHandler(translateStash(stash
));
163 catch (VcsException ex2
) {
164 GitUIUtil
.showOperationError(myProject
, ex
, h
.printableCommandLine());
172 private GitSimpleHandler
dropHandler(String stash
) {
173 GitSimpleHandler h
= new GitSimpleHandler(myProject
, getGitRoot(), GitHandler
.STASH
);
175 h
.addParameters("drop", stash
);
179 myViewButton
.addActionListener(new ActionListener() {
180 public void actionPerformed(final ActionEvent e
) {
181 final VirtualFile root
= getGitRoot();
182 String resolvedStash
;
183 String selectedStash
= getSelectedStash();
185 resolvedStash
= GitRevisionNumber
.resolve(myProject
, root
, selectedStash
).asString();
187 catch (VcsException ex
) {
189 //noinspection HardCodedStringLiteral
190 if (ex
.getMessage().startsWith("fatal: bad revision 'stash@")) {
191 selectedStash
= translateStash(selectedStash
);
192 resolvedStash
= GitRevisionNumber
.resolve(myProject
, root
, selectedStash
).asString();
198 catch (VcsException ex2
) {
199 GitUIUtil
.showOperationError(myProject
, ex
, "resolving revision");
203 GitShowAllSubmittedFilesAction
.showSubmittedFiles(myProject
, resolvedStash
, root
);
211 * Translate stash name so that { } are escaped.
213 * @param selectedStash a selected stash
214 * @return translated name
216 private static String
translateStash(String selectedStash
) {
217 return selectedStash
.replaceAll("([\\{}])", "\\\\$1");
221 * Update state dialog depending on the current state of the fields
223 public void updateDialogState() {
224 String branch
= myBranchTextField
.getText();
225 if (branch
.length() != 0) {
226 setOKButtonText(GitBundle
.getString("unstash.button.branch"));
227 myPopStashCheckBox
.setEnabled(false);
228 myPopStashCheckBox
.setSelected(true);
229 myReinstateIndexCheckBox
.setEnabled(false);
230 myReinstateIndexCheckBox
.setSelected(true);
231 if (!GitBranchNameValidator
.INSTANCE
.checkInput(branch
)) {
232 setErrorText(GitBundle
.getString("unstash.error.invalid.branch.name"));
233 setOKActionEnabled(false);
236 if (myBranches
.contains(branch
)) {
237 setErrorText(GitBundle
.getString("unstash.error.branch.exists"));
238 setOKActionEnabled(false);
243 if (!myPopStashCheckBox
.isEnabled()) {
244 myPopStashCheckBox
.setSelected(false);
246 myPopStashCheckBox
.setEnabled(true);
248 myPopStashCheckBox
.isSelected() ? GitBundle
.getString("unstash.button.pop") : GitBundle
.getString("unstash.button.apply"));
249 if (!myReinstateIndexCheckBox
.isEnabled()) {
250 myReinstateIndexCheckBox
.setSelected(false);
252 myReinstateIndexCheckBox
.setEnabled(true);
254 if (myStashList
.getModel().getSize() == 0) {
255 myViewButton
.setEnabled(false);
256 myDropButton
.setEnabled(false);
257 myClearButton
.setEnabled(false);
259 setOKActionEnabled(false);
263 myClearButton
.setEnabled(true);
265 if (myStashList
.getSelectedIndex() == -1) {
266 myViewButton
.setEnabled(false);
267 myDropButton
.setEnabled(false);
269 setOKActionEnabled(false);
273 myViewButton
.setEnabled(true);
274 myDropButton
.setEnabled(true);
277 setOKActionEnabled(true);
283 private void refreshStashList() {
284 final DefaultListModel listModel
= (DefaultListModel
)myStashList
.getModel();
286 GitSimpleHandler h
= new GitSimpleHandler(myProject
, getGitRoot(), GitHandler
.STASH
);
289 h
.addParameters("list");
292 h
.setCharset(Charset
.forName(GitConfigUtil
.getLogEncoding(myProject
, getGitRoot())));
295 catch (VcsException e
) {
296 GitUIUtil
.showOperationError(myProject
, e
, h
.printableCommandLine());
299 for (StringScanner s
= new StringScanner(out
); s
.hasMoreData();) {
300 listModel
.addElement(new StashInfo(s
.boundedToken(':'), s
.boundedToken(':'), s
.line()));
304 GitBranch
.listAsStrings(myProject
, getGitRoot(), false, true, myBranches
);
306 catch (VcsException e
) {
312 * @return the selected git root
314 public VirtualFile
getGitRoot() {
315 return (VirtualFile
)myGitRootComboBox
.getSelectedItem();
319 * @param escaped if true stash name will be escaped
320 * @return unstash handler
322 public GitSimpleHandler
handler(boolean escaped
) {
323 GitSimpleHandler h
= new GitSimpleHandler(myProject
, getGitRoot(), GitHandler
.STASH
);
325 String branch
= myBranchTextField
.getText();
326 if (branch
.length() == 0) {
327 h
.addParameters(myPopStashCheckBox
.isSelected() ?
"pop" : "apply");
328 if (myReinstateIndexCheckBox
.isSelected()) {
329 h
.addParameters("--index");
333 h
.addParameters("branch", branch
);
335 final String selectedStash
= getSelectedStash();
336 h
.addParameters(escaped ?
translateStash(selectedStash
) : selectedStash
);
341 * @return selected stash
342 * @throws NullPointerException if no stash is selected
344 private String
getSelectedStash() {
345 return ((StashInfo
)myStashList
.getSelectedValue()).myStash
;
351 protected JComponent
createCenterPanel() {
359 protected String
getDimensionServiceKey() {
360 return getClass().getName();
367 protected String
getHelpId() {
368 return "reference.VersionControl.Git.Unstash";
372 * Stash information class
374 private static class StashInfo
{
378 private final String myStash
;
380 * The text representation
382 private final String myText
;
387 * @param stash the stash name
388 * @param branch the branch name
389 * @param message the stash message
391 public StashInfo(final String stash
, final String branch
, final String message
) {
394 GitBundle
.message("unstash.stashes.item", StringUtil
.escapeXml(stash
), StringUtil
.escapeXml(branch
), StringUtil
.escapeXml(message
));
398 * @return string representation
401 public String
toString() {