[fusion-commits] r2209 - in trunk: . lib text widgets widgets/QuickPlot widgets/widgetinfo

svn_fusion at osgeo.org svn_fusion at osgeo.org
Sun Aug 29 21:09:37 EDT 2010


Author: liuar
Date: 2010-08-30 01:09:37 +0000 (Mon, 30 Aug 2010)
New Revision: 2209

Added:
   trunk/lib/MapMessage.js
   trunk/widgets/QuickPlot.js
   trunk/widgets/QuickPlot/
   trunk/widgets/QuickPlot/GeneratePicture.php
   trunk/widgets/QuickPlot/MapCapturer.js
   trunk/widgets/QuickPlot/PreviewDialog.js
   trunk/widgets/QuickPlot/QuickPlotPanel.js
   trunk/widgets/QuickPlot/QuickPlotPanel.php
   trunk/widgets/QuickPlot/QuickPlotPanel.templ
   trunk/widgets/QuickPlot/QuickPlotPreview.js
   trunk/widgets/QuickPlot/QuickPlotPreviewInner.php
   trunk/widgets/QuickPlot/QuickPlotPreviewInner.templ
   trunk/widgets/QuickPlot/north_arrow.png
   trunk/widgets/QuickPlot/pixel.gif
   trunk/widgets/QuickPlot/progress_indicator.gif
   trunk/widgets/QuickPlot/rotate.cur
   trunk/widgets/widgetinfo/quickplot.xml
Modified:
   trunk/build.xml
   trunk/lib/ApplicationDefinition.js
   trunk/lib/fusion.js
   trunk/text/en
   trunk/text/en.json
   trunk/text/fr
   trunk/text/fr.json
Log:
Submit on behalf of Mars Wu.
The implementation of QuickPlot.

Modified: trunk/build.xml
===================================================================
--- trunk/build.xml	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/build.xml	2010-08-30 01:09:37 UTC (rev 2209)
@@ -221,7 +221,8 @@
                           MGBroker.js
                           Widget.js
                           Search.js
-                          Map.js"
+                          Map.js
+                          MapMessage.js"
         />
         <filelist dir="${build.home}/layers" files="Layers.js"/>
         <fileset dir="${build.home}/text" includes="**/*.json"/>

Modified: trunk/lib/ApplicationDefinition.js
===================================================================
--- trunk/lib/ApplicationDefinition.js	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/lib/ApplicationDefinition.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -677,6 +677,14 @@
         this.mapWidget.setMenu();
         $(this.mapWidgetTag.name).widget = this.mapWidget;
 
+        //create the floating map message
+        this.mapWidget.message = new Fusion.MapMessage(this.mapWidget.oMapOL.viewPortDiv);
+        this.mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, (function(){
+                if (this.message != null){
+                    this.message.refreshLayout();
+                }
+            }).bind(this.mapWidget));
+
         //create all the other widgets for the widget set
         for (var i=0; i<this.widgetTags.length; i++) {
             this.widgetTags[i].create(this);

Added: trunk/lib/MapMessage.js
===================================================================
--- trunk/lib/MapMessage.js	                        (rev 0)
+++ trunk/lib/MapMessage.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ * Class: Fusion.MapMessage
+ *
+ * It is to show a floating message bar over the main map viewer
+ */
+Fusion.MapMessage = OpenLayers.Class({
+	parentNode : null,
+	domObj : null,
+	leadingIcon : null,
+	textCell : null,
+	message : "",
+	
+	infoIconName : "images/icons/info.png",
+	warningIconName : "images/icons/warning.png",
+	errorIconName : "images/icons/error.png",
+	
+	containerCssText : "position:absolute; z-index:10000; padding:10px; border:solid 2px #ECECEC; background:#FFFFBB",
+	iconCssText : "margin-right:10px",
+	textCellCssText : "width:100%; vertical-align:top; font: 8pt Tahoma",
+
+	opacity: 0.95,
+	
+	initialize : function(parentNode)
+	{
+		this.parentNode = $(parentNode);
+		// Create the div container
+		var container   = document.createElement("div");
+		container.style.visibility = "hidden";
+		this.container  = $(container);
+		parentNode.appendChild(container);
+
+		container.style.cssText = this.containerCssText;
+		var offset = {left:10, top:10};
+		container.style.left = offset.left + "px";
+		container.style.top  = offset.top  + "px";
+		
+		// Create the inner table
+		var table = document.createElement("table");
+		container.appendChild(table);
+		table.style.width = "100%";
+		table.cellSpacing = "0";
+		table.cellPadding = "0";
+		table.border      = "0";
+		// Create the table row
+		var row   = table.insertRow(0);
+		// The icon cell
+		var cell  = row.insertCell(0);
+		// Add the info icon by default
+		var icon  = document.createElement("img");
+		icon.src  = this.infoIconName;
+		cell.appendChild(icon);
+		icon.style.cssText = this.iconCssText;
+		this.leadingIcon   = icon;
+		// Create the text cell
+		cell      = row.insertCell(1);
+		cell.style.cssText = this.textCellCssText;
+		this.textCell = $(cell);
+		this.textCell.innerHTML = this.message;
+		
+		this.refreshLayout();
+		// Hide message bar by default
+		this.container.setOpacity(0);
+		this.container.style.visibility = "visible";
+	},
+	
+	info : function(message)
+	{
+		this.message = message;
+		this.leadingIcon.src = this.infoIconName;
+		this.show();
+	},
+	
+	warn : function(message)
+	{
+		this.message = message;
+		this.leadingIcon.src = this.warningIconName;
+		this.show();
+	},
+	
+	error : function(message)
+	{
+		this.message = message;
+		this.leadingIcon.src = this.errorIconName;
+		this.show();
+	},
+	
+	clear : function()
+	{
+		this.message = "";
+		this.textCell.innerHTML = "";
+		this.hide();
+	},
+	
+	show : function()
+	{
+		this.textCell.innerHTML = this.message;
+		this.container.fade(this.opacity);
+	},
+	
+	hide : function()
+	{
+		this.container.fade(0);
+	},
+	
+	refreshLayout: function()
+	{
+		// 44 = 2 * padding (10) + 2 * offset(10) + 2 * border (2)
+		this.container.style.width  = this.parentNode.offsetWidth - 44 + "px";
+	},
+	
+	CLASS_NAME: "Fusion.MapMessage"
+});
\ No newline at end of file

Modified: trunk/lib/fusion.js
===================================================================
--- trunk/lib/fusion.js	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/lib/fusion.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -1365,6 +1365,7 @@
                             'lib/MGBroker.js',
                             'lib/Widget.js',
                             'lib/Map.js',
+                            'lib/MapMessage.js',
                             'layers/Layers.js',
                             'lib/Search.js',
                             'text/en.json'];

Modified: trunk/text/en
===================================================================
--- trunk/text/en	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/text/en	2010-08-30 01:09:37 UTC (rev 2209)
@@ -332,3 +332,18 @@
 
 # Localized Icon Files
 POWEREDBYICON           = PoweredBy_en.gif
+
+# Quick Plot UI
+QUICKPLOT_HEADER        = Quick Plot
+QUICKPLOT_TITLE         = Title
+QUICKPLOT_SUBTITLE      = Sub title
+QUICKPLOT_PAPER_SIZE    = Paper size
+QUICKPLOT_SCALING       = Scaling
+QUICKPLOT_DPI           = Print DPI
+QUICKPLOT_GENERATE      = Generate
+QUICKPLOT_ADVANCED_OPTIONS = Advanced options
+QUICKPLOT_PRINT         = Print
+QUICKPLOT_CANCEL        = Cancel
+QUICKPLOT_PREVIEW_ERROR = The application resources required to generate the plot exceed the settings defined by the administrator
+QUICKPLOT_RESOLUTION_WARNING = The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot
+QUICKPLOT_SCALE_LABEL   = Scale

Modified: trunk/text/en.json
===================================================================
--- trunk/text/en.json	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/text/en.json	2010-08-30 01:09:37 UTC (rev 2209)
@@ -59,5 +59,6 @@
 'printShowLegend':'Show Legend?',
 'printShowNorthArrow':'Show North Arrow?',
 
+'quickPlotResolutionWarning':'The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot',
 'end': ''
 };

Modified: trunk/text/fr
===================================================================
--- trunk/text/fr	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/text/fr	2010-08-30 01:09:37 UTC (rev 2209)
@@ -333,3 +333,18 @@
 
 # Localized Icon Files
 POWEREDBYICON           = PoweredBy_en.gif
+
+# Quick Plot UI
+QUICKPLOT_HEADER        = Quick Plot
+QUICKPLOT_TITLE         = Title
+QUICKPLOT_SUBTITLE      = Sub title
+QUICKPLOT_PAPER_SIZE    = Paper size
+QUICKPLOT_SCALING       = Scaling
+QUICKPLOT_DPI           = Print DPI
+QUICKPLOT_GENERATE      = Generate
+QUICKPLOT_ADVANCED_OPTIONS = Advanced options
+QUICKPLOT_PRINT         = Print
+QUICKPLOT_CANCEL        = Cancel
+QUICKPLOT_PREVIEW_ERROR = The application resources required to generate the plot exceed the settings defined by the administrator
+QUICKPLOT_RESOLUTION_WARNING = The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot
+QUICKPLOT_SCALE_LABEL   = Scale

Modified: trunk/text/fr.json
===================================================================
--- trunk/text/fr.json	2010-08-26 13:49:01 UTC (rev 2208)
+++ trunk/text/fr.json	2010-08-30 01:09:37 UTC (rev 2209)
@@ -50,5 +50,6 @@
 'printGenerate': 'Generate',
 'maptipLinkText': 'Cliquer pour plus d information',
 
+'quickPlotResolutionWarning':'The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot',
 'end': ''
 };

