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.navigator;
043:
044: import java.awt.BorderLayout;
045: import java.awt.CardLayout;
046: import java.awt.Color;
047: import java.awt.event.ActionEvent;
048: import java.awt.event.KeyEvent;
049: import java.lang.ref.Reference;
050: import java.lang.ref.WeakReference;
051: import java.util.Iterator;
052: import java.util.List;
053: import java.util.logging.Logger;
054: import javax.swing.AbstractAction;
055: import javax.swing.Action;
056: import javax.swing.FocusManager;
057: import javax.swing.JComboBox;
058: import javax.swing.JComponent;
059: import javax.swing.JLabel;
060: import javax.swing.KeyStroke;
061: import javax.swing.SwingConstants;
062: import javax.swing.UIManager;
063: import org.netbeans.spi.navigator.NavigatorPanel;
064: import org.openide.ErrorManager;
065: import org.openide.awt.UndoRedo;
066: import org.openide.util.HelpCtx;
067: import org.openide.util.Lookup;
068: import org.openide.util.NbBundle;
069: import org.openide.util.Utilities;
070: import org.openide.util.lookup.ProxyLookup;
071: import org.openide.windows.TopComponent;
072: import org.openide.windows.WindowManager;
073:
074: /** Navigator TopComponent. Simple visual envelope for navigator graphics
075: * content. Behaviour is delegated and separated into NavigatorController.
076: *
077: * @author Dafe Simonek
078: */
079: public final class NavigatorTC extends TopComponent {
080:
081: /** singleton instance */
082: private static NavigatorTC instance;
083:
084: /** Currently active panel in navigator (or null if empty) */
085: private NavigatorPanel selectedPanel;
086: /** A list of panels currently available (or null if empty) */
087: private List<NavigatorPanel> panels;
088: /** Controller, controls behaviour and reacts to user actions */
089: private NavigatorController controller;
090: /** label signalizing no available providers */
091: private final JLabel notAvailLbl = new JLabel(NbBundle.getMessage(
092: NavigatorTC.class, "MSG_NotAvailable")); //NOI18N
093: /** special lookup for naviagtor TC */
094: private Lookup navTCLookup;
095:
096: /** Creates new NavigatorTC, singleton */
097: private NavigatorTC() {
098: initComponents();
099:
100: setName(NbBundle.getMessage(NavigatorTC.class, "LBL_Navigator")); //NOI18N
101: setIcon(Utilities
102: .loadImage("org/netbeans/modules/navigator/resources/navigator.png")); //NOI18N
103: // accept focus when empty to work correctly in nb winsys
104: setFocusable(true);
105: // special title for sliding mode
106: // XXX - please rewrite to regular API when available - see issue #55955
107: putClientProperty("SlidingName", getName());
108: getAccessibleContext().setAccessibleDescription(
109: NbBundle.getMessage(NavigatorTC.class,
110: "ACC_DESC_NavigatorTC")); //NOI18N
111:
112: notAvailLbl.setHorizontalAlignment(SwingConstants.CENTER);
113: notAvailLbl.setEnabled(false);
114: Color usualWindowBkg = UIManager.getColor("window"); //NOI18N
115: notAvailLbl
116: .setBackground(usualWindowBkg != null ? usualWindowBkg
117: : Color.white);
118: // to ensure our background color will have effect
119: notAvailLbl.setOpaque(true);
120:
121: getController().installActions();
122:
123: // empty initially
124: setToEmpty();
125: }
126:
127: /** Singleton accessor, finds instance in winsys structures */
128: public static final NavigatorTC getInstance() {
129: NavigatorTC navTC = (NavigatorTC) WindowManager.getDefault()
130: .findTopComponent("navigatorTC"); //NOI18N
131: if (navTC == null) {
132: // shouldn't happen under normal conditions
133: navTC = privateGetInstance();
134: Logger
135: .getAnonymousLogger()
136: .warning(
137: "Could not locate the navigator component via its winsys id"); //NOI18N
138: }
139: return navTC;
140: }
141:
142: /** Singleton intance accessor, to be used only from module's layer.xml
143: * file, winsys section and as fallback from getInstance().
144: *
145: * Please don't call directly otherwise.
146: */
147: public static final NavigatorTC privateGetInstance() {
148: if (instance == null) {
149: instance = new NavigatorTC();
150: }
151: return instance;
152: }
153:
154: /** Shows given navigator panel's component
155: */
156: public void setSelectedPanel(NavigatorPanel panel) {
157: int panelIdx = panels.indexOf(panel);
158: assert panelIdx != -1 : "Panel to select is not available"; //NOI18N
159:
160: if (panel.equals(selectedPanel)) {
161: return;
162: }
163:
164: this .selectedPanel = panel;
165: ((CardLayout) contentArea.getLayout()).show(contentArea, String
166: .valueOf(panelIdx));
167: // #93123: follow-up, synchronizing combo selection with content area selection
168: panelSelector.setSelectedIndex(panelIdx);
169: }
170:
171: /** Returns panel currently selected.
172: * @return Panel currently selected or null if navigator is empty
173: */
174: public NavigatorPanel getSelectedPanel() {
175: return selectedPanel;
176: }
177:
178: /** List of panels currently contained in navigator component.
179: * @return List of NavigatorPanel instances or null if navigator is empty
180: */
181: public List<NavigatorPanel> getPanels() {
182: return panels;
183: }
184:
185: /** Sets content of navigator to given panels, selecting the first one
186: */
187: public void setPanels(List<NavigatorPanel> panels) {
188: this .panels = panels;
189: int panelsCount = panels == null ? -1 : panels.size();
190: // no panel, so make UI look empty
191: if (panelsCount <= 0) {
192: selectedPanel = null;
193: setToEmpty();
194: } else {
195: // clear regular content
196: contentArea.removeAll();
197: panelSelector.removeAllItems();
198: // #63777: hide panel selector when only one panel available
199: panelSelector.setVisible(panelsCount != 1);
200: // fill with new content
201: JComponent curComp = null;
202: int i = 0;
203: for (NavigatorPanel curPanel : panels) {
204: panelSelector.addItem(curPanel.getDisplayName());
205: curComp = curPanel.getComponent();
206: // for better error report in cases like #68544
207: if (curComp == null) {
208: Throwable npe = new NullPointerException("Method "
209: + curPanel.getClass().getName() + //NOI18N
210: ".getComponent() must not return null under any condition!" //NOI18N
211: );
212: ErrorManager.getDefault().notify(
213: ErrorManager.EXCEPTION, npe);
214: } else {
215: contentArea.add(curComp, String.valueOf(i));
216: }
217: if (i == 0) {
218: selectedPanel = curPanel;
219: }
220: i++;
221: }
222: // show if was hidden
223: resetFromEmpty();
224: }
225: }
226:
227: /** Returns combo box, UI for selecting proper panels */
228: public JComboBox getPanelSelector() {
229: return panelSelector;
230: }
231:
232: public JComponent getContentArea() {
233: return contentArea;
234: }
235:
236: // Window System related methods >>
237:
238: public String preferredID() {
239: return "navigatorTC"; //NOI18N
240: }
241:
242: public int getPersistenceType() {
243: return PERSISTENCE_ALWAYS;
244: }
245:
246: /** Overriden to pass focus directly into content panel */
247: @SuppressWarnings("deprecation")
248: public boolean requestFocusInWindow() {
249: if (selectedPanel != null) {
250: return selectedPanel.getComponent().requestFocusInWindow();
251: } else {
252: return super .requestFocusInWindow();
253: }
254: }
255:
256: @Override
257: public void requestFocus() {
258: if (selectedPanel != null) {
259: selectedPanel.getComponent().requestFocus();
260: } else {
261: super .requestFocus();
262: }
263: }
264:
265: /** Defines nagivator Help ID */
266: public HelpCtx getHelpCtx() {
267: return new HelpCtx("navigator.java");
268: }
269:
270: /** Just delegates to controller */
271: public void componentOpened() {
272: getController().navigatorTCOpened();
273: }
274:
275: /** Just delegates to controller */
276: public void componentClosed() {
277: getController().navigatorTCClosed();
278: }
279:
280: // << Window system
281:
282: /** Combines default Lookup of TC with lookup from active navigator
283: * panel.
284: */
285: public Lookup getLookup() {
286: if (navTCLookup == null) {
287: Lookup defaultLookup = super .getLookup();
288: Lookup clientLookup = getController().getPanelLookup();
289: navTCLookup = new ProxyLookup(new Lookup[] { defaultLookup,
290: clientLookup });
291: }
292: return navTCLookup;
293: }
294:
295: @Override
296: public UndoRedo getUndoRedo() {
297: return getController().getUndoRedo();
298: }
299:
300: /** Accessor for controller which controls UI behaviour */
301: public NavigatorController getController() {
302: if (controller == null) {
303: controller = new NavigatorController(this );
304: }
305: return controller;
306: }
307:
308: /*************** private stuff ************/
309:
310: /** Removes regular UI content and sets UI to empty state */
311: private void setToEmpty() {
312: if (notAvailLbl.isShowing()) {
313: // already empty
314: return;
315: }
316: remove(panelSelector);
317: remove(contentArea);
318: add(notAvailLbl, BorderLayout.CENTER);
319: revalidate();
320: repaint();
321: }
322:
323: /** Puts regular UI content back */
324: private void resetFromEmpty() {
325: if (contentArea.isShowing()) {
326: // content already shown
327: }
328: remove(notAvailLbl);
329: add(panelSelector, BorderLayout.NORTH);
330: add(contentArea, BorderLayout.CENTER);
331: revalidate();
332: repaint();
333: }
334:
335: /** This method is called from within the constructor to
336: * initialize the form.
337: * WARNING: Do NOT modify this code. The content of this method is
338: * always regenerated by the Form Editor.
339: */
340: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
341: private void initComponents() {
342: panelSelector = new javax.swing.JComboBox();
343: contentArea = new javax.swing.JPanel();
344:
345: setLayout(new java.awt.BorderLayout());
346:
347: add(panelSelector, java.awt.BorderLayout.NORTH);
348:
349: contentArea.setLayout(new java.awt.CardLayout());
350:
351: add(contentArea, java.awt.BorderLayout.CENTER);
352:
353: }
354:
355: // </editor-fold>//GEN-END:initComponents
356:
357: // Variables declaration - do not modify//GEN-BEGIN:variables
358: private javax.swing.JPanel contentArea;
359: private javax.swing.JComboBox panelSelector;
360: // End of variables declaration//GEN-END:variables
361:
362: }
|