com.intellij.compiler.impl.javaCompiler.TargetOptionsComponent.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.compiler.impl.javaCompiler.TargetOptionsComponent.java

Source

/*
 * 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 com.intellij.compiler.impl.javaCompiler;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.*;

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultCellEditor;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

import org.jetbrains.annotations.Nullable;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.configuration.ChooseModulesDialog;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.AnActionButtonRunnable;
import com.intellij.ui.JBColor;
import com.intellij.ui.TableUtil;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.ItemRemovable;
import lombok.val;

/**
 * @author Eugene Zhuravlev
 *         Date: 5/9/12
 */
public class TargetOptionsComponent extends JPanel {
    private static final class TargetLevelTableModel extends AbstractTableModel implements ItemRemovable {
        private static final class Item {
            final Module module;
            String targetLevel = "";

            Item(Module module) {
                this.module = module;
            }

            Item(Module module, String targetLevel) {
                this.module = module;
                this.targetLevel = targetLevel;
            }
        }

        private final List<Item> myItems = new ArrayList<Item>();

        @Override
        public int getRowCount() {
            return myItems.size();
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex != 0;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            final Item item = myItems.get(rowIndex);
            return columnIndex == 0 ? item.module : item.targetLevel;
        }

        //public void addItem(Module module)  {
        //  final int size = myItems.size();
        //  myItems.add(new Item(module.getName()));
        //  fireTableRowsInserted(size, size);
        //}

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            final Item item = myItems.get(rowIndex);
            item.targetLevel = ((String) aValue).trim();
            fireTableCellUpdated(rowIndex, columnIndex);
        }

        public void addItems(Collection<Module> modules) {
            for (Module module : modules) {
                myItems.add(new Item(module));
            }
            sorItems();
            fireTableDataChanged();
        }

        private void sorItems() {
            Collections.sort(myItems, new Comparator<Item>() {
                @Override
                public int compare(Item o1, Item o2) {
                    return o1.module.getName().compareTo(o2.module.getName());
                }
            });
        }

        public List<Item> getItems() {
            return myItems;
        }

        public void setItems(Map<Module, String> items) {
            myItems.clear();
            for (Map.Entry<Module, String> entry : items.entrySet()) {
                myItems.add(new Item(entry.getKey(), entry.getValue()));
            }
            sorItems();
            fireTableDataChanged();
        }

