You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by rw...@apache.org on 2015/08/05 20:45:38 UTC

svn commit: r1694282 - in /pivot/trunk: ./ tests/src/org/apache/pivot/tests/ wtk-terra/src/org/apache/pivot/wtk/skin/terra/ wtk/src/org/apache/pivot/wtk/

Author: rwhitcomb
Date: Wed Aug  5 18:45:38 2015
New Revision: 1694282

URL: http://svn.apache.org/r1694282
Log:
PIVOT-977:  Implement a specialized subclass of LinkButton to really do an HTML hyperlink.

This is the complete implementation, plus small tests, of this functionality.

The HyperlinkButton subclasses LinkButton, but uses the TerraLinkButtonSkin class
(that is, no new skin is neeeded).  The component completely relies on the existing
LinkButton class for all functionality, but adds the ability to specify a URI or URL
as the target of the link, then defines a custom Action object that calls
Desktop.getDesktop().browse(URI)
to implement the hyperlink jump.

Normally the hyperlink text is the string form of the URI or URL, but this can be
overridden via alternate constructors or by specifying "buttonData" as a BXML
attribute or with an embedded <ButtonData> element.

The test programs test these alternate forms.

The "build.xml" is changed to copy the .png files from the test source to the
test binary area so the icon image can be found in the test program.

The "TerraTheme" is extended to associate the HyperlinkButton component with
the TerraLinkButtonSkin skin class.


Added:
    pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest.java
    pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest2.java
    pivot/trunk/wtk/src/org/apache/pivot/wtk/HyperlinkButton.java
Modified:
    pivot/trunk/build.xml
    pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraTheme.java

Modified: pivot/trunk/build.xml
URL: http://svn.apache.org/viewvc/pivot/trunk/build.xml?rev=1694282&r1=1694281&r2=1694282&view=diff
==============================================================================
--- pivot/trunk/build.xml (original)
+++ pivot/trunk/build.xml Wed Aug  5 18:45:38 2015
@@ -513,6 +513,9 @@ limitations under the License.
         <compile project="tests">
             <fileset dir="wtk" includes="lib/**/*.jar"/>
         </compile>
+        <copy todir="tests/${folder.bin}">
+            <fileset dir="tests/src" includes="**/*.png"/>
+        </copy>
     </target>
 
     <target name="tutorials" depends="core, wtk, web">

Added: pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest.java?rev=1694282&view=auto
==============================================================================
--- pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest.java (added)
+++ pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest.java Wed Aug  5 18:45:38 2015
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.tests;
+
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.wtk.Application;
+import org.apache.pivot.wtk.BoxPane;
+import org.apache.pivot.wtk.DesktopApplicationContext;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.Frame;
+import org.apache.pivot.wtk.Orientation;
+import org.apache.pivot.wtk.HyperlinkButton;
+
+
+public class HyperlinkButtonTest extends Application.Adapter {
+    private Frame frame = null;
+
+    @Override
+    public void startup(Display display, Map<String, String> properties) throws Exception {
+        frame = new Frame();
+        frame.setTitle("Hyperink Button Test");
+        frame.setPreferredSize(480, 360);
+
+        HyperlinkButton button1 = new HyperlinkButton("http://pivot.apache.org");
+        HyperlinkButton button2 = new HyperlinkButton("Apache website", "http://apache.org");
+        BoxPane bp = new BoxPane(Orientation.VERTICAL);
+        bp.add(button1);
+        bp.add(button2);
+
+        frame.setContent(bp);
+
+        frame.open(display);
+    }
+
+    @Override
+    public boolean shutdown(boolean optional) {
+        if (frame != null) {
+            frame.close();
+        }
+
+        return false;
+    }
+
+    public static void main(String[] args) {
+        DesktopApplicationContext.main(HyperlinkButtonTest.class, args);
+    }
+}

