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