This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 182698
Collapse All | Expand All

(-)1f7b91420663 (+5 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project basedir="." default="netbeans" name="api.menus">
3
    <description>Builds, tests, and runs the project org.netbeans.api.menus</description>
4
    <import file="../nbbuild/templates/projectized.xml"/>
5
</project>
(-)1f7b91420663 (+7 lines)
Added Link Here
1
Manifest-Version: 1.0
2
AutoUpdate-Show-In-Client: false
3
OpenIDE-Module: org.netbeans.api.menus/1
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/menus/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.0
6
OpenIDE-Module-Recommends: org.netbeans.api.menus.MenuProvider
7
(-)1f7b91420663 (+4 lines)
Added Link Here
1
is.autoload=true
2
javac.source=1.6
3
javac.compilerargs=-Xlint -Xlint:-serial
4
nbm.module.author=Tim Boudreau
(-)1f7b91420663 (+30 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://www.netbeans.org/ns/project/1">
3
    <type>org.netbeans.modules.apisupport.project</type>
4
    <configuration>
5
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6
            <code-name-base>org.netbeans.api.menus</code-name-base>
7
            <module-dependencies>
8
                <dependency>
9
                    <code-name-base>org.openide.util</code-name-base>
10
                    <build-prerequisite/>
11
                    <compile-dependency/>
12
                    <run-dependency>
13
                        <specification-version>8.2</specification-version>
14
                    </run-dependency>
15
                </dependency>
16
                <dependency>
17
                    <code-name-base>org.openide.util.lookup</code-name-base>
18
                    <build-prerequisite/>
19
                    <compile-dependency/>
20
                    <run-dependency>
21
                        <specification-version>8.2</specification-version>
22
                    </run-dependency>
23
                </dependency>
24
            </module-dependencies>
25
            <public-packages>
26
                <package>org.netbeans.api.menus</package>
27
            </public-packages>
28
        </data>
29
    </configuration>
30
</project>
(-)1f7b91420663 (+7 lines)
Added Link Here
1
OpenIDE-Module-Display-Category=Infrastructure
2
OpenIDE-Module-Long-Description=\
3
    API which allows another module to inject a factory which creates the main window's menu bar.
4
OpenIDE-Module-Name=Main Menu API
5
FILE_MENU=File
6
EXIT_MENU_ITEM=Exit
7
OpenIDE-Module-Short-Description=API for generating the application's menu(s)
(-)1f7b91420663 (+142 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.api.menus;
40
41
import java.awt.EventQueue;
42
import java.awt.event.ActionEvent;
43
import java.util.logging.Level;
44
import java.util.logging.Logger;
45
import javax.swing.AbstractAction;
46
import javax.swing.Action;
47
import javax.swing.JFrame;
48
import javax.swing.JMenu;
49
import javax.swing.JMenuBar;
50
import org.openide.LifecycleManager;
51
import org.openide.util.Exceptions;
52
import org.openide.util.Lookup;
53
import org.openide.util.NbBundle;
54
import org.openide.util.Parameters;
55
56
/**
57
 * Factory for the application window main menu.  Registered in the default
58
 * lookup.
59
 *
60
 * @author Tim Boudreau
61
 * @since 1.0
62
 */
63
public abstract class MenuProvider {
64
65
    /**
66
     * Install a menu in a JFrame.  Called by the window system to set up the
67
     * main menu.  This method is not guaranteed to return the same JMenuBar
68
     * if called repeatedly, and should not be used as a way to look up the
69
     * main window's menu.
70
     * <p/>
71
     * This method must be called on the AWT event dispatch thread.
72
     * <p/>
73
     * If no MenuProvider is registered in the default lookup, will create a
74
     * menu which simply contains a File menu with an Exit menu item that
75
     * uses LifecycleManager to cleanly exit the application.
76
     *
77
     * @param frame A JFrame.  May not be null.
78
     * @return The JMenuBar which has been installed in the frame.
79
     */
80
    public static JMenuBar installMenu(JFrame frame) {
81
        Parameters.notNull("frame", frame); //NOI18N
82
        if (!EventQueue.isDispatchThread()) {
83
            throw new IllegalStateException("Not on event thread"); //NOI18N
84
        }
85
        MenuProvider p = Lookup.getDefault().lookup(MenuProvider.class);
86
        JMenuBar menu = p == null ? fallbackMenu() : p.createMenu(frame);
87
        if (p == null) {
88
            Logger.getLogger(MenuProvider.class.getName()).log (Level.WARNING,
89
                    "No instance of {0} registered in the default lookup. " + //NOI18N
90
                    "Using fallback.", MenuProvider.class.getName()); //NOI18N
91
        }
92
        if (menu == null) {
93
            if (p != null) {
94
                Exceptions.printStackTrace(new NullPointerException(p
95
                    + " returned null menu")); //NOI18N
96
            }
97
            menu = fallbackMenu();
98
        }
99
        frame.setJMenuBar(menu);
100
        return menu;
101
    }
102
103
    private static JMenuBar fallbackMenu() {
104
        String fileMenuName = NbBundle.getMessage(MenuProvider.class,
105
                "FILE_MENU"); //NOI18N
106
        String exitItemName = NbBundle.getMessage(MenuProvider.class,
107
                "EXIT_MENU_ITEM"); //NOI18N
108
        JMenuBar result = new JMenuBar();
109
        JMenu fileMenu = new JMenu(fileMenuName);
110
        Action exitAction = new ExitAction();
111
        exitAction.putValue(Action.NAME, exitItemName);
112
        fileMenu.add(exitAction);
113
        result.add(fileMenu);
114
        return result;
115
    }
116
117
    /**
118
     * Create a menu for the provided JFrame.  This method is not expected
119
     * to cache the return value.  It should not actually call the target frame's
120
     * <code>setJMenuBar()</code> method - the target frame is provided as a
121
     * convenience in case some multi-frame application provides menus for
122
     * multiple frames.
123
     * <p/>
124
     * This method will only be called by NetBeans from the event dispatch thread.
125
     * Constructing components is safe here, but it is preferable not to perform
126
     * heavy-duty I/O in this method, but rather to create the initial menu bar
127
     * quickly, and then populate its menus lazily or in the background.
128
     * <p/>
129
     * @param target The frame the menu should be created for
130
     * @since 1.0
131
     * @return A JMenuBar
132
     */
133
    protected abstract JMenuBar createMenu(JFrame target);
134
135
    private static final class ExitAction extends AbstractAction {
136
137
        @Override
138
        public void actionPerformed(ActionEvent e) {
139
            LifecycleManager.getDefault().exit();
140
        }
141
    }
142
}
(-)1f7b91420663 (+5 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project basedir="." default="netbeans" name="core.menu">
3
    <description>Builds, tests, and runs the project org.netbeans.core.menu</description>
4
    <import file="../nbbuild/templates/projectized.xml"/>
5
</project>
(-)1f7b91420663 (+7 lines)
Added Link Here
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.core.menu
3
OpenIDE-Module-Layer: org/netbeans/core/menu/layer.xml
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/core/menu/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.0
6
OpenIDE-Module-Provides: org.netbeans.api.menus.MenuProvider
7
(-)1f7b91420663 (+2 lines)
Added Link Here
1
javac.source=1.6
2
javac.compilerargs=-Xlint -Xlint:-serial
(-)1f7b91420663 (+83 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://www.netbeans.org/ns/project/1">
3
    <type>org.netbeans.modules.apisupport.project</type>
4
    <configuration>
5
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6
            <code-name-base>org.netbeans.core.menu</code-name-base>
7
            <module-dependencies>
8
                <dependency>
9
                    <code-name-base>org.netbeans.api.menus</code-name-base>
10
                    <build-prerequisite/>
11
                    <compile-dependency/>
12
                    <run-dependency>
13
                        <release-version>1</release-version>
14
                        <specification-version>1.0</specification-version>
15
                    </run-dependency>
16
                </dependency>
17
                <dependency>
18
                    <code-name-base>org.openide.awt</code-name-base>
19
                    <build-prerequisite/>
20
                    <compile-dependency/>
21
                    <run-dependency>
22
                        <specification-version>7.21</specification-version>
23
                    </run-dependency>
24
                </dependency>
25
                <dependency>
26
                    <code-name-base>org.openide.filesystems</code-name-base>
27
                    <build-prerequisite/>
28
                    <compile-dependency/>
29
                    <run-dependency>
30
                        <specification-version>7.37</specification-version>
31
                    </run-dependency>
32
                </dependency>
33
                <dependency>
34
                    <code-name-base>org.openide.loaders</code-name-base>
35
                    <build-prerequisite/>
36
                    <compile-dependency/>
37
                    <run-dependency>
38
                        <specification-version>7.13</specification-version>
39
                    </run-dependency>
40
                </dependency>
41
                <dependency>
42
                    <code-name-base>org.openide.nodes</code-name-base>
43
                    <build-prerequisite/>
44
                    <compile-dependency/>
45
                    <run-dependency>
46
                        <specification-version>7.14</specification-version>
47
                    </run-dependency>
48
                </dependency>
49
                <dependency>
50
                    <code-name-base>org.openide.util</code-name-base>
51
                    <build-prerequisite/>
52
                    <compile-dependency/>
53
                    <run-dependency>
54
                        <specification-version>8.2</specification-version>
55
                    </run-dependency>
56
                </dependency>
57
                <dependency>
58
                    <code-name-base>org.openide.util.lookup</code-name-base>
59
                    <build-prerequisite/>
60
                    <compile-dependency/>
61
                    <run-dependency>
62
                        <specification-version>8.2</specification-version>
63
                    </run-dependency>
64
                </dependency>
65
            </module-dependencies>
66
            <test-dependencies>
67
                <test-type>
68
                    <name>unit</name>
69
                    <test-dependency>
70
                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
71
                        <compile-dependency/>
72
                    </test-dependency>
73
                    <test-dependency>
74
                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
75
                        <recursive/>
76
                        <compile-dependency/>
77
                    </test-dependency>
78
                </test-type>
79
            </test-dependencies>
80
            <public-packages/>
81
        </data>
82
    </configuration>
83
</project>
(-)1f7b91420663 (+125 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.io.IOException;
43
import javax.swing.Action;
44
import javax.swing.JCheckBoxMenuItem;
45
import javax.swing.JMenuItem;
46
import org.openide.awt.AcceleratorBinding;
47
import org.openide.awt.Actions;
48
import org.openide.awt.Mnemonics;
49
import org.openide.loaders.DataObject;
50
import org.openide.util.Exceptions;
51
import org.openide.util.actions.BooleanStateAction;
52
import org.openide.util.actions.Presenter;
53
import org.openide.util.actions.SystemAction;
54
55
/**
56
 *
57
 * @author Tim Boudreau
58
 */
59
final class ActionModelEntry extends ThreadUnconstrainedModelEntry<Action, JMenuItem> {
60
    ActionModelEntry(DataObject dob) {
61
        super (dob, JMenuItem.class, Action.class);
62
    }
63
64
    @Override
65
    protected JMenuItem refreshComponent(JMenuItem old) {
66
        Action a;
67
        try {
68
            a = get();
69
            if (old.getAction() == a) {
70
                configureName (a, old);
71
            }
72
        } catch (IOException ex) {
73
            Exceptions.printStackTrace(ex);
74
        } catch (ClassNotFoundException ex) {
75
            Exceptions.printStackTrace(ex);
76
        }
77
        return old;
78
    }
79
80
    private String getActionName(Action action) {
81
        String name = (String) action.getValue(Action.NAME);
82
        if (name == null && action instanceof SystemAction) {
83
            name = ((SystemAction) action).getName();
84
        }
85
        name = name == null ? getName() : name;
86
        return name;
87
    }
88
89
    private void configureName (Action action, JMenuItem item) {
90
        String txt = item.getText();
91
        if (txt == null || txt.length() == 0) {
92
            Mnemonics.setLocalizedText(item, getActionName(action));
93
            item.setToolTipText(null);
94
        }
95
    }
96
97
    @Override
98
    protected JMenuItem findComponent() {
99
        try {
100
            Action action = get();
101
            if (action instanceof Presenter.Menu) {
102
                throw new IllegalStateException("ActionModelEntry used for a menu presenter action");
103
            }
104
            JMenuItem item;
105
            if (action instanceof BooleanStateAction) {
106
                BooleanStateAction bse = (BooleanStateAction) action;
107
                JCheckBoxMenuItem cbItem = new JCheckBoxMenuItem();
108
                configureName (action, cbItem);
109
                Actions.connect(cbItem, bse, false);
110
                item = cbItem;
111
            } else {
112
                item = new JMenuItem();
113
                configureName (action, item);
114
                Actions.connect (item, action);
115
            }
116
            AcceleratorBinding.setAccelerator(action, file().getPrimaryFile());
117
            return item;
118
        } catch (IOException ex) {
119
            Exceptions.printStackTrace(ex);
120
        } catch (ClassNotFoundException ex) {
121
            Exceptions.printStackTrace(ex);
122
        }
123
        return new JMenuItem("Error from " + file().getName()); //XXX
124
    }
125
}
(-)1f7b91420663 (+1 lines)
Added Link Here
1
OpenIDE-Module-Name=Core Main Menu
(-)1f7b91420663 (+50 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
/**
42
 *
43
 * @author Tim Boudreau
44
 */
45
interface Callback {
46
47
    void onShow(ModelEntry<?, ?> entry);
48
49
    void onHide(ModelEntry<?, ?> entry);
50
}
(-)1f7b91420663 (+178 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.lang.ref.Reference;
44
import java.lang.ref.WeakReference;
45
import java.util.Arrays;
46
import javax.swing.JComponent;
47
import javax.swing.JSeparator;
48
import org.openide.util.Parameters;
49
50
/**
51
 * Wrapper for an array of components which can be checked for value equality.
52
 *
53
 * @author Tim Boudreau
54
 */
55
final class ComponentList {
56
    private final JComponent[] comps;
57
    private final Reference<?>[] refs;
58
    private volatile boolean isWeak;
59
    ComponentList(JComponent[] comps) {
60
        Parameters.notNull("comps", comps);
61
        this.comps = new JComponent[comps.length];
62
        refs = new Reference<?>[comps.length];
63
        for (int i= 0; i < comps.length; i++) {
64
            if (comps[i] == null) {
65
                this.comps[i] = new JSeparator();
66
            } else {
67
                this.comps[i] = comps[i];
68
            }
69
            refs[i] = new WeakReference<Component>(this.comps[i]);
70
        }
71
    }
72
73
    JComponent get (int ix) {
74
        JComponent result = comps[ix];
75
        if (comps[ix] == null) {
76
            result = refs[ix] == null ? null : (JComponent) refs[ix].get();
77
        }
78
        return result;
79
    }
80
81
    private void set (int ix, JComponent comp) {
82
        Parameters.notNull("comp", comp); //NOI18N
83
        comps[ix] = comp;
84
        refs[ix] = new WeakReference<JComponent>(comps[ix]);
85
    }
86
87
    int size() {
88
        return comps.length;
89
    }
90
91
    public JComponent[] getComponents() {
92
        JComponent[] result = new JComponent[size()];
93
        for (int i= 0; i < result.length; i++) {
94
            result[i] = get(i);
95
        }
96
        return result;
97
    }
98
99
    boolean addNotify() {
100
        boolean result = false;
101
        if (!result) {
102
            result = true;
103
            for (int i= 0; i < comps.length; i++) {
104
                if (comps[i] == null) {
105
                    comps[i] = refs[i] == null ? null : (JComponent) refs[i].get();
106
                    if (comps[i] == null) {
107
                        result = false;
108
                    }
109
                }
110
            }
111
        }
112
        isWeak = result;
113
        return result;
114
    }
115
116
    void removeNotify() {
117
//        if (!isWeak) {
118
            for (int i = 0; i < comps.length; i++) {
119
                comps[i] = null;
120
            }
121
//        }
122
        isWeak = true;
123
    }
124
125
    boolean repair (JComponent[] nue) {
126
        Parameters.notNull("nue", nue);
127
        if (nue.length != comps.length) {
128
            return false;
129
        }
130
        boolean result = true;
131
        for (int i= 0; i < comps.length; i++) {
132
            JComponent c = get(i);
133
            if (c == null || c == nue[i]) {
134
                if (nue[i] == null) {
135
                    throw new NullPointerException ("Null element in component " + //NOI18N
136
                            "list at " + i); //NOI18N
137
                }
138
                set (i, nue[i]);
139
            } else {
140
                result = false;
141
            }
142
        }
143
        return result;
144
    }
145
146
    @Override
147
    public boolean equals(Object obj) {
148
        if (obj == null || obj.getClass() != ComponentList.class) {
149
            return false;
150
        }
151
        final ComponentList other = (ComponentList) obj;
152
        if (other == this) {
153
            return true;
154
        }
155
        if (other.comps == comps) {
156
            return true;
157
        }
158
        if (other.comps.length != comps.length) {
159
            return false;
160
        }
161
        for (int i=0; i < comps.length; i++) {
162
            //test only on exact equality
163
            JComponent a = get(i);
164
            JComponent b = other.get(i);
165
            if (a != b) {
166
                return false;
167
            }
168
        }
169
        return true;
170
    }
171
172
    @Override
173
    public int hashCode() {
174
        int hash = 7;
175
        hash = 97 * hash + Arrays.deepHashCode(this.comps);
176
        return hash;
177
    }
178
}
(-)1f7b91420663 (+82 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.io.IOException;
44
import java.util.List;
45
import javax.swing.JComponent;
46
import javax.swing.JMenuItem;
47
import org.openide.loaders.DataObject;
48
import org.openide.util.Exceptions;
49
50
/**
51
 *
52
 * @author Tim Boudreau
53
 */
54
final class ComponentModelEntry extends FileModelEntry <JComponent, JComponent> {
55
    ComponentModelEntry (DataObject dob) {
56
        super (dob, JComponent.class, JComponent.class);
57
    }
58
59
    @Override
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
61
        return false;
62
    }
63
64
    @Override
65
    protected JComponent findComponent() {
66
        try {
67
            return get();
68
        } catch (IOException ex) {
69
            Exceptions.printStackTrace(ex);
70
        } catch (ClassNotFoundException ex) {
71
            Exceptions.printStackTrace(ex);
72
        }
73
        return new JMenuItem("Error getting comp for " + getName());
74
    }
75
76
    @Override
77
    protected JComponent refreshComponent(JComponent old) {
78
        return old;
79
    }
80
81
82
}
(-)1f7b91420663 (+85 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.io.IOException;
43
import javax.swing.JComponent;
44
import javax.swing.JMenuItem;
45
import org.openide.awt.DynamicMenuContent;
46
import org.openide.loaders.DataObject;
47
import org.openide.util.Exceptions;
48
49
/**
50
 *
51
 * @author Tim Boudreau
52
 */
53
public class DynamicModelEntry extends ThreadUnconstrainedModelEntry<DynamicMenuContent, JComponent> {
54
    DynamicModelEntry(DataObject dob) {
55
        super (dob, JComponent.class, DynamicMenuContent.class);
56
    }
57
58
    @Override
59
    protected JComponent[] findComponents() {
60
        try {
61
            DynamicMenuContent dyn = get();
62
            JComponent[] result = dyn.getMenuPresenters();
63
            //Necessary the first time, or we get bogus elements
64
            dyn.synchMenuPresenters(result);
65
            return result;
66
        } catch (IOException ex) {
67
            Exceptions.printStackTrace(ex);
68
        } catch (ClassNotFoundException ex) {
69
            Exceptions.printStackTrace(ex);
70
        }
71
        return new JComponent[] { new JMenuItem("Error getting " + file().getName()) }; //XXX
72
    }
73
74
    @Override
75
    protected JComponent[] refresh(JComponent[] old) {
76
        try {
77
            return get().synchMenuPresenters(old);
78
        } catch (IOException ex) {
79
            Exceptions.printStackTrace(ex);
80
        } catch (ClassNotFoundException ex) {
81
            Exceptions.printStackTrace(ex);
82
        }
83
        return old;
84
    }
85
}
(-)1f7b91420663 (+130 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.awt.EventQueue;
44
import java.io.IOException;
45
import javax.swing.JComponent;
46
import org.openide.cookies.InstanceCookie;
47
import org.openide.loaders.DataFolder;
48
import org.openide.loaders.DataObject;
49
50
/**
51
 *
52
 * @author Tim Boudreau
53
 */
54
abstract class FileModelEntry<T, CompType extends JComponent> extends ModelEntry <CompType, DataObject> {
55
    protected final Class<T> modelObjectType;
56
    FileModelEntry(DataObject dob, Class<CompType> componentType, Class<T> modelObjectType) {
57
        super (dob, DataObject.class, componentType);
58
        this.modelObjectType = modelObjectType;
59
        assert !(dob instanceof DataFolder) : "Folder used for menu item"; //NOI18N
60
    }
61
62
    private final InstanceCookie cookie() {
63
        DataObject dob = file();
64
        InstanceCookie ck = dob.getLookup().lookup(InstanceCookie.class);
65
        if (ck == null) {
66
            ck = new EmptyInstanceCookie(dob.getName());
67
        }
68
        return ck;
69
    }
70
71
    final boolean requiresEq() {
72
        return Component.class.isAssignableFrom(dobType);
73
    }
74
75
    protected T get() throws IOException, ClassNotFoundException {
76
        if (requiresEq() && !EventQueue.isDispatchThread()) {
77
            throw new IllegalStateException ("Not on event thread");
78
        }
79
        return modelObjectType.cast(cookie().instanceCreate());
80
    }
81
82
    private static final class EmptyInstanceCookie implements InstanceCookie, InstanceCookie.Of {
83
        private final String name;
84
        EmptyInstanceCookie (String name) {
85
            this.name = name;
86
        }
87
88
        @Override
89
        public String instanceName() {
90
            return name;
91
        }
92
93
        @Override
94
        public Class<?> instanceClass() throws IOException, ClassNotFoundException {
95
            return Object.class;
96
        }
97
98
        @Override
99
        public Object instanceCreate() throws IOException, ClassNotFoundException {
100
            return null;
101
        }
102
103
        @Override
104
        public boolean instanceOf(Class<?> type) {
105
            return false;
106
        }
107
108
        @Override
109
        public boolean equals(Object obj) {
110
            if (obj == null) {
111
                return false;
112
            }
113
            if (getClass() != obj.getClass()) {
114
                return false;
115
            }
116
            final EmptyInstanceCookie other = (EmptyInstanceCookie) obj;
117
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
118
                return false;
119
            }
120
            return true;
121
        }
122
123
        @Override
124
        public int hashCode() {
125
            int hash = 7;
126
            hash = 17 * hash + (this.name != null ? this.name.hashCode() : 0);
127
            return hash;
128
        }
129
    }
130
}
(-)1f7b91420663 (+336 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.Component;
42
import java.awt.EventQueue;
43
import java.io.IOException;
44
import java.util.ArrayList;
45
import java.util.Arrays;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.Iterator;
49
import java.util.LinkedList;
50
import java.util.List;
51
import java.util.Map;
52
import java.util.Set;
53
import javax.swing.Action;
54
import javax.swing.JComponent;
55
import javax.swing.JSeparator;
56
import org.openide.awt.DynamicMenuContent;
57
import org.openide.cookies.InstanceCookie;
58
import org.openide.loaders.DataFolder;
59
import org.openide.loaders.DataObject;
60
import org.openide.util.Exceptions;
61
import org.openide.util.Parameters;
62
import org.openide.util.actions.Presenter;
63
64
/**
65
 *
66
 * @author Tim Boudreau
67
 */
68
abstract class FolderModelEntry<CompType extends JComponent> extends ModelEntry<CompType, DataFolder> implements Callback {
69
70
    private final List<ModelEntry<?, ?>> children = new ArrayList<ModelEntry<?, ?>>(15);
71
    private final Object childLock = new Object();
72
    private final Object mapLock = new Object();
73
    private final Map<ModelEntry<?, ?>, ComponentList> comps4model =
74
            new HashMap<ModelEntry<?, ?>, ComponentList>();
75
76
    FolderModelEntry(DataFolder fld, Class<CompType> compType) {
77
        super(fld, DataFolder.class, compType);
78
    }
79
80
    boolean setChildren(List<ModelEntry<?, ?>> l) {
81
        boolean result;
82
        synchronized (childLock) {
83
            result = !children.equals(l);
84
            if (result) {
85
                children.clear();
86
                children.addAll(l);
87
            }
88
        }
89
        synchronized (mapLock) {
90
            if (!comps4model.isEmpty()) {
91
                Set<ModelEntry<?,?>> known = new HashSet<ModelEntry<?, ?>>(comps4model.keySet());
92
                known.removeAll(l);
93
                for (ModelEntry<?,?> m : known) {
94
                    comps4model.remove(m);
95
                }
96
            }
97
        }
98
        return result;
99
    }
100
101
    @Override
102
    public final void onHide(ModelEntry<?, ?> entry) {
103
        synchronized (mapLock) {
104
            for (Map.Entry<ModelEntry<?,?>, ComponentList> e : comps4model.entrySet()) {
105
                e.getValue().removeNotify();
106
            }
107
        }
108
    }
109
110
    @Override
111
    public final void onShow(ModelEntry<?, ?> entry) {
112
        synchronized (mapLock) {
113
            for (Map.Entry<ModelEntry<?,?>, ComponentList> e : comps4model.entrySet()) {
114
                e.getValue().addNotify();
115
            }
116
        }
117
    }
118
119
    private ComponentList components(ModelEntry<?,?> e) {
120
        Parameters.notNull("e", e);
121
        synchronized (mapLock) {
122
            return comps4model.get(e);
123
        }
124
    }
125
126
    private void setComponents (ModelEntry<?,?> e, ComponentList comps) {
127
        Parameters.notNull("comps", comps);
128
        Parameters.notNull("e", e);
129
        synchronized (mapLock) {
130
            if (comps == null) {
131
                comps4model.remove(e);
132
            } else {
133
                comps4model.put(e, comps);
134
            }
135
        }
136
    }
137
138
    List<ModelEntry<?, ?>> children() {
139
        synchronized (childLock) {
140
            return new ArrayList<ModelEntry<?, ?>>(children);
141
        }
142
    }
143
144
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
145
        //do nothing - for subclasses to force init
146
    }
147
148
    @Override
149
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children) {
150
//        System.err.println("initBackground " + getName());
151
        DataFolder fld = file();
152
        boolean changed = true;
153
        Set<ModelEntry<?, ?>> created = new HashSet<ModelEntry<?, ?>>();
154
        try {
155
            DataObject[] ch = fld.getChildren();
156
            if (ch != null) { //can be null
157
                outer:
158
                for (DataObject dob : ch) {
159
                    try {
160
                        for (Types t : Types.values()) {
161
                            if (t.accept(dob)) {
162
                                ModelEntry<?, ?> e = t.createEntry(dob, this);
163
                                created.add(e);
164
                                children.add(e);
165
                                //XXX defer or batch afterward?
166
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
167
                                boolean hasKids = e.initBackground(kids);
168
                                changed |= hasKids;
169
                                if (hasKids) {
170
                                    if (e instanceof FolderModelEntry) {
171
                                        FolderModelEntry<?> fme = FolderModelEntry.class.cast(e);
172
                                        changed |= fme.setChildren(kids);
173
                                    }
174
                                }
175
                                continue outer;
176
                            }
177
                        }
178
//                        System.err.println("No type accepted " + dob.getPrimaryFile().getPath() + " : " + ic(dob));
179
                    } catch (IOException ex) {
180
                        Exceptions.printStackTrace(ex);
181
                    } catch (ClassNotFoundException ex) {
182
                        Exceptions.printStackTrace(ex);
183
                    }
184
                }
185
            }
186
        } finally {
187
            onInitBackground(children);
188
        }
189
        return changed;
190
    }
191
192
//    private static String ic(DataObject dob) throws ClassNotFoundException, IOException {
193
//        InstanceCookie ck = dob.getCookie(InstanceCookie.class);
194
//        return ck == null ? " [no ic]" : ck.instanceClass().getName();
195
//    }
196
    @Override
197
    protected CompType refreshComponent(CompType old) {
198
        if (!EventQueue.isDispatchThread()) {
199
            throw new IllegalStateException("Not on event thread");
200
        }
201
//        long start = System.currentTimeMillis();
202
        Parameters.notNull("old", old);
203
        old.removeAll();
204
        List<JComponent> all = new LinkedList<JComponent>();
205
        List<ModelEntry<?, ?>> kids = children();
206
        Boolean expectHasIcon = false;
207
        for (ModelEntry<?, ?> e : kids) {
208
            ComponentList c = components(e);
209
            JComponent[] comps;
210
            if (c == null) {
211
                comps = e.getComponents();
212
                if (comps != null) {
213
                    all.addAll(Arrays.asList(comps));
214
                    setComponents(e, c = new ComponentList(comps));
215
                }
216
            } else {
217
                boolean allStillAlive = c.addNotify();
218
                if (allStillAlive) {
219
                    comps = e.refresh(c.getComponents());
220
                    ComponentList newComps;
221
                    if (comps != null && !((newComps = new ComponentList(comps)).equals(c))) {
222
                        setComponents(e, newComps);
223
                        c = newComps;
224
                    }
225
                } else {
226
                    comps = e.findComponents();
227
                    boolean fixed = c.repair(comps);
228
                    if (!fixed) {
229
                        setComponents(e, c = new ComponentList(comps));
230
                    }
231
                }
232
            }
233
            if (comps != null) {
234
                for (JComponent comp : comps) {
235
                    expectHasIcon = ModelEntry.defaultHasIcon(comp, expectHasIcon);
236
                }
237
            }
238
            if (c != null) {
239
                all.addAll(Arrays.asList(c.getComponents()));
240
            }
241
        }
242
        pruneSeparatorsAndFixIcons(all, expectHasIcon);
243
        installComponents(all, old);
244
//        long dur = System.currentTimeMillis() - start;
245
//        System.err.println("Refresh " + getName() + " took " + dur + " milliseconds");
246
        return old;
247
    }
248
249
    protected void installComponents(List<? extends JComponent> components, CompType into) {
250
        for (Component c : components) {
251
            if (c == null) {
252
                c = new JSeparator();
253
            }
254
            into.add(c);
255
        }
256
    }
257
258
    private void pruneSeparatorsAndFixIcons(List<JComponent> all, Boolean icons) {
259
        boolean lastWasSep = true;
260
        for (Iterator<JComponent> i = all.iterator(); i.hasNext();) {
261
            JComponent c = i.next();
262
            boolean isSep = c instanceof JSeparator;
263
            if ((lastWasSep && isSep) || (!i.hasNext() && isSep)) {
264
                i.remove();
265
            }
266
            lastWasSep = isSep;
267
            if (icons != null) {
268
                ModelEntry.configureIcon(c, icons);
269
            }
270
        }
271
    }
272
273
    private static enum Types {
274
275
        SEPARATOR(JSeparator.class),
276
        DYNAMIC_MENU_CONTENT(DynamicMenuContent.class),
277
        PRESENTER(Presenter.Menu.class),
278
        MENU,
279
        COMPONENT(Component.class),
280
        ACTION(Action.class);
281
        private final Class<?> type;
282
283
        Types(Class<?> type) {
284
            this.type = type;
285
        }
286
287
        Types() {
288
            this(Object.class);
289
        }
290
291
        boolean accept(DataObject dob) throws IOException, ClassNotFoundException {
292
            if (this == MENU) {
293
                DataFolder fld = dob instanceof DataFolder ? (DataFolder) dob
294
                        : dob.getLookup().lookup(DataFolder.class);
295
                return fld != null;
296
            }
297
            InstanceCookie ck = dob.getLookup().lookup(InstanceCookie.class);
298
            return ck instanceof InstanceCookie.Of ? ((InstanceCookie.Of) ck).instanceOf(type)
299
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
300
        }
301
302
        ModelEntry<?, ?> createEntry(DataObject ob, Callback callback) {
303
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
304
            switch (this) {
305
                case SEPARATOR:
306
                    return new SeparatorModelEntry(ob);
307
                case ACTION:
308
                    InstanceCookie ic = ob.getLookup().lookup(InstanceCookie.class);
309
                    try {
310
                        //This is a bit of a mess - some InstanceCookies lie
311
                        if (ic.instanceCreate() instanceof Presenter.Menu) {
312
                            return new PresenterEntry(ob);
313
                        }
314
                    } catch (IOException ex) {
315
                        Exceptions.printStackTrace(ex);
316
                    } catch (ClassNotFoundException ex) {
317
                        Exceptions.printStackTrace(ex);
318
                    }
319
                    return new ActionModelEntry(ob);
320
                case DYNAMIC_MENU_CONTENT:
321
                    return new DynamicModelEntry(ob);
322
                case PRESENTER:
323
                    return new PresenterEntry(ob);
324
                case MENU:
325
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
326
                            : ob.getLookup().lookup(DataFolder.class);
327
                    Parameters.notNull("folder was non-null but is now null", fld);
328
                    return new MenuEntry(fld, null);
329
                case COMPONENT:
330
                    return new ComponentModelEntry(ob);
331
                default:
332
                    throw new AssertionError(this + "");
333
            }
334
        }
335
    }
336
}
(-)1f7b91420663 (+150 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import java.util.LinkedList;
44
import java.util.List;
45
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
49
import org.openide.filesystems.FileRenameEvent;
50
import org.openide.loaders.DataFolder;
51
import org.openide.util.RequestProcessor;
52
53
/**
54
 *
55
 * @author Tim Boudreau
56
 */
57
final class MenuBarModel extends FolderModelEntry<JMenuBar> {
58
    private final JMenuBar bar;
59
    private FCA fca = new FCA();
60
    private final RequestProcessor.Task task;
61
    private static final int DELAY = 100;
62
    MenuBarModel (DataFolder rootFolder, JMenuBar bar, RequestProcessor rp) {
63
        super (rootFolder, JMenuBar.class);
64
        this.bar = bar;
65
        this.task = rp.create(fca);
66
        rootFolder.getPrimaryFile().addFileChangeListener(fca);
67
    }
68
69
    void init() {
70
        fca.refresh();
71
    }
72
73
    @Override
74
    protected JMenuBar findComponent() {
75
        return bar;
76
    }
77
78
    @Override
79
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
80
        super.onInitBackground(children);
81
        if (!refreshing) {
82
            EventQueue.invokeLater(fca);
83
        }
84
    }
85
86
    volatile boolean refreshing;
87
    private final class FCA extends FileChangeAdapter implements Runnable {
88
        private volatile boolean enqueued;
89
        boolean refresh() {
90
            boolean result;
91
            synchronized (this) {
92
                result = enqueued;
93
                if (!enqueued) {
94
                    enqueued = true;
95
                    task.schedule(DELAY);
96
                }
97
                return result;
98
            }
99
        }
100
101
        @Override
102
        public void run() {
103
            if (!EventQueue.isDispatchThread()) {
104
                refreshing = true;
105
                try {
106
                    List<ModelEntry<?,?>> l = new LinkedList<ModelEntry<?,?>>();
107
                    initBackground(l);
108
                    setChildren(l);
109
                } finally {
110
                    refreshing = false;
111
                    EventQueue.invokeLater(this);
112
                }
113
            } else {
114
                enqueued = false;
115
                bar.removeAll();
116
                MenuBarModel.this.refresh(new JMenuBar[] { bar });
117
            }
118
        }
119
120
        @Override
121
        public void fileAttributeChanged(FileAttributeEvent fe) {
122
            refresh();
123
        }
124
125
        @Override
126
        public void fileChanged(FileEvent fe) {
127
            refresh();
128
        }
129
130
        @Override
131
        public void fileDataCreated(FileEvent fe) {
132
            refresh();
133
        }
134
135
        @Override
136
        public void fileDeleted(FileEvent fe) {
137
            refresh();
138
        }
139
140
        @Override
141
        public void fileFolderCreated(FileEvent fe) {
142
            refresh();
143
        }
144
145
        @Override
146
        public void fileRenamed(FileRenameEvent fe) {
147
            refresh();
148
        }
149
    }
150
}
(-)1f7b91420663 (+106 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import java.lang.ref.Reference;
44
import java.lang.ref.WeakReference;
45
import javax.swing.ButtonModel;
46
import javax.swing.JMenu;
47
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeListener;
49
import org.openide.awt.Mnemonics;
50
import org.openide.loaders.DataFolder;
51
52
/**
53
 *
54
 * @author Tim Boudreau
55
 */
56
final class MenuEntry extends FolderModelEntry<JMenu> implements ChangeListener {
57
58
    private Reference<JMenu> menu;
59
    private final Callback callback;
60
61
    MenuEntry (DataFolder fld, Callback callback) {
62
        super (fld, JMenu.class);
63
        this.callback = callback == null ? this : callback;
64
    }
65
66
    private JMenu menu() {
67
        JMenu result = menu == null ? null : menu.get();
68
        if (result == null) {
69
            result = new JMenu();
70
            Mnemonics.setLocalizedText(result, getName());
71
            result.getModel().addChangeListener(this);
72
            menu = new WeakReference<JMenu> (result);
73
        }
74
        return result;
75
    }
76
77
    @Override
78
    protected JMenu findComponent() {
79
        assert EventQueue.isDispatchThread();
80
        return menu();
81
    }
82
83
    private boolean wasSelected = false;
84
    @Override
85
    public void stateChanged(ChangeEvent e) {
86
        ButtonModel mdl = (ButtonModel) e.getSource();
87
        boolean selected = mdl.isSelected();
88
        //XXX wasSelected could be true if the old component was garbage collected
89
        //without resetting its model - possible?
90
        if (selected && !wasSelected) {
91
            if (callback != null) {
92
                callback.onShow(this);
93
            }
94
            refreshComponent(menu());
95
        } else if (wasSelected && !selected) {
96
            JMenu m = menu == null ? null : menu.get();
97
            if (m != null) {
98
                m.removeAll();
99
            }
100
            if (callback != null) {
101
                callback.onHide(this);
102
            }
103
        }
104
        wasSelected = selected;
105
    }
106
}
(-)1f7b91420663 (+63 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import javax.swing.JMenuBar;
43
import org.openide.loaders.DataFolder;
44
import org.openide.util.RequestProcessor;
45
46
/**
47
 *
48
 * @author Tim Boudreau
49
 */
50
final class MenuManager {
51
    private final JMenuBar bar;
52
    private final RequestProcessor rp = new RequestProcessor("Main Menu Refresh", 1, true);
53
    private final MenuBarModel model;
54
55
    MenuManager(DataFolder folder, JMenuBar bar) {
56
        this.bar = bar;
57
        model = new MenuBarModel (folder, bar, rp);
58
    }
59
60
    void init() {
61
        model.init();
62
    }
63
}
(-)1f7b91420663 (+81 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import javax.swing.JFrame;
44
import javax.swing.JMenuBar;
45
import org.netbeans.api.menus.MenuProvider;
46
import org.openide.filesystems.FileObject;
47
import org.openide.filesystems.FileUtil;
48
import org.openide.loaders.DataFolder;
49
import org.openide.util.lookup.ServiceProvider;
50
51
/**
52
 *
53
 * @author Tim Boudreau
54
 */
55
@ServiceProvider(service=MenuProvider.class)
56
public final class MenuProviderImpl extends MenuProvider {
57
    private static final String MENU_FOLDER = "Menu"; //NOI18N
58
    private FileObject menuFolder;
59
    public MenuProviderImpl () {
60
        this (FileUtil.getConfigFile(MENU_FOLDER));
61
    }
62
63
    MenuProviderImpl (FileObject menuFolder) { //used in unit tests w/ memfs
64
        this.menuFolder = menuFolder;
65
    }
66
67
    @Override
68
    protected JMenuBar createMenu(JFrame target) {
69
        if (!EventQueue.isDispatchThread()) {
70
            throw new IllegalStateException("Not on event thread"); //NOI18N
71
        }
72
        FileObject menuFO = menuFolder;
73
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
74
        JMenuBar bar = new JMenuBar();
75
        bar.setBorderPainted(false);
76
        MenuManager mgr = new MenuManager(menuFolder, bar);
77
        mgr.init();
78
        return bar;
79
    }
80
81
}
(-)1f7b91420663 (+172 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import java.lang.reflect.Array;
44
import java.util.List;
45
import javax.swing.Icon;
46
import javax.swing.JComponent;
47
import javax.swing.JMenuItem;
48
import org.openide.loaders.DataObject;
49
import org.openide.util.ImageUtilities;
50
import org.openide.util.Parameters;
51
52
/**
53
 *
54
 * @author Tim Boudreau
55
 */
56
public abstract class ModelEntry<CompType extends JComponent, DataObjectType extends DataObject> {
57
    private final DataObjectType file;
58
    protected final Class<DataObjectType> dobType;
59
    private Class<CompType> compType;
60
    protected static final Icon BLANK_ICON = ImageUtilities.loadImageIcon("org/openide/loaders/empty.gif", false); // NOI18N
61
    public ModelEntry(DataObjectType file, Class<DataObjectType> dobType, Class<CompType> compType) {
62
        this.file = file;
63
        this.dobType = dobType;
64
        this.compType = compType;
65
        Parameters.notNull("compType", compType);
66
        Parameters.notNull("dobType", dobType);
67
        Parameters.notNull("file", file);
68
    }
69
    
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
71
72
    public String getName() {
73
        return file().getNodeDelegate().getDisplayName();
74
    }
75
76
    protected final DataObjectType file() {
77
        return file;
78
    }
79
80
    final Class<CompType> componentType() {
81
        return compType;
82
    }
83
84
    final CompType[] getComponents() {
85
        if (!EventQueue.isDispatchThread()) {
86
            throw new IllegalStateException ("Not on event thread"); //NOI18N
87
        }
88
        return findComponents();
89
    }
90
91
    final CompType[] refreshComponents(CompType[] old) {
92
        if (!EventQueue.isDispatchThread()) {
93
            throw new IllegalStateException ("Not on event thread"); //NOI18N
94
        }
95
        return refresh (old);
96
    }
97
98
    protected CompType[] refresh (CompType[] old) {
99
        return toCompTypeArray(new Object[] { refreshComponent( old.length == 0 ? null : old[0]) });
100
    }
101
102
    protected CompType[] findComponents() {
103
        return toCompTypeArray (new Object[] { findComponent() });
104
    }
105
106
    protected final CompType[] toCompTypeArray(CompType type) {
107
        return toCompTypeArray (new Object[] { type });
108
    }
109
110
    protected final CompType[] toCompTypeArray(Object[] objs) {
111
        CompType[] c = (CompType[]) Array.newInstance(compType, objs == null ? 0 : objs.length);
112
        System.arraycopy(objs, 0, c, 0, objs.length);
113
        return c;
114
    }
115
116
    protected CompType findComponent() {
117
        throw new UnsupportedOperationException("Override findComponent() " + //NOI18N
118
                "or findComponents() in " + getClass().getName()); //NOI18N
119
    }
120
121
    protected CompType refreshComponent(CompType old) {
122
        throw new UnsupportedOperationException("Override refreshComponent() or " + //NOI18N
123
                "refreshComponents() in "  + getClass().getName()); //NOI18N
124
    }
125
126
    protected static void configureIcon (JComponent comp, boolean wantIcons) {
127
        if (comp instanceof JMenuItem) {
128
            JMenuItem item = (JMenuItem) comp;
129
            Icon icon = item.getIcon();
130
            if (!wantIcons && icon != null) {
131
                item.setIcon(null);
132
            } else if (wantIcons && icon == null) {
133
                item.setIcon (BLANK_ICON);
134
            }
135
        }
136
    }
137
138
    protected static Boolean defaultHasIcon (JComponent comp, Boolean hasIcon) {
139
        if (hasIcon != null && hasIcon) {
140
            return hasIcon;
141
        }
142
        if (comp instanceof JMenuItem) {
143
            Icon icon = ((JMenuItem) comp).getIcon();
144
            if (icon != null && BLANK_ICON != icon) {
145
                return true;
146
            }
147
        }
148
        return null;
149
    }
150
151
    @Override
152
    public boolean equals(Object obj) {
153
        if (obj == null) {
154
            return false;
155
        }
156
        if (getClass() != obj.getClass()) {
157
            return false;
158
        }
159
        final ModelEntry<?, ?> other = (ModelEntry<?, ?>) obj;
160
        if (this.file() != other.file() && (this.file() == null || !this.file().equals(other.file()))) {
161
            return false;
162
        }
163
        return true;
164
    }
165
166
    @Override
167
    public int hashCode() {
168
        int hash = 3;
169
        hash = 31 * hash + (this.file != null ? this.file.hashCode() : 0);
170
        return hash;
171
    }
172
}
(-)1f7b91420663 (+86 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.io.IOException;
44
import javax.swing.JComponent;
45
import javax.swing.JMenuItem;
46
import org.openide.awt.DynamicMenuContent;
47
import org.openide.loaders.DataObject;
48
import org.openide.util.Exceptions;
49
import org.openide.util.actions.Presenter;
50
51
/**
52
 *
53
 * @author Tim Boudreau
54
 */
55
public class PresenterEntry extends ThreadUnconstrainedModelEntry<Presenter.Menu, JComponent> {
56
    private DynamicMenuContent dmc;
57
    PresenterEntry (DataObject dob) {
58
        super (dob, JComponent.class, Presenter.Menu.class);
59
    }
60
61
    @Override
62
    protected JComponent[] findComponents() {
63
        try {
64
            Presenter.Menu p = super.get();
65
            JMenuItem c = p.getMenuPresenter();
66
            if (c instanceof DynamicMenuContent) { //ToolsAction.Inline
67
                dmc = (DynamicMenuContent) c;
68
                return dmc.getMenuPresenters();
69
            }
70
            return new JComponent[] { c };
71
        } catch (IOException ex) {
72
            Exceptions.printStackTrace(ex);
73
        } catch (ClassNotFoundException ex) {
74
            Exceptions.printStackTrace(ex);
75
        }
76
        return new JComponent[] { new JMenuItem("Error fetching " + file().getName()) }; //XXX
77
    }
78
79
    @Override
80
    protected JComponent[] refresh(JComponent[] old) {
81
        if (dmc != null) {
82
            return dmc.synchMenuPresenters(old);
83
        }
84
        return old;
85
    }
86
}
(-)1f7b91420663 (+69 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.util.List;
43
import javax.swing.JSeparator;
44
import org.openide.loaders.DataObject;
45
46
/**
47
 *
48
 * @author Tim Boudreau
49
 */
50
final class SeparatorModelEntry extends FileModelEntry <JSeparator, JSeparator> {
51
    SeparatorModelEntry(DataObject dob) {
52
        super (dob, JSeparator.class, JSeparator.class);
53
    }
54
55
    @Override
56
    protected JSeparator findComponent() {
57
        return new JSeparator();
58
    }
59
60
    @Override
61
    protected JSeparator refreshComponent(JSeparator old) {
62
        return old == null ? findComponent() : old;
63
    }
64
65
    @Override
66
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
67
        return false;
68
    }
69
}
(-)1f7b91420663 (+83 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.io.IOException;
43
import java.util.List;
44
import java.util.concurrent.atomic.AtomicReference;
45
import javax.swing.JComponent;
46
import org.openide.loaders.DataObject;
47
import org.openide.util.Exceptions;
48
49
/**
50
 *
51
 * @author Tim Boudreau
52
 */
53
public abstract class ThreadUnconstrainedModelEntry<T, CompType extends JComponent> extends FileModelEntry<T, CompType> {
54
    private final AtomicReference<T> ref = new AtomicReference<T>();
55
56
    ThreadUnconstrainedModelEntry(DataObject dob, Class<CompType> componentType, Class<T> modelObjectType) {
57
        super(dob, componentType, modelObjectType);
58
    }
59
60
    @Override
61
    protected final T get() throws IOException, ClassNotFoundException {
62
        T result = ref.get();
63
        if (result == null) {
64
            result = super.get();
65
            ref.set(result);
66
        }
67
        return result;
68
    }
69
70
    @Override
71
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
72
        //Since it is non-gui, instantiate the Action in the background
73
        try {
74
            ref.set(super.get());
75
        } catch (IOException ex) {
76
            Exceptions.printStackTrace(ex);
77
        } catch (ClassNotFoundException ex) {
78
            Exceptions.printStackTrace(ex);
79
        }
80
        return false;
81
    }
82
83
}
(-)1f7b91420663 (+7 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        
6
    </folder>
7
</filesystem>
(-)1f7b91420663 (+84 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import javax.swing.JComponent;
43
import javax.swing.JMenu;
44
import javax.swing.JMenuItem;
45
import org.openide.awt.DynamicMenuContent;
46
47
/**
48
 *
49
 * @author Tim Boudreau
50
 */
51
public class DynAction implements DynamicMenuContent {
52
    private static final int count = 5;
53
    static int total;
54
    final int index;
55
    public DynAction() {
56
        index = total++;
57
    }
58
59
    @Override
60
    public JComponent[] getMenuPresenters() {
61
        JComponent[] result = new JComponent[count];
62
        for (int i= 0; i < result.length; i++) {
63
            JMenuItem j = new JMenuItem ("Dynamic " + index + ":" + i);
64
            j.putClientProperty("caption", j.getText());
65
            j.putClientProperty("syncCount", 0);
66
            result[i] = j;
67
        }
68
        return result;
69
    }
70
71
    @Override
72
    public JComponent[] synchMenuPresenters(JComponent[] items) {
73
        for (JComponent jc : items) {
74
            JMenuItem m = (JMenuItem) jc;
75
            String cap = (String) m.getClientProperty("caption");
76
            int syncs = ((Integer) m.getClientProperty("syncCount")).intValue();
77
            syncs ++;
78
            m.putClientProperty("syncCount", syncs);
79
            m.setText (cap + " (sync " + syncs + ")");
80
        }
81
        return items;
82
    }
83
84
}
(-)1f7b91420663 (+203 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.Component;
42
import java.awt.Dimension;
43
import java.awt.EventQueue;
44
import java.awt.event.ContainerEvent;
45
import java.awt.event.ContainerListener;
46
import java.awt.event.MouseEvent;
47
import java.lang.ref.Reference;
48
import java.lang.ref.WeakReference;
49
import java.util.ArrayList;
50
import java.util.List;
51
import java.util.concurrent.CountDownLatch;
52
import java.util.concurrent.TimeUnit;
53
import javax.swing.AbstractButton;
54
import javax.swing.JComponent;
55
import javax.swing.JFrame;
56
import javax.swing.JMenu;
57
import javax.swing.JMenuBar;
58
import javax.swing.JMenuItem;
59
import javax.swing.JPanel;
60
import javax.swing.JPopupMenu;
61
import org.junit.Test;
62
import org.netbeans.junit.NbTestCase;
63
import org.openide.filesystems.FileSystem;
64
import org.openide.filesystems.XMLFileSystem;
65
66
/**
67
 *
68
 * @author tim
69
 */
70
public class MenuProviderImplTest extends NbTestCase {
71
72
    private MenuProviderImpl m;
73
    private JMenuBar bar;
74
    private JFrame jf;
75
    private JMenu menu;
76
77
    public MenuProviderImplTest(String name) {
78
        super(name);
79
    }
80
81
    @Override
82
    protected boolean runInEQ() {
83
        return false;
84
    }
85
86
    @Override
87
    public void setUp() throws Exception {
88
        FileSystem fs = new XMLFileSystem(MenuProviderImplTest.class.getResource("fakelayer.xml"));
89
        m = new MenuProviderImpl(fs.getRoot().getFileObject("Menu"));
90
        R r = new R();
91
92
        EventQueue.invokeAndWait(r);
93
        r.latch.await(20000, TimeUnit.MILLISECONDS);
94
        while (!jf.isShowing()) {
95
            Thread.sleep(30);
96
        }
97
        assertFalse(bar.getMenuCount() == 0);
98
        menu = bar.getMenu(0);
99
    }
100
101
    @Override
102
    public void tearDown() {
103
        jf.dispose();
104
    }
105
106
    private void click(final JComponent comp, final boolean showMenu) throws Exception {
107
        EventQueue.invokeAndWait(new Runnable() {
108
109
            public void run() {
110
                ((AbstractButton) comp).getModel().setPressed(showMenu);
111
                MouseEvent evt = new MouseEvent(comp, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
112
                        0, 5, 5, 1, false, 0);
113
                comp.dispatchEvent(evt);
114
                evt = new MouseEvent(comp, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
115
                        0, 5, 5, 1, false, 0);
116
                comp.dispatchEvent(evt);
117
                evt = new MouseEvent(comp, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(),
118
                        0, 5, 5, 1, false, 0);
119
                comp.dispatchEvent(evt);
120
            }
121
        });
122
        if (comp instanceof JMenu) {
123
            JMenu m = (JMenu) comp;
124
            while (showMenu != m.getPopupMenu().isShowing()) {
125
                Thread.sleep (100);
126
            }
127
        }
128
    }
129
130
    @Test
131
    public void testMenuItemsAreNotStronglyReferenced() throws Exception {
132
        assertNotNull (menu);
133
        click (menu, true);
134
        JPopupMenu popup = menu.getPopupMenu();
135
        Component[] c = popup.getComponents();
136
        assertEquals (7, c.length);
137
        List<Reference<Component>> l = new ArrayList<Reference<Component>>();
138
        boolean presenterActionFound = false;
139
        boolean regularActionFound = false;
140
        int pActionIx = -1;
141
        int rActionIx = -1;
142
        for (int i=0; i < c.length; i++) {
143
            Component cc = c[i];
144
            boolean wasPactionFound = presenterActionFound;
145
            presenterActionFound |= cc instanceof PresenterAction.Marker;
146
            if (!wasPactionFound && presenterActionFound) {
147
                pActionIx = i;
148
            }
149
            l.add (new WeakReference<Component>(cc));
150
            boolean wasRactionFound = regularActionFound;
151
            regularActionFound |= cc instanceof JMenuItem && ((JMenuItem) cc).getText().equals("Regular Action");
152
            if (!wasRactionFound && regularActionFound) {
153
                rActionIx = i;
154
            }
155
        }
156
        //Test order while we're here
157
        assertTrue (presenterActionFound);
158
        assertTrue (regularActionFound);
159
        assertEquals ("Wrong index for presenter action", 5, pActionIx);
160
        assertEquals ("Wrong index for presenter action", 6, rActionIx);
161
        click (menu, false);
162
        c = null;
163
        for (Reference<?> r : l) {
164
            assertGC("Menu component not collected", r);
165
        }
166
    }
167
    private static final int EXPECTED_MENU_COUNT = 1; //update if more added to xml
168
169
    private class R implements Runnable, ContainerListener {
170
171
        private final CountDownLatch latch = new CountDownLatch(1);
172
173
        @Override
174
        public void run() {
175
            jf = new JFrame();
176
            bar = m.createMenu(jf);
177
            bar.addContainerListener(this);
178
            JPanel pnl = new JPanel();
179
            pnl.setMinimumSize(new Dimension(300, 300));
180
            pnl.setPreferredSize(new Dimension(300, 300));
181
            jf.setContentPane(pnl);
182
            jf.setJMenuBar(bar);
183
            jf.pack();
184
            jf.setVisible(true);
185
        }
186
187
        @Override
188
        public void componentAdded(ContainerEvent e) {
189
            int count = e.getContainer().getComponentCount();
190
            if (count == EXPECTED_MENU_COUNT) {
191
                latch.countDown();
192
                e.getContainer().invalidate();
193
                ((JMenuBar) e.getContainer()).revalidate();
194
                e.getContainer().repaint();
195
            }
196
        }
197
198
        @Override
199
        public void componentRemoved(ContainerEvent e) {
200
            //do nothing
201
        }
202
    }
203
}
(-)1f7b91420663 (+69 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import javax.swing.JMenuItem;
45
import org.openide.util.actions.Presenter;
46
47
/**
48
 *
49
 * @author Tim Boudreau
50
 */
51
public class PresenterAction extends AbstractAction implements Presenter.Menu {
52
53
    @Override
54
    public JMenuItem getMenuPresenter() {
55
        return new Marker ("Menu Presenter");
56
    }
57
58
    @Override
59
    public void actionPerformed(ActionEvent e) {
60
        throw new UnsupportedOperationException("Not supported yet.");
61
    }
62
63
    public class Marker extends JMenuItem {
64
        Marker (String s) {
65
            super (s);
66
        }
67
    }
68
69
}
(-)1f7b91420663 (+59 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
45
/**
46
 *
47
 * @author Tim Boudreau
48
 */
49
public class RegularAction extends AbstractAction {
50
    private boolean performed;
51
    public RegularAction() {
52
        putValue (NAME, "Regular Action");
53
    }
54
55
    @Override
56
    public void actionPerformed(ActionEvent e) {
57
        performed = true;
58
    }
59
}
(-)1f7b91420663 (+17 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="One">
6
            <file name="org-netbeans-core-menu-DynAction.instance">
7
                <attr name="position" intvalue="0"/>
8
            </file>
9
            <file name="org-netbeans-core-menu-PresenterAction.instance">
10
                <attr name="position" intvalue="1"/>
11
            </file>
12
            <file name="org-netbeans-core-menu-RegularAction.instance">
13
                <attr name="position" intvalue="2"/>
14
            </file>
15
        </folder>
16
    </folder>
17
</filesystem>
(-)a/nbbuild/cluster.properties (+2 lines)
Lines 184-189 Link Here
184
nb.cluster.platform.depends=
184
nb.cluster.platform.depends=
185
nb.cluster.platform=\
185
nb.cluster.platform=\
186
        api.annotations.common,\
186
        api.annotations.common,\
187
        api.menus,\
187
        api.progress,\
188
        api.progress,\
188
        api.visual,\
189
        api.visual,\
189
        applemenu,\
190
        applemenu,\
Lines 192-197 Link Here
192
        core.execution,\
193
        core.execution,\
193
        core.io.ui,\
194
        core.io.ui,\
194
        core.kit,\
195
        core.kit,\
196
        core.menu,\
195
        core.multiview,\
197
        core.multiview,\
196
        core.nativeaccess,\
198
        core.nativeaccess,\
197
        core.netigso,\
199
        core.netigso,\
(-)a/core.windows/manifest.mf (-1 / +1 lines)
Lines 6-10 Link Here
6
OpenIDE-Module-Recommends: org.netbeans.core.windows.nativeaccess.NativeWindowSystem
6
OpenIDE-Module-Recommends: org.netbeans.core.windows.nativeaccess.NativeWindowSystem
7
AutoUpdate-Show-In-Client: false
7
AutoUpdate-Show-In-Client: false
8
AutoUpdate-Essential-Module: true
8
AutoUpdate-Essential-Module: true
9
OpenIDE-Module-Specification-Version: 2.20
9
OpenIDE-Module-Specification-Version: 2.21
10
10
(-)a/core.windows/nbproject/project.xml (+9 lines)
Lines 47-52 Link Here
47
            <code-name-base>org.netbeans.core.windows</code-name-base>
47
            <code-name-base>org.netbeans.core.windows</code-name-base>
48
            <module-dependencies>
48
            <module-dependencies>
49
                <dependency>
49
                <dependency>
50
                    <code-name-base>org.netbeans.api.menus</code-name-base>
51
                    <build-prerequisite/>
52
                    <compile-dependency/>
53
                    <run-dependency>
54
                        <release-version>1</release-version>
55
                        <specification-version>1.0</specification-version>
56
                    </run-dependency>
57
                </dependency>
58
                <dependency>
50
                    <code-name-base>org.netbeans.core</code-name-base>
59
                    <code-name-base>org.netbeans.core</code-name-base>
51
                    <build-prerequisite/>
60
                    <build-prerequisite/>
52
                    <compile-dependency/>
61
                    <compile-dependency/>
(-)a/core.windows/src/org/netbeans/core/windows/WindowSystemImpl.java (-3 lines)
Lines 45-53 Link Here
45
45
46
import java.awt.EventQueue;
46
import java.awt.EventQueue;
47
import org.netbeans.core.WindowSystem;
47
import org.netbeans.core.WindowSystem;
48
import org.netbeans.core.windows.persistence.PersistenceManager;
49
import org.netbeans.core.windows.services.DialogDisplayerImpl;
48
import org.netbeans.core.windows.services.DialogDisplayerImpl;
50
import org.netbeans.core.windows.view.ui.MainWindow;
51
import org.openide.util.lookup.ServiceProvider;
49
import org.openide.util.lookup.ServiceProvider;
52
50
53
51
Lines 61-67 Link Here
61
59
62
    public void init() {
60
    public void init() {
63
        assert !EventQueue.isDispatchThread();
61
        assert !EventQueue.isDispatchThread();
64
        MainWindow.init();
65
    }
62
    }
66
63
67
    public void load() {
64
    public void load() {
(-)a/core.windows/src/org/netbeans/core/windows/view/ViewHierarchy.java (+1 lines)
Lines 122-127 Link Here
122
    public MainWindow getMainWindow() {
122
    public MainWindow getMainWindow() {
123
        if (mainWindow == null) {
123
        if (mainWindow == null) {
124
            mainWindow = new MainWindow();
124
            mainWindow = new MainWindow();
125
            mainWindow.init();
125
        }
126
        }
126
        return mainWindow;
127
        return mainWindow;
127
    }
128
    }
(-)a/core.windows/src/org/netbeans/core/windows/view/ui/MainWindow.java (-2 / +7 lines)
Lines 62-67 Link Here
62
import javax.swing.JPanel;
62
import javax.swing.JPanel;
63
import javax.swing.border.*;
63
import javax.swing.border.*;
64
import javax.swing.event.*;
64
import javax.swing.event.*;
65
import org.netbeans.api.menus.MenuProvider;
65
import org.netbeans.core.windows.*;
66
import org.netbeans.core.windows.*;
66
import org.netbeans.core.windows.view.ui.toolbars.ToolbarConfiguration;
67
import org.netbeans.core.windows.view.ui.toolbars.ToolbarConfiguration;
67
import org.openide.LifecycleManager;
68
import org.openide.LifecycleManager;
Lines 138-144 Link Here
138
        }
139
        }
139
    }
140
    }
140
141
141
    public static void init() {
142
    public void init() {
142
        if (mainMenuBar == null) {
143
        if (mainMenuBar == null) {
143
            mainMenuBar = createMenuBar();
144
            mainMenuBar = createMenuBar();
144
            ToolbarPool.getDefault().waitFinished();
145
            ToolbarPool.getDefault().waitFinished();
Lines 365-372 Link Here
365
        );
366
        );
366
    }
367
    }
367
368
369
    private JMenuBar createMenuBar() {
370
        return MenuProvider.installMenu(this);
371
    }
372
368
    /** Creates menu bar. */
373
    /** Creates menu bar. */
369
    private static JMenuBar createMenuBar() {
374
    private static JMenuBar xcreateMenuBar() {
370
        JMenuBar menu = getCustomMenuBar();
375
        JMenuBar menu = getCustomMenuBar();
371
        if (menu == null) {
376
        if (menu == null) {
372
             menu = new MenuBar (null);
377
             menu = new MenuBar (null);
(-)a/core.menu/src/org/netbeans/core/menu/FolderModelEntry.java (-2 / +6 lines)
Lines 52-57 Link Here
52
import java.util.Set;
52
import java.util.Set;
53
import javax.swing.Action;
53
import javax.swing.Action;
54
import javax.swing.JComponent;
54
import javax.swing.JComponent;
55
import javax.swing.JMenuItem;
55
import javax.swing.JSeparator;
56
import javax.swing.JSeparator;
56
import org.openide.awt.DynamicMenuContent;
57
import org.openide.awt.DynamicMenuContent;
57
import org.openide.cookies.InstanceCookie;
58
import org.openide.cookies.InstanceCookie;
Lines 267-272 Link Here
267
            if (icons != null) {
268
            if (icons != null) {
268
                ModelEntry.configureIcon(c, icons);
269
                ModelEntry.configureIcon(c, icons);
269
            }
270
            }
271
            if (c instanceof JMenuItem) {
272
                c.setToolTipText(null);
273
            }
270
        }
274
        }
271
    }
275
    }
272
276
Lines 299-305 Link Here
299
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
303
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
300
        }
304
        }
301
305
302
        ModelEntry<?, ?> createEntry(DataObject ob, Callback callback) {
306
        ModelEntry<?, ?> createEntry(DataObject ob, FolderModelEntry entry) {
303
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
307
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
304
            switch (this) {
308
            switch (this) {
305
                case SEPARATOR:
309
                case SEPARATOR:
Lines 325-331 Link Here
325
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
329
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
326
                            : ob.getLookup().lookup(DataFolder.class);
330
                            : ob.getLookup().lookup(DataFolder.class);
327
                    Parameters.notNull("folder was non-null but is now null", fld);
331
                    Parameters.notNull("folder was non-null but is now null", fld);
328
                    return new MenuEntry(fld, null);
332
                    return new MenuEntry(fld, MenuManager.rp);
329
                case COMPONENT:
333
                case COMPONENT:
330
                    return new ComponentModelEntry(ob);
334
                    return new ComponentModelEntry(ob);
331
                default:
335
                default:
(-)a/core.menu/src/org/netbeans/core/menu/MenuBarModel.java (-88 / +4 lines)
Lines 39-52 Link Here
39
39
40
package org.netbeans.core.menu;
40
package org.netbeans.core.menu;
41
41
42
import java.awt.EventQueue;
43
import java.util.LinkedList;
44
import java.util.List;
45
import javax.swing.JMenuBar;
42
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
49
import org.openide.filesystems.FileRenameEvent;
50
import org.openide.loaders.DataFolder;
43
import org.openide.loaders.DataFolder;
51
import org.openide.util.RequestProcessor;
44
import org.openide.util.RequestProcessor;
52
45
Lines 54-73 Link Here
54
 *
47
 *
55
 * @author Tim Boudreau
48
 * @author Tim Boudreau
56
 */
49
 */
57
final class MenuBarModel extends FolderModelEntry<JMenuBar> {
50
final class MenuBarModel extends RefreshingFolderModelEntry<JMenuBar> {
58
    private final JMenuBar bar;
51
    private final JMenuBar bar;
59
    private FCA fca = new FCA();
60
    private final RequestProcessor.Task task;
61
    private static final int DELAY = 100;
62
    MenuBarModel (DataFolder rootFolder, JMenuBar bar, RequestProcessor rp) {
52
    MenuBarModel (DataFolder rootFolder, JMenuBar bar, RequestProcessor rp) {
63
        super (rootFolder, JMenuBar.class);
53
        super (rootFolder, JMenuBar.class, rp);
64
        this.bar = bar;
54
        this.bar = bar;
65
        this.task = rp.create(fca);
66
        rootFolder.getPrimaryFile().addFileChangeListener(fca);
67
    }
68
69
    void init() {
70
        fca.refresh();
71
    }
55
    }
72
56
73
    @Override
57
    @Override
Lines 76-150 Link Here
76
    }
60
    }
77
61
78
    @Override
62
    @Override
79
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
63
    JMenuBar cachedComponent() {
80
        super.onInitBackground(children);
64
        return bar;
81
        if (!refreshing) {
82
            EventQueue.invokeLater(fca);
83
        }
84
    }
85
86
    volatile boolean refreshing;
87
    private final class FCA extends FileChangeAdapter implements Runnable {
88
        private volatile boolean enqueued;
89
        boolean refresh() {
90
            boolean result;
91
            synchronized (this) {
92
                result = enqueued;
93
                if (!enqueued) {
94
                    enqueued = true;
95
                    task.schedule(DELAY);
96
                }
97
                return result;
98
            }
99
        }
100
101
        @Override
102
        public void run() {
103
            if (!EventQueue.isDispatchThread()) {
104
                refreshing = true;
105
                try {
106
                    List<ModelEntry<?,?>> l = new LinkedList<ModelEntry<?,?>>();
107
                    initBackground(l);
108
                    setChildren(l);
109
                } finally {
110
                    refreshing = false;
111
                    EventQueue.invokeLater(this);
112
                }
113
            } else {
114
                enqueued = false;
115
                bar.removeAll();
116
                MenuBarModel.this.refresh(new JMenuBar[] { bar });
117
            }
118
        }
119
120
        @Override
121
        public void fileAttributeChanged(FileAttributeEvent fe) {
122
            refresh();
123
        }
124
125
        @Override
126
        public void fileChanged(FileEvent fe) {
127
            refresh();
128
        }
129
130
        @Override
131
        public void fileDataCreated(FileEvent fe) {
132
            refresh();
133
        }
134
135
        @Override
136
        public void fileDeleted(FileEvent fe) {
137
            refresh();
138
        }
139
140
        @Override
141
        public void fileFolderCreated(FileEvent fe) {
142
            refresh();
143
        }
144
145
        @Override
146
        public void fileRenamed(FileRenameEvent fe) {
147
            refresh();
148
        }
149
    }
65
    }
150
}
66
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuEntry.java (-13 / +15 lines)
Lines 42-66 Link Here
42
import java.awt.EventQueue;
42
import java.awt.EventQueue;
43
import java.lang.ref.Reference;
43
import java.lang.ref.Reference;
44
import java.lang.ref.WeakReference;
44
import java.lang.ref.WeakReference;
45
import java.util.concurrent.atomic.AtomicBoolean;
45
import javax.swing.ButtonModel;
46
import javax.swing.ButtonModel;
46
import javax.swing.JMenu;
47
import javax.swing.JMenu;
47
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeListener;
49
import javax.swing.event.ChangeListener;
49
import org.openide.awt.Mnemonics;
50
import org.openide.awt.Mnemonics;
50
import org.openide.loaders.DataFolder;
51
import org.openide.loaders.DataFolder;
52
import org.openide.util.RequestProcessor;
51
53
52
/**
54
/**
53
 *
55
 *
54
 * @author Tim Boudreau
56
 * @author Tim Boudreau
55
 */
57
 */
56
final class MenuEntry extends FolderModelEntry<JMenu> implements ChangeListener {
58
final class MenuEntry extends RefreshingFolderModelEntry<JMenu> implements ChangeListener {
57
58
    private Reference<JMenu> menu;
59
    private Reference<JMenu> menu;
59
    private final Callback callback;
60
    MenuEntry (DataFolder fld, RequestProcessor rp) {
60
61
        super (fld, JMenu.class, rp);
61
    MenuEntry (DataFolder fld, Callback callback) {
62
        super (fld, JMenu.class);
63
        this.callback = callback == null ? this : callback;
64
    }
62
    }
65
63
66
    private JMenu menu() {
64
    private JMenu menu() {
Lines 81-86 Link Here
81
    }
79
    }
82
80
83
    private boolean wasSelected = false;
81
    private boolean wasSelected = false;
82
    private AtomicBoolean showing = new AtomicBoolean();
84
    @Override
83
    @Override
85
    public void stateChanged(ChangeEvent e) {
84
    public void stateChanged(ChangeEvent e) {
86
        ButtonModel mdl = (ButtonModel) e.getSource();
85
        ButtonModel mdl = (ButtonModel) e.getSource();
Lines 88-106 Link Here
88
        //XXX wasSelected could be true if the old component was garbage collected
87
        //XXX wasSelected could be true if the old component was garbage collected
89
        //without resetting its model - possible?
88
        //without resetting its model - possible?
90
        if (selected && !wasSelected) {
89
        if (selected && !wasSelected) {
91
            if (callback != null) {
90
            showing.set(true);
92
                callback.onShow(this);
91
            onShow(this);
93
            }
94
            refreshComponent(menu());
92
            refreshComponent(menu());
95
        } else if (wasSelected && !selected) {
93
        } else if (wasSelected && !selected) {
94
            showing.set(false);
96
            JMenu m = menu == null ? null : menu.get();
95
            JMenu m = menu == null ? null : menu.get();
97
            if (m != null) {
96
            if (m != null) {
98
                m.removeAll();
97
                m.removeAll();
99
            }
98
            }
100
            if (callback != null) {
99
            onHide(this);
101
                callback.onHide(this);
102
            }
103
        }
100
        }
104
        wasSelected = selected;
101
        wasSelected = selected;
105
    }
102
    }
103
104
    @Override
105
    JMenu cachedComponent() {
106
        return menu();
107
    }
106
}
108
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuManager.java (-1 / +2 lines)
Lines 49-55 Link Here
49
 */
49
 */
50
final class MenuManager {
50
final class MenuManager {
51
    private final JMenuBar bar;
51
    private final JMenuBar bar;
52
    private final RequestProcessor rp = new RequestProcessor("Main Menu Refresh", 1, true);
52
    //XXX make this non-static and pass to model entries
53
    static final RequestProcessor rp = new RequestProcessor("Main Menu Refresh", 1, true);
53
    private final MenuBarModel model;
54
    private final MenuBarModel model;
54
55
55
    MenuManager(DataFolder folder, JMenuBar bar) {
56
    MenuManager(DataFolder folder, JMenuBar bar) {
(-)fa24874d2b7b (+155 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.EventQueue;
42
import java.util.LinkedList;
43
import java.util.List;
44
import javax.swing.JComponent;
45
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
49
import org.openide.filesystems.FileObject;
50
import org.openide.filesystems.FileRenameEvent;
51
import org.openide.filesystems.FileUtil;
52
import org.openide.loaders.DataFolder;
53
import org.openide.util.RequestProcessor;
54
55
/**
56
 *
57
 * @author Tim Boudreau
58
 */
59
abstract class RefreshingFolderModelEntry<T extends JComponent> extends FolderModelEntry<T> {
60
61
    private final RequestProcessor.Task task;
62
    private FCA fca = new FCA();
63
    private static final int DELAY = 100;
64
65
    RefreshingFolderModelEntry(DataFolder dob, Class<T> compType, RequestProcessor rp) {
66
        super(dob, compType);
67
        this.task = rp.create(fca);
68
        FileObject fo = dob.getPrimaryFile();
69
        fo.addFileChangeListener(FileUtil.weakFileChangeListener(fca, fo));
70
    }
71
72
    @Override
73
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
74
        super.onInitBackground(children);
75
        if (!refreshing) {
76
            EventQueue.invokeLater(fca);
77
        }
78
    }
79
80
    abstract T cachedComponent();
81
82
    void init() {
83
        fca.refresh();
84
    }
85
    volatile boolean refreshing;
86
87
    private final class FCA extends FileChangeAdapter implements Runnable {
88
89
        private volatile boolean enqueued;
90
91
        boolean refresh() {
92
            boolean result;
93
            synchronized (this) {
94
                result = enqueued;
95
                if (!enqueued) {
96
                    enqueued = true;
97
                    task.schedule(DELAY);
98
                }
99
                return result;
100
            }
101
        }
102
103
        @Override
104
        public void run() {
105
            if (!EventQueue.isDispatchThread()) {
106
                refreshing = true;
107
                try {
108
                    List<ModelEntry<?, ?>> l = new LinkedList<ModelEntry<?, ?>>();
109
                    initBackground(l);
110
                    setChildren(l);
111
                } finally {
112
                    refreshing = false;
113
                    EventQueue.invokeLater(this);
114
                }
115
            } else {
116
                enqueued = false;
117
                T comp = cachedComponent();
118
                if (comp != null) {
119
                    comp.removeAll();
120
                    RefreshingFolderModelEntry.this.refresh(toCompTypeArray(new Object[]{comp}));
121
                }
122
            }
123
        }
124
125
        @Override
126
        public void fileAttributeChanged(FileAttributeEvent fe) {
127
            refresh();
128
        }
129
130
        @Override
131
        public void fileChanged(FileEvent fe) {
132
            refresh();
133
        }
134
135
        @Override
136
        public void fileDataCreated(FileEvent fe) {
137
            refresh();
138
        }
139
140
        @Override
141
        public void fileDeleted(FileEvent fe) {
142
            refresh();
143
        }
144
145
        @Override
146
        public void fileFolderCreated(FileEvent fe) {
147
            refresh();
148
        }
149
150
        @Override
151
        public void fileRenamed(FileRenameEvent fe) {
152
            refresh();
153
        }
154
    }
155
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuEntry.java (+14 lines)
Lines 78-83 Link Here
78
        return menu();
78
        return menu();
79
    }
79
    }
80
80
81
    @Override
82
    protected void onRefresh(JMenu[] newComps) {
83
        if (showing.get()) {
84
            JMenu m = menu();
85
            if (m != null && m.isPopupMenuVisible()) {
86
                m.setPopupMenuVisible(false);
87
                m.invalidate();
88
                m.revalidate();
89
                m.repaint();
90
                m.setPopupMenuVisible(true);
91
            }
92
        }
93
    }
94
81
    private boolean wasSelected = false;
95
    private boolean wasSelected = false;
82
    private AtomicBoolean showing = new AtomicBoolean();
96
    private AtomicBoolean showing = new AtomicBoolean();
83
    @Override
97
    @Override
(-)a/core.menu/src/org/netbeans/core/menu/ModelEntry.java (-2 / +9 lines)
Lines 70-76 Link Here
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
71
71
72
    public String getName() {
72
    public String getName() {
73
        return file().getNodeDelegate().getDisplayName();
73
        DataObject file = file();
74
        return file.isValid() ? file.getNodeDelegate().getDisplayName() : file.getName();
74
    }
75
    }
75
76
76
    protected final DataObjectType file() {
77
    protected final DataObjectType file() {
Lines 95-102 Link Here
95
        return refresh (old);
96
        return refresh (old);
96
    }
97
    }
97
98
99
    protected void onRefresh (CompType[] newComps) {
100
        
101
    }
102
98
    protected CompType[] refresh (CompType[] old) {
103
    protected CompType[] refresh (CompType[] old) {
99
        return toCompTypeArray(new Object[] { refreshComponent( old.length == 0 ? null : old[0]) });
104
        CompType[] result = toCompTypeArray(new Object[] { refreshComponent( old.length == 0 ? null : old[0]) });
105
        onRefresh (result);
106
        return result;
100
    }
107
    }
101
108
102
    protected CompType[] findComponents() {
109
    protected CompType[] findComponents() {
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class AAction extends AbstractAction {
53
    public AAction() {
54
        putValue (NAME, "A");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class ABAction extends AbstractAction {
53
    public ABAction() {
54
        putValue (NAME, "AB");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A, Layers.B);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class ABCAction extends AbstractAction {
53
    public ABCAction() {
54
        putValue (NAME, "ABC");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A, Layers.B, Layers.C);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class ABCDAction extends AbstractAction {
53
    public ABCDAction() {
54
        putValue (NAME, "ABCD");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A, Layers.B, Layers.C, Layers.D);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+96 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.AWTEvent;
43
import static java.awt.AWTEvent.*;
44
import java.awt.Component;
45
import java.awt.Toolkit;
46
import java.awt.event.AWTEventListener;
47
import java.awt.event.MouseEvent;
48
import java.lang.reflect.InvocationTargetException;
49
import java.lang.reflect.Method;
50
import org.openide.util.Exceptions;
51
52
/**
53
 * Blocks real input events from the user, so user's focus behavior cannot
54
 * affect tests
55
 *
56
 * @author Tim Boudreau
57
 */
58
public class EventBlocker implements AWTEventListener {
59
    private static final long MASK = FOCUS_EVENT_MASK | MOUSE_EVENT_MASK | MOUSE_MOTION_EVENT_MASK | MOUSE_WHEEL_EVENT_MASK | 
60
            KEY_EVENT_MASK | ACTION_EVENT_MASK | ADJUSTMENT_EVENT_MASK | 
61
            INPUT_METHOD_EVENT_MASK | ITEM_EVENT_MASK | TEXT_EVENT_MASK;
62
    static void init() {
63
        Toolkit.getDefaultToolkit().addAWTEventListener(new EventBlocker(), MASK);
64
    }
65
66
    @Override
67
    public void eventDispatched(AWTEvent event) {
68
        Class<?> c = event.getClass();
69
        if (event instanceof ME) {
70
            return;
71
        }
72
        try {
73
            Method m = c.getMethod("consume");
74
            try {
75
                m.invoke(event);
76
            } catch (IllegalAccessException ex) {
77
            } catch (IllegalArgumentException ex) {
78
            } catch (InvocationTargetException ex) {
79
            }
80
        } catch (NoSuchMethodException ex) {
81
        } catch (SecurityException ex) {
82
        }
83
    }
84
85
    public static MouseEvent mouseEvent (Component c, int id) {
86
        return new ME(c, id);
87
    }
88
89
    private static final class ME extends MouseEvent {
90
        ME(Component comp, int id) {
91
            super (comp, id, System.currentTimeMillis(),
92
                        0, 5, 5, 1, false, 0);
93
        }
94
    }
95
96
}
(-)d76d479b5dc8 (+303 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.Component;
42
import java.awt.Dimension;
43
import java.awt.EventQueue;
44
import java.awt.event.ContainerEvent;
45
import java.awt.event.ContainerListener;
46
import java.awt.event.MouseEvent;
47
import java.net.URL;
48
import java.util.Arrays;
49
import java.util.concurrent.CountDownLatch;
50
import java.util.concurrent.TimeUnit;
51
import java.util.concurrent.atomic.AtomicBoolean;
52
import java.util.concurrent.atomic.AtomicInteger;
53
import javax.swing.AbstractButton;
54
import javax.swing.JComponent;
55
import javax.swing.JFrame;
56
import javax.swing.JMenu;
57
import javax.swing.JMenuBar;
58
import javax.swing.JPanel;
59
import javax.swing.JPopupMenu;
60
import org.junit.Test;
61
import org.netbeans.junit.NbTestCase;
62
import org.openide.filesystems.FileSystem;
63
import org.openide.filesystems.MultiFileSystem;
64
import org.openide.filesystems.XMLFileSystem;
65
import org.xml.sax.SAXException;
66
67
/**
68
 *
69
 * @author tim
70
 */
71
public class FileChangeTest extends NbTestCase {
72
73
    private MenuProviderImpl m;
74
    private JMenuBar bar;
75
    private JFrame jf;
76
    private JMenu menu;
77
78
79
    public FileChangeTest(String name) {
80
        super(name);
81
    }
82
83
    @Override
84
    protected boolean runInEQ() {
85
        return false;
86
    }
87
88
    @Override
89
    public void setUp() throws Exception {
90
        FileSystem fs = new MFS();
91
        m = new MenuProviderImpl(fs.getRoot().getFileObject("Menu"));
92
        R r = new R();
93
94
        EventQueue.invokeAndWait(r);
95
        r.latch.await(20000, TimeUnit.MILLISECONDS);
96
        while (!jf.isShowing()) {
97
            Thread.sleep(30);
98
        }
99
        while (bar.getMenuCount() < 2) {
100
            Thread.sleep(30);
101
        }
102
        assertFalse(bar.getMenuCount() == 0);
103
        menu = bar.getMenu(0);
104
    }
105
106
    @Override
107
    public void tearDown() {
108
        jf.dispose();
109
    }
110
111
    private void click(final JComponent comp, final boolean showMenu) throws Exception {
112
        EventQueue.invokeAndWait(new Runnable() {
113
114
            public void run() {
115
                ((AbstractButton) comp).getModel().setPressed(showMenu);
116
                MouseEvent evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_PRESSED);
117
                comp.dispatchEvent(evt);
118
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_RELEASED);
119
                comp.dispatchEvent(evt);
120
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_CLICKED);
121
                comp.dispatchEvent(evt);
122
            }
123
        });
124
        if (comp instanceof JMenu) {
125
            JMenu m = (JMenu) comp;
126
            while (showMenu != m.getPopupMenu().isShowing()) {
127
                Thread.sleep (100);
128
            }
129
        }
130
    }
131
132
133
    @Test
134
    public void testMenusAreUpdatedWhenOpen() throws Exception {
135
        EventBlocker.init();
136
        assertNotNull (menu);
137
        click (menu, true);
138
        JPopupMenu popup = menu.getPopupMenu();
139
        Component[] c = popup.getComponents();
140
        assertTrue (menu.isPopupMenuVisible());
141
        assertEquals (4, popup.getComponentCount());
142
        final CountDownLatch l = new CountDownLatch(2);
143
        popup.addContainerListener(new ContainerListener() {
144
145
            @Override
146
            public void componentAdded(ContainerEvent e) {
147
//                System.err.println("added - count now " + e.getContainer().getComponentCount());
148
                if (e.getContainer().getComponentCount() == 5) {
149
                    l.countDown();
150
                }
151
            }
152
153
            @Override
154
            public void componentRemoved(ContainerEvent e) {
155
//                System.err.println("removed - count now " + e.getContainer().getComponentCount());
156
            }
157
158
        });
159
        bar.addContainerListener(new ContainerListener() {
160
161
            @Override
162
            public void componentAdded(ContainerEvent e) {
163
//                System.err.println("bar comp added - count now " + e.getContainer().getComponentCount());
164
                if (e.getContainer().getComponentCount() == 3) {
165
                    l.countDown();
166
                }
167
            }
168
169
            @Override
170
            public void componentRemoved(ContainerEvent e) {
171
//                System.err.println("bar comp removed - count now " + e.getContainer().getComponentCount());
172
            }
173
            
174
        });
175
176
        new ABCDAction().actionPerformed(null);
177
        l.await(20000, TimeUnit.MILLISECONDS);
178
        final AtomicInteger popupCompCount = new AtomicInteger(-1);
179
        final AtomicInteger barCompCount = new AtomicInteger(-1);
180
        final AtomicBoolean vis = new AtomicBoolean();
181
        EventQueue.invokeAndWait (new Runnable() {
182
183
            @Override
184
            public void run() {
185
                popupCompCount.set(menu.getPopupMenu().getComponentCount());
186
                barCompCount.set(bar.getComponentCount());
187
                vis.set(menu.getPopupMenu().isShowing());
188
            }
189
190
        });
191
        
192
        assertTrue (vis.get());
193
        assertEquals (5, popupCompCount.get());
194
        assertEquals (3, barCompCount.get());
195
196
        popupCompCount.set(-1);
197
        barCompCount.set(-1);
198
        vis.set(false);
199
200
        final CountDownLatch ll = new CountDownLatch(4);
201
        popup.addContainerListener(new ContainerListener() {
202
203
            @Override
204
            public void componentAdded(ContainerEvent e) {
205
//                System.err.println("added - count now " + e.getContainer().getComponentCount());
206
                ll.countDown();
207
            }
208
209
            @Override
210
            public void componentRemoved(ContainerEvent e) {
211
//                System.err.println("removed - count now " + e.getContainer().getComponentCount());
212
            }
213
214
        });
215
        new AAction().actionPerformed(null);
216
        ll.await(20000, TimeUnit.MILLISECONDS);
217
        EventQueue.invokeAndWait (new Runnable() {
218
219
            @Override
220
            public void run() {
221
                popupCompCount.set(menu.getPopupMenu().getComponentCount());
222
                barCompCount.set(bar.getComponentCount());
223
                vis.set(menu.getPopupMenu().isShowing());
224
            }
225
226
        });
227
228
        assertTrue (vis.get());
229
        assertEquals (4, popupCompCount.get());
230
        assertEquals (2, barCompCount.get());
231
232
//        Thread.sleep (40000);
233
234
    }
235
    private static final int EXPECTED_MENU_COUNT = 1; //update if more added to xml
236
237
    private class R implements Runnable, ContainerListener {
238
239
        private final CountDownLatch latch = new CountDownLatch(1);
240
241
        @Override
242
        public void run() {
243
            jf = new JFrame();
244
            bar = m.createMenu(jf);
245
            bar.addContainerListener(this);
246
            JPanel pnl = new JPanel();
247
            pnl.setMinimumSize(new Dimension(300, 300));
248
            pnl.setPreferredSize(new Dimension(300, 300));
249
            jf.setContentPane(pnl);
250
            jf.setJMenuBar(bar);
251
            jf.pack();
252
            jf.setVisible(true);
253
        }
254
255
        @Override
256
        public void componentAdded(ContainerEvent e) {
257
            int count = e.getContainer().getComponentCount();
258
            if (count == EXPECTED_MENU_COUNT) {
259
                latch.countDown();
260
                e.getContainer().invalidate();
261
                ((JMenuBar) e.getContainer()).revalidate();
262
                e.getContainer().repaint();
263
            }
264
        }
265
266
        @Override
267
        public void componentRemoved(ContainerEvent e) {
268
            //do nothing
269
        }
270
    }
271
272
    public static final class MFS extends MultiFileSystem {
273
        public static MFS INSTANCE;
274
        MFS() throws SAXException {
275
            setLayers (Layers.A);
276
            INSTANCE = this;
277
        }
278
279
        public void setLayers(Layers... l) throws SAXException {
280
            System.err.println("setLayers " + Arrays.asList(l));
281
            FileSystem[] xfs = new XMLFileSystem[l.length];
282
            for (int i = 0; i < xfs.length; i++) {
283
                xfs[i] = new XMLFileSystem(l[i].res());
284
            }
285
            setDelegates(xfs);
286
        }
287
    }
288
289
    public enum Layers {
290
        A("a.xml"),
291
        B("b.xml"),
292
        C("c.xml"),
293
        D("d.xml");
294
        private String resource;
295
        Layers (String resource) {
296
            this.resource = resource;
297
        }
298
299
        public URL res() {
300
            return Layers.class.getResource(resource);
301
        }
302
    }
303
}
(-)d76d479b5dc8 (+28 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="One">
6
            <attr name="position" intvalue="0"/>
7
            <file name="org-netbeans-core-menu-AAction.instance">
8
                <attr name="position" intvalue="0"/>
9
            </file>
10
            <file name="org-netbeans-core-menu-ABAction.instance">
11
                <attr name="position" intvalue="1"/>
12
            </file>
13
            <file name="org-netbeans-core-menu-ABCAction.instance">
14
                <attr name="position" intvalue="2"/>
15
            </file>
16
            <file name="org-netbeans-core-menu-ABCDAction.instance">
17
                <attr name="position" intvalue="3"/>
18
            </file>
19
        </folder>
20
        <folder name="Two">
21
            <attr name="position" intvalue="1"/>
22
            <file name="org-netbeans-core-menu-PresenterAction.instance">
23
                <attr name="position" intvalue="0"/>
24
            </file>
25
        </folder>
26
27
    </folder>
28
</filesystem>
(-)d76d479b5dc8 (+11 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="Two">
6
            <file name="org-netbeans-core-menu-DynAction.instance">
7
                <attr name="position" intvalue="1"/>
8
            </file>
9
        </folder>
10
    </folder>
11
</filesystem>
(-)d76d479b5dc8 (+11 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="One">
6
            <file name="org-netbeans-core-menu-RegularAction.instance">
7
                <attr name="position" intvalue="4"/>
8
            </file>
9
        </folder>
10
    </folder>
11
</filesystem>
(-)d76d479b5dc8 (+12 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="Three">
6
            <attr name="position" intvalue="2"/>
7
            <file name="org-netbeans-core-menu-RegularAction.instance">
8
                <attr name="position" intvalue="1"/>
9
            </file>
10
        </folder>
11
    </folder>
12
</filesystem>
(-)a/core.menu/src/org/netbeans/core/menu/DynamicModelEntry.java (-2 lines)
Lines 60-67 Link Here
60
        try {
60
        try {
61
            DynamicMenuContent dyn = get();
61
            DynamicMenuContent dyn = get();
62
            JComponent[] result = dyn.getMenuPresenters();
62
            JComponent[] result = dyn.getMenuPresenters();
63
            //Necessary the first time, or we get bogus elements
64
            dyn.synchMenuPresenters(result);
65
            return result;
63
            return result;
66
        } catch (IOException ex) {
64
        } catch (IOException ex) {
67
            Exceptions.printStackTrace(ex);
65
            Exceptions.printStackTrace(ex);
(-)a/core.ui/manifest.mf (-1 / +1 lines)
Lines 4-8 Link Here
4
OpenIDE-Module-Layer: org/netbeans/core/ui/resources/layer.xml
4
OpenIDE-Module-Layer: org/netbeans/core/ui/resources/layer.xml
5
AutoUpdate-Show-In-Client: false
5
AutoUpdate-Show-In-Client: false
6
AutoUpdate-Essential-Module: true
6
AutoUpdate-Essential-Module: true
7
OpenIDE-Module-Specification-Version: 1.21
7
OpenIDE-Module-Specification-Version: 1.22
8
8
(-)a/core.ui/src/org/netbeans/core/ui/warmup/MenuWarmUpTask.java (-37 / +3 lines)
Lines 45-50 Link Here
45
45
46
import java.awt.Component;
46
import java.awt.Component;
47
import java.awt.Dimension;
47
import java.awt.Dimension;
48
import java.awt.EventQueue;
48
import java.awt.Frame;
49
import java.awt.Frame;
49
import java.awt.event.ActionEvent;
50
import java.awt.event.ActionEvent;
50
import java.awt.event.WindowAdapter;
51
import java.awt.event.WindowAdapter;
Lines 58-64 Link Here
58
import javax.swing.JFrame;
59
import javax.swing.JFrame;
59
import javax.swing.JLabel;
60
import javax.swing.JLabel;
60
import javax.swing.JMenu;
61
import javax.swing.JMenu;
61
import javax.swing.SwingUtilities;
62
import javax.swing.text.html.HTMLEditorKit;
62
import javax.swing.text.html.HTMLEditorKit;
63
import org.netbeans.api.progress.ProgressHandle;
63
import org.netbeans.api.progress.ProgressHandle;
64
import org.netbeans.api.progress.ProgressHandleFactory;
64
import org.netbeans.api.progress.ProgressHandleFactory;
Lines 74-131 Link Here
74
import org.openide.util.NbBundle;
74
import org.openide.util.NbBundle;
75
75
76
/**
76
/**
77
 * A menu preheating task. It is referenced from the layer and may be performed
77
 * Triggers filesystem refresh on main window activation.
78
 * by the core after the startup.
79
 * 
80
 * Plus hooked WindowListener on main window (see {@link NbWindowsAdapter})
81
 */
78
 */
82
public final class MenuWarmUpTask implements Runnable {
79
public final class MenuWarmUpTask implements Runnable {
83
80
84
    private Component[] comps;
85
    
86
    /** Actually performs pre-heat.
87
     */
88
    @Override
81
    @Override
89
    public void run() {
82
    public void run() {
90
        try {
83
        try {
91
            SwingUtilities.invokeAndWait(new Runnable() {
84
            EventQueue.invokeLater(new Runnable() {
92
                @Override
85
                @Override
93
                public void run() {
86
                public void run() {
94
                    Frame main = WindowManager.getDefault().getMainWindow();
87
                    Frame main = WindowManager.getDefault().getMainWindow();
95
                    
96
                    assert main != null;
88
                    assert main != null;
97
                    main.addWindowListener(new NbWindowsAdapter());
89
                    main.addWindowListener(new NbWindowsAdapter());
98
                    
99
                    if (main instanceof JFrame) {
100
                        comps = ((JFrame) main).getJMenuBar().getComponents();
101
                    }
102
                }
90
                }
103
            });
91
            });
104
        } catch (Exception e) { // bail out!
92
        } catch (Exception e) { // bail out!
105
            return;
93
            return;
106
        }
94
        }
107
108
109
        if (comps != null) {
110
            walkMenu(comps);
111
            comps = null;
112
        }
113
114
        // tackle the Tools menu now? How?
115
    }
116
117
    private void walkMenu(Component[] items) {
118
        for (int i=0; i<items.length; i++) {
119
            if (! (items[i] instanceof JMenu)) continue;
120
            try {
121
                Class<?> cls = items[i].getClass();
122
                Method m = cls.getDeclaredMethod("doInitialize");
123
                m.setAccessible(true);
124
                m.invoke(items[i]);
125
                walkMenu(((JMenu)items[i]).getMenuComponents()); // recursive?
126
            } catch (Exception e) {// do nothing, it may happen for user-provided menus
127
            }
128
        }
129
    }
95
    }
130
96
131
    /**
97
    /**
(-)a/core.menu/src/org/netbeans/core/menu/ComponentModelEntry.java (-1 / +1 lines)
Lines 57-63 Link Here
57
    }
57
    }
58
58
59
    @Override
59
    @Override
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
61
        return false;
61
        return false;
62
    }
62
    }
63
63
(-)a/core.menu/src/org/netbeans/core/menu/FolderModelEntry.java (-4 / +4 lines)
Lines 142-153 Link Here
142
        }
142
        }
143
    }
143
    }
144
144
145
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
145
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
146
        //do nothing - for subclasses to force init
146
        //do nothing - for subclasses to force init
147
    }
147
    }
148
148
149
    @Override
149
    @Override
150
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children) {
150
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
151
//        System.err.println("initBackground " + getName());
151
//        System.err.println("initBackground " + getName());
152
        DataFolder fld = file();
152
        DataFolder fld = file();
153
        boolean changed = true;
153
        boolean changed = true;
Lines 165-171 Link Here
165
                                children.add(e);
165
                                children.add(e);
166
                                //XXX defer or batch afterward?
166
                                //XXX defer or batch afterward?
167
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
167
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
168
                                boolean hasKids = e.initBackground(kids);
168
                                boolean hasKids = e.initBackground(kids, currDepth+1);
169
                                changed |= hasKids;
169
                                changed |= hasKids;
170
                                if (hasKids) {
170
                                if (hasKids) {
171
                                    if (e instanceof FolderModelEntry) {
171
                                    if (e instanceof FolderModelEntry) {
Lines 185-191 Link Here
185
                }
185
                }
186
            }
186
            }
187
        } finally {
187
        } finally {
188
            onInitBackground(children);
188
            onInitBackground(children, currDepth);
189
        }
189
        }
190
        return changed;
190
        return changed;
191
    }
191
    }
(-)a/core.menu/src/org/netbeans/core/menu/MenuBarModel.java (+16 lines)
Lines 39-44 Link Here
39
39
40
package org.netbeans.core.menu;
40
package org.netbeans.core.menu;
41
41
42
import java.util.List;
43
import javax.swing.JComponent;
42
import javax.swing.JMenuBar;
44
import javax.swing.JMenuBar;
43
import org.openide.loaders.DataFolder;
45
import org.openide.loaders.DataFolder;
44
import org.openide.util.RequestProcessor;
46
import org.openide.util.RequestProcessor;
Lines 63-66 Link Here
63
    JMenuBar cachedComponent() {
65
    JMenuBar cachedComponent() {
64
        return bar;
66
        return bar;
65
    }
67
    }
68
69
    @Override
70
    protected void installComponents(List<? extends JComponent> components, JMenuBar into) {
71
        synchronized (bar.getTreeLock()) {
72
            super.installComponents(components, into);
73
        }
74
        bar.invalidate();
75
        bar.revalidate();
76
        bar.repaint();
77
    }
78
79
80
81
66
}
82
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuProviderImpl.java (-4 / +17 lines)
Lines 40-45 Link Here
40
package org.netbeans.core.menu;
40
package org.netbeans.core.menu;
41
41
42
import java.awt.EventQueue;
42
import java.awt.EventQueue;
43
import java.awt.event.ComponentAdapter;
44
import java.awt.event.ComponentEvent;
45
import java.awt.event.HierarchyEvent;
46
import java.awt.event.HierarchyListener;
43
import javax.swing.JFrame;
47
import javax.swing.JFrame;
44
import javax.swing.JMenuBar;
48
import javax.swing.JMenuBar;
45
import org.netbeans.api.menus.MenuProvider;
49
import org.netbeans.api.menus.MenuProvider;
Lines 71-81 Link Here
71
        }
75
        }
72
        FileObject menuFO = menuFolder;
76
        FileObject menuFO = menuFolder;
73
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
77
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
74
        JMenuBar bar = new JMenuBar();
78
        final JMenuBar bar = new JMenuBar();
75
        bar.setBorderPainted(false);
79
        bar.setBorderPainted(false);
76
        MenuManager mgr = new MenuManager(menuFolder, bar);
80
        final MenuManager mgr = new MenuManager(menuFolder, bar);
77
        mgr.init();
81
        bar.addHierarchyListener(new HierarchyListener() {
82
83
            @Override
84
            public void hierarchyChanged(HierarchyEvent e) {
85
                if (bar.isShowing()) {
86
                    bar.removeHierarchyListener(this);
87
                    mgr.init();
88
                }
89
            }
90
        });
91
//        mgr.init();
78
        return bar;
92
        return bar;
79
    }
93
    }
80
81
}
94
}
(-)a/core.menu/src/org/netbeans/core/menu/ModelEntry.java (-1 / +35 lines)
Lines 67-73 Link Here
67
        Parameters.notNull("file", file);
67
        Parameters.notNull("file", file);
68
    }
68
    }
69
    
69
    
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth);
71
71
72
    public String getName() {
72
    public String getName() {
73
        DataObject file = file();
73
        DataObject file = file();
Lines 136-147 Link Here
136
            Icon icon = item.getIcon();
136
            Icon icon = item.getIcon();
137
            if (!wantIcons && icon != null) {
137
            if (!wantIcons && icon != null) {
138
                item.setIcon(null);
138
                item.setIcon(null);
139
                item.setDisabledIcon(null);
140
                item.setDisabledSelectedIcon(null);
139
            } else if (wantIcons && icon == null) {
141
            } else if (wantIcons && icon == null) {
140
                item.setIcon (BLANK_ICON);
142
                item.setIcon (BLANK_ICON);
143
                item.setDisabledIcon(BLANK_ICON);
144
                item.setDisabledSelectedIcon(BLANK_ICON);
141
            }
145
            }
146
//            String txt = item.getText();
147
//            if (txt != null && txt.contains("Find Issues")) {
148
//                Thread.dumpStack();
149
//                log (item);
150
//            }
142
        }
151
        }
143
    }
152
    }
144
153
154
//Useful for diagnosing strangely painting menu items
155
//    private static void log (JMenuItem item) {
156
//        System.err.println("FIND ISSUES ITEM: " + item);
157
//        logType (item);
158
//        System.err.println(" Action:");
159
//        logType (item.getAction());
160
//    }
161
//
162
//    private static void logType (Object o) {
163
//        if (o == null) return;
164
//        for (Class<?> c : o.getClass().getInterfaces()) {
165
//            System.err.println(" I:" + c.getName());
166
//        }
167
//        Class<?> x = o.getClass();
168
//        while (x != Object.class) {
169
//            System.err.println(" C: " + x.getName());
170
//            x = x.getSuperclass();
171
//        }
172
//    }
173
145
    protected static Boolean defaultHasIcon (JComponent comp, Boolean hasIcon) {
174
    protected static Boolean defaultHasIcon (JComponent comp, Boolean hasIcon) {
146
        if (hasIcon != null && hasIcon) {
175
        if (hasIcon != null && hasIcon) {
147
            return hasIcon;
176
            return hasIcon;
Lines 176-179 Link Here
176
        hash = 31 * hash + (this.file != null ? this.file.hashCode() : 0);
205
        hash = 31 * hash + (this.file != null ? this.file.hashCode() : 0);
177
        return hash;
206
        return hash;
178
    }
207
    }
208
209
    @Override
210
    public String toString() {
211
        return super.toString() + "[" + getName() + "]";
212
    }
179
}
213
}
(-)a/core.menu/src/org/netbeans/core/menu/RefreshingFolderModelEntry.java (-8 / +28 lines)
Lines 42-48 Link Here
42
import java.util.LinkedList;
42
import java.util.LinkedList;
43
import java.util.List;
43
import java.util.List;
44
import javax.swing.JComponent;
44
import javax.swing.JComponent;
45
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
45
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
46
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
47
import org.openide.filesystems.FileEvent;
Lines 61-66 Link Here
61
    private final RequestProcessor.Task task;
60
    private final RequestProcessor.Task task;
62
    private FCA fca = new FCA();
61
    private FCA fca = new FCA();
63
    private static final int DELAY = 100;
62
    private static final int DELAY = 100;
63
    private static final boolean LOG_RUNNABLES = Boolean.getBoolean ("RefreshingFolderModelEntry.log");
64
64
65
    RefreshingFolderModelEntry(DataFolder dob, Class<T> compType, RequestProcessor rp) {
65
    RefreshingFolderModelEntry(DataFolder dob, Class<T> compType, RequestProcessor rp) {
66
        super(dob, compType);
66
        super(dob, compType);
Lines 70-79 Link Here
70
    }
70
    }
71
71
72
    @Override
72
    @Override
73
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
73
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
74
        super.onInitBackground(children);
74
        super.onInitBackground(children, currDepth);
75
        if (!refreshing) {
75
        if (!refreshing && currDepth == 0) {
76
            EventQueue.invokeLater(fca);
76
            EventQueue.invokeLater(LOG_RUNNABLES ? new LogRunnable(fca) : fca);
77
        }
77
        }
78
    }
78
    }
79
79
Lines 84-89 Link Here
84
    }
84
    }
85
    volatile boolean refreshing;
85
    volatile boolean refreshing;
86
86
87
    private final class LogRunnable implements Runnable {
88
        Throwable t;
89
        private final Runnable real;
90
        LogRunnable (Runnable real) {
91
            this.real = real;
92
            t = new Exception("Refresh " + RefreshingFolderModelEntry.this).fillInStackTrace();
93
        }
94
95
        @Override
96
        public void run() {
97
            t.printStackTrace();
98
            real.run();
99
        }
100
    }
101
87
    private final class FCA extends FileChangeAdapter implements Runnable {
102
    private final class FCA extends FileChangeAdapter implements Runnable {
88
103
89
        private volatile boolean enqueued;
104
        private volatile boolean enqueued;
Lines 94-100 Link Here
94
                result = enqueued;
109
                result = enqueued;
95
                if (!enqueued) {
110
                if (!enqueued) {
96
                    enqueued = true;
111
                    enqueued = true;
97
                    task.schedule(DELAY);
112
                    if (!LOG_RUNNABLES) {
113
                        task.schedule(DELAY);
114
                    } else {
115
                        RequestProcessor.Task t = MenuManager.rp.create(new LogRunnable(this));
116
                        t.schedule(DELAY);
117
                    }
98
                }
118
                }
99
                return result;
119
                return result;
100
            }
120
            }
Lines 106-116 Link Here
106
                refreshing = true;
126
                refreshing = true;
107
                try {
127
                try {
108
                    List<ModelEntry<?, ?>> l = new LinkedList<ModelEntry<?, ?>>();
128
                    List<ModelEntry<?, ?>> l = new LinkedList<ModelEntry<?, ?>>();
109
                    initBackground(l);
129
                    initBackground(l, 0);
110
                    setChildren(l);
130
                    setChildren(l);
111
                } finally {
131
                } finally {
112
                    refreshing = false;
132
                    refreshing = false;
113
                    EventQueue.invokeLater(this);
133
                    EventQueue.invokeLater(LOG_RUNNABLES ? new LogRunnable(this) : this);
114
                }
134
                }
115
            } else {
135
            } else {
116
                enqueued = false;
136
                enqueued = false;
(-)a/core.menu/src/org/netbeans/core/menu/SeparatorModelEntry.java (-1 / +1 lines)
Lines 63-69 Link Here
63
    }
63
    }
64
64
65
    @Override
65
    @Override
66
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
66
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
67
        return false;
67
        return false;
68
    }
68
    }
69
}
69
}
(-)a/core.menu/src/org/netbeans/core/menu/ThreadUnconstrainedModelEntry.java (-1 / +1 lines)
Lines 68-74 Link Here
68
    }
68
    }
69
69
70
    @Override
70
    @Override
71
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
71
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
72
        //Since it is non-gui, instantiate the Action in the background
72
        //Since it is non-gui, instantiate the Action in the background
73
        try {
73
        try {
74
            ref.set(super.get());
74
            ref.set(super.get());
(-)a/core.menu/test/unit/src/org/netbeans/core/menu/MenuProviderImplTest.java (-6 / +4 lines)
Lines 108-121 Link Here
108
108
109
            public void run() {
109
            public void run() {
110
                ((AbstractButton) comp).getModel().setPressed(showMenu);
110
                ((AbstractButton) comp).getModel().setPressed(showMenu);
111
                MouseEvent evt = new MouseEvent(comp, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
111
                MouseEvent evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_PRESSED);
112
                        0, 5, 5, 1, false, 0);
113
                comp.dispatchEvent(evt);
112
                comp.dispatchEvent(evt);
114
                evt = new MouseEvent(comp, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
113
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_RELEASED);
115
                        0, 5, 5, 1, false, 0);
116
                comp.dispatchEvent(evt);
114
                comp.dispatchEvent(evt);
117
                evt = new MouseEvent(comp, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(),
115
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_CLICKED);
118
                        0, 5, 5, 1, false, 0);
119
                comp.dispatchEvent(evt);
116
                comp.dispatchEvent(evt);
120
            }
117
            }
121
        });
118
        });
Lines 129-134 Link Here
129
126
130
    @Test
127
    @Test
131
    public void testMenuItemsAreNotStronglyReferenced() throws Exception {
128
    public void testMenuItemsAreNotStronglyReferenced() throws Exception {
129
        EventBlocker.init();
132
        assertNotNull (menu);
130
        assertNotNull (menu);
133
        click (menu, true);
131
        click (menu, true);
134
        JPopupMenu popup = menu.getPopupMenu();
132
        JPopupMenu popup = menu.getPopupMenu();
(-)1f7b91420663 (+5 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project basedir="." default="netbeans" name="api.menus">
3
    <description>Builds, tests, and runs the project org.netbeans.api.menus</description>
4
    <import file="../nbbuild/templates/projectized.xml"/>
5
</project>
(-)1f7b91420663 (+7 lines)
Added Link Here
1
Manifest-Version: 1.0
2
AutoUpdate-Show-In-Client: false
3
OpenIDE-Module: org.netbeans.api.menus/1
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/menus/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.0
6
OpenIDE-Module-Recommends: org.netbeans.api.menus.MenuProvider
7
(-)1f7b91420663 (+4 lines)
Added Link Here
1
is.autoload=true
2
javac.source=1.6
3
javac.compilerargs=-Xlint -Xlint:-serial
4
nbm.module.author=Tim Boudreau
(-)1f7b91420663 (+30 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://www.netbeans.org/ns/project/1">
3
    <type>org.netbeans.modules.apisupport.project</type>
4
    <configuration>
5
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6
            <code-name-base>org.netbeans.api.menus</code-name-base>
7
            <module-dependencies>
8
                <dependency>
9
                    <code-name-base>org.openide.util</code-name-base>
10
                    <build-prerequisite/>
11
                    <compile-dependency/>
12
                    <run-dependency>
13
                        <specification-version>8.2</specification-version>
14
                    </run-dependency>
15
                </dependency>
16
                <dependency>
17
                    <code-name-base>org.openide.util.lookup</code-name-base>
18
                    <build-prerequisite/>
19
                    <compile-dependency/>
20
                    <run-dependency>
21
                        <specification-version>8.2</specification-version>
22
                    </run-dependency>
23
                </dependency>
24
            </module-dependencies>
25
            <public-packages>
26
                <package>org.netbeans.api.menus</package>
27
            </public-packages>
28
        </data>
29
    </configuration>
30
</project>
(-)1f7b91420663 (+7 lines)
Added Link Here
1
OpenIDE-Module-Display-Category=Infrastructure
2
OpenIDE-Module-Long-Description=\
3
    API which allows another module to inject a factory which creates the main window's menu bar.
4
OpenIDE-Module-Name=Main Menu API
5
FILE_MENU=File
6
EXIT_MENU_ITEM=Exit
7
OpenIDE-Module-Short-Description=API for generating the application's menu(s)
(-)1f7b91420663 (+142 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.api.menus;
40
41
import java.awt.EventQueue;
42
import java.awt.event.ActionEvent;
43
import java.util.logging.Level;
44
import java.util.logging.Logger;
45
import javax.swing.AbstractAction;
46
import javax.swing.Action;
47
import javax.swing.JFrame;
48
import javax.swing.JMenu;
49
import javax.swing.JMenuBar;
50
import org.openide.LifecycleManager;
51
import org.openide.util.Exceptions;
52
import org.openide.util.Lookup;
53
import org.openide.util.NbBundle;
54
import org.openide.util.Parameters;
55
56
/**
57
 * Factory for the application window main menu.  Registered in the default
58
 * lookup.
59
 *
60
 * @author Tim Boudreau
61
 * @since 1.0
62
 */
63
public abstract class MenuProvider {
64
65
    /**
66
     * Install a menu in a JFrame.  Called by the window system to set up the
67
     * main menu.  This method is not guaranteed to return the same JMenuBar
68
     * if called repeatedly, and should not be used as a way to look up the
69
     * main window's menu.
70
     * <p/>
71
     * This method must be called on the AWT event dispatch thread.
72
     * <p/>
73
     * If no MenuProvider is registered in the default lookup, will create a
74
     * menu which simply contains a File menu with an Exit menu item that
75
     * uses LifecycleManager to cleanly exit the application.
76
     *
77
     * @param frame A JFrame.  May not be null.
78
     * @return The JMenuBar which has been installed in the frame.
79
     */
80
    public static JMenuBar installMenu(JFrame frame) {
81
        Parameters.notNull("frame", frame); //NOI18N
82
        if (!EventQueue.isDispatchThread()) {
83
            throw new IllegalStateException("Not on event thread"); //NOI18N
84
        }
85
        MenuProvider p = Lookup.getDefault().lookup(MenuProvider.class);
86
        JMenuBar menu = p == null ? fallbackMenu() : p.createMenu(frame);
87
        if (p == null) {
88
            Logger.getLogger(MenuProvider.class.getName()).log (Level.WARNING,
89
                    "No instance of {0} registered in the default lookup. " + //NOI18N
90
                    "Using fallback.", MenuProvider.class.getName()); //NOI18N
91
        }
92
        if (menu == null) {
93
            if (p != null) {
94
                Exceptions.printStackTrace(new NullPointerException(p
95
                    + " returned null menu")); //NOI18N
96
            }
97
            menu = fallbackMenu();
98
        }
99
        frame.setJMenuBar(menu);
100
        return menu;
101
    }
102
103
    private static JMenuBar fallbackMenu() {
104
        String fileMenuName = NbBundle.getMessage(MenuProvider.class,
105
                "FILE_MENU"); //NOI18N
106
        String exitItemName = NbBundle.getMessage(MenuProvider.class,
107
                "EXIT_MENU_ITEM"); //NOI18N
108
        JMenuBar result = new JMenuBar();
109
        JMenu fileMenu = new JMenu(fileMenuName);
110
        Action exitAction = new ExitAction();
111
        exitAction.putValue(Action.NAME, exitItemName);
112
        fileMenu.add(exitAction);
113
        result.add(fileMenu);
114
        return result;
115
    }
116
117
    /**
118
     * Create a menu for the provided JFrame.  This method is not expected
119
     * to cache the return value.  It should not actually call the target frame's
120
     * <code>setJMenuBar()</code> method - the target frame is provided as a
121
     * convenience in case some multi-frame application provides menus for
122
     * multiple frames.
123
     * <p/>
124
     * This method will only be called by NetBeans from the event dispatch thread.
125
     * Constructing components is safe here, but it is preferable not to perform
126
     * heavy-duty I/O in this method, but rather to create the initial menu bar
127
     * quickly, and then populate its menus lazily or in the background.
128
     * <p/>
129
     * @param target The frame the menu should be created for
130
     * @since 1.0
131
     * @return A JMenuBar
132
     */
133
    protected abstract JMenuBar createMenu(JFrame target);
134
135
    private static final class ExitAction extends AbstractAction {
136
137
        @Override
138
        public void actionPerformed(ActionEvent e) {
139
            LifecycleManager.getDefault().exit();
140
        }
141
    }
142
}
(-)1f7b91420663 (+5 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project basedir="." default="netbeans" name="core.menu">
3
    <description>Builds, tests, and runs the project org.netbeans.core.menu</description>
4
    <import file="../nbbuild/templates/projectized.xml"/>
5
</project>
(-)1f7b91420663 (+7 lines)
Added Link Here
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.core.menu
3
OpenIDE-Module-Layer: org/netbeans/core/menu/layer.xml
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/core/menu/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.0
6
OpenIDE-Module-Provides: org.netbeans.api.menus.MenuProvider
7
(-)1f7b91420663 (+2 lines)
Added Link Here
1
javac.source=1.6
2
javac.compilerargs=-Xlint -Xlint:-serial
(-)1f7b91420663 (+83 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://www.netbeans.org/ns/project/1">
3
    <type>org.netbeans.modules.apisupport.project</type>
4
    <configuration>
5
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6
            <code-name-base>org.netbeans.core.menu</code-name-base>
7
            <module-dependencies>
8
                <dependency>
9
                    <code-name-base>org.netbeans.api.menus</code-name-base>
10
                    <build-prerequisite/>
11
                    <compile-dependency/>
12
                    <run-dependency>
13
                        <release-version>1</release-version>
14
                        <specification-version>1.0</specification-version>
15
                    </run-dependency>
16
                </dependency>
17
                <dependency>
18
                    <code-name-base>org.openide.awt</code-name-base>
19
                    <build-prerequisite/>
20
                    <compile-dependency/>
21
                    <run-dependency>
22
                        <specification-version>7.21</specification-version>
23
                    </run-dependency>
24
                </dependency>
25
                <dependency>
26
                    <code-name-base>org.openide.filesystems</code-name-base>
27
                    <build-prerequisite/>
28
                    <compile-dependency/>
29
                    <run-dependency>
30
                        <specification-version>7.37</specification-version>
31
                    </run-dependency>
32
                </dependency>
33
                <dependency>
34
                    <code-name-base>org.openide.loaders</code-name-base>
35
                    <build-prerequisite/>
36
                    <compile-dependency/>
37
                    <run-dependency>
38
                        <specification-version>7.13</specification-version>
39
                    </run-dependency>
40
                </dependency>
41
                <dependency>
42
                    <code-name-base>org.openide.nodes</code-name-base>
43
                    <build-prerequisite/>
44
                    <compile-dependency/>
45
                    <run-dependency>
46
                        <specification-version>7.14</specification-version>
47
                    </run-dependency>
48
                </dependency>
49
                <dependency>
50
                    <code-name-base>org.openide.util</code-name-base>
51
                    <build-prerequisite/>
52
                    <compile-dependency/>
53
                    <run-dependency>
54
                        <specification-version>8.2</specification-version>
55
                    </run-dependency>
56
                </dependency>
57
                <dependency>
58
                    <code-name-base>org.openide.util.lookup</code-name-base>
59
                    <build-prerequisite/>
60
                    <compile-dependency/>
61
                    <run-dependency>
62
                        <specification-version>8.2</specification-version>
63
                    </run-dependency>
64
                </dependency>
65
            </module-dependencies>
66
            <test-dependencies>
67
                <test-type>
68
                    <name>unit</name>
69
                    <test-dependency>
70
                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
71
                        <compile-dependency/>
72
                    </test-dependency>
73
                    <test-dependency>
74
                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
75
                        <recursive/>
76
                        <compile-dependency/>
77
                    </test-dependency>
78
                </test-type>
79
            </test-dependencies>
80
            <public-packages/>
81
        </data>
82
    </configuration>
83
</project>
(-)1f7b91420663 (+125 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.io.IOException;
43
import javax.swing.Action;
44
import javax.swing.JCheckBoxMenuItem;
45
import javax.swing.JMenuItem;
46
import org.openide.awt.AcceleratorBinding;
47
import org.openide.awt.Actions;
48
import org.openide.awt.Mnemonics;
49
import org.openide.loaders.DataObject;
50
import org.openide.util.Exceptions;
51
import org.openide.util.actions.BooleanStateAction;
52
import org.openide.util.actions.Presenter;
53
import org.openide.util.actions.SystemAction;
54
55
/**
56
 *
57
 * @author Tim Boudreau
58
 */
59
final class ActionModelEntry extends ThreadUnconstrainedModelEntry<Action, JMenuItem> {
60
    ActionModelEntry(DataObject dob) {
61
        super (dob, JMenuItem.class, Action.class);
62
    }
63
64
    @Override
65
    protected JMenuItem refreshComponent(JMenuItem old) {
66
        Action a;
67
        try {
68
            a = get();
69
            if (old.getAction() == a) {
70
                configureName (a, old);
71
            }
72
        } catch (IOException ex) {
73
            Exceptions.printStackTrace(ex);
74
        } catch (ClassNotFoundException ex) {
75
            Exceptions.printStackTrace(ex);
76
        }
77
        return old;
78
    }
79
80
    private String getActionName(Action action) {
81
        String name = (String) action.getValue(Action.NAME);
82
        if (name == null && action instanceof SystemAction) {
83
            name = ((SystemAction) action).getName();
84
        }
85
        name = name == null ? getName() : name;
86
        return name;
87
    }
88
89
    private void configureName (Action action, JMenuItem item) {
90
        String txt = item.getText();
91
        if (txt == null || txt.length() == 0) {
92
            Mnemonics.setLocalizedText(item, getActionName(action));
93
            item.setToolTipText(null);
94
        }
95
    }
96
97
    @Override
98
    protected JMenuItem findComponent() {
99
        try {
100
            Action action = get();
101
            if (action instanceof Presenter.Menu) {
102
                throw new IllegalStateException("ActionModelEntry used for a menu presenter action");
103
            }
104
            JMenuItem item;
105
            if (action instanceof BooleanStateAction) {
106
                BooleanStateAction bse = (BooleanStateAction) action;
107
                JCheckBoxMenuItem cbItem = new JCheckBoxMenuItem();
108
                configureName (action, cbItem);
109
                Actions.connect(cbItem, bse, false);
110
                item = cbItem;
111
            } else {
112
                item = new JMenuItem();
113
                configureName (action, item);
114
                Actions.connect (item, action);
115
            }
116
            AcceleratorBinding.setAccelerator(action, file().getPrimaryFile());
117
            return item;
118
        } catch (IOException ex) {
119
            Exceptions.printStackTrace(ex);
120
        } catch (ClassNotFoundException ex) {
121
            Exceptions.printStackTrace(ex);
122
        }
123
        return new JMenuItem("Error from " + file().getName()); //XXX
124
    }
125
}
(-)1f7b91420663 (+1 lines)
Added Link Here
1
OpenIDE-Module-Name=Core Main Menu
(-)1f7b91420663 (+50 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
/**
42
 *
43
 * @author Tim Boudreau
44
 */
45
interface Callback {
46
47
    void onShow(ModelEntry<?, ?> entry);
48
49
    void onHide(ModelEntry<?, ?> entry);
50
}
(-)1f7b91420663 (+178 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.lang.ref.Reference;
44
import java.lang.ref.WeakReference;
45
import java.util.Arrays;
46
import javax.swing.JComponent;
47
import javax.swing.JSeparator;
48
import org.openide.util.Parameters;
49
50
/**
51
 * Wrapper for an array of components which can be checked for value equality.
52
 *
53
 * @author Tim Boudreau
54
 */
55
final class ComponentList {
56
    private final JComponent[] comps;
57
    private final Reference<?>[] refs;
58
    private volatile boolean isWeak;
59
    ComponentList(JComponent[] comps) {
60
        Parameters.notNull("comps", comps);
61
        this.comps = new JComponent[comps.length];
62
        refs = new Reference<?>[comps.length];
63
        for (int i= 0; i < comps.length; i++) {
64
            if (comps[i] == null) {
65
                this.comps[i] = new JSeparator();
66
            } else {
67
                this.comps[i] = comps[i];
68
            }
69
            refs[i] = new WeakReference<Component>(this.comps[i]);
70
        }
71
    }
72
73
    JComponent get (int ix) {
74
        JComponent result = comps[ix];
75
        if (comps[ix] == null) {
76
            result = refs[ix] == null ? null : (JComponent) refs[ix].get();
77
        }
78
        return result;
79
    }
80
81
    private void set (int ix, JComponent comp) {
82
        Parameters.notNull("comp", comp); //NOI18N
83
        comps[ix] = comp;
84
        refs[ix] = new WeakReference<JComponent>(comps[ix]);
85
    }
86
87
    int size() {
88
        return comps.length;
89
    }
90
91
    public JComponent[] getComponents() {
92
        JComponent[] result = new JComponent[size()];
93
        for (int i= 0; i < result.length; i++) {
94
            result[i] = get(i);
95
        }
96
        return result;
97
    }
98
99
    boolean addNotify() {
100
        boolean result = false;
101
        if (!result) {
102
            result = true;
103
            for (int i= 0; i < comps.length; i++) {
104
                if (comps[i] == null) {
105
                    comps[i] = refs[i] == null ? null : (JComponent) refs[i].get();
106
                    if (comps[i] == null) {
107
                        result = false;
108
                    }
109
                }
110
            }
111
        }
112
        isWeak = result;
113
        return result;
114
    }
115
116
    void removeNotify() {
117
//        if (!isWeak) {
118
            for (int i = 0; i < comps.length; i++) {
119
                comps[i] = null;
120
            }
121
//        }
122
        isWeak = true;
123
    }
124
125
    boolean repair (JComponent[] nue) {
126
        Parameters.notNull("nue", nue);
127
        if (nue.length != comps.length) {
128
            return false;
129
        }
130
        boolean result = true;
131
        for (int i= 0; i < comps.length; i++) {
132
            JComponent c = get(i);
133
            if (c == null || c == nue[i]) {
134
                if (nue[i] == null) {
135
                    throw new NullPointerException ("Null element in component " + //NOI18N
136
                            "list at " + i); //NOI18N
137
                }
138
                set (i, nue[i]);
139
            } else {
140
                result = false;
141
            }
142
        }
143
        return result;
144
    }
145
146
    @Override
147
    public boolean equals(Object obj) {
148
        if (obj == null || obj.getClass() != ComponentList.class) {
149
            return false;
150
        }
151
        final ComponentList other = (ComponentList) obj;
152
        if (other == this) {
153
            return true;
154
        }
155
        if (other.comps == comps) {
156
            return true;
157
        }
158
        if (other.comps.length != comps.length) {
159
            return false;
160
        }
161
        for (int i=0; i < comps.length; i++) {
162
            //test only on exact equality
163
            JComponent a = get(i);
164
            JComponent b = other.get(i);
165
            if (a != b) {
166
                return false;
167
            }
168
        }
169
        return true;
170
    }
171
172
    @Override
173
    public int hashCode() {
174
        int hash = 7;
175
        hash = 97 * hash + Arrays.deepHashCode(this.comps);
176
        return hash;
177
    }
178
}
(-)1f7b91420663 (+82 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.io.IOException;
44
import java.util.List;
45
import javax.swing.JComponent;
46
import javax.swing.JMenuItem;
47
import org.openide.loaders.DataObject;
48
import org.openide.util.Exceptions;
49
50
/**
51
 *
52
 * @author Tim Boudreau
53
 */
54
final class ComponentModelEntry extends FileModelEntry <JComponent, JComponent> {
55
    ComponentModelEntry (DataObject dob) {
56
        super (dob, JComponent.class, JComponent.class);
57
    }
58
59
    @Override
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
61
        return false;
62
    }
63
64
    @Override
65
    protected JComponent findComponent() {
66
        try {
67
            return get();
68
        } catch (IOException ex) {
69
            Exceptions.printStackTrace(ex);
70
        } catch (ClassNotFoundException ex) {
71
            Exceptions.printStackTrace(ex);
72
        }
73
        return new JMenuItem("Error getting comp for " + getName());
74
    }
75
76
    @Override
77
    protected JComponent refreshComponent(JComponent old) {
78
        return old;
79
    }
80
81
82
}
(-)1f7b91420663 (+85 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.io.IOException;
43
import javax.swing.JComponent;
44
import javax.swing.JMenuItem;
45
import org.openide.awt.DynamicMenuContent;
46
import org.openide.loaders.DataObject;
47
import org.openide.util.Exceptions;
48
49
/**
50
 *
51
 * @author Tim Boudreau
52
 */
53
public class DynamicModelEntry extends ThreadUnconstrainedModelEntry<DynamicMenuContent, JComponent> {
54
    DynamicModelEntry(DataObject dob) {
55
        super (dob, JComponent.class, DynamicMenuContent.class);
56
    }
57
58
    @Override
59
    protected JComponent[] findComponents() {
60
        try {
61
            DynamicMenuContent dyn = get();
62
            JComponent[] result = dyn.getMenuPresenters();
63
            //Necessary the first time, or we get bogus elements
64
            dyn.synchMenuPresenters(result);
65
            return result;
66
        } catch (IOException ex) {
67
            Exceptions.printStackTrace(ex);
68
        } catch (ClassNotFoundException ex) {
69
            Exceptions.printStackTrace(ex);
70
        }
71
        return new JComponent[] { new JMenuItem("Error getting " + file().getName()) }; //XXX
72
    }
73
74
    @Override
75
    protected JComponent[] refresh(JComponent[] old) {
76
        try {
77
            return get().synchMenuPresenters(old);
78
        } catch (IOException ex) {
79
            Exceptions.printStackTrace(ex);
80
        } catch (ClassNotFoundException ex) {
81
            Exceptions.printStackTrace(ex);
82
        }
83
        return old;
84
    }
85
}
(-)1f7b91420663 (+130 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.awt.EventQueue;
44
import java.io.IOException;
45
import javax.swing.JComponent;
46
import org.openide.cookies.InstanceCookie;
47
import org.openide.loaders.DataFolder;
48
import org.openide.loaders.DataObject;
49
50
/**
51
 *
52
 * @author Tim Boudreau
53
 */
54
abstract class FileModelEntry<T, CompType extends JComponent> extends ModelEntry <CompType, DataObject> {
55
    protected final Class<T> modelObjectType;
56
    FileModelEntry(DataObject dob, Class<CompType> componentType, Class<T> modelObjectType) {
57
        super (dob, DataObject.class, componentType);
58
        this.modelObjectType = modelObjectType;
59
        assert !(dob instanceof DataFolder) : "Folder used for menu item"; //NOI18N
60
    }
61
62
    private final InstanceCookie cookie() {
63
        DataObject dob = file();
64
        InstanceCookie ck = dob.getLookup().lookup(InstanceCookie.class);
65
        if (ck == null) {
66
            ck = new EmptyInstanceCookie(dob.getName());
67
        }
68
        return ck;
69
    }
70
71
    final boolean requiresEq() {
72
        return Component.class.isAssignableFrom(dobType);
73
    }
74
75
    protected T get() throws IOException, ClassNotFoundException {
76
        if (requiresEq() && !EventQueue.isDispatchThread()) {
77
            throw new IllegalStateException ("Not on event thread");
78
        }
79
        return modelObjectType.cast(cookie().instanceCreate());
80
    }
81
82
    private static final class EmptyInstanceCookie implements InstanceCookie, InstanceCookie.Of {
83
        private final String name;
84
        EmptyInstanceCookie (String name) {
85
            this.name = name;
86
        }
87
88
        @Override
89
        public String instanceName() {
90
            return name;
91
        }
92
93
        @Override
94
        public Class<?> instanceClass() throws IOException, ClassNotFoundException {
95
            return Object.class;
96
        }
97
98
        @Override
99
        public Object instanceCreate() throws IOException, ClassNotFoundException {
100
            return null;
101
        }
102
103
        @Override
104
        public boolean instanceOf(Class<?> type) {
105
            return false;
106
        }
107
108
        @Override
109
        public boolean equals(Object obj) {
110
            if (obj == null) {
111
                return false;
112
            }
113
            if (getClass() != obj.getClass()) {
114
                return false;
115
            }
116
            final EmptyInstanceCookie other = (EmptyInstanceCookie) obj;
117
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
118
                return false;
119
            }
120
            return true;
121
        }
122
123
        @Override
124
        public int hashCode() {
125
            int hash = 7;
126
            hash = 17 * hash + (this.name != null ? this.name.hashCode() : 0);
127
            return hash;
128
        }
129
    }
130
}
(-)1f7b91420663 (+336 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.Component;
42
import java.awt.EventQueue;
43
import java.io.IOException;
44
import java.util.ArrayList;
45
import java.util.Arrays;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.Iterator;
49
import java.util.LinkedList;
50
import java.util.List;
51
import java.util.Map;
52
import java.util.Set;
53
import javax.swing.Action;
54
import javax.swing.JComponent;
55
import javax.swing.JSeparator;
56
import org.openide.awt.DynamicMenuContent;
57
import org.openide.cookies.InstanceCookie;
58
import org.openide.loaders.DataFolder;
59
import org.openide.loaders.DataObject;
60
import org.openide.util.Exceptions;
61
import org.openide.util.Parameters;
62
import org.openide.util.actions.Presenter;
63
64
/**
65
 *
66
 * @author Tim Boudreau
67
 */
68
abstract class FolderModelEntry<CompType extends JComponent> extends ModelEntry<CompType, DataFolder> implements Callback {
69
70
    private final List<ModelEntry<?, ?>> children = new ArrayList<ModelEntry<?, ?>>(15);
71
    private final Object childLock = new Object();
72
    private final Object mapLock = new Object();
73
    private final Map<ModelEntry<?, ?>, ComponentList> comps4model =
74
            new HashMap<ModelEntry<?, ?>, ComponentList>();
75
76
    FolderModelEntry(DataFolder fld, Class<CompType> compType) {
77
        super(fld, DataFolder.class, compType);
78
    }
79
80
    boolean setChildren(List<ModelEntry<?, ?>> l) {
81
        boolean result;
82
        synchronized (childLock) {
83
            result = !children.equals(l);
84
            if (result) {
85
                children.clear();
86
                children.addAll(l);
87
            }
88
        }
89
        synchronized (mapLock) {
90
            if (!comps4model.isEmpty()) {
91
                Set<ModelEntry<?,?>> known = new HashSet<ModelEntry<?, ?>>(comps4model.keySet());
92
                known.removeAll(l);
93
                for (ModelEntry<?,?> m : known) {
94
                    comps4model.remove(m);
95
                }
96
            }
97
        }
98
        return result;
99
    }
100
101
    @Override
102
    public final void onHide(ModelEntry<?, ?> entry) {
103
        synchronized (mapLock) {
104
            for (Map.Entry<ModelEntry<?,?>, ComponentList> e : comps4model.entrySet()) {
105
                e.getValue().removeNotify();
106
            }
107
        }
108
    }
109
110
    @Override
111
    public final void onShow(ModelEntry<?, ?> entry) {
112
        synchronized (mapLock) {
113
            for (Map.Entry<ModelEntry<?,?>, ComponentList> e : comps4model.entrySet()) {
114
                e.getValue().addNotify();
115
            }
116
        }
117
    }
118
119
    private ComponentList components(ModelEntry<?,?> e) {
120
        Parameters.notNull("e", e);
121
        synchronized (mapLock) {
122
            return comps4model.get(e);
123
        }
124
    }
125
126
    private void setComponents (ModelEntry<?,?> e, ComponentList comps) {
127
        Parameters.notNull("comps", comps);
128
        Parameters.notNull("e", e);
129
        synchronized (mapLock) {
130
            if (comps == null) {
131
                comps4model.remove(e);
132
            } else {
133
                comps4model.put(e, comps);
134
            }
135
        }
136
    }
137
138
    List<ModelEntry<?, ?>> children() {
139
        synchronized (childLock) {
140
            return new ArrayList<ModelEntry<?, ?>>(children);
141
        }
142
    }
143
144
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
145
        //do nothing - for subclasses to force init
146
    }
147
148
    @Override
149
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children) {
150
//        System.err.println("initBackground " + getName());
151
        DataFolder fld = file();
152
        boolean changed = true;
153
        Set<ModelEntry<?, ?>> created = new HashSet<ModelEntry<?, ?>>();
154
        try {
155
            DataObject[] ch = fld.getChildren();
156
            if (ch != null) { //can be null
157
                outer:
158
                for (DataObject dob : ch) {
159
                    try {
160
                        for (Types t : Types.values()) {
161
                            if (t.accept(dob)) {
162
                                ModelEntry<?, ?> e = t.createEntry(dob, this);
163
                                created.add(e);
164
                                children.add(e);
165
                                //XXX defer or batch afterward?
166
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
167
                                boolean hasKids = e.initBackground(kids);
168
                                changed |= hasKids;
169
                                if (hasKids) {
170
                                    if (e instanceof FolderModelEntry) {
171
                                        FolderModelEntry<?> fme = FolderModelEntry.class.cast(e);
172
                                        changed |= fme.setChildren(kids);
173
                                    }
174
                                }
175
                                continue outer;
176
                            }
177
                        }
178
//                        System.err.println("No type accepted " + dob.getPrimaryFile().getPath() + " : " + ic(dob));
179
                    } catch (IOException ex) {
180
                        Exceptions.printStackTrace(ex);
181
                    } catch (ClassNotFoundException ex) {
182
                        Exceptions.printStackTrace(ex);
183
                    }
184
                }
185
            }
186
        } finally {
187
            onInitBackground(children);
188
        }
189
        return changed;
190
    }
191
192
//    private static String ic(DataObject dob) throws ClassNotFoundException, IOException {
193
//        InstanceCookie ck = dob.getCookie(InstanceCookie.class);
194
//        return ck == null ? " [no ic]" : ck.instanceClass().getName();
195
//    }
196
    @Override
197
    protected CompType refreshComponent(CompType old) {
198
        if (!EventQueue.isDispatchThread()) {
199
            throw new IllegalStateException("Not on event thread");
200
        }
201
//        long start = System.currentTimeMillis();
202
        Parameters.notNull("old", old);
203
        old.removeAll();
204
        List<JComponent> all = new LinkedList<JComponent>();
205
        List<ModelEntry<?, ?>> kids = children();
206
        Boolean expectHasIcon = false;
207
        for (ModelEntry<?, ?> e : kids) {
208
            ComponentList c = components(e);
209
            JComponent[] comps;
210
            if (c == null) {
211
                comps = e.getComponents();
212
                if (comps != null) {
213
                    all.addAll(Arrays.asList(comps));
214
                    setComponents(e, c = new ComponentList(comps));
215
                }
216
            } else {
217
                boolean allStillAlive = c.addNotify();
218
                if (allStillAlive) {
219
                    comps = e.refresh(c.getComponents());
220
                    ComponentList newComps;
221
                    if (comps != null && !((newComps = new ComponentList(comps)).equals(c))) {
222
                        setComponents(e, newComps);
223
                        c = newComps;
224
                    }
225
                } else {
226
                    comps = e.findComponents();
227
                    boolean fixed = c.repair(comps);
228
                    if (!fixed) {
229
                        setComponents(e, c = new ComponentList(comps));
230
                    }
231
                }
232
            }
233
            if (comps != null) {
234
                for (JComponent comp : comps) {
235
                    expectHasIcon = ModelEntry.defaultHasIcon(comp, expectHasIcon);
236
                }
237
            }
238
            if (c != null) {
239
                all.addAll(Arrays.asList(c.getComponents()));
240
            }
241
        }
242
        pruneSeparatorsAndFixIcons(all, expectHasIcon);
243
        installComponents(all, old);
244
//        long dur = System.currentTimeMillis() - start;
245
//        System.err.println("Refresh " + getName() + " took " + dur + " milliseconds");
246
        return old;
247
    }
248
249
    protected void installComponents(List<? extends JComponent> components, CompType into) {
250
        for (Component c : components) {
251
            if (c == null) {
252
                c = new JSeparator();
253
            }
254
            into.add(c);
255
        }
256
    }
257
258
    private void pruneSeparatorsAndFixIcons(List<JComponent> all, Boolean icons) {
259
        boolean lastWasSep = true;
260
        for (Iterator<JComponent> i = all.iterator(); i.hasNext();) {
261
            JComponent c = i.next();
262
            boolean isSep = c instanceof JSeparator;
263
            if ((lastWasSep && isSep) || (!i.hasNext() && isSep)) {
264
                i.remove();
265
            }
266
            lastWasSep = isSep;
267
            if (icons != null) {
268
                ModelEntry.configureIcon(c, icons);
269
            }
270
        }
271
    }
272
273
    private static enum Types {
274
275
        SEPARATOR(JSeparator.class),
276
        DYNAMIC_MENU_CONTENT(DynamicMenuContent.class),
277
        PRESENTER(Presenter.Menu.class),
278
        MENU,
279
        COMPONENT(Component.class),
280
        ACTION(Action.class);
281
        private final Class<?> type;
282
283
        Types(Class<?> type) {
284
            this.type = type;
285
        }
286
287
        Types() {
288
            this(Object.class);
289
        }
290
291
        boolean accept(DataObject dob) throws IOException, ClassNotFoundException {
292
            if (this == MENU) {
293
                DataFolder fld = dob instanceof DataFolder ? (DataFolder) dob
294
                        : dob.getLookup().lookup(DataFolder.class);
295
                return fld != null;
296
            }
297
            InstanceCookie ck = dob.getLookup().lookup(InstanceCookie.class);
298
            return ck instanceof InstanceCookie.Of ? ((InstanceCookie.Of) ck).instanceOf(type)
299
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
300
        }
301
302
        ModelEntry<?, ?> createEntry(DataObject ob, Callback callback) {
303
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
304
            switch (this) {
305
                case SEPARATOR:
306
                    return new SeparatorModelEntry(ob);
307
                case ACTION:
308
                    InstanceCookie ic = ob.getLookup().lookup(InstanceCookie.class);
309
                    try {
310
                        //This is a bit of a mess - some InstanceCookies lie
311
                        if (ic.instanceCreate() instanceof Presenter.Menu) {
312
                            return new PresenterEntry(ob);
313
                        }
314
                    } catch (IOException ex) {
315
                        Exceptions.printStackTrace(ex);
316
                    } catch (ClassNotFoundException ex) {
317
                        Exceptions.printStackTrace(ex);
318
                    }
319
                    return new ActionModelEntry(ob);
320
                case DYNAMIC_MENU_CONTENT:
321
                    return new DynamicModelEntry(ob);
322
                case PRESENTER:
323
                    return new PresenterEntry(ob);
324
                case MENU:
325
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
326
                            : ob.getLookup().lookup(DataFolder.class);
327
                    Parameters.notNull("folder was non-null but is now null", fld);
328
                    return new MenuEntry(fld, null);
329
                case COMPONENT:
330
                    return new ComponentModelEntry(ob);
331
                default:
332
                    throw new AssertionError(this + "");
333
            }
334
        }
335
    }
336
}
(-)1f7b91420663 (+150 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import java.util.LinkedList;
44
import java.util.List;
45
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
49
import org.openide.filesystems.FileRenameEvent;
50
import org.openide.loaders.DataFolder;
51
import org.openide.util.RequestProcessor;
52
53
/**
54
 *
55
 * @author Tim Boudreau
56
 */
57
final class MenuBarModel extends FolderModelEntry<JMenuBar> {
58
    private final JMenuBar bar;
59
    private FCA fca = new FCA();
60
    private final RequestProcessor.Task task;
61
    private static final int DELAY = 100;
62
    MenuBarModel (DataFolder rootFolder, JMenuBar bar, RequestProcessor rp) {
63
        super (rootFolder, JMenuBar.class);
64
        this.bar = bar;
65
        this.task = rp.create(fca);
66
        rootFolder.getPrimaryFile().addFileChangeListener(fca);
67
    }
68
69
    void init() {
70
        fca.refresh();
71
    }
72
73
    @Override
74
    protected JMenuBar findComponent() {
75
        return bar;
76
    }
77
78
    @Override
79
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
80
        super.onInitBackground(children);
81
        if (!refreshing) {
82
            EventQueue.invokeLater(fca);
83
        }
84
    }
85
86
    volatile boolean refreshing;
87
    private final class FCA extends FileChangeAdapter implements Runnable {
88
        private volatile boolean enqueued;
89
        boolean refresh() {
90
            boolean result;
91
            synchronized (this) {
92
                result = enqueued;
93
                if (!enqueued) {
94
                    enqueued = true;
95
                    task.schedule(DELAY);
96
                }
97
                return result;
98
            }
99
        }
100
101
        @Override
102
        public void run() {
103
            if (!EventQueue.isDispatchThread()) {
104
                refreshing = true;
105
                try {
106
                    List<ModelEntry<?,?>> l = new LinkedList<ModelEntry<?,?>>();
107
                    initBackground(l);
108
                    setChildren(l);
109
                } finally {
110
                    refreshing = false;
111
                    EventQueue.invokeLater(this);
112
                }
113
            } else {
114
                enqueued = false;
115
                bar.removeAll();
116
                MenuBarModel.this.refresh(new JMenuBar[] { bar });
117
            }
118
        }
119
120
        @Override
121
        public void fileAttributeChanged(FileAttributeEvent fe) {
122
            refresh();
123
        }
124
125
        @Override
126
        public void fileChanged(FileEvent fe) {
127
            refresh();
128
        }
129
130
        @Override
131
        public void fileDataCreated(FileEvent fe) {
132
            refresh();
133
        }
134
135
        @Override
136
        public void fileDeleted(FileEvent fe) {
137
            refresh();
138
        }
139
140
        @Override
141
        public void fileFolderCreated(FileEvent fe) {
142
            refresh();
143
        }
144
145
        @Override
146
        public void fileRenamed(FileRenameEvent fe) {
147
            refresh();
148
        }
149
    }
150
}
(-)1f7b91420663 (+106 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import java.lang.ref.Reference;
44
import java.lang.ref.WeakReference;
45
import javax.swing.ButtonModel;
46
import javax.swing.JMenu;
47
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeListener;
49
import org.openide.awt.Mnemonics;
50
import org.openide.loaders.DataFolder;
51
52
/**
53
 *
54
 * @author Tim Boudreau
55
 */
56
final class MenuEntry extends FolderModelEntry<JMenu> implements ChangeListener {
57
58
    private Reference<JMenu> menu;
59
    private final Callback callback;
60
61
    MenuEntry (DataFolder fld, Callback callback) {
62
        super (fld, JMenu.class);
63
        this.callback = callback == null ? this : callback;
64
    }
65
66
    private JMenu menu() {
67
        JMenu result = menu == null ? null : menu.get();
68
        if (result == null) {
69
            result = new JMenu();
70
            Mnemonics.setLocalizedText(result, getName());
71
            result.getModel().addChangeListener(this);
72
            menu = new WeakReference<JMenu> (result);
73
        }
74
        return result;
75
    }
76
77
    @Override
78
    protected JMenu findComponent() {
79
        assert EventQueue.isDispatchThread();
80
        return menu();
81
    }
82
83
    private boolean wasSelected = false;
84
    @Override
85
    public void stateChanged(ChangeEvent e) {
86
        ButtonModel mdl = (ButtonModel) e.getSource();
87
        boolean selected = mdl.isSelected();
88
        //XXX wasSelected could be true if the old component was garbage collected
89
        //without resetting its model - possible?
90
        if (selected && !wasSelected) {
91
            if (callback != null) {
92
                callback.onShow(this);
93
            }
94
            refreshComponent(menu());
95
        } else if (wasSelected && !selected) {
96
            JMenu m = menu == null ? null : menu.get();
97
            if (m != null) {
98
                m.removeAll();
99
            }
100
            if (callback != null) {
101
                callback.onHide(this);
102
            }
103
        }
104
        wasSelected = selected;
105
    }
106
}
(-)1f7b91420663 (+63 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import javax.swing.JMenuBar;
43
import org.openide.loaders.DataFolder;
44
import org.openide.util.RequestProcessor;
45
46
/**
47
 *
48
 * @author Tim Boudreau
49
 */
50
final class MenuManager {
51
    private final JMenuBar bar;
52
    private final RequestProcessor rp = new RequestProcessor("Main Menu Refresh", 1, true);
53
    private final MenuBarModel model;
54
55
    MenuManager(DataFolder folder, JMenuBar bar) {
56
        this.bar = bar;
57
        model = new MenuBarModel (folder, bar, rp);
58
    }
59
60
    void init() {
61
        model.init();
62
    }
63
}
(-)1f7b91420663 (+81 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import javax.swing.JFrame;
44
import javax.swing.JMenuBar;
45
import org.netbeans.api.menus.MenuProvider;
46
import org.openide.filesystems.FileObject;
47
import org.openide.filesystems.FileUtil;
48
import org.openide.loaders.DataFolder;
49
import org.openide.util.lookup.ServiceProvider;
50
51
/**
52
 *
53
 * @author Tim Boudreau
54
 */
55
@ServiceProvider(service=MenuProvider.class)
56
public final class MenuProviderImpl extends MenuProvider {
57
    private static final String MENU_FOLDER = "Menu"; //NOI18N
58
    private FileObject menuFolder;
59
    public MenuProviderImpl () {
60
        this (FileUtil.getConfigFile(MENU_FOLDER));
61
    }
62
63
    MenuProviderImpl (FileObject menuFolder) { //used in unit tests w/ memfs
64
        this.menuFolder = menuFolder;
65
    }
66
67
    @Override
68
    protected JMenuBar createMenu(JFrame target) {
69
        if (!EventQueue.isDispatchThread()) {
70
            throw new IllegalStateException("Not on event thread"); //NOI18N
71
        }
72
        FileObject menuFO = menuFolder;
73
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
74
        JMenuBar bar = new JMenuBar();
75
        bar.setBorderPainted(false);
76
        MenuManager mgr = new MenuManager(menuFolder, bar);
77
        mgr.init();
78
        return bar;
79
    }
80
81
}
(-)1f7b91420663 (+172 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.EventQueue;
43
import java.lang.reflect.Array;
44
import java.util.List;
45
import javax.swing.Icon;
46
import javax.swing.JComponent;
47
import javax.swing.JMenuItem;
48
import org.openide.loaders.DataObject;
49
import org.openide.util.ImageUtilities;
50
import org.openide.util.Parameters;
51
52
/**
53
 *
54
 * @author Tim Boudreau
55
 */
56
public abstract class ModelEntry<CompType extends JComponent, DataObjectType extends DataObject> {
57
    private final DataObjectType file;
58
    protected final Class<DataObjectType> dobType;
59
    private Class<CompType> compType;
60
    protected static final Icon BLANK_ICON = ImageUtilities.loadImageIcon("org/openide/loaders/empty.gif", false); // NOI18N
61
    public ModelEntry(DataObjectType file, Class<DataObjectType> dobType, Class<CompType> compType) {
62
        this.file = file;
63
        this.dobType = dobType;
64
        this.compType = compType;
65
        Parameters.notNull("compType", compType);
66
        Parameters.notNull("dobType", dobType);
67
        Parameters.notNull("file", file);
68
    }
69
    
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
71
72
    public String getName() {
73
        return file().getNodeDelegate().getDisplayName();
74
    }
75
76
    protected final DataObjectType file() {
77
        return file;
78
    }
79
80
    final Class<CompType> componentType() {
81
        return compType;
82
    }
83
84
    final CompType[] getComponents() {
85
        if (!EventQueue.isDispatchThread()) {
86
            throw new IllegalStateException ("Not on event thread"); //NOI18N
87
        }
88
        return findComponents();
89
    }
90
91
    final CompType[] refreshComponents(CompType[] old) {
92
        if (!EventQueue.isDispatchThread()) {
93
            throw new IllegalStateException ("Not on event thread"); //NOI18N
94
        }
95
        return refresh (old);
96
    }
97
98
    protected CompType[] refresh (CompType[] old) {
99
        return toCompTypeArray(new Object[] { refreshComponent( old.length == 0 ? null : old[0]) });
100
    }
101
102
    protected CompType[] findComponents() {
103
        return toCompTypeArray (new Object[] { findComponent() });
104
    }
105
106
    protected final CompType[] toCompTypeArray(CompType type) {
107
        return toCompTypeArray (new Object[] { type });
108
    }
109
110
    protected final CompType[] toCompTypeArray(Object[] objs) {
111
        CompType[] c = (CompType[]) Array.newInstance(compType, objs == null ? 0 : objs.length);
112
        System.arraycopy(objs, 0, c, 0, objs.length);
113
        return c;
114
    }
115
116
    protected CompType findComponent() {
117
        throw new UnsupportedOperationException("Override findComponent() " + //NOI18N
118
                "or findComponents() in " + getClass().getName()); //NOI18N
119
    }
120
121
    protected CompType refreshComponent(CompType old) {
122
        throw new UnsupportedOperationException("Override refreshComponent() or " + //NOI18N
123
                "refreshComponents() in "  + getClass().getName()); //NOI18N
124
    }
125
126
    protected static void configureIcon (JComponent comp, boolean wantIcons) {
127
        if (comp instanceof JMenuItem) {
128
            JMenuItem item = (JMenuItem) comp;
129
            Icon icon = item.getIcon();
130
            if (!wantIcons && icon != null) {
131
                item.setIcon(null);
132
            } else if (wantIcons && icon == null) {
133
                item.setIcon (BLANK_ICON);
134
            }
135
        }
136
    }
137
138
    protected static Boolean defaultHasIcon (JComponent comp, Boolean hasIcon) {
139
        if (hasIcon != null && hasIcon) {
140
            return hasIcon;
141
        }
142
        if (comp instanceof JMenuItem) {
143
            Icon icon = ((JMenuItem) comp).getIcon();
144
            if (icon != null && BLANK_ICON != icon) {
145
                return true;
146
            }
147
        }
148
        return null;
149
    }
150
151
    @Override
152
    public boolean equals(Object obj) {
153
        if (obj == null) {
154
            return false;
155
        }
156
        if (getClass() != obj.getClass()) {
157
            return false;
158
        }
159
        final ModelEntry<?, ?> other = (ModelEntry<?, ?>) obj;
160
        if (this.file() != other.file() && (this.file() == null || !this.file().equals(other.file()))) {
161
            return false;
162
        }
163
        return true;
164
    }
165
166
    @Override
167
    public int hashCode() {
168
        int hash = 3;
169
        hash = 31 * hash + (this.file != null ? this.file.hashCode() : 0);
170
        return hash;
171
    }
172
}
(-)1f7b91420663 (+86 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.Component;
43
import java.io.IOException;
44
import javax.swing.JComponent;
45
import javax.swing.JMenuItem;
46
import org.openide.awt.DynamicMenuContent;
47
import org.openide.loaders.DataObject;
48
import org.openide.util.Exceptions;
49
import org.openide.util.actions.Presenter;
50
51
/**
52
 *
53
 * @author Tim Boudreau
54
 */
55
public class PresenterEntry extends ThreadUnconstrainedModelEntry<Presenter.Menu, JComponent> {
56
    private DynamicMenuContent dmc;
57
    PresenterEntry (DataObject dob) {
58
        super (dob, JComponent.class, Presenter.Menu.class);
59
    }
60
61
    @Override
62
    protected JComponent[] findComponents() {
63
        try {
64
            Presenter.Menu p = super.get();
65
            JMenuItem c = p.getMenuPresenter();
66
            if (c instanceof DynamicMenuContent) { //ToolsAction.Inline
67
                dmc = (DynamicMenuContent) c;
68
                return dmc.getMenuPresenters();
69
            }
70
            return new JComponent[] { c };
71
        } catch (IOException ex) {
72
            Exceptions.printStackTrace(ex);
73
        } catch (ClassNotFoundException ex) {
74
            Exceptions.printStackTrace(ex);
75
        }
76
        return new JComponent[] { new JMenuItem("Error fetching " + file().getName()) }; //XXX
77
    }
78
79
    @Override
80
    protected JComponent[] refresh(JComponent[] old) {
81
        if (dmc != null) {
82
            return dmc.synchMenuPresenters(old);
83
        }
84
        return old;
85
    }
86
}
(-)1f7b91420663 (+69 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.util.List;
43
import javax.swing.JSeparator;
44
import org.openide.loaders.DataObject;
45
46
/**
47
 *
48
 * @author Tim Boudreau
49
 */
50
final class SeparatorModelEntry extends FileModelEntry <JSeparator, JSeparator> {
51
    SeparatorModelEntry(DataObject dob) {
52
        super (dob, JSeparator.class, JSeparator.class);
53
    }
54
55
    @Override
56
    protected JSeparator findComponent() {
57
        return new JSeparator();
58
    }
59
60
    @Override
61
    protected JSeparator refreshComponent(JSeparator old) {
62
        return old == null ? findComponent() : old;
63
    }
64
65
    @Override
66
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
67
        return false;
68
    }
69
}
(-)1f7b91420663 (+83 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.io.IOException;
43
import java.util.List;
44
import java.util.concurrent.atomic.AtomicReference;
45
import javax.swing.JComponent;
46
import org.openide.loaders.DataObject;
47
import org.openide.util.Exceptions;
48
49
/**
50
 *
51
 * @author Tim Boudreau
52
 */
53
public abstract class ThreadUnconstrainedModelEntry<T, CompType extends JComponent> extends FileModelEntry<T, CompType> {
54
    private final AtomicReference<T> ref = new AtomicReference<T>();
55
56
    ThreadUnconstrainedModelEntry(DataObject dob, Class<CompType> componentType, Class<T> modelObjectType) {
57
        super(dob, componentType, modelObjectType);
58
    }
59
60
    @Override
61
    protected final T get() throws IOException, ClassNotFoundException {
62
        T result = ref.get();
63
        if (result == null) {
64
            result = super.get();
65
            ref.set(result);
66
        }
67
        return result;
68
    }
69
70
    @Override
71
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
72
        //Since it is non-gui, instantiate the Action in the background
73
        try {
74
            ref.set(super.get());
75
        } catch (IOException ex) {
76
            Exceptions.printStackTrace(ex);
77
        } catch (ClassNotFoundException ex) {
78
            Exceptions.printStackTrace(ex);
79
        }
80
        return false;
81
    }
82
83
}
(-)1f7b91420663 (+7 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        
6
    </folder>
7
</filesystem>
(-)1f7b91420663 (+84 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import javax.swing.JComponent;
43
import javax.swing.JMenu;
44
import javax.swing.JMenuItem;
45
import org.openide.awt.DynamicMenuContent;
46
47
/**
48
 *
49
 * @author Tim Boudreau
50
 */
51
public class DynAction implements DynamicMenuContent {
52
    private static final int count = 5;
53
    static int total;
54
    final int index;
55
    public DynAction() {
56
        index = total++;
57
    }
58
59
    @Override
60
    public JComponent[] getMenuPresenters() {
61
        JComponent[] result = new JComponent[count];
62
        for (int i= 0; i < result.length; i++) {
63
            JMenuItem j = new JMenuItem ("Dynamic " + index + ":" + i);
64
            j.putClientProperty("caption", j.getText());
65
            j.putClientProperty("syncCount", 0);
66
            result[i] = j;
67
        }
68
        return result;
69
    }
70
71
    @Override
72
    public JComponent[] synchMenuPresenters(JComponent[] items) {
73
        for (JComponent jc : items) {
74
            JMenuItem m = (JMenuItem) jc;
75
            String cap = (String) m.getClientProperty("caption");
76
            int syncs = ((Integer) m.getClientProperty("syncCount")).intValue();
77
            syncs ++;
78
            m.putClientProperty("syncCount", syncs);
79
            m.setText (cap + " (sync " + syncs + ")");
80
        }
81
        return items;
82
    }
83
84
}
(-)1f7b91420663 (+203 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.Component;
42
import java.awt.Dimension;
43
import java.awt.EventQueue;
44
import java.awt.event.ContainerEvent;
45
import java.awt.event.ContainerListener;
46
import java.awt.event.MouseEvent;
47
import java.lang.ref.Reference;
48
import java.lang.ref.WeakReference;
49
import java.util.ArrayList;
50
import java.util.List;
51
import java.util.concurrent.CountDownLatch;
52
import java.util.concurrent.TimeUnit;
53
import javax.swing.AbstractButton;
54
import javax.swing.JComponent;
55
import javax.swing.JFrame;
56
import javax.swing.JMenu;
57
import javax.swing.JMenuBar;
58
import javax.swing.JMenuItem;
59
import javax.swing.JPanel;
60
import javax.swing.JPopupMenu;
61
import org.junit.Test;
62
import org.netbeans.junit.NbTestCase;
63
import org.openide.filesystems.FileSystem;
64
import org.openide.filesystems.XMLFileSystem;
65
66
/**
67
 *
68
 * @author tim
69
 */
70
public class MenuProviderImplTest extends NbTestCase {
71
72
    private MenuProviderImpl m;
73
    private JMenuBar bar;
74
    private JFrame jf;
75
    private JMenu menu;
76
77
    public MenuProviderImplTest(String name) {
78
        super(name);
79
    }
80
81
    @Override
82
    protected boolean runInEQ() {
83
        return false;
84
    }
85
86
    @Override
87
    public void setUp() throws Exception {
88
        FileSystem fs = new XMLFileSystem(MenuProviderImplTest.class.getResource("fakelayer.xml"));
89
        m = new MenuProviderImpl(fs.getRoot().getFileObject("Menu"));
90
        R r = new R();
91
92
        EventQueue.invokeAndWait(r);
93
        r.latch.await(20000, TimeUnit.MILLISECONDS);
94
        while (!jf.isShowing()) {
95
            Thread.sleep(30);
96
        }
97
        assertFalse(bar.getMenuCount() == 0);
98
        menu = bar.getMenu(0);
99
    }
100
101
    @Override
102
    public void tearDown() {
103
        jf.dispose();
104
    }
105
106
    private void click(final JComponent comp, final boolean showMenu) throws Exception {
107
        EventQueue.invokeAndWait(new Runnable() {
108
109
            public void run() {
110
                ((AbstractButton) comp).getModel().setPressed(showMenu);
111
                MouseEvent evt = new MouseEvent(comp, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
112
                        0, 5, 5, 1, false, 0);
113
                comp.dispatchEvent(evt);
114
                evt = new MouseEvent(comp, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
115
                        0, 5, 5, 1, false, 0);
116
                comp.dispatchEvent(evt);
117
                evt = new MouseEvent(comp, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(),
118
                        0, 5, 5, 1, false, 0);
119
                comp.dispatchEvent(evt);
120
            }
121
        });
122
        if (comp instanceof JMenu) {
123
            JMenu m = (JMenu) comp;
124
            while (showMenu != m.getPopupMenu().isShowing()) {
125
                Thread.sleep (100);
126
            }
127
        }
128
    }
129
130
    @Test
131
    public void testMenuItemsAreNotStronglyReferenced() throws Exception {
132
        assertNotNull (menu);
133
        click (menu, true);
134
        JPopupMenu popup = menu.getPopupMenu();
135
        Component[] c = popup.getComponents();
136
        assertEquals (7, c.length);
137
        List<Reference<Component>> l = new ArrayList<Reference<Component>>();
138
        boolean presenterActionFound = false;
139
        boolean regularActionFound = false;
140
        int pActionIx = -1;
141
        int rActionIx = -1;
142
        for (int i=0; i < c.length; i++) {
143
            Component cc = c[i];
144
            boolean wasPactionFound = presenterActionFound;
145
            presenterActionFound |= cc instanceof PresenterAction.Marker;
146
            if (!wasPactionFound && presenterActionFound) {
147
                pActionIx = i;
148
            }
149
            l.add (new WeakReference<Component>(cc));
150
            boolean wasRactionFound = regularActionFound;
151
            regularActionFound |= cc instanceof JMenuItem && ((JMenuItem) cc).getText().equals("Regular Action");
152
            if (!wasRactionFound && regularActionFound) {
153
                rActionIx = i;
154
            }
155
        }
156
        //Test order while we're here
157
        assertTrue (presenterActionFound);
158
        assertTrue (regularActionFound);
159
        assertEquals ("Wrong index for presenter action", 5, pActionIx);
160
        assertEquals ("Wrong index for presenter action", 6, rActionIx);
161
        click (menu, false);
162
        c = null;
163
        for (Reference<?> r : l) {
164
            assertGC("Menu component not collected", r);
165
        }
166
    }
167
    private static final int EXPECTED_MENU_COUNT = 1; //update if more added to xml
168
169
    private class R implements Runnable, ContainerListener {
170
171
        private final CountDownLatch latch = new CountDownLatch(1);
172
173
        @Override
174
        public void run() {
175
            jf = new JFrame();
176
            bar = m.createMenu(jf);
177
            bar.addContainerListener(this);
178
            JPanel pnl = new JPanel();
179
            pnl.setMinimumSize(new Dimension(300, 300));
180
            pnl.setPreferredSize(new Dimension(300, 300));
181
            jf.setContentPane(pnl);
182
            jf.setJMenuBar(bar);
183
            jf.pack();
184
            jf.setVisible(true);
185
        }
186
187
        @Override
188
        public void componentAdded(ContainerEvent e) {
189
            int count = e.getContainer().getComponentCount();
190
            if (count == EXPECTED_MENU_COUNT) {
191
                latch.countDown();
192
                e.getContainer().invalidate();
193
                ((JMenuBar) e.getContainer()).revalidate();
194
                e.getContainer().repaint();
195
            }
196
        }
197
198
        @Override
199
        public void componentRemoved(ContainerEvent e) {
200
            //do nothing
201
        }
202
    }
203
}
(-)1f7b91420663 (+69 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import javax.swing.JMenuItem;
45
import org.openide.util.actions.Presenter;
46
47
/**
48
 *
49
 * @author Tim Boudreau
50
 */
51
public class PresenterAction extends AbstractAction implements Presenter.Menu {
52
53
    @Override
54
    public JMenuItem getMenuPresenter() {
55
        return new Marker ("Menu Presenter");
56
    }
57
58
    @Override
59
    public void actionPerformed(ActionEvent e) {
60
        throw new UnsupportedOperationException("Not supported yet.");
61
    }
62
63
    public class Marker extends JMenuItem {
64
        Marker (String s) {
65
            super (s);
66
        }
67
    }
68
69
}
(-)1f7b91420663 (+59 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
45
/**
46
 *
47
 * @author Tim Boudreau
48
 */
49
public class RegularAction extends AbstractAction {
50
    private boolean performed;
51
    public RegularAction() {
52
        putValue (NAME, "Regular Action");
53
    }
54
55
    @Override
56
    public void actionPerformed(ActionEvent e) {
57
        performed = true;
58
    }
59
}
(-)1f7b91420663 (+17 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="One">
6
            <file name="org-netbeans-core-menu-DynAction.instance">
7
                <attr name="position" intvalue="0"/>
8
            </file>
9
            <file name="org-netbeans-core-menu-PresenterAction.instance">
10
                <attr name="position" intvalue="1"/>
11
            </file>
12
            <file name="org-netbeans-core-menu-RegularAction.instance">
13
                <attr name="position" intvalue="2"/>
14
            </file>
15
        </folder>
16
    </folder>
17
</filesystem>
(-)a/nbbuild/cluster.properties (+2 lines)
Lines 184-189 Link Here
184
nb.cluster.platform.depends=
184
nb.cluster.platform.depends=
185
nb.cluster.platform=\
185
nb.cluster.platform=\
186
        api.annotations.common,\
186
        api.annotations.common,\
187
        api.menus,\
187
        api.progress,\
188
        api.progress,\
188
        api.visual,\
189
        api.visual,\
189
        applemenu,\
190
        applemenu,\
Lines 192-197 Link Here
192
        core.execution,\
193
        core.execution,\
193
        core.io.ui,\
194
        core.io.ui,\
194
        core.kit,\
195
        core.kit,\
196
        core.menu,\
195
        core.multiview,\
197
        core.multiview,\
196
        core.nativeaccess,\
198
        core.nativeaccess,\
197
        core.netigso,\
199
        core.netigso,\
(-)a/core.windows/manifest.mf (-1 / +1 lines)
Lines 6-10 Link Here
6
OpenIDE-Module-Recommends: org.netbeans.core.windows.nativeaccess.NativeWindowSystem
6
OpenIDE-Module-Recommends: org.netbeans.core.windows.nativeaccess.NativeWindowSystem
7
AutoUpdate-Show-In-Client: false
7
AutoUpdate-Show-In-Client: false
8
AutoUpdate-Essential-Module: true
8
AutoUpdate-Essential-Module: true
9
OpenIDE-Module-Specification-Version: 2.20
9
OpenIDE-Module-Specification-Version: 2.21
10
10
(-)a/core.windows/nbproject/project.xml (+9 lines)
Lines 47-52 Link Here
47
            <code-name-base>org.netbeans.core.windows</code-name-base>
47
            <code-name-base>org.netbeans.core.windows</code-name-base>
48
            <module-dependencies>
48
            <module-dependencies>
49
                <dependency>
49
                <dependency>
50
                    <code-name-base>org.netbeans.api.menus</code-name-base>
51
                    <build-prerequisite/>
52
                    <compile-dependency/>
53
                    <run-dependency>
54
                        <release-version>1</release-version>
55
                        <specification-version>1.0</specification-version>
56
                    </run-dependency>
57
                </dependency>
58
                <dependency>
50
                    <code-name-base>org.netbeans.core</code-name-base>
59
                    <code-name-base>org.netbeans.core</code-name-base>
51
                    <build-prerequisite/>
60
                    <build-prerequisite/>
52
                    <compile-dependency/>
61
                    <compile-dependency/>
(-)a/core.windows/src/org/netbeans/core/windows/WindowSystemImpl.java (-3 lines)
Lines 45-53 Link Here
45
45
46
import java.awt.EventQueue;
46
import java.awt.EventQueue;
47
import org.netbeans.core.WindowSystem;
47
import org.netbeans.core.WindowSystem;
48
import org.netbeans.core.windows.persistence.PersistenceManager;
49
import org.netbeans.core.windows.services.DialogDisplayerImpl;
48
import org.netbeans.core.windows.services.DialogDisplayerImpl;
50
import org.netbeans.core.windows.view.ui.MainWindow;
51
import org.openide.util.lookup.ServiceProvider;
49
import org.openide.util.lookup.ServiceProvider;
52
50
53
51
Lines 61-67 Link Here
61
59
62
    public void init() {
60
    public void init() {
63
        assert !EventQueue.isDispatchThread();
61
        assert !EventQueue.isDispatchThread();
64
        MainWindow.init();
65
    }
62
    }
66
63
67
    public void load() {
64
    public void load() {
(-)a/core.windows/src/org/netbeans/core/windows/view/ViewHierarchy.java (+1 lines)
Lines 122-127 Link Here
122
    public MainWindow getMainWindow() {
122
    public MainWindow getMainWindow() {
123
        if (mainWindow == null) {
123
        if (mainWindow == null) {
124
            mainWindow = new MainWindow();
124
            mainWindow = new MainWindow();
125
            mainWindow.init();
125
        }
126
        }
126
        return mainWindow;
127
        return mainWindow;
127
    }
128
    }
(-)a/core.windows/src/org/netbeans/core/windows/view/ui/MainWindow.java (-2 / +7 lines)
Lines 62-67 Link Here
62
import javax.swing.JPanel;
62
import javax.swing.JPanel;
63
import javax.swing.border.*;
63
import javax.swing.border.*;
64
import javax.swing.event.*;
64
import javax.swing.event.*;
65
import org.netbeans.api.menus.MenuProvider;
65
import org.netbeans.core.windows.*;
66
import org.netbeans.core.windows.*;
66
import org.netbeans.core.windows.view.ui.toolbars.ToolbarConfiguration;
67
import org.netbeans.core.windows.view.ui.toolbars.ToolbarConfiguration;
67
import org.openide.LifecycleManager;
68
import org.openide.LifecycleManager;
Lines 138-144 Link Here
138
        }
139
        }
139
    }
140
    }
140
141
141
    public static void init() {
142
    public void init() {
142
        if (mainMenuBar == null) {
143
        if (mainMenuBar == null) {
143
            mainMenuBar = createMenuBar();
144
            mainMenuBar = createMenuBar();
144
            ToolbarPool.getDefault().waitFinished();
145
            ToolbarPool.getDefault().waitFinished();
Lines 365-372 Link Here
365
        );
366
        );
366
    }
367
    }
367
368
369
    private JMenuBar createMenuBar() {
370
        return MenuProvider.installMenu(this);
371
    }
372
368
    /** Creates menu bar. */
373
    /** Creates menu bar. */
369
    private static JMenuBar createMenuBar() {
374
    private static JMenuBar xcreateMenuBar() {
370
        JMenuBar menu = getCustomMenuBar();
375
        JMenuBar menu = getCustomMenuBar();
371
        if (menu == null) {
376
        if (menu == null) {
372
             menu = new MenuBar (null);
377
             menu = new MenuBar (null);
(-)a/core.menu/src/org/netbeans/core/menu/FolderModelEntry.java (-2 / +6 lines)
Lines 52-57 Link Here
52
import java.util.Set;
52
import java.util.Set;
53
import javax.swing.Action;
53
import javax.swing.Action;
54
import javax.swing.JComponent;
54
import javax.swing.JComponent;
55
import javax.swing.JMenuItem;
55
import javax.swing.JSeparator;
56
import javax.swing.JSeparator;
56
import org.openide.awt.DynamicMenuContent;
57
import org.openide.awt.DynamicMenuContent;
57
import org.openide.cookies.InstanceCookie;
58
import org.openide.cookies.InstanceCookie;
Lines 267-272 Link Here
267
            if (icons != null) {
268
            if (icons != null) {
268
                ModelEntry.configureIcon(c, icons);
269
                ModelEntry.configureIcon(c, icons);
269
            }
270
            }
271
            if (c instanceof JMenuItem) {
272
                c.setToolTipText(null);
273
            }
270
        }
274
        }
271
    }
275
    }
272
276
Lines 299-305 Link Here
299
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
303
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
300
        }
304
        }
301
305
302
        ModelEntry<?, ?> createEntry(DataObject ob, Callback callback) {
306
        ModelEntry<?, ?> createEntry(DataObject ob, FolderModelEntry entry) {
303
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
307
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
304
            switch (this) {
308
            switch (this) {
305
                case SEPARATOR:
309
                case SEPARATOR:
Lines 325-331 Link Here
325
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
329
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
326
                            : ob.getLookup().lookup(DataFolder.class);
330
                            : ob.getLookup().lookup(DataFolder.class);
327
                    Parameters.notNull("folder was non-null but is now null", fld);
331
                    Parameters.notNull("folder was non-null but is now null", fld);
328
                    return new MenuEntry(fld, null);
332
                    return new MenuEntry(fld, MenuManager.rp);
329
                case COMPONENT:
333
                case COMPONENT:
330
                    return new ComponentModelEntry(ob);
334
                    return new ComponentModelEntry(ob);
331
                default:
335
                default:
(-)a/core.menu/src/org/netbeans/core/menu/MenuBarModel.java (-88 / +4 lines)
Lines 39-52 Link Here
39
39
40
package org.netbeans.core.menu;
40
package org.netbeans.core.menu;
41
41
42
import java.awt.EventQueue;
43
import java.util.LinkedList;
44
import java.util.List;
45
import javax.swing.JMenuBar;
42
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
49
import org.openide.filesystems.FileRenameEvent;
50
import org.openide.loaders.DataFolder;
43
import org.openide.loaders.DataFolder;
51
import org.openide.util.RequestProcessor;
44
import org.openide.util.RequestProcessor;
52
45
Lines 54-73 Link Here
54
 *
47
 *
55
 * @author Tim Boudreau
48
 * @author Tim Boudreau
56
 */
49
 */
57
final class MenuBarModel extends FolderModelEntry<JMenuBar> {
50
final class MenuBarModel extends RefreshingFolderModelEntry<JMenuBar> {
58
    private final JMenuBar bar;
51
    private final JMenuBar bar;
59
    private FCA fca = new FCA();
60
    private final RequestProcessor.Task task;
61
    private static final int DELAY = 100;
62
    MenuBarModel (DataFolder rootFolder, JMenuBar bar, RequestProcessor rp) {
52
    MenuBarModel (DataFolder rootFolder, JMenuBar bar, RequestProcessor rp) {
63
        super (rootFolder, JMenuBar.class);
53
        super (rootFolder, JMenuBar.class, rp);
64
        this.bar = bar;
54
        this.bar = bar;
65
        this.task = rp.create(fca);
66
        rootFolder.getPrimaryFile().addFileChangeListener(fca);
67
    }
68
69
    void init() {
70
        fca.refresh();
71
    }
55
    }
72
56
73
    @Override
57
    @Override
Lines 76-150 Link Here
76
    }
60
    }
77
61
78
    @Override
62
    @Override
79
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
63
    JMenuBar cachedComponent() {
80
        super.onInitBackground(children);
64
        return bar;
81
        if (!refreshing) {
82
            EventQueue.invokeLater(fca);
83
        }
84
    }
85
86
    volatile boolean refreshing;
87
    private final class FCA extends FileChangeAdapter implements Runnable {
88
        private volatile boolean enqueued;
89
        boolean refresh() {
90
            boolean result;
91
            synchronized (this) {
92
                result = enqueued;
93
                if (!enqueued) {
94
                    enqueued = true;
95
                    task.schedule(DELAY);
96
                }
97
                return result;
98
            }
99
        }
100
101
        @Override
102
        public void run() {
103
            if (!EventQueue.isDispatchThread()) {
104
                refreshing = true;
105
                try {
106
                    List<ModelEntry<?,?>> l = new LinkedList<ModelEntry<?,?>>();
107
                    initBackground(l);
108
                    setChildren(l);
109
                } finally {
110
                    refreshing = false;
111
                    EventQueue.invokeLater(this);
112
                }
113
            } else {
114
                enqueued = false;
115
                bar.removeAll();
116
                MenuBarModel.this.refresh(new JMenuBar[] { bar });
117
            }
118
        }
119
120
        @Override
121
        public void fileAttributeChanged(FileAttributeEvent fe) {
122
            refresh();
123
        }
124
125
        @Override
126
        public void fileChanged(FileEvent fe) {
127
            refresh();
128
        }
129
130
        @Override
131
        public void fileDataCreated(FileEvent fe) {
132
            refresh();
133
        }
134
135
        @Override
136
        public void fileDeleted(FileEvent fe) {
137
            refresh();
138
        }
139
140
        @Override
141
        public void fileFolderCreated(FileEvent fe) {
142
            refresh();
143
        }
144
145
        @Override
146
        public void fileRenamed(FileRenameEvent fe) {
147
            refresh();
148
        }
149
    }
65
    }
150
}
66
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuEntry.java (-13 / +15 lines)
Lines 42-66 Link Here
42
import java.awt.EventQueue;
42
import java.awt.EventQueue;
43
import java.lang.ref.Reference;
43
import java.lang.ref.Reference;
44
import java.lang.ref.WeakReference;
44
import java.lang.ref.WeakReference;
45
import java.util.concurrent.atomic.AtomicBoolean;
45
import javax.swing.ButtonModel;
46
import javax.swing.ButtonModel;
46
import javax.swing.JMenu;
47
import javax.swing.JMenu;
47
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeEvent;
48
import javax.swing.event.ChangeListener;
49
import javax.swing.event.ChangeListener;
49
import org.openide.awt.Mnemonics;
50
import org.openide.awt.Mnemonics;
50
import org.openide.loaders.DataFolder;
51
import org.openide.loaders.DataFolder;
52
import org.openide.util.RequestProcessor;
51
53
52
/**
54
/**
53
 *
55
 *
54
 * @author Tim Boudreau
56
 * @author Tim Boudreau
55
 */
57
 */
56
final class MenuEntry extends FolderModelEntry<JMenu> implements ChangeListener {
58
final class MenuEntry extends RefreshingFolderModelEntry<JMenu> implements ChangeListener {
57
58
    private Reference<JMenu> menu;
59
    private Reference<JMenu> menu;
59
    private final Callback callback;
60
    MenuEntry (DataFolder fld, RequestProcessor rp) {
60
61
        super (fld, JMenu.class, rp);
61
    MenuEntry (DataFolder fld, Callback callback) {
62
        super (fld, JMenu.class);
63
        this.callback = callback == null ? this : callback;
64
    }
62
    }
65
63
66
    private JMenu menu() {
64
    private JMenu menu() {
Lines 81-86 Link Here
81
    }
79
    }
82
80
83
    private boolean wasSelected = false;
81
    private boolean wasSelected = false;
82
    private AtomicBoolean showing = new AtomicBoolean();
84
    @Override
83
    @Override
85
    public void stateChanged(ChangeEvent e) {
84
    public void stateChanged(ChangeEvent e) {
86
        ButtonModel mdl = (ButtonModel) e.getSource();
85
        ButtonModel mdl = (ButtonModel) e.getSource();
Lines 88-106 Link Here
88
        //XXX wasSelected could be true if the old component was garbage collected
87
        //XXX wasSelected could be true if the old component was garbage collected
89
        //without resetting its model - possible?
88
        //without resetting its model - possible?
90
        if (selected && !wasSelected) {
89
        if (selected && !wasSelected) {
91
            if (callback != null) {
90
            showing.set(true);
92
                callback.onShow(this);
91
            onShow(this);
93
            }
94
            refreshComponent(menu());
92
            refreshComponent(menu());
95
        } else if (wasSelected && !selected) {
93
        } else if (wasSelected && !selected) {
94
            showing.set(false);
96
            JMenu m = menu == null ? null : menu.get();
95
            JMenu m = menu == null ? null : menu.get();
97
            if (m != null) {
96
            if (m != null) {
98
                m.removeAll();
97
                m.removeAll();
99
            }
98
            }
100
            if (callback != null) {
99
            onHide(this);
101
                callback.onHide(this);
102
            }
103
        }
100
        }
104
        wasSelected = selected;
101
        wasSelected = selected;
105
    }
102
    }
103
104
    @Override
105
    JMenu cachedComponent() {
106
        return menu();
107
    }
106
}
108
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuManager.java (-1 / +2 lines)
Lines 49-55 Link Here
49
 */
49
 */
50
final class MenuManager {
50
final class MenuManager {
51
    private final JMenuBar bar;
51
    private final JMenuBar bar;
52
    private final RequestProcessor rp = new RequestProcessor("Main Menu Refresh", 1, true);
52
    //XXX make this non-static and pass to model entries
53
    static final RequestProcessor rp = new RequestProcessor("Main Menu Refresh", 1, true);
53
    private final MenuBarModel model;
54
    private final MenuBarModel model;
54
55
55
    MenuManager(DataFolder folder, JMenuBar bar) {
56
    MenuManager(DataFolder folder, JMenuBar bar) {
(-)fa24874d2b7b (+155 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.EventQueue;
42
import java.util.LinkedList;
43
import java.util.List;
44
import javax.swing.JComponent;
45
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
49
import org.openide.filesystems.FileObject;
50
import org.openide.filesystems.FileRenameEvent;
51
import org.openide.filesystems.FileUtil;
52
import org.openide.loaders.DataFolder;
53
import org.openide.util.RequestProcessor;
54
55
/**
56
 *
57
 * @author Tim Boudreau
58
 */
59
abstract class RefreshingFolderModelEntry<T extends JComponent> extends FolderModelEntry<T> {
60
61
    private final RequestProcessor.Task task;
62
    private FCA fca = new FCA();
63
    private static final int DELAY = 100;
64
65
    RefreshingFolderModelEntry(DataFolder dob, Class<T> compType, RequestProcessor rp) {
66
        super(dob, compType);
67
        this.task = rp.create(fca);
68
        FileObject fo = dob.getPrimaryFile();
69
        fo.addFileChangeListener(FileUtil.weakFileChangeListener(fca, fo));
70
    }
71
72
    @Override
73
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
74
        super.onInitBackground(children);
75
        if (!refreshing) {
76
            EventQueue.invokeLater(fca);
77
        }
78
    }
79
80
    abstract T cachedComponent();
81
82
    void init() {
83
        fca.refresh();
84
    }
85
    volatile boolean refreshing;
86
87
    private final class FCA extends FileChangeAdapter implements Runnable {
88
89
        private volatile boolean enqueued;
90
91
        boolean refresh() {
92
            boolean result;
93
            synchronized (this) {
94
                result = enqueued;
95
                if (!enqueued) {
96
                    enqueued = true;
97
                    task.schedule(DELAY);
98
                }
99
                return result;
100
            }
101
        }
102
103
        @Override
104
        public void run() {
105
            if (!EventQueue.isDispatchThread()) {
106
                refreshing = true;
107
                try {
108
                    List<ModelEntry<?, ?>> l = new LinkedList<ModelEntry<?, ?>>();
109
                    initBackground(l);
110
                    setChildren(l);
111
                } finally {
112
                    refreshing = false;
113
                    EventQueue.invokeLater(this);
114
                }
115
            } else {
116
                enqueued = false;
117
                T comp = cachedComponent();
118
                if (comp != null) {
119
                    comp.removeAll();
120
                    RefreshingFolderModelEntry.this.refresh(toCompTypeArray(new Object[]{comp}));
121
                }
122
            }
123
        }
124
125
        @Override
126
        public void fileAttributeChanged(FileAttributeEvent fe) {
127
            refresh();
128
        }
129
130
        @Override
131
        public void fileChanged(FileEvent fe) {
132
            refresh();
133
        }
134
135
        @Override
136
        public void fileDataCreated(FileEvent fe) {
137
            refresh();
138
        }
139
140
        @Override
141
        public void fileDeleted(FileEvent fe) {
142
            refresh();
143
        }
144
145
        @Override
146
        public void fileFolderCreated(FileEvent fe) {
147
            refresh();
148
        }
149
150
        @Override
151
        public void fileRenamed(FileRenameEvent fe) {
152
            refresh();
153
        }
154
    }
155
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuEntry.java (+14 lines)
Lines 78-83 Link Here
78
        return menu();
78
        return menu();
79
    }
79
    }
80
80
81
    @Override
82
    protected void onRefresh(JMenu[] newComps) {
83
        if (showing.get()) {
84
            JMenu m = menu();
85
            if (m != null && m.isPopupMenuVisible()) {
86
                m.setPopupMenuVisible(false);
87
                m.invalidate();
88
                m.revalidate();
89
                m.repaint();
90
                m.setPopupMenuVisible(true);
91
            }
92
        }
93
    }
94
81
    private boolean wasSelected = false;
95
    private boolean wasSelected = false;
82
    private AtomicBoolean showing = new AtomicBoolean();
96
    private AtomicBoolean showing = new AtomicBoolean();
83
    @Override
97
    @Override
(-)a/core.menu/src/org/netbeans/core/menu/ModelEntry.java (-2 / +9 lines)
Lines 70-76 Link Here
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
71
71
72
    public String getName() {
72
    public String getName() {
73
        return file().getNodeDelegate().getDisplayName();
73
        DataObject file = file();
74
        return file.isValid() ? file.getNodeDelegate().getDisplayName() : file.getName();
74
    }
75
    }
75
76
76
    protected final DataObjectType file() {
77
    protected final DataObjectType file() {
Lines 95-102 Link Here
95
        return refresh (old);
96
        return refresh (old);
96
    }
97
    }
97
98
99
    protected void onRefresh (CompType[] newComps) {
100
        
101
    }
102
98
    protected CompType[] refresh (CompType[] old) {
103
    protected CompType[] refresh (CompType[] old) {
99
        return toCompTypeArray(new Object[] { refreshComponent( old.length == 0 ? null : old[0]) });
104
        CompType[] result = toCompTypeArray(new Object[] { refreshComponent( old.length == 0 ? null : old[0]) });
105
        onRefresh (result);
106
        return result;
100
    }
107
    }
101
108
102
    protected CompType[] findComponents() {
109
    protected CompType[] findComponents() {
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class AAction extends AbstractAction {
53
    public AAction() {
54
        putValue (NAME, "A");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class ABAction extends AbstractAction {
53
    public ABAction() {
54
        putValue (NAME, "AB");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A, Layers.B);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class ABCAction extends AbstractAction {
53
    public ABCAction() {
54
        putValue (NAME, "ABC");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A, Layers.B, Layers.C);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+68 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.event.ActionEvent;
43
import javax.swing.AbstractAction;
44
import org.netbeans.core.menu.FileChangeTest.Layers;
45
import org.openide.util.Exceptions;
46
import org.xml.sax.SAXException;
47
48
/**
49
 *
50
 * @author Tim Boudreau
51
 */
52
public class ABCDAction extends AbstractAction {
53
    public ABCDAction() {
54
        putValue (NAME, "ABCD");
55
    }
56
57
    @Override
58
    public void actionPerformed(ActionEvent e) {
59
        try {
60
            FileChangeTest.MFS.INSTANCE.setLayers(Layers.A, Layers.B, Layers.C, Layers.D);
61
        } catch (SAXException ex) {
62
            Exceptions.printStackTrace(ex);
63
        }
64
    }
65
66
67
68
}
(-)d76d479b5dc8 (+96 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
40
package org.netbeans.core.menu;
41
42
import java.awt.AWTEvent;
43
import static java.awt.AWTEvent.*;
44
import java.awt.Component;
45
import java.awt.Toolkit;
46
import java.awt.event.AWTEventListener;
47
import java.awt.event.MouseEvent;
48
import java.lang.reflect.InvocationTargetException;
49
import java.lang.reflect.Method;
50
import org.openide.util.Exceptions;
51
52
/**
53
 * Blocks real input events from the user, so user's focus behavior cannot
54
 * affect tests
55
 *
56
 * @author Tim Boudreau
57
 */
58
public class EventBlocker implements AWTEventListener {
59
    private static final long MASK = FOCUS_EVENT_MASK | MOUSE_EVENT_MASK | MOUSE_MOTION_EVENT_MASK | MOUSE_WHEEL_EVENT_MASK | 
60
            KEY_EVENT_MASK | ACTION_EVENT_MASK | ADJUSTMENT_EVENT_MASK | 
61
            INPUT_METHOD_EVENT_MASK | ITEM_EVENT_MASK | TEXT_EVENT_MASK;
62
    static void init() {
63
        Toolkit.getDefaultToolkit().addAWTEventListener(new EventBlocker(), MASK);
64
    }
65
66
    @Override
67
    public void eventDispatched(AWTEvent event) {
68
        Class<?> c = event.getClass();
69
        if (event instanceof ME) {
70
            return;
71
        }
72
        try {
73
            Method m = c.getMethod("consume");
74
            try {
75
                m.invoke(event);
76
            } catch (IllegalAccessException ex) {
77
            } catch (IllegalArgumentException ex) {
78
            } catch (InvocationTargetException ex) {
79
            }
80
        } catch (NoSuchMethodException ex) {
81
        } catch (SecurityException ex) {
82
        }
83
    }
84
85
    public static MouseEvent mouseEvent (Component c, int id) {
86
        return new ME(c, id);
87
    }
88
89
    private static final class ME extends MouseEvent {
90
        ME(Component comp, int id) {
91
            super (comp, id, System.currentTimeMillis(),
92
                        0, 5, 5, 1, false, 0);
93
        }
94
    }
95
96
}
(-)d76d479b5dc8 (+303 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL
25
 * or only the GPL Version 2, indicate your decision by adding
26
 * "[Contributor] elects to include this software in this distribution
27
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28
 * single choice of license, a recipient has the option to distribute
29
 * your version of this file under either the CDDL, the GPL Version 2 or
30
 * to extend the choice of license to its licensees as provided above.
31
 * However, if you add GPL Version 2 code and therefore, elected the GPL
32
 * Version 2 license, then the option applies only if the new code is
33
 * made subject to such option by the copyright holder.
34
 *
35
 * Contributor(s):
36
 *
37
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
38
 */
39
package org.netbeans.core.menu;
40
41
import java.awt.Component;
42
import java.awt.Dimension;
43
import java.awt.EventQueue;
44
import java.awt.event.ContainerEvent;
45
import java.awt.event.ContainerListener;
46
import java.awt.event.MouseEvent;
47
import java.net.URL;
48
import java.util.Arrays;
49
import java.util.concurrent.CountDownLatch;
50
import java.util.concurrent.TimeUnit;
51
import java.util.concurrent.atomic.AtomicBoolean;
52
import java.util.concurrent.atomic.AtomicInteger;
53
import javax.swing.AbstractButton;
54
import javax.swing.JComponent;
55
import javax.swing.JFrame;
56
import javax.swing.JMenu;
57
import javax.swing.JMenuBar;
58
import javax.swing.JPanel;
59
import javax.swing.JPopupMenu;
60
import org.junit.Test;
61
import org.netbeans.junit.NbTestCase;
62
import org.openide.filesystems.FileSystem;
63
import org.openide.filesystems.MultiFileSystem;
64
import org.openide.filesystems.XMLFileSystem;
65
import org.xml.sax.SAXException;
66
67
/**
68
 *
69
 * @author tim
70
 */
71
public class FileChangeTest extends NbTestCase {
72
73
    private MenuProviderImpl m;
74
    private JMenuBar bar;
75
    private JFrame jf;
76
    private JMenu menu;
77
78
79
    public FileChangeTest(String name) {
80
        super(name);
81
    }
82
83
    @Override
84
    protected boolean runInEQ() {
85
        return false;
86
    }
87
88
    @Override
89
    public void setUp() throws Exception {
90
        FileSystem fs = new MFS();
91
        m = new MenuProviderImpl(fs.getRoot().getFileObject("Menu"));
92
        R r = new R();
93
94
        EventQueue.invokeAndWait(r);
95
        r.latch.await(20000, TimeUnit.MILLISECONDS);
96
        while (!jf.isShowing()) {
97
            Thread.sleep(30);
98
        }
99
        while (bar.getMenuCount() < 2) {
100
            Thread.sleep(30);
101
        }
102
        assertFalse(bar.getMenuCount() == 0);
103
        menu = bar.getMenu(0);
104
    }
105
106
    @Override
107
    public void tearDown() {
108
        jf.dispose();
109
    }
110
111
    private void click(final JComponent comp, final boolean showMenu) throws Exception {
112
        EventQueue.invokeAndWait(new Runnable() {
113
114
            public void run() {
115
                ((AbstractButton) comp).getModel().setPressed(showMenu);
116
                MouseEvent evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_PRESSED);
117
                comp.dispatchEvent(evt);
118
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_RELEASED);
119
                comp.dispatchEvent(evt);
120
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_CLICKED);
121
                comp.dispatchEvent(evt);
122
            }
123
        });
124
        if (comp instanceof JMenu) {
125
            JMenu m = (JMenu) comp;
126
            while (showMenu != m.getPopupMenu().isShowing()) {
127
                Thread.sleep (100);
128
            }
129
        }
130
    }
131
132
133
    @Test
134
    public void testMenusAreUpdatedWhenOpen() throws Exception {
135
        EventBlocker.init();
136
        assertNotNull (menu);
137
        click (menu, true);
138
        JPopupMenu popup = menu.getPopupMenu();
139
        Component[] c = popup.getComponents();
140
        assertTrue (menu.isPopupMenuVisible());
141
        assertEquals (4, popup.getComponentCount());
142
        final CountDownLatch l = new CountDownLatch(2);
143
        popup.addContainerListener(new ContainerListener() {
144
145
            @Override
146
            public void componentAdded(ContainerEvent e) {
147
//                System.err.println("added - count now " + e.getContainer().getComponentCount());
148
                if (e.getContainer().getComponentCount() == 5) {
149
                    l.countDown();
150
                }
151
            }
152
153
            @Override
154
            public void componentRemoved(ContainerEvent e) {
155
//                System.err.println("removed - count now " + e.getContainer().getComponentCount());
156
            }
157
158
        });
159
        bar.addContainerListener(new ContainerListener() {
160
161
            @Override
162
            public void componentAdded(ContainerEvent e) {
163
//                System.err.println("bar comp added - count now " + e.getContainer().getComponentCount());
164
                if (e.getContainer().getComponentCount() == 3) {
165
                    l.countDown();
166
                }
167
            }
168
169
            @Override
170
            public void componentRemoved(ContainerEvent e) {
171
//                System.err.println("bar comp removed - count now " + e.getContainer().getComponentCount());
172
            }
173
            
174
        });
175
176
        new ABCDAction().actionPerformed(null);
177
        l.await(20000, TimeUnit.MILLISECONDS);
178
        final AtomicInteger popupCompCount = new AtomicInteger(-1);
179
        final AtomicInteger barCompCount = new AtomicInteger(-1);
180
        final AtomicBoolean vis = new AtomicBoolean();
181
        EventQueue.invokeAndWait (new Runnable() {
182
183
            @Override
184
            public void run() {
185
                popupCompCount.set(menu.getPopupMenu().getComponentCount());
186
                barCompCount.set(bar.getComponentCount());
187
                vis.set(menu.getPopupMenu().isShowing());
188
            }
189
190
        });
191
        
192
        assertTrue (vis.get());
193
        assertEquals (5, popupCompCount.get());
194
        assertEquals (3, barCompCount.get());
195
196
        popupCompCount.set(-1);
197
        barCompCount.set(-1);
198
        vis.set(false);
199
200
        final CountDownLatch ll = new CountDownLatch(4);
201
        popup.addContainerListener(new ContainerListener() {
202
203
            @Override
204
            public void componentAdded(ContainerEvent e) {
205
//                System.err.println("added - count now " + e.getContainer().getComponentCount());
206
                ll.countDown();
207
            }
208
209
            @Override
210
            public void componentRemoved(ContainerEvent e) {
211
//                System.err.println("removed - count now " + e.getContainer().getComponentCount());
212
            }
213
214
        });
215
        new AAction().actionPerformed(null);
216
        ll.await(20000, TimeUnit.MILLISECONDS);
217
        EventQueue.invokeAndWait (new Runnable() {
218
219
            @Override
220
            public void run() {
221
                popupCompCount.set(menu.getPopupMenu().getComponentCount());
222
                barCompCount.set(bar.getComponentCount());
223
                vis.set(menu.getPopupMenu().isShowing());
224
            }
225
226
        });
227
228
        assertTrue (vis.get());
229
        assertEquals (4, popupCompCount.get());
230
        assertEquals (2, barCompCount.get());
231
232
//        Thread.sleep (40000);
233
234
    }
235
    private static final int EXPECTED_MENU_COUNT = 1; //update if more added to xml
236
237
    private class R implements Runnable, ContainerListener {
238
239
        private final CountDownLatch latch = new CountDownLatch(1);
240
241
        @Override
242
        public void run() {
243
            jf = new JFrame();
244
            bar = m.createMenu(jf);
245
            bar.addContainerListener(this);
246
            JPanel pnl = new JPanel();
247
            pnl.setMinimumSize(new Dimension(300, 300));
248
            pnl.setPreferredSize(new Dimension(300, 300));
249
            jf.setContentPane(pnl);
250
            jf.setJMenuBar(bar);
251
            jf.pack();
252
            jf.setVisible(true);
253
        }
254
255
        @Override
256
        public void componentAdded(ContainerEvent e) {
257
            int count = e.getContainer().getComponentCount();
258
            if (count == EXPECTED_MENU_COUNT) {
259
                latch.countDown();
260
                e.getContainer().invalidate();
261
                ((JMenuBar) e.getContainer()).revalidate();
262
                e.getContainer().repaint();
263
            }
264
        }
265
266
        @Override
267
        public void componentRemoved(ContainerEvent e) {
268
            //do nothing
269
        }
270
    }
271
272
    public static final class MFS extends MultiFileSystem {
273
        public static MFS INSTANCE;
274
        MFS() throws SAXException {
275
            setLayers (Layers.A);
276
            INSTANCE = this;
277
        }
278
279
        public void setLayers(Layers... l) throws SAXException {
280
            System.err.println("setLayers " + Arrays.asList(l));
281
            FileSystem[] xfs = new XMLFileSystem[l.length];
282
            for (int i = 0; i < xfs.length; i++) {
283
                xfs[i] = new XMLFileSystem(l[i].res());
284
            }
285
            setDelegates(xfs);
286
        }
287
    }
288
289
    public enum Layers {
290
        A("a.xml"),
291
        B("b.xml"),
292
        C("c.xml"),
293
        D("d.xml");
294
        private String resource;
295
        Layers (String resource) {
296
            this.resource = resource;
297
        }
298
299
        public URL res() {
300
            return Layers.class.getResource(resource);
301
        }
302
    }
303
}
(-)d76d479b5dc8 (+28 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="One">
6
            <attr name="position" intvalue="0"/>
7
            <file name="org-netbeans-core-menu-AAction.instance">
8
                <attr name="position" intvalue="0"/>
9
            </file>
10
            <file name="org-netbeans-core-menu-ABAction.instance">
11
                <attr name="position" intvalue="1"/>
12
            </file>
13
            <file name="org-netbeans-core-menu-ABCAction.instance">
14
                <attr name="position" intvalue="2"/>
15
            </file>
16
            <file name="org-netbeans-core-menu-ABCDAction.instance">
17
                <attr name="position" intvalue="3"/>
18
            </file>
19
        </folder>
20
        <folder name="Two">
21
            <attr name="position" intvalue="1"/>
22
            <file name="org-netbeans-core-menu-PresenterAction.instance">
23
                <attr name="position" intvalue="0"/>
24
            </file>
25
        </folder>
26
27
    </folder>
28
</filesystem>
(-)d76d479b5dc8 (+11 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="Two">
6
            <file name="org-netbeans-core-menu-DynAction.instance">
7
                <attr name="position" intvalue="1"/>
8
            </file>
9
        </folder>
10
    </folder>
11
</filesystem>
(-)d76d479b5dc8 (+11 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="One">
6
            <file name="org-netbeans-core-menu-RegularAction.instance">
7
                <attr name="position" intvalue="4"/>
8
            </file>
9
        </folder>
10
    </folder>
11
</filesystem>
(-)d76d479b5dc8 (+12 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
    <folder name="Menu">
5
        <folder name="Three">
6
            <attr name="position" intvalue="2"/>
7
            <file name="org-netbeans-core-menu-RegularAction.instance">
8
                <attr name="position" intvalue="1"/>
9
            </file>
10
        </folder>
11
    </folder>
12
</filesystem>
(-)a/core.menu/src/org/netbeans/core/menu/DynamicModelEntry.java (-2 lines)
Lines 60-67 Link Here
60
        try {
60
        try {
61
            DynamicMenuContent dyn = get();
61
            DynamicMenuContent dyn = get();
62
            JComponent[] result = dyn.getMenuPresenters();
62
            JComponent[] result = dyn.getMenuPresenters();
63
            //Necessary the first time, or we get bogus elements
64
            dyn.synchMenuPresenters(result);
65
            return result;
63
            return result;
66
        } catch (IOException ex) {
64
        } catch (IOException ex) {
67
            Exceptions.printStackTrace(ex);
65
            Exceptions.printStackTrace(ex);
(-)a/core.ui/manifest.mf (-1 / +1 lines)
Lines 4-8 Link Here
4
OpenIDE-Module-Layer: org/netbeans/core/ui/resources/layer.xml
4
OpenIDE-Module-Layer: org/netbeans/core/ui/resources/layer.xml
5
AutoUpdate-Show-In-Client: false
5
AutoUpdate-Show-In-Client: false
6
AutoUpdate-Essential-Module: true
6
AutoUpdate-Essential-Module: true
7
OpenIDE-Module-Specification-Version: 1.21
7
OpenIDE-Module-Specification-Version: 1.22
8
8
(-)a/core.ui/src/org/netbeans/core/ui/warmup/MenuWarmUpTask.java (-37 / +3 lines)
Lines 45-50 Link Here
45
45
46
import java.awt.Component;
46
import java.awt.Component;
47
import java.awt.Dimension;
47
import java.awt.Dimension;
48
import java.awt.EventQueue;
48
import java.awt.Frame;
49
import java.awt.Frame;
49
import java.awt.event.ActionEvent;
50
import java.awt.event.ActionEvent;
50
import java.awt.event.WindowAdapter;
51
import java.awt.event.WindowAdapter;
Lines 58-64 Link Here
58
import javax.swing.JFrame;
59
import javax.swing.JFrame;
59
import javax.swing.JLabel;
60
import javax.swing.JLabel;
60
import javax.swing.JMenu;
61
import javax.swing.JMenu;
61
import javax.swing.SwingUtilities;
62
import javax.swing.text.html.HTMLEditorKit;
62
import javax.swing.text.html.HTMLEditorKit;
63
import org.netbeans.api.progress.ProgressHandle;
63
import org.netbeans.api.progress.ProgressHandle;
64
import org.netbeans.api.progress.ProgressHandleFactory;
64
import org.netbeans.api.progress.ProgressHandleFactory;
Lines 74-131 Link Here
74
import org.openide.util.NbBundle;
74
import org.openide.util.NbBundle;
75
75
76
/**
76
/**
77
 * A menu preheating task. It is referenced from the layer and may be performed
77
 * Triggers filesystem refresh on main window activation.
78
 * by the core after the startup.
79
 * 
80
 * Plus hooked WindowListener on main window (see {@link NbWindowsAdapter})
81
 */
78
 */
82
public final class MenuWarmUpTask implements Runnable {
79
public final class MenuWarmUpTask implements Runnable {
83
80
84
    private Component[] comps;
85
    
86
    /** Actually performs pre-heat.
87
     */
88
    @Override
81
    @Override
89
    public void run() {
82
    public void run() {
90
        try {
83
        try {
91
            SwingUtilities.invokeAndWait(new Runnable() {
84
            EventQueue.invokeLater(new Runnable() {
92
                @Override
85
                @Override
93
                public void run() {
86
                public void run() {
94
                    Frame main = WindowManager.getDefault().getMainWindow();
87
                    Frame main = WindowManager.getDefault().getMainWindow();
95
                    
96
                    assert main != null;
88
                    assert main != null;
97
                    main.addWindowListener(new NbWindowsAdapter());
89
                    main.addWindowListener(new NbWindowsAdapter());
98
                    
99
                    if (main instanceof JFrame) {
100
                        comps = ((JFrame) main).getJMenuBar().getComponents();
101
                    }
102
                }
90
                }
103
            });
91
            });
104
        } catch (Exception e) { // bail out!
92
        } catch (Exception e) { // bail out!
105
            return;
93
            return;
106
        }
94
        }
107
108
109
        if (comps != null) {
110
            walkMenu(comps);
111
            comps = null;
112
        }
113
114
        // tackle the Tools menu now? How?
115
    }
116
117
    private void walkMenu(Component[] items) {
118
        for (int i=0; i<items.length; i++) {
119
            if (! (items[i] instanceof JMenu)) continue;
120
            try {
121
                Class<?> cls = items[i].getClass();
122
                Method m = cls.getDeclaredMethod("doInitialize");
123
                m.setAccessible(true);
124
                m.invoke(items[i]);
125
                walkMenu(((JMenu)items[i]).getMenuComponents()); // recursive?
126
            } catch (Exception e) {// do nothing, it may happen for user-provided menus
127
            }
128
        }
129
    }
95
    }
130
96
131
    /**
97
    /**
(-)a/core.menu/src/org/netbeans/core/menu/ComponentModelEntry.java (-1 / +1 lines)
Lines 57-63 Link Here
57
    }
57
    }
58
58
59
    @Override
59
    @Override
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
61
        return false;
61
        return false;
62
    }
62
    }
63
63
(-)a/core.menu/src/org/netbeans/core/menu/FolderModelEntry.java (-4 / +4 lines)
Lines 142-153 Link Here
142
        }
142
        }
143
    }
143
    }
144
144
145
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
145
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
146
        //do nothing - for subclasses to force init
146
        //do nothing - for subclasses to force init
147
    }
147
    }
148
148
149
    @Override
149
    @Override
150
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children) {
150
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
151
//        System.err.println("initBackground " + getName());
151
//        System.err.println("initBackground " + getName());
152
        DataFolder fld = file();
152
        DataFolder fld = file();
153
        boolean changed = true;
153
        boolean changed = true;
Lines 165-171 Link Here
165
                                children.add(e);
165
                                children.add(e);
166
                                //XXX defer or batch afterward?
166
                                //XXX defer or batch afterward?
167
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
167
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
168
                                boolean hasKids = e.initBackground(kids);
168
                                boolean hasKids = e.initBackground(kids, currDepth+1);
169
                                changed |= hasKids;
169
                                changed |= hasKids;
170
                                if (hasKids) {
170
                                if (hasKids) {
171
                                    if (e instanceof FolderModelEntry) {
171
                                    if (e instanceof FolderModelEntry) {
Lines 185-191 Link Here
185
                }
185
                }
186
            }
186
            }
187
        } finally {
187
        } finally {
188
            onInitBackground(children);
188
            onInitBackground(children, currDepth);
189
        }
189
        }
190
        return changed;
190
        return changed;
191
    }
191
    }
(-)a/core.menu/src/org/netbeans/core/menu/MenuBarModel.java (+16 lines)
Lines 39-44 Link Here
39
39
40
package org.netbeans.core.menu;
40
package org.netbeans.core.menu;
41
41
42
import java.util.List;
43
import javax.swing.JComponent;
42
import javax.swing.JMenuBar;
44
import javax.swing.JMenuBar;
43
import org.openide.loaders.DataFolder;
45
import org.openide.loaders.DataFolder;
44
import org.openide.util.RequestProcessor;
46
import org.openide.util.RequestProcessor;
Lines 63-66 Link Here
63
    JMenuBar cachedComponent() {
65
    JMenuBar cachedComponent() {
64
        return bar;
66
        return bar;
65
    }
67
    }
68
69
    @Override
70
    protected void installComponents(List<? extends JComponent> components, JMenuBar into) {
71
        synchronized (bar.getTreeLock()) {
72
            super.installComponents(components, into);
73
        }
74
        bar.invalidate();
75
        bar.revalidate();
76
        bar.repaint();
77
    }
78
79
80
81
66
}
82
}
(-)a/core.menu/src/org/netbeans/core/menu/MenuProviderImpl.java (-4 / +17 lines)
Lines 40-45 Link Here
40
package org.netbeans.core.menu;
40
package org.netbeans.core.menu;
41
41
42
import java.awt.EventQueue;
42
import java.awt.EventQueue;
43
import java.awt.event.ComponentAdapter;
44
import java.awt.event.ComponentEvent;
45
import java.awt.event.HierarchyEvent;
46
import java.awt.event.HierarchyListener;
43
import javax.swing.JFrame;
47
import javax.swing.JFrame;
44
import javax.swing.JMenuBar;
48
import javax.swing.JMenuBar;
45
import org.netbeans.api.menus.MenuProvider;
49
import org.netbeans.api.menus.MenuProvider;
Lines 71-81 Link Here
71
        }
75
        }
72
        FileObject menuFO = menuFolder;
76
        FileObject menuFO = menuFolder;
73
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
77
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
74
        JMenuBar bar = new JMenuBar();
78
        final JMenuBar bar = new JMenuBar();
75
        bar.setBorderPainted(false);
79
        bar.setBorderPainted(false);
76
        MenuManager mgr = new MenuManager(menuFolder, bar);
80
        final MenuManager mgr = new MenuManager(menuFolder, bar);
77
        mgr.init();
81
        bar.addHierarchyListener(new HierarchyListener() {
82
83
            @Override
84
            public void hierarchyChanged(HierarchyEvent e) {
85
                if (bar.isShowing()) {
86
                    bar.removeHierarchyListener(this);
87
                    mgr.init();
88
                }
89
            }
90
        });
91
//        mgr.init();
78
        return bar;
92
        return bar;
79
    }
93
    }
80
81
}
94
}
(-)a/core.menu/src/org/netbeans/core/menu/ModelEntry.java (-1 / +35 lines)
Lines 67-73 Link Here
67
        Parameters.notNull("file", file);
67
        Parameters.notNull("file", file);
68
    }
68
    }
69
    
69
    
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children);
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth);
71
71
72
    public String getName() {
72
    public String getName() {
73
        DataObject file = file();
73
        DataObject file = file();
Lines 136-147 Link Here
136
            Icon icon = item.getIcon();
136
            Icon icon = item.getIcon();
137
            if (!wantIcons && icon != null) {
137
            if (!wantIcons && icon != null) {
138
                item.setIcon(null);
138
                item.setIcon(null);
139
                item.setDisabledIcon(null);
140
                item.setDisabledSelectedIcon(null);
139
            } else if (wantIcons && icon == null) {
141
            } else if (wantIcons && icon == null) {
140
                item.setIcon (BLANK_ICON);
142
                item.setIcon (BLANK_ICON);
143
                item.setDisabledIcon(BLANK_ICON);
144
                item.setDisabledSelectedIcon(BLANK_ICON);
141
            }
145
            }
146
//            String txt = item.getText();
147
//            if (txt != null && txt.contains("Find Issues")) {
148
//                Thread.dumpStack();
149
//                log (item);
150
//            }
142
        }
151
        }
143
    }
152
    }
144
153
154
//Useful for diagnosing strangely painting menu items
155
//    private static void log (JMenuItem item) {
156
//        System.err.println("FIND ISSUES ITEM: " + item);
157
//        logType (item);
158
//        System.err.println(" Action:");
159
//        logType (item.getAction());
160
//    }
161
//
162
//    private static void logType (Object o) {
163
//        if (o == null) return;
164
//        for (Class<?> c : o.getClass().getInterfaces()) {
165
//            System.err.println(" I:" + c.getName());
166
//        }
167
//        Class<?> x = o.getClass();
168
//        while (x != Object.class) {
169
//            System.err.println(" C: " + x.getName());
170
//            x = x.getSuperclass();
171
//        }
172
//    }
173
145
    protected static Boolean defaultHasIcon (JComponent comp, Boolean hasIcon) {
174
    protected static Boolean defaultHasIcon (JComponent comp, Boolean hasIcon) {
146
        if (hasIcon != null && hasIcon) {
175
        if (hasIcon != null && hasIcon) {
147
            return hasIcon;
176
            return hasIcon;
Lines 176-179 Link Here
176
        hash = 31 * hash + (this.file != null ? this.file.hashCode() : 0);
205
        hash = 31 * hash + (this.file != null ? this.file.hashCode() : 0);
177
        return hash;
206
        return hash;
178
    }
207
    }
208
209
    @Override
210
    public String toString() {
211
        return super.toString() + "[" + getName() + "]";
212
    }
179
}
213
}
(-)a/core.menu/src/org/netbeans/core/menu/RefreshingFolderModelEntry.java (-8 / +28 lines)
Lines 42-48 Link Here
42
import java.util.LinkedList;
42
import java.util.LinkedList;
43
import java.util.List;
43
import java.util.List;
44
import javax.swing.JComponent;
44
import javax.swing.JComponent;
45
import javax.swing.JMenuBar;
46
import org.openide.filesystems.FileAttributeEvent;
45
import org.openide.filesystems.FileAttributeEvent;
47
import org.openide.filesystems.FileChangeAdapter;
46
import org.openide.filesystems.FileChangeAdapter;
48
import org.openide.filesystems.FileEvent;
47
import org.openide.filesystems.FileEvent;
Lines 61-66 Link Here
61
    private final RequestProcessor.Task task;
60
    private final RequestProcessor.Task task;
62
    private FCA fca = new FCA();
61
    private FCA fca = new FCA();
63
    private static final int DELAY = 100;
62
    private static final int DELAY = 100;
63
    private static final boolean LOG_RUNNABLES = Boolean.getBoolean ("RefreshingFolderModelEntry.log");
64
64
65
    RefreshingFolderModelEntry(DataFolder dob, Class<T> compType, RequestProcessor rp) {
65
    RefreshingFolderModelEntry(DataFolder dob, Class<T> compType, RequestProcessor rp) {
66
        super(dob, compType);
66
        super(dob, compType);
Lines 70-79 Link Here
70
    }
70
    }
71
71
72
    @Override
72
    @Override
73
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children) {
73
    protected void onInitBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
74
        super.onInitBackground(children);
74
        super.onInitBackground(children, currDepth);
75
        if (!refreshing) {
75
        if (!refreshing && currDepth == 0) {
76
            EventQueue.invokeLater(fca);
76
            EventQueue.invokeLater(LOG_RUNNABLES ? new LogRunnable(fca) : fca);
77
        }
77
        }
78
    }
78
    }
79
79
Lines 84-89 Link Here
84
    }
84
    }
85
    volatile boolean refreshing;
85
    volatile boolean refreshing;
86
86
87
    private final class LogRunnable implements Runnable {
88
        Throwable t;
89
        private final Runnable real;
90
        LogRunnable (Runnable real) {
91
            this.real = real;
92
            t = new Exception("Refresh " + RefreshingFolderModelEntry.this).fillInStackTrace();
93
        }
94
95
        @Override
96
        public void run() {
97
            t.printStackTrace();
98
            real.run();
99
        }
100
    }
101
87
    private final class FCA extends FileChangeAdapter implements Runnable {
102
    private final class FCA extends FileChangeAdapter implements Runnable {
88
103
89
        private volatile boolean enqueued;
104
        private volatile boolean enqueued;
Lines 94-100 Link Here
94
                result = enqueued;
109
                result = enqueued;
95
                if (!enqueued) {
110
                if (!enqueued) {
96
                    enqueued = true;
111
                    enqueued = true;
97
                    task.schedule(DELAY);
112
                    if (!LOG_RUNNABLES) {
113
                        task.schedule(DELAY);
114
                    } else {
115
                        RequestProcessor.Task t = MenuManager.rp.create(new LogRunnable(this));
116
                        t.schedule(DELAY);
117
                    }
98
                }
118
                }
99
                return result;
119
                return result;
100
            }
120
            }
Lines 106-116 Link Here
106
                refreshing = true;
126
                refreshing = true;
107
                try {
127
                try {
108
                    List<ModelEntry<?, ?>> l = new LinkedList<ModelEntry<?, ?>>();
128
                    List<ModelEntry<?, ?>> l = new LinkedList<ModelEntry<?, ?>>();
109
                    initBackground(l);
129
                    initBackground(l, 0);
110
                    setChildren(l);
130
                    setChildren(l);
111
                } finally {
131
                } finally {
112
                    refreshing = false;
132
                    refreshing = false;
113
                    EventQueue.invokeLater(this);
133
                    EventQueue.invokeLater(LOG_RUNNABLES ? new LogRunnable(this) : this);
114
                }
134
                }
115
            } else {
135
            } else {
116
                enqueued = false;
136
                enqueued = false;
(-)a/core.menu/src/org/netbeans/core/menu/SeparatorModelEntry.java (-1 / +1 lines)
Lines 63-69 Link Here
63
    }
63
    }
64
64
65
    @Override
65
    @Override
66
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
66
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
67
        return false;
67
        return false;
68
    }
68
    }
69
}
69
}
(-)a/core.menu/src/org/netbeans/core/menu/ThreadUnconstrainedModelEntry.java (-1 / +1 lines)
Lines 68-74 Link Here
68
    }
68
    }
69
69
70
    @Override
70
    @Override
71
    protected boolean initBackground(List<? super ModelEntry<?,?>> children) {
71
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
72
        //Since it is non-gui, instantiate the Action in the background
72
        //Since it is non-gui, instantiate the Action in the background
73
        try {
73
        try {
74
            ref.set(super.get());
74
            ref.set(super.get());
(-)a/core.menu/test/unit/src/org/netbeans/core/menu/MenuProviderImplTest.java (-6 / +4 lines)
Lines 108-121 Link Here
108
108
109
            public void run() {
109
            public void run() {
110
                ((AbstractButton) comp).getModel().setPressed(showMenu);
110
                ((AbstractButton) comp).getModel().setPressed(showMenu);
111
                MouseEvent evt = new MouseEvent(comp, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
111
                MouseEvent evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_PRESSED);
112
                        0, 5, 5, 1, false, 0);
113
                comp.dispatchEvent(evt);
112
                comp.dispatchEvent(evt);
114
                evt = new MouseEvent(comp, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(),
113
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_RELEASED);
115
                        0, 5, 5, 1, false, 0);
116
                comp.dispatchEvent(evt);
114
                comp.dispatchEvent(evt);
117
                evt = new MouseEvent(comp, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(),
115
                evt = EventBlocker.mouseEvent(comp, MouseEvent.MOUSE_CLICKED);
118
                        0, 5, 5, 1, false, 0);
119
                comp.dispatchEvent(evt);
116
                comp.dispatchEvent(evt);
120
            }
117
            }
121
        });
118
        });
Lines 129-134 Link Here
129
126
130
    @Test
127
    @Test
131
    public void testMenuItemsAreNotStronglyReferenced() throws Exception {
128
    public void testMenuItemsAreNotStronglyReferenced() throws Exception {
129
        EventBlocker.init();
132
        assertNotNull (menu);
130
        assertNotNull (menu);
133
        click (menu, true);
131
        click (menu, true);
134
        JPopupMenu popup = menu.getPopupMenu();
132
        JPopupMenu popup = menu.getPopupMenu();
(-)a/core.menu/src/org/netbeans/core/menu/MenuProviderImpl.java (-4 / +14 lines)
Lines 50-55 Link Here
50
import org.openide.filesystems.FileObject;
50
import org.openide.filesystems.FileObject;
51
import org.openide.filesystems.FileUtil;
51
import org.openide.filesystems.FileUtil;
52
import org.openide.loaders.DataFolder;
52
import org.openide.loaders.DataFolder;
53
import org.openide.util.Parameters;
53
import org.openide.util.lookup.ServiceProvider;
54
import org.openide.util.lookup.ServiceProvider;
54
55
55
/**
56
/**
Lines 61-83 Link Here
61
    private static final String MENU_FOLDER = "Menu"; //NOI18N
62
    private static final String MENU_FOLDER = "Menu"; //NOI18N
62
    private FileObject menuFolder;
63
    private FileObject menuFolder;
63
    public MenuProviderImpl () {
64
    public MenuProviderImpl () {
64
        this (FileUtil.getConfigFile(MENU_FOLDER));
65
        this (defaultMenuFolder());
65
    }
66
    }
66
67
67
    MenuProviderImpl (FileObject menuFolder) { //used in unit tests w/ memfs
68
    MenuProviderImpl (FileObject menuFolder) { //used in unit tests w/ memfs
69
        Parameters.notNull("menuFolder", menuFolder);
68
        this.menuFolder = menuFolder;
70
        this.menuFolder = menuFolder;
69
    }
71
    }
70
72
73
    static FileObject defaultMenuFolder() {
74
        String fld = System.getProperty ("MenuProviderImpl.menuBarFolder"); //NOI18N
75
        if (fld == null) {
76
            fld = MENU_FOLDER;
77
        }
78
        return FileUtil.getConfigFile(fld);
79
    }
80
71
    @Override
81
    @Override
72
    protected JMenuBar createMenu(JFrame target) {
82
    protected JMenuBar createMenu(JFrame target) {
73
        if (!EventQueue.isDispatchThread()) {
83
        if (!EventQueue.isDispatchThread()) {
74
            throw new IllegalStateException("Not on event thread"); //NOI18N
84
            throw new IllegalStateException("Not on event thread"); //NOI18N
75
        }
85
        }
86
        Parameters.notNull("target", target); //NOI18N
76
        FileObject menuFO = menuFolder;
87
        FileObject menuFO = menuFolder;
77
        DataFolder menuFolder = DataFolder.findFolder(menuFO);
88
        DataFolder folder = DataFolder.findFolder(menuFO);
78
        final JMenuBar bar = new JMenuBar();
89
        final JMenuBar bar = new JMenuBar();
79
        bar.setBorderPainted(false);
90
        bar.setBorderPainted(false);
80
        final MenuManager mgr = new MenuManager(menuFolder, bar);
91
        final MenuManager mgr = new MenuManager(folder, bar);
81
        bar.addHierarchyListener(new HierarchyListener() {
92
        bar.addHierarchyListener(new HierarchyListener() {
82
93
83
            @Override
94
            @Override
Lines 88-94 Link Here
88
                }
99
                }
89
            }
100
            }
90
        });
101
        });
91
//        mgr.init();
92
        return bar;
102
        return bar;
93
    }
103
    }
94
}
104
}
(-)a/core.windows/src/org/netbeans/core/windows/view/ui/MainWindow.java (-13 / +7 lines)
Lines 367-386 Link Here
367
    }
367
    }
368
368
369
    private JMenuBar createMenuBar() {
369
    private JMenuBar createMenuBar() {
370
        return MenuProvider.installMenu(this);
371
    }
372
373
    /** Creates menu bar. */
374
    private static JMenuBar xcreateMenuBar() {
375
        JMenuBar menu = getCustomMenuBar();
370
        JMenuBar menu = getCustomMenuBar();
376
        if (menu == null) {
371
        if (menu == null) {
377
             menu = new MenuBar (null);
372
            menu = MenuProvider.installMenu(this);
373
        } else {
374
            Logger.getLogger(MainWindow.class.getName()).log (Level.WARNING,
375
                    "Use of system property to create main menu deprecated. " +
376
                    "Instead, provide your own MenuProvider in the default " +
377
                    "Lookup.");
378
        }
378
        }
379
        menu.setBorderPainted(false);
380
        if (menu instanceof MenuBar) {
381
            ((MenuBar)menu).waitFinished();
382
        }
383
        
384
        if(Constants.SWITCH_STATUSLINE_IN_MENUBAR) {
379
        if(Constants.SWITCH_STATUSLINE_IN_MENUBAR) {
385
            if (Constants.CUSTOM_STATUS_LINE_PATH == null) {
380
            if (Constants.CUSTOM_STATUS_LINE_PATH == null) {
386
                JLabel status = new StatusLine();
381
                JLabel status = new StatusLine();
Lines 391-397 Link Here
391
                JPanel statusLinePanel = new JPanel(new BorderLayout());
386
                JPanel statusLinePanel = new JPanel(new BorderLayout());
392
                statusLinePanel.add(sep, BorderLayout.WEST);
387
                statusLinePanel.add(sep, BorderLayout.WEST);
393
                statusLinePanel.add(status, BorderLayout.CENTER);
388
                statusLinePanel.add(status, BorderLayout.CENTER);
394
                
389
395
                decoratePanel (statusLinePanel, true);
390
                decoratePanel (statusLinePanel, true);
396
                statusLinePanel.setName("statusLine"); //NOI18N
391
                statusLinePanel.setName("statusLine"); //NOI18N
397
                menu.add(statusLinePanel);
392
                menu.add(statusLinePanel);
Lines 402-408 Link Here
402
                }
397
                }
403
            }
398
            }
404
        }
399
        }
405
        
406
        return menu;
400
        return menu;
407
    }
401
    }
408
402
(-)a/openide.loaders/src/org/openide/awt/MenuBar.java (+2 lines)
Lines 109-116 Link Here
109
 * <LI>executable <CODE>DataObject</CODE>s
109
 * <LI>executable <CODE>DataObject</CODE>s
110
 * </UL>
110
 * </UL>
111
 *
111
 *
112
 * @Deprecated No longer used
112
 * @author  David Peroutka, Dafe Simonek, Petr Nejedly
113
 * @author  David Peroutka, Dafe Simonek, Petr Nejedly
113
 */
114
 */
115
@Deprecated
114
public class MenuBar extends JMenuBar implements Externalizable {
116
public class MenuBar extends JMenuBar implements Externalizable {
115
117
116
    /** the folder which represents and loads content of the menubar */
118
    /** the folder which represents and loads content of the menubar */
(-)a/openide.windows/arch.xml (-1 / +3 lines)
Lines 695-702 Link Here
695
    <code>-J-Dnetbeans.winsys.no_toolbars=true</code>
695
    <code>-J-Dnetbeans.winsys.no_toolbars=true</code>
696
</api>
696
</api>
697
<api group="systemproperty" name="netbeans.winsys.menu_bar.path" type="export" category="private">
697
<api group="systemproperty" name="netbeans.winsys.menu_bar.path" type="export" category="private">
698
    <i>Note: This way of replacing the menu bar is deprecated and may be removed.
699
    Instead, implements MenuProvider to provide your own JMenuBar.</i>
698
    If this property is set its value must point to a file on the system file system
700
    If this property is set its value must point to a file on the system file system
699
    that provides instance of type <code>org.openide.awt.MenuBar</code>. 
701
    that provides instance of type <code>javax.swing.JMenuBar</code>.
700
    This alternative menu bar will be used instead of the default one.
702
    This alternative menu bar will be used instead of the default one.
701
    <code>-J-Dnetbeans.winsys.menu_bar.path=foo/bar.instance</code>
703
    <code>-J-Dnetbeans.winsys.menu_bar.path=foo/bar.instance</code>
702
</api>
704
</api>
(-)a/api.menus/nbproject/project.properties (+1 lines)
Lines 1-4 Link Here
1
is.autoload=true
1
is.autoload=true
2
javac.source=1.6
2
javac.source=1.6
3
javac.compilerargs=-Xlint -Xlint:-serial
3
javac.compilerargs=-Xlint -Xlint:-serial
4
javadoc.arch=${basedir}/arch.xml
4
nbm.module.author=Tim Boudreau
5
nbm.module.author=Tim Boudreau
(-)a/core.menu/nbproject/project.properties (+1 lines)
Lines 1-2 Link Here
1
javac.source=1.6
1
javac.source=1.6
2
javac.compilerargs=-Xlint -Xlint:-serial
2
javac.compilerargs=-Xlint -Xlint:-serial
3
javadoc.arch=${basedir}/arch.xml
(-)a/core.menu/src/org/netbeans/core/menu/ActionModelEntry.java (-2 / +27 lines)
Lines 42-51 Link Here
42
import java.io.IOException;
42
import java.io.IOException;
43
import javax.swing.Action;
43
import javax.swing.Action;
44
import javax.swing.JCheckBoxMenuItem;
44
import javax.swing.JCheckBoxMenuItem;
45
import javax.swing.JComponent;
45
import javax.swing.JMenuItem;
46
import javax.swing.JMenuItem;
46
import org.openide.awt.AcceleratorBinding;
47
import org.openide.awt.AcceleratorBinding;
47
import org.openide.awt.Actions;
48
import org.openide.awt.Actions;
49
import org.openide.awt.DynamicMenuContent;
48
import org.openide.awt.Mnemonics;
50
import org.openide.awt.Mnemonics;
51
import org.openide.cookies.InstanceCookie;
49
import org.openide.loaders.DataObject;
52
import org.openide.loaders.DataObject;
50
import org.openide.util.Exceptions;
53
import org.openide.util.Exceptions;
51
import org.openide.util.actions.BooleanStateAction;
54
import org.openide.util.actions.BooleanStateAction;
Lines 77-82 Link Here
77
        return old;
80
        return old;
78
    }
81
    }
79
82
83
    @Override
84
    protected void verifyType(Action o) throws ReplaceMeException {
85
        if (o instanceof DynamicMenuContent) {
86
            throw new ReplaceMeException(o);
87
        }
88
        if (o instanceof Presenter.Menu) {
89
            throw new ReplaceMeException(o);
90
        }
91
        if (o instanceof JComponent) {
92
            throw new ReplaceMeException(o);
93
        }
94
    }
95
80
    private String getActionName(Action action) {
96
    private String getActionName(Action action) {
81
        String name = (String) action.getValue(Action.NAME);
97
        String name = (String) action.getValue(Action.NAME);
82
        if (name == null && action instanceof SystemAction) {
98
        if (name == null && action instanceof SystemAction) {
Lines 95-105 Link Here
95
    }
111
    }
96
112
97
    @Override
113
    @Override
114
    Types type() {
115
        return Types.ACTION;
116
    }
117
118
    @Override
98
    protected JMenuItem findComponent() {
119
    protected JMenuItem findComponent() {
99
        try {
120
        try {
100
            Action action = get();
121
            Action action = get();
101
            if (action instanceof Presenter.Menu) {
122
            if (action instanceof Presenter.Menu || action instanceof DynamicMenuContent || action instanceof JComponent) {
102
                throw new IllegalStateException("ActionModelEntry used for a menu presenter action");
123
                ReplaceMeException e = new ReplaceMeException(action);
124
                logLiarInstanceCookie(type(), e.getPreferredType(),
125
                        file().getLookup().lookup(InstanceCookie.class), file(),
126
                        action);
127
                throw e;
103
            }
128
            }
104
            JMenuItem item;
129
            JMenuItem item;
105
            if (action instanceof BooleanStateAction) {
130
            if (action instanceof BooleanStateAction) {
(-)a/core.menu/src/org/netbeans/core/menu/ComponentModelEntry.java (+5 lines)
Lines 57-62 Link Here
57
    }
57
    }
58
58
59
    @Override
59
    @Override
60
    Types type() {
61
        return Types.COMPONENT;
62
    }
63
64
    @Override
60
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
65
    protected boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) {
61
        return false;
66
        return false;
62
    }
67
    }
(-)a/core.menu/src/org/netbeans/core/menu/DynamicModelEntry.java (+5 lines)
Lines 56-61 Link Here
56
    }
56
    }
57
57
58
    @Override
58
    @Override
59
    Types type() {
60
        return Types.DYNAMIC_MENU_CONTENT;
61
    }
62
63
    @Override
59
    protected JComponent[] findComponents() {
64
    protected JComponent[] findComponents() {
60
        try {
65
        try {
61
            DynamicMenuContent dyn = get();
66
            DynamicMenuContent dyn = get();
(-)a/core.menu/src/org/netbeans/core/menu/FileModelEntry.java (-1 / +5 lines)
Lines 72-84 Link Here
72
        return Component.class.isAssignableFrom(dobType);
72
        return Component.class.isAssignableFrom(dobType);
73
    }
73
    }
74
74
75
    protected T get() throws IOException, ClassNotFoundException {
75
    protected T get() throws IOException, ClassNotFoundException, ReplaceMeException {
76
        if (requiresEq() && !EventQueue.isDispatchThread()) {
76
        if (requiresEq() && !EventQueue.isDispatchThread()) {
77
            throw new IllegalStateException ("Not on event thread");
77
            throw new IllegalStateException ("Not on event thread");
78
        }
78
        }
79
        return modelObjectType.cast(cookie().instanceCreate());
79
        return modelObjectType.cast(cookie().instanceCreate());
80
    }
80
    }
81
81
82
    protected void verifyType (T o) throws ReplaceMeException {
83
        //do nothing
84
    }
85
82
    private static final class EmptyInstanceCookie implements InstanceCookie, InstanceCookie.Of {
86
    private static final class EmptyInstanceCookie implements InstanceCookie, InstanceCookie.Of {
83
        private final String name;
87
        private final String name;
84
        EmptyInstanceCookie (String name) {
88
        EmptyInstanceCookie (String name) {
(-)a/core.menu/src/org/netbeans/core/menu/FolderModelEntry.java (-78 / +98 lines)
Lines 50-66 Link Here
50
import java.util.List;
50
import java.util.List;
51
import java.util.Map;
51
import java.util.Map;
52
import java.util.Set;
52
import java.util.Set;
53
import javax.swing.Action;
53
import java.util.logging.Level;
54
import java.util.logging.Logger;
54
import javax.swing.JComponent;
55
import javax.swing.JComponent;
55
import javax.swing.JMenuItem;
56
import javax.swing.JMenuItem;
56
import javax.swing.JSeparator;
57
import javax.swing.JSeparator;
57
import org.openide.awt.DynamicMenuContent;
58
import org.openide.cookies.InstanceCookie;
58
import org.openide.cookies.InstanceCookie;
59
import org.openide.loaders.DataFolder;
59
import org.openide.loaders.DataFolder;
60
import org.openide.loaders.DataObject;
60
import org.openide.loaders.DataObject;
61
import org.openide.util.Exceptions;
61
import org.openide.util.Exceptions;
62
import org.openide.util.Parameters;
62
import org.openide.util.Parameters;
63
import org.openide.util.actions.Presenter;
64
63
65
/**
64
/**
66
 *
65
 *
Lines 148-154 Link Here
148
147
149
    @Override
148
    @Override
150
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
149
    protected boolean initBackground(List<? super ModelEntry<?, ?>> children, int currDepth) {
151
//        System.err.println("initBackground " + getName());
152
        DataFolder fld = file();
150
        DataFolder fld = file();
153
        boolean changed = true;
151
        boolean changed = true;
154
        Set<ModelEntry<?, ?>> created = new HashSet<ModelEntry<?, ?>>();
152
        Set<ModelEntry<?, ?>> created = new HashSet<ModelEntry<?, ?>>();
Lines 161-171 Link Here
161
                        for (Types t : Types.values()) {
159
                        for (Types t : Types.values()) {
162
                            if (t.accept(dob)) {
160
                            if (t.accept(dob)) {
163
                                ModelEntry<?, ?> e = t.createEntry(dob, this);
161
                                ModelEntry<?, ?> e = t.createEntry(dob, this);
162
                                //XXX defer or batch afterward?
163
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
164
                                boolean hasKids;
165
                                try {
166
                                    hasKids = e.initBackground(kids, currDepth+1);
167
                                } catch (ReplaceMeException ex) {
168
                                    Types type = ex.getPreferredType();
169
                                    logLiarInstanceCookie(t, type, dob.getCookie(InstanceCookie.class), dob, ex.culprit());
170
                                    if (type != null) {
171
                                        e = ex.getPreferredType().createEntry(dob, this);
172
                                        kids = new ArrayList<ModelEntry<?, ?>>();
173
                                        hasKids = e.initBackground(kids, currDepth+1);
174
                                    } else {
175
                                        continue;
176
                                    }
177
                                }
164
                                created.add(e);
178
                                created.add(e);
165
                                children.add(e);
179
                                children.add(e);
166
                                //XXX defer or batch afterward?
167
                                List<ModelEntry<?, ?>> kids = new ArrayList<ModelEntry<?, ?>>();
168
                                boolean hasKids = e.initBackground(kids, currDepth+1);
169
                                changed |= hasKids;
180
                                changed |= hasKids;
170
                                if (hasKids) {
181
                                if (hasKids) {
171
                                    if (e instanceof FolderModelEntry) {
182
                                    if (e instanceof FolderModelEntry) {
Lines 176-182 Link Here
176
                                continue outer;
187
                                continue outer;
177
                            }
188
                            }
178
                        }
189
                        }
179
//                        System.err.println("No type accepted " + dob.getPrimaryFile().getPath() + " : " + ic(dob));
190
                        Logger.getLogger(FolderModelEntry.class.getName()).log (Level.INFO,
191
                                "Unrecognized menu entry: {0} - not an Action, Presenter.Menu, folder, " + //NOI18N
192
                                "DynamicMenuContent or JComponent", dob.getPrimaryFile().getPath()); //NOI18N
180
                    } catch (IOException ex) {
193
                    } catch (IOException ex) {
181
                        Exceptions.printStackTrace(ex);
194
                        Exceptions.printStackTrace(ex);
182
                    } catch (ClassNotFoundException ex) {
195
                    } catch (ClassNotFoundException ex) {
Lines 190-199 Link Here
190
        return changed;
203
        return changed;
191
    }
204
    }
192
205
193
//    private static String ic(DataObject dob) throws ClassNotFoundException, IOException {
206
    private JComponent[] fetchComponents (int index, ModelEntry<?,?> e, List<ModelEntry<?,?>> loop, int[] offset) {
194
//        InstanceCookie ck = dob.getCookie(InstanceCookie.class);
207
        JComponent[] comps = null;
195
//        return ck == null ? " [no ic]" : ck.instanceClass().getName();
208
        try {
196
//    }
209
            //If an InstanceCookie claims to just provide an Action,
210
            //but in fact provides, say, a Presenter.Menu, or
211
            //DynamicMenuContent, an exception will be thrown and we
212
            //have to replace the model object with the one we actually
213
            //need
214
            comps = e.getComponents();
215
        } catch (ReplaceMeException ex) {
216
            Types t = ex.getPreferredType();
217
            if (t == e.type()) {
218
                throw new IllegalStateException ("Keep getting same wrong type for " + e);
219
            }
220
            if (t == null) {
221
                synchronized (childLock) {
222
                    children.remove (e);
223
                }
224
                loop.remove(index);
225
                offset[0] = -1;
226
                return null;
227
            } else {
228
                ModelEntry<?,?> nue = t.createEntry(e.file(), this);
229
                Logger.getLogger (FolderModelEntry.class.getName()).log(Level.FINE,
230
                        "Replace {0} with {1}", new Object[] { e, nue });
231
                loop.set(index, nue);
232
                synchronized (childLock) {
233
                    int ix = children.indexOf(e); //May have changed, so look up the index
234
                    if (ix >= 0) {
235
                        children.set(ix, nue);
236
                    }
237
                }
238
                e = nue;
239
                comps = e.getComponents();
240
                offset[0] = Integer.MAX_VALUE;
241
            }
242
        }
243
        return comps;
244
    }
245
197
    @Override
246
    @Override
198
    protected CompType refreshComponent(CompType old) {
247
    protected CompType refreshComponent(CompType old) {
199
        if (!EventQueue.isDispatchThread()) {
248
        if (!EventQueue.isDispatchThread()) {
Lines 205-215 Link Here
205
        List<JComponent> all = new LinkedList<JComponent>();
254
        List<JComponent> all = new LinkedList<JComponent>();
206
        List<ModelEntry<?, ?>> kids = children();
255
        List<ModelEntry<?, ?>> kids = children();
207
        Boolean expectHasIcon = false;
256
        Boolean expectHasIcon = false;
208
        for (ModelEntry<?, ?> e : kids) {
257
        int max = kids.size();
258
        for (int i=0; i < max; i++) {
259
            ModelEntry<?, ?> e = kids.get(i);
209
            ComponentList c = components(e);
260
            ComponentList c = components(e);
210
            JComponent[] comps;
261
            JComponent[] comps = null;
211
            if (c == null) {
262
            if (c == null) {
212
                comps = e.getComponents();
263
                //A little tortured here, but... Some InstanceCookies,
264
                //particularly ones registered with methodvalue, do not
265
                //tell the truth about whether they are a Presenter.Menu
266
                //or DynamicMenuContent.
267
                //So, fetchComponents() will trigger actual instantiation,
268
                //and if the model object type is wrong, it will replace it
269
                //in the model...at which point we modify the list we're
270
                //looping over and continue merrily onward
271
                int[] offset = new int[1];
272
                comps = fetchComponents(i, e, kids, offset);
273
                if (offset[0] < 0) {
274
                    //We got back an object that is not an Action or anything
275
                    //we can use, and the elemnent has been removed from the
276
                    //model
277
                    max += offset[0]; //subtraction
278
                    i += offset[0]; //subtraction
279
                    continue;
280
                } else if (offset[0] == Integer.MAX_VALUE) {
281
                    //Signal that the model element has been replaced - 
282
                    //fetch it again so we are using the replacement object
283
                    e = kids.get(i);
284
                }
213
                if (comps != null) {
285
                if (comps != null) {
214
                    all.addAll(Arrays.asList(comps));
286
                    all.addAll(Arrays.asList(comps));
215
                    setComponents(e, c = new ComponentList(comps));
287
                    setComponents(e, c = new ComponentList(comps));
Lines 224-230 Link Here
224
                        c = newComps;
296
                        c = newComps;
225
                    }
297
                    }
226
                } else {
298
                } else {
227
                    comps = e.findComponents();
299
                    //If we get a ReplaceMeException here, then the return
300
                    //type has changed on the fly - we're just screwed.
301
                    try {
302
                        comps = e.findComponents();
303
                    } catch (ReplaceMeException ex) {
304
                        Exceptions.printStackTrace(ex);
305
                        continue;
306
                    }
228
                    boolean fixed = c.repair(comps);
307
                    boolean fixed = c.repair(comps);
229
                    if (!fixed) {
308
                    if (!fixed) {
230
                        setComponents(e, c = new ComponentList(comps));
309
                        setComponents(e, c = new ComponentList(comps));
Lines 274-340 Link Here
274
        }
353
        }
275
    }
354
    }
276
355
277
    private static enum Types {
356
    @Override
278
357
    final Types type() {
279
        SEPARATOR(JSeparator.class),
358
        return Types.MENU;
280
        DYNAMIC_MENU_CONTENT(DynamicMenuContent.class),
281
        PRESENTER(Presenter.Menu.class),
282
        MENU,
283
        COMPONENT(Component.class),
284
        ACTION(Action.class);
285
        private final Class<?> type;
286
287
        Types(Class<?> type) {
288
            this.type = type;
289
        }
290
291
        Types() {
292
            this(Object.class);
293
        }
294
295
        boolean accept(DataObject dob) throws IOException, ClassNotFoundException {
296
            if (this == MENU) {
297
                DataFolder fld = dob instanceof DataFolder ? (DataFolder) dob
298
                        : dob.getLookup().lookup(DataFolder.class);
299
                return fld != null;
300
            }
301
            InstanceCookie ck = dob.getLookup().lookup(InstanceCookie.class);
302
            return ck instanceof InstanceCookie.Of ? ((InstanceCookie.Of) ck).instanceOf(type)
303
                    : ck == null ? false : type.isAssignableFrom(ck.instanceClass());
304
        }
305
306
        ModelEntry<?, ?> createEntry(DataObject ob, FolderModelEntry entry) {
307
//            System.err.println("Create " + name() + " entry for " + ob.getPrimaryFile().getPath());
308
            switch (this) {
309
                case SEPARATOR:
310
                    return new SeparatorModelEntry(ob);
311
                case ACTION:
312
                    InstanceCookie ic = ob.getLookup().lookup(InstanceCookie.class);
313
                    try {
314
                        //This is a bit of a mess - some InstanceCookies lie
315
                        if (ic.instanceCreate() instanceof Presenter.Menu) {
316
                            return new PresenterEntry(ob);
317
                        }
318
                    } catch (IOException ex) {
319
                        Exceptions.printStackTrace(ex);
320
                    } catch (ClassNotFoundException ex) {
321
                        Exceptions.printStackTrace(ex);
322
                    }
323
                    return new ActionModelEntry(ob);
324
                case DYNAMIC_MENU_CONTENT:
325
                    return new DynamicModelEntry(ob);
326
                case PRESENTER:
327
                    return new PresenterEntry(ob);
328
                case MENU:
329
                    DataFolder fld = ob instanceof DataFolder ? (DataFolder) ob
330
                            : ob.getLookup().lookup(DataFolder.class);
331
                    Parameters.notNull("folder was non-null but is now null", fld);
332
                    return new MenuEntry(fld, MenuManager.rp);
333
                case COMPONENT:
334
                    return new ComponentModelEntry(ob);
335
                default:
336
                    throw new AssertionError(this + "");
337
            }
338
        }
339
    }
359
    }
340
}
360
}
(-)a/core.menu/src/org/netbeans/core/menu/ModelEntry.java (-2 / +31 lines)
Lines 41-50 Link Here
41
41
42
import java.awt.EventQueue;
42
import java.awt.EventQueue;
43
import java.lang.reflect.Array;
43
import java.lang.reflect.Array;
44
import java.util.HashSet;
44
import java.util.List;
45
import java.util.List;
46
import java.util.Set;
47
import java.util.logging.Level;
48
import java.util.logging.Logger;
45
import javax.swing.Icon;
49
import javax.swing.Icon;
46
import javax.swing.JComponent;
50
import javax.swing.JComponent;
47
import javax.swing.JMenuItem;
51
import javax.swing.JMenuItem;
52
import org.openide.cookies.InstanceCookie;
48
import org.openide.loaders.DataObject;
53
import org.openide.loaders.DataObject;
49
import org.openide.util.ImageUtilities;
54
import org.openide.util.ImageUtilities;
50
import org.openide.util.Parameters;
55
import org.openide.util.Parameters;
Lines 67-73 Link Here
67
        Parameters.notNull("file", file);
72
        Parameters.notNull("file", file);
68
    }
73
    }
69
    
74
    
70
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth);
75
    protected abstract boolean initBackground(List<? super ModelEntry<?,?>> children, int currDepth) throws ReplaceMeException;
71
76
72
    public String getName() {
77
    public String getName() {
73
        DataObject file = file();
78
        DataObject file = file();
Lines 78-83 Link Here
78
        return file;
83
        return file;
79
    }
84
    }
80
85
86
    abstract Types type();
87
81
    final Class<CompType> componentType() {
88
    final Class<CompType> componentType() {
82
        return compType;
89
        return compType;
83
    }
90
    }
Lines 208-213 Link Here
208
215
209
    @Override
216
    @Override
210
    public String toString() {
217
    public String toString() {
211
        return super.toString() + "[" + getName() + "]";
218
        String path = file().isValid() ? file().getPrimaryFile().getPath() : getName();
219
        return super.toString() + "[" + path + "," + type() + "]"; //NOI18N
220
    }
221
222
223
    private static final Set<String> loggedFiles = new HashSet<String>();
224
    static void logLiarInstanceCookie (Types expect, Types got, InstanceCookie ic, DataObject ob, Object o) {
225
        if (!loggedFiles.contains(ob.getPrimaryFile().getPath())) {
226
            loggedFiles.add(ob.getPrimaryFile().getPath());
227
            Logger.getLogger(ModelEntry.class.getName()).log(Level.WARNING, //NOI18N
228
                    "{0} - InstanceCookie.instanceClass() does " + //NOI18N
229
                    "not return a type assignable to {5} " + //NOI18N
230
                    "but the object it creates is a {6}: {1} " + //NOI18N
231
                    "({2}). If using 'methodvalue' in a layer, add " + //NOI18N
232
                    "<attr name=\"instanceClass\" " + //NOI18N
233
                    "stringvalue=\"{6}\"/>" + //NOI18N
234
                    "({3} ({4})",  //NOI18N
235
                    new Object[] {
236
237
            ob.getPrimaryFile().getPath(), o, o.getClass().getName(),
238
            ic, ic.getClass().getName(), expect.type().getName(),
239
            got == null ? "null" : got.type().getName()});
240
        }
212
    }
241
    }
213
}
242
}
(-)a/core.menu/src/org/netbeans/core/menu/PresenterEntry.java (+5 lines)
Lines 59-64 Link Here
59
    }
59
    }
60
60
61
    @Override
61
    @Override
62
    Types type() {
63
        return Types.PRESENTER;
64
    }
65
66
    @Override
62
    protected JComponent[] findComponents() {
67
    protected JComponent[] findComponents() {
63
        try {
68
        try {
64
            Presenter.Menu p = super.get();
69
            Presenter.Menu p = super.get();
(-)a/core.menu/src/org/netbeans/core/menu/SeparatorModelEntry.java (+5 lines)
Lines 53-58 Link Here
53
    }
53
    }
54
54
55
    @Override
55
    @Override
56
    public Types type() {
57
        return Types.SEPARATOR;
58
    }
59
60
    @Override
56
    protected JSeparator findComponent() {
61
    protected JSeparator findComponent() {
57
        return new JSeparator();
62
        return new JSeparator();
58
    }
63
    }
(-)a/core.windows/src/org/netbeans/core/windows/actions/UndockWindowAction.java (+2 lines)
Lines 69-74 Link Here
69
     */
69
     */
70
    public UndockWindowAction () {
70
    public UndockWindowAction () {
71
        this.tc = null;
71
        this.tc = null;
72
        putValue (NAME, NbBundle.getMessage(UndockWindowAction.class, "CTL_UndockWindowAction"));
72
    }
73
    }
73
74
74
    /**
75
    /**
Lines 77-82 Link Here
77
     */
78
     */
78
    public UndockWindowAction (TopComponent tc) {
79
    public UndockWindowAction (TopComponent tc) {
79
        this.tc = tc;
80
        this.tc = tc;
81
        putValue (NAME, NbBundle.getMessage(UndockWindowAction.class, "CTL_UndockWindowAction"));
80
    }
82
    }
81
    
83
    
82
    public void actionPerformed (ActionEvent e) {
84
    public void actionPerformed (ActionEvent e) {
(-)a/core.windows/src/org/netbeans/core/windows/view/ui/MainWindow.java (-1 / +3 lines)
Lines 165-171 Link Here
165
        getAccessibleContext().setAccessibleDescription(
165
        getAccessibleContext().setAccessibleDescription(
166
                NbBundle.getBundle(MainWindow.class).getString("ACSD_MainWindow"));
166
                NbBundle.getBundle(MainWindow.class).getString("ACSD_MainWindow"));
167
167
168
        setJMenuBar(mainMenuBar);
168
        if (mainMenuBar != null) { //can legally have an app with no menu
169
            setJMenuBar(mainMenuBar);
170
        }
169
    
171
    
170
        if (!Constants.NO_TOOLBARS) {
172
        if (!Constants.NO_TOOLBARS) {
171
            JComponent tb = getToolbarComponent();
173
            JComponent tb = getToolbarComponent();
(-)a/favorites/src/org/netbeans/modules/favorites/resources/layer.xml (+1 lines)
Lines 63-68 Link Here
63
            <folder name="SelectDocumentNode">
63
            <folder name="SelectDocumentNode">
64
                <file name="org-netbeans-modules-favorites-Select.instance">
64
                <file name="org-netbeans-modules-favorites-Select.instance">
65
                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.favorites.Actions.select"/>
65
                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.favorites.Actions.select"/>
66
                    <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
66
                    <attr name="position" intvalue="300"/>
67
                    <attr name="position" intvalue="300"/>
67
                </file>
68
                </file>
68
            </folder>
69
            </folder>
(-)a/profiler/src/org/netbeans/modules/profiler/mf-layer.xml (+1 lines)
Lines 394-399 Link Here
394
394
395
            <file name="org-netbeans-modules-profiler-actions-ProfileMainProjectAction.instance">
395
            <file name="org-netbeans-modules-profiler-actions-ProfileMainProjectAction.instance">
396
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.profiler.actions.AntActions.profileMainProject"/>
396
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.profiler.actions.AntActions.profileMainProject"/>
397
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
397
            </file>
398
            </file>
398
            <file name="org-netbeans-modules-profiler-actions-RerunAction.instance"/>
399
            <file name="org-netbeans-modules-profiler-actions-RerunAction.instance"/>
399
            <file name="org-netbeans-modules-profiler-actions-StopAction.instance"/>
400
            <file name="org-netbeans-modules-profiler-actions-StopAction.instance"/>
(-)a/projectui/src/org/netbeans/modules/project/ui/resources/layer.xml (+8 lines)
Lines 99-108 Link Here
99
            <!-- Current project -->            
99
            <!-- Current project -->            
100
            <file name="org-netbeans-modules-project-ui-TestProject.instance">
100
            <file name="org-netbeans-modules-project-ui-TestProject.instance">
101
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.testProject"/>
101
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.testProject"/>
102
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
102
            </file>
103
            </file>
103
            
104
            
104
            <file name="org-netbeans-modules-project-ui-JavadocProject.instance">
105
            <file name="org-netbeans-modules-project-ui-JavadocProject.instance">
105
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.javadocProject"/>                       
106
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.javadocProject"/>                       
107
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
106
            </file>
108
            </file>
107
            
109
            
108
            <file name="org-netbeans-modules-project-ui-BuildProject.instance">
110
            <file name="org-netbeans-modules-project-ui-BuildProject.instance">
Lines 124-141 Link Here
124
            <!-- 1 off actions -->            
126
            <!-- 1 off actions -->            
125
            <file name="org-netbeans-modules-project-ui-CompileSingle.instance">
127
            <file name="org-netbeans-modules-project-ui-CompileSingle.instance">
126
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.compileSingle"/>
128
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.compileSingle"/>
129
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
127
            </file>
130
            </file>
128
                        
131
                        
129
            <file name="org-netbeans-modules-project-ui-RunSingle.instance">
132
            <file name="org-netbeans-modules-project-ui-RunSingle.instance">
130
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.runSingle"/>
133
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.runSingle"/>
134
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
131
            </file>
135
            </file>
132
            
136
            
133
            <file name="org-netbeans-modules-project-ui-TestSingle.instance">
137
            <file name="org-netbeans-modules-project-ui-TestSingle.instance">
134
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.testSingle"/>
138
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.testSingle"/>
139
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
135
            </file>
140
            </file>
136
141
137
            <file name="org-netbeans-modules-project-ui-Rerun.instance">
142
            <file name="org-netbeans-modules-project-ui-Rerun.instance">
138
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.rebuildProjectAction"/>
143
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.Actions.rebuildProjectAction"/>
144
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
139
            </file>
145
            </file>
140
            <file name="org-netbeans-modules-project-ui-actions-StopBuildingAction.instance"/>
146
            <file name="org-netbeans-modules-project-ui-actions-StopBuildingAction.instance"/>
141
            <file name="org-netbeans-modules-project-ui-SetMainProjectPopupWithoutContext.instance">
147
            <file name="org-netbeans-modules-project-ui-SetMainProjectPopupWithoutContext.instance">
Lines 169-174 Link Here
169
                
175
                
170
                <file name="org-netbeans-modules-project-ui-SelectInProjects.instance">
176
                <file name="org-netbeans-modules-project-ui-SelectInProjects.instance">
171
                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.SelectNodeAction.inProjects"/>
177
                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.SelectNodeAction.inProjects"/>
178
                    <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
172
                    <attr name="position" intvalue="100"/>
179
                    <attr name="position" intvalue="100"/>
173
                </file>
180
                </file>
174
181
Lines 176-181 Link Here
176
                
183
                
177
                <file name="org-netbeans-modules-project-ui-SelectInFiles.instance">
184
                <file name="org-netbeans-modules-project-ui-SelectInFiles.instance">
178
                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.SelectNodeAction.inFiles"/>
185
                    <attr name="instanceCreate" methodvalue="org.netbeans.modules.project.ui.actions.SelectNodeAction.inFiles"/>
186
                    <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
179
                    <attr name="position" intvalue="200"/>
187
                    <attr name="position" intvalue="200"/>
180
                </file>
188
                </file>
181
                
189
                
(-)a/refactoring.api/src/org/netbeans/modules/refactoring/api/resources/layer.xml (+4 lines)
Lines 114-128 Link Here
114
          <file name="org-netbeans-modules-refactoring-spi-impl-RedoAction.instance"/>
114
          <file name="org-netbeans-modules-refactoring-spi-impl-RedoAction.instance"/>
115
          <file name="org-netbeans-modules-refactoring-api-ui-SafeDeleteAction.instance">
115
          <file name="org-netbeans-modules-refactoring-api-ui-SafeDeleteAction.instance">
116
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.safeDeleteAction"/>
116
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.safeDeleteAction"/>
117
              <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
117
          </file>
118
          </file>
118
          <file name="org-netbeans-modules-refactoring-api-ui-RenameAction.instance">
119
          <file name="org-netbeans-modules-refactoring-api-ui-RenameAction.instance">
119
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.renameAction"/>
120
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.renameAction"/>
121
              <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
120
          </file>
122
          </file>
121
          <file name="org-netbeans-modules-refactoring-api-ui-MoveAction.instance">
123
          <file name="org-netbeans-modules-refactoring-api-ui-MoveAction.instance">
122
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.moveAction"/>
124
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.moveAction"/>
125
              <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
123
          </file>
126
          </file>
124
          <file name="org-netbeans-modules-refactoring-api-ui-CopyAction.instance">
127
          <file name="org-netbeans-modules-refactoring-api-ui-CopyAction.instance">
125
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.copyAction"/>
128
              <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.copyAction"/>
129
              <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
126
          </file>
130
          </file>
127
        <file name="RefactoringWhereUsed.instance">
131
        <file name="RefactoringWhereUsed.instance">
128
            <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.whereUsedAction"/>
132
            <attr name="instanceCreate" methodvalue="org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory.whereUsedAction"/>
(-)a/spi.debugger.ui/src/org/netbeans/modules/debugger/resources/mf-layer.xml (+2 lines)
Lines 148-156 Link Here
148
            <file name="org-netbeans-modules-debugger-ui-actions-DebugProjectAction.instance"/>
148
            <file name="org-netbeans-modules-debugger-ui-actions-DebugProjectAction.instance"/>
149
            <file name="org-netbeans-modules-debugger-ui-actions-DebugFileAction.instance">
149
            <file name="org-netbeans-modules-debugger-ui-actions-DebugFileAction.instance">
150
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.debugger.ui.actions.DebuggerAction.createDebugFileAction"/>
150
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.debugger.ui.actions.DebuggerAction.createDebugFileAction"/>
151
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
151
            </file>
152
            </file>
152
            <file name="org-netbeans-modules-debugger-ui-actions-DebugTestFileAction.instance">
153
            <file name="org-netbeans-modules-debugger-ui-actions-DebugTestFileAction.instance">
153
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.debugger.ui.actions.DebuggerAction.createDebugTestFileAction"/>
154
                <attr name="instanceCreate" methodvalue="org.netbeans.modules.debugger.ui.actions.DebuggerAction.createDebugTestFileAction"/>
155
                <attr name="instanceClass" stringvalue="org.openide.util.actions.Presenter$Menu"/>
154
            </file>
156
            </file>
155
            
157
            
156
            <file name="org-netbeans-modules-debugger-ui-actions-ConnectAction.instance"/>
158
            <file name="org-netbeans-modules-debugger-ui-actions-ConnectAction.instance"/>

Return to bug 182698