git4idea: IDEADEV-35690: added cancelling editing before move
[fedora-idea.git] / plugins / git4idea / src / git4idea / rebase / GitRebaseEditor.java
bloba4bc1b080dafedca640c51411f32d7d51d1b7b88
1 /*
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.
16 package git4idea.rebase;
18 import com.intellij.openapi.project.Project;
19 import com.intellij.openapi.ui.DialogWrapper;
20 import com.intellij.openapi.util.SystemInfo;
21 import com.intellij.openapi.util.io.FileUtil;
22 import com.intellij.openapi.vfs.VirtualFile;
23 import com.intellij.util.ListWithSelection;
24 import com.intellij.util.ui.ComboBoxTableCellEditor;
25 import com.intellij.util.ui.ComboBoxTableCellRenderer;
26 import git4idea.actions.GitShowAllSubmittedFilesAction;
27 import git4idea.commands.StringScanner;
28 import git4idea.config.GitConfigUtil;
29 import git4idea.i18n.GitBundle;
30 import org.jetbrains.annotations.NonNls;
32 import javax.swing.*;
33 import javax.swing.event.ListSelectionEvent;
34 import javax.swing.event.ListSelectionListener;
35 import javax.swing.event.TableModelEvent;
36 import javax.swing.event.TableModelListener;
37 import javax.swing.table.AbstractTableModel;
38 import javax.swing.table.TableColumn;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.io.*;
42 import java.util.ArrayList;
43 import java.util.Arrays;
45 /**
46 * Editor for rebase entries. It allows reordering of
47 * the entries and changing commit status.
49 public class GitRebaseEditor extends DialogWrapper {
50 /**
51 * The table that lists all commits
53 private JTable myCommitsTable;
54 /**
55 * The move up button
57 private JButton myMoveUpButton;
58 /**
59 * The move down button
61 private JButton myMoveDownButton;
62 /**
63 * The view commit button
65 private JButton myViewButton;
66 /**
67 * The root panel
69 private JPanel myPanel;
70 /**
71 * Table model
73 private final MyTableModel myTableModel;
74 /**
75 * The file name
77 private final String myFile;
78 /**
79 * The project
81 private final Project myProject;
82 /**
83 * The git root
85 private final VirtualFile myGitRoot;
86 /**
87 * The cygwin drive prefix
89 @NonNls private static final String CYGDRIVE_PREFIX = "/cygdrive/";
91 /**
92 * The constructor
94 * @param project the project
95 * @param gitRoot the git root
96 * @param file the file to edit
97 * @throws IOException if file could not be loaded
99 protected GitRebaseEditor(final Project project, final VirtualFile gitRoot, String file) throws IOException {
100 super(project, true);
101 myProject = project;
102 myGitRoot = gitRoot;
103 setTitle(GitBundle.getString("rebase.editor.title"));
104 if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) {
105 final int prefixSize = CYGDRIVE_PREFIX.length();
106 file = file.substring(prefixSize, prefixSize + 1) + ":" + file.substring(prefixSize + 1);
108 myFile = file;
109 myTableModel = new MyTableModel();
110 myTableModel.load(file);
111 myCommitsTable.setModel(myTableModel);
112 myCommitsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
113 TableColumn actionColumn = myCommitsTable.getColumnModel().getColumn(MyTableModel.ACTION);
114 actionColumn.setCellEditor(ComboBoxTableCellEditor.INSTANCE);
115 actionColumn.setCellRenderer(ComboBoxTableCellRenderer.INSTANCE);
116 myCommitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
117 public void valueChanged(final ListSelectionEvent e) {
118 boolean selected = myCommitsTable.getSelectedRowCount() != 0;
119 myMoveUpButton.setEnabled(selected);
120 if (selected) {
121 myViewButton.setEnabled(true);
122 int row = myCommitsTable.getSelectedRow();
123 myMoveUpButton.setEnabled(row != 0);
124 myMoveDownButton.setEnabled(row != myTableModel.myEntries.size() - 1);
126 else {
127 myMoveUpButton.setEnabled(false);
128 myMoveDownButton.setEnabled(false);
129 myViewButton.setEnabled(false);
133 myViewButton.addActionListener(new ActionListener() {
134 public void actionPerformed(final ActionEvent e) {
135 int row = myCommitsTable.getSelectedRow();
136 if (row < 0) {
137 return;
139 GitRebaseEntry entry = myTableModel.myEntries.get(row);
140 GitShowAllSubmittedFilesAction.showSubmittedFiles(project, entry.getCommit(), gitRoot);
143 myMoveUpButton.addActionListener(new ActionListener() {
144 public void actionPerformed(final ActionEvent e) {
145 final int row = myCommitsTable.getSelectedRow();
146 if (myTableModel.moveUp(row)) {
147 myCommitsTable.getSelectionModel().setSelectionInterval(row - 1, row - 1);
151 myMoveDownButton.addActionListener(new ActionListener() {
152 public void actionPerformed(final ActionEvent e) {
153 final int row = myCommitsTable.getSelectedRow();
154 if (myTableModel.moveDown(row)) {
155 myCommitsTable.getSelectionModel().setSelectionInterval(row + 1, row + 1);
159 myTableModel.addTableModelListener(new TableModelListener() {
160 public void tableChanged(final TableModelEvent e) {
161 validateFields();
164 init();
168 * Validate fields
170 private void validateFields() {
171 final ArrayList<GitRebaseEntry> entries = myTableModel.myEntries;
172 if (entries.size() == 0) {
173 setErrorText(GitBundle.getString("rebase.editor.invalid.entryset"));
174 setOKActionEnabled(false);
175 return;
177 int i = 0;
178 while (i < entries.size() && entries.get(i).getAction() == GitRebaseEntry.Action.skip) {
179 i++;
181 if (i < entries.size() && entries.get(i).getAction() == GitRebaseEntry.Action.squash) {
182 setErrorText(GitBundle.getString("rebase.editor.invalid.squash"));
183 setOKActionEnabled(false);
184 return;
186 setErrorText(null);
187 setOKActionEnabled(true);
191 * Save entries back to the file
193 * @throws IOException if there is IO problem with saving
195 public void save() throws IOException {
196 myTableModel.save(myFile);
200 * {@inheritDoc}
202 protected JComponent createCenterPanel() {
203 return myPanel;
207 * {@inheritDoc}
209 @Override
210 protected String getDimensionServiceKey() {
211 return getClass().getName();
215 * {@inheritDoc}
217 @Override
218 protected String getHelpId() {
219 return "reference.VersionControl.Git.RebaseCommits";
223 * Cancel rebase
225 * @throws IOException if file cannot be reset to empty one
227 public void cancel() throws IOException {
228 myTableModel.cancel(myFile);
233 * The table model for the commits
235 private class MyTableModel extends AbstractTableModel {
237 * The action column
239 private static final int ACTION = 0;
241 * The commit hash column
243 private static final int COMMIT = 1;
245 * The subject column
247 private static final int SUBJECT = 2;
250 * The entries
252 final ArrayList<GitRebaseEntry> myEntries = new ArrayList<GitRebaseEntry>();
255 * {@inheritDoc}
257 @Override
258 public Class<?> getColumnClass(final int columnIndex) {
259 return columnIndex == ACTION ? ListWithSelection.class : String.class;
263 * {@inheritDoc}
265 @Override
266 public String getColumnName(final int column) {
267 switch (column) {
268 case ACTION:
269 return GitBundle.getString("rebase.editor.action.column");
270 case COMMIT:
271 return GitBundle.getString("rebase.editor.commit.column");
272 case SUBJECT:
273 return GitBundle.getString("rebase.editor.comment.column");
274 default:
275 throw new IllegalArgumentException("Unsupported column index: " + column);
280 * {@inheritDoc}
282 public int getRowCount() {
283 return myEntries.size();
287 * {@inheritDoc}
289 public int getColumnCount() {
290 return SUBJECT + 1;
294 * {@inheritDoc}
296 public Object getValueAt(final int rowIndex, final int columnIndex) {
297 GitRebaseEntry e = myEntries.get(rowIndex);
298 switch (columnIndex) {
299 case ACTION:
300 return new ListWithSelection<GitRebaseEntry.Action>(Arrays.asList(GitRebaseEntry.Action.values()), e.getAction());
301 case COMMIT:
302 return e.getCommit();
303 case SUBJECT:
304 return e.getSubject();
305 default:
306 throw new IllegalArgumentException("Unsupported column index: " + columnIndex);
311 * {@inheritDoc}
313 @Override
314 @SuppressWarnings({"unchecked"})
315 public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) {
316 assert columnIndex == ACTION;
317 GitRebaseEntry e = myEntries.get(rowIndex);
318 e.setAction((GitRebaseEntry.Action)aValue);
319 fireTableCellUpdated(rowIndex, columnIndex);
323 * {@inheritDoc}
325 @Override
326 public boolean isCellEditable(final int rowIndex, final int columnIndex) {
327 return columnIndex == ACTION;
331 * Load data from the file
333 * @param file the file to load
334 * @throws IOException if file could not be loaded
336 public void load(final String file) throws IOException {
337 String encoding = GitConfigUtil.getLogEncoding(myProject, myGitRoot);
338 final StringScanner s = new StringScanner(new String(FileUtil.loadFileText(new File(file), encoding)));
339 while (s.hasMoreData()) {
340 if (s.isEol() || s.startsWith('#') || s.startsWith("noop")) {
341 s.nextLine();
342 continue;
344 String action = s.spaceToken();
345 assert "pick".equals(action) : "Initial action should be pick: " + action;
346 String hash = s.spaceToken();
347 String comment = s.line();
348 myEntries.add(new GitRebaseEntry(hash, comment));
353 * Save text to the file
355 * @param file the file to save to
356 * @throws IOException if there is IO problem
358 public void save(final String file) throws IOException {
359 String encoding = GitConfigUtil.getLogEncoding(myProject, myGitRoot);
360 PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), encoding));
361 try {
362 for (GitRebaseEntry e : myEntries) {
363 if (e.getAction() != GitRebaseEntry.Action.skip) {
364 out.println(e.getAction().toString() + " " + e.getCommit() + " " + e.getSubject());
368 finally {
369 out.close();
374 * Save text to the file
376 * @param file the file to save to
377 * @throws IOException if there is IO problem
379 public void cancel(final String file) throws IOException {
380 PrintWriter out = new PrintWriter(new FileWriter(file));
381 try {
382 //noinspection HardCodedStringLiteral
383 out.println("# rebase is cancelled");
385 finally {
386 out.close();
392 * Move selected row up. If row cannot be moved up, do nothing and return false.
394 * @param row a row to move
395 * @return true if row was moved
397 public boolean moveUp(final int row) {
398 if (row < 1 || row >= myEntries.size()) {
399 return false;
401 myCommitsTable.removeEditor();
402 GitRebaseEntry e = myEntries.get(row);
403 myEntries.set(row, myEntries.get(row - 1));
404 myEntries.set(row - 1, e);
405 fireTableRowsUpdated(row - 1, row);
406 return true;
410 * Move selected row down. If row cannot be moved down, do nothing and return false.
412 * @param row a row to move
413 * @return true if row was moved
415 public boolean moveDown(final int row) {
416 if (row < 0 || row >= myEntries.size() - 1) {
417 return false;
419 myCommitsTable.removeEditor();
420 GitRebaseEntry e = myEntries.get(row);
421 myEntries.set(row, myEntries.get(row + 1));
422 myEntries.set(row + 1, e);
423 fireTableRowsUpdated(row, row + 1);
424 return true;