KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > search > project > ProjectsSearchAction


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.search.project;
21
22 import java.awt.Component JavaDoc;
23 import java.beans.PropertyChangeEvent JavaDoc;
24 import java.beans.PropertyChangeListener JavaDoc;
25 import java.lang.ref.Reference JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.List JavaDoc;
29 import org.netbeans.api.project.Project;
30 import org.netbeans.api.project.ProjectUtils;
31 import org.netbeans.api.project.SourceGroup;
32 import org.netbeans.api.project.Sources;
33 import org.netbeans.api.project.ui.OpenProjects;
34 import org.netbeans.modules.search.SearchPanel;
35 import org.netbeans.modules.search.SearchPerformer;
36 import org.openide.filesystems.FileObject;
37 import org.openide.nodes.AbstractNode;
38 import org.openide.nodes.Children;
39
40 import org.openide.nodes.Node;
41 import org.openide.util.Mutex;
42 import org.openide.util.actions.CallableSystemAction;
43 import org.openide.util.HelpCtx;
44 import org.openide.util.NbBundle;
45 import org.openide.util.SharedClassObject;
46 import org.openide.util.lookup.Lookups;
47 import org.openidex.search.FileObjectFilter;
48 import org.openidex.search.SearchInfo;
49 import org.openidex.search.SearchInfoFactory;
50
51
52 /**
53  * Action which searches visible and sharable files of all open projects.
54  * <p>
55  * This action uses two different mechanisms of enabling/disabling,
56  * depending on whether the action is available in the toolbar or not:
57  * <ul>
58  * <li><u>if the action is in the toolbar:</u><br />
59  * The action is updated (enabled/disabled) continuously,
60  * i.e. whenever some project is open or closed.
61  * </li>
62  * <li><u>if the action is <em>not</em> in the toolbar</u><br />
63  * The action state is not updated but it is computed on demand,
64  * i.e. when method <code>isEnabled()</code> is called.
65  * </li>
66  * </ul>
67  * Moreover, the first call of method <code>isEnabled()</code> returns
68  * <code>false</code>, no matter whether some projects are open or not.
69  * This is made so based on the assumption that the first call of
70  * <code>isEnabled()</code> is done during IDE startup as a part of menu
71  * creation. It reduces startup time as it does not force projects
72  * initialization.
73  *
74  * @author Petr Kuzel
75  * @author Marian Petras
76  */

