/* * Copyright (c) 2007-2009, Osmorc Development Team * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * Neither the name of 'Osmorc Development Team' nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.osmorc.run.ui; import com.intellij.execution.ui.AlternativeJREPanel; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.CompilerProjectExtension; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.pointers.VirtualFilePointer; import com.intellij.ui.PanelWithAnchor; import com.intellij.ui.RawCommandLineEditor; import com.intellij.ui.components.JBLabel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.osmorc.frameworkintegration.BundleSelectionAction; import org.osmorc.frameworkintegration.FrameworkInstanceDefinition; import org.osmorc.frameworkintegration.FrameworkIntegrator; import org.osmorc.frameworkintegration.FrameworkIntegratorRegistry; import org.osmorc.run.OsgiRunConfiguration; import org.osmorc.run.OsgiRunConfigurationChecker; import org.osmorc.run.OsgiRunConfigurationCheckerProvider; import org.osmorc.settings.ApplicationSettings; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import javax.swing.text.DefaultFormatterFactory; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Editor for a bundle run configuration. * * @author <a href="mailto:janthomae@janthomae.de">Jan Thomä</a> * @author Robert F. Beeger (robert@beeger.net) * @version $Id$ */ public class OsgiRunConfigurationEditor extends SettingsEditor<OsgiRunConfiguration> implements BundleSelectionAction.Context, PanelWithAnchor { private final DefaultActionGroup frameworkSpecificBundleSelectionActions; private JComponent anchor; public OsgiRunConfigurationEditor(final Project project) { ApplicationSettings registry = ServiceManager.getService(ApplicationSettings.class); myFrameworkStartLevel.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor)myFrameworkStartLevel.getEditor(); editor.getTextField().setFormatterFactory(new DefaultFormatterFactory(new JSpinnerCellEditor.MyNumberFormatter("Auto"))); DefaultComboBoxModel cbmodel = new DefaultComboBoxModel(registry.getFrameworkInstanceDefinitions().toArray()); myDefaultStartLevel.setModel(new SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 1)); frameworkInstances.setModel(cbmodel); frameworkInstances.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onFrameworkChange(); } }); this.project = project; RunConfigurationTableModel model = new RunConfigurationTableModel(); modulesList.setModel(model); modulesList.setRowSelectionAllowed(true); modulesList.setColumnSelectionAllowed(false); modulesList.setDefaultEditor(Integer.class, new JSpinnerCellEditor()); modulesList.setDefaultRenderer(Integer.class, new JSpinnerCellEditor()); modulesList.setAutoCreateRowSorter(true); addButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onAddClick(); } }); removeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { onRemoveClick(); } }); osmorcControlledRadioButton.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { boolean isUserDefined = !osmorcControlledRadioButton.isSelected(); workingDirField.setEnabled(isUserDefined); } }); workingDirField .addBrowseFolderListener("Choose a working directory", "The working directory is the directory from which the framework is started", null, FileChooserDescriptorFactory.createSingleFolderDescriptor()); workingDirField.getTextField().setColumns(30); frameworkSpecificBundleSelectionActions = new DefaultActionGroup("frameworkSpecificBundleSelectionActions", true); frameworkSpecificButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JBPopupFactory.getInstance().createActionGroupPopup(null, frameworkSpecificBundleSelectionActions, DataManager.getInstance().getDataContext(frameworkSpecificButton), JBPopupFactory.ActionSelectionAid.NUMBERING, true) .showUnderneathOf(frameworkSpecificButton); } }); modulesList.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { int width = modulesList.getWidth(); int bundleNameWidth = 2 * width / 3; int otherWidth = width / 3 / 2; TableColumn bundleColumn = modulesList.getColumnModel().getColumn(0); bundleColumn.setPreferredWidth(bundleNameWidth); TableColumn startLevelColumn = modulesList.getColumnModel().getColumn(1); startLevelColumn.setPreferredWidth(otherWidth); TableColumn startColumn = modulesList.getColumnModel().getColumn(2); startColumn.setPreferredWidth(otherWidth); } }); // avoid text fields growing the dialog when much text is entered. vmParams.getTextField().setPreferredSize(new Dimension(100,20)); programParameters.getTextField().setPreferredSize(new Dimension(100,20)); setAnchor(alternativeJREPanel.getCbEnabled()); } /** * Called when the framework is changed. This will create a new editor for framework properties and will also remove * any framework bundles from the list, as they are no longer in classpath. */ private void onFrameworkChange() { frameworkSpecificBundleSelectionActions.removeAll(); if (frameworkInstances.getSelectedItem() != null) { FrameworkInstanceDefinition frameworkInstanceDefinition = (FrameworkInstanceDefinition)frameworkInstances.getSelectedItem(); // we got a framework instance, get the integrator FrameworkIntegratorRegistry registry = ServiceManager.getService(FrameworkIntegratorRegistry.class); FrameworkIntegrator integrator = registry.findIntegratorByInstanceDefinition(frameworkInstanceDefinition); // clear the panel additionalFrameworkPropertiesPanel.removeAll(); // create and install a new editor (if present) currentFrameworkRunPropertiesEditor = integrator.createRunPropertiesEditor(); if (currentFrameworkRunPropertiesEditor != null) { additionalFrameworkPropertiesPanel.removeAll(); additionalFrameworkPropertiesPanel.add(currentFrameworkRunPropertiesEditor.getUI(), BorderLayout.CENTER); if (osgiRunConfiguration != null) { currentFrameworkRunPropertiesEditor.resetEditorFrom(osgiRunConfiguration); OsgiRunConfigurationChecker checker = null; if (integrator instanceof OsgiRunConfigurationCheckerProvider) { checker = ((OsgiRunConfigurationCheckerProvider)integrator).getOsgiRunConfigurationChecker(); } osgiRunConfiguration.setAdditionalChecker(checker); } } // remove all framework bundles from the list RunConfigurationTableModel model = getTableModel(); model.removeAllOfType(SelectedBundle.BundleType.FrameworkBundle); for (BundleSelectionAction bundleSelectionAction : integrator.getBundleSelectionActions()) { bundleSelectionAction.setContext(this); frameworkSpecificBundleSelectionActions.add(bundleSelectionAction); } } } private void onRemoveClick() { int[] indices = modulesList.getSelectedRows(); RunConfigurationTableModel model = getTableModel(); for (int i = indices.length - 1; i >= 0; i--) { model.removeBundleAt(indices[i]); } } private RunConfigurationTableModel getTableModel() { return (RunConfigurationTableModel)modulesList.getModel(); } private void onAddClick() { BundleSelector selector = new BundleSelector(project); selector.setUp((FrameworkInstanceDefinition)frameworkInstances.getSelectedItem(), getBundlesToRun()); selector.show(root); List<SelectedBundle> selectedModules = selector.getSelectedBundles(); if (selectedModules != null) { RunConfigurationTableModel model = getTableModel(); for (SelectedBundle aModule : selectedModules) { model.addBundle(aModule); } } } @NotNull public List<SelectedBundle> getCurrentlySelectedBundles() { return getBundlesToRun(); } public void addBundle(@NotNull SelectedBundle bundle) { getTableModel().addBundle(bundle); } public void removeBundle(@NotNull SelectedBundle bundle) { getTableModel().removeBundle(bundle); } @Nullable public FrameworkInstanceDefinition getUsedFrameworkInstance() { return (FrameworkInstanceDefinition)frameworkInstances.getSelectedItem(); } protected void resetEditorFrom(OsgiRunConfiguration osgiRunConfiguration) { this.osgiRunConfiguration = osgiRunConfiguration; vmParams.setText(osgiRunConfiguration.getVmParameters()); programParameters.setText(osgiRunConfiguration.getProgramParameters()); frameworkInstances.setSelectedItem(osgiRunConfiguration.getInstanceToUse()); includeAllBundlesinClassPath.setSelected(osgiRunConfiguration.isIncludeAllBundlesInClassPath()); if (currentFrameworkRunPropertiesEditor != null) { currentFrameworkRunPropertiesEditor.resetEditorFrom(osgiRunConfiguration); } // I deliberately set the list of modules as the last step here as // the framework specific modules are cleaned out when you change the framework instance // so the framework instance should be changed first List<SelectedBundle> modules = osgiRunConfiguration.getBundlesToDeploy(); RunConfigurationTableModel model = getTableModel(); while (model.getRowCount() > 0) { model.removeBundleAt(0); } for (SelectedBundle module : modules) { model.addBundle(module); } modulesList.getColumnModel().getColumn(1).setPreferredWidth(200); myFrameworkStartLevel.setValue(osgiRunConfiguration.getFrameworkStartLevel()); myDefaultStartLevel.setValue(osgiRunConfiguration.getDefaultStartLevel()); boolean useUserDefinedFields = !osgiRunConfiguration.isGenerateWorkingDir(); workingDirField.setText(osgiRunConfiguration.getWorkingDir()); if (workingDirField.getText().length() == 0) { final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(project); if (extension != null) { final VirtualFilePointer outputDirPointer = extension.getCompilerOutputPointer(); if (outputDirPointer != null) { workingDirField.setText(VfsUtil.urlToPath(outputDirPointer.getUrl() + "/run.osgi/")); } } } workingDirField.setEnabled(useUserDefinedFields); userDefinedRadioButton.setSelected(useUserDefinedFields); osmorcControlledRadioButton.setSelected(!useUserDefinedFields); alternativeJREPanel.init(osgiRunConfiguration.getAlternativeJrePath(), osgiRunConfiguration.isUseAlternativeJre()); } protected void applyEditorTo(OsgiRunConfiguration osgiRunConfiguration) throws ConfigurationException { List<SelectedBundle> modules = getBundlesToRun(); osgiRunConfiguration.setBundlesToDeploy(modules); osgiRunConfiguration.setVmParameters(vmParams.getText()); osgiRunConfiguration.setProgramParameters(programParameters.getText()); osgiRunConfiguration.setIncludeAllBundlesInClassPath(includeAllBundlesinClassPath.isSelected()); osgiRunConfiguration.setWorkingDir(workingDirField.getText().replace('\\', '/')); osgiRunConfiguration.setUseAlternativeJre(alternativeJREPanel.isPathEnabled()); osgiRunConfiguration.setAlternativeJrePath(alternativeJREPanel.getPath()); osgiRunConfiguration.setFrameworkStartLevel((Integer)myFrameworkStartLevel.getValue()); osgiRunConfiguration.setDefaultStartLevel((Integer)myDefaultStartLevel.getValue()); osgiRunConfiguration.setGenerateWorkingDir(osmorcControlledRadioButton.isSelected()); FrameworkInstanceDefinition frameworkInstanceDefinition = (FrameworkInstanceDefinition)frameworkInstances.getSelectedItem(); if (frameworkInstanceDefinition != null) { osgiRunConfiguration.setInstanceToUse(frameworkInstanceDefinition); } if (currentFrameworkRunPropertiesEditor != null) { currentFrameworkRunPropertiesEditor.applyEditorTo(osgiRunConfiguration); } } private List<SelectedBundle> getBundlesToRun() { return getTableModel().getBundles(); } @NotNull protected JComponent createEditor() { return root; } protected void disposeEditor() { } private OsgiRunConfiguration osgiRunConfiguration; private RawCommandLineEditor vmParams; private JButton addButton; private JButton removeButton; private JComboBox frameworkInstances; private JPanel additionalFrameworkPropertiesPanel; private JTable modulesList; private JTabbedPane root; private JCheckBox includeAllBundlesinClassPath; private JRadioButton osmorcControlledRadioButton; private JRadioButton userDefinedRadioButton; private TextFieldWithBrowseButton workingDirField; private RawCommandLineEditor programParameters; private JButton frameworkSpecificButton; private AlternativeJREPanel alternativeJREPanel; private JSpinner myFrameworkStartLevel; private JSpinner myDefaultStartLevel; private JBLabel myProgramParametersLabel; private final Project project; private FrameworkRunPropertiesEditor currentFrameworkRunPropertiesEditor; @Override public JComponent getAnchor() { return anchor; } @Override public void setAnchor(JComponent anchor) { this.anchor = anchor; myProgramParametersLabel.setAnchor(anchor); alternativeJREPanel.setAnchor(anchor); } private static class RunConfigurationTableModel extends AbstractTableModel { private final List<SelectedBundle> selectedBundles; public RunConfigurationTableModel() { selectedBundles = new ArrayList<SelectedBundle>(); } public SelectedBundle getBundleAt(final int index) { return selectedBundles.get(index); } public List<SelectedBundle> getBundles() { return selectedBundles; } public void removeBundle(SelectedBundle bundle) { removeBundleAt(selectedBundles.indexOf(bundle)); } public void removeBundleAt(final int index) { selectedBundles.remove(index); fireTableRowsDeleted(index, index); } public void addBundle(final SelectedBundle bundle) { selectedBundles.add(bundle); fireTableRowsInserted(selectedBundles.size() - 1, selectedBundles.size() - 1); } public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return String.class; case 1: return Integer.class; case 2: return Boolean.class; default: return Object.class; } } @Override public String getColumnName(int columnIndex) { switch (columnIndex) { case 0: return "Bundle Name"; case 1: return "Start Level"; case 2: return "Start After Install"; default: return ""; } } public int getColumnCount() { return 3; } public int getRowCount() { return selectedBundles.size(); } public boolean isCellEditable(int row, int column) { return column != 0; } @Override public void setValueAt(Object o, int row, int column) { SelectedBundle bundle = getBundleAt(row); switch (column) { case 1: bundle.setStartLevel((Integer)o); break; case 2: bundle.setStartAfterInstallation((Boolean)o); break; default: throw new RuntimeException("Cannot edit column " + column); } } public Object getValueAt(int row, int column) { SelectedBundle bundle = getBundleAt(row); switch (column) { case 0: return bundle.toString(); case 1: return bundle.getStartLevel(); case 2: return bundle.isStartAfterInstallation(); default: throw new RuntimeException("Don't know column " + column); } } public void removeAllOfType(SelectedBundle.BundleType type) { for (Iterator<SelectedBundle> selectedBundleIterator = selectedBundles.iterator(); selectedBundleIterator.hasNext();) { SelectedBundle selectedBundle = selectedBundleIterator.next(); if (selectedBundle.getBundleType() == type) { selectedBundleIterator.remove(); } } fireTableDataChanged(); } } }