Added: trunk/widgets/QuickPlot/GeneratePicture.php
===================================================================
--- trunk/widgets/QuickPlot/GeneratePicture.php	                        (rev 0)
+++ trunk/widgets/QuickPlot/GeneratePicture.php	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,181 @@
+<?php
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Utilities.php';
+
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Common.php';
+    
+    $sessionID = "";
+    $mapName   = "";
+    $rotation  = 0.0;
+    $printDpi  = 300;
+    $scaleDenominator = 0;
+    $captureBox;
+    $normalizedCapture;
+    $printSize;
+    $paperSize;
+    
+    GetParameters();
+    GenerateMap($printSize);
+?>
+
+<?php    
+    function GetParameters()
+    {
+        global $sessionID, $mapName, $printDpi, $rotation, $paperSize, $captureBox, $printSize, $scaleDenominator, $normalizedCapture;
+        $args = $_GET;
+        if ($_SERVER["REQUEST_METHOD"] == "POST")
+        {
+            $args = $_POST;
+        }
+        
+        // Not necessary to validate the parameters    	
+        $sessionID   = $args["session_id"];
+        $mapName     = $args["map_name"];
+        $rotation    = floatval($args["rotation"]);
+        $printDpi    = intval($args["print_dpi"]);
+
+        $scaleDenominator = intval($args["scale_denominator"]);
+
+        $array       = explode(",", $args["paper_size"]);
+        $paperSize   = new Size(floatval($array[0]), floatval($array[1]));
+        $printSize   = new Size($paperSize->width / 25.4 * $printDpi, $paperSize->height / 25.4 * $printDpi);
+        
+        $array       = explode(",", $args["box"]);
+        $captureBox  = CreatePolygon($array);
+        
+        $array       = explode(",", $args["normalized_box"]);
+        $normalizedCapture = CreatePolygon($array);
+    }
+    
+    function CreatePolygon($coordinates)
+    {
+        $geometryFactory      = new MgGeometryFactory();
+        $coordinateCollection = new MgCoordinateCollection();
+        $linearRingCollection = new MgLinearRingCollection();
+        
+        for ($index = 0; $index < count($coordinates); ++$index)
+        {
+            $coordinate = $geometryFactory->CreateCoordinateXY(floatval($coordinates[$index]), floatval($coordinates[++$index]));
+            $coordinateCollection->Add($coordinate);
+        }
+        
+        $coordinateCollection->Add($geometryFactory->CreateCoordinateXY(floatval($coordinates[0]), floatval($coordinates[1])));
+        
+        $linearRingCollection = $geometryFactory->CreateLinearRing($coordinateCollection);
+        $captureBox           = $geometryFactory->CreatePolygon($linearRingCollection, null);
+        
+        return $captureBox;
+    }
+
+    function GenerateMap($size)
+    {
+        global $sessionID, $mapName, $captureBox, $printSize, $normalizedCapture, $rotation, $scaleDenominator, $printDpi;
+        
+        $userInfo         = new MgUserInformation($sessionID);
+        $siteConnection   = new MgSiteConnection();
+        $siteConnection->Open($userInfo);
+        $resourceService  = $siteConnection->CreateService(MgServiceType::ResourceService);
+        $renderingService = $siteConnection->CreateService(MgServiceType::RenderingService);
+        
+        $map = new MgMap();
+        $map->Open($resourceService, $mapName);
+        
+        $selection        = new MgSelection($map);
+        $color            = new MgColor(255, 255, 255);
+        
+        // Calculate the generated picture size
+        $envelope         = $captureBox->Envelope();
+        $normalizedE      = $normalizedCapture->Envelope();
+        $size1            = new Size($envelope->getWidth(), $envelope->getHeight());
+        $size2            = new Size($normalizedE->getWidth(), $normalizedE->getHeight());
+        $toSize           = new Size($size1->width / $size2->width * $size->width, $size1->height / $size2->height * $size->height);
+        $center           = $captureBox->GetCentroid()->GetCoordinate();
+        
+        // Get the map agent url
+        // Get the correct http protocal
+        $mapAgent = "http";
+        if ($_SERVER["HTTPS"] == "on")
+        {
+            $mapAgent .= "s";
+        }
+        // Get the correct port number
+        $mapAgent .= "://" . $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"];
+        // Get the correct virtual directory
+        $mapAgent .= substr($_SERVER["URL"], 0, strpos($_SERVER["URL"], "/", 1) + 1);
+        $mapAgent .="/mapagent/mapagent.fcgi?VERSION=1.0.0&OPERATION=GETMAPIMAGE" .
+                    "&SESSION=$sessionID" .  
+                    "&MAPNAME=$mapName" .
+                    "&FORMAT=PNG" .
+                    "&SETVIEWCENTERX=" . $center->GetX() .
+                    "&SETVIEWCENTERY=" . $center->GetY() .
+                    "&SETVIEWSCALE=$scaleDenominator" . 
+                    "&SETDISPLAYDPI=$printDpi" . 
+                    "&SETDISPLAYWIDTH=$toSize->width" . 
+                    "&SETDISPLAYHEIGHT=$toSize->height" . 
+                    "&CLIP=0";
+        $image = imagecreatefrompng($mapAgent);
+        // Rotate the picture back to be normalized
+        $normalizedImg = imagerotate($image, -$rotation, 0);
+        // Free the original image
+        imagedestroy($image);
+        // Crop the normalized image
+        $croppedImg = imagecreatetruecolor($size->width, $size->height);
+        imagecopy($croppedImg, $normalizedImg, 0, 0, (imagesx($normalizedImg) - $size->width) / 2, (imagesy($normalizedImg) - $size->height) / 2, $size->width, $size->height);
+        // Free the normalized image
+        imagedestroy($normalizedImg);
+        // Draw the north arrow on the map
+        DrawNorthArrow($croppedImg);
+
+        header ("Content-type: image/png"); 
+        imagepng($croppedImg);
+        imagedestroy($croppedImg);
+    }
+    
+    function DrawNorthArrow($map)
+    {
+        global $paperSize, $rotation;
+        
+        // Load the north arrow image which has a 300 dpi resolution
+        $na         = imagecreatefrompng("./north_arrow.png");
+        // Rotate the north arrow according to the capture rotation
+        $transparent= imagecolortransparent($na);
+        $rotatedNa  = imagerotate($na, -$rotation, $transparent);
+        // Free the north arrow image
+        imagedestroy($na);
+        // Get the size of north arrow image
+        $naWidth    = imagesx($rotatedNa);
+        $naHeight   = imagesy($rotatedNa);
+        // Get the map size
+        $mapWidth   = imagesx($map);
+        $mapHeight  = imagesy($map);
+        // Get the logical resolution of map
+        $resolution = $mapWidth * 25.4 / $paperSize->width;
+        // On printed paper, north arrow is located at the right bottom corner with 6 MM margin
+        $naRes      = 300;
+        $naMargin   = 12;
+        // Calculate the margin as pixels according to the resolutions
+        $margin     = $resolution * $naMargin / 25.4;
+        // Get the width of the north arrow on the map picture
+        $drawWidth  = $naWidth * $resolution / $naRes;
+        $drawHeight = $naHeight * $resolution / $naRes;
+        // Draw the north arrow on the map picture
+        imagecopyresized($map, $rotatedNa, $mapWidth - $drawWidth - $margin, $mapHeight - $drawHeight - $margin, 0, 0, $drawWidth, $drawHeight, $naWidth, $naHeight);
+        // Free the north arrow image
+        imagedestroy($rotatedNa); 
+    }
+?>
+
+<?php    
+    class Size
+    {
+        public $width;
+        public $height;
+        
+        public function __construct($width, $height)
+        {
+            $this->width  = $width;
+            $this->height = $height;
+        }
+    }
+?>
\ No newline at end of file

