http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/CacheFolder.java ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/CacheFolder.java b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/CacheFolder.java new file mode 100644 index 0000000..ea01606 --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/CacheFolder.java @@ -0,0 +1,269 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.jackpot30.remotingapi; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; +import org.openide.modules.Places; +import org.openide.util.Exceptions; +import org.openide.util.RequestProcessor; + +/** + * + * @author Tomas Zezula + */ +public final class CacheFolder { + + private static final Logger LOG = Logger.getLogger(CacheFolder.class.getName()); + private static final RequestProcessor RP = new RequestProcessor(CacheFolder.class.getName(), 1, false, false); + private static final RequestProcessor.Task SAVER = RP.create(new Saver()); + private static final int SLIDING_WINDOW = 500; + + private static final String SEGMENTS_FILE = "segments"; //NOI18N + private static final String SLICE_PREFIX = "s"; //NOI18N + + //@GuardedBy("CacheFolder.class") + private static FileObject cacheFolder; + //@GuardedBy("CacheFolder.class") + private static Properties segments; + //@GuardedBy("CacheFolder.class") + private static Map<String, String> invertedSegments; + //@GuardedBy("CacheFolder.class") + private static int index = 0; + + + //@NotThreadSafe + @org.netbeans.api.annotations.common.SuppressWarnings( + value="LI_LAZY_INIT_UPDATE_STATIC" + /*,justification="Caller already holds a monitor"*/) + private static void loadSegments(FileObject folder) throws IOException { + assert Thread.holdsLock(CacheFolder.class); + if (segments == null) { + assert folder != null; + segments = new Properties (); + invertedSegments = new HashMap<String,String> (); + final FileObject segmentsFile = folder.getFileObject(SEGMENTS_FILE); + if (segmentsFile!=null) { + final InputStream in = segmentsFile.getInputStream(); + try { + segments.load (in); + } finally { + in.close(); + } + } + for (Map.Entry entry : segments.entrySet()) { + String segment = (String) entry.getKey(); + String root = (String) entry.getValue(); + invertedSegments.put(root,segment); + try { + index = Math.max (index,Integer.parseInt(segment.substring(SLICE_PREFIX.length()))); + } catch (NumberFormatException nfe) { + LOG.log(Level.FINE, null, nfe); + } + } + } + } + + + private static void storeSegments(FileObject folder) throws IOException { + assert Thread.holdsLock(CacheFolder.class); + assert folder != null; + //It's safer to use FileUtil.createData(File) than FileUtil.createData(FileObject, String) + //see issue #173094 + final File _file = FileUtil.toFile(folder); + assert _file != null; + final FileObject segmentsFile = FileUtil.createData(new File(_file, SEGMENTS_FILE)); + final OutputStream out = segmentsFile.getOutputStream(); + try { + segments.store(out,null); + } finally { + out.close(); + } + } + + public static synchronized URL getSourceRootForDataFolder (final FileObject dataFolder) { + final FileObject segFolder = dataFolder.getParent(); + if (segFolder == null || !segFolder.equals(cacheFolder)) { + return null; + } + String source = segments.getProperty(dataFolder.getName()); + if (source != null) { + try { + return new URL (source); + } catch (IOException ioe) { + LOG.log(Level.FINE, null, ioe); + } + } + return null; + } + + public static FileObject getDataFolder (final URL root) throws IOException { + return getDataFolder(root, false); + } + + public static FileObject getDataFolder (final URL root, final boolean onlyIfAlreadyExists) throws IOException { + final String rootName = root.toExternalForm(); + final FileObject _cacheFolder = getCacheFolder(); + String slice; + synchronized (CacheFolder.class) { + loadSegments(_cacheFolder); + slice = invertedSegments.get (rootName); + if (slice == null) { + if (onlyIfAlreadyExists) { + return null; + } + slice = SLICE_PREFIX + (++index); + while (segments.getProperty(slice) != null) { + slice = SLICE_PREFIX + (++index); + } + segments.put (slice,rootName); + invertedSegments.put(rootName, slice); + SAVER.schedule(SLIDING_WINDOW); + } + } + assert slice != null; + if (onlyIfAlreadyExists) { + return cacheFolder.getFileObject(slice); + } else { + return FileUtil.createFolder(_cacheFolder, slice); + } + } + + public static synchronized Iterable<? extends FileObject> findRootsWithCacheUnderFolder(FileObject folder) throws IOException { + URL folderURL = folder.toURL(); + String prefix = folderURL.toExternalForm(); + final FileObject _cacheFolder = getCacheFolder(); + List<FileObject> result = new LinkedList<FileObject>(); + loadSegments(_cacheFolder); + for (Entry<String, String> e : invertedSegments.entrySet()) { + if (e.getKey().startsWith(prefix)) { + FileObject fo = URLMapper.findFileObject(new URL(e.getKey())); + + if (fo != null) { + result.add(fo); + } + } + } + + return result; + } + + public static synchronized FileObject getCacheFolder () { + if (cacheFolder == null) { + File cache = Places.getCacheSubdirectory("index"); // NOI18N + if (!cache.isDirectory()) { + throw new IllegalStateException("Indices cache folder " + cache.getAbsolutePath() + " is not a folder"); //NOI18N + } + if (!cache.canRead()) { + throw new IllegalStateException("Can't read from indices cache folder " + cache.getAbsolutePath()); //NOI18N + } + if (!cache.canWrite()) { + throw new IllegalStateException("Can't write to indices cache folder " + cache.getAbsolutePath()); //NOI18N + } + + cacheFolder = FileUtil.toFileObject(cache); + if (cacheFolder == null) { + throw new IllegalStateException("Can't convert indices cache folder " + cache.getAbsolutePath() + " to FileObject"); //NOI18N + } + } + return cacheFolder; + } + + + /** + * Only for unit tests! It's used also by CslTestBase, which is not in the + * same package, hence the public keyword. + * + */ + public static void setCacheFolder (final FileObject folder) { + SAVER.schedule(0); + SAVER.waitFinished(); + synchronized (CacheFolder.class) { + assert folder != null && folder.canRead() && folder.canWrite(); + cacheFolder = folder; + segments = null; + invertedSegments = null; + index = 0; + } + } + + private CacheFolder() { + // no-op + } + + private static class Saver implements Runnable { + @Override + public void run() { + try { + final FileObject cf = getCacheFolder(); + // #170182 - preventing filesystem events being fired from under the CacheFolder.class lock + cf.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { + @Override + public void run() throws IOException { + synchronized (CacheFolder.class) { + if (segments == null) return ; + storeSegments(cf); + } + } + }); + } catch (IOException ioe) { + Exceptions.printStackTrace(ioe); + } + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties new file mode 100644 index 0000000..1c81565 --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties @@ -0,0 +1,53 @@ +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2009-2017 Oracle and/or its affiliates. All rights reserved. +# +# Oracle and Java are registered trademarks of Oracle and/or its affiliates. +# Other names may be trademarks of their respective owners. +# +# The contents of this file are subject to the terms of either the GNU +# General Public License Version 2 only ("GPL") or the Common +# Development and Distribution License("CDDL") (collectively, the +# "License"). You may not use this file except in compliance with the +# License. You can obtain a copy of the License at +# http://www.netbeans.org/cddl-gplv2.html +# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the +# specific language governing permissions and limitations under the +# License. When distributing the software, include this License Header +# Notice in each file and include the License file at +# nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the GPL Version 2 section of the License file that +# accompanied this code. If applicable, add the following below the +# License Header, with the fields enclosed by brackets [] replaced by +# your own identifying information: +# "Portions Copyrighted [year] [name of copyright owner]" +# +# Contributor(s): +# +# The Original Software is NetBeans. The Initial Developer of the Original +# Software is Sun Microsystems, Inc. Portions Copyright 2009-2010 Sun +# Microsystems, Inc. All Rights Reserved. +# +# If you wish your version of this file to be governed by only the CDDL +# or only the GPL Version 2, indicate your decision by adding +# "[Contributor] elects to include this software in this distribution +# under the [CDDL or GPL Version 2] license." If you do not indicate a +# single choice of license, a recipient has the option to distribute +# your version of this file under either the CDDL, the GPL Version 2 or +# to extend the choice of license to its licensees as provided above. +# However, if you add GPL Version 2 code and therefore, elected the GPL +# Version 2 license, then the option applies only if the new code is +# made subject to such option by the copyright holder. +AdvancedOption_DisplayName_Index=Jackpot 3.0 Indices +AdvancedOption_Keywords_Index=index indices jackpot +CustomizeRemoteIndex.indexURLLabel.text=Index URL: +CustomizeRemoteIndex.indexURL.text= +CustomizeRemoteIndex.jLabel1.text=Subindex: +CustomizeRemoteIndex.folderLabel.text=&Folder: +CustomizeRemoteIndex.folderChooser.text=Browse +CustomizeRemoteIndex.folder.text= +IndexPanel.addButton.text=Add Mapping +IndexPanel.removeButton.text=Remove Mapping +IndexPanel.editButton.text=Edit Mapping +IndexPanel.synchronizeOffline.text=Synchronize Offline http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.form ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.form b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.form new file mode 100644 index 0000000..46368e3 --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.form @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <NonVisualComponents> + <Component class="javax.swing.ButtonGroup" name="buttonGroup1"> + </Component> + </NonVisualComponents> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo"> + <EmptyBorder bottom="12" left="12" right="12" top="12"/> + </Border> + </Property> + </Properties> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,53,0,0,2,-37"/> + </AuxValues> + + <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> + <SubComponents> + <Container class="javax.swing.JPanel" name="folderPanel"> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> + <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> + </Constraint> + </Constraints> + + <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> + <SubComponents> + <Component class="javax.swing.JLabel" name="folderLabel"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="CustomizeRemoteIndex.folderLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> + <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="6" anchor="17" weightX="0.0" weightY="0.0"/> + </Constraint> + </Constraints> + </Component> + <Component class="javax.swing.JButton" name="folderChooser"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="CustomizeRemoteIndex.folderChooser.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="folderChooserActionPerformed"/> + </Events> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> + <GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="6" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> + </Constraint> + </Constraints> + </Component> + <Component class="javax.swing.JTextField" name="folder"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="CustomizeRemoteIndex.folder.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> + <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/> + </Constraint> + </Constraints> + </Component> + </SubComponents> + </Container> + <Component class="javax.swing.JTextArea" name="indexInfo"> + <Properties> + <Property name="columns" type="int" value="20"/> + <Property name="editable" type="boolean" value="false"/> + <Property name="rows" type="int" value="5"/> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="null"/> + </Property> + </Properties> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> + <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/> + </Constraint> + </Constraints> + </Component> + <Container class="javax.swing.JPanel" name="remoteIndexPanel"> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> + <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/> + </Constraint> + </Constraints> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="12" pref="12" max="12" attributes="0"/> + <Component id="jLabel1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="subIndex" pref="589" max="32767" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <Component id="indexURLLabel" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="indexURL" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="indexURLLabel" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="indexURL" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="subIndex" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JTextField" name="indexURL"> + <Properties> + <Property name="columns" type="int" value="40"/> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="CustomizeRemoteIndex.indexURL.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="indexURLLabel"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="CustomizeRemoteIndex.indexURLLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JComboBox" name="subIndex"> + <Properties> + <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> + <StringArray count="0"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="subIndexActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JLabel" name="jLabel1"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="CustomizeRemoteIndex.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + </SubComponents> +</Form> http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.java ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.java b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.java new file mode 100644 index 0000000..7dff967 --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/CustomizeRemoteIndex.java @@ -0,0 +1,616 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010-2011 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2010-2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.jackpot30.remotingapi.options; + +import java.awt.Component; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JList; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.netbeans.modules.jackpot30.remoting.api.RemoteIndex; +import org.netbeans.modules.jackpot30.remoting.api.WebUtilities; +import org.openide.NotificationLineSupport; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.URLMapper; +import org.openide.util.RequestProcessor; + +/** + * + * @author lahvac + */ +public class CustomizeRemoteIndex extends javax.swing.JPanel { + + private final JButton okButton; + + public CustomizeRemoteIndex(JButton okButton) { + this.okButton = okButton; + initComponents(); + DocumentListener updateErrorsListener = new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + validateIndexSelection(); + updateErrors(); + } + public void removeUpdate(DocumentEvent e) { + validateIndexSelection(); + updateErrors(); + } + public void changedUpdate(DocumentEvent e) {} + }; + folder.getDocument().addDocumentListener(updateErrorsListener); + indexURL.getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + indexURLUpdated(); + } + public void removeUpdate(DocumentEvent e) { + indexURLUpdated(); + } + public void changedUpdate(DocumentEvent e) { + } + }); + indexInfo.setFont(UIManager.getFont("Label.font")); + indexInfo.setBackground(UIManager.getColor("Label.background")); + indexInfo.setDisabledTextColor(UIManager.getColor("Label.foreground")); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + + buttonGroup1 = new javax.swing.ButtonGroup(); + folderPanel = new javax.swing.JPanel(); + folderLabel = new javax.swing.JLabel(); + folderChooser = new javax.swing.JButton(); + folder = new javax.swing.JTextField(); + indexInfo = new javax.swing.JTextArea(); + remoteIndexPanel = new javax.swing.JPanel(); + indexURL = new javax.swing.JTextField(); + indexURLLabel = new javax.swing.JLabel(); + subIndex = new javax.swing.JComboBox(); + jLabel1 = new javax.swing.JLabel(); + + setBorder(javax.swing.BorderFactory.createEmptyBorder(12, 12, 12, 12)); + setLayout(new java.awt.GridBagLayout()); + + folderPanel.setLayout(new java.awt.GridBagLayout()); + + org.openide.awt.Mnemonics.setLocalizedText(folderLabel, org.openide.util.NbBundle.getMessage(CustomizeRemoteIndex.class, "CustomizeRemoteIndex.folderLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 6); + folderPanel.add(folderLabel, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(folderChooser, org.openide.util.NbBundle.getMessage(CustomizeRemoteIndex.class, "CustomizeRemoteIndex.folderChooser.text")); // NOI18N + folderChooser.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + folderChooserActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 0); + folderPanel.add(folderChooser, gridBagConstraints); + + folder.setText(org.openide.util.NbBundle.getMessage(CustomizeRemoteIndex.class, "CustomizeRemoteIndex.folder.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + folderPanel.add(folder, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.weightx = 1.0; + add(folderPanel, gridBagConstraints); + + indexInfo.setColumns(20); + indexInfo.setEditable(false); + indexInfo.setRows(5); + indexInfo.setBorder(null); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); + add(indexInfo, gridBagConstraints); + + indexURL.setColumns(40); + indexURL.setText(org.openide.util.NbBundle.getMessage(CustomizeRemoteIndex.class, "CustomizeRemoteIndex.indexURL.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(indexURLLabel, org.openide.util.NbBundle.getMessage(CustomizeRemoteIndex.class, "CustomizeRemoteIndex.indexURLLabel.text")); // NOI18N + + subIndex.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + subIndexActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(CustomizeRemoteIndex.class, "CustomizeRemoteIndex.jLabel1.text")); // NOI18N + + javax.swing.GroupLayout remoteIndexPanelLayout = new javax.swing.GroupLayout(remoteIndexPanel); + remoteIndexPanel.setLayout(remoteIndexPanelLayout); + remoteIndexPanelLayout.setHorizontalGroup( + remoteIndexPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(remoteIndexPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(remoteIndexPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(remoteIndexPanelLayout.createSequentialGroup() + .addGap(12, 12, 12) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(subIndex, 0, 589, Short.MAX_VALUE)) + .addGroup(remoteIndexPanelLayout.createSequentialGroup() + .addComponent(indexURLLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(indexURL, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + remoteIndexPanelLayout.setVerticalGroup( + remoteIndexPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(remoteIndexPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(remoteIndexPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(indexURLLabel) + .addComponent(indexURL, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(remoteIndexPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(subIndex, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + add(remoteIndexPanel, gridBagConstraints); + }// </editor-fold>//GEN-END:initComponents + + private void folderChooserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_folderChooserActionPerformed + showFileChooser(folder); +}//GEN-LAST:event_folderChooserActionPerformed + + private void subIndexActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_subIndexActionPerformed + subindexSelectionUpdated(); + }//GEN-LAST:event_subIndexActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JTextField folder; + private javax.swing.JButton folderChooser; + private javax.swing.JLabel folderLabel; + private javax.swing.JPanel folderPanel; + private javax.swing.JTextArea indexInfo; + private javax.swing.JTextField indexURL; + private javax.swing.JLabel indexURLLabel; + private javax.swing.JLabel jLabel1; + private javax.swing.JPanel remoteIndexPanel; + private javax.swing.JComboBox subIndex; + // End of variables declaration//GEN-END:variables + + private void showFileChooser(JTextField folder) { + JFileChooser c = new JFileChooser(); + + c.setSelectedFile(new File(folder.getText())); + c.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + c.setMultiSelectionEnabled(false); + c.setApproveButtonText("Select"); + + if (c.showDialog(this, null) == JFileChooser.APPROVE_OPTION) { + folder.setText(c.getSelectedFile().getAbsolutePath()); + } +// +// URL result = FSChooser.select("Select folder", "Select", Utils.fromDisplayName(folder.getText())); +// +// if (result != null) { +// folder.setText(Utils.toDisplayName(result)); +// } + } + + private String tempSubIndexSelection; + public void setIndex(RemoteIndex index) { + URL localFolder = index.getLocalFolder(); + folder.setText(localFolder != null ? Utils.toDisplayName(localFolder) : ""); + indexURL.setText(index.remote.toExternalForm()); + tempSubIndexSelection = index.remoteSegment; + } + + private String getSubIndexSelectedItem() { + String sel = (String) subIndex.getSelectedItem(); + + if (sel == null) { + return tempSubIndexSelection; + } + + return sel; + } + + public RemoteIndex getIndex() { + try { + String folderText = folder.getText(); + return RemoteIndex.create(!folderText.isEmpty() ? Utils.fromDisplayName(folderText) : null, new URL(indexURL.getText()), getSubIndexSelectedItem()); + } catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + } + + private NotificationLineSupport notificationSupport; + + public void setNotificationSupport(NotificationLineSupport notificationSupport) { + this.notificationSupport = notificationSupport; + } + + private void updateErrors() { + notificationSupport.clearMessages(); + + String folderText = folder.getText(); + + if (!folderText.isEmpty()) { + URL folderURL = Utils.fromDisplayName(folderText); + FileObject folder = URLMapper.findFileObject(folderURL); + + if (folder == null) { + notificationSupport.setErrorMessage("Specified directory does not exist."); + okButton.setEnabled(false); + return; + } + + if (!folder.isFolder()) { + notificationSupport.setErrorMessage("Specified directory is not directory."); + okButton.setEnabled(false); + return ; + } + } + + if (checkingIndexURL.get()) { + notificationSupport.setInformationMessage("Checking index URL"); + okButton.setEnabled(false); + return; + } + + if (checkingIndexAgainstFolder.get()) { + notificationSupport.setInformationMessage("Checking local folder against the index"); + } + + String urlError = checkingIndexURLError.get(); + + if (urlError != null) { + notificationSupport.setErrorMessage(urlError); + okButton.setEnabled(false); + return; + } + + String urlWarning = checkingIndexURLWarning.get(); + + if (urlWarning != null) { + notificationSupport.setWarningMessage(urlWarning); + } + + okButton.setEnabled(true); + } + + private final AtomicBoolean checkingIndexURL = new AtomicBoolean(); + private final AtomicReference<String> checkingIndexURLContentCopy = new AtomicReference<String>(); + private final AtomicReference<String> checkingIndexURLError = new AtomicReference<String>(); + private final AtomicReference<String> checkingIndexURLWarning = new AtomicReference<String>(); + private final AtomicReference<Collection<? extends String>> indexRandomFiles = new AtomicReference<Collection<? extends String>>(); + + private void indexURLUpdated() { + indexRandomFiles.set(null); + checkingIndexURLContentCopy.set(indexURL.getText()); + urlCheckerTask.cancel(); + urlCheckerTask.schedule(50); + } + + private static final RequestProcessor WORKER = new RequestProcessor(CustomizeRemoteIndex.class.getName(), 1, false, false); + private final RequestProcessor.Task urlCheckerTask = WORKER.create(new Runnable() { + + public void run() { + checkingIndexURL.set(true); + checkingIndexURLError.set(null); + indexRandomFiles.set(null); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + updateErrors(); + } + }); + + String urlText = checkingIndexURLContentCopy.get(); + Collection<? extends String> subindices = null; + + try { + URL url = new URL(urlText); + + if (!url.getPath().endsWith("/")) + url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getPath() + "/" + (url.getQuery() != null ? "?" + url.getQuery() : "")); + + subindices = new ArrayList<String>(WebUtilities.requestStringArrayResponse(url.toURI().resolve("list"), new AtomicBoolean())); + + for (Iterator<? extends String> it = subindices.iterator(); it.hasNext();) { + String idx = it.next(); + if (idx.trim().isEmpty() || !idx.contains(":")) it.remove(); + } + + if (subindices.isEmpty()) { + checkingIndexURLError.set("Not an index."); + } + } catch (URISyntaxException ex) { + checkingIndexURLError.set(ex.getLocalizedMessage()); + } catch (MalformedURLException ex) { + checkingIndexURLError.set(ex.getLocalizedMessage()); + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) {//#6541019 + checkingIndexURLError.set("Invalid URL"); + } + + checkingIndexURL.set(false); + + final Collection<? extends String> subindicesFinal = subindices; + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + updateErrors(); + + if (subindicesFinal == null || subindicesFinal.isEmpty()) return; + + DefaultComboBoxModel model = (DefaultComboBoxModel) subIndex.getModel(); + String selected = getSubIndexSelectedItem(); + + tempSubIndexSelection = null; + model.removeAllElements(); + + boolean containsSelection = false; + Map<String, String> displayNames = new HashMap<String, String>(); + + for (String subindex : subindicesFinal) { + String[] subindexSplit = subindex.split(":", 2); + if (subindexSplit[0].equals(selected)) containsSelection = true; + model.addElement(subindexSplit[0]); + displayNames.put(subindexSplit[0], subindexSplit[1]); + } + + if (containsSelection) { + model.setSelectedItem(selected); + } + + subindexSelectionUpdated(); + subIndex.setRenderer(new RendererImpl(displayNames)); + } + }); + } + }); + + private final AtomicBoolean checkingIndexAgainstFolder = new AtomicBoolean(); + private final AtomicReference<String> indexInfoURLContentCopy = new AtomicReference<String>(); + private final AtomicReference<String> indexInfoSubIndexCopy = new AtomicReference<String>(); + private final AtomicReference<String> checkingIndexFolderContentCopy = new AtomicReference<String>(); + private void subindexSelectionUpdated() { + indexRandomFiles.set(null); + validateIndexSelection(); + } + private void validateIndexSelection() { + indexInfoURLContentCopy.set(indexURL.getText()); + indexInfoSubIndexCopy.set((String) subIndex.getSelectedItem()); + checkingIndexFolderContentCopy.set(folder.getText()); + indexInfoTask.cancel(); + indexInfoTask.schedule(50); + } + + private final RequestProcessor.Task indexInfoTask = WORKER.create(new Runnable() { + + public void run() { + String localFolder = checkingIndexFolderContentCopy.get(); + + if (!localFolder.isEmpty()) { + checkingIndexAgainstFolder.set(true); + checkingIndexURLWarning.set(null); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + updateErrors(); + } + }); + + String urlText = indexInfoURLContentCopy.get(); + String subIndex = indexInfoSubIndexCopy.get(); + URL folderURL = Utils.fromDisplayName(localFolder); + FileObject folder = URLMapper.findFileObject(folderURL); + + try { + if (folder != null) { + Collection<? extends String> random = indexRandomFiles.get(); + + if (random == null) { + URL url = new URL(urlText); + + if (!url.getPath().endsWith("/")) + url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getPath() + "/" + (url.getQuery() != null ? "?" + url.getQuery() : "")); + + indexRandomFiles.set(random = WebUtilities.requestStringArrayResponse(url.toURI().resolve("source/randomfiles?path=" + WebUtilities.escapeForQuery(subIndex)))); + } + + if (!random.isEmpty()) { + boolean found = matches(folder, random); + + if (!found) { + if (folder.getParent() != null && matches(folder.getParent(), random)) { + checkingIndexURLWarning.set("The given folder is unlikely to match the index content, parent folder does."); + } else { + StringBuilder matchingChildren = new StringBuilder(); + + for (FileObject c : folder.getChildren()) { + if (matches(c, random)) { + if (matchingChildren.length() > 0) matchingChildren.append(", "); + matchingChildren.append(c.getName()); + } + } + + if (matchingChildren.length() > 0) { + checkingIndexURLWarning.set("The given folder is unlikely to match the index content, subfolders: " + matchingChildren.toString() + " do."); + } else { + checkingIndexURLWarning.set("The given folder is unlikely to match the index content."); + } + } + } + } else { + //no random files? ignoring for now... + } + } + } catch (URISyntaxException ex) { + checkingIndexURLError.set(ex.getLocalizedMessage()); + } catch (MalformedURLException ex) { + checkingIndexURLError.set(ex.getLocalizedMessage()); + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) {//#6541019 + checkingIndexURLError.set("Invalid URL"); + } finally { + checkingIndexAgainstFolder.set(false); + } + } + + //XXX: the index currently does not provide the info anyway... +// IndexInfo info = null; +// +// try { +// URL url = new URL(urlText); +// +// if (!url.getPath().endsWith("/")) +// url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getPath() + "/" + (url.getQuery() != null ? "?" + url.getQuery() : "")); +// +// String indexInfoText = WebUtilities.requestStringResponse(url.toURI().resolve("info?path=" + WebUtilities.escapeForQuery(subIndex))); +// info = IndexInfo.empty(); +// +// if (indexInfoText != null) +// Pojson.update(info, indexInfoText); +// } catch (URISyntaxException ex) { +// Logger.getLogger(CustomizeRemoteIndex.class.getName()).log(Level.FINE, null, ex); +// } catch (MalformedURLException ex) { +// Logger.getLogger(CustomizeRemoteIndex.class.getName()).log(Level.FINE, null, ex); +// } +// +// final IndexInfo infoFinal = info; +// + SwingUtilities.invokeLater(new Runnable() { + public void run() { + updateErrors(); +// if (infoFinal != null) { +// indexInfo.setText(toDisplayText(infoFinal)); +// } else { +// indexInfo.setText(""); +// } + } + }); + } + + private boolean matches(FileObject folder, Collection<? extends String> random) { + boolean found = false; + for (String rel : random) { + if (folder.getFileObject(rel) != null) { + found = true; + break; + } + } + return found; + } + }); + +// private static String toDisplayText(IndexInfo info) { +// StringBuilder sb = new StringBuilder(); +// +// if (info.sourceLocation != null) { +// sb.append("Source Location: ").append(info.sourceLocation).append("\n"); +// } +// if (info.lastUpdate >= 0) { +// sb.append("Last Update:\t").append(DateFormat.getDateTimeInstance().format(new Date(info.lastUpdate))).append("\n"); +// } +// if (info.totalFiles >= 0) { +// sb.append("Indexed Files:\t").append(info.totalFiles).append("\n"); +// } +// +// return sb.toString(); +// } + + private static final class RendererImpl extends DefaultListCellRenderer { + private final Map<String, String> displayNames; + public RendererImpl(Map<String, String> displayNames) { + this.displayNames = displayNames; + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + return super.getListCellRendererComponent(list, displayNames.get(value), index, isSelected, cellHasFocus); + } + + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/FSChooser.java ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/FSChooser.java b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/FSChooser.java new file mode 100644 index 0000000..e0c442c --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/FSChooser.java @@ -0,0 +1,260 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.jackpot30.remotingapi.options; + +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.swing.JButton; +import javax.swing.JPanel; +import org.netbeans.modules.jackpot30.remoting.api.FileSystemLister; +import org.openide.DialogDescriptor; +import org.openide.DialogDisplayer; +import org.openide.explorer.ExplorerManager; +import org.openide.explorer.view.BeanTreeView; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileStateInvalidException; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; +import org.openide.loaders.DataFilter; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.openide.util.Exceptions; +import org.openide.util.Lookup; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author lahvac + */ +public class FSChooser { + + public static URL select(String caption, String okButton, URL preselect) { + Node n = new RootNode(); + final ExplorerManager m = new ExplorerManager(); + + m.setRootContext(n); + + class P extends JPanel implements ExplorerManager.Provider { + public P() { + setLayout(new BorderLayout()); + add(new BeanTreeView(), BorderLayout.CENTER); + } + @Override public ExplorerManager getExplorerManager() { + return m; + } + } + + //XXX: asynchronously! + FileObject toSelect = preselect != null ? URLMapper.findFileObject(preselect) : null; + + toSelect = toSelect != null ? toSelect : homeFO(); + + if (toSelect != null) { + try { + Node toSelectNode = findFileNode(n, toSelect); + + if (toSelectNode == null) { + FileObject home = homeFO(); + + if (home != null) { + toSelectNode = findFileNode(n, home); + } + } + + if (toSelectNode != null) { + m.setSelectedNodes(new Node[] {toSelectNode}); + } + } catch (PropertyVetoException ex) { + Exceptions.printStackTrace(ex); + } + } + + final boolean[] accepted = new boolean[1]; + final Dialog[] d = new Dialog[1]; + final JButton ok = new JButton(okButton); + + m.addPropertyChangeListener(new PropertyChangeListener() { + @Override public void propertyChange(PropertyChangeEvent evt) { + ok.setEnabled(m.getSelectedNodes().length == 1); + } + }); + + ok.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { + d[0].setVisible(false); + accepted[0] = true; + } + }); + + DialogDescriptor dd = new DialogDescriptor(new P(), caption, true, new Object[] {ok, DialogDescriptor.CANCEL_OPTION}, ok, DialogDescriptor.DEFAULT_ALIGN, null, null); + + d[0] = DialogDisplayer.getDefault().createDialog(dd); + + d[0].setVisible(true); + + if (accepted[0]) { + try { + return m.getSelectedNodes()[0].getLookup().lookup(FileObject.class).getURL(); + } catch (FileStateInvalidException ex) { + Exceptions.printStackTrace(ex); + return null; + } + } else { + return null; + } + } + + private static FileObject homeFO() { + return FileUtil.toFileObject(FileUtil.normalizeFile(new File(System.getProperty("user.home")))); + } + + private static Node findFileNode(Node root, FileObject file) { + for (Node n : root.getChildren().getNodes(true)) { + FileObject p = n.getLookup().lookup(FileObject.class); + + if (p == null) { + continue; + } + + if (FileUtil.isParentOf(p, file)) { + return findFileNode(n, file); + } + + if (p == file) return n; + } + + return null; + } + + private static final class RootNode extends AbstractNode { + public RootNode() { + super(new RootChildren()); + } + } + + private static final class RootChildren extends Children.Keys<FileSystem> { + + @Override + protected Node[] createNodes(FileSystem key) { + try { + DataFolder f = DataFolder.findFolder(key.getRoot()); + + return new Node[] { + new FSNode(f) + }; + } catch (FileStateInvalidException ex) { + Exceptions.printStackTrace(ex); + return new Node[0]; + } + } + + @Override + protected void addNotify() { + List<FileSystem> fss = new ArrayList<FileSystem>(); + + for (FileSystemLister l : Lookup.getDefault().lookupAll(FileSystemLister.class)) { + fss.addAll(l.getKnownFileSystems()); + } + + setKeys(fss); + + super.addNotify(); + } + + @Override + protected void removeNotify() { + super.removeNotify(); + + setKeys(Collections.<FileSystem>emptyList()); + } + } + + private static final class FSNode extends FilterNode { + + public FSNode(DataFolder original) throws FileStateInvalidException { + super(original.getNodeDelegate(), original.createNodeChildren(new DataFilter() { + @Override public boolean acceptDataObject(DataObject obj) { + return obj instanceof DataFolder; + } + })); + } + } + + @ServiceProvider(service=FileSystemLister.class) + public static final class LocalFileSystemLister implements FileSystemLister { + @Override public Collection<? extends FileSystem> getKnownFileSystems() { + Set<FileSystem> fss = new HashSet<FileSystem>(); + + for (File f : File.listRoots()) { + FileObject fo = FileUtil.toFileObject(f); + + if (fo != null) { + try { + fss.add(fo.getFileSystem()); + } catch (FileStateInvalidException ex) { + Exceptions.printStackTrace(ex); + } + } + } + + return fss; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexOptionsPanelController.java ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexOptionsPanelController.java b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexOptionsPanelController.java new file mode 100644 index 0000000..e7c2024 --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexOptionsPanelController.java @@ -0,0 +1,113 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.jackpot30.remotingapi.options; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javax.swing.JComponent; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; + [email protected](location = "Editor", +displayName = "#AdvancedOption_DisplayName_Index", +keywords = "#AdvancedOption_Keywords_Index", +keywordsCategory = "Editor/Index") +public final class IndexOptionsPanelController extends OptionsPanelController { + + private IndexPanel panel; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private boolean changed; + + public void update() { + getPanel().load(); + changed = false; + } + + public void applyChanges() { + getPanel().store(); + changed = false; + } + + public void cancel() { + // need not do anything special, if no changes have been persisted yet + } + + public boolean isValid() { + return getPanel().valid(); + } + + public boolean isChanged() { + return changed; + } + + public HelpCtx getHelpCtx() { + return null; // new HelpCtx("...ID") if you have a help set + } + + public JComponent getComponent(Lookup masterLookup) { + return getPanel(); + } + + public void addPropertyChangeListener(PropertyChangeListener l) { + pcs.addPropertyChangeListener(l); + } + + public void removePropertyChangeListener(PropertyChangeListener l) { + pcs.removePropertyChangeListener(l); + } + + private IndexPanel getPanel() { + if (panel == null) { + panel = new IndexPanel(this); + } + return panel; + } + + void changed() { + if (!changed) { + changed = true; + pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true); + } + pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null); + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-jackpot30/blob/9ed0a377/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexPanel.form ---------------------------------------------------------------------- diff --git a/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexPanel.form b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexPanel.form new file mode 100644 index 0000000..82cc349 --- /dev/null +++ b/remoting/ide/api/src/org/netbeans/modules/jackpot30/remotingapi/options/IndexPanel.form @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="1" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jScrollPane1" pref="263" max="32767" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="removeButton" alignment="1" max="32767" attributes="1"/> + <Component id="addButton" alignment="1" max="32767" attributes="1"/> + <Component id="editButton" alignment="1" max="32767" attributes="0"/> + <Component id="synchronizeOffline" alignment="0" max="32767" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="jScrollPane1" pref="306" max="32767" attributes="0"/> + <Group type="102" attributes="0"> + <Component id="addButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="editButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="removeButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + <Component id="synchronizeOffline" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Container class="javax.swing.JScrollPane" name="jScrollPane1"> + <AuxValues> + <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/> + <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/> + <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> + </AuxValues> + + <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> + <SubComponents> + <Component class="javax.swing.JTable" name="indices"> + <Properties> + <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor"> + <Table columnCount="4" rowCount="4"> + <Column editable="true" title="Title 1" type="java.lang.Object"/> + <Column editable="true" title="Title 2" type="java.lang.Object"/> + <Column editable="true" title="Title 3" type="java.lang.Object"/> + <Column editable="true" title="Title 4" type="java.lang.Object"/> + </Table> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + <Component class="javax.swing.JButton" name="addButton"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="IndexPanel.addButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addButtonActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="removeButton"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="IndexPanel.removeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removeButtonActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="editButton"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="IndexPanel.editButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editButtonActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="synchronizeOffline"> + <Properties> + <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> + <ResourceString bundle="org/netbeans/modules/jackpot30/remotingapi/options/Bundle.properties" key="IndexPanel.synchronizeOffline.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}", {arguments})"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="synchronizeOfflineActionPerformed"/> + </Events> + </Component> + </SubComponents> +</Form>