77 public final class ProjectsSearchAction extends CallableSystemAction
78                                         implements PropertyChangeListener JavaDoc {
79
80     static final long serialVersionUID = 4554342565076372610L;
81     
82     /**
83      * name of a shared variable - is this the first call of method
84      * <code>isEnabled()</code>?
85      * Value of this variable is non-<code>null</code> only until method
86      * {@link #isEnabled()} is called for the first time.
87      */

88     private static final String JavaDoc VAR_FIRST_ISENABLED
89                                 = "first call of isEnabled()"; //NOI18N
90
/**
91      * name of a shared variable - reference to the toolbar presenter
92      */

93     private static final String JavaDoc VAR_TOOLBAR_COMP_REF
94                                 = "toolbar presenter ref"; //NOI18N
95
/**
96      * name of a shared variable - are we listening on the set of open projects?
97      * It contains <code>Boolean.TRUE</code> if we are listening,
98      * and <code>null</code> if we are not listening.
99      */

100     private static final String JavaDoc VAR_LISTENING
101                                 = "listening"; //NOI18N
102

103     /**
104      */

105     protected void initialize() {
106         super.initialize();
107         putProperty(VAR_FIRST_ISENABLED, Boolean.TRUE);
108     }
109
110     /**
111      */

112     public Component JavaDoc getToolbarPresenter() {
113         synchronized (getLock()) {
114             Component JavaDoc presenter = getStoredToolbarPresenter();
115             if (putProperty(VAR_LISTENING, Boolean.TRUE) == null) {
116                 OpenProjects.getDefault().addPropertyChangeListener(this);
117                 putProperty(VAR_FIRST_ISENABLED, null);
118                 updateState();
119             }
120             return presenter;
121         }
122     }
123
124     /**
125      * Returns a toolbar presenter.
126      * If the toolbar presenter already exists, returns the existing instance.
127      * If it does not exist, creates a new toolbar presenter, stores
128      * a reference to it to shared variable <code>VAR_TOOLBAR_BTN_REF</code>
129      * and returns the presenter.
130      *
131      * @return existing presenter; or a new presenter if it did not exist
132      */

133     private Component JavaDoc getStoredToolbarPresenter() {
134         Object JavaDoc refObj = getProperty(VAR_TOOLBAR_COMP_REF);
135         if (refObj != null) {
136             Reference JavaDoc ref = (Reference JavaDoc) refObj;
137             Object JavaDoc presenterObj = ref.get();
138             if (presenterObj != null) {
139                 return (Component JavaDoc) presenterObj;
140             }
141         }
142         
143         Component JavaDoc presenter = super.getToolbarPresenter();
144         putProperty(VAR_TOOLBAR_COMP_REF, new WeakReference JavaDoc<Component JavaDoc>(presenter));
145         return presenter;
146     }
147     
148     /**
149      * Checks whether the stored toolbar presenter exists but does not create
150      * one if it does not exist.
151      *
152      * @return <code>true</code> if the reference to the toolbar presenter
153      * is not <code>null</code> and has not been cleared yet;
154      * <code>false</code> otherwise
155      * @see #getStoredToolbarPresenter
156      */

157     private boolean checkToolbarPresenterExists() {
158         Object JavaDoc refObj = getProperty(VAR_TOOLBAR_COMP_REF);
159         if (refObj == null) {
160             return false;
161         }
162         return ((Reference JavaDoc) refObj).get() != null;
163     }
164     
165     /**
166      * This method is called if we are listening for changes on the set
167      * of open projecst and some project(s) is opened/closed.
168      */

169     public void propertyChange(PropertyChangeEvent JavaDoc e) {
170         synchronized (getLock()) {
171             
172             /*
173              * Check whether listening on open projects is active.
174              * This block of code may be called even if listening is off.
175              * It can happen if this method's synchronized block contended
176              * for the lock with another thread which just switched listening
177              * off.
178              */

179             if (getProperty(VAR_LISTENING) == null) {
180                 return;
181             }
182             
183             if (checkToolbarPresenterExists()) {
184                 updateState();
185             } else {
186                 OpenProjects.getDefault().removePropertyChangeListener(this);
187                 putProperty(VAR_LISTENING, null);
188                 putProperty(VAR_TOOLBAR_COMP_REF, null);
189             }
190         }
191         
192     }
193
194     /**
195      */

196     public boolean isEnabled() {
197         synchronized (getLock()) {
198             if (getProperty(VAR_LISTENING) != null) {
199                 return super.isEnabled();
200             } else if (getProperty(VAR_FIRST_ISENABLED) == null) {
201                 return OpenProjects.getDefault().getOpenProjects().length != 0;
202             } else {
203                 
204                 /* first call of this method */
205                 putProperty(VAR_FIRST_ISENABLED, null);
206                 return false;
207             }
208         }
209     }
210     
211     /**
212      */

213     private synchronized void updateState() {
214         
215         /*
216          * no extra synchronization needed - the method is called
217          * only from synchronized blocks of the following methods:
218          * propertyChange(...)
219          * getToolbarPresenter()
220          */

221         
222         final boolean enabled
223                 = OpenProjects.getDefault().getOpenProjects().length != 0;
224         Mutex.EVENT.writeAccess(new Runnable JavaDoc() {
225             public void run() {
226                 setEnabled(enabled);
227             }
228         });
229     }
230
231     protected String JavaDoc iconResource() {
232         return "org/openide/resources/actions/find.gif"; //NOI18N
233
}
234     
235     public String JavaDoc getName() {
236         return NbBundle.getMessage(ProjectsSearchAction.class,
237                                    "LBL_SearchProjects"); //NOI18N
238
}
239
240     public HelpCtx getHelpCtx() {
241         return new HelpCtx(ProjectsSearchAction.class);
242     }
243
244     /** Where to search */
245     Node[] getNodesToSearch() {
246         Project[] openProjects = OpenProjects.getDefault().getOpenProjects();
247         
248         if (openProjects.length == 0) {
249             
250             /*
251              * We cannot prevent this situation. The action may be invoked
252              * between moment the last project had been removed and the removal
253              * notice was distributed to the open projects listener (and this
254              * action disabled). This may happen if the the last project
255              * is being removed in another thread than this action was
256              * invoked from.
257              */

258             return new Node[0];
259         }
260         
261         List JavaDoc<SearchInfo> searchInfos = new ArrayList JavaDoc<SearchInfo>();
262         List JavaDoc<FileObject> rootFolders = new ArrayList JavaDoc<FileObject>();
263         for (int i = 0; i < openProjects.length; i++) {
264             SearchInfo prjSearchInfo = openProjects[i].getLookup().lookup(SearchInfo.class);
265             if (prjSearchInfo != null) {
266                 searchInfos.add(prjSearchInfo);
267                 continue;
268             }
269             
270             Sources sources = ProjectUtils.getSources(openProjects[i]);
271             SourceGroup[] sourceGroups
272                     = sources.getSourceGroups(Sources.TYPE_GENERIC);
273             for (int j = 0; j < sourceGroups.length; j++) {
274                 rootFolders.add(sourceGroups[j].getRootFolder());
275             }
276         }
277
278         int nodesCount = 0;
279         if (!searchInfos.isEmpty()) {
280             nodesCount += searchInfos.size();
281         }
282         if (!rootFolders.isEmpty()) {
283             nodesCount++;
284         }
285         
286         if (nodesCount == 0) {
287             return new Node[0];
288         }
289         
290         Node[] searchNodes = new Node[nodesCount];
291         int nodeIndex = 0;
292         if (!searchInfos.isEmpty()) {
293             for (SearchInfo searchInfo : searchInfos) {
294                 searchNodes[nodeIndex++] = new AbstractNode(
295                                                 Children.LEAF,
296                                                 Lookups.singleton(searchInfo));
297             }
298         }
299         if (!rootFolders.isEmpty()) {
300             SearchInfo searchInfo = SearchInfoFactory.createSearchInfo(
301                     rootFolders.toArray(new FileObject[rootFolders.size()]),
302                     true, //recursive
303
new FileObjectFilter[] {SearchInfoFactory.VISIBILITY_FILTER,
304                                             SearchInfoFactory.SHARABILITY_FILTER});
305             searchNodes[nodeIndex++] = new AbstractNode(
306                                                 Children.LEAF,
307                                                 Lookups.singleton(searchInfo));
308         }
309
310         searchNodes[0].setValue(
311                 SearchPanel.PROP_DIALOG_TITLE,
312                 NbBundle.getMessage(ProjectsSearchAction.class,
313                                     "LBL_Title_SearchProjects")); //NOI18N
314
return searchNodes;
315     }
316
317     /** Perform this action. */
318     public void performAction() {
319         SearchPerformer performer
320                 = ((SearchPerformer) SharedClassObject.findObject(
321                         SearchPerformer.class, true));
322         performer.performAction(getNodesToSearch());
323     }
324     
325     /**
326      */

327     protected boolean asynchronous() {
328         return false;
329     }
330
331 }
332
Popular Tags