blob: 282f44d04a604b79c13750cbbde2452d6f57dae4 [file] [log] [blame]
/*
* Copyright 2000-2013 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 com.intellij.application.options.codeStyle;
import com.intellij.application.options.*;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDialog;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.options.SchemeImportException;
import com.intellij.openapi.options.SchemeImporter;
import com.intellij.openapi.options.SchemeImporterEP;
import com.intellij.openapi.options.SchemesManager;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.impl.source.codeStyle.CodeStyleSchemeImpl;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.table.JBTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.List;
/**
* @author: rvishnyakov
*/
public class ManageCodeStyleSchemesDialog extends DialogWrapper {
private JPanel myContentPane;
private JBTable mySchemesTable;
private JButton myDeleteButton;
private JButton mySaveAsButton;
private JButton myCopyToProjectButton;
private JButton myCloseButton;
private JButton myExportButton;
private JButton myImportButton;
private final MySchemesTableModel mySchemesTableModel;
private final CodeStyleSchemesModel myModel;
private final Component myParent;
private final SchemesManager<CodeStyleScheme, CodeStyleSchemeImpl> mySchemesManager;
protected ManageCodeStyleSchemesDialog(final Component parent, CodeStyleSchemesModel schemesModel) {
super(parent, true);
myParent = parent;
myModel = schemesModel;
setTitle("Code Style Schemes");
mySchemesTableModel = new MySchemesTableModel(schemesModel);
mySchemesTable.setModel(mySchemesTableModel);
mySchemesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
mySchemesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(@NotNull ListSelectionEvent e) {
updateActions();
}
});
setDefaultSelection();
myDeleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
deleteSelected();
}
});
mySaveAsButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
onSaveAs();
}
});
myCopyToProjectButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
onCopyToProject();
}
});
myCloseButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(@NotNull ActionEvent e) {
doCancelAction();
}
});
mySchemesManager = CodeStyleSchemesModel.getSchemesManager();
if (mySchemesManager.isExportAvailable()) {
myExportButton.setVisible(true);
myExportButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull final ActionEvent e) {
CodeStyleScheme selected = getSelectedScheme();
ExportSchemeAction.doExport((CodeStyleSchemeImpl)selected, mySchemesManager);
}
});
myExportButton.setMnemonic('S');
}
else {
myExportButton.setVisible(false);
}
if (mySchemesManager.isImportAvailable() || SchemeImporterEP.getExtensions(CodeStyleScheme.class).size() > 0) {
myImportButton.setVisible(true);
myImportButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull final ActionEvent e) {
chooseAndImport();
}
});
}
else {
myImportButton.setVisible(false);
}
init();
}
private void chooseAndImport() {
ImportSourceChooserDialog<CodeStyleScheme> importSourceChooserDialog =
new ImportSourceChooserDialog<CodeStyleScheme>(myContentPane, CodeStyleScheme.class, mySchemesManager);
importSourceChooserDialog.show();
if (importSourceChooserDialog.isOK()) {
if (importSourceChooserDialog.isImportFromSharedSelected()) {
SchemesToImportPopup<CodeStyleScheme, CodeStyleSchemeImpl> popup =
new SchemesToImportPopup<CodeStyleScheme, CodeStyleSchemeImpl>(myContentPane) {
@Override
protected void onSchemeSelected(final CodeStyleSchemeImpl scheme) {
if (scheme != null) {
myModel.addScheme(scheme, true);
}
}
};
popup.show(mySchemesManager, myModel.getSchemes());
}
else {
String selectedImporterName = importSourceChooserDialog.getSelectedSourceName();
if (selectedImporterName != null) {
try {
String schemeName = importExternalCodeStyle(selectedImporterName);
if (schemeName != null) {
showStatus(myImportButton,
ApplicationBundle.message("message.code.style.scheme.import.success", selectedImporterName, schemeName),
MessageType.INFO);
}
}
catch (SchemeImportException e) {
showStatus(myImportButton,
ApplicationBundle.message("message.code.style.scheme.import.failure", selectedImporterName, e.getMessage()),
MessageType.ERROR);
}
}
}
}
}
private static void showStatus(final Component component, final String message, MessageType messageType) {
BalloonBuilder balloonBuilder = JBPopupFactory.getInstance()
.createHtmlTextBalloonBuilder(message, messageType.getDefaultIcon(),
messageType.getPopupBackground(), null);
balloonBuilder.setFadeoutTime(5000);
final Balloon balloon = balloonBuilder.createBalloon();
final Rectangle rect = component.getBounds();
final Point p = new Point(rect.x, rect.y + rect.height);
final RelativePoint point = new RelativePoint(component, p);
balloon.show(point, Balloon.Position.below);
Disposer.register(ProjectManager.getInstance().getDefaultProject(), balloon);
}
@Nullable
private String importExternalCodeStyle(String importerName) throws SchemeImportException {
final SchemeImporter<CodeStyleScheme> importer = SchemeImporterEP.getImporter(importerName, CodeStyleScheme.class);
if (importer != null) {
FileChooserDialog fileChooser = FileChooserFactory.getInstance()
.createFileChooser(new FileChooserDescriptor(true, false, false, false, false, false) {
@Override
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
return file.isDirectory() || importer.getSourceExtension().equals(file.getExtension());
}
@Override
public boolean isFileSelectable(VirtualFile file) {
return !file.isDirectory() && importer.getSourceExtension().equals(file.getExtension());
}
}, null, myContentPane);
VirtualFile[] selection = fileChooser.choose(null, CodeStyleSchemesUIConfiguration.Util.getRecentImportFile());
if (selection.length == 1) {
VirtualFile selectedFile = selection[0];
selectedFile.refresh(false, false);
CodeStyleSchemesUIConfiguration.Util.setRecentImportFile(selectedFile);
try {
InputStream nameInputStream = selectedFile.getInputStream();
String[] schemeNames;
try {
schemeNames = importer.readSchemeNames(nameInputStream);
}
finally {
nameInputStream.close();
}
CodeStyleScheme currScheme = myModel.getSelectedScheme();
ImportSchemeChooserDialog schemeChooserDialog =
new ImportSchemeChooserDialog(myContentPane, schemeNames, !currScheme.isDefault() ? currScheme.getName() : null);
schemeChooserDialog.show();
if (schemeChooserDialog.isOK()) {
String schemeName = schemeChooserDialog.getSelectedName();
String targetName = schemeChooserDialog.getTargetName();
CodeStyleScheme targetScheme = null;
if (schemeChooserDialog.isUseCurrentScheme()) {
targetScheme = myModel.getSelectedScheme();
}
else {
if (targetName == null) targetName = ApplicationBundle.message("code.style.scheme.import.unnamed");
for (CodeStyleScheme scheme : myModel.getSchemes()) {
if (targetName.equals(scheme.getName())) {
targetScheme = scheme;
break;
}
}
if (targetScheme == null) {
int row = mySchemesTableModel.createNewScheme(getSelectedScheme(), targetName);
mySchemesTable.getSelectionModel().setSelectionInterval(row, row);
targetScheme = mySchemesTableModel.getSchemeAt(row);
}
else {
int result = Messages.showYesNoDialog(myContentPane,
ApplicationBundle.message("message.code.style.scheme.already.exists", targetName),
ApplicationBundle.message("title.code.style.settings.import"),
Messages.getQuestionIcon());
if (result != Messages.YES) {
return null;
}
}
}
InputStream dataInputStream = selectedFile.getInputStream();
try {
importer.importScheme(dataInputStream, schemeName, targetScheme);
myModel.fireSchemeChanged(targetScheme);
}
finally {
dataInputStream.close();
}
return targetScheme.getName();
}
}
catch (IOException e) {
throw new SchemeImportException(e);
}
}
}
return null;
}
private void updateActions() {
CodeStyleScheme selectedScheme = getSelectedScheme();
myDeleteButton.setEnabled(!(selectedScheme.isDefault() || mySchemesTableModel.isProjectScheme(selectedScheme)));
myCopyToProjectButton.setEnabled(!mySchemesTableModel.isProjectScheme(selectedScheme));
}
@NotNull
private CodeStyleScheme getSelectedScheme() {
int row = mySchemesTable.getSelectedRow();
assert row >= 0;
return mySchemesTableModel.getSchemeAt(row);
}
@NotNull
@Override
protected Action[] createActions() {
return new Action[]{};
}
private void deleteSelected() {
int row = mySchemesTable.getSelectedRow();
if (row >= 0) {
int rowToSelect = row + 1;
if (rowToSelect >= mySchemesTableModel.getRowCount()) {
rowToSelect = mySchemesTableModel.getDefaultRow();
}
mySchemesTable.getSelectionModel().setSelectionInterval(rowToSelect, rowToSelect);
mySchemesTableModel.deleteAt(row);
}
}
@Override
protected JComponent createCenterPanel() {
return myContentPane;
}
private void createUIComponents() {
mySchemesTable = new MySchemesTable();
}
private class MySchemesTable extends JBTable {
private final TableCellRenderer myFixedItemsRenderer;
private MySchemesTable() {
myFixedItemsRenderer = new DefaultTableCellRenderer() {
@NotNull
@Override
public Component getTableCellRendererComponent(@NotNull JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component defaultComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value instanceof CodeStyleScheme) {
CodeStyleScheme scheme = (CodeStyleScheme)value;
if (scheme.isDefault() || myModel.isProjectScheme(scheme)) {
defaultComponent.setFont(defaultComponent.getFont().deriveFont(Font.BOLD));
}
}
return defaultComponent;
}
};
}
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
return myFixedItemsRenderer;
}
}
private static class MySchemesTableModel extends AbstractTableModel {
private final CodeStyleSchemesModel mySchemesModel;
private final List<CodeStyleScheme> mySchemes;
public MySchemesTableModel(CodeStyleSchemesModel schemesModel) {
mySchemesModel = schemesModel;
mySchemes = new ArrayList<CodeStyleScheme>();
updateSchemes();
}
@NotNull
@Override
public String getColumnName(int column) {
assert column == 0;
return "Name";
}
@Override
public int getRowCount() {
return mySchemes.size();
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
assert columnIndex == 0;
return mySchemes.get(rowIndex);
}
public CodeStyleScheme getSchemeAt(int row) {
return mySchemes.get(row);
}
public void deleteAt(int row) {
CodeStyleScheme scheme = mySchemes.get(row);
mySchemesModel.removeScheme(scheme);
updateSchemes();
fireTableRowsDeleted(row, row);
}
public int createNewScheme(CodeStyleScheme selectedScheme, String schemeName) {
CodeStyleScheme newScheme = mySchemesModel.createNewScheme(schemeName, selectedScheme);
mySchemesModel.addScheme(newScheme, true);
updateSchemes();
int row = 0;
for (CodeStyleScheme scheme : mySchemes) {
if (scheme == newScheme) {
fireTableRowsInserted(row, row);
break;
}
row ++;
}
return row;
}
public int getDefaultRow() {
int row = 0;
for (CodeStyleScheme scheme : mySchemes) {
if (scheme.isDefault()) return row;
row ++;
}
return 0;
}
public void copyToProject(CodeStyleScheme scheme) {
mySchemesModel.copyToProject(scheme);
int switchToProject = Messages
.showYesNoDialog("Scheme '" + scheme.getName() + "' was copied to be used as the project scheme.\n" +
"Switch to this created scheme?",
"Copy Scheme to Project", Messages.getQuestionIcon());
if (switchToProject == Messages.YES) {
mySchemesModel.setUsePerProjectSettings(true, true);
}
}
public int exportProjectScheme() {
String name = Messages.showInputDialog("Enter new scheme name:", "Copy Project Scheme to Global List", Messages.getQuestionIcon());
if (name != null && !CodeStyleSchemesModel.PROJECT_SCHEME_NAME.equals(name)) {
CodeStyleScheme newScheme = mySchemesModel.exportProjectScheme(name);
updateSchemes();
int switchToGlobal = Messages
.showYesNoDialog("Project scheme was copied to global scheme list as '" + newScheme.getName() + "'.\n" +
"Switch to this created scheme?",
"Copy Project Scheme to Global List", Messages.getQuestionIcon());
if (switchToGlobal == Messages.YES) {
mySchemesModel.setUsePerProjectSettings(false);
mySchemesModel.selectScheme(newScheme, null);
}
int row = 0;
for (CodeStyleScheme scheme : mySchemes) {
if (scheme == newScheme) {
fireTableRowsInserted(row, row);
return switchToGlobal == 0 ? row : -1;
}
row++;
}
}
return -1;
}
private void updateSchemes() {
mySchemes.clear();
mySchemes.addAll(mySchemesModel.getAllSortedSchemes());
}
public boolean isProjectScheme(CodeStyleScheme scheme) {
return mySchemesModel.isProjectScheme(scheme);
}
}
private void onSaveAs() {
if (mySchemesTableModel.isProjectScheme(getSelectedScheme())) {
int rowToSelect = mySchemesTableModel.exportProjectScheme();
if (rowToSelect > 0) {
mySchemesTable.getSelectionModel().setSelectionInterval(rowToSelect, rowToSelect);
}
}
else {
CodeStyleScheme[] schemes = CodeStyleSchemes.getInstance().getSchemes();
ArrayList<String> names = new ArrayList<String>();
for (CodeStyleScheme scheme : schemes) {
names.add(scheme.getName());
}
String selectedName = getSelectedScheme().getName();
SaveSchemeDialog saveDialog = new SaveSchemeDialog(myParent, ApplicationBundle.message("title.save.code.style.scheme.as"), names, selectedName);
saveDialog.show();
if (saveDialog.isOK()) {
int row = mySchemesTableModel.createNewScheme(getSelectedScheme(), saveDialog.getSchemeName());
mySchemesTable.getSelectionModel().setSelectionInterval(row, row);
}
}
}
private void onCopyToProject() {
mySchemesTableModel.copyToProject(getSelectedScheme());
}
private void setDefaultSelection() {
CodeStyleScheme selectedScheme = myModel.getSelectedScheme();
for (int i = 0; i < mySchemesTableModel.getRowCount(); i ++) {
if (mySchemesTableModel.getSchemeAt(i).equals(selectedScheme)) {
mySchemesTable.getSelectionModel().setSelectionInterval(i, i);
return;
}
}
}
}