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: package org.netbeans.modules.project.ui;
042:
043: import java.awt.GridBagConstraints;
044: import java.awt.GridBagLayout;
045: import java.awt.Font;
046: import java.awt.Image;
047: import java.awt.event.ActionEvent;
048: import java.awt.event.ActionListener;
049: import java.awt.event.KeyEvent;
050: import java.beans.PropertyChangeEvent;
051: import java.beans.PropertyChangeListener;
052: import java.beans.PropertyVetoException;
053: import java.beans.VetoableChangeListener;
054: import java.io.IOException;
055: import java.io.InputStream;
056: import java.net.URL;
057: import java.util.StringTokenizer;
058: import javax.swing.JComponent;
059: import javax.swing.JPanel;
060: import javax.swing.KeyStroke;
061: import javax.swing.SwingUtilities;
062: import javax.swing.ToolTipManager;
063: import javax.swing.UIManager;
064: import javax.swing.border.Border;
065: import javax.swing.text.ChangedCharSetException;
066: import javax.swing.text.Document;
067: import javax.swing.text.html.HTMLEditorKit;
068: import javax.swing.text.html.StyleSheet;
069: import org.openide.ErrorManager;
070: import org.openide.awt.Mnemonics;
071: import org.openide.explorer.ExplorerManager;
072: import org.openide.explorer.view.BeanTreeView;
073: import org.openide.explorer.view.ListView;
074: import org.openide.filesystems.FileObject;
075: import org.openide.loaders.*;
076: import org.openide.nodes.AbstractNode;
077: import org.openide.nodes.Children;
078: import org.openide.nodes.FilterNode;
079: import org.openide.nodes.Node;
080: import org.openide.nodes.NodeNotFoundException;
081: import org.openide.nodes.NodeOp;
082: import org.openide.util.NbBundle;
083: import org.openide.util.RequestProcessor;
084: import org.openide.util.Utilities;
085:
086: /**
087: *
088: * @author tom
089: */
090: public class TemplatesPanelGUI extends javax.swing.JPanel implements
091: PropertyChangeListener {
092:
093: public static interface Builder {
094:
095: public Children createCategoriesChildren(DataFolder folder);
096:
097: public Children createTemplatesChildren(DataFolder folder);
098:
099: public String getCategoriesName();
100:
101: public String getTemplatesName();
102:
103: public void fireChange();
104: }
105:
106: public static final String TEMPLATES_FOLDER = "templatesFolder"; //NOI18N
107: public static final String TARGET_TEMPLATE = "targetTemplate"; //NOI18N
108: private static final String ATTR_INSTANTIATING_DESC = "instantiatingWizardURL"; //NOI18N
109: private static final Image PLEASE_WAIT_ICON = Utilities
110: .loadImage("org/netbeans/modules/project/ui/resources/wait.gif"); // NOI18N
111:
112: private Builder firer;
113:
114: private static final RequestProcessor RP = new RequestProcessor();
115:
116: private String presetTemplateName = null;
117: private Node pleaseWait;
118:
119: /** Creates new form TemplatesPanelGUI */
120: public TemplatesPanelGUI(Builder firer) {
121: assert firer != null : "Builder can not be null"; //NOI18N
122: this .firer = firer;
123: initComponents();
124: postInitComponents();
125: setName(NbBundle.getMessage(TemplatesPanelGUI.class,
126: "TXT_SelectTemplate")); // NOI18N
127: }
128:
129: public void setTemplatesFolder(final FileObject folder) {
130: DataFolder dobj = DataFolder.findFolder(folder);
131: ((ExplorerProviderPanel) this .categoriesPanel)
132: .setRootNode(new FilterNode(dobj.getNodeDelegate(),
133: this .firer.createCategoriesChildren(dobj)));
134: }
135:
136: public void setSelectedCategoryByName(final String categoryName) {
137: if (categoryName != null) {
138: try {
139: ((org.netbeans.modules.project.ui.TemplatesPanelGUI.ExplorerProviderPanel) this .categoriesPanel)
140: .setSelectedNode(categoryName);
141: } catch (NodeNotFoundException ex) {
142: // if categoryName is null then select first category leastwise
143: ((CategoriesPanel) this .categoriesPanel)
144: .selectFirstCategory();
145: }
146: } else {
147: // if categoryName is null then select first category leastwise
148: ((CategoriesPanel) this .categoriesPanel)
149: .selectFirstCategory();
150: }
151: }
152:
153: public String getSelectedCategoryName() {
154: return ((ExplorerProviderPanel) this .categoriesPanel)
155: .getSelectionPath();
156: }
157:
158: public void setSelectedTemplateByName(final String templateName) {
159: presetTemplateName = templateName;
160: final TemplatesPanel tempExplorer = ((TemplatesPanel) this .projectsPanel);
161:
162: SwingUtilities.invokeLater(new Runnable() {
163: public void run() {
164: if (templateName != null) {
165: try {
166: tempExplorer.setSelectedNode(templateName);
167: } catch (NodeNotFoundException ex) {
168: //ignore here..
169: }
170: if (tempExplorer.getSelectionPath() == null) {
171: presetTemplateName = null;
172: tempExplorer.selectFirstTemplate();
173: }
174: } else {
175: tempExplorer.selectFirstTemplate();
176: }
177: }
178: });
179:
180: }
181:
182: public String getSelectedTemplateName() {
183: return ((TemplatesPanel) this .projectsPanel).getSelectionPath();
184: }
185:
186: public FileObject getSelectedTemplate() {
187: Node[] nodes = ((ExplorerProviderPanel) this .projectsPanel)
188: .getSelectedNodes();
189: if (nodes != null && nodes.length == 1) {
190: DataObject dobj = nodes[0].getCookie(DataObject.class);
191: if (dobj != null) {
192: while (dobj instanceof DataShadow) {
193: dobj = ((DataShadow) dobj).getOriginal();
194: }
195: return dobj.getPrimaryFile();
196: }
197: }
198: return null;
199: }
200:
201: @Override
202: public void removeNotify() {
203: super .removeNotify();
204: jScrollPane1.setViewportView(null);
205: jLabel3.setLabelFor(null);
206: }
207:
208: public void propertyChange(PropertyChangeEvent event) {
209: if (event.getSource() == this .categoriesPanel) {
210: if (ExplorerManager.PROP_SELECTED_NODES.equals(event
211: .getPropertyName())) {
212: Node[] selectedNodes = (Node[]) event.getNewValue();
213: if (selectedNodes != null && selectedNodes.length == 1) {
214: assert pleaseWait == null
215: || !pleaseWait.equals(selectedNodes[0]) : "Cannot be fired a propertyChange with PleaseWaitNode, but was "
216: + selectedNodes[0];
217: try {
218: ((ExplorerProviderPanel) this .projectsPanel)
219: .setSelectedNodes(new Node[0]);
220: } catch (PropertyVetoException e) {
221: /*Ignore it*/
222: }
223: DataObject template = (DataObject) selectedNodes[0]
224: .getCookie(DataFolder.class);
225: if (template != null) {
226: FileObject fo = template.getPrimaryFile();
227: ((ExplorerProviderPanel) this .projectsPanel)
228: .setRootNode(new FilterNode(
229: selectedNodes[0],
230: this .firer
231: .createTemplatesChildren((DataFolder) template)));
232: // after change of root select the first template to make easy move in wizard
233: this
234: .setSelectedTemplateByName(presetTemplateName);
235: }
236: }
237: }
238: } else if (event.getSource() == this .projectsPanel) {
239: if (ExplorerManager.PROP_SELECTED_NODES.equals(event
240: .getPropertyName())) {
241: Node[] selectedNodes = (Node[]) event.getNewValue();
242: if (selectedNodes != null && selectedNodes.length == 1) {
243: DataObject template = selectedNodes[0]
244: .getCookie(DataObject.class);
245: if (template != null) {
246: FileObject fo = template.getPrimaryFile();
247: URL descURL = getDescription(template);
248: if (descURL != null) {
249: try {
250: //this.description.setPage (descURL);
251: // Set page does not work well if there are mutiple calls to that
252: // see issue #49067. This is a hotfix for the bug which causes
253: // synchronous loading of the content. It should be improved later
254: // by doing it in request processor.
255:
256: //this.description.read( descURL.openStream(), descURL );
257: // #52801: handlig changed charset
258: String charset = findEncodingFromURL(descURL
259: .openStream());
260: ErrorManager.getDefault().log(
261: ErrorManager.INFORMATIONAL,
262: "Url " + descURL
263: + " has charset "
264: + charset); // NOI18N
265: if (charset != null) {
266: description.putClientProperty(
267: "charset", charset); // NOI18N
268: }
269: this .description.read(descURL
270: .openStream(), descURL);
271: } catch (ChangedCharSetException x) {
272: Document doc = description
273: .getEditorKit()
274: .createDefaultDocument();
275: doc.putProperty(
276: "IgnoreCharsetDirective",
277: Boolean.valueOf(true)); // NOI18N
278: try {
279: description.read(descURL
280: .openStream(), doc);
281: } catch (IOException ioe) {
282: ErrorManager.getDefault().notify(
283: ErrorManager.INFORMATIONAL,
284: ioe);
285: this .description
286: .setText(NbBundle
287: .getBundle(
288: TemplatesPanelGUI.class)
289: .getString(
290: "TXT_NoDescription")); // NOI18N
291: }
292: } catch (IOException e) {
293: ErrorManager.getDefault().notify(
294: ErrorManager.INFORMATIONAL, e);
295: this .description
296: .setText(NbBundle
297: .getBundle(
298: TemplatesPanelGUI.class)
299: .getString(
300: "TXT_NoDescription")); // NOI18N
301: }
302: } else {
303: this .description.setText(NbBundle
304: .getBundle(TemplatesPanelGUI.class)
305: .getString("TXT_NoDescription")); // NOI18N
306: }
307: }
308: } else {
309: // bugfix #46738, Description in New Project dialog doesn't show description of selected categories
310: this .description.setText(NbBundle.getBundle(
311: TemplatesPanelGUI.class).getString(
312: "TXT_NoDescription")); // NOI18N
313: }
314: this .firer.fireChange();
315: }
316: }
317: }
318:
319: private void postInitComponents() {
320: Mnemonics.setLocalizedText(jLabel1, this .firer
321: .getCategoriesName());
322: Mnemonics.setLocalizedText(jLabel2, this .firer
323: .getTemplatesName());
324: this .description.setEditorKit(new HTMLEditorKit());
325:
326: // please wait node, see issue 52900
327: pleaseWait = new AbstractNode(Children.LEAF) {
328: public Image getIcon(int ignore) {
329: return PLEASE_WAIT_ICON;
330: }
331: };
332: pleaseWait.setName(NbBundle.getBundle(TemplatesPanelGUI.class)
333: .getString("LBL_TemplatesPanel_PleaseWait"));
334: Children ch = new Children.Array();
335: ch.add(new Node[] { pleaseWait });
336: final Node root = new AbstractNode(ch);
337: SwingUtilities.invokeLater(new Runnable() {
338: public void run() {
339: ((ExplorerProviderPanel) categoriesPanel)
340: .setRootNode(root);
341: }
342: });
343: }
344:
345: /** This method is called from within the constructor to
346: * initialize the form.
347: * WARNING: Do NOT modify this code. The content of this method is
348: * always regenerated by the Form Editor.
349: */
350: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
351: private void initComponents() {
352: java.awt.GridBagConstraints gridBagConstraints;
353:
354: jLabel1 = new javax.swing.JLabel();
355: jLabel2 = new javax.swing.JLabel();
356: categoriesPanel = new CategoriesPanel();
357: projectsPanel = new TemplatesPanel();
358: jLabel3 = new javax.swing.JLabel();
359: jScrollPane1 = new javax.swing.JScrollPane();
360: description = new javax.swing.JEditorPane();
361:
362: setPreferredSize(new java.awt.Dimension(500, 230));
363: setLayout(new java.awt.GridBagLayout());
364:
365: jLabel1.setLabelFor(categoriesPanel);
366: org.openide.awt.Mnemonics.setLocalizedText(jLabel1,
367: org.openide.util.NbBundle.getBundle(
368: TemplatesPanelGUI.class).getString(
369: "CTL_Categories")); // NOI18N
370: gridBagConstraints = new java.awt.GridBagConstraints();
371: gridBagConstraints.gridx = 0;
372: gridBagConstraints.gridy = 0;
373: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
374: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
375: gridBagConstraints.weightx = 0.4;
376: gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 6);
377: add(jLabel1, gridBagConstraints);
378:
379: jLabel2.setLabelFor(projectsPanel);
380: org.openide.awt.Mnemonics.setLocalizedText(jLabel2,
381: org.openide.util.NbBundle.getBundle(
382: TemplatesPanelGUI.class).getString(
383: "CTL_Templates")); // NOI18N
384: gridBagConstraints = new java.awt.GridBagConstraints();
385: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
386: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
387: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
388: gridBagConstraints.weightx = 0.6;
389: gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 0);
390: add(jLabel2, gridBagConstraints);
391: gridBagConstraints = new java.awt.GridBagConstraints();
392: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
393: gridBagConstraints.weightx = 0.4;
394: gridBagConstraints.weighty = 0.8;
395: gridBagConstraints.insets = new java.awt.Insets(2, 0, 6, 6);
396: add(categoriesPanel, gridBagConstraints);
397: gridBagConstraints = new java.awt.GridBagConstraints();
398: gridBagConstraints.gridx = 1;
399: gridBagConstraints.gridy = 1;
400: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
401: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
402: gridBagConstraints.weightx = 0.6;
403: gridBagConstraints.weighty = 0.8;
404: gridBagConstraints.insets = new java.awt.Insets(2, 6, 6, 0);
405: add(projectsPanel, gridBagConstraints);
406:
407: jLabel3.setLabelFor(description);
408: org.openide.awt.Mnemonics.setLocalizedText(jLabel3,
409: org.openide.util.NbBundle.getBundle(
410: TemplatesPanelGUI.class).getString(
411: "CTL_Description")); // NOI18N
412: gridBagConstraints = new java.awt.GridBagConstraints();
413: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
414: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
415: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
416: gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0);
417: add(jLabel3, gridBagConstraints);
418:
419: description.setEditable(false);
420: description
421: .setText(org.openide.util.NbBundle.getBundle(
422: TemplatesPanelGUI.class).getString(
423: "TXT_NoDescription")); // NOI18N
424: description.setPreferredSize(new java.awt.Dimension(100, 66));
425: jScrollPane1.setViewportView(description);
426:
427: gridBagConstraints = new java.awt.GridBagConstraints();
428: gridBagConstraints.gridx = 0;
429: gridBagConstraints.gridy = 3;
430: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
431: gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
432: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
433: gridBagConstraints.weightx = 1.0;
434: gridBagConstraints.weighty = 0.2;
435: gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0);
436: add(jScrollPane1, gridBagConstraints);
437: }// </editor-fold>//GEN-END:initComponents
438:
439: private URL getDescription(DataObject dobj) {
440: //XXX: Some templates are using templateWizardURL others instantiatingWizardURL. What is correct?
441: FileObject fo = dobj.getPrimaryFile();
442: URL desc = (URL) fo.getAttribute(ATTR_INSTANTIATING_DESC);
443: if (desc != null) {
444: return desc;
445: }
446: desc = TemplateWizard.getDescription(dobj);
447: return desc;
448: }
449:
450: private static abstract class ExplorerProviderPanel extends JPanel
451: implements ExplorerManager.Provider,
452: PropertyChangeListener, VetoableChangeListener {
453:
454: private ExplorerManager manager;
455:
456: protected ExplorerProviderPanel() {
457: this .manager = new ExplorerManager();
458: this .manager.addPropertyChangeListener(this );
459: this .manager.addVetoableChangeListener(this );
460: this .initGUI();
461: }
462:
463: public void setRootNode(Node node) {
464: this .manager.setRootContext(node);
465: }
466:
467: public Node getRootNode() {
468: return this .manager.getRootContext();
469: }
470:
471: public Node[] getSelectedNodes() {
472: return this .manager.getSelectedNodes();
473: }
474:
475: public void setSelectedNodes(Node[] nodes)
476: throws PropertyVetoException {
477: this .manager.setSelectedNodes(nodes);
478: }
479:
480: public void setSelectedNode(String path)
481: throws NodeNotFoundException {
482: if (path == null) {
483: return;
484: }
485: StringTokenizer tk = new StringTokenizer(path, "/"); //NOI18N
486: String[] names = new String[tk.countTokens()];
487: for (int i = 0; tk.hasMoreTokens(); i++) {
488: names[i] = tk.nextToken();
489: }
490: try {
491: Node node = NodeOp.findPath(this .manager
492: .getRootContext(), names);
493: if (node != null) {
494: this .manager.setSelectedNodes(new Node[] { node });
495: }
496: } catch (PropertyVetoException e) {
497: //Skip it, not important
498: }
499: }
500:
501: public String getSelectionPath() {
502: Node[] selectedNodes = this .manager.getSelectedNodes();
503: if (selectedNodes == null || selectedNodes.length != 1) {
504: return null;
505: }
506: Node rootNode = this .manager.getRootContext();
507: String[] path = NodeOp.createPath(selectedNodes[0],
508: rootNode);
509: StringBuffer builder = new StringBuffer();
510: for (int i = 0; i < path.length; i++) {
511: builder.append('/'); //NOI18N
512: builder.append(path[i]);
513: }
514: return builder.substring(1);
515: }
516:
517: public ExplorerManager getExplorerManager() {
518: return this .manager;
519: }
520:
521: public void propertyChange(final PropertyChangeEvent event) {
522: // workaround of issue 43502, update of Help button set back the focus
523: // to component which is active when this change starts
524: //XXX: this workaround causes problems in the selection of templates
525: // and should be removed, this workaround can be workarounded in the
526: // setSelectedTemplateByName when template name is null
527: // select the first template only if no template is already selected,
528: // but nicer solution is to remove this workaround at all.
529: SwingUtilities.invokeLater(new Runnable() {
530: public void run() {
531: firePropertyChange(event.getPropertyName(), event
532: .getOldValue(), event.getNewValue());
533: }
534: });
535: }
536:
537: public void vetoableChange(PropertyChangeEvent evt)
538: throws PropertyVetoException {
539: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
540: .getPropertyName())) {
541: Node[] newValue = (Node[]) evt.getNewValue();
542: if (newValue == null
543: || (newValue.length != 1 && newValue.length != 0)) {
544: throw new PropertyVetoException("Invalid length",
545: evt); //NOI18N
546: }
547: }
548: }
549:
550: public void requestFocus() {
551: this .createComponent().requestFocus();
552: }
553:
554: protected abstract JComponent createComponent();
555:
556: private void initGUI() {
557: this .setLayout(new GridBagLayout());
558: GridBagConstraints c = new GridBagConstraints();
559: c.gridx = GridBagConstraints.RELATIVE;
560: c.gridy = GridBagConstraints.RELATIVE;
561: c.gridwidth = GridBagConstraints.REMAINDER;
562: c.gridheight = GridBagConstraints.REMAINDER;
563: c.fill = GridBagConstraints.BOTH;
564: c.anchor = GridBagConstraints.NORTHWEST;
565: c.weightx = 1.0;
566: c.weighty = 1.0;
567: JComponent component = this .createComponent();
568: ((GridBagLayout) this .getLayout()).setConstraints(
569: component, c);
570: this .add(component);
571: }
572:
573: }
574:
575: private static class CategoriesBeanTreeView extends BeanTreeView {
576: public CategoriesBeanTreeView() {
577: super ();
578: this .tree.setEditable(false);
579: }
580:
581: public void selectFirstCategory() {
582: SwingUtilities.invokeLater(new Runnable() {
583: public void run() {
584: tree.setSelectionRow(0);
585: }
586: });
587: }
588: }
589:
590: private static final class CategoriesPanel extends
591: ExplorerProviderPanel {
592:
593: private CategoriesBeanTreeView btv;
594:
595: protected synchronized JComponent createComponent() {
596: if (this .btv == null) {
597: this .btv = new CategoriesBeanTreeView();
598: this .btv.setRootVisible(false);
599: this .btv.setPopupAllowed(false);
600: this .btv.setFocusable(false);
601: this .btv.setDefaultActionAllowed(false);
602: this .btv.getAccessibleContext().setAccessibleName(
603: NbBundle.getMessage(TemplatesPanelGUI.class,
604: "ACSN_CategoriesPanel")); // NOI18N
605: this .btv.getAccessibleContext()
606: .setAccessibleDescription(
607: NbBundle.getMessage(
608: TemplatesPanelGUI.class,
609: "ACSD_CategoriesPanel")); // NOI18N
610: Border b = (Border) UIManager
611: .get("Nb.ScrollPane.border"); // NOI18N
612: if (b != null) {
613: this .btv.setBorder(b);
614: }
615: }
616: return this .btv;
617: }
618:
619: public void selectFirstCategory() {
620: btv.selectFirstCategory();
621: }
622:
623: }
624:
625: private static class TemplatesListView extends ListView implements
626: ActionListener {
627: public TemplatesListView() {
628: super ();
629: // bugfix #44717, Enter key must work regardless if TemplatesPanels is focused
630: list.unregisterKeyboardAction(KeyStroke.getKeyStroke(
631: KeyEvent.VK_ENTER, 0, false));
632: getAccessibleContext().setAccessibleName("OUTER LIST");
633: getAccessibleContext().setAccessibleDescription(
634: "DESC OUTER LIST");
635: setDefaultProcessor(this );
636: ToolTipManager.sharedInstance().unregisterComponent(list);
637: }
638:
639: public void actionPerformed(ActionEvent e) {
640: // Do nothing
641: }
642: }
643:
644: private static final class TemplatesPanel extends
645: ExplorerProviderPanel {
646:
647: private ListView list;
648:
649: protected synchronized JComponent createComponent() {
650: if (this .list == null) {
651: this .list = new TemplatesListView();
652: this .list.setPopupAllowed(false);
653: this .list.getAccessibleContext().setAccessibleName(
654: NbBundle.getMessage(TemplatesPanelGUI.class,
655: "ACSN_TemplatesPanel")); // NOI18N
656: this .list.getAccessibleContext()
657: .setAccessibleDescription(
658: NbBundle.getMessage(
659: TemplatesPanelGUI.class,
660: "ACSD_TemplatesPanel")); // NOI18N
661: Border b = (Border) UIManager
662: .get("Nb.ScrollPane.border");
663: if (b != null) {
664: this .list.setBorder(b); // NOI18N
665: }
666: }
667:
668: return this .list;
669: }
670:
671: public void selectFirstTemplate() {
672: try {
673: Children ch = getExplorerManager().getRootContext()
674: .getChildren();
675: if (ch.getNodesCount() > 0) {
676: getExplorerManager().setSelectedNodes(
677: new Node[] { ch.getNodes()[0] });
678: }
679: } catch (PropertyVetoException pve) {
680: // doesn't matter, can ignore it
681: }
682: }
683:
684: }
685:
686: // Variables declaration - do not modify//GEN-BEGIN:variables
687: private javax.swing.JPanel categoriesPanel;
688: private javax.swing.JEditorPane description;
689: private javax.swing.JLabel jLabel1;
690: private javax.swing.JLabel jLabel2;
691: private javax.swing.JLabel jLabel3;
692: private javax.swing.JScrollPane jScrollPane1;
693: private javax.swing.JPanel projectsPanel;
694:
695: // End of variables declaration//GEN-END:variables
696:
697: void warmUp(FileObject templatesFolder) {
698: if (templatesFolder != null) {
699: DataFolder df = DataFolder.findFolder(templatesFolder);
700: if (df != null) {
701: df.getChildren();
702: }
703: }
704: }
705:
706: void doFinished(FileObject temlatesFolder, String category,
707: String template) {
708: assert temlatesFolder != null;
709:
710: this .categoriesPanel.addPropertyChangeListener(this );
711: this .projectsPanel.addPropertyChangeListener(this );
712:
713: this .setTemplatesFolder(temlatesFolder);
714: this .setSelectedCategoryByName(category);
715: this .setSelectedTemplateByName(template);
716: categoriesPanel.requestFocus();
717: if (description.getEditorKit() instanceof HTMLEditorKit) {
718: // override the Swing default CSS to make the HTMLEditorKit use the
719: // same font as the rest of the UI.
720:
721: // XXX the style sheet is shared by all HTMLEditorKits. We must
722: // detect if it has been tweaked by ourselves or someone else
723: // (code completion javadoc popup for example) and avoid doing the
724: // same thing again
725:
726: HTMLEditorKit htmlkit = (HTMLEditorKit) description
727: .getEditorKit();
728: StyleSheet css = htmlkit.getStyleSheet();
729: if (css.getStyleSheets() != null)
730: return;
731:
732: StyleSheet css2 = new StyleSheet();
733: Font f = jLabel1.getFont();
734: css2.addRule(new StringBuffer("body { font-size: ").append(
735: f.getSize())
736: // NOI18N
737: .append("; font-family: ").append(f.getName())
738: .append("; }").toString()); // NOI18N
739: css2.addStyleSheet(css);
740: htmlkit.setStyleSheet(css2);
741: }
742: }
743:
744: // encoding support; copied from html/HtmlEditorSupport
745: private static String findEncodingFromURL(InputStream stream) {
746: try {
747: byte[] arr = new byte[4096];
748: int len = stream.read(arr, 0, arr.length);
749: String txt = new String(arr, 0, (len >= 0) ? len : 0)
750: .toUpperCase();
751: // encoding
752: return findEncoding(txt);
753: } catch (Exception x) {
754: x.printStackTrace();
755: }
756: return null;
757: }
758:
759: /** Tries to guess the mime type from given input stream. Tries to find
760: * <em><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></em>
761: * @param txt the string to search in (should be in upper case)
762: * @return the encoding or null if no has been found
763: */
764: private static String findEncoding(String txt) {
765: int headLen = txt.indexOf("</HEAD>"); // NOI18N
766: if (headLen == -1)
767: headLen = txt.length();
768:
769: int content = txt.indexOf("CONTENT-TYPE"); // NOI18N
770: if (content == -1 || content > headLen) {
771: return null;
772: }
773:
774: int charset = txt.indexOf("CHARSET=", content); // NOI18N
775: if (charset == -1) {
776: return null;
777: }
778:
779: int charend = txt.indexOf('"', charset);
780: int charend2 = txt.indexOf('\'', charset);
781: if (charend == -1 && charend2 == -1) {
782: return null;
783: }
784:
785: if (charend2 != -1) {
786: if (charend == -1 || charend > charend2) {
787: charend = charend2;
788: }
789: }
790:
791: return txt.substring(charset + "CHARSET=".length(), charend); // NOI18N
792: }
793:
794: }
|