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-2007 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: * CodeClipItemNode.java
043: *
044: * Created on July 27, 2006, 10:16 AM
045: *
046: * This node represents the dataobject in the palette
047: *
048: * @author Joelle Lam <joelle.lam@sun.com>
049: * @date 08/20/2006
050: */
051:
052: package org.netbeans.modules.visualweb.palette.codeclips;
053:
054: import java.awt.Image;
055: import java.awt.datatransfer.DataFlavor;
056: import java.awt.datatransfer.Transferable;
057: import java.awt.datatransfer.UnsupportedFlavorException;
058: import java.beans.BeanInfo;
059: import java.io.IOException;
060: import java.util.ArrayList;
061: import java.util.MissingResourceException;
062: import javax.swing.text.JTextComponent;
063: import org.openide.ErrorManager;
064: import org.openide.cookies.EditCookie;
065: import org.openide.filesystems.FileObject;
066: import org.openide.loaders.DataNode;
067: import org.openide.nodes.FilterNode;
068: import org.openide.nodes.Node;
069: import org.openide.text.ActiveEditorDrop;
070: import org.openide.util.Lookup;
071: import org.openide.util.NbBundle;
072: import org.openide.util.Utilities;
073: import org.openide.util.datatransfer.ExTransferable;
074: import org.openide.util.lookup.AbstractLookup;
075: import org.openide.util.lookup.InstanceContent;
076:
077: public final class CodeClipItemNode extends FilterNode implements
078: EditCookie {
079:
080: private static final Node.PropertySet[] NO_PROPERTIES = new Node.PropertySet[0];
081:
082: private String name;
083: private String bundleName;
084: private String displayNameKey;
085: private String tooltipKey;
086: private String icon16URL;
087: private String icon32URL;
088: private String displayName;
089: private String description;
090: private Image icon16;
091: private Image icon32;
092: private String body;
093: private DataNode dataNode;
094: private FileObject fileObj;
095:
096: /*
097: * Class constructor
098: *
099: * @param
100: */
101: CodeClipItemNode(DataNode dataNode, String name, String bundleName,
102: String displayNameKey, String tooltipKey, String icon16URL,
103: String icon32URL, String body, InstanceContent content) {
104:
105: super (dataNode, Children.LEAF, new AbstractLookup(content));
106:
107: // DataObject dataObj = dataNode.getDataObject();
108: fileObj = (dataNode.getDataObject()).getPrimaryFile();
109:
110: this .dataNode = dataNode;
111: content.add(this );
112: this .name = name;
113: this .bundleName = bundleName;
114: this .displayNameKey = displayNameKey;
115: this .tooltipKey = tooltipKey;
116: this .icon16URL = icon16URL;
117: this .icon32URL = icon32URL;
118: this .body = body;
119: }
120:
121: public String getName() {
122: return getDisplayName();
123: }
124:
125: public void setName(String s) {
126:
127: if (!fileObj.canWrite()) {
128: System.out.println("Cannot write to file.");
129: return;
130: }
131: // File file = FileUtil.toFile(fileObj);
132: try {
133: this .destroy();
134: } catch (IOException ex) {
135: ErrorManager.getDefault().notify(ex);
136: }
137:
138: displayNameKey = s;
139:
140: try {
141: CodeClipUtilities.createCodeClipFile(fileObj.getParent(),
142: body, displayNameKey, this .bundleName, tooltipKey);
143: } catch (IOException ex) {
144: ErrorManager.getDefault().notify(
145: ErrorManager.INFORMATIONAL, ex);
146: }
147: }
148:
149: public String getDisplayName() {
150: if (displayName == null) {
151: displayName = _getDisplayName(bundleName, displayNameKey);
152: }
153: return displayName;
154: }
155:
156: public String getShortDescription() {
157: if (description == null) {
158: description = _getShortDescription(bundleName, tooltipKey,
159: displayNameKey);
160: }
161: return description;
162: }
163:
164: public Image getIcon(int type) {
165:
166: Image icon = null;
167:
168: if (type == BeanInfo.ICON_COLOR_16x16
169: || type == BeanInfo.ICON_MONO_16x16) {
170: if (icon16 == null) {
171: icon16 = _getIcon(icon16URL);
172: if (icon16 == null) {
173: icon16 = Utilities
174: .loadImage("org/netbeans/modules/palette/resources/unknown16.gif"); // NOI18N
175: }
176: }
177: icon = icon16;
178: } else if (type == BeanInfo.ICON_COLOR_32x32
179: || type == BeanInfo.ICON_MONO_32x32) {
180: if (icon32 == null) {
181: icon32 = _getIcon(icon32URL);
182: if (icon32 == null) {
183: icon32 = Utilities
184: .loadImage("org/netbeans/modules/palette/resources/unknown32.gif"); // NOI18N
185: }
186: }
187: icon = icon32;
188: }
189:
190: return icon;
191: }
192:
193: public boolean canRename() {
194: return true;
195: }
196:
197: // TODO properties
198: // public Node.PropertySet[] getPropertySets() {
199: // return NO_PROPERTIES;
200: // }
201:
202: public Transferable clipboardCopy() throws IOException {
203:
204: ExTransferable t = ExTransferable.create(super .clipboardCopy());
205:
206: Lookup lookup = getLookup();
207:
208: // Can we create our own version of Active Editor Drop here?
209: ActiveEditorDrop drop = lookup.lookup(ActiveEditorDrop.class);
210: ActiveEditorDropTransferable s = new ActiveEditorDropTransferable(
211: drop);
212: t.put(s);
213:
214: return new NoExternalDndTransferable(t);
215: }
216:
217: @Override
218: public Transferable drag() throws IOException {
219: Transferable t = clipboardCopy();
220: return t;
221: }
222:
223: private static class ActiveEditorDropTransferable extends
224: ExTransferable.Single {
225:
226: private ActiveEditorDrop drop;
227:
228: ActiveEditorDropTransferable(ActiveEditorDrop drop) {
229: super (ActiveEditorDrop.FLAVOR);
230:
231: this .drop = drop;
232: }
233:
234: public Object getData() {
235: return drop;
236: }
237: }
238:
239: public String _getDisplayName(String bundleName,
240: String displayNameKey) {
241: String displayName = null;
242: if (bundleName != null) {
243: try {
244: displayName = NbBundle.getBundle(bundleName).getString(
245: displayNameKey);
246: } catch (MissingResourceException mre) {
247: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
248: displayName = displayNameKey;
249: }
250: } else {
251: displayName = displayNameKey;
252: }
253:
254: return displayName;
255: }
256:
257: public String _getShortDescription(String bundleName,
258: String tooltipKey, String displayNameKey) {
259:
260: String tooltip = null;
261: if (tooltipKey != null && bundleName != null) {
262: try {
263: tooltip = NbBundle.getBundle(bundleName).getString(
264: tooltipKey);
265: } catch (Exception ex) {
266: ErrorManager.getDefault().notify(
267: ErrorManager.INFORMATIONAL, ex);
268: }
269: /* This will make sure the tooltips. I chose to do this here even
270: * thou it means that sometimes it may happen twice due to
271: * performance. I prefer that the palette not be dependent on loading
272: * all of the body comments. By doing this, it is only loaded when
273: * the category is opened. I wish there was a better way to do this.
274: * I would suggest that we never allow the user to use the body as
275: * the tooltip, but I guess that is preference.
276: */
277: // } else if (body != null) {
278: //
279: //
280: // tooltip = CodeClipUtilities.fillFromBundle(body, bundleName);
281: // if (tooltip.length() > 200) {
282: // tooltip = tooltip.substring(0, 200);
283: // }
284: //
285: // tooltip = tooltip.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\n", "<br>");
286: //
287: // /*
288: // * This is a temporary workaround.
289: // * For some reason if the tooltip bigs with / the first line
290: // * is removed altogether form the tooltip. Not sure where this is
291: // * happening.
292: // */
293: //
294: // if (tooltip.startsWith("//")) {
295: // tooltip = " <br>" + tooltip;
296: // }
297: //
298: // tooltip = "<html>".concat(tooltip).concat("</html>");
299: } else if (tooltipKey != null) {
300: tooltip = tooltipKey;
301:
302: } else if (bundleName != null) {
303: // no tooltip derived from the item
304: tooltip = _getDisplayName(bundleName, displayNameKey);
305: } else {
306: tooltip = displayNameKey;
307: }
308:
309: return tooltip;
310: }
311:
312: public Image _getIcon(String iconURL) {
313:
314: Image icon = null;
315: try {
316: icon = Utilities.loadImage(iconURL);
317: } catch (Exception ex) {
318: ErrorManager.getDefault().notify(
319: ErrorManager.INFORMATIONAL, ex);
320: }
321:
322: return icon;
323: }
324:
325: public String getBody() {
326: return body;
327: }
328:
329: public void setBody(String body) {
330: this .body = body;
331: }
332:
333: /*
334: * Edit this codeclip
335: * @param none
336: */
337: public void edit() {
338: String oldDisplayName = this .getDisplayName();
339: String oldToolTip = this .getShortDescription();
340: CodeClipViewerPanel snippetViewer = new CodeClipViewerPanel(
341: this .getDisplayName(), oldToolTip, this .body);
342: snippetViewer.setVisible(true);
343: if (!snippetViewer.isCancelled()) {
344: String newDisplayName = displayNameKey; /* Store the bundle key */
345: String myBundleName = this .bundleName;
346: String text = snippetViewer.getContentText();
347: String title = snippetViewer.getClipName();
348: String newToolTip = tooltipKey;
349: String toolTip = snippetViewer.getToolTip();
350:
351: /* If the name has changed then we will stop worry about keys, etc. */
352: if (!oldDisplayName.equals(title)) {
353: newDisplayName = title;
354: if (this .bundleName != null) /* if this is the first time it is going to null */{
355: newToolTip = toolTip;
356: }
357: myBundleName = null; /* If the title has changed, we no longer need the bundle. */
358: }
359: if (!oldToolTip.equals(toolTip)) {
360: newToolTip = toolTip;
361: if (this .bundleName != null) {
362: newDisplayName = title;
363: }
364: myBundleName = null;
365: }
366: try {
367: CodeClipUtilities.createCodeClipFile(fileObj
368: .getParent(), text, newDisplayName,
369: myBundleName, newToolTip);
370: this .destroy();
371: } catch (IOException ex) {
372: ErrorManager.getDefault().notify(
373: ErrorManager.INFORMATIONAL, ex);
374: }
375: }
376: // this.setBody(text);
377: }
378:
379: /*
380: * Drop the codeclip on the given text component target
381: * @param target JTextComponent or the targeted editor component
382: */
383: public void drop(JTextComponent target) {
384:
385: // if (target == null) {
386: // String msg = NbBundle.getMessage(CodeClipItemNode.class, "MSG_ErrorNoFocusedDocument");
387: // DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(msg, NotifyDescriptor.ERROR_MESSAGE));
388: // return;
389: // }
390: ActiveEditorDrop drop = (ActiveEditorDrop) getLookup().lookup(
391: ActiveEditorDrop.class);
392: drop.handleTransfer(target);
393: }
394:
395: /**
396: * Transferable wrapper that does not allow DataFlavors for external drag and drop
397: * (FileListFlavor and URI list flavors)
398: */
399: private static class NoExternalDndTransferable implements
400: Transferable {
401: private Transferable t;
402: private DataFlavor uriListFlavor;
403:
404: public NoExternalDndTransferable(Transferable t) {
405: this .t = t;
406: }
407:
408: public DataFlavor[] getTransferDataFlavors() {
409: DataFlavor[] flavors = t.getTransferDataFlavors();
410: if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
411: || t.isDataFlavorSupported(getUriListFlavor())) {
412: ArrayList<DataFlavor> tmp = new ArrayList<DataFlavor>(
413: flavors.length);
414: for (int i = 0; i < flavors.length; i++) {
415: if (isDataFlavorSupported(flavors[i]))
416: tmp.add(flavors[i]);
417: }
418: flavors = tmp.toArray(new DataFlavor[tmp.size()]);
419: }
420: return flavors;
421: }
422:
423: public boolean isDataFlavorSupported(DataFlavor flavor) {
424: if (DataFlavor.javaFileListFlavor.equals(flavor)
425: || getUriListFlavor().equals(flavor))
426: return false;
427: return t.isDataFlavorSupported(flavor);
428: }
429:
430: public Object getTransferData(DataFlavor flavor)
431: throws UnsupportedFlavorException, IOException {
432: if (!isDataFlavorSupported(flavor))
433: throw new UnsupportedFlavorException(flavor);
434: return t.getTransferData(flavor);
435: }
436:
437: private DataFlavor getUriListFlavor() {
438: if (null == uriListFlavor) {
439: try {
440: uriListFlavor = new DataFlavor(
441: "text/uri-list;class=java.lang.String");
442: } catch (ClassNotFoundException ex) {
443: //cannot happen
444: throw new AssertionError(ex);
445: }
446: }
447: return uriListFlavor;
448: }
449: }
450: }
|