Added: pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest2.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest2.java?rev=1694282&view=auto
==============================================================================
--- pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest2.java (added)
+++ pivot/trunk/tests/src/org/apache/pivot/tests/HyperlinkButtonTest2.java Wed Aug  5 18:45:38 2015
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.tests;
+
+import java.io.ByteArrayInputStream;
+import org.apache.pivot.beans.BXMLSerializer;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.wtk.Application;
+import org.apache.pivot.wtk.DesktopApplicationContext;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.Frame;
+
+
+public class HyperlinkButtonTest2 extends Application.Adapter {
+    private Frame frame = null;
+
+    private static final String bxmlFile =
+        "<Frame title=\"Hyperlink Button Test 2\"" +
+        " xmlns:bxml=\"http://pivot.apache.org/bxml\"" +
+        " xmlns:content=\"org.apache.pivot.wtk.content\"" +
+        " xmlns=\"org.apache.pivot.wtk\">" +
+        "  <BoxPane orientation=\"vertical\">" +
+        "    <HyperlinkButton url=\"http://commons.apache.org\"/>" +
+        "    <HyperlinkButton url=\"http://apache.org\">" +
+        "      <content:ButtonData text=\"ASF website\" icon=\"/org/apache/pivot/tests/house.png\"/>" +
+        "    </HyperlinkButton>" +
+        "  </BoxPane>" +
+        "</Frame>";
+
+    @Override
+    public void startup(Display display, Map<String, String> properties) throws Exception {
+        BXMLSerializer serializer = new BXMLSerializer();
+        frame = (Frame)serializer.readObject(new ByteArrayInputStream(bxmlFile.getBytes()));
+
+        frame.open(display);
+    }
+
+    @Override
+    public boolean shutdown(boolean optional) {
+        if (frame != null) {
+            frame.close();
+        }
+
+        return false;
+    }
+
+    public static void main(String[] args) {
+        DesktopApplicationContext.main(HyperlinkButtonTest2.class, args);
+    }
+}

Modified: pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraTheme.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraTheme.java?rev=1694282&r1=1694281&r2=1694282&view=diff
==============================================================================
--- pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraTheme.java (original)
+++ pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraTheme.java Wed Aug  5 18:45:38 2015
@@ -48,6 +48,7 @@ import org.apache.pivot.wtk.FileBrowserS
 import org.apache.pivot.wtk.Form;
 import org.apache.pivot.wtk.Frame;
 import org.apache.pivot.wtk.GridPane;
+import org.apache.pivot.wtk.HyperlinkButton;
 import org.apache.pivot.wtk.Label;
 import org.apache.pivot.wtk.LinkButton;
 import org.apache.pivot.wtk.ListButton;
@@ -128,6 +129,7 @@ public final class TerraTheme extends Th
         componentSkinMap.put(BoxPane.class, TerraBoxPaneSkin.class);
         componentSkinMap.put(Frame.class, TerraFrameSkin.class);
         componentSkinMap.put(GridPane.class, TerraGridPaneSkin.class);
+        componentSkinMap.put(HyperlinkButton.class, TerraLinkButtonSkin.class);
         componentSkinMap.put(Label.class, TerraLabelSkin.class);
         componentSkinMap.put(LinkButton.class, TerraLinkButtonSkin.class);
         componentSkinMap.put(ListButton.class, TerraListButtonSkin.class);

