[Commits] r1738 - in sandbox/ahocevar/playground: trunk/geoext/lib trunk/geoext/lib/GeoExt trunk/geoext/lib/GeoExt/data trunk/geoext/lib/GeoExt/plugins trunk/geoext/lib/GeoExt/widgets trunk/geoext/lib/GeoExt/widgets/form ux/Printing/build ux/Printing/examples ux/Printing/resources/css ux/Printing/ux ux/Printing/ux/widgets ux/Printing/ux/widgets/form

commits at geoext.org commits at geoext.org
Wed Jan 13 12:18:51 CET 2010


Author: ahocevar
Date: 2010-01-13 12:18:51 +0100 (Wed, 13 Jan 2010)
New Revision: 1738

Added:
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintPage.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintProvider.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintPageField.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintProviderField.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/PrintMapPanel.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/PrintForm.js
   sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.html
   sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.js
   sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.html
   sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.js
   sandbox/ahocevar/playground/ux/Printing/resources/css/printing-all-debug.css
   sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css
Removed:
   sandbox/ahocevar/playground/ux/Printing/build/Printing/
   sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.html
   sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.js
   sandbox/ahocevar/playground/ux/Printing/examples/Printing.html
   sandbox/ahocevar/playground/ux/Printing/examples/Printing.js
   sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css
   sandbox/ahocevar/playground/ux/Printing/ux/data/
   sandbox/ahocevar/playground/ux/Printing/ux/plugins/
   sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintMapPanel.js
   sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/PrintForm.js
Modified:
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js
   sandbox/ahocevar/playground/ux/Printing/build/Makefile
   sandbox/ahocevar/playground/ux/Printing/ux/Printing.js
   sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintPreview.js
   sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/SimplePrint.js
