You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/08/13 10:06:24 UTC
[2/4] groovy-examples git commit: initial version
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/Widgets.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/Widgets.groovy b/src/main/groovy/swing/Widgets.groovy
new file mode 100644
index 0000000..14266cf
--- /dev/null
+++ b/src/main/groovy/swing/Widgets.groovy
@@ -0,0 +1,220 @@
+/*
+ * 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 swing
+
+import java.awt.Color
+import javax.swing.SwingConstants
+import javax.swing.WindowConstants
+import groovy.swing.SwingBuilder
+
+class Widgets {
+
+ def swing = new SwingBuilder()
+ def unownedDialog
+ def ownedDialog
+
+
+ static void main(args) {
+ def demo = new Widgets()
+ demo.run()
+ }
+
+ def showUnownedDialog(event) {
+ unownedDialog.show();
+ }
+
+ def showOwnedDialog(event) {
+ ownedDialog.show();
+ }
+
+ void run() {
+ unownedDialog = swing.dialog(
+ title:'unrooted dialog',
+ location: [200, 200],
+ pack:true,
+ defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE
+ ) {
+ label("I am unowned, but not unwanted");
+ }
+
+ def frame = swing.frame(
+ title:'FrameTitle',
+ location:[100,100],
+ size:[800,400],
+ defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) {
+
+ menuBar {
+ menu(text:'File') {
+ menuItem() {
+ action(name:'New', closure:{ println("clicked on the new menu item!") })
+ }
+ menuItem() {
+ action(name:'Open', closure:{ println("clicked on the open menu item!") })
+ }
+ separator()
+ menuItem() {
+ action(name:'Save', enabled:false, closure:{ println("clicked on the Save menu item!") })
+ }
+ }
+ menu(text:'Dialogs') {
+ menuItem() {
+ action(name:'Owned Dialog', closure: this.&showOwnedDialog)
+ }
+ menuItem() {
+ action(name:'Unowned Dialog', closure: this.&showUnownedDialog)
+ }
+ def deeplyOwnedDialog = swing.dialog(
+ title:'rooted dialog #2',
+ location: [200, 200],
+ pack:true,
+ defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE
+ ) {
+ label("ownership is deep");
+ }
+ menuItem() {
+ action(name:'Deeply Owned Dialog', closure: {deeplyOwnedDialog.show()} )
+ }
+ }
+ }
+
+ tabbedPane() {
+
+ //colorChooser(
+ // name:"Color Chooser",
+ // color: 0xfeed42)
+
+ panel(name:"Formatted Text Fields") {
+ gridLayout(columns: 2, rows: 0)
+ label("Simple Constructor:")
+ formattedTextField()
+ label("Date Value")
+ formattedTextField(value: new java.util.Date())
+ label("Integer Value")
+ formattedTextField(value: new java.lang.Integer(42))
+ label("Date Format")
+ formattedTextField(format: java.text.DateFormat.getDateInstance())
+ label("Currency Format ")
+ formattedTextField(format: new java.text.DecimalFormat("¤###.00;(¤###.00)"))
+ }
+
+ panel(name:"Sliders") {
+ flowLayout()
+ slider(minimum:-100,
+ maximum:100,
+ majorTickSpacing: 50,
+ orientation: SwingConstants.VERTICAL,
+ paintLabels:true)
+ slider(minimum:-100,
+ maximum:100,
+ orientation: SwingConstants.VERTICAL,
+ paintLabels:true,
+ paintTicks:true,
+ majorTickSpacing: 50,
+ minorTickSpacing: 10,
+ snapToTicks:true,
+ paintTrack:true)
+ }
+
+ panel(name:"Spinners") {
+ gridBagLayout()
+ label(
+ text:"Tempuature in London:",
+ insets:[12, 12, 2, 2],
+ anchor: EAST,
+ gridx: 0)
+ spinner(
+ model:spinnerNumberModel(minimum:-10,
+ maximum: 40,
+ value:20,
+ stepSize:5),
+ insets:[12, 3, 2, 12],
+ anchor: WEST,
+ gridx: 1,
+ fill: HORIZONTAL)
+ label(
+ text:"Baseball Leagues:",
+ insets:[3, 12, 2, 2],
+ anchor: EAST,
+ gridx: 0)
+ spinner(
+ model:spinnerListModel(
+ list: ["Major League", "AAA", "AA", "A", "Rookie", "Semi-Pro", "Rec A", "Rec B"],
+ value: "AA"),
+ insets:[3, 3, 2, 12],
+ anchor: WEST,
+ gridx: 1,
+ fill: HORIZONTAL)
+ label(
+ text:"Today's Date:",
+ insets:[3, 12, 2, 2],
+ anchor: EAST,
+ gridx: 0)
+ spinner(
+ model:spinnerDateModel(calendarField: Calendar.HOUR_OF_DAY),
+ insets:[3, 3, 2, 12],
+ anchor: WEST,
+ gridx: 1,
+ fill: HORIZONTAL)
+ }
+
+ panel(name:"Border Layout") {
+ borderLayout()
+ label(text:"Border Layout",
+ constraints:NORTH,
+ horizontalAlignment:SwingConstants.CENTER)
+ label(text:"South",
+ constraints:SOUTH,
+ background:Color.YELLOW,
+ opaque:true,
+ horizontalAlignment:SwingConstants.CENTER,
+ toolTipText:"Tooltip on south")
+ label(text:"West",
+ constraints:WEST,
+ background:Color.ORANGE,
+ opaque:true,
+ horizontalAlignment:SwingConstants.CENTER,
+ toolTipText:"Tooltip on west")
+ label(text:"East",
+ constraints:EAST,
+ background:Color.GREEN,
+ opaque:true,
+ horizontalAlignment:SwingConstants.CENTER,
+ toolTipText:"Tooltip on east")
+ label(text:"Center",
+ constraints:CENTER,
+ background:Color.WHITE,
+ opaque:true,
+ horizontalAlignment:SwingConstants.CENTER,
+ toolTipText:"<html>This is not the tooltip you are looking for.<br><i>*waves hand*</i>")
+ }
+ }
+
+ ownedDialog = swing.dialog(
+ title:'rooted dialog',
+ location: [200, 200],
+ pack:true,
+ defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE
+ ) {
+ label("j00 h4v3 b33n 0wn3xed");
+ }
+ }
+ frame.show()
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/Caricature.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/Caricature.groovy b/src/main/groovy/swing/binding/caricature/Caricature.groovy
new file mode 100644
index 0000000..a37519c
--- /dev/null
+++ b/src/main/groovy/swing/binding/caricature/Caricature.groovy
@@ -0,0 +1,79 @@
+/*
+ * 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 swing.binding.caricature
+
+import groovy.swing.SwingBuilder
+import java.awt.Color
+import javax.swing.border.TitledBorder
+
+SwingBuilder.build {
+ frame(pack:true, show:true,
+ defaultCloseOperation:javax.swing.JFrame.DISPOSE_ON_CLOSE)
+ {
+ borderLayout()
+ panel(constraints:CENTER,) {
+ // place in panel to insure square layout
+ caricature = widget(new JCaricature(
+ background:Color.WHITE, opaque:true))
+ }
+ hbox(constraints:SOUTH) {
+ panel(border:new TitledBorder("Style")) {
+ gridLayout(new java.awt.GridLayout(5, 2))
+ label("Eyes") // font stuff
+ eyeSlider = slider(minimum:0, maximum:4,
+ value:bind(target:caricature,
+ targetProperty:'eyeStyle',
+ value:2))
+ label("Face") // font stuff
+ faceSlider = slider(minimum:0, maximum:4,
+ value:bind(target:caricature,
+ targetProperty:'faceStyle',
+ value:2))
+ label("Mouth") // font stuff
+ mouthSlider = slider(minimum:0, maximum:4,
+ value:bind(target:caricature,
+ targetProperty:'mouthStyle',
+ value:2))
+ label("Hair") // font stuff
+ hairSlider = slider(minimum:0, maximum:4,
+ value:bind(target:caricature,
+ targetProperty:'hairStyle',
+ value:2))
+ label("Nose") // font stuff
+ noseSlider = slider(minimum:0, maximum:4,
+ value:bind(target:caricature,
+ targetProperty:'noseStyle',
+ value:2))
+ }
+ panel(border:new TitledBorder("Effects")) {
+ gridLayout(new java.awt.GridLayout(2, 5))
+ label("Rotation") // font stuff
+ rotationSlider = slider(maximum:360,
+ value:bind(target:caricature,
+ targetProperty:'rotation',
+ value:0))
+ label("Scale") // font stuff
+ scaleSlider = slider(maximum: 150, minimum:50,
+ value:bind(target:caricature,
+ targetProperty:'scale',
+ converter: {it / 100f}, value:100))
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/JCaricature.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/JCaricature.java b/src/main/groovy/swing/binding/caricature/JCaricature.java
new file mode 100644
index 0000000..0041862
--- /dev/null
+++ b/src/main/groovy/swing/binding/caricature/JCaricature.java
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+/*
+ * Caricature.java
+ *
+ * Created on April 8, 2006, 4:09 PM
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package swing.binding.caricature;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+
+/**
+ *
+ * @author sky
+ */
+public class JCaricature extends JPanel {
+ private Map/*<String,Image>*/ imageMap;
+
+ private boolean empty;
+ private int mouthStyle;
+ private int faceStyle;
+ private int hairStyle;
+ private int eyeStyle;
+ private int noseStyle;
+ private int rotation;
+ private float scale = 1.0f;
+
+ public JCaricature() {
+ if (imageMap == null) {
+ imageMap = new HashMap/*<String,Image>*/(1);
+ for (int i = 0; i < 5; i++) {
+ getImage("face", i);
+ getImage("hair", i);
+ getImage("eyes", i);
+ getImage("nose", i);
+ getImage("mouth", i);
+ }
+ }
+ }
+
+ public void setEmpty(boolean empty) {
+ if (this.empty != empty) {
+ this.empty = empty;
+ firePropertyChange("empty", !empty, empty);
+ repaint();
+ }
+ }
+
+ public boolean isEmpty() {
+ return empty;
+ }
+
+ public void setRotation(int rotation) {
+ int oldRotation = this.rotation;
+ this.rotation = rotation;
+ repaint();
+ firePropertyChange("rotation", oldRotation, rotation);
+ }
+
+ public int getRotation() {
+ return rotation;
+ }
+
+ public void setScale(float scale) {
+ float oldScale = this.scale;
+ this.scale = scale;
+ repaint();
+ firePropertyChange("scale", oldScale, scale);
+ }
+
+ public float getScale() {
+ return scale;
+ }
+
+ public void setMouthStyle(int style) {
+ int oldStyle = mouthStyle;
+ mouthStyle = style;
+ firePropertyChange("mouthStyle", oldStyle, style);
+ repaint();
+ }
+
+ public int getMouthStyle() {
+ return mouthStyle;
+ }
+
+ public void setFaceStyle(int style) {
+ int oldStyle = faceStyle;
+ faceStyle = style;
+ firePropertyChange("faceStyle", oldStyle, style);
+ repaint();
+ }
+
+ public int getFaceStyle() {
+ return faceStyle;
+ }
+
+ public void setHairStyle(int style) {
+ int oldStyle = hairStyle;
+ hairStyle = style;
+ firePropertyChange("hairStyle", oldStyle, style);
+ repaint();
+ }
+
+ public int getHairStyle() {
+ return hairStyle;
+ }
+
+ public void setEyeStyle(int style) {
+ int oldStyle = eyeStyle;
+ eyeStyle = style;
+ firePropertyChange("eyeStyle", oldStyle, style);
+ repaint();
+ }
+
+ public int getEyeStyle() {
+ return eyeStyle;
+ }
+
+ public void setNoseStyle(int style) {
+ int oldStyle = noseStyle;
+ noseStyle = style;
+ firePropertyChange("noseStyle", oldStyle, style);
+ repaint();
+ }
+
+ public int getNoseStyle() {
+ return noseStyle;
+ }
+
+ public Dimension getPreferredSize() {
+ if (!isPreferredSizeSet()) {
+ Image image = getImage("mouth", 0);
+ return new Dimension(image.getWidth(null), image.getHeight(null));
+ }
+ return super.getPreferredSize();
+ }
+
+ public Dimension getMaximumSize() {
+ if (!isMaximumSizeSet()) {
+ return getPreferredSize();
+ }
+ return super.getMaximumSize();
+ }
+
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ if (empty) {
+ return;
+ }
+ Graphics2D g2 = (Graphics2D)g.create();
+ Image image = getImage("face", getFaceStyle());
+ int iw = image.getWidth(null);
+ int ih = image.getHeight(null);
+// g2.translate(iw / 2, ih / 2);
+ g2.translate(getWidth() / 2, getHeight() / 2);
+ if (iw != getWidth()) {
+ float forcedScale = (float)getWidth() / (float)iw;
+ g2.scale(forcedScale, forcedScale);
+ }
+ float scale = getScale();
+ if (scale != 1) {
+ g2.scale((double)scale, (double)scale);
+ }
+ int rotation = getRotation();
+ if (rotation != 0) {
+ g2.rotate(Math.toRadians(rotation));
+ }
+ drawImage(g2, "face", getFaceStyle());
+ drawImage(g2, "hair", getHairStyle());
+ drawImage(g2, "eyes", getEyeStyle());
+ drawImage(g2, "nose", getNoseStyle());
+ drawImage(g2, "mouth", getMouthStyle());
+ g2.dispose();
+ }
+
+ private void drawImage(Graphics g, String string, int i) {
+ Image image = getImage(string, i);
+ g.drawImage(image, -image.getWidth(null) / 2, -image.getHeight(null) / 2, null);
+ }
+
+ private Image getImage(String key, int style) {
+ String imageName = key + (style + 1) + ".gif";
+ Image image = (Image) imageMap.get(imageName);
+ if (image == null) {
+ System.err.println("name=" + imageName);
+ URL imageLoc = getClass().getResource("resources/" + imageName);
+ image = new ImageIcon(imageLoc).getImage();
+ imageMap.put(imageName, image);
+ }
+ return image;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/eyes1.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/eyes1.gif b/src/main/groovy/swing/binding/caricature/resources/eyes1.gif
new file mode 100644
index 0000000..54d0eb0
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/eyes1.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/eyes2.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/eyes2.gif b/src/main/groovy/swing/binding/caricature/resources/eyes2.gif
new file mode 100644
index 0000000..4aa3091
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/eyes2.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/eyes3.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/eyes3.gif b/src/main/groovy/swing/binding/caricature/resources/eyes3.gif
new file mode 100644
index 0000000..bfbbdea
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/eyes3.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/eyes4.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/eyes4.gif b/src/main/groovy/swing/binding/caricature/resources/eyes4.gif
new file mode 100644
index 0000000..e25f652
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/eyes4.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/eyes5.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/eyes5.gif b/src/main/groovy/swing/binding/caricature/resources/eyes5.gif
new file mode 100644
index 0000000..e5b6d6b
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/eyes5.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/face1.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/face1.gif b/src/main/groovy/swing/binding/caricature/resources/face1.gif
new file mode 100644
index 0000000..01a107f
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/face1.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/face2.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/face2.gif b/src/main/groovy/swing/binding/caricature/resources/face2.gif
new file mode 100644
index 0000000..0a8ea44
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/face2.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/face3.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/face3.gif b/src/main/groovy/swing/binding/caricature/resources/face3.gif
new file mode 100644
index 0000000..e8c467b
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/face3.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/face4.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/face4.gif b/src/main/groovy/swing/binding/caricature/resources/face4.gif
new file mode 100644
index 0000000..9364ab8
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/face4.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/face5.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/face5.gif b/src/main/groovy/swing/binding/caricature/resources/face5.gif
new file mode 100644
index 0000000..e5f5e7c
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/face5.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/glasses.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/glasses.gif b/src/main/groovy/swing/binding/caricature/resources/glasses.gif
new file mode 100644
index 0000000..ef46483
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/glasses.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/glassesWEyes.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/glassesWEyes.gif b/src/main/groovy/swing/binding/caricature/resources/glassesWEyes.gif
new file mode 100644
index 0000000..93585b0
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/glassesWEyes.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/hair1.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/hair1.gif b/src/main/groovy/swing/binding/caricature/resources/hair1.gif
new file mode 100644
index 0000000..0466d00
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/hair1.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/hair2.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/hair2.gif b/src/main/groovy/swing/binding/caricature/resources/hair2.gif
new file mode 100644
index 0000000..47adf81
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/hair2.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/hair3.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/hair3.gif b/src/main/groovy/swing/binding/caricature/resources/hair3.gif
new file mode 100644
index 0000000..d93bd45
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/hair3.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/hair4.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/hair4.gif b/src/main/groovy/swing/binding/caricature/resources/hair4.gif
new file mode 100644
index 0000000..eca9d4b
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/hair4.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/hair5.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/hair5.gif b/src/main/groovy/swing/binding/caricature/resources/hair5.gif
new file mode 100644
index 0000000..147057a
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/hair5.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/mouth1.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/mouth1.gif b/src/main/groovy/swing/binding/caricature/resources/mouth1.gif
new file mode 100644
index 0000000..a92e1d3
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/mouth1.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/mouth2.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/mouth2.gif b/src/main/groovy/swing/binding/caricature/resources/mouth2.gif
new file mode 100644
index 0000000..1486022
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/mouth2.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/mouth3.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/mouth3.gif b/src/main/groovy/swing/binding/caricature/resources/mouth3.gif
new file mode 100644
index 0000000..b6f5348
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/mouth3.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/mouth4.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/mouth4.gif b/src/main/groovy/swing/binding/caricature/resources/mouth4.gif
new file mode 100644
index 0000000..937b46d
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/mouth4.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/mouth5.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/mouth5.gif b/src/main/groovy/swing/binding/caricature/resources/mouth5.gif
new file mode 100644
index 0000000..f61a7a1
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/mouth5.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/nose1.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/nose1.gif b/src/main/groovy/swing/binding/caricature/resources/nose1.gif
new file mode 100644
index 0000000..336ea9f
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/nose1.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/nose2.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/nose2.gif b/src/main/groovy/swing/binding/caricature/resources/nose2.gif
new file mode 100644
index 0000000..5ab8609
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/nose2.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/nose3.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/nose3.gif b/src/main/groovy/swing/binding/caricature/resources/nose3.gif
new file mode 100644
index 0000000..ea3c643
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/nose3.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/nose4.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/nose4.gif b/src/main/groovy/swing/binding/caricature/resources/nose4.gif
new file mode 100644
index 0000000..832628b
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/nose4.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/binding/caricature/resources/nose5.gif
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/binding/caricature/resources/nose5.gif b/src/main/groovy/swing/binding/caricature/resources/nose5.gif
new file mode 100644
index 0000000..ec51067
Binary files /dev/null and b/src/main/groovy/swing/binding/caricature/resources/nose5.gif differ
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/greet/Greet.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/greet/Greet.groovy b/src/main/groovy/swing/greet/Greet.groovy
new file mode 100644
index 0000000..ca93900
--- /dev/null
+++ b/src/main/groovy/swing/greet/Greet.groovy
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+/*
+ * Created by IntelliJ IDEA.
+ * User: Danno.Ferrin
+ * Date: Apr 26, 2008
+ * Time: 8:32:03 AM
+ */
+package groovy.swing.greet
+
+import groovy.beans.Bindable
+import groovy.swing.SwingBuilder
+import javax.swing.JOptionPane
+
+class Greet {
+
+ TwitterAPI api
+ Binding view
+
+ @Bindable boolean allowLogin = true
+ @Bindable boolean allowSelection = true
+ @Bindable boolean allowTweet = true
+ @Bindable def focusedUser = ""
+ @Bindable def friends = []
+ @Bindable def tweets = []
+ @Bindable def timeline = []
+ @Bindable def statuses = []
+
+ void startUp() {
+ setAllowSelection(false)
+ setAllowTweet(false)
+ view.greetFrame.show()
+ view.loginDialog.show()
+ }
+
+ void login(evt) {
+ setAllowLogin(false)
+ view.doOutside {
+ try {
+ if (api.login(view.twitterNameField.text, view.twitterPasswordField.password)) {
+ setFriends(api.getFriends(api.authenticatedUser))
+ friends.each {it.status.user = [screen_name:it.screen_name, profile_image_url:it.profile_image_url] }
+ setStatuses(friends.collect {it.status})
+ selectUser(api.authenticatedUser)
+ view.greetFrame.show()
+ view.loginDialog.dispose()
+ } else {
+ JOptionPane.showMessageDialog(view.loginDialog, "Login failed")
+ }
+ } catch (Exception e) {
+ e.printStackTrace()
+ } finally {
+ view.edt {
+ setAllowLogin(true)
+ setAllowSelection(true)
+ setAllowTweet(true)
+ }
+ }
+ }
+ }
+
+ void filterTweets(evt = null) {
+ setAllowSelection(false)
+ setAllowTweet(false)
+ view.doOutside {
+ try {
+ setStatuses(
+ friends.collect {it.status}.findAll {it.text =~ view.searchField.text}
+ )
+ setTimeline(
+ api.getFriendsTimeline(focusedUser).findAll {it.text =~ view.searchField.text}
+ )
+ setTweets(
+ api.getTweets(focusedUser).findAll {it.text =~ view.searchField.text}
+ )
+ } catch (Exception e) {
+ e.printStackTrace()
+ } finally {
+ view.edt {
+ setAllowSelection(true)
+ setAllowTweet(true)
+ }
+ }
+ }
+ }
+
+ def userSelected(evt) {
+ view.doOutside {
+ selectUser(view.users.selectedItem)
+ }
+ }
+
+ def selectUser(user) {
+ setAllowSelection(false)
+ setAllowTweet(false)
+ try {
+ setFocusedUser(api.getUser(user.screen_name as String))
+ setTweets(api.getTweets(focusedUser).findAll {it.text =~ view.searchField.text})
+ setTimeline(api.getFriendsTimeline(focusedUser).findAll {it.text =~ view.searchField.text})
+ } finally {
+ view.edt {
+ setAllowSelection(true)
+ setAllowTweet(true)
+ }
+ }
+ }
+
+ def tweet(evt = null) {
+ setAllowTweet(false)
+ view.doOutside {
+ try {
+ api.tweet(view.tweetBox.text)
+ // true story: it froze w/o the EDT call here
+ view.edt {tweetBox.text = ""}
+ filterTweets()
+ } finally {
+ setAllowTweet(true)
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ def model = new TwitterAPI()
+ def controller = new Greet()
+ def view = new SwingBuilder()
+
+ controller.api = model
+ controller.view = view
+
+ view.controller = controller
+
+ view.build(View)
+ view.view = view
+
+ controller.startUp()
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/greet/TwitterAPI.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/greet/TwitterAPI.groovy b/src/main/groovy/swing/greet/TwitterAPI.groovy
new file mode 100644
index 0000000..76d13f4
--- /dev/null
+++ b/src/main/groovy/swing/greet/TwitterAPI.groovy
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+/**
+ * Created by IntelliJ IDEA.
+ * User: Danno.Ferrin
+ * Date: Apr 25, 2008
+ * Time: 9:47:20 PM
+ */
+package groovy.swing.greet
+
+import groovy.beans.Bindable
+
+class TwitterAPI {
+
+ @Bindable String status = "\u00a0"
+ def authenticatedUser
+ XmlSlurper slurper = new XmlSlurper()
+ def imageMap = [:]
+
+ def withStatus(status, c) {
+ setStatus(status)
+ try {
+ def o = c()
+ setStatus("\u00a0")
+ return o
+ } catch (Throwable t) {
+ setStatus("Error $status : ${t.message =~ '400'?'Rate Limit Reached':t}")
+ throw t
+ }
+ }
+
+
+ boolean login(def name, def password) {
+ withStatus("Logging in") {
+ Authenticator.setDefault(
+ [getPasswordAuthentication : {
+ return new PasswordAuthentication(name, password) }
+ ] as Authenticator)
+ authenticatedUser = getUser(name)
+ return true
+ }
+ }
+
+ def getFriends() {
+ getFriends(authenticatedUser)
+ }
+
+ def getFriends(String user) {
+ return getFriends(getUser(user))
+ }
+
+ def getFriends(user) {
+ def friends = [user]
+ withStatus("Loading Friends") {
+ def page = 1
+ def list = slurper.parse(new URL("http://twitter.com/statuses/friends/${user.screen_name}.xml").openStream())
+ while (list.length) {
+ list.user.collect(friends) {it}
+ page++
+ try {
+ list = slurper.parse("http://twitter.com/statuses/friends/${user.screen_name}.xml&page=$page")
+ } catch (Exception e) { break }
+ }
+ }
+ withStatus("Loading Friends Images") {
+ return friends.each {
+ loadImage(it.profile_image_url as String)
+ }
+ }
+ }
+
+ def getFriendsTimeline() {
+ getFriendsTimeline(user)
+ }
+
+ def getFriendsTimeline(String friend) {
+ getFriendsTimeline(getUser(friend))
+ }
+
+ def getFriendsTimeline(user) {
+ def timeline = []
+ withStatus("Loading Timeline") {
+ timeline = slurper.parse(
+ new URL("http://twitter.com/statuses/friends_timeline/${user.screen_name}.xml").openStream()
+ ).status.collect{it}
+ }
+ withStatus("Loading Timeline Images") {
+ return timeline.each {
+ loadImage(it.user.profile_image_url as String)
+ }
+ }
+ }
+
+ def getTweets() {
+ return getTweets(user)
+ }
+
+ def getTweets(String friend) {
+ return getTweets(getUser(frield))
+ }
+
+ def getTweets(friend) {
+ def tweets = []
+ withStatus("Loading Tweets") {
+ tweets = slurper.parse(
+ new URL("http://twitter.com/statuses/user_timeline/${friend.screen_name}.xml").openStream()
+ ).status.collect{it}
+ }
+ withStatus("Loading Tweet Images") {
+ return tweets.each {
+ loadImage(it.user.profile_image_url as String)
+ }
+ }
+ }
+
+ def getUser(String screen_name) {
+ withStatus("Loading User $screen_name") {
+ if (screen_name.contains('@')) {
+ return slurper.parse(
+ new URL("http://twitter.com/users/show.xml?email=${screen_name}").openStream()
+ )
+ } else {
+ return slurper.parse(
+ new URL("http://twitter.com/users/show/${screen_name}.xml").openStream()
+ )
+ }
+ }
+ }
+
+ def tweet(message) {
+ withStatus("Tweeting") {
+ def urlConnection = new URL("http://twitter.com/statuses/update.xml").openConnection()
+ urlConnection.doOutput = true
+ urlConnection.outputStream << "status=${URLEncoder.encode(message, 'UTF-8')}"
+ return slurper.parse(urlConnection.inputStream)
+ }
+ }
+
+ // no need to read these, swing seems to cache these so the EDT won't stall
+ def loadImage(image) {
+ if (!imageMap[image]) {
+ Thread.start {imageMap[image] = new javax.swing.ImageIcon(new URL(image))}
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/greet/View.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/greet/View.groovy b/src/main/groovy/swing/greet/View.groovy
new file mode 100644
index 0000000..3f8597c
--- /dev/null
+++ b/src/main/groovy/swing/greet/View.groovy
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+/**
+ * Created by IntelliJ IDEA.
+ * User: Danno.Ferrin
+ * Date: Apr 26, 2008
+ * Time: 8:31:21 AM
+ */
+package groovy.swing.greet
+
+import java.awt.Cursor
+import java.beans.PropertyChangeListener
+import javax.swing.*
+
+lookAndFeel('nimbus', 'mac', ['metal', [boldFonts: false]])
+
+actions() {
+ loginAction = action(
+ name: 'Login',
+ enabled: bind(source: controller, sourceProperty: 'allowLogin'),
+ closure: controller.&login
+ )
+
+ filterTweets = action(
+ name: 'Filter',
+ enabled: bind(source: controller, sourceProperty: 'allowSelection'),
+ closure: controller.&filterTweets
+ )
+
+ userSelected = action(
+ name: 'Select User',
+ enabled: bind(source: controller, sourceProperty: 'allowSelection'),
+ closure: controller.&userSelected
+ )
+
+ tweetAction = action(
+ name: 'Update',
+ enabled: bind(source: controller, sourceProperty: 'allowTweet'),
+ closure: controller.&tweet
+ )
+}
+
+tweetLineFont = new java.awt.Font("Ariel", 0, 12)
+tweetLine = panel(border: emptyBorder(3), preferredSize:[250,84]) {
+ gridBagLayout()
+ tweetIcon = label(verticalTextPosition:SwingConstants.BOTTOM,
+ horizontalTextPosition:SwingConstants.CENTER,
+ //anchor: BASELINE, insets: [3, 3, 3, 3])
+ anchor: CENTER, insets: [3, 3, 3, 3])
+ tweetText = textArea(rows: 4, lineWrap: true, wrapStyleWord: true,
+ opaque: false, editable: false, font: tweetLineFont,
+ gridwidth: REMAINDER, weightx: 1.0, fill: BOTH, insets: [3, 3, 3, 3])
+}
+tweetRenderer = {list, tweet, index, isSelected, isFocused ->
+ if (tweet?.user as String) {
+ tweetIcon.icon = controller.api.imageMap[tweet.user.profile_image_url as String]
+ tweetIcon.text = tweet.user.screen_name
+ tweetText.text = tweet.text
+ } else if (tweet?.text as String) {
+ tweetIcon.icon = controller.api.imageMap[tweet.parent().profile_image_url as String]
+ tweetIcon.text = tweet.parent().screen_name
+ tweetText.text = tweet.text
+ } else {
+ tweetIcon.icon = null
+ tweetIcon.text = null
+ tweetText.text = null
+ }
+ tweetLine
+} as ListCellRenderer
+
+
+userCell = label(border: emptyBorder(3))
+userCellRenderer = {list, user, index, isSelected, isFocused ->
+ if (user) {
+ userCell.icon = controller.api.imageMap[user.profile_image_url as String]
+ userCell.text = "<html>$user.screen_name<br>$user.name<br>$user.location<br>"
+ } else {
+ userCell.icon = null
+ userCell.text = null
+ }
+ userCell
+} as ListCellRenderer
+
+greetFrame = frame(title: "Greet - A Groovy Twitter Client",
+ defaultCloseOperation: javax.swing.JFrame.DISPOSE_ON_CLOSE, size: [320, 480],
+ locationByPlatform:true)
+{
+ panel(cursor: bind(source: controller, sourceProperty: 'allowSelection',
+ converter: {it ? null : Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)})
+ ) {
+
+ gridBagLayout()
+ users = comboBox(renderer: userCellRenderer, action: userSelected,
+ gridwidth: REMAINDER, insets: [6, 6, 3, 6], fill: HORIZONTAL)
+ label('Search:', insets: [3, 6, 3, 3])
+ searchField = textField(columns: 20, action: filterTweets,
+ insets: [3, 3, 3, 3], weightx: 1.0, fill: BOTH)
+ button(action: filterTweets,
+ gridwidth: REMAINDER, insets: [3, 3, 3, 6], fill:HORIZONTAL)
+ tabbedPane(gridwidth: REMAINDER, weighty: 1.0, fill: BOTH) {
+ scrollPane(title: 'Timeline') {
+ timelineList = list(visibleRowCount: 20, cellRenderer: tweetRenderer)
+ }
+ scrollPane(title: 'Tweets') {
+ tweetList = list(visibleRowCount: 20, cellRenderer: tweetRenderer)
+ }
+ scrollPane(title: 'Statuses') {
+ statusList = list(visibleRowCount: 20, cellRenderer: tweetRenderer)
+ }
+ // add data change listeners
+ [timeline:timelineList, tweets:tweetList, statuses:statusList].each {p, w ->
+ controller.addPropertyChangeListener(p,
+ {evt -> w.listData = evt.newValue as Object[]} as PropertyChangeListener
+ )
+ }
+ }
+ separator(fill: HORIZONTAL, gridwidth: REMAINDER)
+ tweetBox = textField(action:tweetAction,
+ fill:BOTH, weightx:1.0, insets:[3,3,3,3], gridwidth:2)
+ tweetButton = button(tweetAction,
+ enabled:bind(source:tweetBox, sourceProperty:'text', converter:{it.length() < 140}),
+ gridwidth:REMAINDER, insets:[3,3,3,3])
+ separator(fill: HORIZONTAL, gridwidth: REMAINDER)
+ statusLine = label(text: bind(source: controller.api, sourceProperty: 'status'),
+ gridwidth: REMAINDER, insets: [3, 6, 3, 6], anchor: WEST
+ )
+ }
+
+
+ loginDialog = dialog(
+ title: "Login to Greet", pack: true, resizable: false,
+ defaultCloseOperation: WindowConstants.DISPOSE_ON_CLOSE,
+ locationByPlatform:true)
+ {
+ panel(border: emptyBorder(3),
+ cursor: bind(source: controller, sourceProperty: 'allowLogin',
+ converter: {it ? null : Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)})
+ ) {
+ gridBagLayout()
+ label("Username:",
+ anchor: EAST, insets: [3, 3, 3, 3])
+ twitterNameField = textField(action:loginAction, columns: 20,
+ gridwidth: REMAINDER, insets: [3, 3, 3, 3])
+ label("Password:",
+ anchor: EAST, insets: [3, 3, 3, 3])
+ twitterPasswordField = passwordField(action:loginAction, columns: 20,
+ gridwidth: REMAINDER, insets: [3, 3, 3, 3])
+ panel()
+ button(loginAction, defaultButton: true,
+ anchor: EAST, insets: [3, 3, 3, 3])
+ }
+ }
+}
+
+controller.addPropertyChangeListener("friends", {evt ->
+ view.edt { users.model = new DefaultComboBoxModel(evt.newValue as Object[]) }
+} as PropertyChangeListener)
+
+new Timer(120000, filterTweets).start()
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/timelog/TimeLogMain.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/timelog/TimeLogMain.groovy b/src/main/groovy/swing/timelog/TimeLogMain.groovy
new file mode 100644
index 0000000..31acefa
--- /dev/null
+++ b/src/main/groovy/swing/timelog/TimeLogMain.groovy
@@ -0,0 +1,46 @@
+/*
+ * 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 groovy.swing.timelog
+
+import groovy.swing.SwingBuilder
+
+SwingBuilder swing = new SwingBuilder();
+swing.lookAndFeel('system')
+
+swing.model = new TimeLogModel()
+
+swing.actions() {
+ action(name:'Start', id:'startAction') {
+ stopButton.requestFocusInWindow()
+ doOutside {
+ model.startRecording(tfClient.text)
+ }
+ }
+ action(name:'Stop', id:'stopAction') {
+ doOutside {
+ model.stopRecording();
+ clientsTable.revalidate()
+ }
+ }
+}
+
+frame = swing.build(TimeLogView)
+frame.pack()
+frame.show()
+
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/timelog/TimeLogModel.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/timelog/TimeLogModel.groovy b/src/main/groovy/swing/timelog/TimeLogModel.groovy
new file mode 100644
index 0000000..bb93772
--- /dev/null
+++ b/src/main/groovy/swing/timelog/TimeLogModel.groovy
@@ -0,0 +1,62 @@
+/*
+ * 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 groovy.swing.timelog
+
+import groovy.beans.Bindable
+
+class TimeLogRow {
+ String client
+ long start
+ long stop
+
+ long getDuration() {
+ return stop - start
+ }
+}
+
+class TimeLogModel {
+
+ String currentClient
+ long currentStart
+ List<TimeLogRow> entries = []
+
+ @Bindable boolean running
+ @Bindable long elapsedTime
+
+ public synchronized startRecording(String client) {
+ if (running) throw new RuntimeException("Currently Running")
+ currentClient = client
+ currentStart = System.currentTimeMillis()
+ setRunning(true)
+
+ while (running) {
+ setElapsedTime(System.currentTimeMillis() - currentStart)
+ this.wait(1000)
+ }
+ }
+
+ public synchronized stopRecording() {
+ if (!running) throw new RuntimeException("Not Running")
+ setRunning(false)
+ this.notifyAll()
+ entries.add(new TimeLogRow(client:currentClient, start:currentStart, stop:System.currentTimeMillis()))
+ }
+
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/swing/timelog/TimeLogView.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/swing/timelog/TimeLogView.groovy b/src/main/groovy/swing/timelog/TimeLogView.groovy
new file mode 100644
index 0000000..91f711d
--- /dev/null
+++ b/src/main/groovy/swing/timelog/TimeLogView.groovy
@@ -0,0 +1,67 @@
+/*
+ * 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 groovy.swing.timelog
+
+import java.text.SimpleDateFormat
+import javax.swing.JFrame
+import java.awt.Font
+import java.awt.Color
+
+SimpleDateFormat timeFormat = new SimpleDateFormat('HH:mm:ss')
+timeFormat.setTimeZone(TimeZone.getTimeZone('GMT'))
+SimpleDateFormat dateFormat = new SimpleDateFormat('dd MMM yyyy HH:mm:ss')
+def convertTime = {it -> timeFormat.format new Date(it) }
+def convertDate = {it -> dateFormat.format new Date(it) }
+
+frame(title: 'Time Log Demo',
+ defaultCloseOperation : JFrame.EXIT_ON_CLOSE)
+{
+ gridBagLayout()
+
+ label('Client:', insets:[6,6,3,3])
+ textField('', id: 'tfClient',
+ enabled: bind( source: model, sourceProperty: 'running', converter: {!it} ),
+ gridwidth: REMAINDER, fill: HORIZONTAL, insets: [6,3,3,6])
+
+ label('00:00:00', font: new Font('Ariel', Font.BOLD, 42),
+ foreground: bind(source: model, sourceProperty: 'running', converter: {it ? Color.GREEN : Color.RED}),
+ text: bind(source: model, sourceProperty: 'elapsedTime', converter: convertTime),
+ gridwidth: 2, gridheight: 2, anchor: EAST, weightx: 1.0, insets: [3,6,3,3])
+ button(startAction, id: 'startButton',
+ enabled: bind(source: model, sourceProperty: 'running', converter: {!it}),
+ gridwidth: REMAINDER, insets: [3,3,3,6])
+ button(stopAction, id: 'stopButton',
+ enabled: bind(source: model, sourceProperty: 'running'),
+ gridwidth: REMAINDER, insets: [3,3,3,6])
+
+ separator(gridwidth: REMAINDER, fill: HORIZONTAL, insets: [9,6,9,6])
+
+ scrollPane(minimumSize: [100, 100],
+ gridwidth: REMAINDER, weighty: 1.0, fill: BOTH, insets: [3,6,6,6])
+ {
+ table(id: 'clientsTable') {
+ tableModel(list: model.entries) {
+ propertyColumn(header: 'Client', propertyName: 'client')
+ closureColumn( header: 'Start', read: {convertDate it.start})
+ closureColumn( header: 'Stop', read: {convertDate it.stop})
+ closureColumn( header: 'Duration', read: {convertTime it.stop - it.start})
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/CompiledAtASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/CompiledAtASTTransformation.groovy b/src/main/groovy/transforms/global/CompiledAtASTTransformation.groovy
new file mode 100644
index 0000000..f94e444
--- /dev/null
+++ b/src/main/groovy/transforms/global/CompiledAtASTTransformation.groovy
@@ -0,0 +1,66 @@
+/*
+ * 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 transforms.global
+
+import org.codehaus.groovy.ast.*
+import org.codehaus.groovy.transform.*
+import org.codehaus.groovy.control.*
+import org.codehaus.groovy.ast.expr.*
+import org.codehaus.groovy.ast.stmt.*
+import java.lang.annotation.*
+import org.codehaus.groovy.ast.builder.AstBuilder
+
+/**
+* This ASTTransformation adds a static getCompiledTime() : String method to every class.
+*
+* @author Hamlet D'Arcy
+*/
+@GroovyASTTransformation(phase=CompilePhase.CONVERSION)
+public class CompiledAtASTTransformation implements ASTTransformation {
+
+ private static final compileTime = new Date().toString()
+
+ public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
+
+ List classes = sourceUnit.ast?.classes
+ classes?.each { ClassNode clazz ->
+ clazz.addMethod(makeMethod())
+ }
+ }
+
+ /**
+ * OpCodes should normally be referenced, but in a standalone example I don't want to have to include
+ * the jar at compile time.
+ */
+ MethodNode makeMethod() {
+ def ast = new AstBuilder().buildFromSpec {
+ method('getCompiledTime', /*OpCodes.ACC_PUBLIC*/1 | /*OpCodes.ACC_STATIC*/8, String) {
+ parameters {}
+ exceptions {}
+ block {
+ returnStatement {
+ constant(compileTime)
+ }
+ }
+ annotations {}
+ }
+ }
+ ast[0]
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/CompiledAtExample.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/CompiledAtExample.groovy b/src/main/groovy/transforms/global/CompiledAtExample.groovy
new file mode 100644
index 0000000..dffbf4f
--- /dev/null
+++ b/src/main/groovy/transforms/global/CompiledAtExample.groovy
@@ -0,0 +1,33 @@
+/*
+ * 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 transforms.global
+
+/**
+* Demonstrates how a global transformation works.
+*
+* @author Hamlet D'Arcy
+*/
+
+println 'Script compiled at: ' + compiledTime
+
+class MyClass {
+
+}
+
+println 'Class compiled at: ' + MyClass.compiledTime
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/CompiledAtIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/CompiledAtIntegrationTest.groovy b/src/main/groovy/transforms/global/CompiledAtIntegrationTest.groovy
new file mode 100644
index 0000000..1f03f39
--- /dev/null
+++ b/src/main/groovy/transforms/global/CompiledAtIntegrationTest.groovy
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+import transforms.global.CompiledAtASTTransformation
+import org.codehaus.groovy.ast.*
+import org.codehaus.groovy.transform.*
+import org.codehaus.groovy.control.*
+import org.codehaus.groovy.tools.ast.*
+
+/**
+* This shows how to use the TransformTestHelper to test
+* a global transformation. It is a little hard to invoke
+* because the CompiledAtASTTransformation must be on the
+* classpath but the JAR containing the transform must not
+* or the transform gets applied twice.
+*
+* @author Hamlet D'Arcy
+*/
+def transform = new CompiledAtASTTransformation()
+def phase = CompilePhase.CONVERSION
+def helper = new TransformTestHelper(transform, phase)
+def clazz = helper.parse(' class MyClass {} ' )
+assert clazz.getCompiledTime() != null
+println 'compiled at' + clazz.getCompiledTime()
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/LoggingASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/LoggingASTTransformation.groovy b/src/main/groovy/transforms/global/LoggingASTTransformation.groovy
new file mode 100644
index 0000000..c6a2903
--- /dev/null
+++ b/src/main/groovy/transforms/global/LoggingASTTransformation.groovy
@@ -0,0 +1,73 @@
+/*
+ * 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 transforms.global
+
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.GroovyASTTransformation
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import java.lang.annotation.Annotation
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+
+/**
+* This ASTTransformation adds a start and stop message to every single method call.
+*
+* @author Hamlet D'Arcy
+*/
+@GroovyASTTransformation(phase=CompilePhase.CONVERSION)
+public class LoggingASTTransformation implements ASTTransformation {
+
+
+ public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
+ List methods = sourceUnit.getAST()?.getMethods()
+ methods?.each { MethodNode method ->
+ Statement startMessage = createPrintlnAst("Starting $method.name")
+ Statement endMessage = createPrintlnAst("Ending $method.name")
+
+ List existingStatements = method.getCode().getStatements()
+ existingStatements.add(0, startMessage)
+ existingStatements.add(endMessage)
+ }
+ }
+
+ /**
+ * Creates the AST for a println invocation.
+ */
+ private Statement createPrintlnAst(String message) {
+ return new ExpressionStatement(
+ new MethodCallExpression(
+ new VariableExpression("this"),
+ new ConstantExpression("println"),
+ new ArgumentListExpression(
+ new ConstantExpression(message)
+ )
+ )
+ )
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/LoggingExample.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/LoggingExample.groovy b/src/main/groovy/transforms/global/LoggingExample.groovy
new file mode 100644
index 0000000..2d9f38e
--- /dev/null
+++ b/src/main/groovy/transforms/global/LoggingExample.groovy
@@ -0,0 +1,48 @@
+/*
+ * 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 transforms.global
+
+/**
+* Demonstrates how a global transformation works.
+*
+* @author Hamlet D'Arcy
+*/
+
+def greet() {
+ println "Hello World"
+}
+
+// this prints out Hello World along with the extra compile time logging
+greet()
+
+
+//
+// The rest of this script is asserting that this all works correctly.
+//
+
+// redirect standard out so we can make assertions on it
+def standardOut = new ByteArrayOutputStream();
+System.setOut(new PrintStream(standardOut));
+
+greet()
+def result = standardOut.toString("ISO-8859-1").split('\n')
+assert "Starting greet" == result[0].trim()
+assert "Hello World" == result[1].trim()
+assert "Ending greet" == result[2].trim()
+standardOut.close()
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/META-INF/services/org.codehaus.groovy.transform.ASTTransformation b/src/main/groovy/transforms/global/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
new file mode 100644
index 0000000..2de1e18
--- /dev/null
+++ b/src/main/groovy/transforms/global/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
@@ -0,0 +1,17 @@
+# 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.
+
+transforms.global.LoggingASTTransformation
+transforms.global.CompiledAtASTTransformation
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/build.xml
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/build.xml b/src/main/groovy/transforms/global/build.xml
new file mode 100644
index 0000000..66d16c3
--- /dev/null
+++ b/src/main/groovy/transforms/global/build.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!--
+
+ 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.
+
+-->
+<project name="groovy-global-ast-transformation-example" default="jar-transform">
+
+ <!-- necessary groovy jars are assumed to be on your classpath. -->
+ <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" />
+
+ <target name="init" description="cleanup old class files">
+ <delete dir="examples"/>
+ <delete>
+ <fileset dir="." includes="**/*.jar"/>
+ </delete>
+ </target>
+
+ <target name="compile-transform" depends="init" description="Compiles the AST Transformation">
+
+ <groovyc destdir="."
+ srcdir="."
+ includes="*Transformation.groovy"
+ listfiles="true">
+ </groovyc>
+
+ </target>
+
+ <target name="jar-transform" depends="compile-transform" description="Creates a .jar file for the global transform" >
+ <jar destfile="LoggingTransform.jar"
+ basedir="."
+ includes="**/*.class,META-INF/**" />
+
+ <echo>You can now run "groovy -cp LoggingTransform.jar LoggingExample.groovy" or "groovy -cp LoggingTransform.jar CompiledAtExample.groovy" to see that the transformation worked.</echo>
+ </target>
+</project>
+
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/global/readme.txt
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/global/readme.txt b/src/main/groovy/transforms/global/readme.txt
new file mode 100644
index 0000000..e774984
--- /dev/null
+++ b/src/main/groovy/transforms/global/readme.txt
@@ -0,0 +1,48 @@
+====
+ 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.
+====
+
+Global AST Transformation Example
+
+This example shows how to wire together a global transformation.
+
+The example requires ant in your path and the Groovy 1.6 (or greater)
+Jar in your classpath. The current directory must *not* be on your
+classpath, otherwise ant will try to read the META-INF directory and
+apply the transformations prematurely.
+
+To build the example run "ant" from the current directory. The default
+target will compile the classes needed. The last step of the build
+script prints out the command needed to run the example.
+
+To run the first example perform the following from the command line:
+ groovy -cp LoggingTransform.jar LoggingExample.groovy
+
+The example should print:
+ Starting greet
+ Hello World
+ Ending greet
+
+To run the second example perform the following from the command line:
+ groovy -cp LoggingTransform.jar CompiledAtExample.groovy
+
+The example should print:
+ Scripted compiled at: [recently]
+ Class compiled at: [recently]
+
+No exceptions should occur.
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/local/LoggingASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/local/LoggingASTTransformation.groovy b/src/main/groovy/transforms/local/LoggingASTTransformation.groovy
new file mode 100644
index 0000000..bd19b95
--- /dev/null
+++ b/src/main/groovy/transforms/local/LoggingASTTransformation.groovy
@@ -0,0 +1,74 @@
+/*
+ * 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 transforms.local
+
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.GroovyASTTransformation
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.stmt.Statement
+
+/**
+* This transformation finds all the methods defined in a script that have
+* the @WithLogging annotation on them, and then weaves in a start and stop
+* message that is logged using println.
+*
+* @author Hamlet D'Arcy
+*/
+@GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
+public class LoggingASTTransformation implements ASTTransformation {
+
+ public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
+ List methods = sourceUnit.getAST()?.getMethods()
+ // find all methods annotated with @WithLogging
+ methods.findAll { MethodNode method ->
+ method.getAnnotations(new ClassNode(WithLogging))
+ }.each { MethodNode method ->
+ Statement startMessage = createPrintlnAst("Starting $method.name")
+ Statement endMessage = createPrintlnAst("Ending $method.name")
+
+ List existingStatements = method.getCode().getStatements()
+ existingStatements.add(0, startMessage)
+ existingStatements.add(endMessage)
+ }
+ }
+
+ /**
+ * This creates the ASTNode for a println statement.
+ */
+ private Statement createPrintlnAst(String message) {
+ return new ExpressionStatement(
+ new MethodCallExpression(
+ new VariableExpression("this"),
+ new ConstantExpression("println"),
+ new ArgumentListExpression(
+ new ConstantExpression(message)
+ )
+ )
+ )
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/local/LoggingExample.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/local/LoggingExample.groovy b/src/main/groovy/transforms/local/LoggingExample.groovy
new file mode 100644
index 0000000..4d47a64
--- /dev/null
+++ b/src/main/groovy/transforms/local/LoggingExample.groovy
@@ -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 transforms.local
+
+/**
+* Demonstrates how a local transformation works.
+*
+* @author Hamlet D'Arcy
+*/
+
+def greet() {
+ println "Hello World"
+}
+
+@WithLogging //this should trigger extra logging
+def greetWithLogging() {
+ println "Hello World"
+}
+
+// this prints out a simple Hello World
+greet()
+
+// this prints out Hello World along with the extra compile time logging
+greetWithLogging()
+
+
+//
+// The rest of this script is asserting that this all works correctly.
+//
+
+// redirect standard out so we can make assertions on it
+def standardOut = new ByteArrayOutputStream();
+System.setOut(new PrintStream(standardOut));
+
+greet()
+assert "Hello World" == standardOut.toString("ISO-8859-1").trim()
+
+// reset standard out and redirect it again
+standardOut.close()
+standardOut = new ByteArrayOutputStream();
+System.setOut(new PrintStream(standardOut));
+
+greetWithLogging()
+def result = standardOut.toString("ISO-8859-1").split('\n')
+assert "Starting greetWithLogging" == result[0].trim()
+assert "Hello World" == result[1].trim()
+assert "Ending greetWithLogging" == result[2].trim()
+
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/local/WithLogging.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/local/WithLogging.groovy b/src/main/groovy/transforms/local/WithLogging.groovy
new file mode 100644
index 0000000..03611f2
--- /dev/null
+++ b/src/main/groovy/transforms/local/WithLogging.groovy
@@ -0,0 +1,37 @@
+/*
+ * 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 transforms.local
+import java.lang.annotation.Retention
+import java.lang.annotation.Target
+import org.codehaus.groovy.transform.GroovyASTTransformationClass
+import java.lang.annotation.ElementType
+import java.lang.annotation.RetentionPolicy
+
+/**
+* This is just a marker interface that will trigger a local transformation.
+* The 3rd Annotation down is the important one: @GroovyASTTransformationClass
+* The parameter is the String form of a fully qualified class name.
+*
+* @author Hamlet D'Arcy
+*/
+@Retention(RetentionPolicy.SOURCE)
+@Target([ElementType.METHOD])
+@GroovyASTTransformationClass(["transforms.local.LoggingASTTransformation"])
+public @interface WithLogging {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/local/build.xml
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/local/build.xml b/src/main/groovy/transforms/local/build.xml
new file mode 100644
index 0000000..eef390a
--- /dev/null
+++ b/src/main/groovy/transforms/local/build.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!--
+
+ 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.
+
+-->
+<project name="groovy-local-ast-transformation-example" default="compile-transform">
+
+ <!-- necessary groovy jars are assumed to be on your classpath. -->
+ <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" />
+
+
+ <target name="init" description="cleanup old class files">
+ <delete dir="examples"/>
+ </target>
+
+ <target name="compile-transform" depends="init" description="Compiles the AST Transformation">
+
+ <groovyc destdir="."
+ srcdir="."
+ includes="LoggingASTTransformation.groovy,WithLogging.groovy"
+ listfiles="true">
+ </groovyc>
+
+ <echo>You can now run "groovy LoggingExample.groovy" to see that the transformation worked.</echo>
+ </target>
+
+</project>
+
http://git-wip-us.apache.org/repos/asf/groovy-examples/blob/3bd1e181/src/main/groovy/transforms/local/readme.txt
----------------------------------------------------------------------
diff --git a/src/main/groovy/transforms/local/readme.txt b/src/main/groovy/transforms/local/readme.txt
new file mode 100644
index 0000000..2daade2
--- /dev/null
+++ b/src/main/groovy/transforms/local/readme.txt
@@ -0,0 +1,40 @@
+====
+ 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.
+====
+
+Local AST Transformation Example
+
+This example shows how to wire together a local transformation.
+
+The example requires ant in your path and the Groovy 1.6 (or greater)
+Jar in your classpath.
+
+To build the example run "ant" from the current directory. The default
+target will compile the classes needed. The last step of the build
+script prints out the command needed to run the example.
+
+To run the example perform the following from the command line:
+ groovy LoggingExample.groovy
+
+The example should print:
+ Hello World
+ Starting greetWithLogging
+ Hello World
+ Ending greetWithLogging
+
+No exceptions should occur.
\ No newline at end of file