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
;
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
;
42 import java
.util
.ArrayList
;
43 import java
.util
.Arrays
;
46 * Editor for rebase entries. It allows reordering of
47 * the entries and changing commit status.
49 public class GitRebaseEditor
extends DialogWrapper
{
51 * The table that lists all commits
53 private JTable myCommitsTable
;
57 private JButton myMoveUpButton
;
59 * The move down button
61 private JButton myMoveDownButton
;
63 * The view commit button
65 private JButton myViewButton
;
69 private JPanel myPanel
;
73 private final MyTableModel myTableModel
;
77 private final String myFile
;
81 private final Project myProject
;
85 private final VirtualFile myGitRoot
;
87 * The cygwin drive prefix
89 @NonNls private static final String CYGDRIVE_PREFIX
= "/cygdrive/";
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);
103 setTitle(GitBundle
.getString("rebase.editor.title"));
104 setOKButtonText(GitBundle
.getString("rebase.editor.button"));
105 if (SystemInfo
.isWindows
&& file
.startsWith(CYGDRIVE_PREFIX
)) {
106 final int prefixSize
= CYGDRIVE_PREFIX
.length();
107 file
= file
.substring(prefixSize
, prefixSize
+ 1) + ":" + file
.substring(prefixSize
+ 1);
110 myTableModel
= new MyTableModel();
111 myTableModel
.load(file
);
112 myCommitsTable
.setModel(myTableModel
);
113 myCommitsTable
.setSelectionMode(ListSelectionModel
.SINGLE_SELECTION
);
114 TableColumn actionColumn
= myCommitsTable
.getColumnModel().getColumn(MyTableModel
.ACTION
);
115 actionColumn
.setCellEditor(ComboBoxTableCellEditor
.INSTANCE
);
116 actionColumn
.setCellRenderer(ComboBoxTableCellRenderer
.INSTANCE
);
117 myCommitsTable
.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
118 public void valueChanged(final ListSelectionEvent e
) {
119 boolean selected
= myCommitsTable
.getSelectedRowCount() != 0;
120 myMoveUpButton
.setEnabled(selected
);
122 myViewButton
.setEnabled(true);
123 int row
= myCommitsTable
.getSelectedRow();
124 myMoveUpButton
.setEnabled(row
!= 0);
125 myMoveDownButton
.setEnabled(row
!= myTableModel
.myEntries
.size() - 1);
128 myMoveUpButton
.setEnabled(false);
129 myMoveDownButton
.setEnabled(false);
130 myViewButton
.setEnabled(false);
134 myViewButton
.addActionListener(new ActionListener() {
135 public void actionPerformed(final ActionEvent e
) {
136 int row
= myCommitsTable
.getSelectedRow();
140 GitRebaseEntry entry
= myTableModel
.myEntries
.get(row
);
141 GitShowAllSubmittedFilesAction
.showSubmittedFiles(project
, entry
.getCommit(), gitRoot
);
144 myMoveUpButton
.addActionListener(new ActionListener() {
145 public void actionPerformed(final ActionEvent e
) {
146 final int row
= myCommitsTable
.getSelectedRow();
147 if (myTableModel
.moveUp(row
)) {
148 myCommitsTable
.getSelectionModel().setSelectionInterval(row
- 1, row
- 1);
152 myMoveDownButton
.addActionListener(new ActionListener() {
153 public void actionPerformed(final ActionEvent e
) {
154 final int row
= myCommitsTable
.getSelectedRow();
155 if (myTableModel
.moveDown(row
)) {
156 myCommitsTable
.getSelectionModel().setSelectionInterval(row
+ 1, row
+ 1);
160 myTableModel
.addTableModelListener(new TableModelListener() {
161 public void tableChanged(final TableModelEvent e
) {
171 private void validateFields() {
172 final ArrayList
<GitRebaseEntry
> entries
= myTableModel
.myEntries
;
173 if (entries
.size() == 0) {
174 setErrorText(GitBundle
.getString("rebase.editor.invalid.entryset"));
175 setOKActionEnabled(false);
179 while (i
< entries
.size() && entries
.get(i
).getAction() == GitRebaseEntry
.Action
.skip
) {
182 if (i
< entries
.size() && entries
.get(i
).getAction() == GitRebaseEntry
.Action
.squash
) {
183 setErrorText(GitBundle
.getString("rebase.editor.invalid.squash"));
184 setOKActionEnabled(false);
188 setOKActionEnabled(true);
192 * Save entries back to the file
194 * @throws IOException if there is IO problem with saving
196 public void save() throws IOException
{
197 myTableModel
.save(myFile
);
203 protected JComponent
createCenterPanel() {
211 protected String
getDimensionServiceKey() {
212 return getClass().getName();
219 protected String
getHelpId() {
220 return "reference.VersionControl.Git.RebaseCommits";
226 * @throws IOException if file cannot be reset to empty one
228 public void cancel() throws IOException
{
229 myTableModel
.cancel(myFile
);
234 * The table model for the commits
236 private class MyTableModel
extends AbstractTableModel
{
240 private static final int ACTION
= 0;
242 * The commit hash column
244 private static final int COMMIT
= 1;
248 private static final int SUBJECT
= 2;
253 final ArrayList
<GitRebaseEntry
> myEntries
= new ArrayList
<GitRebaseEntry
>();
259 public Class
<?
> getColumnClass(final int columnIndex
) {
260 return columnIndex
== ACTION ? ListWithSelection
.class : String
.class;
267 public String
getColumnName(final int column
) {
270 return GitBundle
.getString("rebase.editor.action.column");
272 return GitBundle
.getString("rebase.editor.commit.column");
274 return GitBundle
.getString("rebase.editor.comment.column");
276 throw new IllegalArgumentException("Unsupported column index: " + column
);
283 public int getRowCount() {
284 return myEntries
.size();
290 public int getColumnCount() {
297 public Object
getValueAt(final int rowIndex
, final int columnIndex
) {
298 GitRebaseEntry e
= myEntries
.get(rowIndex
);
299 switch (columnIndex
) {
301 return new ListWithSelection
<GitRebaseEntry
.Action
>(Arrays
.asList(GitRebaseEntry
.Action
.values()), e
.getAction());
303 return e
.getCommit();
305 return e
.getSubject();
307 throw new IllegalArgumentException("Unsupported column index: " + columnIndex
);
315 @SuppressWarnings({"unchecked"})
316 public void setValueAt(final Object aValue
, final int rowIndex
, final int columnIndex
) {
317 assert columnIndex
== ACTION
;
318 GitRebaseEntry e
= myEntries
.get(rowIndex
);
319 e
.setAction((GitRebaseEntry
.Action
)aValue
);
320 fireTableCellUpdated(rowIndex
, columnIndex
);
327 public boolean isCellEditable(final int rowIndex
, final int columnIndex
) {
328 return columnIndex
== ACTION
;
332 * Load data from the file
334 * @param file the file to load
335 * @throws IOException if file could not be loaded
337 public void load(final String file
) throws IOException
{
338 String encoding
= GitConfigUtil
.getLogEncoding(myProject
, myGitRoot
);
339 final StringScanner s
= new StringScanner(new String(FileUtil
.loadFileText(new File(file
), encoding
)));
340 while (s
.hasMoreData()) {
341 if (s
.isEol() || s
.startsWith('#') || s
.startsWith("noop")) {
345 String action
= s
.spaceToken();
346 assert "pick".equals(action
) : "Initial action should be pick: " + action
;
347 String hash
= s
.spaceToken();
348 String comment
= s
.line();
349 myEntries
.add(new GitRebaseEntry(hash
, comment
));
354 * Save text to the file
356 * @param file the file to save to
357 * @throws IOException if there is IO problem
359 public void save(final String file
) throws IOException
{
360 String encoding
= GitConfigUtil
.getLogEncoding(myProject
, myGitRoot
);
361 PrintWriter out
= new PrintWriter(new OutputStreamWriter(new FileOutputStream(file
), encoding
));
363 for (GitRebaseEntry e
: myEntries
) {
364 if (e
.getAction() != GitRebaseEntry
.Action
.skip
) {
365 out
.println(e
.getAction().toString() + " " + e
.getCommit() + " " + e
.getSubject());
375 * Save text to the file
377 * @param file the file to save to
378 * @throws IOException if there is IO problem
380 public void cancel(final String file
) throws IOException
{
381 PrintWriter out
= new PrintWriter(new FileWriter(file
));
383 //noinspection HardCodedStringLiteral
384 out
.println("# rebase is cancelled");
393 * Move selected row up. If row cannot be moved up, do nothing and return false.
395 * @param row a row to move
396 * @return true if row was moved
398 public boolean moveUp(final int row
) {
399 if (row
< 1 || row
>= myEntries
.size()) {
402 myCommitsTable
.removeEditor();
403 GitRebaseEntry e
= myEntries
.get(row
);
404 myEntries
.set(row
, myEntries
.get(row
- 1));
405 myEntries
.set(row
- 1, e
);
406 fireTableRowsUpdated(row
- 1, row
);
411 * Move selected row down. If row cannot be moved down, do nothing and return false.
413 * @param row a row to move
414 * @return true if row was moved
416 public boolean moveDown(final int row
) {
417 if (row
< 0 || row
>= myEntries
.size() - 1) {
420 myCommitsTable
.removeEditor();
421 GitRebaseEntry e
= myEntries
.get(row
);
422 myEntries
.set(row
, myEntries
.get(row
+ 1));
423 myEntries
.set(row
+ 1, e
);
424 fireTableRowsUpdated(row
, row
+ 1);