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: * If you wish your version of this file to be governed by only the CDDL
025: * or only the GPL Version 2, indicate your decision by adding
026: * "[Contributor] elects to include this software in this distribution
027: * under the [CDDL or GPL Version 2] license." If you do not indicate a
028: * single choice of license, a recipient has the option to distribute
029: * your version of this file under either the CDDL, the GPL Version 2 or
030: * to extend the choice of license to its licensees as provided above.
031: * However, if you add GPL Version 2 code and therefore, elected the GPL
032: * Version 2 license, then the option applies only if the new code is
033: * made subject to such option by the copyright holder.
034: *
035: * Contributor(s):
036: *
037: * Portions Copyrighted 2007 Sun Microsystems, Inc.
038: */
039:
040: package org.netbeans.modules.project.ui;
041:
042: import java.awt.EventQueue;
043: import java.beans.PropertyChangeEvent;
044: import java.io.IOException;
045: import java.net.URL;
046: import java.util.ArrayList;
047: import java.util.EventObject;
048: import java.util.List;
049: import java.util.concurrent.CountDownLatch;
050: import javax.swing.Action;
051: import junit.framework.TestCase;
052: import org.netbeans.api.project.Project;
053: import org.netbeans.api.project.ProjectManager;
054: import org.netbeans.junit.MockServices;
055: import org.netbeans.junit.NbTestCase;
056: import org.netbeans.modules.project.ui.actions.TestSupport;
057: import org.netbeans.spi.project.ui.ProjectOpenedHook;
058: import org.openide.filesystems.FileObject;
059: import org.openide.filesystems.FileUtil;
060: import org.openide.filesystems.URLMapper;
061: import org.openide.nodes.Node;
062: import org.openide.nodes.Node.Handle;
063: import org.openide.nodes.NodeEvent;
064: import org.openide.nodes.NodeListener;
065: import org.openide.nodes.NodeMemberEvent;
066: import org.openide.nodes.NodeReorderEvent;
067: import org.openide.util.ContextGlobalProvider;
068: import org.openide.util.Exceptions;
069: import org.openide.util.Lookup;
070: import org.openide.util.lookup.Lookups;
071:
072: /**
073: *
074: * @author Jaroslav Tulach <jtulach@netbeans.org>
075: */
076: public class ProjectsRootNodePreferredFromContextOpenTest extends
077: NbTestCase {
078: CountDownLatch first;
079: CountDownLatch middle;
080: CountDownLatch rest;
081:
082: public ProjectsRootNodePreferredFromContextOpenTest(String testName) {
083: super (testName);
084: }
085:
086: @Override
087: protected void setUp() throws Exception {
088: clearWorkDir();
089:
090: MockServices.setServices(TestSupport.TestProjectFactory.class,
091: ContextProv.class);
092:
093: FileObject workDir = FileUtil.toFileObject(getWorkDir());
094: assertNotNull(workDir);
095:
096: first = new CountDownLatch(1);
097: middle = new CountDownLatch(1);
098: rest = new CountDownLatch(2);
099:
100: List<URL> list = new ArrayList<URL>();
101: List<ExtIcon> icons = new ArrayList<ExtIcon>();
102: List<String> names = new ArrayList<String>();
103: for (int i = 0; i < 10; i++) {
104: FileObject prj = TestSupport.createTestProject(workDir,
105: "prj" + i);
106: URL url = URLMapper.findURL(prj, URLMapper.EXTERNAL);
107: list.add(url);
108: names.add(url.toExternalForm());
109: icons.add(new ExtIcon());
110: TestSupport.TestProject tmp = (TestSupport.TestProject) ProjectManager
111: .getDefault().findProject(prj);
112: assertNotNull("Project found", tmp);
113: CountDownLatch down = i == 0 ? first : (i == 5 ? middle
114: : rest);
115: tmp.setLookup(Lookups
116: .singleton(new TestProjectOpenedHookImpl(down)));
117: }
118:
119: OpenProjectListSettings.getInstance().setOpenProjectsURLs(list);
120: OpenProjectListSettings.getInstance()
121: .setOpenProjectsDisplayNames(names);
122: OpenProjectListSettings.getInstance().setOpenProjectsIcons(
123: icons);
124: }
125:
126: @Override
127: protected void tearDown() throws Exception {
128: super .tearDown();
129: }
130:
131: public void testPreferencesInOpenCanBeChanged()
132: throws InterruptedException, IOException {
133: Node logicalView = new ProjectsRootNode(
134: ProjectsRootNode.LOGICAL_VIEW);
135: L listener = new L();
136: logicalView.addNodeListener(listener);
137:
138: assertEquals("10 children", 10, logicalView.getChildren()
139: .getNodesCount());
140: listener.assertEvents("None", 0);
141: assertEquals("No project opened yet", 0,
142: TestProjectOpenedHookImpl.opened);
143:
144: for (Node n : logicalView.getChildren().getNodes()) {
145: TestSupport.TestProject p = n.getLookup().lookup(
146: TestSupport.TestProject.class);
147: assertNull("No project of this type, yet", p);
148: }
149:
150: Node midNode = logicalView.getChildren().getNodes()[5];
151: {
152: TestSupport.TestProject p = midNode.getLookup().lookup(
153: TestSupport.TestProject.class);
154: assertNull("No project of this type, yet", p);
155: }
156: Project lazyP = midNode.getLookup().lookup(Project.class);
157: assertNotNull("Some project is found", lazyP);
158: assertEquals("It is lazy project", LazyProject.class, lazyP
159: .getClass());
160:
161: middle.countDown();
162: // not necessary, but to ensure middle really does not run
163: Thread.sleep(300);
164: assertEquals("Still no processing", 0,
165: TestProjectOpenedHookImpl.opened);
166:
167: // make a file of some project selected, that
168: // shall trigger OpenProjectList.preferredProject(lazyP);
169: FileObject create = FileUtil.createData(lazyP
170: .getProjectDirectory(), "test.txt");
171: ContextProv.assign(Lookups.singleton(create));
172: first.countDown();
173:
174: TestProjectOpenedHookImpl.toOpen.await();
175:
176: {
177: TestSupport.TestProject p = null;
178: for (int i = 0; i < 10; i++) {
179: Node midNode2 = logicalView.getChildren().getNodes()[5];
180: p = midNode.getLookup().lookup(
181: TestSupport.TestProject.class);
182: if (p != null) {
183: break;
184: }
185: Thread.sleep(100);
186: }
187: assertNotNull("The right project opened", p);
188: }
189:
190: rest.countDown();
191: rest.countDown();
192: OpenProjectList.waitProjectsFullyOpen();
193:
194: assertEquals("All projects opened", 10,
195: TestProjectOpenedHookImpl.opened);
196:
197: for (Node n : logicalView.getChildren().getNodes()) {
198: TestSupport.TestProject p = n.getLookup().lookup(
199: TestSupport.TestProject.class);
200: assertNotNull("Nodes have correct project of this type", p);
201: }
202: }
203:
204: private static class L implements NodeListener {
205: public List<EventObject> events = new ArrayList<EventObject>();
206:
207: public void childrenAdded(NodeMemberEvent ev) {
208: assertFalse("No event in AWT thread", EventQueue
209: .isDispatchThread());
210: events.add(ev);
211: }
212:
213: public void childrenRemoved(NodeMemberEvent ev) {
214: assertFalse("No event in AWT thread", EventQueue
215: .isDispatchThread());
216: events.add(ev);
217: }
218:
219: public void childrenReordered(NodeReorderEvent ev) {
220: assertFalse("No event in AWT thread", EventQueue
221: .isDispatchThread());
222: events.add(ev);
223: }
224:
225: public void nodeDestroyed(NodeEvent ev) {
226: assertFalse("No event in AWT thread", EventQueue
227: .isDispatchThread());
228: events.add(ev);
229: }
230:
231: public void propertyChange(PropertyChangeEvent evt) {
232: assertFalse("No event in AWT thread", EventQueue
233: .isDispatchThread());
234: events.add(evt);
235: }
236:
237: final void assertEvents(String string, int i) {
238: assertEquals(string + events, i, events.size());
239: events.clear();
240: }
241:
242: }
243:
244: private static class TestProjectOpenedHookImpl extends
245: ProjectOpenedHook {
246:
247: public static CountDownLatch toOpen = new CountDownLatch(2);
248: public static int opened = 0;
249: public static int closed = 0;
250:
251: private CountDownLatch toWaitOn;
252:
253: public TestProjectOpenedHookImpl(CountDownLatch toWaitOn) {
254: this .toWaitOn = toWaitOn;
255: }
256:
257: protected void projectClosed() {
258: closed++;
259: }
260:
261: protected void projectOpened() {
262: if (toWaitOn != null) {
263: try {
264: toWaitOn.await();
265: } catch (InterruptedException ex) {
266: throw new IllegalStateException(ex);
267: }
268: }
269: opened++;
270: toOpen.countDown();
271: }
272:
273: }
274:
275: public static final class ContextProv implements
276: ContextGlobalProvider, Lookup.Provider {
277: private static Lookup current = Lookup.EMPTY;
278: private static Lookup proxy;
279:
280: public ContextProv() {
281: assert proxy == null;
282: proxy = Lookups.proxy(this );
283: }
284:
285: public static void assign(Lookup current) {
286: ContextProv.current = current;
287: // refresh
288: if (proxy != null) {
289: proxy.lookup((Class<?>) null);
290: }
291: }
292:
293: public Lookup createGlobalContext() {
294: return proxy;
295: }
296:
297: public Lookup getLookup() {
298: return current;
299: }
300:
301: }
302: }
|