Log:
restructured: SimplePrint and PrintPreview remain in the ux, the rest will be proposed for trunk.

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintPage.js (from rev 1719, sandbox/ahocevar/playground/ux/Printing/ux/data/PrintPage.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintPage.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintPage.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,321 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+Ext.namespace("GeoExt.data");
+
+/** api: (define)
+ *  module = GeoExt.data
+ *  class = PrintPage
+ *  base_link = `Ext.util.Observable <http://extjs.com/deploy/dev/docs/?class=Ext.util.Observable>`_
+ */
+
+/** api: constructor
+ *  .. class:: PrintPage
+ * 
+ *  Provides a representation of a print page for
+ *  :class:`GeoExt.data.PrintProvider`. The extent of the page is stored as
+ *  ``OpenLayers.Feature.Vector``. Widgets can use this to display the print
+ *  extent on the map. In addition, a handle feature is also provided, which
+ *  controls can use to modify the print extent's scale and rotation.
+ */
+GeoExt.data.PrintPage = Ext.extend(Ext.util.Observable, {
+    
+    /** api:config[printProvider]
+     * :class:`GeoExt.data.PrintProvider` The print provider to use with
+     * this page.
+     */
+    
+    /** private: property[printProvider]
+     *  :class:`GeoExt.data.PrintProvider`
+     */
+    printProvider: null,
+    
+    /** api: config[layer]
+     *  ``OpenLayers.Layer.Vector`` Optional. If provided, feature and handle
+     *  will be added to that layer.
+     */
+    
+    /** api: property[feature]
+     *  ``OpenLayers.Feature.Vector`` Feature representing the page extent.
+     *  Read-only.
+     */
+    feature: null,
+    
+    /** api: property[handle]
+     *  ``OpenLayers.Feature.Vector`` Feature providing the scale/rotation
+     *  handle for the page. Read-only.
+     */
+    handle: null,
+    
+    /** api: property[scale]
+     *  ``Ext.data.Record`` The current scale record of the page. Read-only.
+     */
+    scale: null,
+    
+    /** api: property[rotation]
+     *  ``Float`` The current rotation of the page. Read-only.
+     */
+    rotation: 0,
+    
+    /** api:config[customParams]
+     *  ``Object`` Key-value pairs of additional parameters that the
+     *  printProvider will send to the print service for this page.
+     */
+
+    /** api: property[customParams]
+     *  ``Object`` Key-value pairs of additional parameters that the
+     *  printProvider will send to the print service for this page.
+     */
+    customParams: null,
+    
+    /** private: method[constructor]
+     *  Private constructor override.
+     */
+    constructor: function(config) {
+        this.initialConfig = config;
+        Ext.apply(this, config);
+        delete this.layer;
+        
+        if(!this.customParams) {
+            this.customParams = {};
+        }
+        
+        this.addEvents(
+            /** api: events[change]
+             *  Triggered when any of the page properties have changed
+             *  
+             *  Listener arguments:
+             *  * printPage - :class:`GeoExt.data.PrintPage` this printPage
+             */
+            "change"
+        );
+
+        this.feature = new OpenLayers.Feature.Vector(
+            OpenLayers.Geometry.fromWKT("POLYGON((-1 -1,1 -1,1 1,-1 1,-1 -1))"));
+        this.handle = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Point(0,0));
+        if(config.layer) {
+            config.layer.addFeatures([this.feature, this.handle]);
+        }
+        
+        this.printProvider.on({
+            "layoutchange": this.updateByHandle,
+            scope: this
+        });
+
+        GeoExt.data.PrintPage.superclass.constructor.apply(this, arguments);
+    },
+
+    /** api: method[getCenter]
+     *  :return: ``OpenLayers.LonLat``
+     *  
+     *  Returns the current page center.
+     */
+    getCenter: function() {
+        return this.feature.geometry.getBounds().getCenterLonLat();
+    },
+    
+    /** api: method[setScale]
+     *  :param scale: ``Ext.data.Record`` The new scale record.
+     *  :param units: ``String`` map units to use for the scale calculation.
+     *      Optional if a ``layer`` that is added to a map was configured.
+     *      If neither is provided, "dd" will be assumed.
+     * 
+     *  Updates the page geometry to match a given scale. Since this takes the
+     *  current layout of the printProvider into account, this can be used to
+     *  update the page geometry feature when the layout has changed.
+     */
+    setScale: function(scale, units) {
+        var bounds = this.calculatePageBounds(scale, units);
+        var geom = bounds.toGeometry();
+        var rotation = this.rotation;
+        if(rotation != 0) {
+            geom.rotate(-rotation, geom.getCentroid());
+        }
+        this.scale = scale;
+        this.updateFeature(geom);
+    },
+    
+    /** api: method[setCenter]
+     *  :param scale: ``OpenLayers.LonLat`` The new center.
+     * 
+     *  Moves the page geometry to a new center.
+     */
+    setCenter: function(center) {
+        var geom = this.feature.geometry;
+        var oldCenter = geom.getBounds().getCenterLonLat();
+        var dx = center.lon - oldCenter.lon;
+        var dy = center.lat - oldCenter.lat;
+        geom.move(dx, dy);
+        this.updateFeature(geom);
+    },
+    
+    /** api: method[setRotation]
+     *  :param rotation: ``Float`` The new rotation.
+     *  
+     *  Sets a new rotation for the page geometry.
+     */
+    setRotation: function(rotation) {
+        if(this.printProvider.layout.get("rotation") === true) {
+            var geom = this.feature.geometry;
+            geom.rotate(this.rotation - rotation, geom.getCentroid());
+            this.rotation = rotation;
+            this.updateFeature(geom);
+        }
+    },
+    
+    /** api: method[fitPage]
+     *  :param map: ``OpenLayers.Map`` The map to fit the page to.
+     *  :param loose: ``Boolean`` If set to true, the print extent will
+     *      be at least as large as the visible map extent. Default is false.
+     * 
+     *  Fits the page layout to the current map extent, using the smallest
+     *  scale that entirely fits the extent.
+     */
+    fitPage: function(map, loose) {
+        this.suspendEvents();
+        this.setCenter(map.getCenter());
+        this.resumeEvents();
+        var extent = map.getExtent();
+        var units = map.baseLayer.units;
+        var scale, looseScale, contains;
+        this.printProvider.scales.each(function(rec) {
+            looseScale = scale || rec;
+            scale = rec;
+            contains = extent.containsBounds(
+                this.calculatePageBounds(scale, units));
+            return !contains
+        }, this);
+        this.setScale(loose && contains ? looseScale : scale, units);
+    },
+
+    /** api: method[updateByHandle]
+     *  :param updateHandle: ``Boolean`` If set to false, the handle location
+     *      will not be aligned with the feature after updating. Default is
+     *      true.
+     *  
+     *  Updates scale and rotation based on the current handle location. This
+     *  method is useful for drag handlers on the handle geometry, when
+     *  displayed on a layer.
+     */
+    updateByHandle: function(updateHandle) {
+        var f = this.feature;
+        
+        var rotation = 0;
+        if(this.printProvider.layout.get("rotation") === true) {
+            var hLoc = this.handle.geometry.getBounds().getCenterLonLat();
+            var center = f.geometry.getBounds().getCenterLonLat();
+            var dx = hLoc.lon - center.lon;
+            var dy = hLoc.lat - center.lat;
+            rotation = Math.round(Math.atan2(dx, dy) * 180 / Math.PI);
+        }
+
+        var geom = this.handle.geometry;
+        var dist = f.geometry.getCentroid().distanceTo(geom);
+        var scaleFits = [], distHash = {};
+        this.printProvider.scales.each(function(rec){
+            var bounds = this.calculatePageBounds(rec);
+            var d = Math.abs((bounds.getHeight() / 2) - dist);
+            scaleFits.push(d);
+            distHash[d.toPrecision(8)] = rec;
+        }, this);
+        var min = scaleFits.concat().sort(function(a,b){return a<b?-1:1;})[0];
+        var scale = distHash[min.toPrecision(8)];
+        
+        var bounds = this.calculatePageBounds(scale);
+        var geom = bounds.toGeometry();
+        geom.rotate(-rotation, geom.getCentroid());
+        
+        this.scale = scale;
+        this.rotation = rotation;
+        this.updateFeature(geom, updateHandle);
+    },
+
+    /** private: method[updateFeature]
+     *  :param geometry: ``OpenLayers.Geometry`` New geometry for the feature.
+     *      If not provided, the existing geometry will be left unchanged.
+     *  :param updateHandle: ``Boolean`` If set to false, only the feature
+     *      will be updated, but the handle will not be aligned. Defaults to
+     *      true.
+     *      
+     *  Updates the page feature with a new geometry and aligns the handle
+     *  with it.
+     */
+    updateFeature: function(geometry, updateHandle) {
+        var f = this.feature;
+        geometry.id = f.geometry.id;
+        f.geometry = geometry;
+        f.layer && f.layer.drawFeature(f);
+        
+        if(updateHandle !== false) {
+            this.updateHandle();
+        }
+        this.fireEvent("change", this);
+    },
+    
+    /** api: method[updateHandle]
+     *  Updates the handle position to align with the page feature.
+     */
+    updateHandle: function() {
+        var f = this.feature;
+        var h = this.handle;
+        var hLoc = this.calculateHandleLocation();
+        var geom = new OpenLayers.Geometry.Point(hLoc.lon, hLoc.lat);
+        geom.id = h.geometry.id;
+        h.geometry = geom;
+        h.layer && h.layer.drawFeature(h);
+    },
+    
+    /** private: method[calculateHandleLocation]
+     *  :return: ``OpenLayers.LonLat`` The location of the scale/rotation
+     *      handle.
+     *  
+     *  Calculates the position of the scale/rotation handle to align with the
+     *  page feature.
+     */
+    calculateHandleLocation: function() {
+        var c = this.feature.geometry.components[0].components;
+        var top = new OpenLayers.Geometry.LineString([c[2], c[3]]);
+        return top.getBounds().getCenterLonLat();
+    },
+
+    /** private: method[calculatePageBounds]
+     *  :param scale: ``Ext.data.Record`` Scale record to calculate the page
+     *      bounds for.
+     *  :param units: ``String`` map units to use for the scale calculation.
+     *      Optional if a ``layer`` that is added to a map was configured. If
+     *      neither is provided, "dd" will be assumed.
+     *  :return: ``OpenLayers.Bounds``
+     *  
+     *  Calculates the page bounds for a given scale.
+     */
+    calculatePageBounds: function(scale, units) {
+        var s = scale.get("value");
+        var f = this.feature;
+        var geom = this.feature.geometry;
+        var center = geom.getBounds().getCenterLonLat();
+
+        var size = this.printProvider.layout.get("size");
+        var units = units ||
+            (f.layer && f.layer.map && f.layer.map.baseLayer.units) ||
+            "dd";
+        var unitsRatio = OpenLayers.INCHES_PER_UNIT[units];
+        var w = size.width / 72 / unitsRatio * s / 2;
+        var h = size.height / 72 / unitsRatio * s / 2;
+        
+        return new OpenLayers.Bounds(center.lon - w, center.lat - h,
+            center.lon + w, center.lat + h);
+    },
+    
+    /** private: method[destroy]
+     */
+    destroy: function() {
+        this.printProvider.un("layoutchange", this.updateByHandle, this);
+        GeoExt.data.PrintPage.superclass.destroy.apply(this, arguments);
+    }
+
+});
\ No newline at end of file

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintProvider.js (from rev 1712, sandbox/ahocevar/playground/ux/Printing/ux/data/PrintProvider.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintProvider.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/data/PrintProvider.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,578 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+Ext.namespace("GeoExt.data");
+
+/** api: (define)
+ *  module = GeoExt.data
+ *  class = PrintProvider
+ *  base_link = `Ext.util.Observable <http://extjs.com/deploy/dev/docs/?class=Ext.util.Observable>`_
+ */
+
+/** api: example
+ *  Minimal code to print as much of the current map extent as possible as
+ *  soon as the print service capabilities are loaded:
+ * 
+ *  .. code-block:: javascript
+ *     
+ *      var printProvider = new GeoExt.data.PrintProvider({
+ *          url: "/geoserver/pdf",
+ *          listeners: {
+ *              "loadcapabilities": function() {
+ *                  var printPage = new GeoExt.data.PrintPage({
+ *                      printProvider: printProvider
+ *                  });
+ *                  printPage.fitPage(map);
+ *                  printProvider.print(map, [printPage]);
+ *              }
+ *          }
+ *      });
+ */
+
+/** api: constructor
+ *  .. class:: PrintProvider
+ * 
+ *  Provides an interface to a Mapfish or GeoServer print module.
+ */
+GeoExt.data.PrintProvider = Ext.extend(Ext.util.Observable, {
+    
+    /** api: config[url]
+     *  ``String`` Base url of the print service. Only required if
+     *  :ref:`GeoExt.data.PrintProvider.capabilities` is not provided. This
+     *  is usually something like ``http://path/to/mapfish/print`` for Mapfish,
+     *  and ``http://path/to/geoserver/pdf`` for GeoServer with the printing
+     *  extension installed. This property requires that the print service is
+     *  at the same origin as the application (or accessible via proxy).
+     */
+    
+    /** private:  property[url]
+     *  ``String`` Base url of the print service. Will always have a trailing
+     *  "/".
+     */
+    url: null,
+    
+    /** api: config[capabilities]
+     *  ``Object`` Capabilities of the print service. Only required if
+     *  :ref:`GeoExt.data.PrintProvider.url` is not provided. This is the
+     *  object returned by the ``info.json`` endpoint of the print service,
+     *  and is usually obtained by including a script tag pointing to
+     *  ``http://path/to/printservice/info.json?var=myvar`` in the head of the
+     *  html document, making the capabilities accessible as ``window.myvar``.
+     *  This property should be used when no local print service or proxy is
+     *  available, or when you do not listen for the ``loadcapabilities``
+     *  events before creating components that require the PrintProvider's
+     *  capabilities to be available.
+     */
+    
+    /** private: property[capabilities]
+     *  ``Object`` Capabilities as returned from the print service.
+     */
+    capabilities: null,
+    
+    /** api: config[method]
+     *  ``String`` Either ``POST`` or ``GET`` (case-sensitive). Method to use
+     *  when sending print requests to the servlet. If the print service is at
+     *  the same origin as the application (or accessible via proxy), then
+     *  ``POST`` is recommended. Use ``GET`` when accessing a remote print
+     *  service with no proxy available, but expect issues with character
+     *  encoding and URLs exceeding the maximum length. Default is ``POST``.
+     */
+    
+    /** private: property[method]
+     *  ``String`` Either ``POST`` or ``GET`` (case-sensitive). Method to use
+     *  when sending print requests to the servlet.
+     */
+    method: "POST",
+
+    /** api: config[customParams]
+     *  ``Object`` Key-value pairs of custom data to be sent to the print
+     *  service. Optional. This is e.g. useful for complex layout definitions
+     *  on the server side that require additional parameters.
+     */
+    
+    /** api: property[customParams]
+     *  ``Object`` Key-value pairs of custom data to be sent to the print
+     *  service. Optional. This is e.g. useful for complex layout definitions
+     *  on the server side that require additional parameters.
+     */
+    customParams: null,
+    
+    /** api: property[scales]
+     *  ``Ext.data.JsonStore`` read-only. A store representing the scales
+     *  available.
+     *  
+     *  Record fields:
+     *  * name - ``String`` the name of the scale
+     *  * value - ``Float`` the scale denominator
+     */
+    scales: null,
+    
+    /** api: property[dpis]
+     *  ``Ext.data.JsonStore`` read-only. A store representing the dpis
+     *  available.
+     *  
+     *  Record fields:
+     *  * name - ``String`` the name of the dpi
+     *  * value - ``Float`` the dots per inch
+     */
+    dpis: null,
+        
+    /** api: property[layouts]
+     *  ``Ext.data.JsonStore`` read-only. A store representing the layouts
+     *  available.
+     *  
+     *  Records fields:
+     *  * name - ``String`` the name of the layout
+     *  * size - ``Object`` width and height of the map in points
+     *  * rotation - ``Boolean`` indicates if rotation is supported
+     */
+    layouts: null,
+    
+    /** api: property[dpi]
+     *  ``Ext.data.Record`` the record for the currently used layout.
+     *  Read-only, use :ref:`GeoExt.data.PrintProvider.setDpi` to set the
+     *  value.
+     */
+    dpi: null,
+
+    /** api: property[layout]
+     *  ``Ext.data.Record`` the record of the currently used layout. Read-only,
+     *  use :ref:`GeoExt.data.PrintProvider.setLayout` to set the value.
+     */
+    layout: null,
+
+    /** private:  method[constructor]
+     *  Private constructor override.
+     */
+    constructor: function(config) {
+        this.initialConfig = config;
+        Ext.apply(this, config);
+        
+        if(!this.customParams) {
+            this.customParams = {};
+        }
+
+        this.addEvents(
+            /** api: events[loadcapabilities]
+             *  Triggered when the capabilities have finished loading. This
+             *  event will only fire when
+             *  :ref:`GeoExt.data.PrintProvider.capabilities` is not
+             *  configured.
+             *  
+             *  Listener arguments:
+             *  * printProvider - :class:`GeoExt.data.PrintProvider` this
+             *    PrintProvider
+             *  * capabilities - ``Object`` the capabilities
+             */
+            "loadcapabilities",
+            
+            /** api: events[layoutchange]
+             *  Triggered when the layout is changed.
+             *  
+             *  Listener arguments:
+             *  * printProvider - :class:`GeoExt.data.PrintProvider` this
+             *    PrintProvider
+             *  * layout - ``Ext.data.Record`` the new layout
+             */
+            "layoutchange",
+
+            /** api: events[dpichange]
+             *  Triggered when the dpi value is changed.
+             *  
+             *  Listener arguments:
+             *  * printProvider - :class:`GeoExt.data.PrintProvider` this
+             *    PrintProvider
+             *  * dpi - ``Ext.data.Record`` the new dpi record
+             */
+            "dpichange",
+            
+            /** api: events[beforeprint]
+             *  Triggered when the print method is called.
+             *  
+             *  Listener arguments:
+             *  * printProvider - :class:`GeoExt.data.PrintProvider` this
+             *    PrintProvider
+             *  * map - ``OpenLayers.Map`` the map being printed
+             *  * pages - Array of :class:`GeoExt.data.PrintPage` the print
+             *    pages being printed
+             *  * options - ``Object`` the options to the print command
+             */
+            "beforeprint",
+            
+            /** api: events[print]
+             *  Triggered when the print document is opened.
+             *  
+             *  Listener arguments:
+             *  * printProvider - :class:`GeoExt.data.PrintProvider` this
+             *    PrintProvider
+             *  * url - ``String`` the url of the print document
+             */
+            "print"
+        );
+        
+        this.scales = new Ext.data.JsonStore({
+            root: "scales",
+            sortInfo: {field: "value", direction: "DESC"},
+            fields: ["name", {name: "value", type: "float"}]
+        });
+        
+        this.dpis = new Ext.data.JsonStore({
+            root: "dpis",
+            fields: ["name", {name: "value", type: "float"}]
+        });
+        
+        this.layouts = new Ext.data.JsonStore({
+            root: "layouts",
+            fields: [
+                "name",
+                {name: "size", mapping: "map"},
+                {name: "rotation", type: "boolean"}
+            ]
+        });
+        
+        if(config.capabilities) {
+            this.loadStores();
+        } else {
+            if(this.url.split("/").pop()) {
+                this.url += "/";            
+            }
+            this.loadCapabilities();
+        }
+
+        GeoExt.data.PrintProvider.superclass.constructor.apply(this, arguments);
+    },
+    
+    /** api: method[setLayout]
+     *  :param layout: ``Ext.data.Record`` the record of the layout.
+     *  
+     *  Sets the layout for this printProvider.
+     */
+    setLayout: function(layout) {
+        this.layout = layout;
+        this.fireEvent("layoutchange", this, layout);
+    },
+    
+    /** api: method[setDpi]
+     *  :param layout: ``Ext.data.Record`` the dpi record.
+     *  
+     *  Sets the dpi for this printProvider.
+     */
+    setDpi: function(dpi) {
+        this.dpi = dpi;
+        this.fireEvent("dpichange", this, dpi);
+    },
+
+    /** api: method[print]
+     *  :param map: ``GeoExt.MapPanel``|``OpenLayers.Map`` The map to print.
+     *  :param pages: ``Array`` of :class:`GeoExt.data.PrintPage`` pages to
+     *      print.
+     *  :param options: ``Object`` of additional options:
+     *      * ``legend``: :class:`GeoExt.LegendPanel` If provided, the legend
+     *        will be added to the print document. For this to look like in
+     *        the MapPanel, the following settings in the ``!legends`` block
+     *        of the print module are recommended:
+     *        
+     *        .. code-block:: none
+     *        
+     *          maxIconWidth: 0
+     *          maxIconHeight: 0
+     *          classIndentation: 0
+     *
+     *  Sends the print command to the print service and opens a new window
+     *  with the resulting PDF.
+     */
+    print: function(map, pages, options) {
+        if(map instanceof GeoExt.MapPanel) {
+            map = map.map;
+        }
+        options = options || {};
+        if(this.fireEvent("beforeprint", this, map, pages, options) === false) {
+            return;
+        }
+
+        var jsonData = Ext.apply({
+            units: map.baseLayer.units,
+            srs: map.baseLayer.projection.getCode(),
+            layout: this.layout.get("name"),
+            dpi: this.dpi.get("value")
+        }, this.customParams);
+
+        var pagesLayer = pages[0].feature.layer;
+        var encodedLayers = [];
+        Ext.each(map.layers, function(layer){
+            if(layer !== pagesLayer && layer.getVisibility() === true) {
+                var enc = this.encodeLayer(layer);
+                enc && encodedLayers.push(enc);
+            }
+        }, this);
+        jsonData.layers = encodedLayers;
+        
+        var encodedPages = [];
+        Ext.each(pages, function(page) {
+            var center = page.getCenter();
+            encodedPages.push(Ext.apply({
+                center: [center.lon, center.lat],
+                scale: page.scale.get("value"),
+                rotation: page.rotation
+            }, page.customParams));
+        }, this);
+        jsonData.pages = encodedPages;
+        
+        if(options.legend) {
+            var encodedLegends = [];
+            options.legend.items.each(function(cmp) {
+                if(cmp.isVisible()) {
+                    var encFn = this.encoders.legends[cmp.getXType()];
+                    encodedLegends = encodedLegends.concat(
+                        encFn.call(this, cmp));
+                }
+            }, this);
+            jsonData.legends = encodedLegends;
+        }
+
+        if(this.method === "GET") {
+            var url = this.capabilities.printURL + "?spec=" +
+                escape(Ext.encode(jsonData));
+            window.open(url);
+            this.fireEvent("print", this, url);
+        } else {
+            Ext.Ajax.request({
+                url: this.capabilities.createURL,
+                jsonData: jsonData,
+                success: function(response) {
+                    // In IE, using a Content-disposition: attachment header
+                    // may make it hard or impossible to download the pdf due
+                    // to security settings. So we'll display the pdf inline.
+                    var url = Ext.decode(response.responseText).getURL +
+                        (Ext.isIE ? "?inline=true" : "");
+                    if(Ext.isOpera || Ext.isIE) {
+                        // Make sure that Opera and IE don't replace the
+                        // content tab with the pdf
+                        window.open(url);
+                    } else {
+                        // This avoids popup blockers for all other browers
+                        window.location.href = url;                        
+                    } 
+                    this.fireEvent("print", this, url);
+                },
+                scope: this
+            });
+        }
+    },
+    
+    /** private: method[loadCapabilities]
+     */
+    loadCapabilities: function() {
+        var url = this.url + "info.json";
+        Ext.Ajax.request({
+            url: url,
+            disableCaching: false,
+            success: function(response) {
+                this.capabilities = Ext.decode(response.responseText);
+                this.loadStores();
+            },
+            scope: this
+        });
+    },
+    
+    /** private: method[loadStores]
+     */
+    loadStores: function() {
+        this.scales.loadData(this.capabilities);
+        this.dpis.loadData(this.capabilities);
+        this.layouts.loadData(this.capabilities);
+        
+        this.setLayout(this.layouts.getAt(0));
+        this.setDpi(this.dpis.getAt(0));
+        this.fireEvent("loadcapabilities", this, this.capabilities);
+    },
+        
+    /** private: method[encodeLayer]
+     *  :param layer: ``OpenLayers.Layer``
+     *  :return: ``Object``
+     * 
+     *  Encodes a layer for the print service.
+     */
+    encodeLayer: function(layer) {
+        var encLayer;
+        for(var c in this.encoders.layers) {
+            if(OpenLayers.Layer[c] && layer instanceof OpenLayers.Layer[c]) {
+                encLayer = this.encoders.layers[c].call(this, layer);
+                break;
+            }
+        }
+        // only return the encLayer object when we have a type. Prevents a
+        // fallback on base encoders like HTTPRequest.
+        return (encLayer && encLayer.type) ? encLayer : null;
+    },
+
+    /** private: method[getAbsoluteUrl]
+     *  :param url: ``String``
+     *  :return: ``String``
+     *  
+     *  Converts the provided url to an absolute url.
+     */
+    getAbsoluteUrl: function(url) {
+        var a;
+        if(Ext.isIE) {
+            a = document.createElement("<a href='" + url + "'/>");
+        } else {
+            a = document.createElement("a");
+            a.href = url;
+        }
+        return a.href;
+    },
+    
+    /** private: property[encoders]
+     *  ``Object`` Encoders for all print content
+     */
+    encoders: {
+        "layers": {
+            "WMS": function(layer) {
+                var enc = this.encoders.layers.HTTPRequest.call(this, layer);
+                Ext.apply(enc, {
+                    type: 'WMS',
+                    layers: [layer.params.LAYERS].join(",").split(","),
+                    format: layer.params.FORMAT,
+                    styles: [layer.params.STYLES].join(",").split(","),
+                    customParams: {}
+                });
+                var param;
+                for(var p in layer.params) {
+                    param = p.toLowerCase();
+                    if(!layer.DEFAULT_PARAMS[param] &&
+                    "layers,styles,width,height,srs".indexOf(param) == -1) {
+                        enc.customParams[p] = layer.params[p];
+                    }
+                }
+                return enc;
+            },
+            "OSM": function(layer) {
+                var enc = this.encoders.layers.TileCache.call(this, layer);
+                return Ext.apply(enc, {
+                    type: 'OSM',
+                    baseURL: enc.baseURL.substr(0, enc.baseURL.indexOf("$")),
+                    extension: "png"
+                });
+            },
+            "TileCache": function(layer) {
+                var enc = this.encoders.layers.HTTPRequest.call(this, layer);
+                return Ext.apply(enc, {
+                    type: 'TileCache',
+                    layer: layer.layername,
+                    maxExtent: layer.maxExtent.toArray(),
+                    tileSize: [layer.tileSize.w, layer.tileSize.h],
+                    extension: layer.extension,
+                    resolutions: layer.serverResolutions || layer.resolutions
+                });
+            },
+            "HTTPRequest": function(layer) {
+                return {
+                    baseURL: this.getAbsoluteUrl(layer.url instanceof Array ?
+                        layer.url[0] : layer.url),
+                    opacity: (layer.opacity != null) ? layer.opacity : 1.0,
+                    singleTile: layer.singleTile
+                };
+            },
+            "Image": function(layer) {
+                return {
+                    type: 'Image',
+                    baseURL: this.getAbsoluteUrl(layer.getURL(layer.extent)),
+                    opacity: (layer.opacity != null) ? layer.opacity : 1.0,
+                    extent: layer.extent.toArray(),
+                    pixelSize: [layer.size.w, layer.size.h],
+                    name: layer.name
+                };
+            },
+            "Vector": function(layer) {
+                if(!layer.features.length) {
+                    return;
+                }
+                
+                var encFeatures = [];
+                var encStyles = {};
+                var features = layer.features;
+                var featureFormat = new OpenLayers.Format.GeoJSON();
+                var styleFormat = new OpenLayers.Format.JSON();
+                var nextId = 1;
+                var styleDict = {};
+                var feature, style, dictKey, dictItem;
+                for(var i=0, len=features.length; i<len; ++i) {
+                    feature = features[i];
+                    style = feature.style || layer.style ||
+                    layer.styleMap.createSymbolizer(feature,
+                        feature.renderIntent);
+                    dictKey = styleFormat.write(style);
+                    dictItem = styleDict[dictKey];
+                    if(dictItem) {
+                        //this style is already known
+                        styleName = dictItem;
+                    } else {
+                        //new style
+                        styleDict[dictKey] = styleName = nextId++;
+                        if(style.externalGraphic) {
+                            encStyles[styleName] = Ext.applyIf({
+                                externalGraphic: this.getAbsoluteUrl(
+                                    style.externalGraphic)}, style);
+                        } else {
+                            encStyles[styleName] = style;
+                        }
+                    }
+                    var featureGeoJson = featureFormat.extract.feature.call(
+                        featureFormat, feature);
+                    
+                    featureGeoJson.properties = OpenLayers.Util.extend({
+                        _gx_style: styleName
+                    }, featureGeoJson.properties);
+                    
+                    encFeatures.push(featureGeoJson);
+                }
+                
+                return {
+                    type: 'Vector',
+                    styles: encStyles,
+                    styleProperty: '_gx_style',
+                    geoJson: {
+                        type: "FeatureCollection",
+                        features: encFeatures
+                    },
+                    name: layer.name,
+                    opacity: (layer.opacity != null) ? layer.opacity : 1.0
+                };
+            }
+        },
+        "legends": {
+            "gx_wmslegend": function(legend) {
+                var enc = this.encoders.legends.base.call(this, legend);
+                var icons = [];
+                for(var i=1, len=legend.items.getCount(); i<len; ++i) {
+                    icons.push(this.getAbsoluteUrl(legend.items.get(i).url));
+                };
+                enc[0].classes[0] = {
+                    name: "",
+                    icons: icons
+                };
+                return enc;
+            },
+            "gx_urllegend": function(legend) {
+                var enc = this.encoders.legends.base.call(this, legend);
+                enc[0].classes.push({
+                    name: "",
+                    icon: this.getAbsoluteUrl(legend.items.get(1).url)
+                });
+                return enc;
+            },
+            "base": function(legend){
+                return [{
+                    name: legend.items.get(0).text,
+                    classes: []
+                }];
+            }
+        }
+    }
+    
+});
\ No newline at end of file

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintPageField.js (from rev 1690, sandbox/ahocevar/playground/ux/Printing/ux/plugins/PrintPageField.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintPageField.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintPageField.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+Ext.namespace("GeoExt.plugins");
+
+/** api: (define)
+ *  module = GeoExt.plugins
+ *  class = PrintPageField
+ *  base_link = `Ext.util.Observable <http://extjs.com/deploy/dev/docs/?class=Ext.util.Observable>`_
+ */
+
+/** api: constructor
+ *  .. class:: PrintPageField
+ * 
+ *  A plugin for ``Ext.form.Field`` components which provides synchronization
+ *  with a :class:`GeoExt.data.PrintPage`.
+ */
+GeoExt.plugins.PrintPageField = Ext.extend(Ext.util.Observable, {
+    
+    /** api: config[page]
+     *  ``GeoExt.data.PrintPage`` The print page to synchronize with.
+     */
+
+    /** private: property[page]
+     *  ``GeoExt.data.PrintPage`` The print page to synchronize with.
+     */
+    page: null,
+    
+    /** private: property[target]
+     *  ``Ext.form.Field`` This plugin's target field.
+     */
+    target: null,
+    
+    /** private: method[constructor]
+     */
+    constructor: function(config) {
+        this.initialConfig = config;
+        Ext.apply(this, config);
+        
+        GeoExt.plugins.PrintPageField.superclass.constructor.apply(this, arguments);
+    },
+    
+    /** private: method[init]
+     *  :param target: ``Ext.form.Field`` The component that this plugin
+     *      extends.
+     * @param {Object} target
+     */
+    init: function(target) {
+        this.target = target;
+        onCfg = {scope: this};
+        onCfg[target instanceof Ext.form.ComboBox ? "select" : "valid"] =
+            this.onFieldChange;
+        target.on(onCfg);
+        this.page.on({
+            "change": this.onPageChange,
+            scope: this
+        });
+    },
+
+    /** private: method[onFieldChange]
+     *  :param field: ``Ext.form.Field``
+     *  :param record: ``Ext.data.Record`` Optional.
+     *  
+     *  Handler for the target field's "valid" or "select" event.
+     */
+    onFieldChange: function(field, record) {
+        var printProvider = this.page.printProvider;
+        var value = field.getValue();
+        this._updating = true;
+        if(field.store === printProvider.scales) {
+            this.page.setScale(record);
+        } else if(field.name == "rotation") {
+            this.page.setRotation(value);
+        } else {
+            this.page.customParams[field.name] = value;
+        }
+        delete this._updating;
+    },
+
+    /** private: method[onPageChange]
+     *  :param page: :class:`GeoExt.data.PrintPage`
+     *  
+     *  Handler for the "change" event for the page this plugin is configured
+     *  with.
+     */
+    onPageChange: function(page) {
+        if(!this._updating) {
+            var t = this.target;
+            t.suspendEvents();
+            if(t.store === page.printProvider.scales) {
+                t.setValue(page.scale.get(t.displayField));
+            } else if(t.name == "rotation") {
+                t.setValue(page.rotation);
+                t.setDisabled(!page.printProvider.layout.get("rotation"));
+            }
+            t.resumeEvents();
+        }
+    },
+    
+    /** private: method[destroy]
+     */
+    destroy: function() {
+        this.target.un("select", this.onFieldChange, this);
+        this.target.un("valid", this.onFieldChange, this);
+        this.page.un("change", this.onPageChange, this);
+        GeoExt.plugins.PrintPageField.superclass.destroy.apply(this, arguments);
+    }
+
+});
+
+/** api: ptype = gx_printpagefield */
+Ext.preg && Ext.preg("gx_printpagefield", GeoExt.plugins.PrintPageField);

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintProviderField.js (from rev 1714, sandbox/ahocevar/playground/ux/Printing/ux/plugins/PrintProviderField.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintProviderField.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/plugins/PrintProviderField.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+Ext.namespace("GeoExt.plugins");
+
+/** api: (define)
+ *  module = GeoExt.plugins
+ *  class = PrintProviderField
+ *  base_link = `Ext.util.Observable <http://extjs.com/deploy/dev/docs/?class=Ext.util.Observable>`_
+ */
+
+/** api: constructor
+ *  .. class:: PrintProviderField
+ * 
+ *  A plugin for ``Ext.form.Field`` components which provides synchronization
+ *  with a :class:`GeoExt.data.PrintProvider`.
+ */
+GeoExt.plugins.PrintProviderField = Ext.extend(Ext.util.Observable, {
+    
+    /** api: config[printProvider]
+     *  ``GeoExt.data.PrintProvider`` The print provider to use with this
+     *  plugin's field. Not required if set on the owner container of the
+     *  field.
+     */
+    
+    /** private: property[target]
+     *  ``Ext.form.Field`` This plugin's target field.
+     */
+    target: null,
+    
+    /** private: method[constructor]
+     */
+    constructor: function(config) {
+        this.initialConfig = config;
+        Ext.apply(this, config);
+        
+        GeoExt.plugins.PrintProviderField.superclass.constructor.apply(this, arguments);
+    },
+    
+    /** private: method[init]
+     *  :param target: ``Ext.form.Field`` The component that this plugin
+     *      extends.
+     */
+    init: function(target) {
+        this.target = target;
+        var onCfg = {
+            scope: this,
+            "render": this.onRender
+        };
+        onCfg[target instanceof Ext.form.ComboBox ? "select" : "valid"] =
+            this.onFieldChange;
+        target.on(onCfg);
+    },
+    
+    /** private: method[onRender]
+     *  :param field: ``Ext.Form.Field``
+     *  
+     *  Handler for the target field's "render" event.
+     */
+    onRender: function(field) {
+        var printProvider = this.printProvider || field.ownerCt.printProvider;
+        if(field.store === printProvider.layouts) {
+            field.setValue(printProvider.layout.get(field.displayField));
+            printProvider.on({
+                "layoutchange": this.onProviderChange,
+                scope: this
+            });
+        } else if(field.store === printProvider.dpis) {
+            field.setValue(printProvider.dpi.get(field.displayField));
+            printProvider.on({
+                "dpichange": this.onProviderChange,
+                scope: this
+            });
+        } else if(field.initialConfig.value === undefined) {
+            field.setValue(printProvider.customParams[field.name]);
+        }
+    },
+    
+    /** private: method[onFieldChange]
+     *  :param field: ``Ext.form.Field``
+     *  :param record: ``Ext.data.Record`` Optional.
+     *  
+     *  Handler for the target field's "valid" or "select" event.
+     */
+    onFieldChange: function(field, record) {
+        var printProvider = this.printProvider || field.ownerCt.printProvider;
+        var value = field.getValue();
+        this._updating = true;
+        if(record) {
+            switch(field.store) {
+                case printProvider.layouts:
+                    printProvider.setLayout(record);
+                    break;
+                case printProvider.dpis:
+                    printProvider.setDpi(record);
+            }
+        } else {
+            printProvider.customParams[field.name] = value;
+        }
+        delete this._updating;
+    },
+    
+    /** private: method[onProviderChange]
+     *  :param printProvider: :class:`GeoExt.data.PrintProvider`
+     *  :param rec: ``Ext.data.Record``
+     *  
+     *  Handler for the printProvider's dpichange and layoutchange event
+     */
+    onProviderChange: function(printProvider, rec) {
+        if(!this._updating) {
+            this.target.setValue(rec.get(this.target.displayField));
+        }
+    }
+    
+});
+
+/** api: ptype = gx_printproviderfield */
+Ext.preg && Ext.preg("gx_printproviderfield", GeoExt.plugins.PrintProviderField);

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/PrintMapPanel.js (from rev 1721, sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintMapPanel.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/PrintMapPanel.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/PrintMapPanel.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,196 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/**
+ * @include data/PrintProvider.js
+ * @include data/PrintPage.js
+ */
+Ext.namespace("GeoExt");
+
+/** api: (define)
+ *  module = GeoExt
+ *  class = PrintMapPanel
+ */
+
+/** api: (extends)
+ * GeoExt/widgets/MapPanel.js
+ */
+
+/** api: constructor
+ *  .. class:: PrintMapPanel
+ * 
+ *  A map panel that controls scale and center of a print page, based the
+ *  current view of a source map.
+ */
+GeoExt.PrintMapPanel = Ext.extend(GeoExt.MapPanel, {
+    
+    /** api: config[map]
+     *  ``Object`` Optional configuration for the ``OpenLayers.Map`` object
+     *  that this PrintMapPanel uses. Useful e.g. to configure a map with a
+     *  custom set of controls.
+     *  
+     *  .. note:: ``numZoomLevels`` and ``resolutions`` of the map will be set
+     *      by this PrintMapPanel, and the layers will be copied from
+     *      :ref:`GeoExt.PrintMapPanel.sourceMap`.
+     */
+    
+    /** api: config[sourceMap]
+     *  :class:`GeoExt.MapPanel`|``OpenLayers.Layer`` The map that is to be
+     *  printed.
+     */
+    
+    /** private: property[sourceMap]
+     *  ``OpenLayers.Map``
+     */
+    sourceMap: null,
+    
+    /** config: property[printProvider]
+     *  :class:`GeoExt.data.PrintProvider`|``Object`` PrintProvider to use
+     *  for printing. If an ``Object`` is provided, a new PrintProvider will
+     *  be created and configured with the object.
+     */
+    
+    /** api: property[printProvider]
+     *  :class:`GeoExt.data.PrintProvider` PrintProvider for this
+     *  PrintMapPanel.
+     *  
+     *  .. note:: The PrintMapPanel requires the printProvider's capabilities
+     *  to be available upon initialization. This means that a PrintMapPanel
+     *  configured with an object as ``printProvider`` will only work when
+     *  ``capabilities`` is provided in the printProvider's configuration
+     *  object. If ``printProvider`` is provided as an instance of
+     *  :class:`GeoExt.data.PrintProvider`, the capabilities must be loaded
+     *  upon PrintMapPanel initialization.
+     */
+    printProvider: null,
+    
+    /** api: property[printPage]
+     *  :class:`GeoExt.data.PrintPage` PrintPage for this PrintMapPanel.
+     *  read-only.
+     */
+    printPage: null,
+    
+    /**
+     * private: method[initComponent]
+     * private override
+     */
+    initComponent: function() {
+        if(this.sourceMap instanceof GeoExt.MapPanel) {
+            this.sourceMap = this.sourceMap.map;
+        }
+        if(!(this.printProvider instanceof GeoExt.data.PrintProvider)) {
+            this.printProvider = new GeoExt.data.PrintProvider(
+                this.printProvider);
+        }
+        this.printPage = new GeoExt.data.PrintPage({
+            printProvider: this.printProvider
+        });
+        
+        var resolutions = [];
+        this.printProvider.scales.each(function(s){
+            var res = OpenLayers.Util.getResolutionFromScale(s.get("value"),
+                this.sourceMap.baseLayer.units);
+            var zoom = this.sourceMap.getZoomForResolution(res)
+            resolutions.push(this.sourceMap.baseLayer.resolutions[zoom]);
+        }, this)
+        
+        this.zoom = resolutions.indexOf(this.sourceMap.getResolution());
+        this.center = this.sourceMap.getCenter();
+
+        this.layers = [];
+        var layer;
+        Ext.each(this.sourceMap.layers, function(layer){
+            var clone = layer.clone();
+            layer.getVisibility() === true && this.layers.push(clone);
+        }, this);
+
+        this.map = Ext.apply(this.map || {}, {
+            resolutions: resolutions,
+            numZoomLevels: resolutions.length
+        });
+
+        // set an initial size with the same aspect ratio as the print page.
+        // This is crucial for the first fitMap call to determine the correct
+        // resolution, otherwise we may be one zoom level off.
+        var size = this.printProvider.layout.get("size");
+        this.width = size.width;
+        this.height = size.height;
+        
+        GeoExt.PrintMapPanel.superclass.initComponent.call(this);
+        
+        this.fitMap();
+        this.printProvider.on("layoutchange", this.fitMap, this);
+        this.printPage.on("change", this.fitZoom, this);
+        this.map.events.register("moveend", this, this.updatePage);
+    },
+    
+    /** private: method[fitMap]
+     *  Fits this PrintMapPanel's width and height to the print extent. This
+     *  calculation is based on the print extent for the first available scale,
+     *  which means that the print view extent is only guaranteed to be
+     *  accurate at that scale. The aspect ratio, however, can be taken for
+     *  granted at any scale.
+     */
+    fitMap: function() {
+        this.printPage.setScale(this.printProvider.scales.getAt(0),
+            this.sourceMap.units);
+        this.printPage.setCenter(this.sourceMap.getCenter());
+        var extent = this.printPage.feature.geometry.getBounds();
+        var zoom = this.map.getZoomForExtent(extent);
+        var resolution = this.map.getResolutionForZoom(zoom);
+        this.setSize(
+            extent.getWidth() / resolution,
+            extent.getHeight() / resolution
+        );
+    },
+    
+    /** private: method[fitZoom]
+     *  Fits this PrintMapPanel's zoom to the print scale.
+     */
+    fitZoom: function() {
+        var zoom = this.map.getZoomForResolution(
+            OpenLayers.Util.getResolutionFromScale(
+                this.printPage.scale.get("value"),
+                this.map.baseLayer.units));
+        this._updating = true;
+        this.map.getZoom() != zoom && this.map.zoomTo(zoom);
+        delete this._updating;
+    },
+    
+    /** private: method[updatePage]
+     *  updates the print page to match this PrintMapPanel's center and scale.
+     */
+    updatePage: function() {
+        if(!this._updating) {
+            this.printPage.fitPage(this.map, true);
+        }
+    },
+    
+    /** api: method[print]
+     *  :param options: ``Object`` options for the printProvider's
+     *  :ref:`GeoExt.data.PrintProvider.print` method.
+     *  Convenience methods for printing the map, without the need to interact
+     *  with the printProvider.
+     */
+    print: function(options) {
+        this.printProvider.print(this.map, [this.printPage], options);
+    },
+    
+    /** private: method[beforeDestroy]
+     */
+    beforeDestroy: function() {
+        this.map.events.unregister("moveend", this, this.updatePage);
+        this.printPage.un("change", this.fitZoom, this);
+        this.printProvider.un("layoutchange", this.fitMap, this);
+        GeoExt.PrintMapPanel.superclass.beforeDestroy.apply(this, arguments);
+    }
+});
+
+/** api: xtype = gx_printmappanel */
+Ext.reg('gx_printmappanel', GeoExt.PrintMapPanel); 
+

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/PrintForm.js (from rev 1690, sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/PrintForm.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/PrintForm.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/PrintForm.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+Ext.namespace("GeoExt.form")
+
+/** api: (define)
+ *  module = GeoExt.form
+ *  class = PrintForm
+ *  base_link = `Ext.form.FormPanel <http://extjs.com/deploy/dev/docs/?class=Ext.form.FormPanel>`_
+ */
+
+/** api: constructor
+ *  .. class:: PrintForm
+ * 
+ *  Provides a base class form for working with
+ *  :class:`GeoExt.data.PrintProvider`, :class:`GeoExt.data.PrintPage`
+ *  and the plugins available for fields to synchronize. The form uses
+ *  a layer to draw the page extent and handle features of print pages,
+ *  with a control to modify them.
+ *  
+ *  This form comes with no fields and is meant to be extended (unless it is
+ *  enough to configure print extent, scale and rotation interactively on the
+ *  map). See :ref:`GeoExt.ux.form.SimplePrint` for a simple implementation.
+ */
+GeoExt.form.PrintForm = Ext.extend(Ext.form.FormPanel, {
+    
+    /** api: config[printProvider]
+     *  :class:`GeoExt.data.PrintProvider` The print provider this form
+     *  is connected to.
+     */
+    
+    /** api: property[printProvider]
+     *  :class:`GeoExt.data.PrintProvider` The print provider this form
+     *  is connected to. Read-only.
+     */
+    printProvider: null,
+    
+    /** api: config[map]
+     *  ``GeoExt.MapPanel``|``OpenLayers.Map`` The map the drag control will
+     *  be added to. Optional if a layer is provided and the layer has already
+     *  been added to a map.
+     */
+    
+    /** private: property[map]
+     *  ``OpenLayers.Map`` The map that layer and control will be added to.
+     */
+    map: null,
+    
+    /** api: config[layer]
+     *  ``OpenLayers.Layer.Vector`` The layer used to render extent and handle
+     *  features to. Optional, will be created if not provided.
+     */
+
+    /** private: property[layer]
+     *  ``OpenLayers.Layer.Vector`` The layer used to render extent and handle
+     *  features to.
+     */
+    layer: null,
+    
+    /** private: property[control]
+     *  ``OpenLayers.Control.DragFeature`` The control used to change extent
+     *  center, rotation and scale.
+     */
+    control: null,
+    
+    /** api: config[pages]
+     *  Array of :class:`GeoExt.data.PrintPage` The pages that this form
+     *  controls. Optional, will be created if not provided.
+     */
+    
+    /** api: property[pages]
+     *  Array of :class:`GeoExt.data.PrintPage` The pages that this form
+     *  controls.
+     */
+    pages: null,
+    
+    /** private: method[initComponent]
+     */
+    initComponent: function() {
+        GeoExt.form.PrintForm.superclass.initComponent.call(this);
+        if(this.map instanceof GeoExt.MapPanel) {
+            this.map = this.map.map;
+        }
+        if(!this.map) {
+            this.map = this.layer.map;
+        }
+        
+        if(!this.pages) {
+            this.pages = [];
+        }
+                        
+        this.initLayer();
+        this.initControl();
+
+        this.on({
+            "show": function() {
+                this.layer.setVisibility(true);
+                this.control.activate();
+            },
+            "hide": function() {
+                this.control.deactivate();
+                this.layer.setVisibility(false);
+            }
+        });
+    },
+    
+    /** private: method[initLayer]
+     */
+    initLayer: function() {
+        if(!this.layer) {
+            this.layer = new OpenLayers.Layer.Vector(null, {
+                displayInLayerSwitcher: false
+            });
+        }
+        if(!this.layer.map) {
+            this.map.addLayer(this.layer);
+        }
+    },
+    
+    /** private: method[initControl]
+     */
+    initControl: function() {
+        var pages = this.pages;
+
+        var updateHandles = function() {
+            for(var i=0, len=pages.length; i<len; ++i) {
+                pages[i].updateHandle();
+            };
+        }
+
+        this.control = new OpenLayers.Control.DragFeature(this.layer, {
+            onDrag: function(feature) {
+                if(feature.geometry instanceof OpenLayers.Geometry.Polygon) {
+                    // a page geometry was dragged
+                    updateHandles();
+                } else if(feature.geometry instanceof OpenLayers.Geometry.Point) {
+                    // a scale/rotation handle was dragged
+                    for(var i=0, len=pages.length; i<len; ++i) {
+                        pages[i].updateByHandle(false);
+                    }
+                }
+            },
+            onComplete: updateHandles
+        });
+
+        this.map.addControl(this.control);
+        this.control.activate();
+    },
+    
+    /** private: method[beforeDestroy]
+     */
+    beforeDestroy: function() {
+        Ext.each(this.pages, function(page) {
+            this.layer.removeFeatures(page.feature, page.handle);
+        }, this);
+        this.control.destroy();
+        if(!this.initialConfig.layer) {
+            this.layer.destroy();
+        }
+        delete this.layer;
+        delete this.map;
+        delete this.control;
+    }
+    
+});
+
+/** api: xtype = gx_printform */
+Ext.reg("gx_printform", GeoExt.form.PrintForm);

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -107,7 +107,13 @@
             "GeoExt/widgets/WMSLegend.js",
             "GeoExt/widgets/LegendPanel.js",
             "GeoExt/widgets/ZoomSlider.js",
-            "GeoExt/widgets/grid/FeatureSelectionModel.js"
+            "GeoExt/widgets/grid/FeatureSelectionModel.js",
+            "GeoExt/data/PrintPage.js",
+            "GeoExt/data/PrintProvider.js",
+            "GeoExt/plugins/PrintPageField.js",
+            "GeoExt/plugins/PrintProviderField.js",
+            "GeoExt/widgets/PrintMapPanel.js",
+            "GeoExt/widgets/form/PrintForm.js"
         );
 
         var agent = navigator.userAgent;

Modified: sandbox/ahocevar/playground/ux/Printing/build/Makefile
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/build/Makefile	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/build/Makefile	2010-01-13 11:18:51 UTC (rev 1738)
@@ -4,6 +4,10 @@
 LIB_NAME = Printing
 ZIP_NAME = $(LIB_NAME)-$(VERSION).zip
 
+CSS_DIR = $(LIB_NAME)/resources/css
+CSS_IMPORTS = $(shell cat ../resources/css/printing-all-debug.css | grep '@import' | sed 's/^@import "\(.*\)";/\1/')
+ALL_CSS = $(CSS_DIR)/printing-all.css
+
 .PHONEY: help clean ext examples lib zip dist
 
 help:
@@ -19,7 +23,7 @@
 	@echo "  make lib LIB_NAME=MyLib"
 	@echo "  make zip"
 	@echo "  make zip ZIP_NAME=MyZip.zip"
-	@echo "  make dist VERSION=0.5-rc1"
+	@echo "  make dist VERSION=0.6"
 
 clean:
 	-rm -rf $(LIB_NAME)
@@ -30,9 +34,22 @@
 	rsync -au --exclude=.svn `pwd`/../examples `pwd`/$(LIB_NAME)
 	for file in `find $(LIB_NAME)/examples/ -name "*.html"`; do \
 	    sed -i "s/\.\.\/ux\/Printing\.js/\.\.\/script\/Printing\.js/g" $${file} ; \
+        sed -i "s/printing-all-debug\.css/printing-all\.css/g" $${file} ; \
 	done ; 	
 
-lib:
+resources:
+    rsync -au --exclude=.svn `pwd`/../resources `pwd`/$(LIB_NAME)
+    
+    for file in `find $(CSS_DIR) -name "*.css"`; do \
+        csstidy $${file} --template=highest $${file} ; \
+    done ;
+    echo "" > $(ALL_CSS)
+    for filename in $(CSS_IMPORTS); do \
+        cat $(CSS_DIR)/$${filename} >> $(ALL_CSS) ; \
+    done ;
+    -rm $(CSS_DIR)/printing-all-debug.css
+
+lib: resources
 	@echo "Building the library."
 	mkdir -p $(LIB_NAME)/script
 	jsbuild full.cfg -v -o $(LIB_NAME)/script/

Deleted: sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.html
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.html	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.html	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,41 +0,0 @@
-<html>
-    <head>
-        <title>Printing ux (PrintMapPanel) Example</title>
-
-        <script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/adapter/ext/ext-base.js"></script>
-        <script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/ext-all.js"></script>
-        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.0.0/resources/css/ext-all.css" />
-        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.0.0/examples/shared/examples.css" />
-        <script src="http://dev.openlayers.org/nightly/OpenLayers.js"></script>
-        <script type="text/javascript" src="../../../trunk/geoext/lib/GeoExt.js"></script>
-        
-        <script type="text/javascript" src="../ux/Printing.js"></script>
-        <link rel="stylesheet" type="text/css" href="../resources/css/printpreview.css" />
-        
-        <script type="text/javascript" src="PrintMapPanel.js"></script>
-
-        <script type="text/javascript" src="http://demo.opengeo.org/geoserver/pdf/info.json?var=printCapabilities"></script>
-        
-    </head>
-    <body>
-        <h1>PrintProvider with a PrintMapPanel</h1>
-        
-        <p>This example shows how to use GeoExt.ux.data.PrintProvider to talk
-        to the <a href="http://trac.mapfish.org/trac/mapfish/wiki/PrintModuleInstallation">Mapfish print module</a>,
-        which is also available as
-        <a href="http://geoserver.org/display/GEOS/Printing+2.0+HOWTO">GeoServer print module</a>.</p>
-        
-        <p>Use the "Print" button from the bottom toolbar of the map to open
-        the print dialog.</p>
-        
-        <p>Note that this example uses GET requests to communicate with the
-        print servlet (provided by the OpenGeo demo server). This saves us a
-        proxy, but has limitations (URL length in Internet Explorer, and
-        character encoding issues). For production use, the POST method is
-        recommended.</p>
-        
-        <p>See <a href="PrintMapPanel.js">PrintMapPanel.js</a> for the source code.</p>
-        
-        <div id="content"></div>
-    </body>
-</html>

Deleted: sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,67 +0,0 @@
-var mapPanel, printMapPanel, legendPanel;
-
-Ext.onReady(function() {
-
-    mapPanel = new GeoExt.MapPanel({
-        region: "center",
-        layers: [
-            new OpenLayers.Layer.WMS("Tasmania State Boundaries",
-                "http://demo.opengeo.org/geoserver/wms",
-                {layers: "topp:tasmania_state_boundaries"}, {singleTile: true}),
-            new OpenLayers.Layer.WMS("Tasmania Water Bodies",
-                "http://demo.opengeo.org/geoserver/wms",
-                {layers: "topp:tasmania_water_bodies", transparent: true},
-                {buffer: 0})],
-        center: [146.56, -41.56],
-        zoom: 6,
-        bbar: [{
-            text: "Print...",
-            handler: showPrintWindow
-        }]
-    });
-
-    legendPanel = new GeoExt.LegendPanel({
-        width: 200,
-        region: "west",
-        defaults: {
-            style: "padding:5px",
-            imageFormat: "image/png"
-        }
-    });
-    new Ext.Panel({
-        layout: "border",
-        renderTo: "content",
-        width: 800,
-        height: 350,
-        items: [mapPanel, legendPanel]
-    });    
-});
-
-function showPrintWindow() {
-    var printWindow = new Ext.Window({
-        title: "Print",
-        modal: true,
-        border: false,
-        resizable: false,
-        width: 360,
-        items: new GeoExt.ux.PrintPreview({
-            printProvider: {
-                // using get for remote service access without same origin
-                // restriction. For async requests, we would set method to "POST".
-                method: "GET",
-                //method: "POST",
-                
-                // capabilities from script tag in Printing.html.
-                capabilities: printCapabilities,
-                listeners: {
-                    "print": function() {printWindow.close();}
-                }
-            },
-            includeLegend: true,
-            mapTitle: "PrintMapPanel Demo",
-            bodyStyle: "padding:5px",
-            sourceMap: mapPanel,
-            legend: legendPanel
-        })
-    }).show().center();
-}

Copied: sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.html (from rev 1715, sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.html)
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.html	                        (rev 0)
+++ sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.html	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,42 @@
+<html>
+    <head>
+        <title>Printing ux PrintPreview Example</title>
+
+        <script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/adapter/ext/ext-base.js"></script>
+        <script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/ext-all.js"></script>
+        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.0.0/resources/css/ext-all.css" />
+        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.0.0/examples/shared/examples.css" />
+        <script src="http://dev.openlayers.org/nightly/OpenLayers.js"></script>
+        <script type="text/javascript" src="../../../trunk/geoext/lib/GeoExt.js"></script>
+        
+        <!-- script and css resources for this ux -->
+        <script type="text/javascript" src="../ux/Printing.js"></script>
+        <link rel="stylesheet" type="text/css" href="../resources/css/printing-all-debug.css" />
+        
+        <script type="text/javascript" src="PrintPreview.js"></script>
+
+        <script type="text/javascript" src="http://demo.opengeo.org/geoserver/pdf/info.json?var=printCapabilities"></script>
+        
+    </head>
+    <body>
+        <h1>PrintPreview using GeoExt.data.PrintProvider and GeoExt.PrintMapPanel</h1>
+        
+        <p>This example shows how to use GeoExt.data.PrintProvider to talk
+        to the <a href="http://trac.mapfish.org/trac/mapfish/wiki/PrintModuleInstallation">Mapfish print module</a>,
+        which is also available as
+        <a href="http://geoserver.org/display/GEOS/Printing+2.0+HOWTO">GeoServer print module</a>.</p>
+        
+        <p>Use the "Print" button from the bottom toolbar of the map to open
+        the print dialog.</p>
+        
+        <p>Note that this example uses GET requests to communicate with the
+        print servlet (provided by the OpenGeo demo server). This saves us a
+        proxy, but has limitations (URL length in Internet Explorer, and
+        character encoding issues). For production use, the POST method is
+        recommended.</p>
+        
+        <p>See <a href="PrintPreview.js">PrintPreview.js</a> for the source code.</p>
+        
+        <div id="content"></div>
+    </body>
+</html>

Copied: sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.js (from rev 1734, sandbox/ahocevar/playground/ux/Printing/examples/PrintMapPanel.js)
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.js	                        (rev 0)
+++ sandbox/ahocevar/playground/ux/Printing/examples/PrintPreview.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,67 @@
+var mapPanel, printMapPanel, legendPanel;
+
+Ext.onReady(function() {
+
+    mapPanel = new GeoExt.MapPanel({
+        region: "center",
+        layers: [
+            new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+                "http://demo.opengeo.org/geoserver/wms",
+                {layers: "topp:tasmania_state_boundaries"}, {singleTile: true}),
+            new OpenLayers.Layer.WMS("Tasmania Water Bodies",
+                "http://demo.opengeo.org/geoserver/wms",
+                {layers: "topp:tasmania_water_bodies", transparent: true},
+                {buffer: 0})],
+        center: [146.56, -41.56],
+        zoom: 6,
+        bbar: [{
+            text: "Print...",
+            handler: showPrintWindow
+        }]
+    });
+
+    legendPanel = new GeoExt.LegendPanel({
+        width: 200,
+        region: "west",
+        defaults: {
+            style: "padding:5px",
+            imageFormat: "image/png"
+        }
+    });
+    new Ext.Panel({
+        layout: "border",
+        renderTo: "content",
+        width: 800,
+        height: 350,
+        items: [mapPanel, legendPanel]
+    });    
+});
+
+function showPrintWindow() {
+    var printWindow = new Ext.Window({
+        title: "Print",
+        modal: true,
+        border: false,
+        resizable: false,
+        width: 360,
+        items: new GeoExt.ux.PrintPreview({
+            printProvider: {
+                // using get for remote service access without same origin
+                // restriction. For async requests, we would set method to "POST".
+                method: "GET",
+                //method: "POST",
+                
+                // capabilities from script tag in Printing.html.
+                capabilities: printCapabilities,
+                listeners: {
+                    "print": function() {printWindow.close();}
+                }
+            },
+            includeLegend: true,
+            mapTitle: "PrintMapPanel Demo",
+            bodyStyle: "padding:5px",
+            sourceMap: mapPanel,
+            legend: legendPanel
+        })
+    }).show().center();
+}

Deleted: sandbox/ahocevar/playground/ux/Printing/examples/Printing.html
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/Printing.html	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/examples/Printing.html	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,46 +0,0 @@
-<html>
-    <head>
-        <title>Printing ux (SimplePrint Form) Example</title>
-
-        <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2.1/adapter/ext/ext-base.js"></script>
-        <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2.1/ext-all.js"></script>
-        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/resources/css/ext-all.css" />
-        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/examples/shared/examples.css" />
-        <script src="http://openlayers.org/api/2.8/OpenLayers.js"></script>
-        <script type="text/javascript" src="../../../trunk/geoext/lib/GeoExt.js"></script>
-        
-        <script type="text/javascript" src="../ux/Printing.js"></script>
-        
-        <script type="text/javascript" src="Printing.js"></script>
-
-        <!--
-        Using the script tag method to get the print service capabilities and
-        make them available in the printCapabilities variable.
-        The script tag below can be removed when configuring the printProvider
-        with url instead of capabilities
-        -->
-        <script type="text/javascript" src="http://demo.mapfish.org/mapfishsample/1.2/print/info.json?var=printCapabilities"></script>
-        
-    </head>
-    <body>
-        <h1>PrintProvider with a Simple Print Form</h1>
-        
-        <p>This example shows how to use GeoExt.ux.data.PrintProvider to talk
-        to the <a href="http://trac.mapfish.org/trac/mapfish/wiki/PrintModuleInstallation">Mapfish print module</a>,
-        which is also available as
-        <a href="http://geoserver.org/display/GEOS/Printing+2.0+HOWTO">GeoServer print module</a>.</p>
-        
-        <p>The rectangle and handle on the map can be used to change center,
-        scale and rotation.</p>
-        
-        <p>Note that this example uses GET requests to communicate with the
-        print servlet (provided by the Mapfish demo server). This saves us a
-        proxy, but has limitations (URL length in Internet Explorer, and
-        character encoding issues). For production use, the POST method is
-        recommended.</p>
-        
-        <p>See <a href="Printing.js">Printing.js</a> for the source code.</p>
-        
-        <div id="content"></div>
-    </body>
-</html>

Deleted: sandbox/ahocevar/playground/ux/Printing/examples/Printing.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/Printing.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/examples/Printing.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,110 +0,0 @@
-var printProvider, printForm;
-
-Ext.onReady(function() {
-
-    printProvider = new GeoExt.ux.data.PrintProvider({
-        // using get for remote service access without same origin restriction.
-        // For asynchronous requests, we would set method to "POST".
-        method: "GET",
-        //method: "POST",
-        
-        // capabilities from script tag in Printing.html. For asynchonous
-        // loading, we would configure url instead of capabilities.
-        capabilities: printCapabilities
-        //url: "/geoserver/pdf/"
-    });
-    
-    var mapPanel = new GeoExt.MapPanel({
-        region: "center",
-        layers: [new OpenLayers.Layer.WMS("Global Imagery",
-            "http://labs.metacarta.com/wms/vmap0",
-            {layers: "basic"})] ,
-        center: [16,48],
-        zoom: 5
-    });
-
-    // create a vector layer, which will also be printed.
-    var redline = new OpenLayers.Layer.Vector("vector", {
-        styleMap: new OpenLayers.StyleMap({
-            strokeColor: "red",
-            fillColor: "red",
-            fillOpacity: 0.7,
-            strokeWidth: 2,
-            pointRadius: 12,
-            externalGraphic: "http://openlayers.org/dev/img/marker-blue.png"
-        })
-    });
-    var geom = OpenLayers.Geometry.fromWKT, Vec = OpenLayers.Feature.Vector;
-    redline.addFeatures([
-        new Vec(geom("POLYGON(15 47, 16 48, 14 49)")),
-        new Vec(geom("LINESTRING(15 48, 16 47, 17 46)")),
-        new Vec(geom("POINT(16 46)"))
-    ]);
-    mapPanel.map.addLayer(redline);
-    
-    // a simple print form
-    printForm = new GeoExt.ux.form.SimplePrint({
-        map: mapPanel,
-        printProvider: printProvider,
-        bodyStyle: {padding: "5px"},
-        labelWidth: 65,
-        defaults: {width: 115},
-        region: "east",
-        border: false,
-        width: 200
-    });
-
-    // add custom fields to the form
-    printForm.insert(0, {
-        xtype: "textfield",
-        name: "mapTitle",
-        fieldLabel: "Title",
-        value: "A custom title",
-        plugins: new GeoExt.ux.plugins.PrintPageField({
-            page: printForm.pages[0]
-        })
-    });
-    printForm.insert(1, {
-        xtype: "textarea",
-        fieldLabel: "Comment",
-        name: "comment",
-        value: "A custom comment",
-        plugins: new GeoExt.ux.plugins.PrintPageField({
-            page: printForm.pages[0]
-        })
-    });
-    
-    var formCt = new Ext.Panel({
-        layout: "fit",
-        region: "east",
-        width: 200
-    });
-    
-    new Ext.Panel({
-        renderTo: "content",
-        layout: "border",
-        width: 800,
-        height: 350,
-        items: [mapPanel, formCt]
-    });
-    
-    /* add the print form to its container and make sure that the print page
-     * fits the max extent
-     */
-    formCt.add(printForm);
-    formCt.doLayout();
-    printForm.pages[0].fitPage(mapPanel.map);
-
-    /* use this code block instead of the above one if you configured the
-     * printProvider with url instead of capabilities
-    var myMask = new Ext.LoadMask(formCt.body, {msg:"Loading data..."});
-    myMask.show();
-    printProvider.on("loadcapabilities", function() {
-        myMask.hide();
-        formCt.add(printForm);
-        formCt.doLayout();
-        printForm.pages[0].fitPage(mapPanel.map);
-    });
-     */
-    
-});

Copied: sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.html (from rev 1691, sandbox/ahocevar/playground/ux/Printing/examples/Printing.html)
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.html	                        (rev 0)
+++ sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.html	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,47 @@
+<html>
+    <head>
+        <title>Printing ux SimplePrint Example</title>
+
+        <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2.1/adapter/ext/ext-base.js"></script>
+        <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2.1/ext-all.js"></script>
+        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/resources/css/ext-all.css" />
+        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/examples/shared/examples.css" />
+        <script src="http://openlayers.org/api/2.8/OpenLayers.js"></script>
+        <script type="text/javascript" src="../../../trunk/geoext/lib/GeoExt.js"></script>
+        
+        <!-- script resources for this ux -->
+        <script type="text/javascript" src="../ux/Printing.js"></script>
+        
+        <script type="text/javascript" src="SimplePrint.js"></script>
+        
+        <!--
+        Using the script tag method to get the print service capabilities and
+        make them available in the printCapabilities variable.
+        The script tag below can be removed when configuring the printProvider
+        with url instead of capabilities
+        -->
+        <script type="text/javascript" src="http://demo.opengeo.org/geoserver/pdf/info.json?var=printCapabilities"></script>
+        
+    </head>
+    <body>
+        <h1>SimplePrint Form using GeoExt.data.PrintProvider and GeoExt.form.PrintForm</h1>
+        
+        <p>This example shows how to use GeoExt.data.PrintProvider to talk
+        to the <a href="http://trac.mapfish.org/trac/mapfish/wiki/PrintModuleInstallation">Mapfish print module</a>,
+        which is also available as
+        <a href="http://geoserver.org/display/GEOS/Printing+2.0+HOWTO">GeoServer print module</a>.</p>
+        
+        <p>The rectangle and handle on the map can be used to change center,
+        scale and rotation.</p>
+        
+        <p>Note that this example uses GET requests to communicate with the
+        print servlet (provided by the OpenGeo demo server). This saves us a
+        proxy, but has limitations (URL length in Internet Explorer, and
+        character encoding issues). For production use, the POST method is
+        recommended.</p>
+        
+        <p>See <a href="SimplePrint.js">SimplePrint.js</a> for the source code.</p>
+        
+        <div id="content"></div>
+    </body>
+</html>

Copied: sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.js (from rev 1690, sandbox/ahocevar/playground/ux/Printing/examples/Printing.js)
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.js	                        (rev 0)
+++ sandbox/ahocevar/playground/ux/Printing/examples/SimplePrint.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,110 @@
+var printProvider, printForm;
+
+Ext.onReady(function() {
+
+    printProvider = new GeoExt.data.PrintProvider({
+        // using get for remote service access without same origin restriction.
+        // For asynchronous requests, we would set method to "POST".
+        method: "GET",
+        //method: "POST",
+        
+        // capabilities from script tag in Printing.html. For asynchonous
+        // loading, we would configure url instead of capabilities.
+        capabilities: printCapabilities
+        //url: "/geoserver/pdf/"
+    });
+    
+    var mapPanel = new GeoExt.MapPanel({
+        region: "center",
+        layers: [new OpenLayers.Layer.WMS("Global Imagery",
+            "http://labs.metacarta.com/wms/vmap0",
+            {layers: "basic"})] ,
+        center: [16,48],
+        zoom: 5
+    });
+
+    // create a vector layer, which will also be printed.
+    var redline = new OpenLayers.Layer.Vector("vector", {
+        styleMap: new OpenLayers.StyleMap({
+            strokeColor: "red",
+            fillColor: "red",
+            fillOpacity: 0.7,
+            strokeWidth: 2,
+            pointRadius: 12,
+            externalGraphic: "http://openlayers.org/dev/img/marker-blue.png"
+        })
+    });
+    var geom = OpenLayers.Geometry.fromWKT, Vec = OpenLayers.Feature.Vector;
+    redline.addFeatures([
+        new Vec(geom("POLYGON(15 47, 15 46, 16 47, 16 48)")),
+        new Vec(geom("LINESTRING(14 48, 14 47, 15 48, 14 49, 16 49)")),
+        new Vec(geom("POINT(16 49)"))
+    ]);
+    mapPanel.map.addLayer(redline);
+    
+    // a simple print form
+    printForm = new GeoExt.ux.form.SimplePrint({
+        map: mapPanel,
+        printProvider: printProvider,
+        bodyStyle: {padding: "5px"},
+        labelWidth: 65,
+        defaults: {width: 115},
+        region: "east",
+        border: false,
+        width: 200
+    });
+
+    // add custom fields to the form
+    printForm.insert(0, {
+        xtype: "textfield",
+        name: "mapTitle",
+        fieldLabel: "Title",
+        value: "A custom title",
+        plugins: new GeoExt.plugins.PrintPageField({
+            page: printForm.pages[0]
+        })
+    });
+    printForm.insert(1, {
+        xtype: "textarea",
+        fieldLabel: "Comment",
+        name: "comment",
+        value: "A custom comment",
+        plugins: new GeoExt.plugins.PrintPageField({
+            page: printForm.pages[0]
+        })
+    });
+    
+    var formCt = new Ext.Panel({
+        layout: "fit",
+        region: "east",
+        width: 200
+    });
+    
+    new Ext.Panel({
+        renderTo: "content",
+        layout: "border",
+        width: 800,
+        height: 350,
+        items: [mapPanel, formCt]
+    });
+    
+    /* add the print form to its container and make sure that the print page
+     * fits the max extent
+     */
+    formCt.add(printForm);
+    formCt.doLayout();
+    printForm.pages[0].fitPage(mapPanel.map);
+
+    /* use this code block instead of the above one if you configured the
+     * printProvider with url instead of capabilities
+    var myMask = new Ext.LoadMask(formCt.body, {msg:"Loading data..."});
+    myMask.show();
+    printProvider.on("loadcapabilities", function() {
+        myMask.hide();
+        formCt.add(printForm);
+        formCt.doLayout();
+        printForm.pages[0].fitPage(mapPanel.map);
+    });
+     */
+    
+});

Added: sandbox/ahocevar/playground/ux/Printing/resources/css/printing-all-debug.css
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/resources/css/printing-all-debug.css	                        (rev 0)
+++ sandbox/ahocevar/playground/ux/Printing/resources/css/printing-all-debug.css	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,6 @@
+/**
+ * This file combines all default css files. It will be parsed by the build
+ * processor to generate a minified geoext-all.css file. Theme specific
+ * overrides go into gxtheme-<theme>.css
+ */
+ at import "printpreview.css";

Deleted: sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,29 +0,0 @@
-.x-btn .icon-print { 
-    background-image: url(../images/silk/printer.png);
-}
-
-.gx-map-overlay {
-    z-index: 1000; 
-    position: absolute; 
-    right: 10px; 
-    bottom: 10px;
-    text-align: left;
-}
-
-.gx-map-overlay .x-panel-body {
-    background-color: #D0DEF0;
-}
-
-.gx-map-overlay .olControlScaleLine {
-    bottom: 0;
-    left: 0;
-    position: relative !important;
-}
-
-.gx-northarrow {
-    background: transparent url(../images/north_arrow.png) no-repeat;
-    *-background: none;
-    *-filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../resources/images/north_arrow.png',sizingMethod='crop');
-    height: 24px;
-    width: 24px;
-}

Copied: sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css (from rev 1714, sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css)
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css	                        (rev 0)
+++ sandbox/ahocevar/playground/ux/Printing/resources/css/printpreview.css	2010-01-13 11:18:51 UTC (rev 1738)
@@ -0,0 +1,29 @@
+.x-btn .icon-print { 
+    background-image: url(../images/silk/printer.png);
+}
+
+.gx-map-overlay {
+    z-index: 1000; 
+    position: absolute; 
+    right: 10px; 
+    bottom: 10px;
+    text-align: left;
+}
+
+.gx-map-overlay .x-panel-body {
+    background-color: #D0DEF0;
+}
+
+.gx-map-overlay .olControlScaleLine {
+    bottom: 0;
+    left: 0;
+    position: relative !important;
+}
+
+.gx-northarrow {
+    background: transparent url(../images/north_arrow.png) no-repeat;
+    *-background: none;
+    *-filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../resources/images/north_arrow.png',sizingMethod='crop');
+    height: 24px;
+    width: 24px;
+}

Modified: sandbox/ahocevar/playground/ux/Printing/ux/Printing.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/ux/Printing.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/ux/Printing.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -52,12 +52,6 @@
     };
 
     var jsfiles = new Array(
-        "data/PrintPage.js",
-        "data/PrintProvider.js",
-        "plugins/PrintPageField.js",
-        "plugins/PrintProviderField.js",
-        "widgets/PrintMapPanel.js",
-        "widgets/form/PrintForm.js",
         "widgets/form/SimplePrint.js",
         "widgets/PrintPreview.js"
     );

Deleted: sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintMapPanel.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintMapPanel.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintMapPanel.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,196 +0,0 @@
-/**
- * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
- * 
- * Published under the BSD license.
- * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
- * of the license.
- */
-
-/**
- * @include data/PrintProvider.js
- * @include data/PrintPage.js
- */
-Ext.namespace("GeoExt.ux");
-
-/** api: (define)
- *  module = GeoExt.ux
- *  class = PrintMapPanel
- */
-
-/** api: (extends)
- * trunk/widgets/MapPanel.js
- */
-
-/** api: constructor
- *  .. class:: PrintMapPanel
- * 
- *  A map panel that controls scale and center of a print page, based the
- *  current view of a source map.
- */
-GeoExt.ux.PrintMapPanel = Ext.extend(GeoExt.MapPanel, {
-    
-    /** api: config[map]
-     *  ``Object`` Optional configuration for the ``OpenLayers.Map`` object
-     *  that this PrintMapPanel uses. Useful e.g. to configure a map with a
-     *  custom set of controls.
-     *  
-     *  .. note:: ``numZoomLevels`` and ``resolutions`` of the map will be set
-     *      by this PrintMapPanel, and the layers will be copied from
-     *      :ref:`GeoExt.ux.PrintMapPanel.sourceMap`.
-     */
-    
-    /** api: config[sourceMap]
-     *  :class:`GeoExt.MapPanel`|``OpenLayers.Layer`` The map that is to be
-     *  printed.
-     */
-    
-    /** private: property[sourceMap]
-     *  ``OpenLayers.Map``
-     */
-    sourceMap: null,
-    
-    /** config: property[printProvider]
-     *  :class:`GeoExt.ux.data.PrintProvider`|``Object`` PrintProvider to use
-     *  for printing. If an ``Object`` is provided, a new PrintProvider will
-     *  be created and configured with the object.
-     */
-    
-    /** api: property[printProvider]
-     *  :class:`GeoExt.ux.data.PrintProvider` PrintProvider for this
-     *  PrintMapPanel.
-     *  
-     *  .. note:: The PrintMapPanel requires the printProvider's capabilities
-     *  to be available upon initialization. This means that a PrintMapPanel
-     *  configured with an object as ``printProvider`` will only work when
-     *  ``capabilities`` is provided in the printProvider's configuration
-     *  object. If ``printProvider`` is provided as an instance of
-     *  :class:`GeoExt.ux.data.PrintProvider`, the capabilities must be loaded
-     *  upon PrintMapPanel initialization.
-     */
-    printProvider: null,
-    
-    /** api: property[printPage]
-     *  :class:`GeoExt.ux.data.PrintPage` PrintPage for this PrintMapPanel.
-     *  read-only.
-     */
-    printPage: null,
-    
-    /**
-     * private: method[initComponent]
-     * private override
-     */
-    initComponent: function() {
-        if(this.sourceMap instanceof GeoExt.MapPanel) {
-            this.sourceMap = this.sourceMap.map;
-        }
-        if(!(this.printProvider instanceof GeoExt.ux.data.PrintProvider)) {
-            this.printProvider = new GeoExt.ux.data.PrintProvider(
-                this.printProvider);
-        }
-        this.printPage = new GeoExt.ux.data.PrintPage({
-            printProvider: this.printProvider
-        });
-        
-        var resolutions = [];
-        this.printProvider.scales.each(function(s){
-            var res = OpenLayers.Util.getResolutionFromScale(s.get("value"),
-                this.sourceMap.baseLayer.units);
-            var zoom = this.sourceMap.getZoomForResolution(res)
-            resolutions.push(this.sourceMap.baseLayer.resolutions[zoom]);
-        }, this)
-        
-        this.zoom = resolutions.indexOf(this.sourceMap.getResolution());
-        this.center = this.sourceMap.getCenter();
-
-        this.layers = [];
-        var layer;
-        Ext.each(this.sourceMap.layers, function(layer){
-            var clone = layer.clone();
-            layer.getVisibility() === true && this.layers.push(clone);
-        }, this);
-
-        this.map = Ext.apply(this.map || {}, {
-            resolutions: resolutions,
-            numZoomLevels: resolutions.length
-        });
-
-        // set an initial size with the same aspect ratio as the print page.
-        // This is crucial for the first fitMap call to determine the correct
-        // resolution, otherwise we may be one zoom level off.
-        var size = this.printProvider.layout.get("size");
-        this.width = size.width;
-        this.height = size.height;
-        
-        GeoExt.ux.PrintMapPanel.superclass.initComponent.call(this);
-        
-        this.fitMap();
-        this.printProvider.on("layoutchange", this.fitMap, this);
-        this.printPage.on("change", this.fitZoom, this);
-        this.map.events.register("moveend", this, this.updatePage);
-    },
-    
-    /** private: method[fitMap]
-     *  Fits this PrintMapPanel's width and height to the print extent. This
-     *  calculation is based on the print extent for the first available scale,
-     *  which means that the print view extent is only guaranteed to be
-     *  accurate at that scale. The aspect ratio, however, can be taken for
-     *  granted at any scale.
-     */
-    fitMap: function() {
-        this.printPage.setScale(this.printProvider.scales.getAt(0),
-            this.sourceMap.units);
-        this.printPage.setCenter(this.sourceMap.getCenter());
-        var extent = this.printPage.feature.geometry.getBounds();
-        var zoom = this.map.getZoomForExtent(extent);
-        var resolution = this.map.getResolutionForZoom(zoom);
-        this.setSize(
-            extent.getWidth() / resolution,
-            extent.getHeight() / resolution
-        );
-    },
-    
-    /** private: method[fitZoom]
-     *  Fits this PrintMapPanel's zoom to the print scale.
-     */
-    fitZoom: function() {
-        var zoom = this.map.getZoomForResolution(
-            OpenLayers.Util.getResolutionFromScale(
-                this.printPage.scale.get("value"),
-                this.map.baseLayer.units));
-        this._updating = true;
-        this.map.getZoom() != zoom && this.map.zoomTo(zoom);
-        delete this._updating;
-    },
-    
-    /** private: method[updatePage]
-     *  updates the print page to match this PrintMapPanel's center and scale.
-     */
-    updatePage: function() {
-        if(!this._updating) {
-            this.printPage.fitPage(this.map, true);
-        }
-    },
-    
-    /** api: method[print]
-     *  :param options: ``Object`` options for the printProvider's
-     *  :ref:`GeoExt.ux.data.PrintProvider.print` method.
-     *  Convenience methods for printing the map, without the need to interact
-     *  with the printProvider.
-     */
-    print: function(options) {
-        this.printProvider.print(this.map, [this.printPage], options);
-    },
-    
-    /** private: method[beforeDestroy]
-     */
-    beforeDestroy: function() {
-        this.map.events.unregister("moveend", this, this.updatePage);
-        this.printPage.un("change", this.fitZoom, this);
-        this.printProvider.un("layoutchange", this.fitMap, this);
-        GeoExt.ux.PrintMapPanel.superclass.beforeDestroy.apply(this, arguments);
-    }
-});
-
-/** api: xtype = gx_printmappanel */
-Ext.reg('gx_printmappanel', GeoExt.ux.PrintMapPanel); 
-

Modified: sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintPreview.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintPreview.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/ux/widgets/PrintPreview.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -5,12 +5,6 @@
  * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
  * of the license.
  */
-
-/**
- * @include widgets/PrintMapPanel.js
- * @include plugins/PrintProviderField.js
- * @include plugins/PrintPageField.js
- */
 Ext.namespace("GeoExt.ux");
 
 /** api: (define)
@@ -24,7 +18,7 @@
  * 
  *  A print preview with an interactive map. Requires a server-side print
  *  module configuration with two custom fields (by default ``mapTitle`` and
- *  ``comment``.  
+ *  ``comment``).
  */
 GeoExt.ux.PrintPreview = Ext.extend(Ext.Panel, {
     
@@ -46,12 +40,12 @@
     /* end i18n */
     
     /** api: config[printProvider]
-     *  :class:`GeoExt.ux.data.PrintProvider`|``Object`` Instance or
+     *  :class:`GeoExt.data.PrintProvider`|``Object`` Instance or
      *  configuration for the PrintProvider that this dialog will use.
      */
     
     /** private: property[printProvider]
-     *  :class:`GeoExt.ux.data.PrintProvider`
+     *  :class:`GeoExt.data.PrintProvider`
      */
     printProvider: null,
     
@@ -123,7 +117,7 @@
     busyMask: null,
 
     /** api: property[printMapPanel]
-     *  class:`GeoExt.ux.PrintMapPanel` The print preview map.
+     *  class:`GeoExt.PrintMapPanel` The print preview map.
      */
     printMapPanel: null,
     
@@ -140,7 +134,7 @@
             cls: "x-panel-body"
         }, this.bodyCfg);
         
-        this.printMapPanel = new GeoExt.ux.PrintMapPanel({
+        this.printMapPanel = new GeoExt.PrintMapPanel({
             map: this.mapOptions,
             sourceMap: this.sourceMap,
             printProvider: this.printProvider,
@@ -182,10 +176,11 @@
      *  :return: ``Ext.Toolbar``
      */
     createToolbar: function() {
-        return new Ext.Toolbar([this.paperSizeText, {
+        var items = [];
+        this.printProvider.layouts.getCount() > 1 && items.push(this.paperSizeText, {
             xtype: "combo",
             width: 98,
-            plugins: new GeoExt.ux.plugins.PrintProviderField({
+            plugins: new GeoExt.plugins.PrintProviderField({
                 printProvider: this.printProvider
             }),
             store: this.printProvider.layouts,
@@ -195,10 +190,11 @@
             forceSelection: true,
             triggerAction: "all",
             selectOnFocus: true
-        }, "&nbsp;" + this.resolutionText, {
+        }, "&nbsp");
+        this.printProvider.dpis.getCount() > 1 && items.push(this.resolutionText, {
             xtype: "combo",
             width: 62,
-            plugins: new GeoExt.ux.plugins.PrintProviderField({
+            plugins: new GeoExt.plugins.PrintProviderField({
                 printProvider: this.printProvider
             }),
             store: this.printProvider.dpis,
@@ -213,7 +209,8 @@
                 v = parseInt(v) + " dpi";
                 Ext.form.ComboBox.prototype.setValue.apply(this, arguments);
             }
-        }, "->", {
+        });
+        items.push("->", {
             text: this.printText,
             iconCls: "icon-print",
             handler: function(){
@@ -221,7 +218,8 @@
                     {legend: this.legend});
             },
             scope: this
-        }]);
+        });
+        return new Ext.Toolbar(items);
     },
     
     /** private: method[createForm]
@@ -235,7 +233,7 @@
             emptyText: this.emptyTitleText,
             anchor: "100%",
             hideLabel: true,
-            plugins: new GeoExt.ux.plugins.PrintProviderField({
+            plugins: new GeoExt.plugins.PrintProviderField({
                 printProvider: this.printProvider
             })
         };
@@ -289,7 +287,7 @@
                     value: this.comment,
                     emptyText: this.emptyCommentText,
                     hideLabel: true,
-                    plugins: new GeoExt.ux.plugins.PrintProviderField({
+                    plugins: new GeoExt.plugins.PrintProviderField({
                         printProvider: this.printProvider
                     })
                 }
@@ -330,7 +328,7 @@
                     forceSelection: true,
                     triggerAction: "all",
                     selectOnFocus: true,
-                    plugins: new GeoExt.ux.plugins.PrintPageField({
+                    plugins: new GeoExt.plugins.PrintPageField({
                         page: this.printMapPanel.printPage
                     })
                 }

Deleted: sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/PrintForm.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/PrintForm.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/PrintForm.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -1,172 +0,0 @@
-/**
- * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
- * 
- * Published under the BSD license.
- * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
- * of the license.
- */
-Ext.namespace("GeoExt.ux.form")
-
-/** api: (define)
- *  module = GeoExt.ux.form
- *  class = PrintForm
- *  base_link = `Ext.form.FormPanel <http://extjs.com/deploy/dev/docs/?class=Ext.form.FormPanel>`_
- */
-
-/** api: constructor
- *  .. class:: PrintForm
- * 
- *  Provides a base class form for working with
- *  :class:`GeoExt.ux.data.PrintProvider`, :class:`GeoExt.ux.data.PrintPage`
- *  and the plugins available for fields to synchronize. The form uses
- *  a layer to draw the page extent and handle features of print pages,
- *  with a control to modify them.
- *  
- *  This form comes with no fields and is meant to be extended (unless it is
- *  enough to configure print extent, scale and rotation interactively on the
- *  map). See :ref:`GeoExt.ux.form.SimplePrint` for a simple implementation.
- */
-GeoExt.ux.form.PrintForm = Ext.extend(Ext.form.FormPanel, {
-    
-    /** api: config[printProvider]
-     *  :class:`GeoExt.ux.data.PrintProvider` The print provider this form
-     *  is connected to.
-     */
-    
-    /** api: property[printProvider]
-     *  :class:`GeoExt.ux.data.PrintProvider` The print provider this form
-     *  is connected to. Read-only.
-     */
-    printProvider: null,
-    
-    /** api: config[map]
-     *  ``GeoExt.MapPanel``|``OpenLayers.Map`` The map the drag control will
-     *  be added to. Optional if a layer is provided and the layer has already
-     *  been added to a map.
-     */
-    
-    /** private: property[map]
-     *  ``OpenLayers.Map`` The map that layer and control will be added to.
-     */
-    map: null,
-    
-    /** api: config[layer]
-     *  ``OpenLayers.Layer.Vector`` The layer used to render extent and handle
-     *  features to. Optional, will be created if not provided.
-     */
-
-    /** private: property[layer]
-     *  ``OpenLayers.Layer.Vector`` The layer used to render extent and handle
-     *  features to.
-     */
-    layer: null,
-    
-    /** private: property[control]
-     *  ``OpenLayers.Control.DragFeature`` The control used to change extent
-     *  center, rotation and scale.
-     */
-    control: null,
-    
-    /** api: config[pages]
-     *  Array of :class:`GeoExt.ux.data.PrintPage` The pages that this form
-     *  controls. Optional, will be created if not provided.
-     */
-    
-    /** api: property[pages]
-     *  Array of :class:`GeoExt.ux.data.PrintPage` The pages that this form
-     *  controls.
-     */
-    pages: null,
-    
-    /** private: method[initComponent]
-     */
-    initComponent: function() {
-        GeoExt.ux.form.PrintForm.superclass.initComponent.call(this);
-        if(this.map instanceof GeoExt.MapPanel) {
-            this.map = this.map.map;
-        }
-        if(!this.map) {
-            this.map = this.layer.map;
-        }
-        
-        if(!this.pages) {
-            this.pages = [];
-        }
-                        
-        this.initLayer();
-        this.initControl();
-
-        this.on({
-            "show": function() {
-                this.layer.setVisibility(true);
-                this.control.activate();
-            },
-            "hide": function() {
-                this.control.deactivate();
-                this.layer.setVisibility(false);
-            }
-        });
-    },
-    
-    /** private: method[initLayer]
-     */
-    initLayer: function() {
-        if(!this.layer) {
-            this.layer = new OpenLayers.Layer.Vector(null, {
-                displayInLayerSwitcher: false
-            });
-        }
-        if(!this.layer.map) {
-            this.map.addLayer(this.layer);
-        }
-    },
-    
-    /** private: method[initControl]
-     */
-    initControl: function() {
-        var pages = this.pages;
-
-        var updateHandles = function() {
-            for(var i=0, len=pages.length; i<len; ++i) {
-                pages[i].updateHandle();
-            };
-        }
-
-        this.control = new OpenLayers.Control.DragFeature(this.layer, {
-            onDrag: function(feature) {
-                if(feature.geometry instanceof OpenLayers.Geometry.Polygon) {
-                    // a page geometry was dragged
-                    updateHandles();
-                } else if(feature.geometry instanceof OpenLayers.Geometry.Point) {
-                    // a scale/rotation handle was dragged
-                    for(var i=0, len=pages.length; i<len; ++i) {
-                        pages[i].updateByHandle(false);
-                    }
-                }
-            },
-            onComplete: updateHandles
-        });
-
-        this.map.addControl(this.control);
-        this.control.activate();
-    },
-    
-    /** private: method[beforeDestroy]
-     */
-    beforeDestroy: function() {
-        Ext.each(this.pages, function(page) {
-            this.layer.removeFeatures(page.feature, page.handle);
-        }, this);
-        this.control.destroy();
-        if(!this.initialConfig.layer) {
-            this.layer.destroy();
-        }
-        delete this.layer;
-        delete this.map;
-        delete this.control;
-    }
-    
-});
-
-/** api: xtype = gx_printform */
-Ext.reg("gx_printform", GeoExt.ux.form.PrintForm);

Modified: sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/SimplePrint.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/SimplePrint.js	2010-01-13 10:00:55 UTC (rev 1737)
+++ sandbox/ahocevar/playground/ux/Printing/ux/widgets/form/SimplePrint.js	2010-01-13 11:18:51 UTC (rev 1738)
@@ -12,23 +12,23 @@
 Ext.namespace("GeoExt.ux.form")
 
 /** api: (define)
- *  module = GeoExt.ux.form
+ *  module = GeoExt.form
  *  class = SimplePrint
  */
 
 /** api: (extends)
- * ux/widgets/form/PrintForm.js
+ * ../../trunk/lib/GeoExt/widgets/form/PrintForm.js
  */
 
 /** api: constructor
  *  .. class:: SimplePrint
  * 
- *  A simple implementation of :ref:`GeoExt.ux.form.PrintForm`. The form
+ *  A simple implementation of :ref:`GeoExt.form.PrintForm`. The form
  *  creates a single print page. Layout, DPI, scale and rotation are
  *  configurable. A Print button is also added to actually let the
  *  printProvider send the configuration to the print service.
  */
-GeoExt.ux.form.SimplePrint = Ext.extend(GeoExt.ux.form.PrintForm, {
+GeoExt.ux.form.SimplePrint = Ext.extend(GeoExt.form.PrintForm, {
     
     /* begin i18n */
     /** api: config[layoutText] ``String`` i18n */
@@ -80,7 +80,7 @@
     initComponent: function() {
         GeoExt.ux.form.SimplePrint.superclass.initComponent.call(this);
         
-        this.pages.push(new GeoExt.ux.data.PrintPage({
+        this.pages.push(new GeoExt.data.PrintPage({
             printProvider: this.printProvider,
             layer: this.layer
         }));
@@ -124,7 +124,7 @@
             forceSelection: true,
             triggerAction: "all",
             selectOnFocus: true,
-            plugins: new GeoExt.ux.plugins.PrintProviderField()
+            plugins: new GeoExt.plugins.PrintProviderField()
         });
         !(hideUnique && p.dpis.getCount() <= 1) && this.add({
             xtype: "combo",
@@ -136,7 +136,7 @@
             forceSelection: true,
             triggerAction: "all",
             selectOnFocus: true,
-            plugins: new GeoExt.ux.plugins.PrintProviderField()
+            plugins: new GeoExt.plugins.PrintProviderField()
         });
         !(hideUnique && p.scales.getCount() <= 1) && this.add({
             xtype: "combo",
@@ -148,7 +148,7 @@
             forceSelection: true,
             triggerAction: "all",
             selectOnFocus: true,
-            plugins: new GeoExt.ux.plugins.PrintPageField({
+            plugins: new GeoExt.plugins.PrintPageField({
                 page: this.pages[0]
             })
         });
@@ -160,7 +160,7 @@
             validator: function(v) {
                 return !isNaN(v)
             },
-            plugins: new GeoExt.ux.plugins.PrintPageField({
+            plugins: new GeoExt.plugins.PrintPageField({
                 page: this.pages[0]
             })
         });
@@ -182,7 +182,7 @@
     beforeDestroy: function() {
         this.printProvider.un("beforePrint", this.busyMask.show, this.busyMask);
         this.printProvider.un("print", this.busyMask.hide, this.busyMask);
-        GeoExt.ux.SimplePrint.superclass.beforeDestroy.apply(this, arguments);
+        GeoExt.SimplePrint.superclass.beforeDestroy.apply(this, arguments);
     }
     
 });



More information about the Commits mailing list