Over a million developers have joined DZone.

Implementing Copy/Paste in Apache Pivot Using Only Script and Markup

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

As part of our effort to expand the documentation for Apache Pivot, I have recently been working on some new tutorials, one of which focuses on Pivot's support for interacting with the system clipboard. In this entry, I will discuss the implementation of this sample application, which, unlike most of the previous tutorial examples I have written, is constructed entirely in markup and script - no Java is involved.

Demo

A screen shot of the application is shown below (click for a live demo). Users can copy one of three sample images provided by the application to the clipboard using the "Copy" button, and can paste images from the clipboard using the "Paste" button:

Note that the applet is signed to allow it to access the system clipboard; untrusted Pivot applications can only perform copy and paste with a local clipboard whose content is not shared with other applications.

Implementation

The application source code consists of two files: a main WTKX file that declares the structure of the user interface along with some simple event handlers, and a JavaScript file that defines two functions: copy() and paste(). These functions are invoked by the button press listeners attached to the UI elements declared in the WTKX file.

WTKX Source

The WTKX source code for the example ("clipboard.wtkx") is shown below:

<Window title="Clipboard" maximized="true"
xmlns:wtkx="http://pivot.apache.org/wtkx"
xmlns="org.apache.pivot.wtk">
<wtkx:script src="clipboard.js"/>

<windowStateListeners>
<wtkx:script>
<![CDATA[
function windowOpened(window) {
sourceImageButtonGroup.setSelection(sourceImageButton1);
sourceImageButton1.requestFocus();
}
]]>
</wtkx:script>
</windowStateListeners>

<content>
<TablePane styles="{horizontalSpacing:4, verticalSpacing:4}">
<columns>
<TablePane.Column width="1*"/>
<TablePane.Column width="1*"/>
</columns>
<rows>
<TablePane.Row height="1*">
<Border>
<content>
<CardPane wtkx:id="sourceImageCardPane" styles="{padding:4}">
<ImageView image="org/apache/pivot/tutorials/IMG_0725_2.jpg"/>
<ImageView image="org/apache/pivot/tutorials/IMG_0735_2.jpg"/>
<ImageView image="org/apache/pivot/tutorials/IMG_0767_2.jpg"/>
</CardPane>
</content>
</Border>
<Border>
<content>
<CardPane selectedIndex="0" styles="{padding:4}">
<ImageView wtkx:id="destinationImageView"/>
</CardPane>
</content>
</Border>
</TablePane.Row>

<TablePane.Row height="-1">
<BoxPane orientation="vertical" styles="{fill:true}">
<BoxPane wtkx:id="sourceImageButtonBoxPane"
styles="{horizontalAlignment:'center', verticalAlignment:'center'}">
<wtkx:define>
<ButtonGroup wtkx:id="sourceImageButtonGroup">
<buttonGroupListeners>
<wtkx:script>
<![CDATA[
function selectionChanged(buttonGroup, previousSelection) {
var selection = buttonGroup.getSelection();

if (selection != null) {
var index = sourceImageButtonBoxPane.indexOf(selection);
sourceImageCardPane.setSelectedIndex(index);
}
}
]]>
</wtkx:script>
</buttonGroupListeners>
</ButtonGroup>
</wtkx:define>

<PushButton wtkx:id="sourceImageButton1"
buttonData="IMG_0725_2.jpg" toggleButton="true"
buttonGroup="$sourceImageButtonGroup"/>
<PushButton wtkx:id="sourceImageButton2"
buttonData="IMG_0735_2.jpg" toggleButton="true"
buttonGroup="$sourceImageButtonGroup"/>
<PushButton wtkx:id="sourceImageButton3"
buttonData="IMG_0767_2.jpg" toggleButton="true"
buttonGroup="$sourceImageButtonGroup"/>
</BoxPane>

<BoxPane styles="{horizontalAlignment:'center'}">
<PushButton wtkx:id="copyButton" buttonData="Copy"
ButtonPressListener.buttonPressed="copy()"/>
</BoxPane>
</BoxPane>