Added: trunk/widgets/QuickPlot/MapCapturer.js
===================================================================
--- trunk/widgets/QuickPlot/MapCapturer.js	                        (rev 0)
+++ trunk/widgets/QuickPlot/MapCapturer.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,853 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+ 
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ * @requires OpenLayers/Handler/Feature.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MapCapturer
+ * The MapCapturer control shows a box on the map to illustrate the area that will be captured.
+ * Normally the capture information will be used to print the map. If the MapCapturer is configured not
+ * show the capture box, then the current viewport will be used as the capture area.
+ * 
+ * The user can move or rotate the capture box to change the area he'd like to capture.
+ * And the user can hold SHIFT key to snapp to a certain angle when he is rotating the capture box
+ *
+ * Inherits From:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.MapCapturer = OpenLayers.Class(OpenLayers.Control, {
+    /**
+     * Property: layer
+     * {<OpenLayers.Layer.Vector>}
+     */
+    layer: null,
+    
+    /**
+     * Property: feature. The active feature which is repsonding to mouse action
+     * {<OpenLayers.Feature.Vector>}
+     */
+    feature: null,
+
+    /**
+     * Property: captureBox. It's the feature represnting the capture area
+     * {<OpenLayers.Feature.Vector>}
+     */
+    captureBox: null,
+    
+    /**
+     * Property: rotateHandle. It's the feature representing a rotate handle
+     * (<OpenLayers.Feature.Vector)
+     */
+    rotateHandle: null,
+    
+    /**
+     * Property: rotateHandleStart. It's the feature representing the center point of capture box.
+     * And it's also the start point of the rotate handle.
+     * (<OpenLayers.Feature.Vector>)
+     */
+    rotateHandleStart: null,
+    
+    /**
+     * Property: rotateHandleEnd. It's the feature responding to the rotate command.
+     * (<OpenLayers.Feature.Vector>)
+     */
+    rotateHandleEnd: null,
+
+    /**
+     * Property: snappingLine. It's the feature indicating a certain angle to snap to. It shows up in the rotate process
+     * (<OpenLayers.Feature.Vector>)
+     */
+    snappingLine: null,
+    
+    /**
+     * Property: rotation. The rotation of the capture box
+     * {float}
+     */	
+    rotation: 0.0,
+    
+    /**
+     * Property: rotateHandleLength. Defines the length of the rotate handle 
+     * in pixel. default is 30 pixels
+     * {int}
+     */	
+    rotateHandleLength: 30,
+    
+    /**
+     * Property: captureBoxStyle. Style for the capture box
+     * {<OpenLayers.Style>}
+     */	
+    captureBoxStyle: null,
+    
+    /**
+     * Property: rotateHandleStyle. Style for the rotate handle
+     * (<OpenLayers.Style>)
+     */
+    rotateHandleStyle: null,
+    
+    /**
+     * Property: rotateHandlePointStyle. Style for the snap handle's start and end points
+     * (<OpenLayers.Style>)
+     */
+    rotateHandlePointStyle: null,
+    
+    /**
+     * Property: snappingLineStyle. Style for the snapping line
+     * (<OpenLayers.Style>)
+     */
+    snappingLineStyle: null,
+
+    /**
+     * Indicates if the capture box is enabled. An enabled capture box will show up on the map
+     * {bool}
+     */	
+    enabled: false,
+    
+    /**
+     * Property: warningMessage. The warning message when the capture box cannot display completely in current zoom level
+     * (string)
+     */
+    warningMessage: OpenLayers.i18n("quickPlotResolutionWarning"),
+    
+    /**
+     * Property: rotateSnappingStep. Defines the rotate snapping angle step. In degrees
+     * (int)
+     */
+    rotateSnappingStep: 45,
+    
+    /**
+     * Property: rotateSnappingTolerance. Defines the rotate snapping tolerance. In degress
+     */
+    rotateSnappingTolerance: 2,
+    
+    /**
+     * Property: lastPixel. The last position the mouse action was responded
+     * {<OpenLayers.Pixel>}
+     */
+    lastPixel: null,
+
+    /**
+     * Constructor: OpenLayers.Control.DragFeature
+     * Create a new control to drag features.
+     *
+     * Parameters:
+     * map - The widget map which encapsulates an OpenLayers.Map
+     *
+     * options - {Object} Optional object whose properties will be set on the control.
+     */
+    initialize: function(map, options) 
+    {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        
+        // Initialize the styles
+        this.captureBoxStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.captureBoxStyle.fillOpacity    = 0.8;
+        this.captureBoxStyle.fillColor      = "#476387";
+        this.captureBoxStyle.strokeColor    = "#39506F";
+        
+        this.rotateHandleStyle              = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.rotateHandleStyle.strokeColor  = "#39506F";
+        this.rotateHandlePointStyle             = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.rotateHandlePointStyle.strokeColor = "#39506F";
+        this.rotateHandlePointStyle.fillOpacity = 1.0;
+        this.rotateHandlePointStyle.fillColor   = "#476387";
+        this.rotateHandlePointStyle.pointRadius = 4;
+        
+        this.snappingLineStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.snappingLineStyle.strokeOpacity   = 0.8;
+        this.snappingLineStyle.strokeColor     = "black";
+        this.snappingLineStyle.strokeDashstyle = "dot";
+
+        
+        // The cursor styles
+        this.cursorMove   = "move";
+        this.cursorRotate = "url(../../../Widgets/QuickPlot/rotate.cur), default";
+        
+        // The widget map
+        this.wMap = map;
+        
+        // Create a new layer to show the capture box
+        this.layer  = new OpenLayers.Layer.Vector("Map Capturer Layer");
+        map.oMapOL.addLayer(this.layer);
+        
+        // Create the features
+        this.captureBox        = new OpenLayers.Feature.Vector(null, null, this.captureBoxStyle);
+        this.rotateHandle      = new OpenLayers.Feature.Vector(null, null, this.rotateHandleStyle);
+        this.rotateHandleStart = new OpenLayers.Feature.Vector(null, null, this.rotateHandlePointStyle);
+        this.rotateHandleEnd   = new OpenLayers.Feature.Vector(null, null, this.rotateHandlePointStyle);
+        this.snappingLine      = new OpenLayers.Feature.Vector(null, null, this.snappingLineStyle);
+        
+        // Add the features into the layer
+        this.layer.addFeatures([this.captureBox, this.rotateHandle, this.rotateHandleStart, this.rotateHandleEnd, this.snappingLine]);
+
+        // Overwrite layer's drawFeatures method to consider the map capturer's enable / disable
+        this.layer.drawFeature = (function(f, item, style)
+                {
+                    if (this.enabled)
+                    {
+                        f.apply(this.layer, Array.prototype.slice.call(arguments, 1));
+                    }
+                }).bind(this, this.layer.drawFeature);
+        this.handlers = 
+        {
+            drag: new OpenLayers.Handler.Drag(
+                this, OpenLayers.Util.extend({
+                    down: this.downFeature,
+                    up: this.upFeature,
+                    out: this.cancel,
+                    done: this.doneDragging
+                }, this.dragCallbacks)),
+            feature: new OpenLayers.Handler.Feature(
+                this, this.layer, OpenLayers.Util.extend({
+                    over: this.overFeature,
+                    out: this.outFeature
+                }, this.featureCallbacks),
+                {geometryTypes: this.geometryTypes}
+            )
+        };
+
+        // List to the mouse move event
+        this.handlers.drag.move = this.mouseMove.bind(this);
+        
+        // Listen to MAP_EXTENTS_CHANGED event to refresh the outer box because the 'delta' is fixed regardless current scale
+        var oMap = this.wMap.oMapOL;
+        oMap.events.register("zoomend", this, this.drawFeatures.bind(this));
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Take care of things that are not handled in superclass
+     */
+    destroy: function() 
+    {
+        this.layer = null;
+        OpenLayers.Control.prototype.destroy.apply(this, []);
+    },
+
+    /**
+     * APIMethod: activate
+     * Activate the control and the feature handler.
+     * 
+     * Returns:
+     * {Boolean} Successfully activated the control and feature handler.
+     */
+    activate: function() 
+    {
+        return (this.handlers.feature.activate() &&
+                OpenLayers.Control.prototype.activate.apply(this, arguments));
+    },
+
+    /**
+     * APIMethod: deactivate
+     * Deactivate the control and all handlers.
+     * 
+     * Returns:
+     * {Boolean} Successfully deactivated the control.
+     */
+    deactivate: function() {
+        // The return from the handlers is unimportant in this case
+        this.handlers.feature.deactivate();
+        this.handlers.drag.deactivate();
+        this.feature   = null;
+        this.dragging  = false;
+        this.lastPixel = null;
+
+        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
+    },
+
+    /**
+     * Method: overFeature
+     * Called when the feature handler detects a mouse-over on a feature.
+     *     This enables the drag control if the event target is the outer polygon,
+     *		and the rotate control will be activated if the event target is the inner polygon
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The selected feature.
+     */
+    overFeature: function(feature) 
+    {
+        // The feature that the cursor stops on
+        this.stopFeature = feature;
+        
+        if(!this.handlers.drag.dragging) 
+        {
+            this.feature = feature;
+            this.handlers.drag.activate();
+            this.over = true;
+            
+            this.setCursor(); 
+        } 
+        else 
+        {
+            if(this.captureBox.id == feature.id || this.rotateHandleEnd.id == feature.id) 
+            {
+                this.over = true;
+            } 
+            else 
+            {
+                this.over = false;
+            }
+        }
+    },
+    
+    /**
+     * Method: dragging
+     * Check if it's currently in dragging to move mode
+     */
+    dragging: function() 
+    {
+        if (this.feature && this.captureBox)
+        {
+            return this.feature.id == this.captureBox.id || this.feature.id == this.rotateHandleStart.id;
+        }
+        
+        return false;
+    },
+    
+    /**
+     * Method: dragging
+     * Check if it's currently in dragging to rotate mode
+     */
+    rotating: function() 
+    {
+        return this.feature && this.rotateHandleEnd && this.feature.id == this.rotateHandleEnd.id;
+    },
+
+    /**
+     * Method: downFeature
+     * Called when the drag handler detects a mouse-down.
+     *
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
+     */
+    downFeature: function(pixel) 
+    {
+        this.setCursor();
+        this.lastPixel = pixel;
+    },
+    
+    /**
+     * Method: setCursor
+     * Set the cursor according to current action: moving or rotating
+     */
+    setCursor: function() 
+    {
+        if (this.dragging())
+        {
+            this.wMap.setCursor(this.cursorMove);
+        }
+        else if (this.rotating())
+        {
+            this.wMap.setCursor(this.cursorRotate);
+        }
+    },
+    /**
+     * Method: moveFeature
+     * Called when the drag handler detects a mouse-move.  Also calls the
+     *     optional onDrag method.
+     */
+    mouseMove: function(evt) 
+    {
+        if (this.dragging()) 
+        {
+            this.moveFeature(evt);
+        }
+        else if (this.rotating()) 
+        {
+            this.rotateFeature(evt);
+        }
+    },
+    
+    /**
+     * Method: moveFeature
+     *  Move the feature according to the mouse-move
+     */
+    moveFeature: function(evt) 
+    {
+        pixel     = evt.xy;
+        var res   = this.wMap.getResolution();
+        var delta = {x:res * (pixel.x - this.lastPixel.x), y:res * (this.lastPixel.y - pixel.y)};
+        
+        var features = this.layer.features;
+        for (var i = 0; i < features.length; ++i)
+        {
+            // Don't touch the snapping line
+            if (features[i].geometry != null && features[i].id != this.snappingLine.id)
+            {
+                features[i].geometry.move(delta.x, delta.y);
+                this.layer.drawFeature(features[i]);
+            }
+        }
+        
+        this.lastPixel = pixel;
+    },
+    
+    /**
+     * Method: moveFeature
+     * Called when the drag handler detects a mouse-move.  Also calls the
+     *     optional onDrag method.
+     */
+    rotateFeature: function(evt)
+    {
+        pixel = evt.xy;
+        var centroid   = this.captureBox.geometry.getCentroid();
+        var origin     = this.map.getViewPortPxFromLonLat(new OpenLayers.LonLat(centroid.x, centroid.y));
+        var angle      = this.calculateAngle(pixel, origin);
+        var rotation   = this.rotation + angle;
+
+        if (evt.shiftKey)
+        {
+            var a = rotation % this.rotateSnappingStep;
+            var b = Math.round(rotation / this.rotateSnappingStep);
+            var targetRotation = rotation;
+            
+            if (Math.abs(a) <= this.rotateSnappingTolerance || Math.abs(a)>= this.rotateSnappingStep - this.rotateSnappingTolerance)
+            {
+                targetRotation = b * this.rotateSnappingStep;
+                
+                // Draw the snapping guide
+                if (this.snappingLine.geometry == null)
+                {
+                    this.drawSnappingHint(targetRotation);
+                }
+            }
+            else
+            {
+                this.clearSnappingHint();
+            }
+            
+            angle = targetRotation - this.rotation;
+        }
+        else
+        {
+            this.clearSnappingHint();
+        }
+        
+        this.rotation += angle;
+        
+        var features = this.layer.features;
+        for (var i = 0; i < features.length; ++i)
+        {
+            // Don't touch the snapping line here because the snapping line is controlled only by drawSnappingHint
+            if (features[i].geometry != null && features[i].id != this.snappingLine.id)
+            {
+                features[i].geometry.rotate(angle, centroid);
+                this.layer.drawFeature(features[i]);
+            }
+        }
+
+        this.lastPixel = angle == 0 ? this.lastPixel : pixel;
+    },
+    
+    /**
+     * Method: drawSnappingHint
+     * Draw the snapping line
+     */
+    drawSnappingHint: function(angle)
+    {
+        var viewSize = this.wMap.getCurrentExtents().getSize();
+        var length   = Math.sqrt(Math.pow(viewSize.w, 2) + Math.pow(viewSize.h, 2));
+        var origin   = this.captureBox.geometry.getCentroid();
+        
+        var points   = [];
+        points.push(new OpenLayers.Geometry.Point(origin.x - length, origin.y));
+        points.push(new OpenLayers.Geometry.Point(origin.x + length, origin.y));
+        var hint     = new OpenLayers.Geometry.LineString(points);
+        
+        hint.rotate(angle + 90, origin);
+        
+        this.snappingLine.geometry = hint;
+        this.layer.drawFeature(this.snappingLine);
+    },
+    
+    /**
+     * Method: clearSnappingHint
+     * Clear the snapping line
+     */
+    clearSnappingHint: function()
+    {
+        if (this.snappingLine != null && this.snappingLine.geometry != null)
+        {
+            this.layer.eraseFeatures([this.snappingLine]);
+            this.snappingLine.geometry = null;
+        }
+    },
+    
+    /**
+     * Method: calculateAngle
+     * Calculates the rotate angle, in degree and counterclockwise
+     */
+    calculateAngle: function(pixel, origin)
+    {
+        var angle1 = Math.atan2(pixel.y - origin.y, pixel.x - origin.x);
+        var angle2 = Math.atan2(this.lastPixel.y - origin.y, this.lastPixel.x - origin.x);
+        return (angle2 - angle1) * 180 / Math.PI;
+    },
+
+    /**
+     * Method: upFeature
+     * Called when the drag handler detects a mouse-up.
+     * 
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
+     */
+    upFeature: function(pixel) 
+    {
+        if(!this.over) 
+        {
+            this.handlers.drag.deactivate();
+        }
+        else
+        {
+            // Set the last-stop feature to be the active one
+            this.feature = this.stopFeature;
+            // Set the correct cursor
+            this.setCursor();
+        }
+        
+        this.clearSnappingHint();
+    },
+
+    /**
+     * Method: outFeature
+     * Called when the feature handler detects a mouse-out on a feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left.
+     */
+    outFeature: function(feature) 
+    {
+        if(!this.handlers.drag.dragging) 
+        {
+            this.over = false;
+            this.handlers.drag.deactivate();
+            this.wMap.setCursor("auto");            
+            this.feature = null;
+        } 
+        else 
+        {
+            if(this.feature.id == feature.id) 
+            {
+                this.over = false;
+            }
+        }
+    },
+        
+    /**
+     * Method: cancel
+     * Called when the drag handler detects a mouse-out (from the map viewport).
+     */
+    cancel: function() 
+    {
+        this.handlers.drag.deactivate();
+        this.over = false;
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the control and all handlers.
+     *
+     * Parameters: 
+     * map - {<OpenLayers.Map>} The control's map.
+     */
+    setMap: function(map) 
+    {
+        this.handlers.drag.setMap(map);
+        this.handlers.feature.setMap(map);
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+    },
+
+    /**
+     * Method: setRegion
+     * Set the size of the capture box. Then the box will be redrawn on the map
+     *
+     * Parameters: 
+     * paperSize - {<OpenLayers.Size>} The paper size, in mm
+     * scaleDenominator - The denominator of target scale
+     */
+    setSize: function(paperSize, scaleDenominator) 
+    {
+        this.paperSize        = paperSize;
+        this.scaleDenominator = scaleDenominator;
+        this.drawFeatures();
+        // Active the handler
+        this.activate();
+    },
+    
+    /**
+     * Method: drawFeatures
+     * Draw the capture box, rotate handle etc. on the map
+     */
+    drawFeatures: function()
+    {
+        // The paper size is not set yet, so don't draw the features
+        if (!this.paperSize)
+        {
+            return;
+        }
+        
+        // Clear the previous drawn features
+        this.clearFeatures();
+                
+        this.createCaptureBox();
+        this.createRotateHandle();
+        
+        // Draw the box only when control is enabled and the resolution is valid
+        if (this.enabled) 
+        {
+            if (this.validateResolution())
+            {
+                this.layer.features.each(function(item){item.layer.drawFeature(item);});
+                this.wMap.message.hide();
+            }
+            else
+            {
+                this.wMap.message.warn(this.warningMessage);
+            }
+        }
+    },
+    
+    /**
+     * Method: clearFeatures:
+     * Clear the capture box, rotate handle etc. from the map
+     */
+    clearFeatures: function()
+    {
+        // Clear the previous drawn features
+        var features = this.layer.features;
+        var toErase  = [];
+        var feature  = null;
+        
+        for (var i = 0; i < features.length; ++i)
+        {
+            feature = features[i];
+            if (feature.geometry != null)
+            {
+                toErase.push(feature);
+            }
+        }
+        
+        this.layer.eraseFeatures(toErase);
+    },
+    
+    /**
+     * Method: createCaptureBox
+     * Create the capture box feature
+     */
+    createCaptureBox: function()
+    {
+        var origin   = null;
+        var rotation = 0;
+        
+        if (this.captureBox.geometry != null)
+        {
+            origin   = this.captureBox.geometry.getCentroid();
+            rotation = this.rotation;
+        }
+        else
+        {
+            origin   = this.wMap.getCurrentCenter();
+        }
+        
+        var factor = this.scaleDenominator / (this.wMap.getMetersPerUnit() * 1000 * 2);
+        
+        var pointList = [];
+        pointList.push(new OpenLayers.Geometry.Point(origin.x - this.paperSize.w * factor, origin.y - this.paperSize.h * factor));
+        pointList.push(new OpenLayers.Geometry.Point(origin.x + this.paperSize.w * factor, origin.y - this.paperSize.h * factor));
+        pointList.push(new OpenLayers.Geometry.Point(origin.x + this.paperSize.w * factor, origin.y + this.paperSize.h * factor));
+        pointList.push(new OpenLayers.Geometry.Point(origin.x - this.paperSize.w * factor, origin.y + this.paperSize.h * factor));
+        pointList.push(pointList[0]);
+        
+        var box = new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(pointList));
+        
+        if (rotation != 0)
+        {
+            box.rotate(rotation, box.getCentroid());
+        }
+        
+        this.captureBox.geometry = box;
+    },
+
+    /**
+     * Method: createRotateHandle
+     * Create the rotate handle feature
+     */
+    createRotateHandle: function()
+    {
+        var box        = this.captureBox.geometry.clone();
+        var startPoint = box.getCentroid();
+        
+        if (this.rotation != 0)
+        {
+            box.rotate(-this.rotation, startPoint);
+        }
+        
+        var length = this.rotateHandleLength * this.wMap.getResolution();
+        
+        var endPoint   = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y + box.getBounds().getHeight() / 2 + length);
+        var line       = new OpenLayers.Geometry.LineString([startPoint.clone(), endPoint.clone()]);
+        
+        if (this.rotation != 0)
+        {
+            endPoint.rotate(this.rotation, startPoint);
+            line.rotate(this.rotation, startPoint);
+        }
+        
+        this.rotateHandle.geometry      = line;
+        this.rotateHandleStart.geometry = startPoint;
+        this.rotateHandleEnd.geometry   = endPoint;
+    },
+    
+    /**
+     * Method: validateResolution
+     * Check if the capture box could display completely on current screen view port.
+     * If it cannot, then an warning message will show up to warn the user. Then the user could zoom out to get
+     * the box back
+     * 
+     * Returns:
+     * (Boolean) True if the box can display completely, otherwise false.
+     *
+     */
+    validateResolution: function() 
+    {
+        if (this.captureBox)
+        {
+            var screenSize = this.map.getExtent().getSize();
+            var boxSize    = this.captureBox.geometry.getBounds().getSize();
+            
+            if (boxSize.w < screenSize.w || boxSize.h < screenSize.h)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    },
+    
+    /**
+     * Method: getCaptureBox
+     * Get the capture area.
+     */
+    getCaptureBox: function()
+    {
+        var geometry;
+        // The capture box is not enabled, so just use the current viewport as capture box
+        if (!this.enabled)
+        {
+            geometry = this.wMap.getCurrentExtents().toGeometry(); 
+        }
+        else
+        {
+            geometry = this.captureBox.geometry;
+        }
+        
+        var info     = "";
+        var vertices = geometry.getVertices();
+        var vertex   = null;
+        
+        for (var i = 0; i < vertices.length; ++i)
+        {
+            vertex = vertices[i];
+            info += vertex.x + "," + vertex.y + ",";
+        }
+        
+        // Remove the last ","
+        info = info.substr(0, info.length - 1);
+        
+        return {geometry:geometry, params:info};
+    },
+    
+    /**
+     * Method: getNormalizedCapture
+     * Get the normalized capture box
+     */
+    getNormalizedCapture: function()
+    {
+        var info   = "";
+        var geometry = null;
+        if (!this.enabled)
+        {
+            geometry = this.wMap.getCurrentExtents().toGeometry();
+            // Calculate the scale denominator
+            
+        }
+        else
+        {
+            geometry = this.captureBox.geometry.clone();
+            geometry.rotate(-this.rotation, geometry.getCentroid());
+        }
+        
+        var vertices = geometry.getVertices();
+        var vertex   = null;
+        
+        for (var i = 0; i < vertices.length; ++i)
+        {
+            vertex = vertices[i];
+            info += vertex.x + "," + vertex.y + ",";
+        }
+        
+        // Remove the last ","
+        info = info.substr(0, info.length - 1);
+        
+        return {geometry:geometry, params:info};
+    },
+    
+    /**
+     * Method: getCaptureRotation
+     * Get the capture rotation
+     */
+    getCaptureRotation: function()
+    {
+        if (this.enabled)
+        {
+            return this.rotation;
+        }
+        else
+        {
+            return 0.0;
+        }
+    },
+    
+    /**
+     * Method: enable
+     * Enable the capture box to display it on the map
+     */
+    enable: function()
+    {
+        // Reset everything first
+        this.disable();
+        this.enabled = true;
+    },
+    
+    /**
+     * Method: disable
+     * Disable the capture box. Then the capture box will not show up on the Map,
+     * 		and the current view port is treated as the capture area
+     */
+    disable: function()
+    {
+        this.enabled  = false;
+
+        this.wMap.message.hide();
+        this.clearFeatures();
+        this.rotation = 0;
+        
+        var features = this.layer.features;
+        for (var i = 0; i < features.length; ++i)
+        {
+            features[i].geometry = null;
+        }
+    },
+    
+    /**
+     * Property: CLASS_NAME. The class name
+     */
+    CLASS_NAME: "OpenLayers.Control.MapCapturer"
+});
+

Added: trunk/widgets/QuickPlot/PreviewDialog.js
===================================================================
--- trunk/widgets/QuickPlot/PreviewDialog.js	                        (rev 0)
+++ trunk/widgets/QuickPlot/PreviewDialog.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,368 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+var PreviewDialog = function(options)
+{
+    this.initialize(options);
+};
+
+PreviewDialog.prototype = 
+{
+    jxDialog : null,
+    previewFrame : null,
+    innerDoc : null,
+    indicator : null,
+    previewPicture : null,
+    printPicture : null,
+    topLeftXYLabel : null,
+    bottomRightXYLabel : null,
+    previewContainer : null,
+    pictureContainer : null,
+    printButton : null,
+    cancelButton : null,
+    loadingErrorMessage : null,
+    printStyle: null,
+    previewStyle: null,
+    // The offset from the border of the paper, in px 
+    csLabelOffset : 5,
+    // The print margin, in inches
+    printMargin: 0,
+    mapInfo : {sessionID: "", name: ""},
+    captureInfo : {topLeftCs : {x : 0, y : 0}, bottomRightCs : {x : 0, y : 0}, paperSize:{w : 0, h : 0}, scaleDenominator : 0, rotation : 0, params1 : "", params2 : ""},
+    params : null,
+    
+    // The callback will be called right after the JxDialog content has been loaded.
+    // The callback accepts 1 parameter: windowName (string)
+    // Here it is used to submit the quick plot form to the preview frame.
+    contentLoadedCallback : null,
+    
+    initialize : function(options)
+    {
+        this.mapInfo      = options.mapInfo;
+        this.captureInfo  = options.captureInfo;
+        this.params       = options.params;
+        
+        this.jxDialog = new Jx.Dialog(
+        {
+            modal: true,
+            width:400,
+            height: 400,
+            content: '<table border="0" cellspacing="0" cellpadding="0" id="PreviewContainer">' + 
+                     '	<tr>' + 
+                     '		<td>' + 
+                     '			<iframe id="PreviewFrame" scrolling="no" frameborder="0" style="border: 0px; width: 400px; height: 300px;" src="about:blank"></iframe>' +
+                     '		</td>' +
+                     '  </tr>' +
+                     '</table>'
+        });
+        
+        this.jxDialog.addEvent("open", this.jxDialogOpened.bind(this, true));
+        this.jxDialog.addEvent("contentLoaded", this.jxDialogContentLoaded.bind(this));
+        // Listen to the fade complete event to close the dialog
+        var o = this.jxDialog.domObj.get("tween").addEvent("complete", this.closeJxDialog.bind(this));
+    },
+    
+    open : function(contentLoadedCallback)
+    {
+        this.contentLoadedCallback = contentLoadedCallback;
+        this.jxDialog.loadContent(this.jxDialog.content);
+        this.jxDialog.open();
+    },
+    
+    print : function()
+    {
+        //
+        this.previewFrame.contentWindow.doPrint();
+    },
+    
+    cancel : function()
+    {
+        this.indicator.style.display     = "inline";
+        this.indicator.style.visibility  = "visible";
+        this.indicator.setOpacity(1);
+        
+        this.loadingErrorMessage.fade(0);
+        this.loadingErrorMessage.style.display = "none";
+        // Hide the picture but don't set the 'display' style property to avoid messing the print layout up
+        this.printPicture.style.height   = "0px";
+        
+        if (this.topLeftXYLabel && this.bottomRightXYLabel)
+        {
+            this.topLeftXYLabel.setOpacity(0);
+            this.bottomRightXYLabel.setOpacity(0);
+            this.printLabel.setOpacity(0);
+            // Remove the labels
+            this.topLeftXYLabel.parentNode.removeChild(this.topLeftXYLabel);
+            this.topLeftXYLabel     = null;
+            this.bottomRightXYLabel.parentNode.removeChild(this.bottomRightXYLabel);
+            this.bottomRightXYLabel = null;
+            this.printLabel.parentNode.removeChild(this.printLabel);
+            this.printLabel         = null;
+        }
+        
+        this.isClosing = true;
+        this.jxDialog.blanket.fade(0);
+        this.jxDialog.domObj.fade(0);
+    },
+    
+    jxDialogContentLoaded : function()
+    {
+        // Set the window name for the preview frame
+        this.previewFrame = $("PreviewFrame");
+        this.previewFrame.contentWindow.name = "QuickPlotPreviewFrame";
+        
+        // Inform the listener that the content is ready, then the Quick Plot panel can submit its data to the preview frame
+        if (this.contentLoadedCallback)
+        {
+            this.contentLoadedCallback(this.previewFrame.contentWindow.name);
+        }
+    },
+    
+    jxDialogOpened : function(setFrameUrl)
+    {
+        if (this.previewInnerIsLoaded)
+        {
+            // Resize the preview frame according to the monitor resolution
+            this.innerDoc         = this.previewFrame.contentWindow.document;
+            var box       = $(document.body).getDimensions();
+            // Width of preview dialog = screen width * factor
+            var factor    = 0.5;
+            this.previewContainer = $(this.innerDoc.getElementById("PreviewContainer"));
+            this.previewContainer.style.width = box.width * factor + "px";
+            this.pictureContainer = $(this.innerDoc.getElementById("PictureContainer"));
+            var pcBox = this.pictureContainer.getContentBoxSize();
+            
+            this.indicator        = $(this.innerDoc.getElementById("ProgressIndicator"));
+            
+            var paperSize  = this.captureInfo.paperSize;
+            this.paperSize = paperSize;
+            
+            var ratio = paperSize.w / paperSize.h;
+            
+            // Resize the indicator
+            this.indicator.style.width  = pcBox.width + "px";
+            this.indicator.style.height = pcBox.width / ratio + "px";
+            // Set a explicit size to the container
+            this.pictureContainer.style.width  = this.indicator.style.width;
+            this.pictureContainer.style.height = this.indicator.style.height;
+            // Get the styles for the print picture
+            var rules = this.innerDoc.styleSheets[1].cssRules || this.innerDoc.styleSheets[1].rules;
+            this.previewStyle = rules[0];
+            rules     = this.innerDoc.styleSheets[2].cssRules || this.innerDoc.styleSheets[2].rules;
+            this.printStyle   = rules[0];
+            
+            // Reset the background
+            this.indicator.style.background = "url(progress_indicator.gif) no-repeat cneter center";
+            
+            this.loadingErrorMessage = $(this.innerDoc.getElementById("PictureLoadingErrorMessage"));
+            this.loadingErrorMessage.setOpacity(0);
+            
+            // Set the picture url
+            var src = "GeneratePicture.php?session_id=" + this.mapInfo.sessionID +
+                  "&map_name=" + this.mapInfo.name + 
+                  "&print_dpi=" + this.params.printDpi + 
+                  "&paper_size=" + this.captureInfo.paperSize.w + "," + this.captureInfo.paperSize.h + 
+                  "&box=" + this.captureInfo.params1 +
+                  "&normalized_box=" + this.captureInfo.params2 + 
+                  "&scale_denominator=" + this.captureInfo.scaleDenominator + 
+                  "&rotation=" + this.captureInfo.rotation; 
+                
+            this.printPicture       = $(this.innerDoc.getElementById("PrintPicture"));
+            this.printPicture.src   = src;
+            
+            // Listen to print picture onload vent
+            this.printPicture.addEvent("load", this.printPictureLoaded.bind(this));
+            this.printPicture.addEvent("error", this.printPictureLoadError.bind(this));
+            
+            var innerBox  = this.previewContainer.getMarginBoxSize();
+            // Resize the frame according to the inner container's 
+            this.previewFrame.style.width  = innerBox.width + "px";
+            this.previewFrame.style.height = innerBox.height + "px";
+            
+            // Hide the title bar
+            this.jxDialog.title.style.display  = "none";
+            // Hide the chrome
+            this.jxDialog.chrome.style.display = "none";
+            
+            // Disable the print button until the image is ready
+            this.printButton           = this.innerDoc.getElementById("PrintButton");
+            this.cancelButton          = this.innerDoc.getElementById("CancelButton");
+            this.printButton.disabled  = true;
+            this.cancelButton.disabled = true;
+            
+            var delta     = {x: 22, y: 43};
+            var container = $("PreviewContainer");
+            var size      = container.getMarginBoxSize();
+            this.jxDialog.resize(size.width + delta.x, size.height + delta.y, true);
+            
+            this.jxDialog.blanket.fade(0.2);
+            this.jxDialog.domObj.fade(1);
+            this.resizeIsPending = false;
+            
+            this.previewInnerIsLoaded = false;
+        }
+        else
+        {
+            this.jxDialog.blanket.setOpacity(0);
+            this.jxDialog.domObj.setOpacity(0);
+            this.resizeIsPending = true;
+        }
+    },
+    
+    previewInnerLoaded: function()
+    {
+        this.previewInnerIsLoaded = true;
+        if (this.resizeIsPending)
+        {
+            this.jxDialogOpened(false);
+        }
+    },
+    
+    closeJxDialog : function()
+    {
+        if (this.isClosing)
+        {
+            this.jxDialog.close();
+            this.isClosing = false;
+        }
+    },
+    
+    printPictureLoaded : function()
+    {
+        var size = {width: parseInt(this.indicator.style.width), height: parseInt(this.indicator.style.height)};
+        
+        this.indicator.fade(0);
+        this.indicator.style.display = "none";
+        
+        // Set the preview size
+        this.printPicture.setOpacity(0);
+        // Clear the inline style
+        this.printPicture.style.width   = "";
+        this.previewStyle.style.width   = size.width + "px";
+        this.previewStyle.style.height  = size.height + "px";
+        this.printPicture.fade(1);
+        
+        // Set the print size
+        // NOTE: It works only with a 96 dpi device dpi
+        var deviceDpi  = 96;
+        var idealSize  = {width:(this.paperSize.w / 25.4 - 2 * this.printMargin) * deviceDpi, height:(this.paperSize.h / 25.4 - 2 * this.printMargin) * deviceDpi};
+        // Get the size of the print frame
+        var docSize    = $(this.innerDoc.body).getContentBoxSize();
+        var realHeight = idealSize.height - (docSize.height - size.height);
+        var realWidth  = realHeight * this.paperSize.w / this.paperSize.h;
+        if (realWidth > idealSize.width)
+        {
+            realWidth = idealSize.width;
+            realHeight = realWidth / (this.paperSize.w / this.paperSize.h);
+        }
+        
+        this.printStyle.style.width  = realWidth + "px";
+        this.printStyle.style.height = realHeight + "px";
+        
+        // Create the coordinates labels
+        if (!this.topLeftXYLabel)
+        {
+            this.topLeftXYLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.topLeftCs.x, this.captureInfo.topLeftCs.y, "TopLeftXYLabel");
+            this.topLeftXYLabel.setOpacity(0);
+        }
+        
+        if (!this.bottomRightXYLabel)
+        {
+            this.bottomRightXYLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.bottomRightCs.x, this.captureInfo.bottomRightCs.y, "BottomRightXYLabel");
+            this.bottomRightXYLabel.setOpacity(0);
+        }
+        
+        if (!this.printLabel)
+        {
+            this.printLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.bottomRightCs.x, this.captureInfo.bottomRightCs.y, "PrintLabel");
+        }
+        
+        // Set the correct positions for the labels
+        var pos    = this.getContentPosition(this.pictureContainer);
+        var picDim = this.pictureContainer.getContentBoxSize();
+        this.topLeftXYLabel.style.left     = pos.left + this.csLabelOffset + "px";
+        this.topLeftXYLabel.style.top      = pos.top + this.csLabelOffset + "px"; 
+        var labelDim = this.bottomRightXYLabel.getMarginBoxSize();
+        this.bottomRightXYLabel.className  = "ScreenOnly";
+        this.bottomRightXYLabel.style.left = pos.left + picDim.width - this.csLabelOffset - labelDim.width + "px";
+        this.bottomRightXYLabel.style.top  = pos.top + picDim.height - this.csLabelOffset - labelDim.height + "px";
+        labelDim = this.printLabel.getMarginBoxSize();
+        this.printLabel.className          = "PrintOnly";
+        this.printLabel.style.left         = pos.left + realWidth - this.csLabelOffset - labelDim.width + "px";
+        this.printLabel.style.top          = pos.top + realHeight - this.csLabelOffset - labelDim.height + "px";
+        
+        this.topLeftXYLabel.fade(1);
+        this.bottomRightXYLabel.fade(1);
+        // Enable the print button
+        this.printButton.disabled  = false;
+        this.cancelButton.disabled = false;
+    },
+    
+    printPictureLoadError : function()
+    {
+        this.indicator.fade(0);
+        this.indicator.style.display = "none";
+        this.loadingErrorMessage.style.display = "inline";
+        this.loadingErrorMessage.setOpacity(0);
+        this.loadingErrorMessage.fade(1);
+        this.cancelButton.disabled = false;
+    },
+    
+    createCoordinateLabel: function(container, cX, cY, id)
+    {
+        cX = cX + "";
+        cY = cY + "";
+        var digits = 6;
+        
+        var index = cX.indexOf(".");
+        if (index > -1)
+        {
+            cX = cX.substr(0, index + digits + 1);
+        }
+        
+        index = cY.indexOf(".");
+        if (index > -1)
+        {
+            cY = cY.substr(0, index + digits + 1);
+        }
+        
+        var label = this.innerDoc.createElement("div");
+        container.appendChild(label);
+        label.id  = id;
+        label.style.cssText = "border:solid 1px black; padding:1px; background:#F2F2F2; color:black; font-size:8pt; z-index:1000; " +
+                              "position:absolute; white-space:nowrap";
+        label.innerHTML     = "X: " + cX + " Y: " + cY;
+        
+        return $(label);
+    },
+    
+    getContentPosition: function(element)
+    {
+        var offsetLeft = 0;
+        var offsetTop  = 0;
+        var border     = 0;
+        
+        while (element && element.tagName.toLowerCase() != "body" && element.tagName.toLowerCase() != "html")
+        {
+            offsetLeft += element.offsetLeft;
+            offsetTop  += element.offsetTop;
+            
+            border      = parseInt(element.style.borderLeftWidth);
+            if (!isNaN(border))
+            {
+                offsetLeft += border;
+            }
+            
+            border      = parseInt(element.style.borderTopWidth);
+            if (!isNaN(border))
+            {
+                offsetTop += border;
+            }
+            
+            element     = element.offsetParent;
+        }
+        
+        return {left: offsetLeft, top: offsetTop};
+    }
+};
\ No newline at end of file

