Java tutorial
/* * 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 gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.io.IOException; import java.util.*; import javax.swing.Icon; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.table.TableCellRenderer; 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 com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.ide.highlighter.ArchiveFileType; 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.PlainTextFileType; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.NonDefaultProjectConfigurable; import com.intellij.openapi.options.SearchableConfigurable; 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.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.NullableFactory; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWrapper; import com.intellij.ui.BooleanTableCellRenderer; import com.intellij.ui.DoubleClickListener; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleColoredText; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.TableUtil; import com.intellij.ui.TableViewSpeedSearch; import com.intellij.ui.table.TableView; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.FileContentUtil; import com.intellij.util.Function; import com.intellij.util.IconUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.PlatformIcons; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; /** * @author Gregory.Shrago */ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, NonDefaultProjectConfigurable, Configurable.NoScroll { private final Project myProject; private final CfgInfo[] myInfos; private final JPanel myRoot; private final InjectionsTable myInjectionsTable; private final Map<String, LanguageInjectionSupport> mySupports = new THashMap<String, LanguageInjectionSupport>(); private final Map<String, AnAction> myEditActions = new THashMap<String, AnAction>(); private final List<AnAction> myAddActions = new ArrayList<AnAction>(); private final ActionToolbar myToolbar; private final JLabel myCountLabel; private Configurable[] myConfigurables; private Configuration myConfiguration; public InjectionsSettingsUI(final Project project) { this(project, Configuration.getProjectInstance(project)); } 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"); final JPanel tablePanel = new JPanel(new BorderLayout()); tablePanel.add(ScrollPaneFactory.createScrollPane(myInjectionsTable), BorderLayout.CENTER); final DefaultActionGroup group = createActions(); myToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true); myToolbar.setTargetComponent(myInjectionsTable); myRoot.add(myToolbar.getComponent(), BorderLayout.NORTH); myRoot.add(tablePanel, BorderLayout.CENTER); myCountLabel = new JLabel(); myCountLabel.setHorizontalAlignment(SwingConstants.RIGHT); myCountLabel.setForeground(SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES.getFgColor()); myRoot.add(myCountLabel, BorderLayout.SOUTH); updateCountLabel(); } private DefaultActionGroup createActions() { final Consumer<BaseInjection> consumer = new Consumer<BaseInjection>() { @Override public void consume(final BaseInjection injection) { addInjection(injection); } }; final Factory<BaseInjection> producer = new NullableFactory<BaseInjection>() { @Override 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>() { @Override public int compare(final AnAction o1, final AnAction o2) { return Comparing.compare(o1.getTemplatePresentation().getText(), o2.getTemplatePresentation().getText()); } }); final DefaultActionGroup group = new DefaultActionGroup(); final AnAction addAction = new AnAction("Add", "Add", IconUtil.getAddIcon()) { @Override public void update(final AnActionEvent e) { e.getPresentation().setEnabled(!myAddActions.isEmpty()); } @Override public void actionPerformed(final AnActionEvent e) { performAdd(e); } }; final AnAction removeAction = new AnAction("Remove", "Remove", PlatformIcons.DELETE_ICON) { @Override public void update(final AnActionEvent e) { boolean enabled = false; for (InjInfo info : getSelectedInjections()) { if (!info.bundled) { enabled = true; break; } } e.getPresentation().setEnabled(enabled); } @Override public void actionPerformed(final AnActionEvent e) { performRemove(); } }; final AnAction editAction = new AnAction("Edit", "Edit", PlatformIcons.PROPERTIES_ICON) { @Override public void update(final AnActionEvent e) { final AnAction action = getEditAction(); e.getPresentation().setEnabled(action != null); if (action != null) { action.update(e); } } @Override public void actionPerformed(final AnActionEvent e) { performEditAction(e); } }; final AnAction copyAction = new AnAction("Duplicate", "Duplicate", PlatformIcons.COPY_ICON) { @Override public void update(final AnActionEvent e) { final AnAction action = getEditAction(); e.getPresentation().setEnabled(action != null); if (action != null) { action.update(e); } } @Override public void actionPerformed(final AnActionEvent e) { final InjInfo injection = getSelectedInjection(); if (injection != null) { addInjection(injection.injection.copy()); //performEditAction(e); } } }; group.add(addAction); group.add(removeAction); group.add(copyAction); group.add(editAction); addAction.registerCustomShortcutSet(CommonShortcuts.INSERT, myInjectionsTable); removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, myInjectionsTable); editAction.registerCustomShortcutSet(CommonShortcuts.ENTER, myInjectionsTable); group.addSeparator(); group.add(new AnAction("Enable Selected Injections", "Enable Selected Injections", PlatformIcons.SELECT_ALL_ICON) { @Override public void actionPerformed(final AnActionEvent e) { performSelectedInjectionsEnabled(true); } }); group.add(new AnAction("Disable Selected Injections", "Disable Selected Injections", PlatformIcons.UNSELECT_ALL_ICON) { @Override public void actionPerformed(final AnActionEvent e) { performSelectedInjectionsEnabled(false); } }); new AnAction("Toggle") { @Override public void actionPerformed(final AnActionEvent e) { performToggleAction(); } }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myInjectionsTable); if (myInfos.length > 1) { group.addSeparator(); final AnAction shareAction = new AnAction("Make Global", null, PlatformIcons.IMPORT_ICON) { @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); } @Override public void update(final AnActionEvent e) { final CfgInfo cfg = getTargetCfgInfo(getSelectedInjections()); e.getPresentation().setEnabled(cfg != null); e.getPresentation().setText(cfg == getDefaultCfgInfo() ? "Make Global" : "Move to Project"); super.update(e); } @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 cfg; } for (CfgInfo info : myInfos) { if (info != cfg) { return info; } } throw new AssertionError(); } }; shareAction.registerCustomShortcutSet( new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK)), myInjectionsTable); group.add(shareAction); } group.addSeparator(); group.add(new AnAction("Import", "Import", AllIcons.Actions.Install) { @Override public void actionPerformed(final AnActionEvent e) { doImportAction(e.getDataContext()); updateCountLabel(); } }); group.add(new AnAction("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 void update(final AnActionEvent e) { e.getPresentation().setEnabled(!getSelectedInjections().isEmpty()); } }); return group; } private void performEditAction(AnActionEvent e) { final AnAction action = getEditAction(); if (action != null) { final int row = myInjectionsTable.getSelectedRow(); action.actionPerformed(e); 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++; } } } final StringBuilder sb = new StringBuilder(); sb.append(items.size()).append(" injection").append(items.size() > 1 ? "s" : "").append(" (") .append(enablePlacesCount).append(" of ").append(placesCount).append(" place") .append(placesCount > 1 ? "s" : "").append(" enabled) "); myCountLabel.setText(sb.toString()); } 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>() { @Override 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>() { @Override 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()); } }); } @Override public JComponent createComponent() { return myRoot; } @Override public void reset() { for (CfgInfo info : myInfos) { info.reset(); } myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); updateCountLabel(); } @Override public void disposeUIResources() { } @Override public void apply() { for (CfgInfo info : myInfos) { info.apply(); } reset(); } @Override 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(final AnActionEvent e) { final DefaultActionGroup group = new DefaultActionGroup(); for (AnAction action : myAddActions) { group.add(action); } JBPopupFactory.getInstance().createActionGroupPopup(null, group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.NUMBERING, true, new Runnable() { @Override public void run() { updateCountLabel(); } }, -1).showUnderneathOf(myToolbar.getComponent()); } @Override @Nls public String getDisplayName() { return "Language Injections"; } @Override 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()); getColumnModel().getColumn(0).setMaxWidth(new JCheckBox().getPreferredSize().width); 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( new AnActionEvent(e, DataManager.getInstance().getDataContext(InjectionsTable.this), ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0)); return true; } }.installOn(this); final String[] maxName = new String[] { "" }; ContainerUtil.process(injections, new Processor<InjInfo>() { @Override 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>() { @Override public boolean process(final Language language) { String displayName = language.getDisplayName(); if (maxName[0].length() < displayName.length()) { maxName[0] = displayName; } return true; } }); Icon icon = PlainTextFileType.INSTANCE.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>() { @Override 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>() { @Override 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>("Display 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(); @Override 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(); @Override 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(); @Override 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() instanceof ArchiveFileType); } @Override public boolean isFileSelectable(VirtualFile file) { return "xml".equalsIgnoreCase(file.getExtension()); } }; 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>() { @Override 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 = ContainerUtil.concat(InjectorUtils.getActiveInjectionSupportIds(), new Function<String, Collection<? extends BaseInjection>>() { @Override public Collection<? extends BaseInjection> fun(final String s) { return ContainerUtil.findAll(CfgInfo.this.cfg instanceof Configuration.Prj ? ((Configuration.Prj) CfgInfo.this.cfg).getOwnInjections(s) : CfgInfo.this.cfg.getInjections(s), new Condition<BaseInjection>() { @Override public boolean value(final BaseInjection injection) { return InjectedLanguage .findLanguageById(injection.getInjectedLanguageId()) != 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(); } }; } }