blob: 2febf94b2470c0b0c5939000b770e0b9c6f68636 [file] [log] [blame]
/*
* Copyright 2000-2012 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.intellij.plugins.intelliLang;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.ui.SplitterProportionsDataImpl;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.SplitterProportionsData;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWrapper;
import com.intellij.psi.injection.ReferenceInjector;
import com.intellij.ui.*;
import com.intellij.ui.speedSearch.SpeedSearchSupply;
import com.intellij.ui.table.TableView;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport;
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace;
import org.jdom.Document;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* @author Gregory.Shrago
*/
public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Configurable.NoScroll {
private final Project myProject;
private final CfgInfo[] myInfos;
private final JPanel myRoot;
private final InjectionsTable myInjectionsTable;
private final Map<String, LanguageInjectionSupport> mySupports = ContainerUtil.newLinkedHashMap();
private final Map<String, AnAction> myEditActions = ContainerUtil.newLinkedHashMap();
private final List<AnAction> myAddActions = ContainerUtil.newArrayList();
private final JLabel myCountLabel;
private Configurable[] myConfigurables;
private Configuration myConfiguration;
public InjectionsSettingsUI(final Project project, final Configuration configuration) {
myProject = project;
myConfiguration = configuration;
final CfgInfo currentInfo = new CfgInfo(configuration, "project");
myInfos = configuration instanceof Configuration.Prj ?
new CfgInfo[]{new CfgInfo(((Configuration.Prj)configuration).getParentConfiguration(), "global"), currentInfo}
: new CfgInfo[]{currentInfo};
myRoot = new JPanel(new BorderLayout());
myInjectionsTable = new InjectionsTable(getInjInfoList(myInfos));
myInjectionsTable.getEmptyText().setText("No injections configured");
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myInjectionsTable);
createActions(decorator);
//myRoot.add(new TitledSeparator("Languages injection places"), BorderLayout.NORTH);
myRoot.add(decorator.createPanel(), BorderLayout.CENTER);
myCountLabel = new JLabel();
myCountLabel.setHorizontalAlignment(SwingConstants.RIGHT);
myCountLabel.setForeground(SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES.getFgColor());
myRoot.add(myCountLabel, BorderLayout.SOUTH);
updateCountLabel();
}
private void createActions(ToolbarDecorator decorator) {
final Consumer<BaseInjection> consumer = new Consumer<BaseInjection>() {
public void consume(final BaseInjection injection) {
addInjection(injection);
}
};
final Factory<BaseInjection> producer = new NullableFactory<BaseInjection>() {
public BaseInjection create() {
final InjInfo info = getSelectedInjection();
return info == null? null : info.injection;
}
};
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
ContainerUtil.addAll(myAddActions, support.createAddActions(myProject, consumer));
final AnAction action = support.createEditAction(myProject, producer);
myEditActions
.put(support.getId(), action == null ? AbstractLanguageInjectionSupport.createDefaultEditAction(myProject, producer) : action);
mySupports.put(support.getId(), support);
}
Collections.sort(myAddActions, new Comparator<AnAction>() {
public int compare(final AnAction o1, final AnAction o2) {
return Comparing.compare(o1.getTemplatePresentation().getText(), o2.getTemplatePresentation().getText());
}
});
decorator.disableUpDownActions();
decorator.setAddActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
return !myAddActions.isEmpty();
}
});
decorator.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
performAdd(button);
}
});
decorator.setRemoveActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
boolean enabled = false;
for (InjInfo info : getSelectedInjections()) {
if (!info.bundled) {
enabled = true;
break;
}
}
return enabled;
}
});
decorator.setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
performRemove();
}
});
decorator.setEditActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
AnAction edit = getEditAction();
if (edit != null) edit.update(e);
return edit != null && edit.getTemplatePresentation().isEnabled();
}
});
decorator.setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
performEditAction();
}
});
decorator.addExtraAction(new DumbAwareActionButton("Duplicate", "Duplicate", PlatformIcons.COPY_ICON) {
@Override
public boolean isEnabled() {
return getEditAction() != null;
}
@Override
public void actionPerformed(AnActionEvent e) {
final InjInfo injection = getSelectedInjection();
if (injection != null) {
addInjection(injection.injection.copy());
//performEditAction(e);
}
}
});
decorator.addExtraAction(new DumbAwareActionButton("Enable Selected Injections", "Enable Selected Injections", PlatformIcons.SELECT_ALL_ICON) {
@Override
public void actionPerformed(final AnActionEvent e) {
performSelectedInjectionsEnabled(true);
}
});
decorator.addExtraAction(new DumbAwareActionButton("Disable Selected Injections", "Disable Selected Injections", PlatformIcons.UNSELECT_ALL_ICON) {
@Override
public void actionPerformed(final AnActionEvent e) {
performSelectedInjectionsEnabled(false);
}
});
new DumbAwareAction("Toggle") {
@Override
public void update(AnActionEvent e) {
SpeedSearchSupply supply = SpeedSearchSupply.getSupply(myInjectionsTable);
e.getPresentation().setEnabled(supply == null || !supply.isPopupActive());
}
@Override
public void actionPerformed(final AnActionEvent e) {
performToggleAction();
}
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myInjectionsTable);
if (myInfos.length > 1) {
AnActionButton shareAction = new DumbAwareActionButton("Make Global", null, PlatformIcons.IMPORT_ICON) {
{
addCustomUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
CfgInfo cfg = getTargetCfgInfo(getSelectedInjections());
e.getPresentation().setText(cfg == getDefaultCfgInfo() ? "Make Global" : "Move to Project");
return cfg != null;
}
});
}
@Override
public void actionPerformed(final AnActionEvent e) {
final List<InjInfo> injections = getSelectedInjections();
final CfgInfo cfg = getTargetCfgInfo(injections);
if (cfg == null) return;
for (InjInfo info : injections) {
if (info.cfgInfo == cfg) continue;
if (info.bundled) continue;
info.cfgInfo.injectionInfos.remove(info);
cfg.addInjection(info.injection);
}
final int[] selectedRows = myInjectionsTable.getSelectedRows();
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
TableUtil.selectRows(myInjectionsTable, selectedRows);
}
@Nullable
private CfgInfo getTargetCfgInfo(final List<InjInfo> injections) {
CfgInfo cfg = null;
for (InjInfo info : injections) {
if (info.bundled) {
continue;
}
if (cfg == null) cfg = info.cfgInfo;
else if (cfg != info.cfgInfo) return info.cfgInfo;
}
if (cfg == null) return null;
for (CfgInfo info : myInfos) {
if (info != cfg) return info;
}
throw new AssertionError();
}
};
shareAction.setShortcut(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK)));
decorator.addExtraAction(shareAction);
}
decorator.addExtraAction(new DumbAwareActionButton("Import", "Import", AllIcons.Actions.Install) {
@Override
public void actionPerformed(final AnActionEvent e) {
doImportAction(e.getDataContext());
updateCountLabel();
}
});
decorator.addExtraAction(new DumbAwareActionButton("Export", "Export", AllIcons.Actions.Export) {
@Override
public void actionPerformed(final AnActionEvent e) {
final List<BaseInjection> injections = getInjectionList(getSelectedInjections());
final VirtualFileWrapper wrapper = FileChooserFactory.getInstance().createSaveFileDialog(
new FileSaverDescriptor("Export Selected Injections to File...", "", "xml"), myProject).save(null, null);
if (wrapper == null) return;
final Configuration configuration = new Configuration();
configuration.setInjections(injections);
final Document document = new Document(configuration.getState());
try {
JDOMUtil.writeDocument(document, wrapper.getFile(), "\n");
}
catch (IOException ex) {
final String msg = ex.getLocalizedMessage();
Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : ex.toString(), "Export Failed");
}
}
@Override
public boolean isEnabled() {
return !getSelectedInjections().isEmpty();
}
});
}
private void performEditAction() {
final AnAction action = getEditAction();
if (action != null) {
final int row = myInjectionsTable.getSelectedRow();
action.actionPerformed(new AnActionEvent(null, DataManager.getInstance().getDataContext(myInjectionsTable),
ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0));
myInjectionsTable.getListTableModel().fireTableDataChanged();
myInjectionsTable.getSelectionModel().setSelectionInterval(row, row);
updateCountLabel();
}
}
private void updateCountLabel() {
int placesCount = 0;
int enablePlacesCount = 0;
final List<InjInfo> items = myInjectionsTable.getListTableModel().getItems();
if (!items.isEmpty()) {
for (InjInfo injection : items) {
for (InjectionPlace place : injection.injection.getInjectionPlaces()) {
placesCount++;
if (place.isEnabled()) enablePlacesCount++;
}
}
myCountLabel.setText(items.size() + " injection" + (items.size() > 1 ? "s" : "") + " (" + enablePlacesCount + " of " +
placesCount + " place" + (placesCount > 1 ? "s" : "") + " enabled) ");
}
else {
myCountLabel.setText("no injections configured ");
}
}
@Nullable
private AnAction getEditAction() {
final InjInfo info = getSelectedInjection();
final String supportId = info == null? null : info.injection.getSupportId();
return supportId == null? null : myEditActions.get(supportId);
}
private void addInjection(final BaseInjection injection) {
final InjInfo info = getDefaultCfgInfo().addInjection(injection);
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
final int index = myInjectionsTable.convertRowIndexToView(myInjectionsTable.getListTableModel().getItems().indexOf(info));
myInjectionsTable.getSelectionModel().setSelectionInterval(index, index);
TableUtil.scrollSelectionToVisible(myInjectionsTable);
}
private CfgInfo getDefaultCfgInfo() {
return myInfos[0];
}
@Override
public boolean hasOwnContent() {
return true;
}
@Override
public boolean isVisible() {
return true;
}
@Override
public Configurable[] getConfigurables() {
if (myConfigurables == null) {
final ArrayList<Configurable> configurables = new ArrayList<Configurable>();
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
ContainerUtil.addAll(configurables, support.createSettings(myProject, myConfiguration));
}
Collections.sort(configurables, new Comparator<Configurable>() {
public int compare(final Configurable o1, final Configurable o2) {
return Comparing.compare(o1.getDisplayName(), o2.getDisplayName());
}
});
myConfigurables = configurables.toArray(new Configurable[configurables.size()]);
}
return myConfigurables;
}
@NotNull
@Override
public String getId() {
return "IntelliLang.Configuration";
}
@Override
public Runnable enableSearch(String option) {
return null;
}
private static void sortInjections(final List<BaseInjection> injections) {
Collections.sort(injections, new Comparator<BaseInjection>() {
public int compare(final BaseInjection o1, final BaseInjection o2) {
final int support = Comparing.compare(o1.getSupportId(), o2.getSupportId());
if (support != 0) return support;
final int lang = Comparing.compare(o1.getInjectedLanguageId(), o2.getInjectedLanguageId());
if (lang != 0) return lang;
return Comparing.compare(o1.getDisplayName(), o2.getDisplayName());
}
});
}
public JComponent createComponent() {
return myRoot;
}
public void reset() {
for (CfgInfo info : myInfos) {
info.reset();
}
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
updateCountLabel();
}
public void disposeUIResources() {
}
public void apply() {
for (CfgInfo info : myInfos) {
info.apply();
}
reset();
}
public boolean isModified() {
for (CfgInfo info : myInfos) {
if (info.isModified()) return true;
}
return false;
}
private void performSelectedInjectionsEnabled(final boolean enabled) {
for (InjInfo info : getSelectedInjections()) {
info.injection.setPlaceEnabled(null, enabled);
}
myInjectionsTable.updateUI();
updateCountLabel();
}
private void performToggleAction() {
final List<InjInfo> selectedInjections = getSelectedInjections();
boolean enabledExists = false;
boolean disabledExists = false;
for (InjInfo info : selectedInjections) {
if (info.injection.isEnabled()) enabledExists = true;
else disabledExists = true;
if (enabledExists && disabledExists) break;
}
boolean allEnabled = !enabledExists && disabledExists;
performSelectedInjectionsEnabled(allEnabled);
}
private void performRemove() {
final int selectedRow = myInjectionsTable.getSelectedRow();
if (selectedRow < 0) return;
final List<InjInfo> selected = getSelectedInjections();
for (InjInfo info : selected) {
if (info.bundled) continue;
info.cfgInfo.injectionInfos.remove(info);
}
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
final int index = Math.min(myInjectionsTable.getListTableModel().getRowCount() - 1, selectedRow);
myInjectionsTable.getSelectionModel().setSelectionInterval(index, index);
TableUtil.scrollSelectionToVisible(myInjectionsTable);
updateCountLabel();
}
private List<InjInfo> getSelectedInjections() {
final ArrayList<InjInfo> toRemove = new ArrayList<InjInfo>();
for (int row : myInjectionsTable.getSelectedRows()) {
toRemove.add(myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row)));
}
return toRemove;
}
@Nullable
private InjInfo getSelectedInjection() {
final int row = myInjectionsTable.getSelectedRow();
return row < 0? null : myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row));
}
private void performAdd(AnActionButton e) {
DefaultActionGroup group = new DefaultActionGroup(myAddActions);
JBPopupFactory.getInstance().createActionGroupPopup(null, group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.NUMBERING, true, new Runnable() {
public void run() {
updateCountLabel();
}
}, -1).show(e.getPreferredPopupPoint());
}
@Nls
public String getDisplayName() {
return "Language Injections";
}
public String getHelpTopic() {
return "reference.settings.injection.language.injection.settings";
}
private class InjectionsTable extends TableView<InjInfo> {
private InjectionsTable(final List<InjInfo> injections) {
super(new ListTableModel<InjInfo>(createInjectionColumnInfos(), injections, 1));
setAutoResizeMode(AUTO_RESIZE_LAST_COLUMN);
getColumnModel().getColumn(2).setCellRenderer(createLanguageCellRenderer());
getColumnModel().getColumn(1).setCellRenderer(createDisplayNameCellRenderer());
getColumnModel().getColumn(0).setResizable(false);
setShowGrid(false);
setShowVerticalLines(false);
setGridColor(getForeground());
TableUtil.setupCheckboxColumn(getColumnModel().getColumn(0));
new DoubleClickListener() {
@Override
protected boolean onDoubleClick(MouseEvent e) {
final int row = rowAtPoint(e.getPoint());
if (row < 0) return false;
if (columnAtPoint(e.getPoint()) <= 0) return false;
myInjectionsTable.getSelectionModel().setSelectionInterval(row, row);
performEditAction();
return true;
}
}.installOn(this);
final String[] maxName = new String[]{""};
ContainerUtil.process(injections, new Processor<InjInfo>() {
public boolean process(final InjInfo injection) {
String languageId = injection.injection.getInjectedLanguageId();
Language language = InjectedLanguage.findLanguageById(languageId);
String displayName = language == null ? languageId : language.getDisplayName();
if (maxName[0].length() < displayName.length()) maxName[0] = displayName;
return true;
}
});
ContainerUtil.process(InjectedLanguage.getAvailableLanguages(), new Processor<Language>() {
public boolean process(final Language language) {
String displayName = language.getDisplayName();
if (maxName[0].length() < displayName.length()) maxName[0] = displayName;
return true;
}
});
Icon icon = FileTypes.PLAIN_TEXT.getIcon();
int preferred = (int)(new JLabel(maxName[0], icon, SwingConstants.LEFT).getPreferredSize().width * 1.1);
getColumnModel().getColumn(2).setMinWidth(preferred);
getColumnModel().getColumn(2).setPreferredWidth(preferred);
getColumnModel().getColumn(2).setMaxWidth(preferred);
new TableViewSpeedSearch<InjInfo>(this) {
@Override
protected String getItemText(@NotNull InjInfo element) {
final BaseInjection injection = element.injection;
return injection.getSupportId() + " " + injection.getInjectedLanguageId() + " " + injection.getDisplayName();
}
};
}
}
private ColumnInfo[] createInjectionColumnInfos() {
final TableCellRenderer booleanCellRenderer = createBooleanCellRenderer();
final TableCellRenderer displayNameCellRenderer = createDisplayNameCellRenderer();
final TableCellRenderer languageCellRenderer = createLanguageCellRenderer();
final Comparator<InjInfo> languageComparator = new Comparator<InjInfo>() {
public int compare(final InjInfo o1, final InjInfo o2) {
return Comparing.compare(o1.injection.getInjectedLanguageId(), o2.injection.getInjectedLanguageId());
}
};
final Comparator<InjInfo> displayNameComparator = new Comparator<InjInfo>() {
public int compare(final InjInfo o1, final InjInfo o2) {
final int support = Comparing.compare(o1.injection.getSupportId(), o2.injection.getSupportId());
if (support != 0) return support;
return Comparing.compare(o1.injection.getDisplayName(), o2.injection.getDisplayName());
}
};
final ColumnInfo[] columnInfos = {new ColumnInfo<InjInfo, Boolean>(" ") {
@Override
public Class getColumnClass() {
return Boolean.class;
}
@Override
public Boolean valueOf(final InjInfo o) {
return o.injection.isEnabled();
}
@Override
public boolean isCellEditable(final InjInfo injection) {
return true;
}
@Override
public void setValue(final InjInfo injection, final Boolean value) {
injection.injection.setPlaceEnabled(null, value.booleanValue());
}
@Override
public TableCellRenderer getRenderer(final InjInfo injection) {
return booleanCellRenderer;
}
}, new ColumnInfo<InjInfo, InjInfo>("Name") {
@Override
public InjInfo valueOf(final InjInfo info) {
return info;
}
@Override
public Comparator<InjInfo> getComparator() {
return displayNameComparator;
}
@Override
public TableCellRenderer getRenderer(final InjInfo injection) {
return displayNameCellRenderer;
}
}, new ColumnInfo<InjInfo, InjInfo>("Language") {
@Override
public InjInfo valueOf(final InjInfo info) {
return info;
}
@Override
public Comparator<InjInfo> getComparator() {
return languageComparator;
}
@Override
public TableCellRenderer getRenderer(final InjInfo info) {
return languageCellRenderer;
}
}};
if (myInfos.length > 1) {
final TableCellRenderer typeRenderer = createTypeRenderer();
return ArrayUtil.append(columnInfos, new ColumnInfo<InjInfo, String>("Type") {
@Override
public String valueOf(final InjInfo info) {
return info.bundled ? "bundled" : info.cfgInfo.title;
}
@Override
public TableCellRenderer getRenderer(final InjInfo injInfo) {
return typeRenderer;
}
@Override
public int getWidth(final JTable table) {
return table.getFontMetrics(table.getFont()).stringWidth(StringUtil.repeatSymbol('m', 6));
}
@Override
public Comparator<InjInfo> getComparator() {
return new Comparator<InjInfo>() {
@Override
public int compare(final InjInfo o1, final InjInfo o2) {
return Comparing.compare(valueOf(o1), valueOf(o2));
}
};
}
});
}
return columnInfos;
}
private static BooleanTableCellRenderer createBooleanCellRenderer() {
return new BooleanTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(final JTable table,
final Object value,
final boolean isSelected,
final boolean hasFocus,
final int row,
final int column) {
return setLabelColors(super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column), table, isSelected, row);
}
};
}
private static TableCellRenderer createLanguageCellRenderer() {
return new TableCellRenderer() {
final JLabel myLabel = new JLabel();
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
final int row,
final int column) {
final InjInfo injection = (InjInfo)value;
// fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here
if (injection == null) return myLabel;
final String languageId = injection.injection.getInjectedLanguageId();
final Language language = InjectedLanguage.findLanguageById(languageId);
final FileType fileType = language == null ? null : language.getAssociatedFileType();
myLabel.setIcon(fileType == null ? null : fileType.getIcon());
myLabel.setText(language == null ? languageId : language.getDisplayName());
setLabelColors(myLabel, table, isSelected, row);
return myLabel;
}
};
}
private TableCellRenderer createDisplayNameCellRenderer() {
return new TableCellRenderer() {
final SimpleColoredComponent myLabel = new SimpleColoredComponent();
final SimpleColoredText myText = new SimpleColoredText();
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
final int row,
final int column) {
myLabel.clear();
final InjInfo info = (InjInfo)value;
// fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here
if (info == null) return myLabel;
final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES;
final String supportId = info.injection.getSupportId();
myText.append(supportId + ": ", grayAttrs);
mySupports.get(supportId).setupPresentation(info.injection, myText, isSelected);
myText.appendToComponent(myLabel);
myText.clear();
setLabelColors(myLabel, table, isSelected, row);
return myLabel;
}
};
}
private static TableCellRenderer createTypeRenderer() {
return new TableCellRenderer() {
final SimpleColoredComponent myLabel = new SimpleColoredComponent();
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
final int row,
final int column) {
myLabel.clear();
final String info = (String)value;
if (info == null) return myLabel;
final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES;
myLabel.append(info, grayAttrs);
setLabelColors(myLabel, table, isSelected, row);
return myLabel;
}
};
}
private static Component setLabelColors(final Component label, final JTable table, final boolean isSelected, final int row) {
if (label instanceof JComponent) {
((JComponent)label).setOpaque(true);
}
label.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
label.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
return label;
}
private void doImportAction(final DataContext dataContext) {
final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, true, false, true, false) {
@Override
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
return super.isFileVisible(file, showHiddenFiles) &&
(file.isDirectory() || "xml".equals(file.getExtension()) || file.getFileType() == FileTypes.ARCHIVE);
}
@Override
public boolean isFileSelectable(VirtualFile file) {
return file.getFileType() == StdFileTypes.XML;
}
};
descriptor.setDescription("Please select the configuration file (usually named IntelliLang.xml) to import.");
descriptor.setTitle("Import Configuration");
descriptor.putUserData(LangDataKeys.MODULE_CONTEXT, LangDataKeys.MODULE.getData(dataContext));
final SplitterProportionsData splitterData = new SplitterProportionsDataImpl();
splitterData.externalizeFromDimensionService("IntelliLang.ImportSettingsKey.SplitterProportions");
final VirtualFile file = FileChooser.chooseFile(descriptor, myProject, null);
if (file == null) return;
try {
final Configuration cfg = Configuration.load(file.getInputStream());
if (cfg == null) {
Messages.showWarningDialog(myProject, "The selected file does not contain any importable configuration.", "Nothing to Import");
return;
}
final CfgInfo info = getDefaultCfgInfo();
final Map<String,Set<InjInfo>> currentMap =
ContainerUtil.classify(info.injectionInfos.iterator(), new Convertor<InjInfo, String>() {
public String convert(final InjInfo o) {
return o.injection.getSupportId();
}
});
final List<BaseInjection> originalInjections = new ArrayList<BaseInjection>();
final List<BaseInjection> newInjections = new ArrayList<BaseInjection>();
//// remove duplicates
//for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) {
// final Set<BaseInjection> currentInjections = currentMap.get(supportId);
// if (currentInjections == null) continue;
// for (BaseInjection injection : currentInjections) {
// Configuration.importInjections(newInjections, Collections.singleton(injection), originalInjections, newInjections);
// }
//}
//myInjections.clear();
//myInjections.addAll(newInjections);
for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) {
ArrayList<InjInfo> list = new ArrayList<InjInfo>(ObjectUtils.notNull(currentMap.get(supportId), Collections.<InjInfo>emptyList()));
final List<BaseInjection> currentInjections = getInjectionList(list);
final List<BaseInjection> importingInjections = cfg.getInjections(supportId);
if (currentInjections == null) {
newInjections.addAll(importingInjections);
}
else {
Configuration.importInjections(currentInjections, importingInjections, originalInjections, newInjections);
}
}
info.replace(originalInjections, newInjections);
myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos));
final int n = newInjections.size();
if (n > 1) {
Messages.showInfoMessage(myProject, n + " entries have been successfully imported", "Import Successful");
}
else if (n == 1) {
Messages.showInfoMessage(myProject, "One entry has been successfully imported", "Import Successful");
}
else {
Messages.showInfoMessage(myProject, "No new entries have been imported", "Import");
}
}
catch (Exception ex) {
Configuration.LOG.error(ex);
final String msg = ex.getLocalizedMessage();
Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : ex.toString(), "Import Failed");
}
}
private static class CfgInfo {
final Configuration cfg;
final List<BaseInjection> originalInjections;
final List<InjInfo> injectionInfos = new ArrayList<InjInfo>();
final THashSet<BaseInjection> bundledInjections = new THashSet<BaseInjection>(new SameParamsAndPlacesStrategy());
final String title;
public CfgInfo(Configuration cfg, final String title) {
this.cfg = cfg;
this.title = title;
bundledInjections.addAll(cfg.getDefaultInjections());
originalInjections = new ArrayList<BaseInjection>(ContainerUtil
.concat(InjectorUtils.getActiveInjectionSupportIds(), new Function<String, Collection<? extends BaseInjection>>() {
public Collection<? extends BaseInjection> fun(final String s) {
List<BaseInjection> injections =
CfgInfo.this.cfg instanceof Configuration.Prj ? ((Configuration.Prj)CfgInfo.this.cfg).getOwnInjections(s) : CfgInfo.this.cfg
.getInjections(s);
return ContainerUtil.findAll(injections, new Condition<BaseInjection>() {
public boolean value(final BaseInjection injection) {
String id = injection.getInjectedLanguageId();
return InjectedLanguage.findLanguageById(id) != null || ReferenceInjector.findById(id) != null;
}
});
}
}));
sortInjections(originalInjections);
reset();
}
public void apply() {
final List<BaseInjection> injectionList = getInjectionList(injectionInfos);
cfg.replaceInjections(injectionList, originalInjections, true);
originalInjections.clear();
originalInjections.addAll(injectionList);
sortInjections(originalInjections);
FileContentUtil.reparseOpenedFiles();
}
public void reset() {
injectionInfos.clear();
for (BaseInjection injection : originalInjections) {
injectionInfos.add(new InjInfo(injection.copy(), this));
}
}
public InjInfo addInjection(final BaseInjection injection) {
final InjInfo info = new InjInfo(injection, this);
injectionInfos.add(info);
return info;
}
public boolean isModified() {
final List<BaseInjection> copy = new ArrayList<BaseInjection>(getInjectionList(injectionInfos));
sortInjections(copy);
return !originalInjections.equals(copy);
}
public void replace(final List<BaseInjection> originalInjections, final List<BaseInjection> newInjections) {
for (Iterator<InjInfo> it = injectionInfos.iterator(); it.hasNext(); ) {
final InjInfo info = it.next();
if (originalInjections.contains(info.injection)) it.remove();
}
for (BaseInjection newInjection : newInjections) {
injectionInfos.add(new InjInfo(newInjection, this));
}
}
}
private static class SameParamsAndPlacesStrategy implements TObjectHashingStrategy<BaseInjection> {
@Override
public int computeHashCode(final BaseInjection object) {
return object.hashCode();
}
@Override
public boolean equals(final BaseInjection o1, final BaseInjection o2) {
return o1.sameLanguageParameters(o2) && Arrays.equals(o1.getInjectionPlaces(), o2.getInjectionPlaces());
}
}
private static class InjInfo {
final BaseInjection injection;
final CfgInfo cfgInfo;
final boolean bundled;
private InjInfo(final BaseInjection injection, final CfgInfo cfgInfo) {
this.injection = injection;
this.cfgInfo = cfgInfo;
bundled = cfgInfo.bundledInjections.contains(injection);
}
}
private static List<InjInfo> getInjInfoList(final CfgInfo[] infos) {
return ContainerUtil.concat(infos, new Function<CfgInfo, Collection<? extends InjInfo>>() {
@Override
public Collection<InjInfo> fun(final CfgInfo cfgInfo) {
return cfgInfo.injectionInfos;
}
});
}
private static List<BaseInjection> getInjectionList(final List<InjInfo> list) {
return new AbstractList<BaseInjection>() {
@Override
public BaseInjection get(final int index) {
return list.get(index).injection;
}
@Override
public int size() {
return list.size();
}
};
}
}