alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.core.ui;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.Collator;
import java.util.*;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.event.*;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.KeyStroke;
import javax.swing.AbstractAction;

import org.openide.ErrorManager;
import org.openide.actions.*;
import org.openide.filesystems.*;
import org.openide.loaders.*;
import org.openide.nodes.*;
import org.openide.options.*;
import org.openide.util.*;
import org.openide.util.actions.*;
import org.openide.util.datatransfer.*;

import org.netbeans.core.IDESettings;
import org.openide.windows.WindowManager;

/** Node representing modules.
 * @author Jesse Glick, Jaroslav Tulach, Rostislav Levy (?), et al.
 */
public class ModuleNode extends AbstractNode {
    
    private static final ResourceBundle bundle = NbBundle.getBundle( ModuleNode.class );

    /** Icon bases */
    private static final String MODULE_ITEM_ICON_BASE = "org/netbeans/core/resources/moduleItem"; // NOI18N
    private static final String MODULE_ITEM_DISABLED_BASE = "org/netbeans/core/resources/moduleItemDisabled"; // NOI18N
    private static final String MODULE_ITEM_ERROR_BASE = "org/netbeans/core/resources/moduleItemError"; // NOI18N
    private static final String MODULE_TEST_ITEM_ICON_BASE = "org/netbeans/core/resources/testModuleItem"; // NOI18N
    private static final String MODULES_ICON_BASE = "org/netbeans/core/resources/modules"; // NOI18N

    /** Last directory used by the install new module file chooser. */
    private static File lastChosenDir = null;


    /** New types */
    private static NewType[] newTypes = null;

    /** The actual data. */
    private static ModuleBean.AllModulesBean allModules = ModuleBean.AllModulesBean.getDefault();
    
    /** Creates a new ModulesNode */
    public ModuleNode() {
        this(false);
    }
    
    private boolean simple = false;
    public ModuleNode(boolean simple) {
        // #14553: try to keep code name consistent for node path compatibility
        super(new Modules (simple));
        setName("Modules"); // NOI18N
        setDisplayName(bundle.getString("CTL_Modules_name"));
        setShortDescription (bundle.getString ("CTL_Modules_hint"));
        setIconBase (MODULES_ICON_BASE);
        this.simple = simple;
    }

    public HelpCtx getHelpCtx () {
        return new HelpCtx (ModuleNode.class);
    }

    public Node cloneNode () {
        return new ModuleNode ();
    }

    protected SystemAction[] createActions () {

        return new SystemAction[] {
                   SystemAction.get (NewAction.class),
                   null,
                   SystemAction.get (ToolsAction.class),
                   SystemAction.get (PropertiesAction.class),
               };

    }

    /** Add a sorting property. */
    protected Sheet createSheet () {
        Sheet.Set set = new Sheet.Set ();
        set.setName ("sorting"); // NOI18N
        set.setDisplayName (bundle.getString ("LBL_ModuleNode_sheet_sorting"));
        set.put (((Modules) getChildren ()).createSortingProperty ());
        Sheet sheet = new Sheet ();
        sheet.put (set);
        return sheet;
    }

    public NewType[] getNewTypes () {

        if ( newTypes == null ) {
            int size = Boolean.getBoolean ("netbeans.module.test") ? 2 : 1;
            
            Lookup lkp = Lookup.getDefault();
            // XXX use Looks in the future instead of this hack
            Lookup.Result result = lkp.lookup( new Lookup.Template( org.netbeans.core.ModuleNode.ModuleNewType.class ) );
            
            newTypes = new NewType[size + result.allInstances().size()];
            newTypes[0] = new NewType () {
                          public String getName () {
                              return bundle.getString ("CTL_NewModuleByFile");
                          }

                          public void create () throws IOException {
                              addFile (false);
                          }
                      };            
            if ( Boolean.getBoolean ("netbeans.module.test")) { // NOI18N
                 newTypes[1] = new NewType () {
                              public String getName () {
                                  return bundle.getString( "CTL_NewTestModule");
                              }

                              public void create () throws IOException {
                                  addFile (true);
                              }
                          };            
            }
                                      
            Iterator instances = result.allInstances().iterator();
            while (instances.hasNext()) {
                newTypes[size] = (NewType) instances.next();
                size++;
            }             

        }

        return newTypes;


    }

