apply fix
[fedora-idea.git] / plugins / IntelliLang / src / org / intellij / plugins / intelliLang / InjectionsSettingsUI.java
blob3eee17db18f52d7adb76e11675bf3e2af1133d27
1 /*
2 * Copyright 2000-2009 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.
17 package org.intellij.plugins.intelliLang;
19 import com.intellij.lang.Language;
20 import com.intellij.openapi.actionSystem.*;
21 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
22 import com.intellij.openapi.fileChooser.FileChooserDialog;
23 import com.intellij.openapi.fileChooser.FileChooserFactory;
24 import com.intellij.openapi.fileTypes.FileType;
25 import com.intellij.openapi.fileTypes.StdFileTypes;
26 import com.intellij.openapi.options.Configurable;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.ui.Messages;
29 import com.intellij.openapi.ui.SplitterProportionsData;
30 import com.intellij.openapi.ui.popup.JBPopupFactory;
31 import com.intellij.openapi.util.Comparing;
32 import com.intellij.openapi.util.Condition;
33 import com.intellij.openapi.util.Factory;
34 import com.intellij.openapi.util.IconLoader;
35 import com.intellij.openapi.util.text.StringUtil;
36 import com.intellij.openapi.vfs.VirtualFile;
37 import com.intellij.peer.PeerFactory;
38 import com.intellij.ui.*;
39 import com.intellij.ui.table.TableView;
40 import com.intellij.ui.tabs.BetterJTable;
41 import com.intellij.util.Consumer;
42 import com.intellij.util.Function;
43 import com.intellij.util.Icons;
44 import com.intellij.util.Processor;
45 import com.intellij.util.containers.ContainerUtil;
46 import com.intellij.util.ui.ColumnInfo;
47 import com.intellij.util.ui.ListTableModel;
48 import gnu.trove.THashMap;
49 import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
50 import org.intellij.plugins.intelliLang.inject.InjectorUtils;
51 import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
52 import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
53 import org.jetbrains.annotations.Nls;
54 import org.jetbrains.annotations.Nullable;
56 import javax.swing.*;
57 import javax.swing.table.TableCellRenderer;
58 import java.awt.*;
59 import java.awt.event.KeyEvent;
60 import java.util.*;
61 import java.util.List;
63 /**
64 * @author Gregory.Shrago
66 public class InjectionsSettingsUI implements Configurable {
68 private final Project myProject;
69 private final Configuration myConfiguration;
70 private List<BaseInjection> myInjections;
71 private List<BaseInjection> myOriginalInjections;
74 private final JPanel myRoot;
75 private final InjectionsTable myInjectionsTable;
76 private final Map<String, LanguageInjectionSupport> mySupports = new THashMap<String, LanguageInjectionSupport>();
77 private final Map<String, AnAction> myEditActions = new THashMap<String, AnAction>();
78 private final List<AnAction> myAddActions = new ArrayList<AnAction>();
79 private ActionToolbar myToolbar;
81 public InjectionsSettingsUI(final Project project, final Configuration configuration) {
82 myProject = project;
83 myConfiguration = configuration;
85 myOriginalInjections = ContainerUtil
86 .concat(InjectorUtils.getActiveInjectionSupportIds(), new Function<String, Collection<? extends BaseInjection>>() {
87 public Collection<? extends BaseInjection> fun(final String s) {
88 return ContainerUtil.findAll(myConfiguration.getInjections(s), new Condition<BaseInjection>() {
89 public boolean value(final BaseInjection injection) {
90 return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()) != null;
92 });
94 });
95 sortInjections(myOriginalInjections);
96 myInjections = new ArrayList<BaseInjection>();
97 for (BaseInjection injection : myOriginalInjections) {
98 myInjections.add(injection.copy());
101 myRoot = new JPanel(new BorderLayout());
103 myInjectionsTable = new InjectionsTable(myInjections);
104 final JPanel tablePanel = new JPanel(new BorderLayout());
105 //tablePanel.setBorder(BorderFactory.createTitledBorder("Available Injections"));
106 tablePanel.add(BetterJTable.createStripedJScrollPane(myInjectionsTable), BorderLayout.CENTER);
107 tablePanel.add(Box.createVerticalStrut(10), BorderLayout.SOUTH);
109 final DefaultActionGroup group = createActions();
111 myToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true);
112 myToolbar.setTargetComponent(myInjectionsTable);
113 myRoot.add(myToolbar.getComponent(), BorderLayout.NORTH);
114 myRoot.add(tablePanel, BorderLayout.CENTER);
117 private DefaultActionGroup createActions() {
118 final Consumer<BaseInjection> consumer = new Consumer<BaseInjection>() {
119 public void consume(final BaseInjection injection) {
120 addInjection(injection);
123 final Factory<BaseInjection> producer = new Factory<BaseInjection>() {
124 public BaseInjection create() {
125 return getSelectedInjection();
128 for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
129 myAddActions.addAll(Arrays.asList(support.createAddActions(myProject, consumer)));
130 ContainerUtil.putIfNotNull(support.getId(), support.createEditAction(myProject, producer), myEditActions);
131 mySupports.put(support.getId(), support);
134 final DefaultActionGroup group = new DefaultActionGroup();
135 final AnAction addAction = new AnAction("Add", "Add", Icons.ADD_ICON) {
136 @Override
137 public void update(final AnActionEvent e) {
138 e.getPresentation().setEnabled(!myAddActions.isEmpty());
141 @Override
142 public void actionPerformed(final AnActionEvent e) {
143 performAdd(e);
146 final AnAction removeAction = new AnAction("Remove", "Remove", Icons.DELETE_ICON) {
147 @Override
148 public void update(final AnActionEvent e) {
149 e.getPresentation().setEnabled(!getSelectedInjections().isEmpty());
152 @Override
153 public void actionPerformed(final AnActionEvent e) {
154 performRemove();
158 final AnAction editAction = new AnAction("Edit", "Edit", Icons.PROPERTIES_ICON) {
159 @Override
160 public void update(final AnActionEvent e) {
161 final AnAction action = getEditAction();
162 e.getPresentation().setEnabled(action != null);
163 if (action != null) action.update(e);
166 @Override
167 public void actionPerformed(final AnActionEvent e) {
168 final AnAction action = getEditAction();
169 action.actionPerformed(e);
172 group.add(addAction);
173 group.add(removeAction);
174 group.add(editAction);
176 addAction.registerCustomShortcutSet(CommonShortcuts.INSERT, myInjectionsTable);
177 removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, myInjectionsTable);
178 editAction.registerCustomShortcutSet(CommonShortcuts.ENTER, myInjectionsTable);
180 group.add(new AnAction("Import", "Import", IconLoader.getIcon("/actions/install.png")) {
181 @Override
182 public void actionPerformed(final AnActionEvent e) {
183 doImportAction(e.getDataContext());
186 group.addSeparator();
187 group.add(new AnAction("Enabled Selected Injections", "Enabled Selected Injections", Icons.SELECT_ALL_ICON) {
188 @Override
189 public void actionPerformed(final AnActionEvent e) {
190 performSelectedInjectionsEnabled(true);
193 group.add(new AnAction("Disabled Selected Injections", "Disabled Selected Injections", Icons.UNSELECT_ALL_ICON) {
194 @Override
195 public void actionPerformed(final AnActionEvent e) {
196 performSelectedInjectionsEnabled(false);
200 new AnAction("Toggle") {
201 @Override
202 public void actionPerformed(final AnActionEvent e) {
203 performToggleAction();
205 }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myInjectionsTable);
206 return group;
209 private AnAction getEditAction() {
210 final BaseInjection injection = getSelectedInjection();
211 final String supportId = injection == null? null : injection.getSupportId();
212 return supportId == null? null : myEditActions.get(supportId);
215 private void addInjection(final BaseInjection injection) {
216 injection.initializePlaces(true);
217 myInjections.add(injection);
218 ((ListTableModel<BaseInjection>)myInjectionsTable.getModel()).setItems(myInjections);
219 final int index = myInjections.indexOf(injection);
220 myInjectionsTable.getSelectionModel().setSelectionInterval(index, index);
221 TableUtil.scrollSelectionToVisible(myInjectionsTable);
224 private void sortInjections(final List<BaseInjection> injections) {
225 Collections.sort(injections, new Comparator<BaseInjection>() {
226 public int compare(final BaseInjection o1, final BaseInjection o2) {
227 final int support = Comparing.compare(o1.getSupportId(), o2.getSupportId());
228 if (support != 0) return support;
229 final int lang = Comparing.compare(o1.getInjectedLanguageId(), o2.getInjectedLanguageId());
230 if (lang != 0) return lang;
231 return Comparing.compare(o1.getDisplayName(), o2.getDisplayName());
236 public JComponent createComponent() {
237 return myRoot;
240 public void reset() {
241 myInjections.clear();
242 for (BaseInjection injection : myOriginalInjections) {
243 myInjections.add(injection.copy());
245 ((ListTableModel<BaseInjection>)myInjectionsTable.getModel()).setItems(myInjections);
248 public void disposeUIResources() {
251 public void apply() {
252 myConfiguration.replaceInjections(myInjections, myOriginalInjections);
253 myOriginalInjections.clear();
254 myOriginalInjections.addAll(myInjections);
255 sortInjections(myOriginalInjections);
256 reset();
259 public boolean isModified() {
260 final List<BaseInjection> copy = new ArrayList<BaseInjection>(myInjections);
261 sortInjections(copy);
262 return !myOriginalInjections.equals(copy);
265 private void performSelectedInjectionsEnabled(final boolean enabled) {
266 for (BaseInjection injection : getSelectedInjections()) {
267 injection.setPlaceEnabled(null, enabled);
269 myInjectionsTable.updateUI();
272 private void performToggleAction() {
273 final List<BaseInjection> selectedInjections = getSelectedInjections();
274 boolean enabledExists = false;
275 boolean disabledExists = false;
276 for (BaseInjection injection : selectedInjections) {
277 if (injection.isEnabled()) enabledExists = true;
278 else disabledExists = true;
279 if (enabledExists && disabledExists) break;
281 boolean allEnabled = !enabledExists && disabledExists;
282 performSelectedInjectionsEnabled(allEnabled);
285 private void performRemove() {
286 final int selectedRow = myInjectionsTable.getSelectedRow();
287 if (selectedRow < 0) return;
288 myInjections.removeAll(getSelectedInjections());
289 ((ListTableModel)myInjectionsTable.getModel()).fireTableDataChanged();
290 final int index = Math.min(myInjections.size() - 1, selectedRow);
291 myInjectionsTable.getSelectionModel().setSelectionInterval(index, index);
292 TableUtil.scrollSelectionToVisible(myInjectionsTable);
295 private List<BaseInjection> getSelectedInjections() {
296 final ArrayList<BaseInjection> toRemove = new ArrayList<BaseInjection>();
297 for (int row : myInjectionsTable.getSelectedRows()) {
298 toRemove.add((BaseInjection)myInjectionsTable.getItems().get(row));
300 return toRemove;
303 @Nullable
304 private BaseInjection getSelectedInjection() {
305 final int row = myInjectionsTable.getSelectedRow();
306 return row < 0? null : (BaseInjection)myInjectionsTable.getItems().get(row);
309 private void performAdd(final AnActionEvent e) {
310 final DefaultActionGroup group = new DefaultActionGroup();
311 for (AnAction action : myAddActions) {
312 group.add(action);
315 JBPopupFactory.getInstance().createActionGroupPopup(null, group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.NUMBERING, true)
316 .showUnderneathOf(myToolbar.getComponent());
319 @Nls
320 public String getDisplayName() {
321 return "Injections";
324 public Icon getIcon() {
325 return null;
328 public String getHelpTopic() {
329 return null;
332 private class InjectionsTable extends TableView {
333 private InjectionsTable(final List<BaseInjection> injections) {
334 super(new ListTableModel<BaseInjection>(createInjectionColumnInfos(), injections, -1));
335 setAutoResizeMode(AUTO_RESIZE_LAST_COLUMN);
336 getColumnModel().getColumn(2).setCellRenderer(createLanguageCellRenderer());
337 getColumnModel().getColumn(1).setCellRenderer(createDisplayNameCellRenderer());
338 getColumnModel().getColumn(0).setResizable(false);
339 setShowGrid(false);
340 setShowVerticalLines(false);
341 setGridColor(getForeground());
342 setOpaque(false);
343 getColumnModel().getColumn(0).setMaxWidth(new JCheckBox().getPreferredSize().width);
344 final int[] preffered = new int[] {0} ;
345 ContainerUtil.process(myInjections, new Processor<BaseInjection>() {
346 public boolean process(final BaseInjection injection) {
347 final String languageId = injection.getInjectedLanguageId();
348 if (preffered[0] < languageId.length()) preffered[0] = languageId.length();
349 return true;
352 final int[] max = new int[] {0} ;
353 ContainerUtil.process(InjectedLanguage.getAvailableLanguageIDs(), new Processor<String>() {
354 public boolean process(final String languageId) {
355 if (max[0] < languageId.length()) max[0] = languageId.length();
356 return true;
359 getColumnModel().getColumn(2).setResizable(false);
360 final Icon icon = StdFileTypes.PLAIN_TEXT.getIcon();
361 final int preferred = new JLabel(StringUtil.repeatSymbol('m', preffered[0]), icon, SwingConstants.LEFT).getPreferredSize().width;
362 getColumnModel().getColumn(2).setMinWidth(preferred);
363 getColumnModel().getColumn(2).setPreferredWidth(preferred);
364 getColumnModel().getColumn(2).setMaxWidth(new JLabel(StringUtil.repeatSymbol('m', max[0]), icon, SwingConstants.LEFT).getPreferredSize().width);
365 new TableViewSpeedSearch(this) {
367 @Override
368 protected String getElementText(final Object element) {
369 final BaseInjection injection = (BaseInjection)element;
370 return injection.getSupportId() + " " + injection.getInjectedLanguageId() + " " + injection.getDisplayName();
377 private ColumnInfo[] createInjectionColumnInfos() {
378 final TableCellRenderer booleanCellRenderer = createBooleanCellRenderer();
379 final TableCellRenderer displayNameCellRenderer = createDisplayNameCellRenderer();
380 final TableCellRenderer languageCellRenderer = createLanguageCellRenderer();
381 final Comparator<BaseInjection> languageComparator = new Comparator<BaseInjection>() {
382 public int compare(final BaseInjection o1, final BaseInjection o2) {
383 return Comparing.compare(o1.getInjectedLanguageId(), o2.getInjectedLanguageId());
386 final Comparator<BaseInjection> displayNameComparator = new Comparator<BaseInjection>() {
387 public int compare(final BaseInjection o1, final BaseInjection o2) {
388 final int support = Comparing.compare(o1.getSupportId(), o2.getSupportId());
389 if (support != 0) return support;
390 return Comparing.compare(o1.getDisplayName(), o2.getDisplayName());
393 return new ColumnInfo[]{new ColumnInfo<BaseInjection, Boolean>(" ") {
394 @Override
395 public Class getColumnClass() {
396 return Boolean.class;
399 @Override
400 public Boolean valueOf(final BaseInjection o) {
401 return o.isEnabled();
404 @Override
405 public boolean isCellEditable(final BaseInjection injection) {
406 return true;
409 @Override
410 public void setValue(final BaseInjection injection, final Boolean value) {
411 injection.setPlaceEnabled(null, value.booleanValue());
414 @Override
415 public TableCellRenderer getRenderer(final BaseInjection injection) {
416 return booleanCellRenderer;
418 }, new ColumnInfo<BaseInjection, BaseInjection>("Display Name") {
419 @Override
420 public BaseInjection valueOf(final BaseInjection injection) {
421 return injection;
424 @Override
425 public Comparator<BaseInjection> getComparator() {
426 return displayNameComparator;
429 @Override
430 public TableCellRenderer getRenderer(final BaseInjection injection) {
431 return displayNameCellRenderer;
433 }, new ColumnInfo<BaseInjection, BaseInjection>("Language") {
434 @Override
435 public BaseInjection valueOf(final BaseInjection injection) {
436 return injection;
439 @Override
440 public Comparator<BaseInjection> getComparator() {
441 return languageComparator;
444 @Override
445 public TableCellRenderer getRenderer(final BaseInjection injection) {
446 return languageCellRenderer;
451 private static BooleanTableCellRenderer createBooleanCellRenderer() {
452 return new BooleanTableCellRenderer() {
453 @Override
454 public Component getTableCellRendererComponent(final JTable table,
455 final Object value,
456 final boolean isSelected,
457 final boolean hasFocus,
458 final int row,
459 final int column) {
460 return setLabelColors(super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column), table, isSelected, row);
465 private static TableCellRenderer createLanguageCellRenderer() {
466 return new TableCellRenderer() {
467 final JLabel label = new JLabel();
469 public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
470 final int row,
471 final int column) {
472 final BaseInjection injection = (BaseInjection)value;
473 final Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId());
474 final FileType fileType = language == null ? null : language.getAssociatedFileType();
475 label.setIcon(fileType == null ? null : fileType.getIcon());
476 label.setText(language == null ? injection.getInjectedLanguageId() : language.getDisplayName());
477 setLabelColors(label, table, isSelected, row);
478 return label;
483 private TableCellRenderer createDisplayNameCellRenderer() {
484 return new TableCellRenderer() {
485 final SimpleColoredComponent myLabel = new SimpleColoredComponent();
486 final SimpleColoredText myText = new SimpleColoredText();
488 public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus,
489 final int row,
490 final int column) {
491 myLabel.clear();
492 final BaseInjection injection = (BaseInjection)value;
493 final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES;
494 myText.append(injection.getSupportId() + ": ", grayAttrs);
495 mySupports.get(injection.getSupportId()).setupPresentation(injection, myText, isSelected);
496 myText.appendToComponent(myLabel);
497 myText.clear();
498 setLabelColors(myLabel, table, isSelected, row);
499 return myLabel;
504 private static Component setLabelColors(final Component label, final JTable table, final boolean isSelected, final int row) {
505 if (label instanceof JComponent) {
506 ((JComponent)label).setOpaque(isSelected);
508 label.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
509 label.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
510 return label;
513 private void doImportAction(final DataContext dataContext) {
514 final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, true, false, true, false) {
515 @Override
516 public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
517 return super.isFileVisible(file, showHiddenFiles) &&
518 (file.isDirectory() || "xml".equals(file.getExtension()) || file.getFileType() == StdFileTypes.ARCHIVE);
521 @Override
522 public boolean isFileSelectable(VirtualFile file) {
523 return file.getFileType() == StdFileTypes.XML;
526 descriptor.setDescription("Please select the configuration file (usually named IntelliLang.xml) to import.");
527 descriptor.setTitle("Import Configuration");
529 descriptor.putUserData(LangDataKeys.MODULE_CONTEXT, LangDataKeys.MODULE.getData(dataContext));
531 final FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, myProject);
533 final SplitterProportionsData splitterData = PeerFactory.getInstance().getUIHelper().createSplitterProportionsData();
534 splitterData.externalizeFromDimensionService("IntelliLang.ImportSettingsKey.SplitterProportions");
536 final VirtualFile[] files = chooser.choose(null, myProject);
537 if (files.length != 1) return;
538 try {
539 final Configuration cfg = Configuration.load(files[0].getInputStream());
540 if (cfg == null) {
541 Messages.showWarningDialog(myProject, "The selected file does not contain any importable configuration.", "Nothing to Import");
542 return;
544 final List<BaseInjection> newInjections =
545 ContainerUtil.concat(cfg.getAllInjectorIds(), new Function<String, Collection<? extends BaseInjection>>() {
546 public Collection<? extends BaseInjection> fun(final String s) {
547 return cfg.getInjections(s);
550 newInjections.removeAll(myInjections);
551 myInjections.addAll(newInjections);
552 final int n = newInjections.size();
553 if (n > 1) {
554 Messages.showInfoMessage(myProject, n + " entries have been successfully imported", "Import Successful");
556 else if (n == 1) {
557 Messages.showInfoMessage(myProject, "One entry has been successfully imported", "Import Successful");
559 else {
560 Messages.showInfoMessage(myProject, "No new entries have been imported", "Import");
563 catch (Exception e1) {
564 Configuration.LOG.error("Unable to load Settings", e1);
566 final String msg = e1.getLocalizedMessage();
567 Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : e1.toString(), "Could not load Settings");