Added: trunk/widgets/QuickPlot/QuickPlotPanel.js
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPanel.js	                        (rev 0)
+++ trunk/widgets/QuickPlot/QuickPlotPanel.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,155 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+function restoreUI()
+{
+    setAdvancedOptionsUI(false);
+    
+    // Read the last used options
+    lastPaperSize = getParent().Cookie.read("QuickPlotLastUsedPaperSize");
+    lastScale     = getParent().Cookie.read("QuickPlotLastUsedScaling");
+    lastDPI       = getParent().Cookie.read("QuickPlotLastUsedDPI");
+    
+    if (lastPaperSize != null)
+    {
+        document.getElementById("PaperList").value   = lastPaperSize;
+    }
+    
+    if (lastScale != null)
+    {
+        document.getElementById("ScalingList").value = lastScale;
+    }
+    
+    if (lastDPI != null)
+    {
+        document.getElementById("DPIList").value     = lastDPI;
+    }
+}
+
+function setAdvancedOptionsUI(enabled)
+{
+    document.getElementById("PaperList").disabled   = !enabled;
+    document.getElementById("ScalingList").disabled = !enabled;
+    document.getElementById("DPIList").disabled     = !enabled;
+    
+    var mapCapturer = getParent().Fusion.getWidgetsByType("QuickPlot")[0].mapCapturer;
+    
+    if (enabled)
+    {
+        mapCapturer.enable();
+        drawCaptureBox();
+    }
+    else
+    {
+        mapCapturer.disable();
+    }
+}
+
+function generatePlot()
+{
+    var widget      = getParent().Fusion.getWidgetsByType("QuickPlot")[0];
+    var mapCapturer = widget.mapCapturer;
+
+    if (!advancedOptionsOn())
+    {
+        // Get paper size. Use the last used paper size by default
+        mapCapturer.setSize(getPaperSize(), getScale());
+        
+    }
+    
+    widget.preview(submitForm, getPrintDpi());
+}
+
+function submitForm(windowName)
+{
+    var form = document.getElementById("Form1");
+    form.target = windowName;
+    // Save the advanced options to a cookie
+    var cookieDuration = 365;
+    getParent().Cookie.write("QuickPlotLastUsedPaperSize", document.getElementById("PaperList").value, {duration:cookieDuration});
+    getParent().Cookie.write("QuickPlotLastUsedScaling", document.getElementById("ScalingList").value, {duration:cookieDuration});
+    getParent().Cookie.write("QuickPlotLastUsedDPI", document.getElementById("DPIList").value, {duration:cookieDuration});
+    form.submit();
+}
+
+
+function advancedOptionsOn()
+{
+    var o = document.getElementById("AdvancedOptionsCheckBox");
+    if (o && o.checked)
+    {
+        return true;
+    }
+    
+    return false;
+}
+
+function getPaperSize()
+{
+    var value = document.getElementById("PaperList").value.split(",");
+    var size = {w: parseFloat(value[0]), h: parseFloat(value[1])};
+
+    if (!advancedOptionsOn())
+    {
+        // Calculate the paper size to make sure it has a same ratio with the viweport
+        var map        = getParent().Fusion.getWidgetById("Map");
+        var paperRatio = size.w / size.h;
+        var viewSize   = map.getSize();
+        var viewRatio  = viewSize.w / viewSize.h;
+
+        if (paperRatio > viewRatio)
+        {
+            size.w     = size.h * viewRatio;
+        }
+        else
+        {
+            size.h     = size.w / viewRatio;
+        }
+    }
+
+    return size;
+}
+
+function getScale()
+{
+    var scale = 0;
+    if (advancedOptionsOn())
+    {
+        scale = document.getElementById("ScalingList").value;
+    }
+    else
+    {
+        var map        = getParent().Fusion.getWidgetById("Map");
+        var paperSize  = getPaperSize();
+        var viewerSize = map.getCurrentExtents().getSize();
+        var factor     = map.getMetersPerUnit();
+        
+        if (paperSize.w / paperSize.h > viewerSize.w / viewerSize.h)
+        {
+            scale = viewerSize.h * factor * 1000 / paperSize.h;
+        } 
+        else
+        {
+            scale = viewerSize.w * factor * 1000 / paperSize.w;
+        }
+    }
+
+    scale = parseInt(scale);
+    // Set the value to a hidden field so that it could be sent by POST method
+    // We cannot rely on the ScalingList.value because we have to handle also the viewport print 
+    document.getElementById("ScaleDenominator").value = scale;
+    
+    return scale;
+}
+
+function getPrintDpi()
+{
+    return document.getElementById("DPIList").value;
+}
+
+function drawCaptureBox()
+{
+    var mapCapturer = getParent().Fusion.getWidgetsByType("QuickPlot")[0].mapCapturer;
+    mapCapturer.setSize(getPaperSize(), getScale());
+}

