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.javadoc.search;
043:
044: import javax.swing.JPopupMenu;
045:
046: import java.awt.event.ActionEvent;
047: import java.awt.event.ActionListener;
048: import java.net.URL;
049: import java.util.*;
050: import java.lang.ref.Reference;
051: import java.lang.ref.WeakReference;
052: import javax.swing.JComponent;
053: import javax.swing.JMenu;
054: import javax.swing.JMenuItem;
055: import javax.swing.event.ChangeEvent;
056: import javax.swing.event.ChangeListener;
057: import org.openide.ErrorManager;
058: import org.openide.awt.HtmlBrowser;
059: import org.openide.awt.Mnemonics;
060: import org.openide.filesystems.FileObject;
061: import org.openide.filesystems.FileStateInvalidException;
062: import org.openide.filesystems.FileSystem;
063: import org.openide.util.HelpCtx;
064: import org.openide.util.NbBundle;
065: import org.openide.awt.DynamicMenuContent;
066: import org.openide.util.actions.SystemAction;
067: import org.openide.util.actions.Presenter;
068:
069: /**
070: * Action which shows mounted Javadoc filesystems with known indexes as a submenu,
071: * so you can choose a Javadoc set.
072: *
073: * @author Jesse Glick
074: */
075: public final class IndexOverviewAction extends SystemAction implements
076: Presenter.Menu {
077:
078: private static final ErrorManager err = ErrorManager
079: .getDefault()
080: .getInstance(
081: "org.netbeans.modules.javadoc.search.IndexOverviewAction.IndexMenu"); // NOI18N
082:
083: public IndexOverviewAction() {
084: putValue("noIconInMenu", Boolean.TRUE); // NOI18N
085: }
086:
087: public void actionPerformed(ActionEvent ev) {
088: // do nothing -- should never be called
089: }
090:
091: public String getName() {
092: return NbBundle.getMessage(IndexOverviewAction.class,
093: "CTL_INDICES_MenuItem");
094: }
095:
096: protected String iconResource() {
097: return null;//"org/netbeans/modules/javadoc/resources/JavaDoc.gif"; // NOI18N
098: }
099:
100: public HelpCtx getHelpCtx() {
101: return new HelpCtx("javadoc.search"); // NOI18N
102: }
103:
104: public JMenuItem getMenuPresenter() {
105: return new IndexMenu();
106: }
107:
108: /**
109: * Lazy menu which when added to its parent menu, will begin creating the
110: * list of filesystems and finding their titles. When the popup for it
111: * is created, it will create submenuitems for each available index.
112: */
113: private final class IndexMenu extends JMenu implements
114: HelpCtx.Provider, DynamicMenuContent {
115:
116: private int itemHash = 0;
117:
118: public IndexMenu() {
119: Mnemonics.setLocalizedText(this , IndexOverviewAction.this
120: .getName());
121: //setIcon(IndexOverviewAction.this.getIcon());
122: // model listening is the only lazy menu procedure that works on macosx
123: getModel().addChangeListener(new ChangeListener() {
124: public void stateChanged(ChangeEvent e) {
125: if (getModel().isSelected()) {
126: getPopupMenu2();
127: }
128: }
129: });
130: }
131:
132: public HelpCtx getHelpCtx() {
133: return IndexOverviewAction.this .getHelpCtx();
134: }
135:
136: public JComponent[] getMenuPresenters() {
137: return new JComponent[] { this };
138: }
139:
140: public JComponent[] synchMenuPresenters(JComponent[] items) {
141: return items;
142: }
143:
144: // public void addNotify() {
145: // if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
146: // err.log("addNotify");
147: // }
148: // super.addNotify();
149: // IndexBuilder.getDefault();
150: // }
151:
152: public void getPopupMenu2() {
153: List[] data = IndexBuilder.getDefault().getIndices();
154: int newHash = computeDataHash(data);
155: if (newHash != itemHash) {
156: if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
157: err.log("recreating popup menu (" + itemHash
158: + " -> " + newHash + ")");
159: }
160: itemHash = newHash;
161: // Probably need to recreate the menu.
162: removeAll();
163: List names = data[0]; // List<String>
164: List indices = data[1]; // List<FileObject>
165: int size = names.size();
166: if (size != indices.size())
167: throw new IllegalStateException();
168: if (size > 0) {
169: for (int i = 0; i < size; i++) {
170: try {
171: add(new IndexMenuItem(
172: (String) names.get(i),
173: (FileObject) indices.get(i)));
174: } catch (FileStateInvalidException e) {
175: err.notify(ErrorManager.INFORMATIONAL, e);
176: }
177: }
178: } else {
179: JMenuItem dummy = new JMenuItem(NbBundle
180: .getMessage(IndexOverviewAction.class,
181: "CTL_no_indices_found"));
182: dummy.setEnabled(false);
183: add(dummy);
184: }
185: }
186: }
187:
188: private int computeDataHash(List[] data) {
189: int x = data[0].hashCode();
190: Iterator it = data[1].iterator();
191: while (it.hasNext()) {
192: FileObject fo = (FileObject) it.next();
193: // Just using fo.hashCode() does not work because sometimes the FileObject
194: // is collected and recreated randomly, and now has a new hash code...
195: try {
196: x += fo.getURL().hashCode();
197: } catch (FileStateInvalidException e) {
198: err.notify(ErrorManager.INFORMATIONAL, e);
199: }
200: }
201: return x;
202: }
203:
204: }
205:
206: /**
207: * Menu item representing one Javadoc index.
208: */
209: private final class IndexMenuItem extends JMenuItem implements
210: ActionListener, HelpCtx.Provider {
211:
212: /** cached url */
213: private URL u;
214: /** a reference to org.openide.filesystems.FileSystem */
215: private final Reference fsRef;
216: /** path to index file */
217: private String foPath;
218:
219: public IndexMenuItem(String display, FileObject index)
220: throws FileStateInvalidException {
221: super (display);
222: fsRef = new WeakReference(index.getFileSystem());
223: foPath = index.getPath();
224: addActionListener(this );
225: }
226:
227: public void actionPerformed(ActionEvent ev) {
228: URL loc = getURL();
229: HtmlBrowser.URLDisplayer.getDefault().showURL(loc);
230: }
231:
232: private URL getURL() {
233: if (u == null) {
234: FileSystem fs = (FileSystem) fsRef.get();
235: assert fs != null;
236: FileObject index = fs.findResource(foPath);
237: assert index != null : foPath;
238: u = JavadocURLMapper.findURL(index);
239: }
240: return u;
241: }
242:
243: public HelpCtx getHelpCtx() {
244: return IndexOverviewAction.this.getHelpCtx();
245: }
246:
247: }
248:
249: }
|