        @Override
        public void removeRow(int idx) {
            myItems.remove(idx);
        }
    }

    private static final class TargetLevelComboboxModel extends AbstractListModel implements ComboBoxModel {

        private final List<String> myOptions = new ArrayList<String>();
        private String mySelectedItem = "";

        TargetLevelComboboxModel() {
            //myOptions.add("");
            for (int i = KNOWN_TARGETS.length - 1; i >= 0; i--) {
                myOptions.add(KNOWN_TARGETS[i]);
            }
        }

        @Override
        public int getSize() {
            return myOptions.size();
        }

        @Override
        public Object getSelectedItem() {
            return mySelectedItem;
        }

        @Override
        public void setSelectedItem(Object anItem) {
            mySelectedItem = toModelItem((String) anItem);
            fireContentsChanged(this, 0, myOptions.size());
        }

        @Override
        public Object getElementAt(int index) {
            return myOptions.get(index);
        }

        private String toModelItem(String item) {
            item = item.trim();
            for (String option : myOptions) {
                if (option.equals(item)) {
                    return option;
                }
            }
            return item;
        }
    }

    private static class ModuleCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
            try {
                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            } finally {
                final Module module = (Module) value;
                setText(module.getName());
                setIcon(AllIcons.Nodes.Module);
            }
        }
    }

    private static class TargetLevelCellEditor extends DefaultCellEditor {
        private TargetLevelCellEditor() {
            super(createTargetOptionsCombo());
            setClickCountToStart(0);
        }
    }

    private static class TargetLevelCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
            final Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
                    column);
            if (component instanceof JLabel) {
                final JLabel comp = (JLabel) component;
                comp.setHorizontalAlignment(SwingConstants.CENTER);
                if ("".equals(value)) {
                    comp.setForeground(JBColor.GRAY);
                    comp.setText(COMPILER_DEFAULT);
                } else {
                    comp.setForeground(table.getForeground());
                }
            }
            return component;
        }
    }

    static class HintTextField extends JTextField {
        private final char[] myHint;

        public HintTextField(final String hint) {
            this(hint, 0);
        }

        public HintTextField(final String hint, final int columns) {
            super(hint, columns);
            myHint = hint.toCharArray();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            final boolean isFocused = isFocusOwner();
            if (!isFocused && getText().isEmpty()) {
                final Color oldColor = g.getColor();
                final Font oldFont = g.getFont();
                try {
                    g.setColor(JBColor.GRAY);
                    //g.setFont(oldFont.deriveFont(Font.ITALIC));
                    final FontMetrics metrics = g.getFontMetrics();
                    int x = Math.abs(getWidth() - metrics.charsWidth(myHint, 0, myHint.length)) / 2;
                    int y = Math.abs(getHeight() - metrics.getHeight()) / 2 + metrics.getAscent();
                    g.drawChars(myHint, 0, myHint.length, x, y);
                } finally {
                    g.setColor(oldColor);
                    g.setFont(oldFont);
                }
            }
        }
    }

    private static final String[] KNOWN_TARGETS = new String[] { "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7",
            "1.8", "1.9" };
    private static final String COMPILER_DEFAULT = "JDK default";
    private final Project myProject;
    private ComboBox myCbProjectTargetLevel;
    private JBTable myTable;

    public TargetOptionsComponent(Project project) {
        super(new GridBagLayout());
        myProject = project;
        //setBorder(BorderFactory.createTitledBorder("Bytecode target level"));
        myCbProjectTargetLevel = createTargetOptionsCombo();

        myTable = new JBTable(new TargetLevelTableModel());
        myTable.setRowHeight(22);
        myTable.getEmptyText().setText("All modules will be compiled with project bytecode version");

        final TableColumn moduleColumn = myTable.getColumnModel().getColumn(0);
        moduleColumn.setHeaderValue("Module");
        moduleColumn.setCellRenderer(new ModuleCellRenderer());

        final TableColumn targetLevelColumn = myTable.getColumnModel().getColumn(1);
        final String columnTitle = "Target bytecode version";
        targetLevelColumn.setHeaderValue(columnTitle);
        targetLevelColumn.setCellEditor(new TargetLevelCellEditor());
        targetLevelColumn.setCellRenderer(new TargetLevelCellRenderer());
        final int width = myTable.getFontMetrics(myTable.getFont()).stringWidth(columnTitle) + 10;
        targetLevelColumn.setPreferredWidth(width);
        targetLevelColumn.setMinWidth(width);
        targetLevelColumn.setMaxWidth(width);

        add(new JLabel("Project bytecode version (leave blank for jdk default): "),
                constraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NONE));
        add(myCbProjectTargetLevel, constraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NONE));
        add(new JLabel("Per-module bytecode version:"), constraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.NONE));
        final JPanel tableComp = ToolbarDecorator.createDecorator(myTable).disableUpAction().disableDownAction()
                .setAddAction(new AnActionButtonRunnable() {
                    @Override
                    public void run(AnActionButton anActionButton) {
                        addModules();
                    }
                }).setRemoveAction(new AnActionButtonRunnable() {
                    @Override
                    public void run(AnActionButton anActionButton) {
                        removeSelectedModules();
                    }
                }).createPanel();

        tableComp.setPreferredSize(new Dimension(myTable.getWidth(), 150));
        add(tableComp, constraints(0, 2, 2, 1, 1.0, 1.0, GridBagConstraints.BOTH));
    }

    private static GridBagConstraints constraints(final int gridx, final int gridy, final int gridwidth,
            final int gridheight, final double weightx, final double weighty, final int fill) {
        return new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty,
                GridBagConstraints.WEST, fill, new Insets(5, 5, 0, 0), 0, 0);
    }

    private static ComboBox createTargetOptionsCombo() {
        final ComboBox combo = new ComboBox(new TargetLevelComboboxModel());
        //combo.setRenderer(new DefaultListCellRenderer() {
        //  @Override
        //  public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        //    try {
        //      return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        //    }
        //    finally {
        //      //if ("".equals(value)) {
        //      //  setText(COMPILER_DEFAULT);
        //      //}
        //    }
        //  }
        //});
        combo.setEditable(true);
        combo.setEditor(new BasicComboBoxEditor() {
            @Override
            protected JTextField createEditorComponent() {
                return new HintTextField(COMPILER_DEFAULT, 10);
            }
        });
        return combo;
    }

    private void removeSelectedModules() {
        val rows = myTable.getSelectedRows();
        if (rows.length > 0) {
            TableUtil.removeSelectedItems(myTable);
        }
    }

    private void addModules() {
        val model = (TargetLevelTableModel) myTable.getModel();
        val items = new ArrayList<Module>(Arrays.asList(ModuleManager.getInstance(myProject).getModules()));
        Set<Module> alreadyAdded = new HashSet<Module>();
        for (TargetLevelTableModel.Item item : model.getItems()) {
            alreadyAdded.add(item.module);
        }
        for (Iterator<Module> it = items.iterator(); it.hasNext();) {
            Module module = it.next();
            if (alreadyAdded.contains(module)) {
                it.remove();
            }
        }
        Collections.sort(items, new Comparator<Module>() {
            @Override
            public int compare(Module o1, Module o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        val chooser = new ChooseModulesDialog(this, items, "Choose module");
        chooser.show();
        val elements = chooser.getChosenElements();
        if (!elements.isEmpty()) {
            model.addItems(elements);
        }
    }

    public void setProjectBytecodeTargetLevel(String level) {
        myCbProjectTargetLevel.setSelectedItem(level == null ? "" : level);
    }

    @Nullable
    public String getProjectBytecodeTarget() {
        val item = ((String) myCbProjectTargetLevel.getSelectedItem()).trim();
        return "".equals(item) ? null : item;
    }

    public Map<String, String> getModulesBytecodeTargetMap() {
        TargetLevelTableModel model = (TargetLevelTableModel) myTable.getModel();
        val map = new HashMap<String, String>();
        for (TargetLevelTableModel.Item item : model.getItems()) {
            map.put(item.module.getName(), item.targetLevel);
        }
        return map;
    }

    public void setModuleTargetLevels(Map<String, String> moduleLevels) {
        val map = new HashMap<Module, String>();
        for (val module : ModuleManager.getInstance(myProject).getModules()) {
            val target = moduleLevels.get(module.getName());
            if (target != null) {
                map.put(module, target);
            }
        }
        ((TargetLevelTableModel) myTable.getModel()).setItems(map);
    }
}