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.api.project.ui;
043:
044: import java.beans.PropertyChangeListener;
045: import java.util.concurrent.Future;
046: import org.netbeans.api.project.Project;
047: import org.netbeans.modules.project.uiapi.OpenProjectsTrampoline;
048: import org.netbeans.modules.project.uiapi.Utilities;
049:
050: /**
051: * List of projects open in the GUI.
052: * <p class="nonnormative">
053: * <strong>Warning:</strong> this API is intended only for a limited set of use
054: * cases where obtaining a list of all open projects is really the direct goal.
055: * For example, you may wish to display a chooser letting the user select a
056: * file from among the top-level source folders of any open project.
057: * For many cases, however, this API is not the correct approach, so use it as
058: * a last resort. Consider <a href="@JAVA/API@/org/netbeans/api/java/classpath/GlobalPathRegistry.html"><code>GlobalPathRegistry</code></a>,
059: * {@link org.netbeans.spi.project.ui.ProjectOpenedHook},
060: * and {@link org.netbeans.spi.project.ui.support.ProjectSensitiveActions}
061: * (or {@link org.netbeans.spi.project.ui.support.MainProjectSensitiveActions})
062: * first. Only certain operations should actually be aware of which projects
063: * are "open"; by default, all project functionality should be available whether
064: * it is open or not.
065: * </p>
066: * @author Jesse Glick, Petr Hrebejk
067: */
068: public final class OpenProjects {
069:
070: /**
071: * Property representing open projects.
072: * @see #getOpenProjects
073: */
074: public static final String PROPERTY_OPEN_PROJECTS = "openProjects"; // NOI18N
075:
076: /**
077: * Property representing main project.
078: * @see #getMainProject
079: * @since org.netbeans.modules.projectuiapi/1 1.20
080: */
081: public static final String PROPERTY_MAIN_PROJECT = "MainProject"; // NOI18N
082:
083: private static OpenProjects INSTANCE = new OpenProjects();
084:
085: private OpenProjectsTrampoline trampoline;
086:
087: private OpenProjects() {
088: this .trampoline = Utilities.getOpenProjectsTrampoline();
089: }
090:
091: /**
092: * Get the default singleton instance of this class.
093: * @return the default instance
094: */
095: public static OpenProjects getDefault() {
096: return INSTANCE;
097: }
098:
099: /**
100: * Gets a list of currently open projects.
101: * <p>
102: * <span class="nonnormative">Since 1.26, the standard implementation
103: * handling the list of opened projects, delays their actual loading. First of
104: * all the startup of all modules is finished and only then the projects are loaded
105: * and opened on background. As soon as and no sooner before
106: * all opened projects are opened, the
107: * return value of this method changes and appropriate property change
108: * event with <q>PROPERTY_OPEN_PROJECTS</q> is delivered.
109: * </span>
110: *
111: * @return list of projects currently opened in the IDE's GUI; order not specified
112: */
113: public Project[] getOpenProjects() {
114: return trampoline.getOpenProjectsAPI();
115: }
116:
117: /**
118: * Method to track progress of projects opening and closing. As the
119: * opening of a project may take long time, and as there can be multiple
120: * projects open at once, it may be necessary to be notified that the process
121: * of open project list modification started or that it has
122: * finished. This method provides a <q>future</q> that can do that.
123: * To find out that the list of open projects is currently modified use:
124: * <pre>
125: * assert openProjects().isDone() == false;
126: * </pre>
127: * To wait for the opening/closing to be finished and then obtain the result
128: * use:
129: * <pre>
130: * Project[] current = openProjects().get();
131: * </pre>
132: * This result is different that a plain call to {@link #getOpenProjects} as
133: * that methods returns the current state, whatever it is. While the call through
134: * the <q>future</q> awaits for current modifications to finish. As such wait
135: * can take a long time one can also wait for just a limited amount of time.
136: * However this waiting methods should very likely only be used from dedicated threads,
137: * where the wait does not block other essencial operations (read: do not
138: * use such methods from AWT or other known threads!).
139: *
140: * @return future to track computation of open projects
141: * @since 1.27
142: */
143: public Future<Project[]> openProjects() {
144: return trampoline.openProjectsAPI();
145: }
146:
147: /**
148: * Opens given projects.
149: * Acquires {@link org.netbeans.api.project.ProjectManager#mutex()} in the write mode.
150: * @param projects to be opened. In the case when some of the projects are already opened
151: * these projects are not opened again. If the projects contain duplicates, the duplicated
152: * projects are opened just once.
153: * @param openSubprojects if true also subprojects are opened.
154: * @since org.netbeans.modules.projectuiapi/0 1.2
155: * <p class="nonnormative">
156: * This method is designed for use by logical view's Libraries Node to open one or more of dependent
157: * projects. This method can be used also by other project GUI components which need to open certain
158: * project(s), eg. code generation wizards.<br>
159: * The method should not be used for opening newly created project, insted the
160: * {@link org.openide.WizardDescriptor.InstantiatingIterator#instantiate()} used for creation of new project
161: * should return the project directory.<br>
162: * The method should not be also used to provide a GUI to open subprojects.
163: * The {@link org.netbeans.spi.project.ui.support.CommonProjectActions#openSubprojectsAction()} should be used
164: * instead.
165: * </p>
166: */
167: public void open(Project[] projects, boolean openSubprojects) {
168: trampoline.openAPI(projects, openSubprojects);
169: }
170:
171: /**
172: * Closes given projects.
173: * Acquires {@link org.netbeans.api.project.ProjectManager#mutex()} in the write mode.
174: * @param projects to be closed. The non opened project contained in the projects array are ignored.
175: * @since org.netbeans.modules.projectuiapi/0 1.2
176: */
177: public void close(Project[] projects) {
178: trampoline.closeAPI(projects);
179: }
180:
181: /**Retrieves the current main project set in the IDE.
182: *
183: * <div class="nonnormative">
184: * <p><strong>Warning:</strong> the set of usecases that require invoking this method is
185: * limited. {@link org.netbeans.spi.project.ui.support.MainProjectSensitiveActions} should
186: * be used in favour of this method if possible. In particular, this method should <em>not</em>
187: * be used to let the user choose if an action should be run on the main vs. the currently selected project.</p>
188: * <p>As a rule of thumb, any code outside of the project system infrastructure which behaves differently
189: * depending on the choice of main project should be reviewed critically. All functionality
190: * of a project ought to be available regardless of the "main project" flag, which is intended only
191: * as a convenient shortcut to permit certain actions (such as <b>Run</b>) to be invoked
192: * from a global context on a preselected project.</p>
193: * </div>
194: *
195: * @return the current main project or null if none
196: * @since 1.11
197: */
198: public Project getMainProject() {
199: return trampoline.getMainProject();
200: }
201:
202: /**Sets the main project.
203: *
204: * <div class="nonnormative">
205: * <p><strong>Warning:</strong> the set of usecases that require invoking this method is
206: * very limited and should be generally avoided if possible. In particular, this method
207: * should <em>not</em> be used to mark a project just created by the <b>New Project</b> wizard
208: * as the main project.</p>
209: * </div>
210: *
211: * @param project project to set as main project (must be open), or
212: * <code>null</code> to set no project as main.
213: * @throws IllegalArgumentException if the project is not opened.
214: * @since 1.11
215: */
216: public void setMainProject(Project project)
217: throws IllegalArgumentException {
218: trampoline.setMainProject(project);
219: }
220:
221: /**
222: * Adds a listener to changes in the set of open projects.
223: * As this class is a singleton and is not subject to garbage collection,
224: * it is recommended to add only weak listeners, or remove regular listeners reliably.
225: * @param listener a listener to add
226: * @see #PROPERTY_OPEN_PROJECTS
227: */
228: public void addPropertyChangeListener(
229: PropertyChangeListener listener) {
230: trampoline.addPropertyChangeListenerAPI(listener, this );
231: }
232:
233: /**
234: * Removes a listener.
235: * @param listener a listener to remove
236: */
237: public void removePropertyChangeListener(
238: PropertyChangeListener listener) {
239: trampoline.removePropertyChangeListenerAPI(listener);
240: }
241:
242: }
|