Added: trunk/widgets/QuickPlot/QuickPlotPanel.php
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPanel.php	                        (rev 0)
+++ trunk/widgets/QuickPlot/QuickPlotPanel.php	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,43 @@
+<?php
+
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Common.php';
+
+    $locale = GetDefaultLocale();
+    $popup = 0;
+    $mapName = "";
+    $sessionId = "";
+    $us = "";
+    $popup = "false";
+
+    GetRequestParameters();
+
+    $templ = file_get_contents("QuickPlotPanel.templ");
+    SetLocalizedFilesPath(GetLocalizationPath());
+    $templ = Localize($templ, $locale, GetClientOS());
+
+    $vpath = GetSurroundVirtualPath();
+    $jsPath = "";
+    print sprintf($templ, $popup, $jsPath);
+
+function GetParameters($params)
+{
+    global $target, $cmdIndex, $clientWidth, $mapName, $sessionId, $popup, $us, $locale, $popup;
+
+    $locale    = $params['locale'];
+    $mapName   = $params['mapname'];
+    $sessionId = $params['session'];
+    $popup     = $params['popup'];
+    $us        = $params['us'];
+    $popup     = $params['popup'];
+}
+
+function GetRequestParameters()
+{
+    if($_SERVER['REQUEST_METHOD'] == "POST")
+        GetParameters($_POST);
+    else
+        GetParameters($_GET);
+}
+
+?>