<BoxPane styles="{horizontalAlignment:'center', verticalAlignment:'center'}">
<PushButton wtkx:id="pasteButton" buttonData="Paste"
ButtonPressListener.buttonPressed="paste()"/>
</BoxPane>
</TablePane.Row>
</rows>
</TablePane>
</content>
</Window>

Like most Pivot tutorial examples, it defines a single top-level, maximized, undecorated Window instance that contains the rest of the UI. The source images are contained in a set of ImageView components stored in a CardPane, and a set of toggle-style PushButtons is used to navigate between them. Another ImageView is used to display the image content pasted from the clipboard.

The file defines several event handlers:

  • A window state listener that initializes the selection of the card pane when the window is opened:

    <windowStateListeners>
    <wtkx:script>
    <![CDATA[
    function windowOpened(window) {
    sourceImageButtonGroup.setSelection(sourceImageButton1);
    sourceImageButton1.requestFocus();
    }
    ]]>
    </wtkx:script>
    </windowStateListeners>
  • A button group listener that changes the card pane's selection in response to a button group selection change:

    <buttonGroupListeners>
    <wtkx:script>
    <![CDATA[
    function selectionChanged(buttonGroup, previousSelection) {
    var selection = buttonGroup.getSelection();

    if (selection != null) {
    var index = sourceImageButtonBoxPane.indexOf(selection);
    sourceImageCardPane.setSelectedIndex(index);
    }
    }
    ]]>
    </wtkx:script>
    </buttonGroupListeners>
  • A button press listener that calls the copy() function when the "Copy" button is pressed:

    <PushButton wtkx:id="copyButton" buttonData="Copy"
    ButtonPressListener.buttonPressed="copy()"/>
  • A button press listener that calls the paste() function when the "Paste" button is pressed:

    <PushButton wtkx:id="pasteButton" buttonData="Paste"
    ButtonPressListener.buttonPressed="paste()"/>

NOTE The attribute-based event handlers used in this example are a feature of Pivot 1.4, which is still in active development. However, they can easily be replaced with the element-based syntax supported by the currently available Pivot 1.3.

JavaScript Source

The contents of "clipboard.js" are shown below:

importPackage(org.apache.pivot.wtk);

function copy() {
// Copy the selected image to the clipboard
var selectedSourceIndex = sourceImageCardPane.getSelectedIndex();
var sourceImageView = sourceImageCardPane.get(selectedSourceIndex);
var sourceImage = sourceImageView.getImage();

var content = new LocalManifest();
content.putImage(sourceImage);

Clipboard.setContent(content);
}

function paste() {
// Paste any available image from the clipboard
var content = Clipboard.getContent();

if (content != null) {
var image = content.getImage();

if (image != null) {
destinationImageView.setImage(image);
}
}
}

These two functions perform the actual copying and pasting of the image data. The copy() function gets a reference to the actual image displayed by the selected card (an instance of org.apache.pivot.wtk.media.Image) and sets it as the "image" property of a LocalManifest instance. LocalManifest is a concrete implementation of the abstract Manifest class that is used to represent the source data in a clipboard transaction. In contrast, a RemoteManifest represents data obtained from the clipboard. Local manifests are created by an application, whereas remote manifests are created by the system.

A manifest encapsulates the content that may be placed on the clipboard by a Pivot application. It can represent the data in a variety of "flavors": as text, as an image, as a list of files, as a URL, or as a custom data format. An application may provide one or more flavors depending on the nature of the data. An application that is interested in consuming the data can then choose the most appropriate format based on the available flavors.

Once the manifest has been created and populated, it is placed on the clipboard via the Clipboard.setContent() method. It is now available for other applications to consume.

The paste() method performs the opposite transaction. It retrieves the current clipboard contents and checks for the presence of an image flavor. If available, it extracts the image content and sets it as the source of the destinationImageView component.

Summary

While this (like many tutorial applications) represents a somewhat contrived example, it demonstrates that non-trivial behavior such as interacting with the system clipboard can realistically be implemented exclusively in markup and script. While a full-fledged application is still most likely to employ a combination of WTKX, Java, and JavaScript, this example shows that it is possible to achieve some fairly complex functionality with just a few lines of script and markup.

For more information, please visit the Apache Pivot home page.

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}