001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.project.ui.actions;
043:
044: import java.awt.event.ActionEvent;
045: import java.awt.event.ActionListener;
046: import java.beans.PropertyChangeEvent;
047: import java.beans.PropertyChangeListener;
048: import java.util.Arrays;
049: import javax.swing.Action;
050: import javax.swing.JMenu;
051: import javax.swing.JMenuItem;
052: import javax.swing.JRadioButtonMenuItem;
053: import org.netbeans.api.project.Project;
054: import org.netbeans.api.project.ProjectUtils;
055: import org.netbeans.modules.project.ui.OpenProjectList;
056: import org.netbeans.api.project.ProjectInformation;
057: import org.openide.util.Lookup;
058: import org.openide.util.NbBundle;
059: import org.openide.util.WeakListeners;
060: import org.openide.util.actions.Presenter;
061:
062: public class SetMainProject extends ProjectAction implements
063: Presenter.Menu, PropertyChangeListener {
064:
065: private static final String namePattern = NbBundle.getMessage(
066: SetMainProject.class, "LBL_SetAsMainProjectAction_Name"); // NOI18N
067:
068: /** Key for remembering project in JMenuItem
069: */
070: private static final String PROJECT_KEY = "org.netbeans.modules.project.ui.MainProjectItem"; // NOI18N
071:
072: protected JMenu subMenu;
073:
074: // private PropertyChangeListener wpcl;
075:
076: public SetMainProject() {
077: this (null);
078: }
079:
080: public SetMainProject(Lookup context) {
081: super (
082: SetMainProject.class.getName() /*this is a fake command to make ActionUtils.SHORCUTS_MANAGER work*/,
083: namePattern, null, context);
084: // wpcl = WeakListeners.propertyChange( this, OpenProjectList.getDefault() );
085: // OpenProjectList.getDefault().addPropertyChangeListener( wpcl );
086: if (context == null) {
087: OpenProjectList.getDefault().addPropertyChangeListener(
088: WeakListeners.propertyChange(this , OpenProjectList
089: .getDefault()));
090: }
091: refresh(getLookup());
092: }
093:
094: protected void actionPerformed(Lookup context) {
095: Project[] projects = ActionsUtil.getProjectsFromLookup(context,
096: null);
097:
098: if (projects != null && projects.length > 0)
099: OpenProjectList.getDefault().setMainProject(projects[0]);
100:
101: }
102:
103: public void refresh(Lookup context) {
104:
105: super .refresh(context);
106:
107: Project[] projects = ActionsUtil.getProjectsFromLookup(context,
108: null);
109: if (projects.length != 1 /* Some projects have to be open !OpenProjectList.getDefault().isOpen( projects[0] ) */) {
110: setEnabled(false);
111: } else {
112: setEnabled(true);
113: }
114: }
115:
116: public Action createContextAwareInstance(Lookup actionContext) {
117: return new SetMainProject(actionContext);
118: }
119:
120: public JMenuItem getMenuPresenter() {
121: createSubMenu();
122: return subMenu;
123: }
124:
125: private void createSubMenu() {
126:
127: Project projects[] = OpenProjectList.getDefault()
128: .getOpenProjects();
129:
130: Arrays.sort(projects, OpenProjectList.PROJECT_BY_DISPLAYNAME);
131:
132: // Enable disable the action according to number of open projects
133: if (projects == null || projects.length == 0) {
134: setEnabled(false);
135: } else {
136: setEnabled(true);
137: }
138:
139: if (subMenu == null) {
140: String label = NbBundle.getMessage(SetMainProject.class,
141: "LBL_SetMainProjectAction_Name"); // NOI18N
142: subMenu = new JMenu(label);
143: //ok to have mnenomics here, not shown on mac anyway
144: subMenu.setMnemonic(NbBundle.getMessage(
145: SetMainProject.class,
146: "MNE_SetMainProjectAction_Name").charAt(0)); // NOI18N
147: //#70835: the menu bar holds only subMenu not this action. As this action listens only weakly on OPL, noone holds this action.
148: //The action is the garbage collected and the sub menu does not react on changes of opened projects.
149: //The action instance has to exists as long as the subMenu:
150: subMenu.putClientProperty(SetMainProject.class, this );
151: }
152:
153: subMenu.removeAll();
154: ActionListener jmiActionListener = new MenuItemActionListener();
155:
156: // Fill menu with items
157: for (int i = 0; i < projects.length; i++) {
158: ProjectInformation pi = ProjectUtils
159: .getInformation(projects[i]);
160: JRadioButtonMenuItem jmi = new JRadioButtonMenuItem(pi
161: .getDisplayName(), pi.getIcon(), false);
162: subMenu.add(jmi);
163: jmi.putClientProperty(PROJECT_KEY, projects[i]);
164: jmi.addActionListener(jmiActionListener);
165: }
166:
167: // Set main project
168: selectMainProject();
169:
170: subMenu.setEnabled(projects.length > 0);
171:
172: }
173:
174: private void selectMainProject() {
175:
176: for (int i = 0; i < subMenu.getItemCount(); i++) {
177: JMenuItem jmi = subMenu.getItem(i);
178: Project project = (Project) jmi
179: .getClientProperty(PROJECT_KEY);
180:
181: if (jmi instanceof JRadioButtonMenuItem) {
182: if (OpenProjectList.getDefault().isMainProject(project)) {
183: ((JRadioButtonMenuItem) jmi).setSelected(true);
184: } else {
185: ((JRadioButtonMenuItem) jmi).setSelected(false);
186: }
187: }
188: }
189:
190: }
191:
192: // Implementation of change listener ---------------------------------------
193:
194: public void propertyChange(PropertyChangeEvent e) {
195:
196: if (OpenProjectList.PROPERTY_OPEN_PROJECTS.equals(e
197: .getPropertyName())) {
198: createSubMenu();
199: } else if (OpenProjectList.PROPERTY_MAIN_PROJECT.equals(e
200: .getPropertyName())
201: && subMenu != null) {
202: selectMainProject();
203: }
204:
205: }
206:
207: // Innerclasses ------------------------------------------------------------
208:
209: private static class MenuItemActionListener implements
210: ActionListener {
211:
212: public void actionPerformed(ActionEvent e) {
213:
214: if (e.getSource() instanceof JMenuItem) {
215: JMenuItem jmi = (JMenuItem) e.getSource();
216: Project project = (Project) jmi
217: .getClientProperty(PROJECT_KEY);
218: if (project != null) {
219: OpenProjectList.getDefault()
220: .setMainProject(project);
221: }
222:
223: }
224:
225: }
226:
227: }
228:
229: /**
230: * Variant which behaves just like the menu presenter without a context, but
231: * can be displayed in a context menu.
232: */
233: public static final class PopupWithoutContext extends
234: SetMainProject implements Presenter.Popup {
235:
236: public PopupWithoutContext() {
237: }
238:
239: private PopupWithoutContext(Lookup actionContext) {
240: super (actionContext);
241: }
242:
243: public JMenuItem getPopupPresenter() {
244: // Hack!
245: subMenu = null;
246: return getMenuPresenter();
247: }
248:
249: public Action createContextAwareInstance(Lookup actionContext) {
250: return new PopupWithoutContext(actionContext);
251: }
252:
253: }
254:
255: }
|