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
