0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package com.sun.jsfcl.std;
0042:
0043: import java.awt.Color;
0044: import java.awt.Component;
0045: import java.awt.Dimension;
0046: import java.awt.GridBagConstraints;
0047: import java.awt.GridBagLayout;
0048: import java.awt.Image;
0049: import java.awt.Insets;
0050: import java.awt.event.ActionEvent;
0051: import java.awt.event.ActionListener;
0052: import java.beans.PropertyChangeEvent;
0053: import java.beans.PropertyChangeListener;
0054: import java.io.File;
0055: import java.io.IOException;
0056: import java.lang.reflect.Field;
0057: import java.lang.reflect.Method;
0058: import java.net.MalformedURLException;
0059: import java.net.URI;
0060: import java.net.URISyntaxException;
0061: import java.net.URL;
0062: import java.util.ArrayList;
0063: import java.util.Collections;
0064: import java.util.WeakHashMap;
0065: import javax.swing.Box;
0066: import javax.swing.BoxLayout;
0067: import javax.swing.ButtonGroup;
0068: import javax.swing.ButtonModel;
0069: import javax.swing.Icon;
0070: import javax.swing.ImageIcon;
0071: import javax.swing.JComponent;
0072: import javax.swing.JFileChooser;
0073: import javax.swing.JLabel;
0074: import javax.swing.JOptionPane;
0075: import javax.swing.JPanel;
0076: import javax.swing.JRadioButton;
0077: import javax.swing.JTabbedPane;
0078: import javax.swing.JTextField;
0079: import javax.swing.JToggleButton;
0080: import javax.swing.JToolBar;
0081: import javax.swing.UIManager;
0082: import javax.swing.event.ChangeEvent;
0083: import javax.swing.event.ChangeListener;
0084: import javax.swing.event.DocumentEvent;
0085: import javax.swing.event.DocumentListener;
0086: import javax.swing.filechooser.FileSystemView;
0087: import com.sun.java.swing.plaf.windows.WindowsFileChooserUI;
0088: import com.sun.jsfcl.util.ComponentBundle;
0089: import com.sun.rave.designtime.DesignContext;
0090: import com.sun.rave.designtime.DesignProject;
0091: import com.sun.rave.designtime.DesignProperty;
0092: import org.openide.explorer.propertysheet.editors.EnhancedCustomPropertyEditor;
0093: import org.openide.nodes.Node;
0094: import org.openide.ErrorManager;
0095:
0096: //!CQ TODO: rename this to UrlPanel
0097: public class URLPanel extends JPanel implements PropertyChangeListener,
0098: ActionListener, ChangeListener, EnhancedCustomPropertyEditor,
0099: DocumentListener {
0100:
0101: static String copyString = "Copy"; //NOI18N
0102: static String linkString = "Link"; //NOI18N
0103: protected static WeakHashMap lastDirectoryByProject = new WeakHashMap();
0104: protected static final String LAST_DIRECTORY_KEY_NO_PROJECT = "DEFAULT"; // NOI18N
0105:
0106: private static final ComponentBundle bundle = ComponentBundle
0107: .getBundle(URLPanel.class);
0108:
0109: JTabbedPane tabs = new JTabbedPane();
0110:
0111: JFileChooser filePanel;
0112: HTTPPanel httpPanel;
0113:
0114: JTextField valueTextField = new JTextField();
0115: GridBagLayout gridBagLayout1 = new GridBagLayout();
0116: JLabel valueLabel = new JLabel();
0117: URLPropertyEditor ure;
0118:
0119: JRadioButton copyButton = new JRadioButton(bundle
0120: .getMessage("copy")); //NOI18N
0121: JRadioButton linkButton = new JRadioButton(bundle
0122: .getMessage("link")); //NOI18N
0123:
0124: ButtonGroup group = new ButtonGroup();
0125:
0126: RadioListener myListener = new RadioListener();
0127:
0128: private boolean initialized = false;
0129:
0130: /** The DesignProperty for the property that is being edited */
0131: protected DesignProperty liveProperty;
0132: protected DesignContext liveContext;
0133:
0134: protected Node.Property property;
0135:
0136: /** Opening mode.*/
0137: // private int mode = JFileChooser.FILES_ONLY;
0138: /** Filter for files to show. */
0139: // private javax.swing.filechooser.FileFilter fileFilter;
0140: /** Base directory to which to show relative path, if is set. */
0141: private File baseDirectory;
0142:
0143: // Constructors
0144:
0145: public URLPanel(URLPropertyEditor ure) {
0146: this ();
0147: this .ure = ure;
0148: }
0149:
0150: public URLPanel() {
0151: try {
0152: jbInit();
0153: copyButton.getAccessibleContext().setAccessibleDescription(
0154: org.openide.util.NbBundle.getMessage(
0155: URLPanel.class, "COPY_BUTTON_ACCESS_DESC"));
0156: linkButton.getAccessibleContext().setAccessibleDescription(
0157: org.openide.util.NbBundle.getMessage(
0158: URLPanel.class, "LINK_BUTTON_ACCESS_DESC"));
0159: copyButton.setMnemonic(org.openide.util.NbBundle
0160: .getMessage(URLPanel.class, "COPY_BUTTON_MNEMONIC")
0161: .charAt(0));
0162: linkButton.setMnemonic(org.openide.util.NbBundle
0163: .getMessage(URLPanel.class, "LINK_BUTTON_MNEMONIC")
0164: .charAt(0));
0165: valueTextField.getAccessibleContext().setAccessibleName(
0166: org.openide.util.NbBundle.getMessage(
0167: URLPanel.class,
0168: "VALUE_TEXTFIELD_ACCESS_NAME"));
0169: valueTextField.getAccessibleContext()
0170: .setAccessibleDescription(
0171: org.openide.util.NbBundle.getMessage(
0172: URLPanel.class,
0173: "VALUE_TEXTFIELD_ACCESS_DESC"));
0174: tabs.getAccessibleContext().setAccessibleDescription(
0175: org.openide.util.NbBundle.getMessage(
0176: URLPanel.class, "TAB_PANE_ACCESS_DESC"));
0177: } catch (Exception e) {
0178: e.printStackTrace();
0179: }
0180: }
0181:
0182: public static Image loadImage(final String resourceName,
0183: final Class clazz) {
0184:
0185: try {
0186: java.awt.image.ImageProducer ip = (java.awt.image.ImageProducer) java.security.AccessController
0187: .doPrivileged(new java.security.PrivilegedAction() {
0188: public Object run() {
0189: java.net.URL url;
0190: if ((url = clazz.getResource(resourceName)) == null) {
0191: return null;
0192: } else {
0193: try {
0194: return url.getContent();
0195: } catch (java.io.IOException ioe) {
0196: return null;
0197: }
0198: }
0199: }
0200: });
0201:
0202: if (ip == null) {
0203: return null;
0204: }
0205: java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
0206: return tk.createImage(ip);
0207: } catch (Exception ex) {
0208: return null;
0209: }
0210: }
0211:
0212: private void jbInit() throws Exception {
0213:
0214: copyButton.setActionCommand(copyString);
0215: linkButton.setActionCommand(linkString);
0216:
0217: group.add(copyButton);
0218: group.add(linkButton);
0219: linkButton.setSelected(true);
0220:
0221: copyButton.addActionListener(myListener);
0222: linkButton.addActionListener(myListener);
0223:
0224: this .setLayout(gridBagLayout1);
0225: valueLabel.setText(bundle.getMessage("urlPanelCurrSetting")); //NOI18N
0226: valueTextField.setText(""); //NOI18N
0227: this .add(valueLabel, new GridBagConstraints(0, 0, 1, 1, 1.0,
0228: 0.0, GridBagConstraints.CENTER,
0229: GridBagConstraints.HORIZONTAL, new Insets(8, 8, 2, 8),
0230: 0, 0));
0231: this .add(valueTextField, new GridBagConstraints(0, 1, 1, 1,
0232: 1.0, 0.0, GridBagConstraints.WEST,
0233: GridBagConstraints.HORIZONTAL, new Insets(0, 8, 4, 8),
0234: 0, 0));
0235: this .add(tabs, new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0,
0236: GridBagConstraints.CENTER, GridBagConstraints.BOTH,
0237: new Insets(0, 8, 8, 8), 0, 0));
0238: this .add(copyButton, new GridBagConstraints(2, 1, 1, 1, 0.0,
0239: 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE,
0240: new Insets(0, 0, 0, 0), 0, 0));
0241:
0242: this .add(linkButton, new GridBagConstraints(
0243: GridBagConstraints.RELATIVE, 1, 1, 1, 0.0, 0.0,
0244: GridBagConstraints.EAST, GridBagConstraints.NONE,
0245: new Insets(0, 0, 0, 0), 0, 0));
0246: }
0247:
0248: protected File getLastDirectoryUsed() {
0249:
0250: Object key;
0251: if (getDesignProperty() == null) {
0252: key = LAST_DIRECTORY_KEY_NO_PROJECT;
0253: } else {
0254: key = getDesignProperty().getDesignBean()
0255: .getDesignContext().getProject();
0256: }
0257: File dir = (File) lastDirectoryByProject.get(key);
0258: if (dir == null) {
0259: dir = getRelativeRootDirectory();
0260: lastDirectoryByProject.put(key, dir);
0261: }
0262: return dir;
0263: }
0264:
0265: protected void setLastDirectoryUsed(File dir) {
0266:
0267: Object key;
0268: if (getDesignProperty() == null) {
0269: key = LAST_DIRECTORY_KEY_NO_PROJECT;
0270: } else {
0271: key = getDesignProperty().getDesignBean()
0272: .getDesignContext().getProject();
0273: }
0274: lastDirectoryByProject.put(key, dir);
0275: }
0276:
0277: /**
0278: * Specified by PropertyChangeListener, for the JFileChooser
0279: */
0280: public void propertyChange(PropertyChangeEvent event) {
0281:
0282: if (event.getSource() == filePanel) {
0283: File file = filePanel.getSelectedFile();
0284: if (file == null) {
0285: file = filePanel.getCurrentDirectory();
0286: }
0287: processValueFile(file);
0288: ignoreValueTextFieldChanges = true;
0289: try {
0290: valueTextField.setText(propertyValue);
0291: } finally {
0292: ignoreValueTextFieldChanges = false;
0293: }
0294: }
0295: }
0296:
0297: /**
0298: * Specified by ActionListener, for the HTTPPanel TextField
0299: */
0300: public void actionPerformed(ActionEvent event) {
0301:
0302: if (event.getSource() == shortCutPanelMyProjectButton) {
0303: filePanel.setCurrentDirectory(getRelativeRootDirectory());
0304: return;
0305: }
0306: }
0307:
0308: /**
0309: * Specified by ChangeListener, for the tabs
0310: */
0311: public void stateChanged(ChangeEvent evt) {
0312:
0313: }
0314:
0315: protected DesignProperty getDesignProperty() {
0316:
0317: return liveProperty;
0318: }
0319:
0320: public void setDesignProperty(DesignProperty prop) {
0321:
0322: this .liveProperty = prop;
0323: if (prop != null) {
0324: this .liveContext = prop.getDesignBean().getDesignContext();
0325: }
0326: }
0327:
0328: public void setProperty(Node.Property prop) {
0329:
0330: this .property = prop;
0331: }
0332:
0333: public void setDesignContext(DesignContext context) {
0334:
0335: this .liveContext = context;
0336: }
0337:
0338: public void changedUpdate(DocumentEvent event) {
0339:
0340: if (event.getDocument() == httpPanel.textField.getDocument()) {
0341: httpTextFieldChanged();
0342: }
0343: if (event.getDocument() == valueTextField.getDocument()) {
0344: valueTextFieldChanged();
0345: }
0346: }
0347:
0348: public void insertUpdate(DocumentEvent event) {
0349:
0350: if (event.getDocument() == httpPanel.textField.getDocument()) {
0351: httpTextFieldChanged();
0352: }
0353: if (event.getDocument() == valueTextField.getDocument()) {
0354: valueTextFieldChanged();
0355: }
0356: }
0357:
0358: public void removeUpdate(DocumentEvent event) {
0359:
0360: if (event.getDocument() == httpPanel.textField.getDocument()) {
0361: httpTextFieldChanged();
0362: }
0363: if (event.getDocument() == valueTextField.getDocument()) {
0364: valueTextFieldChanged();
0365: }
0366: }
0367:
0368: public void httpTextFieldChanged() {
0369:
0370: processValueUri(httpPanel.textField.getText());
0371: ignoreValueTextFieldChanges = true;
0372: try {
0373: valueTextField.setText(propertyValue);
0374: } finally {
0375: ignoreValueTextFieldChanges = false;
0376: }
0377: }
0378:
0379: protected boolean ignoreValueTextFieldChanges;
0380:
0381: public void valueTextFieldChanged() {
0382:
0383: if (ignoreValueTextFieldChanges) {
0384: return;
0385: }
0386: processValueString(valueTextField.getText());
0387: }
0388:
0389: // Set the initial Property value to show in the Editor
0390:
0391: public void initialize() {
0392:
0393: if (!initialized) {
0394: filePanel = org.netbeans.modules.visualweb.extension.openide.awt.JFileChooser_RAVE
0395: .getJFileChooser();
0396: if (filePanel.getUI() instanceof WindowsFileChooserUI) {
0397: // IF anything goes wrong just ignore it and hope all goes well
0398: try {
0399: tweakWindowsFileChooserUI(filePanel,
0400: (WindowsFileChooserUI) filePanel.getUI());
0401: } catch (Throwable t) {
0402: // t.printStackTrace();
0403: }
0404: }
0405: filePanel.setControlButtonsAreShown(false);
0406: filePanel
0407: .setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
0408: // filePanel.addPropertyChangeListener(JFileChooser.DIRECTORY_CHANGED_PROPERTY, this);
0409: filePanel.addPropertyChangeListener(
0410: JFileChooser.SELECTED_FILE_CHANGED_PROPERTY, this );
0411: // filePanel.addPropertyChangeListener(JFileChooser.DIRECTORY_CHANGED_PROPERTY, this);
0412: tabs.add(filePanel, bundle.getMessage("file")); //NOI18N
0413:
0414: httpPanel = new HTTPPanel();
0415: tabs.add(httpPanel, bundle.getMessage("url")); //NOI18N
0416:
0417: tabs.addChangeListener(this );
0418: // Now initialize the panel with the current value
0419:
0420: String original = null;
0421: if (liveProperty == null) {
0422: if (property != null) {
0423: try {
0424: original = (String) property.getValue();
0425: } catch (Exception e) {
0426: throw new RuntimeException(e);
0427: }
0428: }
0429: } else {
0430: original = (String) liveProperty.getValue();
0431: }
0432:
0433: if (original == null || original.trim().length() == 0) {
0434: tabs.setSelectedComponent(filePanel);
0435: } else {
0436: tabs.setSelectedComponent(httpPanel);
0437: }
0438: httpPanel.textField.setText(original);
0439: httpTextFieldChanged();
0440:
0441: valueTextField.getDocument().addDocumentListener(this );
0442: httpPanel.textField.getDocument().addDocumentListener(this );
0443:
0444: File dir = getLastDirectoryUsed();
0445: filePanel.setCurrentDirectory(dir);
0446: initialized = true;
0447: }
0448: }
0449:
0450: JToggleButton shortCutPanelMyProjectButton;
0451:
0452: protected void tweakWindowsFileChooserUI(JFileChooser fileChooser,
0453: WindowsFileChooserUI ui) {
0454:
0455: File projectDirectory = getRelativeRootDirectory();
0456: if (projectDirectory == null) {
0457: return;
0458: }
0459: JToolBar shortCutPanel;
0460: try {
0461: Field shortCutPanelField = WindowsFileChooserUI.class
0462: .getDeclaredField("shortCutPanel"); // NOI18N
0463: boolean oldAccessibleState = shortCutPanelField
0464: .isAccessible();
0465: shortCutPanelField.setAccessible(true);
0466: shortCutPanel = (JToolBar) shortCutPanelField.get(ui);
0467: shortCutPanelField.setAccessible(false);
0468: } catch (Exception e) {
0469: // we can't do it for some reason, but its not important
0470: return;
0471: }
0472: if (shortCutPanel == null) {
0473: return;
0474: }
0475: FileSystemView fsv = fileChooser.getFileSystemView();
0476: if (fsv.isFileSystemRoot(projectDirectory)) {
0477: // Create special File wrapper for drive path
0478: projectDirectory = fsv.createFileObject(projectDirectory
0479: .getAbsolutePath());
0480: }
0481: String folderName = fsv.getSystemDisplayName(projectDirectory);
0482: int index = folderName.lastIndexOf(File.separatorChar);
0483: if (index >= 0 && index < folderName.length() - 1) {
0484: folderName = folderName.substring(index + 1);
0485: }
0486: boolean xp = false;
0487: try {
0488: Class clazz = Class
0489: .forName("com.sun.java.swing.plaf.windows.XPStyle"); // NOI18N
0490: Method method = clazz.getDeclaredMethod("getXP",
0491: new Class[0]); // NOI18N
0492: method.setAccessible(true);
0493: Object object = method.invoke(null, new Object[0]);
0494: method.setAccessible(false);
0495: xp = object != null;
0496: } catch (Exception e) {
0497: // e.printStackTrace();
0498: }
0499: Icon icon = null;
0500: if (xp) {
0501: Image image = loadImage("urlpanel_myproject.png",
0502: getClass()); //NOI18N
0503: icon = new ImageIcon(image, bundle.getMessage("myProject")); //NOI18N
0504: }
0505: if (icon == null) {
0506: icon = fsv.getSystemIcon(projectDirectory);
0507: folderName = bundle.getMessage("myProject");
0508: }
0509: final Dimension buttonSize = new Dimension(83, xp ? 69 : 54);
0510: shortCutPanelMyProjectButton = new JToggleButton(folderName,
0511: icon);
0512: if (xp) {
0513: shortCutPanelMyProjectButton.setIconTextGap(2);
0514: shortCutPanelMyProjectButton.setMargin(new Insets(2, 2, 2,
0515: 2));
0516: shortCutPanelMyProjectButton.setText("<html><center>" + // NOI18N
0517: bundle.getMessage("myProject") + //NOI18N
0518: "</center></html>"); // NOI18N
0519: } else {
0520: Color fgColor = new Color(UIManager.getColor(
0521: "List.selectionForeground").getRGB()); // NOI18N
0522: shortCutPanelMyProjectButton.setBackground(fileChooser
0523: .getBackground());
0524: shortCutPanelMyProjectButton.setForeground(fileChooser
0525: .getForeground());
0526: }
0527: shortCutPanelMyProjectButton
0528: .setHorizontalTextPosition(JToggleButton.CENTER);
0529: shortCutPanelMyProjectButton
0530: .setVerticalTextPosition(JToggleButton.BOTTOM);
0531: shortCutPanelMyProjectButton
0532: .setAlignmentX(JComponent.CENTER_ALIGNMENT);
0533: shortCutPanelMyProjectButton.setPreferredSize(buttonSize);
0534: // shortCutPanelMyProjectButton.setMaximumSize(buttonSize);
0535: shortCutPanelMyProjectButton.addActionListener(this );
0536: shortCutPanel.add(shortCutPanelMyProjectButton, 0);
0537: shortCutPanel.add(Box.createRigidArea(new Dimension(1, 1)), 1);
0538: Component components[] = shortCutPanel.getComponents();
0539: for (int i = 0; i < components.length; i++) {
0540: if (components[i] instanceof JToggleButton) {
0541: JToggleButton button = (JToggleButton) components[i];
0542: ButtonModel buttonModel = button.getModel();
0543: try {
0544: Field field = buttonModel.getClass()
0545: .getSuperclass().getDeclaredField("group"); // NOI18N
0546: field.setAccessible(true);
0547: ButtonGroup group = (ButtonGroup) field
0548: .get(buttonModel);
0549: field.setAccessible(false);
0550: if (group != null) {
0551: group.add(shortCutPanelMyProjectButton);
0552: break;
0553: }
0554: } catch (Exception e) {
0555: // e.printStackTrace();
0556: }
0557: }
0558: }
0559: }
0560:
0561: class HTTPPanel extends JPanel {
0562:
0563: JLabel httpLabel = new JLabel();
0564: JTextField textField = new JTextField();
0565:
0566: // Constructor for inner class
0567: HTTPPanel() {
0568: this .setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
0569: httpLabel.setText(bundle.getMessage("enterUrlHttp")); //NOI18N
0570: httpLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
0571: this .add(httpLabel);
0572: // textField.setMaximumSize(new Dimension(Integer.MAX_VALUE,
0573: // textField.getPreferredSize().height));
0574: textField.setAlignmentX(JTextField.LEFT_ALIGNMENT);
0575: textField.getAccessibleContext().setAccessibleName(
0576: org.openide.util.NbBundle
0577: .getMessage(URLPanel.class,
0578: "URL_TEXTFIELD_ACCESS_NAME"));
0579: textField.getAccessibleContext().setAccessibleDescription(
0580: org.openide.util.NbBundle
0581: .getMessage(URLPanel.class,
0582: "URL_TEXTFIELD_ACCESS_DESC"));
0583: this .add(textField);
0584: }
0585: }
0586:
0587: // Called when the user enters or selects a file url
0588:
0589: class RadioListener implements ActionListener {
0590:
0591: public void actionPerformed(ActionEvent e) {
0592: }
0593: }
0594:
0595: protected File relativeRootDirectoryCache;
0596: protected boolean relativeRootDirectoryCacheSet;
0597:
0598: /**
0599: * Return null if I can't figure it out.
0600: * @return
0601: */
0602: protected File getRelativeRootDirectory() {
0603:
0604: if (!relativeRootDirectoryCacheSet) {
0605: relativeRootDirectoryCache = getRelativeRootDirectoryImp();
0606: relativeRootDirectoryCacheSet = true;
0607: if (relativeDirectoryCache != null
0608: && relativeRootDirectoryCache != null) {
0609: // If root and relative are same path, then make them identical objects
0610: if (relativeDirectoryCache.getPath().equals(
0611: relativeRootDirectoryCache.getPath())) {
0612: relativeRootDirectoryCache = relativeDirectoryCache;
0613: }
0614: }
0615: }
0616: return relativeRootDirectoryCache;
0617: }
0618:
0619: protected File relativeDirectoryCache;
0620: protected boolean relativeDirectoryCacheSet;
0621:
0622: /**
0623: * Return null if I can't figure it out.
0624: * @return
0625: */
0626: protected File getRelativeDirectory() {
0627:
0628: if (!relativeDirectoryCacheSet) {
0629: relativeDirectoryCache = getRelativeDirectoryImp();
0630: relativeDirectoryCacheSet = true;
0631: }
0632: return relativeDirectoryCache;
0633: }
0634:
0635: protected File getFileFromUrl(URL url) {
0636:
0637: File result = null;
0638: if (url != null && "file".equals(url.getProtocol())) { // NOI18N
0639: if (url.getAuthority() == null) {
0640: result = new File(url.getPath());
0641: } else {
0642: result = new File(url.getAuthority(), url.getPath());
0643: }
0644: }
0645: if (result != null && result.isFile()) {
0646: result = result.getParentFile();
0647: }
0648: return result;
0649: }
0650:
0651: protected File getRelativeRootDirectoryImp() {
0652:
0653: /*
0654: * I need to be able to figure out
0655: * 1) if a file is contained withint a project's web tree
0656: * 2) if contained within a project's web tree, give me its relative URI
0657: *
0658: * HACK
0659: * Here I am doing 1) in a VERY HACKED way.
0660: * I end up doing 2) by combining the result of this with getRelativeDirectory().
0661: */
0662: File rootFile = getRelativeDirectory();
0663: if (rootFile == null) {
0664: return null;
0665: }
0666: try {
0667: while (rootFile != null) {
0668: boolean isProjectRoot = isProjectRootFolder(rootFile);
0669: if (isProjectRoot) {
0670: break;
0671: }
0672: rootFile = rootFile.getParentFile();
0673: }
0674: if (rootFile == null) {
0675: return getRelativeDirectory();
0676: }
0677: if (liveContext == null) {
0678: // HACK BAD - what happens if src not proper folder
0679: rootFile = new File(rootFile, "src/web"); // NOI18N
0680: } else {
0681: // HACK
0682: String sourcePath = (String) liveContext.getProject()
0683: .getProjectData("sourceRoot"); // NOI18N
0684: rootFile = new File(rootFile, sourcePath);
0685: rootFile = new File(rootFile, "web"); // NOI18N
0686: }
0687: return rootFile;
0688: } catch (Exception e) {
0689: return getRelativeDirectory();
0690: }
0691: }
0692:
0693: /* EAT:
0694: * Method cloned from com.sun.rave.project.model.Project
0695: * HACK
0696: * Determine whether this directory appears to be a project root folder
0697: * @param f potential project folder
0698: * @return true if the directory appears to contain "well known" project artifacts
0699: * otherwise false.
0700: */
0701: public boolean isProjectRootFolder(File f) {
0702: final String PROJECT_DATA = "project-data"; // NOI18N
0703: final String FILE_EXTENSION = "prj"; // NOI18N
0704: final String PROJECT_FILE = "project." + FILE_EXTENSION; // NOI18N
0705:
0706: if (!f.isDirectory()) {
0707: return false;
0708: }
0709: File subF = new File(f, PROJECT_DATA);
0710: if (!subF.exists()) {
0711: return false;
0712: }
0713: subF = new File(subF, PROJECT_FILE);
0714: if (!subF.exists()) {
0715: return false;
0716: }
0717: return true;
0718: }
0719:
0720: public void setRelativeRootDirectory(File file) {
0721:
0722: relativeRootDirectoryCache = file;
0723: relativeRootDirectoryCacheSet = true;
0724: }
0725:
0726: protected File getRelativeDirectoryImp() {
0727:
0728: if (liveContext == null) {
0729: return null;
0730: }
0731: URL url = liveContext.resolveResource(""); // NOI18N
0732: File contextFile = getFileFromUrl(url);
0733: try {
0734: contextFile = contextFile.getCanonicalFile();
0735: } catch (IOException e) {
0736: return null;
0737: }
0738: return contextFile;
0739: }
0740:
0741: public void setRelativeDirectory(File file) {
0742:
0743: relativeDirectoryCache = file;
0744: if (file != null && file.isFile()) {
0745: relativeDirectoryCache = relativeDirectoryCache
0746: .getParentFile();
0747: }
0748: relativeDirectoryCacheSet = true;
0749: }
0750:
0751: public Object getPropertyValue() throws IllegalStateException {
0752:
0753: try {
0754: Object result = getPropertyValueImp();
0755: return result;
0756: } catch (IllegalStateException e) {
0757: JOptionPane.showMessageDialog(this , e.getMessage(), bundle
0758: .getMessage("urlPanelErroDialogTitle"), //NOI18N
0759: JOptionPane.WARNING_MESSAGE);
0760: throw e;
0761: }
0762: }
0763:
0764: protected String propertyValue;
0765:
0766: protected Object getPropertyValueImp() {
0767:
0768: if (delayedFileToAdd != null) {
0769: if (!delayedFileToAdd.exists()) {
0770: throw new IllegalStateException(bundle
0771: .getMessage("fileSpecifiedNotExist")); //NOI18N
0772: }
0773: try {
0774: // XXX #6336303 Making image (and also Css style) property context-relative,
0775: // i.e. all such files are added into resources.
0776: // TODO Missing convenient API(designtime/insync) to add context-relative resources.
0777: // For now basically copied the impl from UrlPropertyPanel -> propertyeditors).
0778: DesignProject designProject = liveContext.getProject();
0779: URI uri = new URI("web/resources/"
0780: + encodeUrl(delayedFileToAdd.getName())); // NOI18N
0781: if (designProject.getResourceFile(uri) == null) {
0782: designProject.addResource(delayedFileToAdd.toURI()
0783: .toURL(), uri);
0784: }
0785: propertyValue = "/resources/"
0786: + delayedFileToAdd.getName(); // NOI18N
0787: } catch (MalformedURLException mue) {
0788: ErrorManager.getDefault().notify(
0789: ErrorManager.INFORMATIONAL, mue);
0790: } catch (IOException ioe) {
0791: ErrorManager.getDefault().notify(
0792: ErrorManager.INFORMATIONAL, ioe);
0793: } catch (URISyntaxException use) {
0794: ErrorManager.getDefault().notify(
0795: ErrorManager.INFORMATIONAL, use);
0796: }
0797: }
0798: if (delayedSetLastDirectoryUsed != null) {
0799: setLastDirectoryUsed(delayedSetLastDirectoryUsed);
0800: }
0801: return propertyValue;
0802: }
0803:
0804: // XXX Copied from com.sun.rave.propertyeditors.UrlPropertyEditor!
0805: /**
0806: * Convert a file system path to a URL by converting unsafe characters into
0807: * numeric character entity references. The unsafe characters are listed in
0808: * in the IETF specification of URLs
0809: * (<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>). Safe URL
0810: * characters are all printable ASCII characters, with the exception of the
0811: * space characters, '#', <', '>', '%', '[', ']', '{', '}', and '~'. This
0812: * method differs from {@link java.net.URLEncoder.encode(String)}, in that
0813: * it is intended for encoding the path portion of a URL, not the query
0814: * string.
0815: */
0816: private static String encodeUrl(String url) {
0817: if (url == null || url.length() == 0)
0818: return url;
0819: StringBuffer buffer = new StringBuffer();
0820: String anchor = null;
0821: int index = url.lastIndexOf('#');
0822: if (index > 0) {
0823: anchor = url.substring(index + 1);
0824: url = url.substring(0, index);
0825: }
0826: char[] chars = url.toCharArray();
0827: for (int i = 0; i < chars.length; i++) {
0828: if (chars[i] <= '\u0020') {
0829: buffer.append('%');
0830: buffer.append(Integer.toHexString((int) chars[i]));
0831: } else {
0832: switch (chars[i]) {
0833: case '\u0009': // Tab
0834: buffer.append("%09");
0835: break;
0836: case '\u0020': // Space
0837: buffer.append("%20");
0838: break;
0839: case '#':
0840: buffer.append("%23");
0841: break;
0842: case '%':
0843: buffer.append("%25");
0844: break;
0845: case '<':
0846: buffer.append("%3C");
0847: break;
0848: case '>':
0849: buffer.append("%3E");
0850: break;
0851: case '[':
0852: buffer.append("%5B");
0853: break;
0854: case ']':
0855: buffer.append("%5D");
0856: break;
0857: case '{':
0858: buffer.append("%7B");
0859: break;
0860: case '}':
0861: buffer.append("%7D");
0862: break;
0863: case '~':
0864: buffer.append("%7E");
0865: break;
0866: default:
0867: buffer.append(chars[i]);
0868: }
0869: }
0870: }
0871: if (anchor != null) {
0872: buffer.append('#');
0873: buffer.append(anchor);
0874: }
0875: if (buffer.length() == url.length())
0876: return url;
0877: return buffer.toString();
0878: }
0879:
0880: protected File delayedFileToAdd;
0881: protected File delayedSetLastDirectoryUsed;
0882:
0883: protected void processValueFile(File file) {
0884:
0885: if (file.isAbsolute()) {
0886: try {
0887: file = file.getCanonicalFile();
0888: String fileAbsolutePath = file.toURI().toString();
0889: String rootAbsolutePath;
0890: if (getRelativeRootDirectory() == null) {
0891: rootAbsolutePath = null;
0892: } else {
0893: rootAbsolutePath = getRelativeRootDirectory()
0894: .toURI().toString();
0895: }
0896: if (rootAbsolutePath != null
0897: && fileAbsolutePath
0898: .startsWith(rootAbsolutePath)) {
0899: // file is inside project tree
0900: linkButton.setSelected(true);
0901: linkButton.setEnabled(true);
0902: copyButton.setEnabled(false);
0903: delayedFileToAdd = null;
0904: delayedSetLastDirectoryUsed = file.getParentFile();
0905: propertyValue = fileAbsolutePath
0906: .substring(rootAbsolutePath.length());
0907: if (getRelativeRootDirectory() != getRelativeDirectory()) {
0908: // make URI relative to directory in which the doc being modified is in
0909: File fileDir = file;
0910: if (file.isFile()) {
0911: fileDir = file.getParentFile();
0912: }
0913: ArrayList filePathList = getPathList(fileDir,
0914: getRelativeRootDirectory());
0915: ArrayList relativePathList = getPathList(
0916: getRelativeDirectory(),
0917: getRelativeRootDirectory());
0918: int index = 0;
0919: // find the first non matching sub dir
0920: for (; index < filePathList.size()
0921: && index < relativePathList.size(); index++) {
0922: if (!filePathList.get(index).equals(
0923: relativePathList.get(index))) {
0924: break;
0925: }
0926: }
0927: StringBuffer stringBuffer = new StringBuffer();
0928: // create a file that goes up to match found
0929: for (int i = index; i < relativePathList.size(); i++) {
0930: stringBuffer.append("../"); // NOI18N
0931: }
0932: // create a file that goes down from match found
0933: for (int i = index; i < filePathList.size(); i++) {
0934: stringBuffer.append(filePathList.get(i));
0935: stringBuffer.append("/"); // NOI18N
0936: }
0937: if (file.isFile()) {
0938: stringBuffer.append(file.getName());
0939: }
0940: propertyValue = stringBuffer.toString();
0941: }
0942: return;
0943: } else {
0944: // file is somewhere else on local drive
0945: copyButton.setSelected(true);
0946: copyButton.setEnabled(true);
0947: linkButton.setEnabled(false);
0948: delayedFileToAdd = file;
0949: delayedSetLastDirectoryUsed = file.getParentFile();
0950: propertyValue = file.getPath();
0951: return;
0952: }
0953: } catch (IOException e) {
0954: }
0955: }
0956: processValueUri(file.getPath());
0957: }
0958:
0959: /*
0960: * Return list of sub dirs between from and to.
0961: * Assume from is inside to.
0962: */
0963: protected ArrayList getPathList(File from, File to) {
0964:
0965: String toPath = to.getPath();
0966: ArrayList result = new ArrayList();
0967: while (!from.getPath().equals(toPath)) {
0968: File parent = from.getParentFile();
0969: String subDir = from.getPath()
0970: .substring(
0971: parent.getPath().length()
0972: + File.separator.length());
0973: result.add(subDir);
0974: from = parent;
0975: }
0976: Collections.reverse(result);
0977: return result;
0978: }
0979:
0980: protected void processValueString(String valueString) {
0981:
0982: File file = new File(valueString);
0983: // can we treat valueString a file ?
0984: try {
0985: // is it a value file specification
0986: // dont keep the value since getCanonicalPath() forces an absolute path
0987: file.getCanonicalPath();
0988: // will only fall through if the file name was ok
0989: processValueFile(file);
0990: return;
0991: } catch (IOException e) {
0992: }
0993: processValueUri(valueString);
0994: }
0995:
0996: protected void processValueUri(String uriString) {
0997:
0998: delayedFileToAdd = null;
0999: delayedSetLastDirectoryUsed = null;
1000: linkButton.setSelected(true);
1001: linkButton.setEnabled(true);
1002: copyButton.setEnabled(false);
1003: propertyValue = uriString.replace('\\', '/');
1004: }
1005:
1006: public void customizerApply() {
1007:
1008: liveProperty.setValue(getPropertyValue());
1009: }
1010:
1011: }
|