Package org.openquark.gems.client.generators

Source Code of org.openquark.gems.client.generators.JavaForeignImportModuleGenerator$ScopeSelectorPanel

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* 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 Business Objects 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.
*/


/*
* JavaForeignImportModuleGenerator.java
* Creation date: Sep 27, 2005.
* By: Edward Lam
*/
package org.openquark.gems.client.generators;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileView;

import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.TypeChecker;
import org.openquark.cal.compiler.SourceModel.ModuleDefn;
import org.openquark.cal.services.CALFeatureName;
import org.openquark.cal.services.Perspective;
import org.openquark.cal.services.ResourceName;
import org.openquark.cal.services.Status;
import org.openquark.gems.client.GemCutter;
import org.openquark.gems.client.ValueRunner;
import org.openquark.gems.client.jfit.ForeignImportGenerator;
import org.openquark.gems.client.jfit.JFit;
import org.openquark.gems.client.valueentry.ValueEditorManager;
import org.openquark.util.FileSystemHelper;
import org.openquark.util.UnsafeCast;
import org.openquark.util.ui.DetailsDialog;
import org.openquark.util.ui.DialogBase;
import org.openquark.util.ui.ExtensionFileFilter;
import org.openquark.util.ui.SortedListModel;



/**
* This is the container class for the generator to create a cal module importing multiple Java functions and types.
* @author Edward Lam
*/
public final class JavaForeignImportModuleGenerator extends DialogBase {

    private static final long serialVersionUID = -1549293981732061092L;

    /** The value of the "java.home" system property.  This is guaranteed to be defined. */
    private static final String JAVA_HOME = System.getProperty("java.home");

    /** The icon used by the generator. */
    private static final Icon GENERATOR_ICON = new ImageIcon(GemGenerator.class.getResource("/Resources/supercombinator.gif"));
   
    /** The icon to use for error messages. */
    private static final Icon ERROR_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/error.gif"));

    /** The icon to use for warning messages. */
    private static final Icon WARNING_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/warning.gif"));
   
    /** The icon to use if everything is ok. */
    private static final Icon OK_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/checkmark.gif"));

    /** The icon to use to represent folders. */
    private static final Icon FOLDER_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/fldr_obj.gif"));
   
    /** The icon to use to represent .jar files. */
    private static final Icon JAR_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/jar_obj.gif"));

    /** The icon to use for an include pattern. */
    private static final Icon INCLUDE_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/add_exc.gif"));
   
    /** The icon to use for an exclude pattern.*/
    private static final Icon EXCLUDE_ICON = new ImageIcon(GemCutter.class.getResource("/Resources/remove_exc.gif"));

    /** The perspective this UI is running in. */
    private final Perspective perspective;

    /** The JList displaying the roots from which to import the Java classes and members.
     *  The model consists of elements of type ImportSource. */
    private ImportFromJList importFromJList;

    /** The JList displaying the patterns used to filter the classes being imported. */
    private PatternJList patternsJList;

    /** The panel allowing the generation scope to be selected. */
    private ScopeSelectorPanel scopeSelectorPanel;

    /** The panel allowing methods to be excluded from generation. */
    private MethodExcludeSelectorPanel methodExcludeSelectorPanel;
   
    /** The OK button for the dialog. */
    private JButton okButton = null;
   
    /** The cancel button for the dialog. */
    private JButton cancelButton = null;
   
    /** The text field for entering the name of the new module. */
    private final JTextField moduleNameField = new JTextField();
   
    /** The label for displaying status messages. */
    private final JLabel statusLabel = new JLabel();