Added: trunk/widgets/QuickPlot/QuickPlotPanel.templ
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPanel.templ	                        (rev 0)
+++ trunk/widgets/QuickPlot/QuickPlotPanel.templ	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,150 @@
+<html>
+<head>
+<title>__#QUICKPLOT_HEADER#__</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style type="text/css">
+body, table, td, div, select, input 
+{
+    font: 8pt/1em __#@font#__;
+}
+
+div.Label
+{
+    padding:5px 0px;
+}
+
+div.Ctrl
+{
+    padding:5px 0px;
+}
+
+div.Title
+{
+    font-size: 14px;
+    font-weight: bold;
+    padding: 10px 0px;
+}
+
+div.HPlaceholder5px
+{
+    font-size:0px;
+    height:5px;
+}
+
+div.ButtonContainer
+{
+    padding: 5px 0px;
+    text-align: right;
+}
+
+.FixWidth
+{
+    width: 100%%;
+}
+
+input.Button
+{
+    width:75px;
+    height:23px;
+    margin-left:7px;
+}
+</style>
+<script language="javascript" type="text/javascript">
+var popup = %s;
+
+// Get window where the Fusion object is available
+function getParent()
+{
+    if (popup) 
+    {
+        return opener;
+    } 
+    else if (parent.Fusion)
+    {
+        return parent;
+    } 
+    else if (parent.parent.Fusion) 
+    {
+        return parent.parent;
+    }
+    
+    return null;
+}
+
+</script>
+<script language="javascript" type="text/javascript" src="%sQuickPlotPanel.js"></script>
+
+</head>
+<body onload="restoreUI()">
+    <form id="Form1" name="Form1" method="post" action="QuickPlotPreviewInner.php">
+        <div class="Title FixWidth">__#QUICKPLOT_HEADER#__</div>
+        <div class="Label ">__#QUICKPLOT_TITLE#__</div>
+        <div class="Ctrl">
+            <input type="text" class="FixWidth" name="{field:title}" maxLength=100"/>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">__#QUICKPLOT_SUBTITLE#__</div>
+        <div class="Ctrl">
+            <input type="text" class="FixWidth" name="{field:sub_title}" maxLength=100"/>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">
+            <table cellspacing="0" cellpadding="0">
+                <tr>
+                    <td><input type="checkbox" id="AdvancedOptionsCheckBox" onclick="setAdvancedOptionsUI(this.checked)" /></td>
+                    <td><label for="AdvancedOptionsCheckBox">__#QUICKPLOT_ADVANCED_OPTIONS#__</label></td>
+                </tr>
+            </table>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">__#QUICKPLOT_PAPER_SIZE#__</div>
+        <div class="Ctrl">
+            <!--
+                The pre-defined paper size list. The value for each "option" item is in this format: [width,height]. The unit is in millimeter.
+                We can change the html code to add more paper size or remove some ones.
+            -->
+            <select class="FixWidth" id="PaperList" onchange="drawCaptureBox(this)">
+                <option value="297.0,210.0">A4 (210 MM x 297 MM)</option>
+                <option value="420.0,297.0">A3 (297 MM) x 420 MM</option>
+                <option value="279.4,215.9">Letter (8.50 x 11.00 Inches)</option>
+                <option value="355.6,215.9">Legal (8.50 x 14.00 Inches)</option>
+            </select>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">__#QUICKPLOT_SCALING#__</div>
+        <div class="Ctrl">
+            <!--
+                The pre-defined scales. The value for each "option" item is the scale denominator.
+                We can change the html code to extend the pre-defined scales
+            -->
+            <select class="FixWidth" id="ScalingList" onchange="drawCaptureBox(this)">
+                <option value="500">1 : 500</option>
+                <option value="1000">1 : 1000</option>
+                <option value="2500">1 : 2500</option>
+                <option value="5000">1 : 5000</option>
+            </select>
+        </div>
+        <div class="Label">__#QUICKPLOT_DPI#__</div>
+        <div class="Ctrl">
+            <!--
+                The pre-defined print DPI. 
+                We can change the html code to extend the pre-defined values
+            -->
+            <select class="FixWidth" id="DPIList">
+                <option value="96">96</option>
+                <option value="150" selected>150</option>
+                <option value="300">300</option>
+                <option value="600">600</option>
+            </select>
+        </div>
+        <input type="hidden" id="ScaleDenominator" name="scale_denominator" />
+        <div class="ButtonContainer FixWidth">
+            <input type="button" class="Button" value="__#QUICKPLOT_GENERATE#__" onclick="generatePlot()" />
+        </div>
+    </form>
+</body>
+</html>

