/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.community.intellij.plugins.communitycase.checkout.branches;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.table.AbstractTableModel;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The dialog shown to inform of changes in the current configuration
*/
public class BranchConfigurationChangedDialog extends DialogWrapper {
/**
* The new configuration exit code
*/
private static final int NEW_CONFIGURATION = NEXT_USER_EXIT_CODE;
/**
* The name text field
*/
private JTextField myNameTextField;
/**
* The table that describes configuration changes
*/
private JBTable myTable;
/**
* The root panel
*/
private JPanel myRootPanel;
/**
* The base directory for the project
*/
private final File myBaseFile;
/**
* The branch descriptors to show in the table
*/
private final List<BranchDescriptor> myBranches;
/**
* The new configuration action
*/
private DialogWrapperExitAction myNewAction;
/**
* The constructor from project
*
* @param project the project to use to display window
* @param config
* @param branches
* @param names
*/
protected BranchConfigurationChangedDialog(Project project,
final BranchConfiguration config,
List<BranchDescriptor> branches, final Set<String> names) {
super(project, true);
setTitle(" Branch Configuration Changed");
myBranches = branches;
VirtualFile baseDir = project.getBaseDir();
myBaseFile = baseDir == null ? null : new File(baseDir.getPath());
myTable.setModel(new DescriptorTableModel());
myNameTextField.setText(config.getName());
myNewAction = new DialogWrapperExitAction("New Configuration", NEW_CONFIGURATION);
final DocumentAdapter l = new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
String text = myNameTextField.getText().trim();
if (text.length() == 0) {
setError("Empty configuration name is not allowed.");
}
else if (text.equals(config.getName())) {
setError(null);
myNewAction.setEnabled(false);
}
else if (names.contains(text)) {
setError("There is another configuration with the same name");
}
else {
setError(null);
}
}
private void setError(String s) {
setErrorText(s);
setOKActionEnabled(s == null);
myNewAction.setEnabled(s == null);
}
};
myNameTextField.getDocument().addDocumentListener(l);
l.changedUpdate(null);
setOKButtonText("Update");
init();
}
/**
* {@inheritDoc}
*/
@Override
protected JComponent createCenterPanel() {
return myRootPanel;
}
/**
* Show the dialog in AWT thread and wait for its completion
*
* @param settings the settings to use
* @param config the configuration to check
* @param roots the roots collection
* @return null if project is cancelled, or configuration that user has selected for storing the current state (created or updated)
*/
@Nullable
static BranchConfiguration showDialog(final BranchConfigurations settings,
final BranchConfiguration config,
final List<VirtualFile> roots)
throws VcsException {
final Set<String> names = settings.getConfigurationNames();
final Ref<String> name = new Ref<String>();
final Ref<Integer> code = new Ref<Integer>();
final List<BranchDescriptor> list = prepareBranchDescriptors(settings, config, roots);
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
BranchConfigurationChangedDialog d = new BranchConfigurationChangedDialog(settings.getProject(), config, list, names);
d.show();
code.set(d.getExitCode());
name.set(d.myNameTextField.getText());
}
});
if (code.get() == CANCEL_EXIT_CODE) {
return null;
}
BranchConfiguration updateConfig;
synchronized (settings.getStateLock()) {
if (code.get() == OK_EXIT_CODE) {
updateConfig = config;
updateConfig.setName(name.get());
}
else if (code.get() == NEW_CONFIGURATION) {
updateConfig = settings.createConfiguration(name.get());
}
else {
throw new RuntimeException("Unexpected exit code: " + code.get());
}
updateConfig.clearReferences();
for (BranchDescriptor d : list) {
if (d.root != null) {
updateConfig.setReference(d.root.getPath(), d.actualRef);
}
}
}
return updateConfig;
}
/**
* {@inheritDoc}
*/
@Override
protected Action[] createActions() {
return new Action[]{getOKAction(), myNewAction, getCancelAction()};
}
/**
* {@inheritDoc}
*/
@Override
protected String getDimensionServiceKey() {
return getClass().getName();
}
static List<BranchDescriptor> prepareBranchDescriptors(BranchConfigurations settings,
BranchConfiguration config,
List<VirtualFile> roots)
throws VcsException {
List<BranchDescriptor> rc = new ArrayList<BranchDescriptor>();
Map<String, String> map = config.getReferences();
for (VirtualFile root : roots) {
BranchDescriptor d = new BranchDescriptor();
d.root = root;
d.actualRef = settings.describeRoot(root);
d.storedRef = map.remove(root.getPath());
rc.add(d);
}
for (Map.Entry<String, String> m : map.entrySet()) {
BranchDescriptor d = new BranchDescriptor();
d.storedRoot = m.getKey();
d.storedRef = m.getValue();
rc.add(d);
}
return rc;
}
/**
* The table model that describes roots
*/
private class DescriptorTableModel extends AbstractTableModel {
/**
* The relative path for the root
*/
private static final int ROOT_COLUMN = 0;
/**
* The actual reference
*/
private static final int ACTUAL_REF_COLUMN = 1;
/**
* The reference stored in the configuration
*/
private static final int STORED_REF_COLUMN = 2;
/**
* {@inheritDoc}
*/
@Override
public int getRowCount() {
return myBranches.size();
}
/**
* {@inheritDoc}
*/
@Override
public int getColumnCount() {
return STORED_REF_COLUMN + 1;
}
/**
* {@inheritDoc}
*/
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
BranchDescriptor d = myBranches.get(rowIndex);
switch (columnIndex) {
case ROOT_COLUMN:
return d.getRoot(myBaseFile);
case ACTUAL_REF_COLUMN:
return d.actualRef == null ? "" : d.actualRef;
case STORED_REF_COLUMN:
return d.storedRef == null ? "" : d.storedRef;
default:
throw new IllegalStateException("Unexpected column");
}
}
/**
* {@inheritDoc}
*/
@Override
public String getColumnName(int column) {
switch (column) {
case ROOT_COLUMN:
return "Vcs Root";
case ACTUAL_REF_COLUMN:
return "Actual";
case STORED_REF_COLUMN:
return "Configured";
default:
throw new IllegalStateException("Unexpected column");
}
}
}
/**
* The descriptor for the branch
*/
private static class BranchDescriptor {
/**
* The vcs root
*/
VirtualFile root;
/**
* The branch information stored in the configuration
*/
String storedRoot;
/**
* The stored reference
*/
String storedRef;
/**
* The actual reference
*/
String actualRef;
public String getRoot(final File baseFile) {
String path = root == null ? storedRoot : root.getPath();
String relative = baseFile == null ? path : FileUtil.getRelativePath(baseFile, new File(path));
return relative == null ? path : relative;
}
}
}