/* * Copyright 2003-2016 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 jetbrains.mps.ide.java.ui; import com.intellij.openapi.ui.ComboBox; import com.intellij.ui.AnActionButton; import com.intellij.ui.AnActionButtonRunnable; import com.intellij.ui.ColoredTableCellRenderer; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.TableUtil; import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBLabel; import com.intellij.ui.table.JBTable; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; import com.intellij.util.ui.ItemRemovable; import jetbrains.mps.ide.icons.IdeIcons; import jetbrains.mps.ide.ui.dialogs.properties.MPSPropertiesConfigurable; import jetbrains.mps.ide.ui.dialogs.properties.PropertiesBundle; import jetbrains.mps.ide.ui.dialogs.properties.creators.StubRootChooser; import jetbrains.mps.ide.ui.dialogs.properties.tabs.BaseTab; import jetbrains.mps.ide.ui.filechoosers.treefilechooser.TreeFileChooser; import jetbrains.mps.project.Solution; import jetbrains.mps.project.facets.JavaModuleFacetImpl; import jetbrains.mps.project.structure.model.ModelRootDescriptor; import jetbrains.mps.project.structure.modules.SolutionDescriptor; import jetbrains.mps.project.structure.modules.SolutionKind; import jetbrains.mps.smodel.Language; import jetbrains.mps.util.Computable; import jetbrains.mps.util.FileUtil; import jetbrains.mps.vfs.IFile; import org.jetbrains.mps.openapi.module.SModuleFacet; import org.jetbrains.mps.openapi.ui.persistence.FacetTab; import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import java.awt.Dimension; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; // FIXME #apply() shall not deal with ModuleDescriptor directly, instead, JavaModuleFacet.save() shall put that there (better yet, // to memento, not to be different from other facets, provided we don't use isCompileInMPS and getKind directly from descriptor) public class JavaModuleFacetTab extends BaseTab implements FacetTab { private PathsTableModel myPathsTableModel; private LibraryTableModel myLibraryTableModel; private JBCheckBox myCheckBox; private ComboBox myComboBox; private JavaModuleFacetImpl myJavaModuleFacet; public JavaModuleFacetTab(JavaModuleFacetImpl javaModuleFacet) { super(javaModuleFacet.getFacetPresentation(), IdeIcons.DEFAULT_ICON, PropertiesBundle.message("facet.java.tip")); myJavaModuleFacet = javaModuleFacet; } @Override public void init() { JPanel advancedTab = new JPanel(); advancedTab.setLayout(new GridLayoutManager((myJavaModuleFacet.getModule() instanceof Solution ? 5 : 3), 2, MPSPropertiesConfigurable.INSETS, -1, -1)); int row = 0; if (myJavaModuleFacet.getModule() instanceof Solution) { SolutionDescriptor descriptor = ((Solution) myJavaModuleFacet.getModule()).getModuleDescriptor(); assert descriptor != null; JBLabel solutionKindLabel = new JBLabel(PropertiesBundle.message("facet.java.solutionkind")); myComboBox = new ComboBox(new DefaultComboBoxModel<SolutionKind>(SolutionKind.values())); myComboBox.setSelectedItem(descriptor.getKind()); advancedTab.add(solutionKindLabel, new GridConstraints(row, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); advancedTab.add(myComboBox, new GridConstraints(row++, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); myCheckBox = new JBCheckBox(PropertiesBundle.message("facet.java.compileinmps"), descriptor.getCompileInMPS()); advancedTab.add(myCheckBox, new GridConstraints(row++, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); } advancedTab.add(getSourcePathsTable(), new GridConstraints(row++, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); advancedTab.add(getLibrariesTable(), new GridConstraints(row, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); setTabComponent(advancedTab); } private JComponent getSourcePathsTable() { myPathsTableModel = new PathsTableModel(); final JBTable sourcePathTable = new JBTable(myPathsTableModel); sourcePathTable.setTableHeader(null); sourcePathTable.setDefaultRenderer(String.class, new MyPathRenderer()); sourcePathTable.setShowHorizontalLines(false); sourcePathTable.setShowVerticalLines(false); sourcePathTable.setAutoCreateRowSorter(false); sourcePathTable.setAutoscrolls(true); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(sourcePathTable); decorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { myPathsTableModel.add((new PathChooser()).compute()); } }).setRemoveAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { TableUtil.removeSelectedItems(sourcePathTable); myPathsTableModel.fireTableDataChanged(); } }); decorator.setToolbarBorder(IdeBorderFactory.createBorder()); decorator.setPreferredSize(new Dimension(500, 100)); JPanel table = decorator.createPanel(); table.setBorder(IdeBorderFactory.createTitledBorder(PropertiesBundle.message("facet.java.sourcepath"), false)); return table; } private JComponent getLibrariesTable() { myLibraryTableModel = new LibraryTableModel(); final JBTable librariesTable = new JBTable(myLibraryTableModel); librariesTable.setTableHeader(null); librariesTable.setDefaultRenderer(String.class, new MyPathRenderer()); librariesTable.setShowHorizontalLines(false); librariesTable.setShowVerticalLines(false); librariesTable.setAutoCreateRowSorter(false); librariesTable.setAutoscrolls(true); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(librariesTable); decorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { List<ModelRootDescriptor> modelRoots = new ArrayList<ModelRootDescriptor>(myJavaModuleFacet.getModule().getModuleDescriptor().getModelRootDescriptors()); StubRootChooser stubRootChooser = new StubRootChooser(librariesTable, modelRoots, myJavaModuleFacet.getModule() instanceof Language); myLibraryTableModel.addAll(stubRootChooser.compute()); } }).setRemoveAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { TableUtil.removeSelectedItems(librariesTable); myLibraryTableModel.fireTableDataChanged(); } }); decorator.setToolbarBorder(IdeBorderFactory.createBorder()); decorator.setPreferredSize(new Dimension(500, 100)); JPanel table = decorator.createPanel(); table.setBorder(IdeBorderFactory.createTitledBorder(PropertiesBundle.message("facet.java.libraries"), false)); return table; } @Override public boolean isModified() { boolean solutionCheck = false; if (myJavaModuleFacet.getModule() instanceof Solution) { SolutionDescriptor descriptor = (SolutionDescriptor) myJavaModuleFacet.getModule().getModuleDescriptor(); assert descriptor != null; solutionCheck = descriptor.getCompileInMPS() != myCheckBox.isSelected() || descriptor.getKind() != myComboBox.getSelectedItem(); } return myPathsTableModel.isModified() || myLibraryTableModel.isModified() || solutionCheck; } @Override public void apply() { if (myJavaModuleFacet.getModule() instanceof Solution) { SolutionDescriptor descriptor = (SolutionDescriptor) myJavaModuleFacet.getModule().getModuleDescriptor(); assert descriptor != null; descriptor.setCompileInMPS(myCheckBox.isSelected()); descriptor.setKind((SolutionKind) myComboBox.getSelectedItem()); } myPathsTableModel.apply(); myLibraryTableModel.apply(); } @Override public SModuleFacet getFacet() { return myJavaModuleFacet; } private class PathsTableModel extends AbstractTableModel implements ItemRemovable { public PathsTableModel() { for(String s : myJavaModuleFacet.getAdditionalSourcePaths()) { myPaths.add(s); } } List<String> myPaths = new ArrayList<String>(); public void add(String path) { if (path != null && !myPaths.contains(path)) { myPaths.add(path); fireTableDataChanged(); } } @Override public int getRowCount() { return myPaths.size(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { return myPaths.get(rowIndex); } @Override public int getColumnCount() { return 1; } @Override public String getColumnName(int columnIndex) { return ""; } @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == 0) { return String.class; } return super.getColumnClass(columnIndex); } @Override public void removeRow(int idx) { myPaths.remove(idx); } public boolean isModified() { return !(myJavaModuleFacet.getAdditionalSourcePaths().containsAll(myPaths) && myPaths.containsAll(myJavaModuleFacet.getAdditionalSourcePaths())); } public void apply() { myJavaModuleFacet.getModule().getModuleDescriptor().getSourcePaths().clear(); if (!myPaths.isEmpty()) { myJavaModuleFacet.getModule().getModuleDescriptor().getSourcePaths().addAll(myPaths); } } } private class PathChooser implements Computable<String> { @Override public String compute() { TreeFileChooser chooser = new TreeFileChooser(); chooser.setMode(TreeFileChooser.MODE_DIRECTORIES); IFile result = chooser.showDialog(); if (result == null) { return null; } return result.getPath(); } } private class LibraryTableModel extends AbstractTableModel implements ItemRemovable { private List<String> myStubModelEntries = new ArrayList<String>(); public LibraryTableModel() { for (String javaStubPath : myJavaModuleFacet.getModule().getModuleDescriptor().getAdditionalJavaStubPaths()) { myStubModelEntries.add(javaStubPath); } } public void addAll(Collection<String> javaStubPaths) { if (myStubModelEntries.addAll(javaStubPaths)) { fireTableDataChanged(); } } @Override public int getRowCount() { return myStubModelEntries.size(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { return myStubModelEntries.get(rowIndex); } @Override public int getColumnCount() { return 1; } @Override public String getColumnName(int columnIndex) { return ""; } @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == 0) { return String.class; } return super.getColumnClass(columnIndex); } @Override public void removeRow(int idx) { myStubModelEntries.remove(idx); } public boolean isModified() { return !(myJavaModuleFacet.getModule().getModuleDescriptor().getAdditionalJavaStubPaths().containsAll(myStubModelEntries) && myStubModelEntries.containsAll(myJavaModuleFacet.getLibraryClassPath())); } public void apply() { myJavaModuleFacet.getModule().getModuleDescriptor().getAdditionalJavaStubPaths().clear(); if (!myStubModelEntries.isEmpty()) { myJavaModuleFacet.getModule().getModuleDescriptor().getAdditionalJavaStubPaths().addAll(myStubModelEntries); } } } private class MyPathRenderer extends ColoredTableCellRenderer { @Override protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) { setPaintFocusBorder(false); setFocusBorderAroundIcon(true); setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); if (value != null) { String path = FileUtil.getCanonicalPath((String) value); if (!(new File(path)).exists()) { append(path, SimpleTextAttributes.ERROR_ATTRIBUTES); } else { append(path); } } } } }