    /** Allows to add new module by specifying its file.
    */
    void addFile (boolean reloadable) /*throws IOException*/ {
        // XXX should use File property editor, not JFileChooser directly
        final JFileChooser chooser = new JFileChooser ();
        chooser.setFileHidingEnabled(false);
        
        // XXX #18270. Enter doesn't work when expecting folder change,
        // Accessibility problem. We hack default behaviour here.
        
        // Only jdk1.3 there is not the action in action map, i.e. also no 
        // key binding. When running on jdk1.4 only remove this part
        // dealing with setting the key binding.
        InputMap im = chooser.getInputMap(
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        if(im != null) {
            KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);

            Object value = im.get(enter);
            if(value == null) {
                im.put(enter, "approveSelection"); // NOI18N
            }
        }

        // Add(jdk1.3) or replace(jdk1.4) to parent (UI) map the new action
        // doing the folder change.
        ActionMap map = chooser.getActionMap();
        if(map != null) {
            // Get parent map, which is map set by FileChooserUI,
            // containing the default approveSelection action.
            ActionMap parent = map.getParent();

            if(parent != null) {

                // Get original action from parent map, set by UI.
                final Action original = parent.get("approveSelection"); // NOI18N

                // Replace it by our action which adds the folder change,
                // if selected is a directory.
                parent.put("approveSelection", new AbstractAction() { // NOI18N
                    public void actionPerformed(ActionEvent evt) {
                        File file = chooser.getSelectedFile();

                        if(file != null && file.isDirectory()) {
                            try {
                                // Strip trailing ".."
                                file = file.getCanonicalFile();
                            } catch (java.io.IOException ioe) {
                                // Ok, use f as is
                            }

                            chooser.setCurrentDirectory(file);
                        } else {
                            if(original != null) {
                                original.actionPerformed(evt);
                            }
                        }
                    }
                });
            }
        } // End of hacking.
        
        if (lastChosenDir != null) chooser.setCurrentDirectory (lastChosenDir);
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setApproveButtonText (bundle.getString ("CTL_ModuleSelect"));
        chooser.setApproveButtonToolTipText (bundle.getString ("CTL_ModuleSelectToolTip"));
        chooser.setFileFilter (new javax.swing.filechooser.FileFilter () {
            public String getDescription () {
                return bundle.getString ("CTL_ModuleSelectFilter");
            }
            public boolean accept (File f) {
                return f.isDirectory () || f.getName ().endsWith (".jar"); // NOI18N
            }
        });

        int result = chooser.showOpenDialog (WindowManager.getDefault ().getMainWindow ());
        lastChosenDir = chooser.getCurrentDirectory ();
        if (result == JFileChooser.APPROVE_OPTION) {
            // install the file
            File jar = chooser.getSelectedFile();
            allModules.create(jar, reloadable);
        }

    }

    /** Class representing node of one standard module
     */
    static class Item extends AbstractNode implements PropertyChangeListener {

        private ModuleBean item;
        /** true if usedBy prop has been displayed, which can affect all else */
        private boolean listeningToAllModules = false;
        private boolean simple = false;
        
        public Item (ModuleBean item) {
            super (Children.LEAF);
            this.item = item;

            setName (item.getCodeNameBase());
            setDefaultAction (SystemAction.get (PropertiesAction.class));
            item.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(this, item));
            updateDisplayStuff();
            getCookieSet().add(new InstanceSupport.Instance(item));
            // Make sure that settings UI can deal with the Modules/*.xml file correctly.
            String filename = "Modules/" + item.getCodeNameBase().replace('.', '-') + ".xml"; // NOI18N
            FileObject xml = Repository.getDefault().getDefaultFileSystem().findResource(filename);
            if (xml != null) {
                try {
                    getCookieSet().add(DataObject.find(xml));
                } catch (DataObjectNotFoundException donfe) {
                    ErrorManager.getDefault().notify(ErrorManager.WARNING, donfe);
                }
            } else {
                if (item.getJar() != null) {
                    ErrorManager.getDefault().log(ErrorManager.WARNING, "WARNING - ModuleNode.Item could not find " + filename);
                }
                // else not a problem - fixed module, no storage expected
            }
        }
        
        public Item (ModuleBean item, boolean simple) {
            this(item);
            this.simple = simple;
        }
        