Added: pivot/trunk/wtk/src/org/apache/pivot/wtk/HyperlinkButton.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/HyperlinkButton.java?rev=1694282&view=auto
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/HyperlinkButton.java (added)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/HyperlinkButton.java Wed Aug  5 18:45:38 2015
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.wtk;
+
+import java.awt.Desktop;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URISyntaxException;
+
+import org.apache.pivot.beans.DefaultProperty;
+import org.apache.pivot.wtk.content.ButtonData;
+import org.apache.pivot.wtk.content.LinkButtonDataRenderer;
+
+/**
+ * Specialized subclass of {@link LinkButton} that actually implements an HTML hyperlink
+ * using the {@link Desktop#browse} method.
+ * <p> By default the button text will be the string representation of the {@link URI} or
+ * {@link URL} that is the target of the link.  But any arbitrary text can also be used
+ * or a combination of icon and text using {@link ButtonData} (just like any other button).
+ */
+@DefaultProperty("buttonData")
+public class HyperlinkButton extends LinkButton {
+    private static final Button.DataRenderer DEFAULT_DATA_RENDERER = new LinkButtonDataRenderer();
+
+    /**
+     * Private class to implement the "browse" action of this button.
+     * <p> Uses the {@link Desktop#browse} method to implement the functionality.
+     */
+    private class URIAction extends Action {
+        private URI uri;
+
+        public URIAction(URI uri) {
+            this.uri = uri;
+        }
+
+        public URI getUri() {
+            return uri;
+        }
+
+        public void setUri(URI uri) {
+            this.uri = uri;
+        }
+
+        @Override
+        public void perform(Component source) {
+            if (uri == null) {
+                throw new RuntimeException("URI is null.");
+            }
+            try {
+                if (Desktop.isDesktopSupported()) {
+                    Desktop desktop = Desktop.getDesktop();
+                    if (desktop.isSupported(Desktop.Action.BROWSE)) {
+                        desktop.browse(uri);
+                    }
+                }
+            } catch (IOException ioe) {
+                throw new RuntimeException(ioe);
+            }
+        }
+    }
+
+    private URIAction action;
+
+    /**
+     * Default no-arg constructor needed for BXML files.
+     * <p> Sets the hyperlink text to <code>""</code> (empty string).
+     * and the {@link URI} target to null.
+     */
+    public HyperlinkButton() {
+        this((URI)null);
+    }
+
+    /**
+     * Construct a hyperlink button that references the given {@link URI}.
+     * @param uri The target of this hyperlink.
+     */
+    public HyperlinkButton(URI uri) {
+        super();
+        setUri(uri);
+
+        installSkin(HyperlinkButton.class);
+        setDataRenderer(DEFAULT_DATA_RENDERER);
+    }
+
+    /**
+     * Construct a hyperlink button that references the given URI specified
+     * by the string argument.
+     * @param uriString The target of this hyperlink given as a string.
+     * @throws URISyntaxException if the string argument is not a proper URI.
+     */
+    public HyperlinkButton(String uriString) throws URISyntaxException {
+        this(uriString == null ? null : new URI(uriString));
+    }
+
+    /**
+     * Construct a hyperlink button that references the given {@link URL}.
+     * @param url The target of this hyperlink.
+     * @throws URISyntaxException if the URL does not specify a valid {@link URI}.
+     */
+    public HyperlinkButton(URL url) throws URISyntaxException {
+        this(url == null ? null : url.toURI());
+    }
+
+    /**
+     * Constructor to set an alternate text for the link button, in addition
+     * to the target {@link URI}.
+     * @param text Alternate text for the hyperlink.
+     * @param uri The target of this hyperlink.
+     */ 
+    public HyperlinkButton(String text, URI uri) {
+        this(uri);
+        setButtonData(text);
+    }
+
+    /**
+     * Constructor to set an alternate text for the link button, in addition to
+     * specifying the target location with a string.
+     * @param text The alternate text for the hyperlink.
+     * @param uriString The string specifying the hyperlink target.
+     * @throws URISyntaxException if the string does not specify a valid {@link URI}.
+     */
+    public HyperlinkButton(String text, String uriString) throws URISyntaxException {
+        this(text, new URI(uriString));
+    }
+
+    /**
+     * Access the {@link URI} which is the target of this hyperlink.
+     */
+    public URI getUri() {
+        return action == null ? null : action.getUri();
+    }
+
+    /**
+     * Set the {@link URI} which is the target of this hyperlink.
+     * <p> Also sets the button data (that is the text string for the link)
+     * to the string form of the <code>URI</code>, but only if there is not
+     * already something set for the button data.  This logic allows the
+     * button data to be set as an embedded element in BXML and still have
+     * the URI set as an element property.
+     * @param uri The target for this hyperlink.
+     */
+    public void setUri(URI uri) {
+        // If the user has already set the button data in BXML,
+        // then don't set the data to this new URI string
+        Object buttonData = getButtonData();
+        if (buttonData == null ||
+            ((buttonData instanceof String) && ((String)buttonData).isEmpty())) {
+            String uriString = uri == null ? "" : uri.toString();
+            setButtonData(uriString);
+        }
+        if (action == null) {
+            action = new URIAction(uri);
+            setAction(action);
+        } else {
+            action.setUri(uri);
+        }
+    }
+
+    /**
+     * Set the {@link URI} target of this hyperlink via the string representation.
+     * @param uriString String value of the hyperlink target.
+     * @throws IllegalArgumentException if the string is <code>null</code> or empty.
+     * @throws URISyntaxException if the string is not a valid {@link URI}.
+     * @see #setUri(URI)
+     */
+    public void setUri(String uriString)
+        throws URISyntaxException
+    {
+        if (uriString == null) {
+            throw new IllegalArgumentException("URI string must not be null.");
+        }
+        if (uriString.isEmpty()) {
+            throw new IllegalArgumentException("URI string must not be empty.");
+        }
+        setUri(new URI(uriString));
+    }
+
+    /**
+     * Set the target of this hyperlink via a {@link URL}.
+     * @param url Target of this hyperlink.
+     * @throws URISyntaxException if the <code>URL</code> does not specify
+     * a valid {@link URI}.
+     */ 
+    public void setUrl(URL url)
+        throws URISyntaxException
+    {
+        setUri(url == null ? null : url.toURI());
+    }
+
+    /**
+     * Set the {@link URL} target of this hyperlink using the string representation
+     * of the <code>URL</code>.
+     * @param urlString String form of the hyperlink target.
+     * @throws IllegalArgumentException if the input string is <code>null</code> or empty.
+     * @throws MalformedURLException if the string cannot be converted to a <code>URL</code>
+     * @throws URISyntaxException if the <code>URL</code> does not specify a valid {@link URI}.
+     */
+    public void setUrl(String urlString)
+        throws MalformedURLException, URISyntaxException
+    {
+        if (urlString == null) {
+            throw new IllegalArgumentException("URL string must not be null.");
+        }
+        if (urlString.isEmpty()) {
+            throw new IllegalArgumentException("URL string must not be empty.");
+        }
+        setUrl(new URL(urlString));
+    }
+
+}
+