Added: trunk/widgets/QuickPlot/QuickPlotPreview.js
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPreview.js	                        (rev 0)
+++ trunk/widgets/QuickPlot/QuickPlotPreview.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+function innerLoaded()
+{
+    if (parent.Fusion)
+    {
+        parent.Fusion.getWidgetsByType("QuickPlot")[0].previewInnerLoaded();
+    }
+}
+
+function printIt()
+{
+    parent.Fusion.getWidgetsByType("QuickPlot")[0].printPreview();
+}
+
+function cancelPreview()
+{
+    parent.Fusion.getWidgetsByType("QuickPlot")[0].cancelPreview();
+}
+
+function doPrint()
+{
+    window.focus();
+    window.print();
+}

Added: trunk/widgets/QuickPlot/QuickPlotPreviewInner.php
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPreviewInner.php	                        (rev 0)
+++ trunk/widgets/QuickPlot/QuickPlotPreviewInner.php	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,69 @@
+<?php
+
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Common.php';
+
+    $locale = GetDefaultLocale();
+    $scaleDenominator;
+    $annotations;
+    
+    $args = GetRequestMethod();
+    GetParameters($args);
+
+    $templ = file_get_contents("QuickPlotPreviewInner.templ");
+    SetLocalizedFilesPath(GetLocalizationPath());
+    
+    // Localize the page
+    $templ = Localize($templ, $locale, GetClientOS());
+    
+    // Set some annotation labels in the page by replacing the placeholders in the html code
+    $templ = str_replace(array_keys($annotations), array_values($annotations), $templ);
+    // Set the date annotation according to its format mask
+    $pattern = "/\{date:(.+?)\}/";
+    $matches = array();
+    if (preg_match($pattern, $templ, $matches))
+    {
+        $mask  = $matches[1];
+        $date  = date($mask);
+        $templ = preg_replace($pattern, $date, $templ);
+    }
+    
+    $jsPath    = "";
+    print sprintf($templ, $jsPath);
+?>
+
+<?php
+function GetParameters($params)
+{
+    global $scaleDenominator, $annotations;
+    
+    $scaleDenominator = intval($params["scale_denominator"]);
+    $annotations = array();
+    
+    // The parameters whose name matches this pattern will be treated as annotation
+    $pattern = "/^\{field:.+\}$/i";
+    foreach ($params as $key => $value)
+    {
+        if (preg_match($pattern, $key) == 1)
+        {
+            $annotations[$key] = htmlspecialchars(urlDecode($value), ENT_QUOTES);
+        }
+    }
+    
+    // The scale annotation
+    $annotations["{scale}"] = "1 : " . $scaleDenominator;
+}
+
+function GetRequestMethod()
+{
+    if($_SERVER['REQUEST_METHOD'] == "POST")
+    {
+        return $_POST;
+    }
+    else
+    {
+        return $_GET;
+    }
+}
+
+?>