        private void updateDisplayStuff() {
            setDisplayName (item.getDisplayName());
            setShortDescription(item.getShortDescription());
            setIconBase (item.isEnabled () ? (item.isReloadable () ? MODULE_TEST_ITEM_ICON_BASE : MODULE_ITEM_ICON_BASE) : (item.isProblematic() ? MODULE_ITEM_ERROR_BASE : MODULE_ITEM_DISABLED_BASE));
        }

        public void propertyChange(PropertyChangeEvent evt) {
            // Some aspects of the module may have changed. Redisplay everything.
            updateDisplayStuff();
            firePropertyChange(null, null, null);
        }
        
        public HelpCtx getHelpCtx () {
            return new HelpCtx (Item.class);
        }

        protected SystemAction[] createActions () {
            return new SystemAction[] {
                SystemAction.get (DeleteAction.class),
                // XXX reload action too...
                null,
                SystemAction.get (ToolsAction.class),
                SystemAction.get (PropertiesAction.class),
            };
        }

        public void destroy () {
            item.delete();
        }

        public boolean canDestroy () {
            return item.getJar() != null;
        }

        /** Creates properties.
        */
        protected Sheet createSheet () {
            Sheet s = Sheet.createDefault ();
            Sheet.Set ss = s.get (Sheet.PROPERTIES);

            Sheet.Set sse = Sheet.createExpertSet ();
            s.put(sse);
            
            try {
                Node.Property p;
                if (!simple) {
                    p = new PropertySupport.Reflection(item, String.class, "getDisplayName", null); // NOI18N
                    p.setName("displayName"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_name"));
                    p.setShortDescription(bundle.getString ("HINT_modules_name"));
                    ss.put(p);
                }
                p = new PropertySupport.Reflection(item, String.class, "getSpecificationVersion", null); // NOI18N
                p.setValue("suppressCustomEditor",Boolean.TRUE);
                p.setName("specificationVersion"); // NOI18N
                p.setDisplayName(bundle.getString ("PROP_modules_specversion"));
                p.setShortDescription(bundle.getString ("HINT_modules_specversion"));
                ss.put(p);
                if (!simple) {
                    p = new PropertySupport.Reflection(item, String.class, "getImplementationVersion", null); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setName("implementationVersion"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_implversion"));
                    p.setShortDescription(bundle.getString ("HINT_modules_implversion"));
                    sse.put(p);
                    p = new PropertySupport.Reflection(item, String.class, "getBuildVersion", null); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setName("buildVersion"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_buildversion"));
                    p.setShortDescription(bundle.getString ("HINT_modules_buildversion"));
                    sse.put(p);
                    p = new PropertySupport.Reflection(item, String.class, "getShortDescription", null); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setName("shortDescription"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_shortDescription"));
                    p.setShortDescription(bundle.getString ("HINT_modules_shortDescription"));
                    ss.put(p);
                    p = new PropertySupport.Reflection(item, String.class, "getLongDescription", null); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setName("longDescription"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_longDescription"));
                    p.setShortDescription(bundle.getString ("HINT_modules_longDescription"));
                    ss.put(p);
                    p = new PropertySupport.Reflection(item, String.class, "getCategory", null); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setName("category"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_category"));
                    p.setShortDescription(bundle.getString ("HINT_modules_category"));
                    sse.put(p);
                }
                class EnabledOrReloadableProp extends PropertySupport.Reflection {
                    public EnabledOrReloadableProp(String getter, String setter) throws NoSuchMethodException {
                        super(item, Boolean.TYPE, getter, setter);
                    }
                    public boolean canWrite() {
                        if (! super.canWrite()) return false; // not really necessary
                        if (this.getName().equals("enabled")) { // NOI18N
                            return /*! item.isFixed()*/ item.getJar() != null && !item.isProblematic() && !item.isAutoload() && !item.isEager();
                        } else if (this.getName().equals("reloadable")) { // NOI18N
                            // Need to be able to write to the containing directory to use this feature.
                            return item.getJar() != null &&
                            (item.isReloadable() || item.getJar().getParentFile().canWrite());
                        } else {
                            throw new IllegalStateException();
                        }
                    }
                }
                p = new EnabledOrReloadableProp("isEnabled", "setEnabled"); // NOI18N
                p.setName("enabled"); // NOI18N
                p.setDisplayName(bundle.getString("PROP_modules_enabled"));
                p.setShortDescription(bundle.getString("HINT_modules_enabled"));
                ss.put(p);
                if (!simple) {
                    p = new EnabledOrReloadableProp("isReloadable", "setReloadable"); // NOI18N
                    p.setName("reloadable"); // NOI18N
                    p.setDisplayName(bundle.getString("PROP_modules_reloadable"));
                    p.setShortDescription(bundle.getString("HINT_modules_reloadable"));
                    sse.put(p);
                    p = new PropertySupport.Reflection(item, String.class, "getCodeName", null); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setName("codeName"); // NOI18N
                    p.setDisplayName(bundle.getString ("PROP_modules_codename"));
                    p.setShortDescription(bundle.getString ("HINT_modules_codename"));
                    sse.put(p);
                    if (item.getJar() != null) {
                        p = new PropertySupport.Reflection(item, File.class, "getJar", null); // NOI18N
                        p.setName("jar"); // NOI18N
                        p.setDisplayName(bundle.getString ("PROP_modules_jar"));
                        p.setShortDescription(bundle.getString ("HINT_modules_jar"));
                        sse.put(p);
                    }
                    class ClasspathProperty extends PropertySupport.ReadOnly {
                        // See #22466
                        public ClasspathProperty() {
                            super("classpath", getNbClassPathOrStringClass(), // NOI18N
                                  bundle.getString("PROP_modules_classpath"),
                                  bundle.getString("HINT_modules_classpath"));
                        }
                        public Object getValue() throws InvocationTargetException {
                            String cp = item.getEffectiveClasspath();
                            if (getValueType() == String.class) {
                                return cp;
                            } else {
                                try {
                                    Constructor c = getValueType().getConstructor(new Class[] {String.class});
                                    return c.newInstance(new Object[] {cp});
                                } catch (Exception e) {
                                    throw new InvocationTargetException(e);
                                }
                            }
                        }
                        public Object getValue(String key) {
                            if ("suppressCustomEditor".equals(key)) {
                                return Boolean.TRUE;
                            } else {
                                return super.getValue(key);
                            }
                        }
                    }
                    sse.put(new ClasspathProperty());
                    // Though normally in a separate category, still potentially
                    // useful to leave here (e.g. if sorting differently):
                    p = new PropertySupport.Reflection(item, Boolean.TYPE, "isAutoload", null); // NOI18N
                    p.setName("autoload"); // NOI18N
                    p.setDisplayName(bundle.getString("PROP_modules_autoload"));
                    p.setShortDescription(bundle.getString("HINT_modules_autoload"));
                    sse.put(p);
                    p = new PropertySupport.Reflection(item, Boolean.TYPE, "isEager", null); // NOI18N
                    p.setName("eager"); // NOI18N
                    p.setDisplayName(bundle.getString("PROP_modules_eager"));
                    p.setShortDescription(bundle.getString("HINT_modules_eager"));
                    sse.put(p);
                    p = new PropertySupport.Reflection(item, String[].class, "getProvides", null); // NOI18N
                    p.setName("provides"); // NOI18N
                    p.setValue("suppressCustomEditor",Boolean.TRUE);
                    p.setDisplayName(bundle.getString("PROP_modules_provides"));
                    p.setShortDescription(bundle.getString("HINT_modules_provides"));
                    sse.put(p);
                    // #16636:
                    p = new PropertySupport.Reflection(item, String[].class, "getProblemDescriptions", null); // NOI18N
                    p.setName("problemDescriptions"); // NOI18N
                    p.setDisplayName(bundle.getString("PROP_modules_problemDescriptions"));
                    p.setShortDescription(bundle.getString("HINT_modules_problemDescriptions"));
                    sse.put(p);
                }
            } catch (NoSuchMethodException nsme) {
                ErrorManager.getDefault().notify(nsme);
            }
            sse.put(new UsedByProp());

            return s;
        }

        private static Class getNbClassPathOrStringClass() {
            ClassLoader l = (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class);
            try {
                return l.loadClass("org.openide.execution.NbClassPath"); // NOI18N
            } catch (ClassNotFoundException cnfe) {
                return String.class;
            }
        }

        /** For enabled modules, shows other modules which are currently
         * using it, i.e. depending on it to stay enabled.
         * @see #22504
         */
        private final class UsedByProp extends PropertySupport.ReadOnly implements ModuleBean.AllModulesBean.RelationCallback, PropertyChangeListener {
            private String[] value = null;
            public UsedByProp() {
                super("usedBy", String[].class, // NOI18N
                      bundle.getString("PROP_modules_usedby"),
                      bundle.getString("HINT_modules_usedby"));
            }
            public Object getValue() {
                if (value != null) {
                    return value;
                } else {
                    ModuleBean.AllModulesBean amb = ModuleBean.AllModulesBean.getDefault();
                    amb.getRelations(item, ModuleBean.AllModulesBean.RELATION_TRANSITIVELY_NEEDED_BY, this);
                    // All sorts of changes can now affect this!
                    if (!listeningToAllModules) {
                        listeningToAllModules = true;
                        amb.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(this, amb));
                        ModuleBean[] mods = amb.getModules();
                        for (int i = 0; i < mods.length; i++) {
                            if (mods[i] != item) {
                                mods[i].addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(this, mods[i]));
                            }
                        }
                    }
                    return new String[] {bundle.getString("LBL_please_wait_modules_usedby")};
                }
            }
            public void result(Set modules) {
                List l = new ArrayList(Math.max(modules.size(), 1)); // List
                // Only display enabled users, and only display anything if this is enabled:
                if (item.isEnabled()) {
                    Iterator it = modules.iterator();
                    while (it.hasNext()) {
                        ModuleBean mb = (ModuleBean)it.next();
                        if (mb.isEnabled()) {
                            l.add(mb.getDisplayName());
                        }
                    }
                    Collections.sort(l, Collator.getInstance());
                }
                String[] old = value;
                value = (String[])l.toArray(new String[l.size()]);
                Item.this.firePropertyChange("usedBy", old, value); // NOI18N
            }
            public void propertyChange(PropertyChangeEvent ev) {
                value = null;
                Item.this.firePropertyChange("usedBy", null, null); // NOI18N
            }
        }
            
    }
    
    /** Children that contains modules installed it has to
     * dissingushg between modules and test modules.
     * Keys are of type ModuleBean, LIBRARY_KEY, BRIDGE_KEY, or String category name.
     */
    private static class Modules extends Children.Keys implements PropertyChangeListener {
        
        /** Key for fixed/autoload modules, rather than a category per se. */
        private static final Object LIBRARY_KEY = new Object();
        /** Key for eager modules. */
        private static final Object BRIDGE_KEY = new Object();

        private IDESettings settings;
        private boolean simple = false;
        
        public Modules() {}
        public Modules(boolean simple) {
            this.simple = simple;
        }

        /** Refreshed list of nodes acc. to current sorting and contents. */
        private void refreshKeys() {
            if (settings == null) {
                addNotify();
            }
            ModuleBean[] items = allModules.getModules();
            if (settings.getModulesSortMode() == IDESettings.MODULES_SORT_CATEGORY) {
                final Comparator collator = Collator.getInstance();
                class CategoryComparator implements Comparator {
                    public int compare(Object o1, Object o2) {
                        // Libraries always put in the last place.
                        if (o1 == LIBRARY_KEY) {
                            if (o2 == LIBRARY_KEY) {
                                return 0;
                            } else {
                                return 1;
                            }
                        } else {
                            if (o2 == LIBRARY_KEY) {
                                return -1;
                            } else {
                                // Eager modules come between categories and libraries.
                                if (o1 == BRIDGE_KEY) {
                                    if (o2 == BRIDGE_KEY) {
                                        return 0;
                                    } else {
                                        return 1;
                                    }
                                } else if (o2 == BRIDGE_KEY) {
                                    return -1;
                                }
                                // #13078: sort modules and categories inline.
                                String name1;
                                if (o1 instanceof ModuleBean) {
                                    name1 = ((ModuleBean)o1).getDisplayName();
                                } else {
                                    name1 = (String)o1;
                                }
                                String name2;
                                if (o2 instanceof ModuleBean) {
                                    name2 = ((ModuleBean)o2).getDisplayName();
                                } else {
                                    name2 = (String)o2;
                                }
                                return collator.compare(name1, name2);
                            }
                        }
                    }
                }
                SortedSet categories = new TreeSet(new CategoryComparator());
                //ErrorManager.getDefault().getInstance("org.netbeans.core.ui.ModuleNode").log("children Modules.refreshKeys: got " + items.length + " modules");
                for (int i = 0; i < items.length; i++) {
                    if (items[i].getJar() == null || items[i].isAutoload()) {
                        categories.add(LIBRARY_KEY);
                    } else if (items[i].isEager()) {
                        categories.add(BRIDGE_KEY);
                    } else {
                        String category = items[i].getCategory();
                        if (category != null) {
                            categories.add(category);
                        } else {
                            categories.add(items[i]);
                        }
                    }
                }
                setKeys(categories);
            } else if (settings.getModulesSortMode() != IDESettings.MODULES_SORT_UNSORTED) {
                if (settings.getModulesSortMode() == IDESettings.MODULES_SORT_ENABLED) {
                    // Listen for changes in enabled status and resort.
                    for (int i = 0; i < items.length; i++) {
                        items[i].addPropertyChangeListener(this);
                    }
                }
                List itemsL = new ArrayList(Arrays.asList(items));
                Collections.sort(itemsL, new Comparator() {
                    public int compare(Object o1, Object o2) {
                        ModuleBean m1 = (ModuleBean)o1;
                        ModuleBean m2 = (ModuleBean)o2;
                        switch (settings.getModulesSortMode()) {
                            case IDESettings.MODULES_SORT_CODENAME:
                                return m1.getCodeName().compareTo(m2.getCodeName());
                            case IDESettings.MODULES_SORT_ENABLED:
                                // Order:
                                // 0. Reloadable enabled regular modules.
                                // 1. Reloadable disabled regular modules.
                                // 2. Reloadable enabled fixed/autoload/eager modules.
                                // 3. Reloadable disabled fixed/autoload/eager modules.
                                // 4. Enabled regular modules.
                                // 5. Disabled regular modules.
                                // 6. Enabled fixed/autoload/eager modules.
                                // 7. Disabled fixed/autoload/eager modules.
                                int k1 = (m1.isReloadable() ? 0 : 4) +
                                         ((m1.isAutoload() || m1.isEager() || m1.getJar() == null) ? 2 : 0) +
                                         (m1.isEnabled() ? 0 : 1);
                                int k2 = (m2.isReloadable() ? 0 : 4) +
                                         ((m2.isAutoload() || m2.isEager() || m2.getJar() == null) ? 2 : 0) +
                                         (m2.isEnabled() ? 0 : 1);
                                if (k1 != k2) return k1 - k2;
                                // fallthrough
                            case IDESettings.MODULES_SORT_DISPLAYNAME:
                                return Collator.getInstance().compare(m1.getDisplayName(), m2.getDisplayName());
                            case IDESettings.MODULES_SORT_URL:
                                File j1 = m1.getJar();
                                File j2 = m2.getJar();
                                if (j1 != null) {
                                    if (j2 != null) {
                                        return j1.compareTo(j2);
                                    } else {
                                        return 1;
                                    }
                                } else {
                                    if (j2 != null) {
                                        return -1;
                                    } else {
                                        return 0;
                                    }
                                }
                            default:
                                return 0;
                        }
                    }
                });
                setKeys(itemsL);
            } else {
                setKeys(items);
            }
        }

        Node.Property createSortingProperty () {
            settings = (IDESettings) SharedClassObject.findObject (IDESettings.class, true);
            return new PropertySupport.ReadWrite ("sorted", Integer.TYPE, // NOI18N
                                                  bundle.getString ("PROP_ModuleNode_sorted"),
                                                  bundle.getString ("HINT_ModuleNode_sorted")) {
                public Object getValue () {
                    return new Integer (settings.getModulesSortMode ());
                }
                public void setValue (Object o) {
                    settings.setModulesSortMode (((Integer) o).intValue ());
                }
                public boolean supportsDefaultValue () {
                    return true;
                }
                public void restoreDefaultValue () {
                    setValue (new Integer (IDESettings.MODULES_SORT_CATEGORY));
                }
                public PropertyEditor getPropertyEditor () {
                    return new SortingModeEditor();
                }
            };
        }
        
        private static final class SortingModeEditor extends PropertyEditorSupport {
            private final String[] tags = new String[] {
                bundle.getString ("LBL_ModuleNode_SORT_UNSORTED"),
                bundle.getString ("LBL_ModuleNode_SORT_DISPLAYNAME"),
                bundle.getString ("LBL_ModuleNode_SORT_CODENAME"),
                bundle.getString ("LBL_ModuleNode_SORT_ENABLED"),
                bundle.getString ("LBL_ModuleNode_SORT_URL"),
                bundle.getString ("LBL_ModuleNode_SORT_CATEGORY"),
            };
            public SortingModeEditor() {}
            public String[] getTags () {
                return tags;
            }
            public String getAsText () {
                return tags[((Integer) this.getValue ()).intValue ()];
            }
            public void setAsText (String text) {
                for (int i = 0; i < tags.length; i++) {
                    if (tags[i].equals (text)) {
                        this.setValue (new Integer (i));
                        return;
                    }
                }
                throw new IllegalArgumentException ();
            }
        }

        /** Initializes content */
        public void addNotify () {
            settings = (IDESettings) SharedClassObject.findObject (IDESettings.class, true);
            allModules.addPropertyChangeListener (this);
            settings.addPropertyChangeListener (this);
            refreshKeys ();
        }

        /** Releases listener. */
        public void removeNotify () {
            settings.removePropertyChangeListener (this);
            allModules.removePropertyChangeListener (this);
            ModuleBean[] items = allModules.getModules();
            for (int i = 0; i < items.length; i++) {
                items[i].removePropertyChangeListener(this);
            }
        }
        
        /** Make sure hierarchy lookups get the proper module list first. */
        public Node findChild(String name) {
            allModules.waitForModules().waitFinished();
            refreshKeys();
            return super.findChild(name);
        }

        /** Reacts to changes */
        public void propertyChange (PropertyChangeEvent ev) {
            //ErrorManager.getDefault().getInstance("org.netbeans.core.ui.ModuleNode").log("children Modules.propertyChange: " + ev.getPropertyName());
            // From IDESettings or AllModulesBean or ModuleBean:
            refreshKeys ();
        }

        /** Generates node for the ModuleBean key */
        protected Node[] createNodes (Object key) {
            if (key == LIBRARY_KEY) {
                return new Node[] {new CategoryNode(false)};
            } else if (key == BRIDGE_KEY) {
                return new Node[] {new CategoryNode(true)};
            } else if (key instanceof String) {
                return new Node[] { new CategoryNode ((String) key) };
            } else {
                return new Node[] { new Item ((ModuleBean)key, simple) };
            }
        }
    }

    private static final class CategoryNode extends AbstractNode {
        
        private final boolean libraries;
        private final boolean bridges;
        
        public CategoryNode(boolean bridgeNotLib) {
            this (bridgeNotLib, false);
        }
        
        private CategoryNode (boolean bridgeNotLib, boolean simple) {
            super(new CategoryChildren(bridgeNotLib, simple));
            setName(bridgeNotLib ? "bridges" : "libraries"); // NOI18N
            setDisplayName(bundle.getString(bridgeNotLib ? "LBL_ModuleNode_bridges" : "LBL_ModuleNode_libraries"));
            setIconBase (MODULES_ICON_BASE);
            libraries = !bridgeNotLib;
            bridges = bridgeNotLib;
        }

        public CategoryNode (String category) {
            this(category, false);
        }
        
        private CategoryNode (String category, boolean simple) {
            super (new CategoryChildren (category, simple));
            setName (category); // displayName should be the same
            setIconBase (MODULES_ICON_BASE);
            libraries = false;
            bridges = false;
        }

        public boolean canDestroy () {
            return false;
        }

        public boolean canRename () {
            return false;
        }

        public boolean canCut () {
            return false;
        }
        
        public HelpCtx getHelpCtx () {
            return new HelpCtx (CategoryNode.class);
        }

        /** Creates property.
        */
        protected Sheet createSheet () {
            Sheet s = Sheet.createDefault ();
            if (libraries || bridges) {
                // Do not want the enabled prop here.
                return s;
            }
            Sheet.Set ss = s.get (Sheet.PROPERTIES);
            
            class EnabledProp extends PropertySupport.ReadWrite implements PropertyChangeListener {
                /** modules in this category */
                private Set modules = new HashSet(); // Set
                private final String category;
                public EnabledProp(String category) {
                    super("enabled", Boolean.TYPE, // NOI18N
                          bundle.getString ("PROP_modules_enabled"),
                          bundle.getString ("HINT_modules_enabled"));
                    this.category = category;
                    calculateModules();
                    allModules.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(this, allModules));
                }
                public Object getValue() {
                    Boolean val = null;
                    Iterator it = modules.iterator();
                    while (it.hasNext()) {
                        ModuleBean m = (ModuleBean)it.next();
                        if (m.isEnabled()) {
                            if (val == null) {
                                val = Boolean.TRUE;
                            } else if (! val.booleanValue()) {
                                // Mixed results.
                                return null;
                            }
                        } else {
                            if (val == null) {
                                val = Boolean.FALSE;
                            } else if (val.booleanValue()) {
                                // Mixed results.
                                return null;
                            }
                        }
                    }
                    return val;
                }
                public void setValue(Object val) {
                    boolean e = ((Boolean)val).booleanValue();
                    Iterator it = modules.iterator();
                    while (it.hasNext()) {
                        ModuleBean m = (ModuleBean)it.next();
                        m.setEnabled(e);
                    }
                }
                public boolean canWrite() {
                    Iterator it = modules.iterator();
                    while (it.hasNext()) {
                        ModuleBean m = (ModuleBean)it.next();
                        if (m.isAutoload() || m.getJar() == null || m.isEager()) throw new IllegalStateException();
                        if (m.isProblematic()) {
                            return false;
                        }
                    }
                    return true;
                }
                private void calculateModules() {
                    Set modules2 = new HashSet(); // Set
                    ModuleBean[] testing = allModules.getModules();
                    for (int i = 0; i < testing.length; i++) {
                        if (testing[i].getJar() != null && !testing[i].isAutoload() && !testing[i].isEager() &&
                                category.equals(testing[i].getCategory())) {
                            modules2.add(testing[i]);
                            if (! modules.contains(testing[i])) {
                                testing[i].addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(this, testing[i]));
                            }
                        }
                    }
                    modules = modules2;
                }
                public void propertyChange(PropertyChangeEvent evt) {
                    // Something changed--list of modules, enabled status of some, etc.
                    CategoryNode.this.firePropertyChange("enabled", null, null); // NOI18N
                    calculateModules();
                }
                private PropertyEditor editor=null;
                public PropertyEditor getPropertyEditor() {
                    //issue 38019, cache the property editor for TTV performance
                    if (editor == null) {
                        editor = super.getPropertyEditor();
                    }
                    return editor;
                }
            }
            
            ss.put(new EnabledProp(getName()));
            return s;
        }

        private static final class CategoryChildren extends Children.Keys implements PropertyChangeListener {

            private final String category;
            private final boolean bridgeNotLib;
            private boolean simple = false;
            /** Libraries pseudo-category. */
            public CategoryChildren(boolean bridgeNotLib) {
                this(bridgeNotLib, false);
            }

            public CategoryChildren (String category) {
                this(category, false);
            }
            
            public CategoryChildren(String category, boolean simple) {
                this.simple = simple;
                this.category = category;
                bridgeNotLib = false; // arbitrary
            }
            
            public CategoryChildren (boolean bridgeNotLib, boolean simple) {
                this.simple = simple;
                category = null;
                this.bridgeNotLib = bridgeNotLib;
            }

            protected void addNotify () {
                refreshKeys ();
                allModules.addPropertyChangeListener (this);
            }

            protected void removeNotify () {
                allModules.removePropertyChangeListener (this);
                setKeys (Collections.EMPTY_SET);
            }

            /** Make sure hierarchy lookups get the proper module list first. */
            public Node findChild(String name) {
                allModules.waitForModules().waitFinished();
                refreshKeys();
                return super.findChild(name);
            }

            private void refreshKeys () {
                List keys = new ArrayList ();
                ModuleBean[] modules = allModules.getModules();
                for (int i = 0; i < modules.length; i++) {
                    boolean lib = modules[i].getJar() == null || modules[i].isAutoload();
                    boolean bridge = modules[i].isEager();
                    if (category != null && !lib && !bridge && category.equals (modules[i].getCategory())) {
                        keys.add (modules[i]);
                    } else if (category == null && !bridgeNotLib && lib) {
                        keys.add(modules[i]);
                    } else if (category == null && bridgeNotLib && bridge) {
                        keys.add(modules[i]);
                    }
                }
                final Comparator collator = Collator.getInstance();
                Collections.sort (keys, new Comparator () {
                        public int compare (Object o1, Object o2) {
                            ModuleBean m1 = (ModuleBean) o1;
                            ModuleBean m2 = (ModuleBean) o2;
                            return collator.compare(m1.getDisplayName(), m2.getDisplayName());
                        }
                    });
                setKeys (keys);
            }

            protected Node[] createNodes (Object key) {
                return new Node[] { new Item ((ModuleBean) key, simple) };
            }

            public void propertyChange (PropertyChangeEvent ev) {
                refreshKeys ();
            }

        }

    }

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.