    /** Shared dialog instance for selecting imports. */
    private SelectImportDialog selectImportDialog = null;

   
    /**
     * Test target.
     * Comment out check for null Perspective to execute.
     * @param args
     */
    public static void main(String[] args) {
        JavaForeignImportModuleGenerator generator = new JavaForeignImportModuleGenerator(null, null, null);
        JFrame.setDefaultLookAndFeelDecorated(true);
       
        generator.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                System.exit(0);
            }
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        generator.setVisible(true);
    }
   
    /**
     * Provider for a JavaForeignImportModuleGenerator.
     * @author Edward Lam
     */
    public static class Provider implements GemGenerator {
        /**
         * {@inheritDoc}
         */
        public GemGenerator.GeneratedDefinitions launchGenerator(JFrame parent, Perspective perspective, ValueRunner valueRunner, ValueEditorManager valueEditorManager, TypeChecker typeChecker) {
            if (parent == null || perspective == null) {
                throw new NullPointerException();
            }
   
            String title = getGeneratorTitle();
            JavaForeignImportModuleGenerator generatorUI = new JavaForeignImportModuleGenerator(parent, title, perspective);
   
            // Loop around until either:
            // 1) The user accepted the dialog and a module was successfully generated, or
            // 2) The user canceled the dialog.
            while (true) {
                boolean accepted = generatorUI.doModal();
               
                if (accepted) {
                    GeneratedDefinitions sourceDefinitions = generatorUI.getSourceDefinitions();
                   
                    if (sourceDefinitions.getModuleDefn() == null) {
                        // Couldn't successfully generate a module.  Try again.
                        continue;
                    }
                   
                    return sourceDefinitions;
               
                } else {
                    return null;
                }
            }
        }
       
        /**
         * {@inheritDoc}
         */
        public String getGeneratorMenuName() {
            return GeneratorMessages.getString("JFIMF_JavaForeignImportMenuName");
        }
       
        /**
         * {@inheritDoc}
         */
        public String getGeneratorTitle() {
            return GeneratorMessages.getString("JFIMF_JavaForeignImportTitle");
        }
       
        /**
         * {@inheritDoc}
         */
        public Icon getGeneratorIcon() {
            return GENERATOR_ICON;
        }
    }
   
    /**
     * A log handler which will capture logged records to a Status object.
     * @author Edward Lam
     */
    private static class StatusHandler extends Handler {

        /** The status object capturing the published records. */
        private final Status capturingStatus = new Status("Status");
       
        /**
         * {@inheritDoc}
         */
        @Override
        public void flush() {
            // Nothing to flush -- not buffered.
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void close() throws SecurityException {
            // Nothing to close, for now.
            // Later, there may be some way of saying that the capturing status is no longer mutable..
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void publish(LogRecord record) {
           
            // Add the record to the capturing status.
            String message = record.getMessage();
            Level level = record.getLevel();
            int levelValue = level.intValue();
           
            // Only interested in warnings and errors.
            Status.Severity severity = null;
            if (levelValue >= Level.SEVERE.intValue()) {
                severity = Status.Severity.ERROR;
            } else if (levelValue >= Level.WARNING.intValue()) {
                severity = Status.Severity.WARNING;
            }
           
            if (severity != null) {
                capturingStatus.add(new Status(severity, message));
            }
        }
       
        /**
         * @return the status which captured the records published to this handler.
         */
        public Status getStatus() {
            return capturingStatus;
        }
    }
   
    /**
     * A simple class to encapsulate an import source.
     * @author Edward Lam
     */
    private static class ImportSource {
        private final File importFile;
        private final boolean isDir;

        ImportSource(File importFile, boolean isDir) {
            this.importFile = importFile;
            this.isDir = isDir;
        }
       
        /**
         * @return the file object associated with the import source.
         */
        public File getImportFile() {
            return this.importFile;
        }

        /**
         * @return true if the source is a root folder.  False if it is a .jar file.
         */
        public boolean isDir() {
            return this.isDir;
        }
       
        /**
         * {@inheritDoc}
         */
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof ImportSource) {
                ImportSource otherSource = (ImportSource)obj;
                return isDir == otherSource.isDir && importFile.equals(otherSource.importFile);
            }
            return false;
        }
       
        /**
         * {@inheritDoc}
         */
        @Override
        public int hashCode() {
            return importFile.hashCode() + (isDir ? 17 : 37);
        }
       
        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return "(" + (isDir ? "directory: " : "file: ") + importFile.getPath() + ")";
        }
    }

    /**
     * Sorts import sources in the import source list.
     * Folders come first, then files.
     * @author Edward Lam
     */
    static class ImportSourceComparator implements Comparator<ImportSource> {
    
        /** Singleton instance. */
        public static final ImportSourceComparator INSTANCE = new ImportSourceComparator();
       
        /**
         * {@inheritDoc}
         */
        public int compare(ImportSource import1, ImportSource import2) {
           
            // import 1 is a folder?
            if (import1.isDir()) {
                if (!import2.isDir()) {
                    return -1;
                }

                // import 2 is also a folder.
                return import1.getImportFile().compareTo(import2.getImportFile());
           
            } else {
                // If here, import 1 is a file.
               
                if (import2.isDir()) {
                    return 1;
                }
               
                // import 2 is also a file.
                return import1.getImportFile().compareTo(import2.getImportFile());
            }
        }
    }

    /**
     * The custom cell renderer for displaying the import sources in the importFromJList.
     * @author Edward Lam
     */
    private static class ImportFromJListCellRenderer extends DefaultListCellRenderer {
       
        private static final long serialVersionUID = -8242855895470608433L;
        /** Shared renderer instance. */
        public static final ImportFromJListCellRenderer INSTANCE = new ImportFromJListCellRenderer();
       
        /**
         * {@inheritDoc}
         */
        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            ImportSource importSource = (ImportSource)value;
            File importFile = importSource.getImportFile();
            boolean isDir = importSource.isDir();
           
            String displayText = importFile.getPath();
            if (importFile.getAbsolutePath().startsWith(JAVA_HOME) && importFile.getName().equals("rt.jar")) {
                displayText += "  " + GeneratorMessages.getString("JFIMF_RTJarDescription");
            }
           
            // Get the default renderer, displaying the import file.
            JLabel defaultComponent = (JLabel)super.getListCellRendererComponent(list, displayText, index, isSelected, cellHasFocus);
           
            defaultComponent.setIcon(isDir ? FOLDER_ICON : JAR_ICON);
           
            return defaultComponent;
        }
    }
   
    /**
     * The JList for displaying the import sources.
     *
     * A special renderer to show whether the import source is a folder or a .jar file.
     * The items are maintained in sorted order.
     * Selection of items is automatically handled on add/edit/remove.
     *
     * To use, do not manipulate the list model.  Instead, call the appropriate (add/edit/removeSelected)ImportSource() method.
     *
     * @author Edward Lam
     */
    private static final class ImportFromJList extends JList {
        private static final long serialVersionUID = 2899009970173033431L;

        /**
         * Constructor for a new list.
         */
        private ImportFromJList() {
            super(new SortedListModel<ImportSource>(ImportSourceComparator.INSTANCE));
           
            setCellRenderer(ImportFromJListCellRenderer.INSTANCE);
            setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        }

        /**
         * @return the SortedListModel backing this JList.
         */
        SortedListModel<ImportSource> getListModel() {
            return UnsafeCast.unsafeCast(getModel());
        }
       
        /**
         * @return the currently selected ImportSource, or null if the list has no selection
         */
        public ImportSource getSelectedImport() {
            return (ImportSource)getSelectedValue();
        }
       
        /**
         * Add an import source to this JList.
         * @param importSource the import source to add.
         */
        void addImport(ImportSource importSource) {
            getListModel().addElement(importSource);

            // Select the import that was just added.
            selectImport(importSource);
        }
       
        /**
         * Select an import in this JList.
         * @param importToSelect the import to select.
         */
        private void selectImport(ImportSource importToSelect) {
            int importIndex = 0;
            for (Iterator<ImportSource> it = getListModel().iterator(); it.hasNext(); ) {
                if (it.next().equals(importToSelect)) {
                    getSelectionModel().setSelectionInterval(importIndex, importIndex);
                    break;
                }
                importIndex++;
            }
        }
       
        /**
         * Edit an import in this JList.
         * @param oldImport the old import.
         * @param newImport the import with which oldImport will be replaced.
         */
        void editImport(ImportSource oldImport, ImportSource newImport) {
            // The easiest way to edit an import is to remove the old import, and add the new one.
            getListModel().removeElement(oldImport);
            getListModel().addElement(newImport);
           
            // Select the import which was just edited.
            selectImport(newImport);
        }
       
        /**
         * Remove the import currently selected in this JList.
         */
        void removeSelectedImport() {
            ListSelectionModel selectionModel = getSelectionModel();
           
            // Remove the selected element.
            int selectionIndex = selectionModel.getMinSelectionIndex();
            if (selectionIndex < 0) {
                return;
            }
            getListModel().removeElement(getSelectedImport());
           
            // Select another element if any.
            int modelSize = getModel().getSize();
            if (selectionIndex < modelSize) {
                // Select the next element.
                selectionModel.setSelectionInterval(selectionIndex, selectionIndex);
            } else if (modelSize > 0) {
                // Select the last element.
                selectionModel.setSelectionInterval(modelSize - 1, modelSize - 1);
            } else {
                selectionModel.clearSelection();
            }
        }
    }
   
    /**
     * Sorts patterns in the pattern list.
     * Includes come first, then excludes.
     * @author Edward Lam
     */
    static class JFitPatternComparator implements Comparator<Object> {
    
        /** Singleton instance. */
        public static final JFitPatternComparator INSTANCE = new JFitPatternComparator();
       
        /**
         * {@inheritDoc}
         */
        public int compare(Object o1, Object o2) {
           
            if (o1 instanceof String) {
                if (o2 instanceof String) {
                    return ((String)o1).compareTo((String)o2);
                }
                return -1;
            }
            if (o2 instanceof String) {
                return 1;
            }
           
            JFit.Pattern pat1 = (JFit.Pattern)o1;
            JFit.Pattern pat2 = (JFit.Pattern)o2;
           
            // pattern 1 is an include pattern?
            if (pat1.isInclude()) {
                if (!pat2.isInclude()) {
                    return -1;
                }

                // pattern 2 is also an include pattern.
                return pat1.getPattern().compareTo(pat2.getPattern());
           
            } else {
                // If here, pattern 1 is an exclude pattern.
               
                if (pat2.isInclude()) {
                    return 1;
                }
               
                // pattern 2 is also an exclude pattern.
                return pat1.getPattern().compareTo(pat2.getPattern());
            }
        }
    }
   
    /**
     * The custom cell renderer for displaying include and exclude patterns in the patternJList.
     * @author Edward Lam
     */
    private static class PatternJListCellRenderer extends DefaultListCellRenderer {
       
        private static final long serialVersionUID = 3352312909749939764L;
        /** Shared renderer instance. */
        public static final PatternJListCellRenderer INSTANCE = new PatternJListCellRenderer();
       
        /**
         * {@inheritDoc}
         */
        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            if (value instanceof String) {
                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            }
           
            // Get the default renderer, displaying the pattern string.
            JFit.Pattern pattern = (JFit.Pattern)value;
            JLabel defaultComponent = (JLabel)super.getListCellRendererComponent(list, pattern.getPattern(), index, isSelected, cellHasFocus);
           
            defaultComponent.setIcon(pattern.isInclude() ? INCLUDE_ICON : EXCLUDE_ICON);
           
            return defaultComponent;
        }
    }
   
    /**
     * The JList for displaying the include/exclude patterns.
     *
     * A special renderer to show whether a pattern is included or excluded.
     * The items are maintained in sorted order.
     * Selection of items is automatically handled on add/edit/remove.
     *
     * To use, do not manipulate the list model.  Instead, call the appropriate (add/edit/removeSelected)Pattern() method.
     *
     * @author Edward Lam
     */
    private static final class PatternJList extends JList {
       
        private static final long serialVersionUID = 4724753052424581727L;
        // The string to display when no patterns have been specified.
        private static final String NO_PATTERNS_ELEMENT = GeneratorMessages.getString("JFIMF_NoPatternsElement");
       
        /**
         * Constructor for a new list.
         */
        private PatternJList() {
            super(new SortedListModel<Object>(JFitPatternComparator.INSTANCE));
           
            setCellRenderer(PatternJListCellRenderer.INSTANCE);
            setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

            getListModel().addElement(NO_PATTERNS_ELEMENT);
        }

        /**
         * @return the SortedListModel backing this JList.
         */
        SortedListModel<Object> getListModel() {
            return UnsafeCast.unsafeCast(getModel());
        }
       
        /**
         * @return the currently selected JFit.Pattern, or null if:
         * 1) the list has no selection
         * 2) the list selection is the no-patterns element.
         */
        public JFit.Pattern getSelectedPattern() {
            Object selectedValue = getSelectedValue();
           
            if (selectedValue instanceof JFit.Pattern) {
                return (JFit.Pattern)selectedValue;
            }
           
            return null;
        }
       
        /**
         * Add a pattern to this JList.
         * @param jfitPattern the pattern to add.
         */
        void addPattern(JFit.Pattern jfitPattern) {
            // If there were no patterns, we make sure the "No patterns" message is removed.
            if (getListModel().getSize() < 2) {
                // This does nothing if the single element is not the no patterns element.
                getListModel().removeElement(NO_PATTERNS_ELEMENT);
               
                // Clear selection so that the selection changed event will be fired when the first item is selected again.
                getSelectionModel().clearSelection();
            }
            getListModel().addElement(jfitPattern);

            // Select the pattern that was just added.
            selectPattern(jfitPattern);
        }
       
        /**
         * Select a pattern in this JList.
         * @param patternToSelect the pattern to select.
         */
        private void selectPattern(JFit.Pattern patternToSelect) {
            int patternIndex = 0;
            for (Iterator<Object> it = getListModel().iterator(); it.hasNext(); ) {
                if (it.next().equals(patternToSelect)) {
                    getSelectionModel().setSelectionInterval(patternIndex, patternIndex);
                    break;
                }
                patternIndex++;
            }
        }
       
        /**
         * Edit a pattern in this JList.
         * @param oldPattern the old pattern.
         * @param newPattern the pattern with which oldPattern will be replaced.
         */
        void editPattern(JFit.Pattern oldPattern, JFit.Pattern newPattern) {
            // The easiest way to edit a pattern is to remove the old pattern, and add the new one.
            getListModel().removeElement(oldPattern);
            getListModel().addElement(newPattern);
           
            // Select the pattern which was just edited.
            selectPattern(newPattern);
        }
       
        /**
         * Remove the pattern currently selected in this JList.
         */
        void removeSelectedPattern() {
            ListSelectionModel selectionModel = getSelectionModel();
           
            // Remove the selected element.
            int selectionIndex = selectionModel.getMinSelectionIndex();
            if (selectionIndex < 0) {
                return;
            }
            getListModel().removeElement(getSelectedPattern());
           
            // Select another element.
            int modelSize = getModel().getSize();
            if (selectionIndex < modelSize) {
                // Select the next element.
                selectionModel.setSelectionInterval(selectionIndex, selectionIndex);
            } else if (modelSize > 0) {
                // Select the last element.
                selectionModel.setSelectionInterval(modelSize - 1, modelSize - 1);
            } else {
                selectionModel.clearSelection();
            }
           
            // If there are no patterns, display the "No patterns" message.
            if (modelSize == 0) {
                getListModel().addElement(NO_PATTERNS_ELEMENT);
            }
        }

        /**
         * @return true if there are no patterns, false if there are.
         */
        public boolean isEmpty() {
          return (getModel().getSize() == 1) && getModel().getElementAt(0).equals(NO_PATTERNS_ELEMENT);
        }
    }
   
    /**
     * The dialog to select an import source.
     * This is just a dialog with an embedded JFileChooser and a help panel at the top.
     *
     * To use: instantiate, then call showDialog().
     *
     * @author Edward Lam
     */
    private static class SelectImportDialog extends DialogBase {
       
        private static final long serialVersionUID = 8113203595172861783L;

        /** Shared file chooser instance for selecting imports. */
        private final JFileChooser fileChooser;

        /** The help panel at the top of the dialog. */
        private final TitlePanel helpPanel;
       
        /** The current return value. 
         *  This mirrors the same value in JFileChooser, which unfortunately has no accessors. */
        private int returnValue = JFileChooser.ERROR_OPTION;
       
        /** The size constrainer for this dialog. */
        private final SizeConstrainer sizeConstrainer;
       
        /**
         * Constructor for a SelectImportDialog.
         * @param parent the parent of this dialog.
         */
        private SelectImportDialog(JDialog parent) {
            super(parent, "");
           
            sizeConstrainer = new SizeConstrainer();
            addComponentListener(sizeConstrainer);
           
            // main panel
            JPanel topPanel = getTopPanel();
            topPanel.setBorder(null);               // cancel the border set by superclass..
            setContentPane(topPanel);
           
            // Keep track of the number of rows.
            int numRows = 0;
           
            // Help panel to the north.
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.WEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;

                constraints.gridx = 0;
                constraints.gridy = numRows;
               
                helpPanel = new TitlePanel();
               
                topPanel.add(helpPanel, constraints);
                numRows++;
            }
           
            // file chooser to the south.
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.WEST;
                constraints.fill = GridBagConstraints.BOTH;

                constraints.gridx = 0;
                constraints.gridy = numRows;
                constraints.weightx = 1.0;
                constraints.weighty = 1.0;
               
                // Start out pointing at the current directory.
                File currentDirectory = new File(".");
               
                fileChooser = new JFileChooser(currentDirectory) {
                    private static final long serialVersionUID = 2625522895016359504L;
                    @Override
                    public void approveSelection() {
                        returnValue = JFileChooser.APPROVE_OPTION;
                        super.approveSelection();
                        closeDialog(false);
                    }
                    @Override
                    public void cancelSelection() {
                        returnValue = JFileChooser.CANCEL_OPTION;
                        super.cancelSelection();
                        closeDialog(true);
                    }
                };
               
                // Provide a custom icon for .jar files.
                fileChooser.setFileView(new FileView() {
                    @Override
                    public Icon getIcon(File f) {
                        if (f.getName().endsWith(".jar")) {
                            return JAR_ICON;
                        }
                        return null;
                    }
                });
               
                topPanel.add(fileChooser, constraints);
                numRows++;
            }
           
            // Handle window events.
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    returnValue = JFileChooser.CANCEL_OPTION;
                    closeDialog(true);
                }
            });
        }

        /**
         * Show the dialog.
         *
         * @param currentFile
         *            If non-null the file chooser will be specified as "Change"ing
         *            the given import. Otherwise, it will be set up as adding a new
         *            import file.
         * @param chooseDir
         *            if true, this the chooser is to select a directory. If false,
         *            it's so select a file.
         * @return  the return state of the file chooser on popdown:
         * <ul>
         * <li>JFileChooser.CANCEL_OPTION
         * <li>JFileChooser.APPROVE_OPTION
         * <li>JFileCHooser.ERROR_OPTION if an error occurs or the
         *                  dialog is dismissed
         * </ul>
         */
        public int showDialog(File currentFile, boolean chooseDir) {
           
            returnValue = JFileChooser.ERROR_OPTION;
           
            // Customize the existing file chooser.
            {
                // Set the current directory if provided by currentFile.
                if (currentFile != null) {
                    // Change the file chooser's current directory if a file was passed in.
                    File currentDirectory = currentFile.isDirectory() ? currentFile : currentFile.getParentFile();
                    fileChooser.setCurrentDirectory(currentDirectory);
                }
               
                if (chooseDir) {
                    // Set the file selection mode.
                    fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                   
                } else {
                    // Set the file selection mode.
                    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
                   
                    // Set a custom file filter.
                    fileChooser.setFileFilter(new ExtensionFileFilter("jar", GeneratorMessages.getString("JFIMF_Chooser_ImportJarFilterDescription")));
                }
               
                // Customize the add button text.
                String buttonText = GeneratorMessages.getString(
                        chooseDir ? (currentFile == null ? "JFIMF_Chooser_AddImportFolder" : "JFIMF_Chooser_ChangeImportFolder") :
                            (currentFile == null ? "JFIMF_Chooser_AddImportJar" : "JFIMF_Chooser_ChangeImportJar")
                );
               
                fileChooser.setApproveButtonText(buttonText);
                fileChooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
            }
           
            // Set the dialog description and title.
            String title = fileChooser.getUI().getDialogTitle(fileChooser);
            getAccessibleContext().setAccessibleDescription(title);
            setTitle(title);
           
            // Customize the help panel
            {
                String titleText;
                String subtitleText;
                if (chooseDir) {
                    titleText = GeneratorMessages.getString(currentFile == null ? "JFIMF_ChooserHelp_AddFolderTitle" : "JFIMF_ChooserHelp_ChangeFolderTitle");
                    subtitleText = GeneratorMessages.getString("JFIMF_ChooserHelp_ChooseFolderSubtitle");
                } else {
                    titleText = GeneratorMessages.getString(currentFile == null ? "JFIMF_ChooserHelp_AddJarTitle" : "JFIMF_ChooserHelp_ChangeJarTitle");
                    subtitleText = GeneratorMessages.getString("JFIMF_ChooserHelp_ChooseJarSubtitle");
                }
               
                helpPanel.setTitleText(titleText);
                helpPanel.setSubtitleText(subtitleText);
            }
           
            // Decorate like a file chooser dialog.
            if (JDialog.isDefaultLookAndFeelDecorated() && UIManager.getLookAndFeel().getSupportsWindowDecorations()) {
                getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG);
            }
           
            pack();
            sizeConstrainer.setMinimumSize(getSize());
            doModal();
           
            return returnValue;
        }
       
        /**
         * @return the file selected in the embedded file chooser.
         */
        public File getSelectedFile() {
            return fileChooser.getSelectedFile();
        }
    }
   
    /**
     * The dialog to enter a pattern to add.
     *
     * @author Edward Lam
     */
    private static class AddEditPatternDialog extends DialogBase {
       
        private static final long serialVersionUID = 3566552733651814629L;

        /** The radio button for selecting an include pattern. */
        private final JRadioButton includeButton = new JRadioButton(GeneratorMessages.getString("JFIMF_Include"));
       
        /** The radio button for selecting an exclude pattern. */
        private final JRadioButton excludeButton = new JRadioButton(GeneratorMessages.getString("JFIMF_Exclude"));

        /** The button group for the radio buttons. */
        private final ButtonGroup buttonGroup = new ButtonGroup();
       
        /** The text field for entering the pattern. */
        private final JTextField patternField = new JTextField();
       
        /** The OK button for the dialog. */
        private JButton okButton = null;
       
        /** The cancel button for the dialog. */
        private JButton cancelButton = null;

        /** The help panel at the top of the dialog. */
        private final TitlePanel helpPanel;
       
        /**
         * Constructor for an AddEditPatternDialog.
         * @param owner the owner dialog.
         * @param selectedPattern the previously existing pattern, if any.
         * If non-null, this is an edit dialog, and dialog will be initialized with this pattern.
         * If null, this is an add dialog.
         */
        private AddEditPatternDialog(Dialog owner, JFit.Pattern selectedPattern) {
            super(owner, GeneratorMessages.getString(selectedPattern == null ? "JFIMF_AddPatternDialogTitle" : "JFIMF_EditPatternDialogTitle"));

            // main panel
            JPanel topPanel = getTopPanel();
            topPanel.setBorder(null);               // cancel the border set by superclass..
            setContentPane(topPanel);
           
            // Keep track of the number of rows.
            int numRows = 0;
           
            int iconTextGap = includeButton.getIconTextGap();
           
            // Add the help panel.
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.WEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;

                constraints.gridx = 0;
                constraints.gridy = numRows;
               
                this.helpPanel = new TitlePanel();
                helpPanel.setTitleText(getTitle());
                helpPanel.setSubtitleText(GeneratorMessages.getString("JFIMF_AddPatternDialogSubtitle"));

                topPanel.add(helpPanel, constraints);
                numRows++;
            }
           
            // Add the radio panel
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.WEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;

                constraints.gridx = 0;
                constraints.gridy = numRows;

                // Set up the buttons in a button group.
                buttonGroup.add(includeButton);
                buttonGroup.add(excludeButton);
                if (selectedPattern != null) {
                    if (selectedPattern.isInclude()) {
                        buttonGroup.setSelected(includeButton.getModel(), true);
                    } else {
                        buttonGroup.setSelected(excludeButton.getModel(), true);
                    }
                } else {
                    buttonGroup.setSelected(includeButton.getModel(), true);
                }

                // Create the panel with the two radio buttons and some glue..
                JPanel radioPanel = new JPanel();
                radioPanel.setBorder(BorderFactory.createEmptyBorder(5, 5 - iconTextGap, 5, 5));
                radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.X_AXIS));
               
                radioPanel.add(includeButton);
                radioPanel.add(Box.createHorizontalStrut(5));
                radioPanel.add(excludeButton);
                radioPanel.add(Box.createHorizontalGlue());

                topPanel.add(radioPanel, constraints);
                numRows++;
            }
           
            // Add the Pattern entry area
            {
                GridBagConstraints constraints = new GridBagConstraints ();
                constraints.anchor = GridBagConstraints.WEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;
                constraints.insets = new Insets(0, 0, 0, 5);
               
                constraints.gridx = 0;
                constraints.gridy = numRows;
                constraints.gridwidth = GridBagConstraints.REMAINDER;
               

                JPanel patternLabelAndFieldPanel = new JPanel();
                patternLabelAndFieldPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 0));
                patternLabelAndFieldPanel.setLayout(new BoxLayout(patternLabelAndFieldPanel, BoxLayout.X_AXIS));
                patternLabelAndFieldPanel.add(new JLabel(GeneratorMessages.getString("JFIMF_PatternHeader")));
                patternLabelAndFieldPanel.add(Box.createHorizontalStrut(15));
               
                patternField.setColumns(40);
                if (selectedPattern != null) {
                    patternField.setText(selectedPattern.getPattern());
                }
                patternLabelAndFieldPanel.add(patternField);
                patternLabelAndFieldPanel.add(Box.createHorizontalGlue());
               
                topPanel.add(patternLabelAndFieldPanel, constraints);
                numRows++;
            }
           
            // Add the label for the wildcard explanation.
            {
                GridBagConstraints constraints = new GridBagConstraints ();
                constraints.anchor = GridBagConstraints.WEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;
                constraints.insets = new Insets(0, 5, 10, 5);
               
                constraints.gridx = 0;
                constraints.gridy = numRows;
                constraints.gridwidth = GridBagConstraints.REMAINDER;
               

                JLabel wildcardExplanationLabel = new JLabel(GeneratorMessages.getString("JFIMF_WildcardExplanation"));
               
                topPanel.add(wildcardExplanationLabel, constraints);
                numRows++;
            }
           
            // Add the ok/cancel button area.
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.gridy = numRows;
                constraints.gridwidth = GridBagConstraints.REMAINDER;
                constraints.anchor = GridBagConstraints.SOUTHEAST;

                Box buttonBox = new Box (BoxLayout.X_AXIS);
                buttonBox.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 5));
               
                this.okButton = makeOKButton();
                this.cancelButton = makeCancelButton();
               
                getRootPane().setDefaultButton(okButton);
               
                buttonBox.add (Box.createHorizontalGlue());
                buttonBox.add (okButton);
                buttonBox.add (Box.createHorizontalStrut(5));
                buttonBox.add (cancelButton);

                topPanel.add(buttonBox, constraints);
               
                numRows++;
            }
           
            // Make the pattern field have default focus
            setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
                private static final long serialVersionUID = 2187420438565327738L;

                @Override
                public Component getDefaultComponent(Container c) {
                    return patternField;
                }
            });

            // Esc cancels the dialog.
            KeyListener dismissKeyListener = new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                        dispose();
                        e.consume();
                    }
                }
            };
           
            // The ok button is only enabled if there is a pattern entered.
            okButton.setEnabled(false);
            patternField.addKeyListener(new KeyAdapter() {
                @Override
                public void keyReleased(KeyEvent e) {
                    okButton.setEnabled(patternField.getText().length() > 0);
                }
            });

            // Cancel the dialog if the user presses ESC
            addKeyListener(dismissKeyListener);
            patternField.addKeyListener(dismissKeyListener);
            okButton.addKeyListener(dismissKeyListener);
            cancelButton.addKeyListener(dismissKeyListener);

            this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
           
            pack();

            // Not resizeable.
            setResizable(false);
           
            // position relative to the owner frame.
            setLocationRelativeTo(owner);
        }
       
        /**
         * @return the JFit.Pattern entered by the user.
         * Note: this will return a non-null result even if the dialog was cancelled.
         */
        JFit.Pattern getFitPattern() {
            return new JFit.Pattern(patternField.getText().trim(), includeButton.isSelected());
        }
    }

    /**
     * A panel displaying some radio buttons allowing the user to select a generation scope.
     * @author Edward Lam
     */
    private static class ScopeSelectorPanel extends JPanel {
        private static final long serialVersionUID = -5400480868412313409L;
        private final JRadioButton allPrivateButton = new JRadioButton(GeneratorMessages.getString("JFIMF_ScopeAllPrivate"));
        private final JRadioButton partialPublicButton = new JRadioButton(GeneratorMessages.getString("JFIMF_ScopePartialPublic"));
        private final JRadioButton allPublicButton = new JRadioButton(GeneratorMessages.getString("JFIMF_ScopeAllPublic"));
       
        ScopeSelectorPanel() {
            // Set up the buttons in a button group.
            ButtonGroup buttonGroup = new ButtonGroup();

            buttonGroup.add(allPrivateButton);
            buttonGroup.add(partialPublicButton);
            buttonGroup.add(allPublicButton);
           
            // Default to all private.
            buttonGroup.setSelected(allPrivateButton.getModel(), true);

            // Set the layout.
            this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

            // Add the buttons.
            this.add(allPrivateButton);
            this.add(partialPublicButton);
            this.add(allPublicButton);
        }

        /**
         * @return the selected scope.
         */
        ForeignImportGenerator.GenerationScope getSelectedScope() {
            if (allPrivateButton.isSelected()) {
                return ForeignImportGenerator.GenerationScope.ALL_PRIVATE;
            }
           
            if (partialPublicButton.isSelected()) {
                return ForeignImportGenerator.GenerationScope.PARTIAL_PUBLIC;
            }
           
            if (allPublicButton.isSelected()) {
                return ForeignImportGenerator.GenerationScope.ALL_PUBLIC;
            }
           
            return null;
        }
    }
   
    /**
     * A panel allowing the user to indicate methods to exclude.
     * @author Edward Lam
     */
    private static class MethodExcludeSelectorPanel extends JPanel {
        private static final long serialVersionUID = 6319968816481922026L;
        private final JCheckBox equalsHashCodeButton = new JCheckBox(GeneratorMessages.getString("JFIMF_OptionalEqualsHashCode"));
        private final JCheckBox waitNotifyButton = new JCheckBox(GeneratorMessages.getString("JFIMF_OptionalWaitNotify"));
        private final JCheckBox getClassButton = new JCheckBox(GeneratorMessages.getString("JFIMF_OptionalGetClass"));
       
        MethodExcludeSelectorPanel() {

            // Put the check boxes in a column in a panel
           
            // Set the layout.
            this.setLayout(new GridLayout(0, 1));

            // Add the check boxes
            add(equalsHashCodeButton);
            add(waitNotifyButton);
            add(getClassButton);
        }
       
        String[] getExcludeMethods() {
            List<String> excludeMethodList = new ArrayList<String>();
           
            if (!equalsHashCodeButton.isSelected()) {
                excludeMethodList.add("java.lang.Object.equals");
                excludeMethodList.add("java.lang.Object.hashCode");
            }
            if (!waitNotifyButton.isSelected()) {
                excludeMethodList.add("java.lang.Object.wait");
                excludeMethodList.add("java.lang.Object.notify");
                excludeMethodList.add("java.lang.Object.notifyAll");

            }
            if (!getClassButton.isSelected()) {
                excludeMethodList.add("java.lang.Object.getClass");
            }
           

            return excludeMethodList.toArray(new String[excludeMethodList.size()]);
        }
    }
   
    /**
     * Constructor for a new generator ui.
     * Use a factory method to get an instance.
     *
     * @param owner the owner of the dialog
     * @param dialogTitle if null, the default title will be used
     * @param perspective the perspective the UI should use
     */
    private JavaForeignImportModuleGenerator(Frame owner, String dialogTitle, Perspective perspective) {
        super(owner, dialogTitle);
       
        // (Java bug workaround) ensure JFileChooser will load..
        ensureJFileChooserLoadable();
       
        if (perspective == null) {
            throw new NullPointerException();
        }
       
        this.perspective = perspective;

        if (dialogTitle == null) {
            setTitle(GeneratorMessages.getString("JFIMF_JavaForeignImportTitle"));
        }
       
        // main panel
        JPanel topPanel = getTopPanel();
        topPanel.setBorder(null);               // cancel the border set by superclass..
        setContentPane(topPanel);
       
        // Keep track of the number of rows.
        int numRows = 0;
       
        // Add the title panel - the white panel at the top of the dialog.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.NORTH;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
           
            TitlePanel titlePanel = new TitlePanel(true);
            titlePanel.setTitleText(GeneratorMessages.getString("JFIMF_JavaForeignImportTitle"));
            titlePanel.setSubtitleText(GeneratorMessages.getString("JFIMF_JavaForeignImportSubTitle"));

            topPanel.add(titlePanel, constraints);
            numRows++;
        }
        // Add the main panel
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.CENTER;
            constraints.fill = GridBagConstraints.BOTH;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.weightx = 1;
            constraints.weighty = 1;
            topPanel.add(getMainPanel(), constraints);
            numRows++;
        }
        // Add a separator.
        {
            addSeparator(topPanel, null, numRows, new Insets(10, 0, 5, 0));
            numRows++;
        }
        // Add the button panel.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.SOUTH;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
           
            this.okButton = makeOKButton();
            this.cancelButton = makeCancelButton();
           
            JPanel buttonPanel = new JPanel();
           
            buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
           
            buttonPanel.add(Box.createHorizontalGlue());
            buttonPanel.add(okButton);
            buttonPanel.add(Box.createHorizontalStrut(5));
            buttonPanel.add(cancelButton);
           
            topPanel.add(buttonPanel, constraints);
            numRows++;
        }

        getRootPane().setDefaultButton(okButton);

        // Add default import source(s).
        addDefaultImports();

        // Update the state of the dialog.
        updateState();
       
        // Add listeners to update the error message if things change
        moduleNameField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                updateState();
            }
        });
       
        importFromJList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                updateState();
            }
        });

        patternsJList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                updateState();
            }
        });

        // Esc cancels the dialog.
        KeyListener dismissKeyListener = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                    dispose();
                    e.consume();
                }
            }
        };

        // Cancel the dialog if the user presses ESC
        addKeyListener(dismissKeyListener);
        moduleNameField.addKeyListener(dismissKeyListener);
        okButton.addKeyListener(dismissKeyListener);
        cancelButton.addKeyListener(dismissKeyListener);

        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
       
        pack();
        setSize(600, getSize().height);
       
        addComponentListener(new SizeConstrainer(getSize()));
       
        // position relative to the owner frame.
        setLocationRelativeTo(owner);
    }

    /**
     * @return the generated module definition.
     * Note: this method may display a modal dialog if problems were encountered.
     */
    public GemGenerator.GeneratedDefinitions getSourceDefinitions() {
       
        // Create a logger.  Its handler will only handle warnings and errors.
        Logger generatorLogger = Logger.getLogger(getClass().getPackage().getName());
        generatorLogger.setLevel(Level.FINEST);
        generatorLogger.setUseParentHandlers(false);
       
        StatusHandler statusHandler = new StatusHandler();

        // Only interested in warnings and errors.
        statusHandler.setLevel(Level.WARNING);
        generatorLogger.addHandler(statusHandler);
       
       
        // Get the module name.
        String moduleName = moduleNameField.getText();

        // Get the patterns.
        JFit.Pattern[] patterns = getPatterns();
       
        // Get the selected generation scope
        ForeignImportGenerator.GenerationScope generationScope = scopeSelectorPanel.getSelectedScope();
       
        // Get the exclude methods.
        String[] excludeMethods = methodExcludeSelectorPanel.getExcludeMethods();
       
        //
        // Get the input files and dirs.
        //

        List<File> inputFileList = new ArrayList<File>();
        List<File> inputDirList = new ArrayList<File>();
       
        for (Iterator<ImportSource> it = importFromJList.getListModel().iterator(); it.hasNext(); ) {
            ImportSource importSource = it.next();
            if (importSource.isDir()) {
                inputDirList.add(importSource.getImportFile());
            } else {
                inputFileList.add(importSource.getImportFile());
            }
        }
        File[] inputFiles = inputFileList.toArray(new File[inputFileList.size()]);
        File[] inputDirs = inputDirList.toArray(new File[inputDirList.size()]);
       
        // Instantiate the fit options.
        JFit.Options options = JFit.Options.makeOptions(moduleName, inputFiles, inputDirs, null, patterns, generationScope, excludeMethods, generatorLogger);
       
        // Create the fitter and fit.
        JFit jfit = new JFit(options, perspective.getWorkspace(), generatorLogger);
        final ModuleDefn defn = jfit.autoFit();         // null if an error occurred.

        // Deal with warnings/errors.
        Status capturedStatus = statusHandler.getStatus();
        if (capturedStatus.getSeverity().compareTo(Status.Severity.WARNING) >= 0) {
            String title = GeneratorMessages.getString("JFIMF_JavaForeignImportTitle");
            String message = GeneratorMessages.getString("JFIMF_ProblemsGeneratingModule");
            String details = capturedStatus.getDebugMessage();
           
            DetailsDialog.MessageType messageType = capturedStatus.getSeverity() == Status.Severity.WARNING ?
                        DetailsDialog.MessageType.WARNING : DetailsDialog.MessageType.ERROR;
           
            DetailsDialog dialog = new DetailsDialog(this, title, message, details, messageType);
            dialog.doModal();
        }
       
        return new GemGenerator.GeneratedDefinitions() {

            public ModuleDefn getModuleDefn() {
                return defn;
            }

            public Map<String, String> getSourceElementMap() {
                return null;
            }
        };
    }

    /**
     * @return the patterns currently entered in the pattern list.
     */
    private JFit.Pattern[] getPatterns() {
        SortedListModel<Object> listModel = patternsJList.getListModel();
        List<JFit.Pattern> patternList = new ArrayList<JFit.Pattern>(listModel.getSize());

        for (Iterator<Object> it = listModel.iterator(); it.hasNext(); ) {
            Object nextElem = it.next();
            if (nextElem instanceof JFit.Pattern) {
                patternList.add((JFit.Pattern)nextElem);
            }
        }
       
        return patternList.toArray(new JFit.Pattern[patternList.size()]);
    }
   

    /**
     * @return the main panel that shows the contents of the dialog
     */
    private JPanel getMainPanel() {
       
        JPanel mainPanel = new JPanel();
       
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        mainPanel.setLayout(new GridBagLayout());

        // Keep track of the number of rows.
        int numRows = 0;
       
        // Status label.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.NORTHWEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.gridwidth = GridBagConstraints.REMAINDER;
            constraints.insets = new Insets(5, 5, 10, 5);
            mainPanel.add(statusLabel, constraints);
            numRows++;
           
            Font font = getFont();
            if (font == null) {
                font = UIManager.getFont("Label.font");
            }
            if (font != null) {
                statusLabel.setFont(font.deriveFont(Font.BOLD));
            }
        }
       
        // Module name entry
        {
            GridBagConstraints constraints = new GridBagConstraints ();
            constraints.anchor = GridBagConstraints.WEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;
            constraints.insets = new Insets(0, 0, 15, 5);
           
            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.gridwidth = GridBagConstraints.REMAINDER;
           
            JPanel moduleLabelAndFieldPanel = new JPanel();
            moduleLabelAndFieldPanel.setLayout(new BoxLayout(moduleLabelAndFieldPanel, BoxLayout.X_AXIS));
            moduleLabelAndFieldPanel.add(new JLabel(GeneratorMessages.getString("JFIMF_ModuleNameHeader")));
            moduleLabelAndFieldPanel.add(Box.createHorizontalStrut(15));
           
            moduleNameField.setColumns(20);
            moduleLabelAndFieldPanel.add(moduleNameField);
            moduleLabelAndFieldPanel.add(Box.createHorizontalGlue());
           
            mainPanel.add(moduleLabelAndFieldPanel, constraints);
            numRows++;
           
            // Make the module field have default focus
            setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
                private static final long serialVersionUID = -8536707255639997877L;

                @Override
                public Component getDefaultComponent(Container c) {
                    return moduleNameField;
                }
            });
        }


        // Import From Message.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.NORTHWEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.gridwidth = GridBagConstraints.REMAINDER;
           
            JLabel messageLabel = new JLabel(GeneratorMessages.getString("JFIMF_ImportFromHeader"));

            JPanel messagePanel = new JPanel();
            messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.X_AXIS));
            messagePanel.add(messageLabel);
            messagePanel.add(Box.createHorizontalStrut(200));
            messagePanel.add(Box.createHorizontalGlue());
            mainPanel.add(messagePanel, constraints);
            numRows++;
        }
       
        {
            // The buttons..
            final JButton addJarButton;
            final JButton addFolderButton;
            final JButton editImportButton;
            final JButton removeImportButton;
           
            // Import From List
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.NORTHWEST;
                constraints.fill = GridBagConstraints.BOTH;
               
                constraints.gridx = 0;
                constraints.gridy = numRows;
                constraints.gridheight = 4;     // the number of buttons.
                constraints.weightx = 1;
                constraints.weighty = 1;
                constraints.gridwidth = GridBagConstraints.RELATIVE;
                constraints.insets = new Insets(5, 15, 10, 5);
               
                // A mutable list model.  Only one item selectable.
                importFromJList = new ImportFromJList();
                JScrollPane importFromScrollPane = new JScrollPane(importFromJList);
               
                importFromScrollPane.setMinimumSize(new Dimension(1000, 1));
               
                mainPanel.add(importFromScrollPane, constraints);
                // Do not increment numRows.
            }
            // Import button area
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.NORTH;
                constraints.fill = GridBagConstraints.HORIZONTAL;
               
                constraints.gridx = 2;
                constraints.gridwidth = 1;

                // It would have been nice to create a Box, but this doesn't make buttons the same size.
                // A GridLayout makes all cells the same size, which doesn't allow for the extra space between the 2nd and 3rd buttons.
                // So keep using the grid bag layout.  This also allows us to easily make the buttons here the same
                //   size as those in the patterns aprea.
                {
                    addJarButton = new JButton(getAddImportJarAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(5, 5, 5, 5);
                    mainPanel.add(addJarButton, constraints);
                    numRows++;
                   
                    addFolderButton = new JButton(getAddImportFolderAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(0, 5, 10, 5);
                    mainPanel.add(addFolderButton, constraints);
                    numRows++;
                   
                    editImportButton = new JButton(getChangeImportAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(0, 5, 5, 5);
                    mainPanel.add(editImportButton, constraints);
                    numRows++;
                   
                    removeImportButton = new JButton(getRemoveImportAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(0, 5, 5, 5);
                    mainPanel.add(removeImportButton, constraints);
                    numRows++;
                }
            }
           
            //
            // Configure the buttons.
            //
           
            // Edit and remove start out disabled.
            editImportButton.setEnabled(false);
            removeImportButton.setEnabled(false);
           
            // When the list selection changes, change enabling of the edit and remove buttons.
            importFromJList.addListSelectionListener(new ListSelectionListener() {

                public void valueChanged(ListSelectionEvent e) {
                    boolean emptySelection = importFromJList.getSelectionModel().isSelectionEmpty();
                    editImportButton.setEnabled(!emptySelection);
                    removeImportButton.setEnabled(!emptySelection);
                }
            });
        }
       
       
        // Patterns Message.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.NORTHWEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.gridwidth = GridBagConstraints.REMAINDER;

           
            JLabel messageLabel = new JLabel(GeneratorMessages.getString("JFIMF_PatternsHeader"));

            JPanel messagePanel = new JPanel();
            messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.X_AXIS));
            messagePanel.add(messageLabel);
            messagePanel.add(Box.createHorizontalStrut(200));
            messagePanel.add(Box.createHorizontalGlue());
            mainPanel.add(messagePanel, constraints);
            numRows++;
        }
       
        {
            // The buttons.
            final JButton addPatternButton;
            final JButton editPatternButton;
            final JButton removePatternButton;
           
            // Patterns List.
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.NORTHWEST;
                constraints.fill = GridBagConstraints.BOTH;
               
                constraints.gridx = 0;
                constraints.gridy = numRows;
                constraints.gridheight = 3;     // the number of buttons.
                constraints.weightx = 1;
                constraints.weighty = 1;
                constraints.gridwidth = 1;
                constraints.insets = new Insets(5, 15, 15, 5);

                patternsJList = new PatternJList();
                JScrollPane patternsScrollPane = new JScrollPane(patternsJList);
               
                patternsScrollPane.setMinimumSize(new Dimension(1000, 1));
               
                mainPanel.add(patternsScrollPane, constraints);
                // Do not increment numRows.
            }
            // Patterns button area
            {
                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.NORTH;
                constraints.fill = GridBagConstraints.HORIZONTAL;
               
                constraints.gridx = 2;
                constraints.gridwidth = 1;

                // It would have been nice to create a Box, but this doesn't make buttons the same size.
                // A GridLayout makes all cells the same size, which doesn't allow for the extra space between the 2nd and 3rd buttons.
                // So keep using the grid bag layout.  This also allows us to easily make the buttons here the same
                //   size as those in the patterns area.
                {
                    addPatternButton = new JButton(getAddPatternAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(5, 5, 10, 5);
                    mainPanel.add(addPatternButton, constraints);
                    numRows++;
                   
                    editPatternButton = new JButton(getEditPatternAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(0, 5, 5, 5);
                    mainPanel.add(editPatternButton, constraints);
                    numRows++;
                   
                    removePatternButton = new JButton(getRemovePatternAction());
                    constraints.gridy = numRows;
                    constraints.insets = new Insets(0, 5, 5, 5);
                    mainPanel.add(removePatternButton, constraints);
                    numRows++;
                }
            }
            //
            // Configure the buttons.
            //
           
            // Edit and remove start out disabled.
            editPatternButton.setEnabled(false);
            removePatternButton.setEnabled(false);
           
            // When the list selection changes, change enabling of the edit and remove buttons.
            patternsJList.addListSelectionListener(new ListSelectionListener() {

                public void valueChanged(ListSelectionEvent e) {
                    boolean emptyPatternSelection = patternsJList.getSelectedPattern() == null;
                    editPatternButton.setEnabled(!emptyPatternSelection);
                    removePatternButton.setEnabled(!emptyPatternSelection);
                }
            });
        }
       
        // Scope Label.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.NORTHWEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.gridwidth = GridBagConstraints.REMAINDER;

           
            JLabel messageLabel = new JLabel(GeneratorMessages.getString("JFIMF_ScopeHeader"));

            JPanel messagePanel = new JPanel();
            messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.X_AXIS));
            messagePanel.add(messageLabel);
            messagePanel.add(Box.createHorizontalStrut(200));
            messagePanel.add(Box.createHorizontalGlue());
            mainPanel.add(messagePanel, constraints);
            numRows++;
        }
       
        // Scope selection
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.WEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.insets = new Insets(0, 15, 0, 0);

            scopeSelectorPanel = new ScopeSelectorPanel();
           
            mainPanel.add(scopeSelectorPanel, constraints);
            numRows++;
        }
       
        // Object optional methods Label.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.NORTHWEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;
            constraints.gridwidth = GridBagConstraints.REMAINDER;

            constraints.insets = new Insets(10, 0, 0, 0);
           
            JLabel messageLabel = new JLabel(GeneratorMessages.getString("JFIMF_OptionalObjectMethodsHeader"));

            JPanel messagePanel = new JPanel();
            messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.X_AXIS));
            messagePanel.add(messageLabel);
            messagePanel.add(Box.createHorizontalStrut(200));
            messagePanel.add(Box.createHorizontalGlue());
            mainPanel.add(messagePanel, constraints);
            numRows++;
        }
       
        // Check boxes for optional Object methods.
        {
            GridBagConstraints constraints = new GridBagConstraints();
            constraints.anchor = GridBagConstraints.WEST;
            constraints.fill = GridBagConstraints.HORIZONTAL;

            constraints.gridx = 0;
            constraints.gridy = numRows;

            constraints.insets = new Insets(0, 15, 0, 0);

            methodExcludeSelectorPanel = new MethodExcludeSelectorPanel();

            mainPanel.add(methodExcludeSelectorPanel, constraints);
            numRows++;
        }
       
        return mainPanel;
    }
   
    /**
     * @return the action to return in response to pressing the "Add Pattern..." button.
     */
    private Action getAddPatternAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_AddPattern");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = 8776068822378523687L;

            // Add an element.
            public void actionPerformed(ActionEvent e) {

                // Show the pattern dialog.
                AddEditPatternDialog addPatternDialog = new AddEditPatternDialog(JavaForeignImportModuleGenerator.this, null);
                boolean accepted = addPatternDialog.doModal();

                // Add the pattern if accepted.
                if (accepted) {
                    patternsJList.addPattern(addPatternDialog.getFitPattern());
                }
            }
        };
    }
   
    /**
     * Workaround for sun bug id 4711700
     * A bug in the native image loading code sometimes causes the Windows file chooser to throw a
     *   NullPointerException when instantiated in jdk 1.4.2.
     */
    private static void ensureJFileChooserLoadable() {

        if (UIManager.getLookAndFeel().getName().startsWith("Windows")) {
            JFileChooser fileChooser = null;
           
            while (fileChooser == null) {
                try {
                    fileChooser = new JFileChooser();
                } catch (NullPointerException e) {
                }
            }
        }
    }

    /**
     * Display the File chooser for selecting an import source.
     *
     * @param currentFile
     *            If non-null the file chooser will be specified as "Change"ing
     *            the given import. Otherwise, it will be set up as adding a new
     *            import file.
     * @param chooseDir
     *            if true, this the chooser is to select a directory. If false,
     *            it's so select a file.
     * @return the File selected by the file chooser, or null if the chooser was
     *         not approved (eg. canceled).
     */
    private File showSelectImportFileChooser(File currentFile, boolean chooseDir) {

        if (selectImportDialog == null) {
            selectImportDialog = new SelectImportDialog(JavaForeignImportModuleGenerator.this);
        }
        int result = selectImportDialog.showDialog(currentFile, chooseDir);
       
        // Return the result..
        if (result == JFileChooser.APPROVE_OPTION) {
            return selectImportDialog.getSelectedFile();
        }
       
        return null;
    }
   
    /**
     * @return the action to return in response to pressing the "Add Jar..." button.
     */
    private Action getAddImportJarAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_AddImportJar");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = -1327110975197857640L;

            public void actionPerformed(ActionEvent e) {
                File chosenFile = showSelectImportFileChooser(null, false);
                if (chosenFile != null) {
                    ImportSource importSource = new ImportSource(chosenFile, false);
                    importFromJList.addImport(importSource);
                }
            }
        };
    }
   
    /**
     * @return the action to return in response to pressing the "Add Folder..." button.
     */
    private Action getAddImportFolderAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_AddImportFolder");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = -7399609649158755721L;

            public void actionPerformed(ActionEvent e) {
                File chosenFile = showSelectImportFileChooser(null, true);
                if (chosenFile != null) {
                    ImportSource importSource = new ImportSource(chosenFile, true);
                    importFromJList.addImport(importSource);
                }
            }
        };
    }
   
    /**
     * @return the action to return in response to pressing the "Change..." button for imports.
     */
    private Action getChangeImportAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_ChangeImport");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = -2922337374842017884L;

            public void actionPerformed(ActionEvent e) {
                ImportSource selectedImportSource = (ImportSource)importFromJList.getSelectedValue();
               
                if (selectedImportSource != null) {
                    File chosenFile = showSelectImportFileChooser(selectedImportSource.getImportFile(), selectedImportSource.isDir());
                    if (chosenFile != null) {
                        ImportSource newImportSource = new ImportSource(chosenFile, selectedImportSource.isDir());
                        importFromJList.editImport(selectedImportSource, newImportSource);
                    }
                }
            }
        };
    }
   
    /**
     * @return the action to return in response to pressing the "Remove" button for imports.
     */
    private Action getRemoveImportAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_RemoveImport");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = -6469392988956528085L;

            public void actionPerformed(ActionEvent e) {
                importFromJList.removeSelectedImport();
            }
        };
    }
   
    /**
     * @return the action to return in response to pressing the "Edit..." button for patterns.
     */
    private Action getEditPatternAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_EditPattern");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = -527928622059171444L;

            // Edit selected element.
            public void actionPerformed(ActionEvent e) {
                JFit.Pattern selectedPattern = patternsJList.getSelectedPattern();
               
                // Show the pattern dialog.
                AddEditPatternDialog editPatternDialog = new AddEditPatternDialog(JavaForeignImportModuleGenerator.this, selectedPattern);
                boolean accepted = editPatternDialog.doModal();

                // Edit the pattern if accepted.
                if (accepted) {
                    patternsJList.editPattern(selectedPattern, editPatternDialog.getFitPattern());
                }
            }
        };
    }
   
    /**
     * @return the action to return in response to pressing the "Remove" button for patterns.
     */
    private Action getRemovePatternAction() {
        String buttonText = GeneratorMessages.getString("JFIMF_RemovePattern");
        return new AbstractAction(buttonText) {
           
            private static final long serialVersionUID = -1965662784577019107L;

            public void actionPerformed(ActionEvent e) {
                // Remove the selected pattern.
                patternsJList.removeSelectedPattern();
            }
        };
    }
   
    /**
     * Add default imports to the Import From area.
     */
    private void addDefaultImports() {

        // Add the runtime jar if it exists.
        // (java.home)/lib/rt.jar
        File javaRuntimeJar = new File(JAVA_HOME, "lib" + System.getProperty("file.separator") + "rt.jar");
       
        if (FileSystemHelper.fileExists(javaRuntimeJar)) {
            ImportSource importSource = new ImportSource(javaRuntimeJar, false);
            importFromJList.addImport(importSource);
        }
    }

    /**
     * Updates the state of the Ok button to only be enabled if the user has entered
     * all required information. Also updates the information message displayed.
     */
    private void updateState() {

        // Make sure that you check for errors first, then for warnings.
        // Be careful about the order of checks, more important checks come first.
       
        /*
         * Errors.
         */
       
        // Check for a valid module name.
        String moduleNameString = moduleNameField.getText();
        if (moduleNameString.length() == 0) {
           
            statusLabel.setText(GeneratorMessages.getString("JFIMF_NoModuleName"));
            statusLabel.setIcon(ERROR_ICON);
            okButton.setEnabled(false);
            return;
        }
        ModuleName moduleName = ModuleName.maybeMake(moduleNameString);
        if (moduleName == null) {
           
            statusLabel.setText(GeneratorMessages.getString("JFIMF_InvalidModuleName"));
            statusLabel.setIcon(ERROR_ICON);
            okButton.setEnabled(false);
            return;
        }
       
        // Check for a location to import from.
        if (importFromJList.getModel().getSize() < 1) {
           
            String message = GeneratorMessages.getString("JFIMF_NoImportFrom");
           
            statusLabel.setText(message);
            statusLabel.setToolTipText(message);
            statusLabel.setIcon(ERROR_ICON);
            okButton.setEnabled(false);
            return;
        }
       
        // Check that the patterns pane is non-empty.
        if (patternsJList.isEmpty()) {
           
            String message = GeneratorMessages.getString("JFIMF_NoPatternsMessage");
           
            statusLabel.setText(message);
            statusLabel.setToolTipText(message);
            statusLabel.setIcon(ERROR_ICON);
            okButton.setEnabled(false);
            return;
        }
       
        // If here, no errors.  Warnings at worst.
        okButton.setEnabled(true);
       
        /*
         * Warnings.
         */
       
        // Check whether the module name exists.
        // This goes to the workspace source manager -- so it's a bit hacky.
        // We can't just ask the workspace if it has the module though, since it might be the case where the workspace isn't
        //   using a module in the nullary case.
        if (perspective.getWorkspace().getSourceManager(moduleName).getResourceStore().hasFeature(
                new ResourceName(CALFeatureName.getModuleFeatureName(moduleName)))) {
           
            String message = GeneratorMessages.getString("JFIMF_ModuleExists");
           
            statusLabel.setText(message);
            statusLabel.setToolTipText(message);
            statusLabel.setIcon(WARNING_ICON);
            return;
        }
       
        // everything is fine.
        String message = GeneratorMessages.getString("JFIMF_OkGenerateModule");
        statusLabel.setText(message);
        statusLabel.setToolTipText(message);
        statusLabel.setIcon(OK_ICON);
    }   
   
}
TOP

Related Classes of org.openquark.gems.client.generators.JavaForeignImportModuleGenerator$ScopeSelectorPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.