Added: trunk/widgets/QuickPlot/QuickPlotPreviewInner.templ
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPreviewInner.templ	                        (rev 0)
+++ trunk/widgets/QuickPlot/QuickPlotPreviewInner.templ	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,85 @@
+<html>
+<head>
+<title>__#QUICKPLOT_HEADER#__</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style type="text/css">
+body, table, td, div, input
+{
+    font: 9pt/1.5em __#@font#__;
+}
+
+td.LegalNotice
+{
+    font-size: 8pt;
+}
+
+input.Button
+{
+    width:75px;
+    height:23px;
+    margin-left:7px;
+}
+</style>
+
+<style type="text/css" media="screen">
+#PrintPicture { }
+
+.PrintOnly
+{
+    display:none;
+}
+</style>
+
+<style type="text/css" media="print">
+#PrintPicture { }
+input.Button
+{
+    visibility:hidden;
+}
+
+.ScreenOnly
+{
+    display: none;
+}
+</style>
+
+<script language="javascript" type="text/javascript" src="%sQuickPlotPreview.js"></script>
+</head>
+<body style="margin:0px" onLoad="innerLoaded()">
+<table cellspacing="10" cellpadding="0" style="width:100%%; border-width:0px" id="PreviewContainer">
+  <tr>
+    <td><table style="width:100%%" border="0" cellspacing="0" cellpadding="0" id="AnnotationContainer">
+        <tr>
+          <td style="width:100%%">{field:title}</td>
+          <!-- 
+            The date format mask follows the php date() function's instruction
+            see also here for more reference: http://cn.php.net/manual/en/function.date.php
+           -->
+          <td style="white-space:nowrap">{date:m/d/Y}</td>
+        </tr>
+        <tr>
+          <td>{field:sub_title}</td>
+          <td style="white-space:nowrap">__#QUICKPLOT_SCALE_LABEL#__: {scale}</td>
+        </tr>
+      </table></td>
+  </tr>
+  <tr>
+    <td id="PictureContainer" style="border: solid 1px black; text-align:center; vertical-align:center;">
+        <img style="width:1px; background:url(progress_indicator.gif) no-repeat center center" id="ProgressIndicator" src="pixel.gif" />
+        <img style="width:1px" id="PrintPicture" src="pixel.gif" />
+        <span id="PictureLoadingErrorMessage" style="display:none; text-align:center">__#QUICKPLOT_PREVIEW_ERROR#__</span>
+    </td>
+  </tr>
+  <tr>
+    <td><table width="100%%" border="0" cellspacing="0" cellpadding="0">
+        <tr>
+          <!-- Legal notice. Just replace it with the necessary statement -->
+          <td style="width:100%%" class="LegalNotice">The materials available at this web site are for informational purposes only and do not constitute a legal document.</td>
+          <td style="white-space:nowrap"><input type="button" id="PrintButton" class="Button" onClick="printIt()" value="__#QUICKPLOT_PRINT#__" /><input type="button" id="CancelButton" class="Button" onClick="cancelPreview()" value="__#QUICKPLOT_CANCEL#__" />
+          </td>
+        </tr>
+      </table></td>
+  </tr>
+</table>
+</body>
+</html>

Added: trunk/widgets/QuickPlot/north_arrow.png
===================================================================
(Binary files differ)


Property changes on: trunk/widgets/QuickPlot/north_arrow.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/widgets/QuickPlot/pixel.gif
===================================================================
(Binary files differ)


Property changes on: trunk/widgets/QuickPlot/pixel.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/widgets/QuickPlot/progress_indicator.gif
===================================================================
(Binary files differ)


Property changes on: trunk/widgets/QuickPlot/progress_indicator.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/widgets/QuickPlot/rotate.cur
===================================================================
(Binary files differ)


Property changes on: trunk/widgets/QuickPlot/rotate.cur
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/widgets/QuickPlot.js
===================================================================
--- trunk/widgets/QuickPlot.js	                        (rev 0)
+++ trunk/widgets/QuickPlot.js	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,159 @@
+/**
+ * Fusion.Widget.QuickPlot
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+ /*****************************************************************************
+ * Class: Fusion.Widget.QuickPlot
+ * This widget provides a quick way to print a certain region of map in a good quality
+ * **********************************************************************/
+
+Fusion.require("widgets/QuickPlot/MapCapturer.js");
+Fusion.require("widgets/QuickPlot/PreviewDialog.js");
+
+Fusion.Widget.QuickPlot = OpenLayers.Class(Fusion.Widget, 
+{
+    uiClass: Jx.Button,
+    sFeatures : 'menubar=no,location=no,resizable=no,status=no',
+    options : {},
+    
+    initializeWidget: function(widgetTag) 
+    {
+        this.mapCapturer = new OpenLayers.Control.MapCapturer(this.getMap());
+        this.getMap().oMapOL.addControl(this.mapCapturer);
+        
+        var json                     = widgetTag.extension;
+        
+        this.sTarget  = json.Target ? json.Target[0] : "PrintPanelWindow";
+        this.sBaseUrl = Fusion.getFusionURL() + 'widgets/QuickPlot/QuickPlotPanel.php';
+        
+        this.additionalParameters = [];
+        if (json.AdditionalParameter) 
+        {
+            for (var i=0; i<json.AdditionalParameter.length; i++) 
+            {
+                var p = json.AdditionalParameter[i];
+                var k = p.Key[0];
+                var v = p.Value[0];
+                this.additionalParameters.push(k+'='+encodeURIComponent(v));
+            }
+        }
+    },
+
+    activate: function() 
+    {
+        var url = this.sBaseUrl;
+        var map = this.getMap();
+        var mapLayers      = map.getAllMaps();
+        var taskPaneTarget = Fusion.getWidgetById(this.sTarget);
+        var pageElement    = $(this.sTarget);
+
+        var params = [];
+        params.push('locale='+Fusion.locale);
+        params.push('session='+mapLayers[0].getSessionID());
+        params.push('mapname='+mapLayers[0].getMapName());
+        
+        if (taskPaneTarget || pageElement) 
+        {
+          params.push('popup=false');
+        } 
+        else 
+        {
+          params.push('popup=true');
+        }
+
+        params = params.concat(this.additionalParameters);
+
+        if (url.indexOf('?') < 0) 
+        {
+            url += '?';
+        } 
+        else if (url.slice(-1) != '&') 
+        {
+            url += '&';
+        }
+        
+        url += params.join('&');
+        
+        if (taskPaneTarget) 
+        {
+            taskPaneTarget.setContent(url);
+        } 
+        else 
+        {
+            if (pageElement) 
+            {
+                pageElement.src = url;
+            } 
+            else 
+            {
+                window.open(url, this.sTarget, this.sWinFeatures);
+            }
+        }
+        
+        // Expand taskpane automatically if it is the target window
+        if (panelman)
+        {
+            var panel = null;
+            for (var i = 0; i < panelman.panels.length; ++i)
+            {
+                panel = panelman.panels[i];
+                if (panel.options.contentId == this.sTarget)
+                {
+                    panelman.maximizePanel(panel);
+                    return;
+                }
+            }
+        }
+    },
+    
+    /***************************************************************************************
+     * The dialogContentLoadedCallback is used to submit the Quick Plot panel's parameters to the preview iframe
+     ***************************************************************************************/
+    preview: function(dialogConentLoadedCallback, printDpi)
+    {
+        var map = this.getMap();
+        var capture  = this.mapCapturer.getCaptureBox();
+        var normalizedCapture = this.mapCapturer.getNormalizedCapture();
+        var vertices = capture.geometry.getVertices();
+        this.options.printDpi = printDpi;
+        var options = {mapInfo : {sessionID : map.getSessionID(), name : map.getMapName()}, 
+                       captureInfo : {topLeftCs : {x : vertices[3].x, y : vertices[3].y},
+                                     bottomRightCs : {x : vertices[1].x, y : vertices[1].y}, 
+                                     paperSize : {w : this.mapCapturer.paperSize.w, h : this.mapCapturer.paperSize.h},
+                                     scaleDenominator : this.mapCapturer.scaleDenominator,
+                                     rotation : this.mapCapturer.rotation,
+                                     center : capture.geometry.getCentroid(),
+                                     params1 : capture.params,
+                                     params2 : normalizedCapture.params},
+                       params : this.options};
+        
+        if (!this.previewDialog)
+        {
+            this.previewDialog = new PreviewDialog(options);
+        }
+        else
+        {
+            this.previewDialog.mapInfo     = options.mapInfo;
+            this.previewDialog.captureInfo = options.captureInfo;
+            this.previewDialog.params      = options.params;
+        }
+        
+        this.previewDialog.open(dialogConentLoadedCallback);
+    },
+    
+    cancelPreview: function()
+    {
+        this.previewDialog.cancel();
+    },
+    
+    printPreview: function()
+    {
+        this.previewDialog.print();
+    },
+    
+    previewInnerLoaded: function()
+    {
+        this.previewDialog.previewInnerLoaded();
+    }
+});
\ No newline at end of file

Added: trunk/widgets/widgetinfo/quickplot.xml
===================================================================
--- trunk/widgets/widgetinfo/quickplot.xml	                        (rev 0)
+++ trunk/widgets/widgetinfo/quickplot.xml	2010-08-30 01:09:37 UTC (rev 2209)
@@ -0,0 +1,19 @@
+<WidgetInfo>
+    <Type>QuickPlot</Type>
+    <LocalizedType>QuickPlot</LocalizedType>
+    <Description>This widget offers a quick way to print map</Description>
+    <Label>Quick Plot</Label>
+    <Tooltip>Click to create a plot quickly</Tooltip>
+    <ImageUrl>images/icons/print.png</ImageUrl>
+    <ImageClass></ImageClass>
+    <StandardUi>true</StandardUi>
+    <ContainableBy>Any</ContainableBy>
+    <Parameter>
+        <Name>Target</Name>
+        <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
+        <Type>target</Type>
+        <Label>Target</Label>
+        <DefaultValue>TaskPane</DefaultValue>
+        <IsMandatory>true</IsMandatory>
+    </Parameter>
+</WidgetInfo>



More information about the fusion-commits mailing list