NEW - bug 245232: [Article] BIRT Extension Mechanism : Part 1
https://bugs.eclipse.org/bugs/show_bug.cgi?id=245232
diff --git a/Article-BIRT-ExtensionTutorial1/index.html b/Article-BIRT-ExtensionTutorial1/index.html
index 8bc267a..0e7e845 100644
--- a/Article-BIRT-ExtensionTutorial1/index.html
+++ b/Article-BIRT-ExtensionTutorial1/index.html
@@ -1,836 +1,593 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

 <html>

 <head>

-

-

-  

-

-

-  

-  

-  

-  <title>*DRAFT* BIRT Extension Mechanism : Part 1</title>

+  <title>BIRT Extension Mechanism : Part 1</title>

   <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">

-

-

-

-  

-  

   <link href="../article.css" type="text/css" rel="stylesheet">

 </head>

 

-

 <body>

 

-

-

-<h1>*DRAFT* BIRT Extension Mechanism : Part 1</h1>

-

-

+<h1>BIRT Extension Mechanism : Part 1</h1>

 

 <div class="summary">

 <h2>Abstract</h2>

 

-

-

 <p>This article introduces the extension mechanism of BIRT report

 model, engine and designer, shows how to create custom extended report items

 step by

 step.</p>

 

-

-

 <div class="author">By&nbsp;Zhiqiang

 Qian,&nbsp;Actuate Corporation</div>

 

-

-

 <div class="copyright">Copyright &copy; 2008 Actuate Corporation.</div>

 

-

-

 <div class="date">August 7, 2008</div>

 

-

-

 </div>

 

-

-

 <div class="content">

 <h2>Introduction</h2>

 

-

-

-<p>For many people,&nbsp;<a href="http://eclipse.org/birt">BIRT(Business

-Intelligence and Reporting Tools)</a> may

-only mean a regular reporting tool. But in fact, the real strength of

-BIRT is not only&nbsp;its built-in reporting functionality, but also

+<p>For many people, <a href="http://eclipse.org/birt">BIRT (Business

+Intelligence and Reporting Tools)</a> may be

+only a reporting tool. But in fact, the real strength of

+BIRT is not only its built-in reporting functionality, but also

 its

-extension capabilities. By&nbsp;extensions, user can easily extend the

+extension capabilities. Using extensions, a user can easily extend the

 functionality of BIRT, creating custom extended report items, adding custom

-emitters, and even having custom editor pages. The powerfulness of extensions

-enables user to create

+emitters, and even having custom editor pages. The power of extensions

+enables the user to create

 custom reporting features that can meet very specific requirements. In

 this

-article, we will explorer how to leverage the BIRT extension mechanism to

-extend the BIRT&nbsp;capabilities. The given samples will

-cover&nbsp;most of the essential extension points that provided by BIRT report

+article, we explore how to leverage the BIRT extension mechanism to

+extend the BIRT capabilities. The provided samples 

+cover most of the essential extension points that provided by BIRT report

 model, engine and designer.<br>

 

-

-

 </p>

 

-

-

 <h2>The Basics</h2>

 

-

-

 <p>BIRT already contains the basic Label and Text report items,

-but&nbsp;these items can only show horizontal text. Sometimes, user

+but these items can only show horizontal text. Sometimes, user

 would

-like to show angled text, in this case, alternative solution is needed.

-In following sections, we are introducing how to implement a

+like to show angled text; in this case, alternative solution is needed.

+In following sections, we introduce how to implement a

 RotatedText

-extended report&nbsp;item through BIRT extensions, and how to enhance

+extended report item through BIRT extensions, and how to enhance

 the functionality step by step by implementing more extension points.</p>

 

-

-

 <p>Note: This example is a modified version based

-on&nbsp;RotatedText&nbsp;sample on BIRT CVS, the original code

-can&nbsp;be retrieved <a href="http://dev.eclipse.org/viewcvs/index.cgi/?root=BIRT_Project">here.</a></p>

+on the <code>RotatedText</code> sample on BIRT CVS, the original code

+can be retrieved <a href="http://dev.eclipse.org/viewcvs/index.cgi/?root=BIRT_Project">in Eclipse CVS.</a></p>

 

-

-

-<p>To implement an extended report item, basically we need look at&nbsp;following extension points:</p>

-

-

+<p>To implement an extended report item, we need look at the following extension points:</p>

 

 <ul>

-

-

-

   <li>org.eclipse.birt.report.model.reportItemModel</li>

-

-

-

   <li>org.eclipse.birt.report.designer.ui.reportitemUI</li>

-

-

-

   <li>org.eclipse.birt.report.engine.reportitemPresentation</li>

-

-

-

 </ul>

 

-

-

 <br>

 

-

-

 <img style="width: 514px; height: 156px;" alt="" src="images/extensions.png"><br>

 

+<p>These three extensions provide the basics to implement an extended

+report item. In brief,

+<code>org.eclipse.birt.report.model.reportItemModel</code> provides the report

+model extensibility, <code>org.eclipse.birt.report.designer.ui.reportitemUI</code>

 

+provides the report designer extensibility, and

+<code>org.eclipse.birt.report.engine.reportitemPresentation</code> provides the

+report engine extensibility.</p>

 

-<p>These three extensions are the basics to implement an extended

-report item. In brief,&nbsp;

-"org.eclipse.birt.report.model.reportItemModel" provides the report

-model extensibility, "org.eclipse.birt.report.designer.ui.reportitemUI"

-provides the report designer extensibility and

-"org.eclipse.birt.report.engine.reportitemPresentation" provides the

-report engine extensibility. Now we will introduce them one by one.</p>

+<h3>org.eclipse.birt.report.model.reportItemModel</h3>

 

-

-

-<h3>1) org.eclipse.birt.report.model.reportItemModel</h3>

-

-

-

-<p>This extension point is provided by BIRT Report Model, normally user

+<p>This extension point is provided by the BIRT Report Model. Normally the user

 uses this extension point to define the extended report item model.</p>

 

-

-

 <img style="width: 1036px; height: 224px;" alt="" src="images/model-extension.png">

-<p>First we need define a new extended report item model

-extension&nbsp;as&nbsp;"RotatedText", this name is the&nbsp;identifier

+<p>First we need define a new report item model

+extension. To achieve this, we create a &quot;reportItem&quot; element under the extension and specify the <code>extensionName</code> property as &quot;RotatedText&quot;. 

+The extension name is the identifier

 for the extended item, it's also the only symbol that connects between the report model

-and designer extensions.</p>

+and engine/designer extensions.</p>

 

 

 <p>Then we define the model factory class as

-"org.eclipse.birt.sample.reportitem.rotatedtext.RotatedTextItemFactory".

+<code>org.eclipse.birt.sample.reportitem.rotatedtext.RotatedTextItemFactory</code>.

 This factory class will be used to create and initialize the

-IReportItem instance,&nbsp;usually this class can also implement an

-additional&nbsp;IMessages interface to provide localization support:</p>

+<code>IReportItem</code> instance, as well as providing optional localization support:</p>

 

+<pre>public class RotatedTextItemFactory extends ReportItemFactory

+{

+	public IReportItem newReportItem( DesignElementHandle modelHandle )

+	{

+		if ( modelHandle instanceof ExtendedItemHandle &amp;&amp; RotatedTextItem.EXTENSION_NAME.equals( ( (ExtendedItemHandle) modelHandle ).getExtensionName( ) ) )

+		{

+			return new RotatedTextItem( (ExtendedItemHandle) modelHandle );

+		}

+		return null;

+	}

 

+	public IMessages getMessages( )

+	{

+		// TODO implement this to support localization

+		return null;

+	}

+}</pre>

 

-<pre style="font-family: monospace;">public class RotatedTextItemFactory extends ReportItemFactory<br>{<br>	public IReportItem newReportItem( DesignElementHandle modelHanlde )<br>	{<br>		if ( modelHanlde instanceof ExtendedItemHandle &amp;&amp; RotatedTextItem.EXTENSION_NAME.equals( ( (ExtendedItemHandle) modelHanlde ).getExtensionName( ) ) )<br>		{<br>			return new RotatedTextItem( (ExtendedItemHandle) modelHanlde );<br>		}<br>	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return null;<br>	}<br><br>	public IMessages getMessages( )<br>	{<br>		// TODO implement this to support localization<br>		return null;<br>	}<br>}<br></pre>

+<p>From the &quot;reportItem&quot; properties page, we can see some other settings like &quot;defaultStyle&quot;, &quot;extendsFrom&quot;, etc. 

+They can be used to control more capabilities of the extended item. As we are not using them in this example,

+we just omit them here.</p>

 

-

-

-<p>There are some extra properties here that are not used by this example, we just introduce them briefly:</p>

-

-

+<p>Here we define two new properties for the <code>RotatedText</code> extended report item:</p>

 

 <ul>

 

+  <li><em>rotationAngle</em>, the rotation angle, integer type, default as 0.</li>

 

+<br><img style="width: 1001px; height: 279px;" alt="" src="images/rotationangle-property.png">

 

-  <li>defaultStyle</li>

+  <li><em>text</em>, the text content, string type, default as "Rotated Text".</li>

 

-

-

-  

-  

-  <ul>

-

-

-

-    <li>specify the default style name, this will be used by BIRT

-to find and match the default style for this extended report item

-automatically.</li>

-

-

-

-  

-  

-  </ul>

-

-

-

-  <li>isNameRequired</li>

-

-

-

-  

-  

-  <ul>

-

-

-

-    <li>specify if the&nbsp;name is required for this extended report item.</li>

-

-

-

-  

-  

-  </ul>

-

-

-

-  <li>displayNameID</li>

-

-

-

-  

-  

-  <ul>

-

-

-

-    <li>specify the display name ID for this extended report item, the

-ID will be passed to&nbsp;IMessags interface to get the localized

-extended report item name.</li>

-

-

-

-  

-  

-  </ul>

-

-

-

-  <li>extendsFrom</li>

-

-

-

-  

-  

-  <ul>

-

-

-

-    <li>specify the name of the report item that this extended report

-item extends from, if this is not specified, the item will by default extend from

-"ExtendedItem".</li>

-

-

-

-  

-  

-  </ul>

-

-

-

-  <li>hasStyle</li>

-

-

-

-  

-  

-  <ul>

-

-

-

-    <li>specify if this extended report item supports styled properties, for some non-UI report items, it can be set to "false".</li>

-

-

-

-  

-  

-  </ul>

-

-

+<br><img style="width: 1000px; height: 274px;" alt="" src="images/text-property.png">

 

 </ul>

 

 

+<p>We can see in the properties page there are also some settings that we didn't touch. Normally they are for more complex property types and

+are out of the scope of this article, so we just omit them here.</p>

 

-<p>Now we need define two new properties for the RotatedText extended report item:</p>

-

-

-

-<ul>

-

-

-

-  <li>rotationAngle &nbsp; &nbsp;</li>

-

-

-

-</ul>

-

-

-

-&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;

-&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;

-the rotation angle, integer type, default&nbsp;as 0.<br>

-

-

-

-<img style="width: 1001px; height: 279px;" alt="" src="images/rotationangle-property.png">

-<ul>

-

-

-

-  <li>text</li>

-

-

-

-</ul>

-

-

-

-&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;

-&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;

-the text content, string type, default as "Rotated Text".<br>

-

-

-

-<img style="width: 1000px; height: 274px;" alt="" src="images/text-property.png"><br>

-

-

-

-<br>

-

-

-

-<p>We can see a lot of things in the

-property setting page that we haven't used yet, normally they are for more complex property types, we

-just skip them here.<br>

-

-

-

-<br>

-Once we completed the model definition, we need give a basic IReportItem

+<p>

+Once we completed the model definition, we need give a <code>IReportItem</code>

 implementation. This class is used to encapsulate the extended report

-item model, providing some convenient property accessing APIs:</p>

+item model, and providing some convenient property accessing APIs:</p>

+

+<pre>public class RotatedTextItem extends ReportItem

+{

+	public static final String EXTENSION_NAME = "RotatedText"; //$NON-NLS-1$

+	public static final String TEXT_PROP = "text"; //$NON-NLS-1$

+	public static final String ROTATION_ANGLE_PROP = "rotationAngle"; //$NON-NLS-1$

+

+	private ExtendedItemHandle modelHandle;

+

+	RotatedTextItem( ExtendedItemHandle modelHandle )

+	{

+		this.modelHandle = modelHandle;

+	}

+

+	public String getText( )

+	{

+		return modelHandle.getStringProperty( TEXT_PROP );

+	}

+

+	public int getRotationAngle( )

+	{

+		return modelHandle.getIntProperty( ROTATION_ANGLE_PROP );

+	}

+

+	public void setText( String value ) throws SemanticException

+	{

+		modelHandle.setProperty( TEXT_PROP, value );

+	}

+

+	public void setRotationAngle( int value ) throws SemanticException

+	{

+		modelHandle.setProperty( ROTATION_ANGLE_PROP, value );

+	}

+}</pre>

+

+<p>We can see most of the methods here are just getter/setters. For

+a simple extended report item, this is normally enough.</p>

+

+<h3>org.eclipse.birt.report.designer.ui.reportitemUI</h3>

+

+<p>This extension point is provided by BIRT Designer, the user uses this

+extension point to define the UI behavior for extended report

+items.</p>

+

+<img style="width: 1001px; height: 233px;" alt="" src="images/ui-extension.png">

 

 

+<!--  WTB I realize that the image above provides context for the comment below, but 

+I think that I'd like to see some more descriptive text  around this step. -->

 

-<pre>public class RotatedTextItem extends ReportItem<br>{<br>	public static final String EXTENSION_NAME = "RotatedText"; //$NON-NLS-1$<br>	public static final String TEXT_PROP = "text"; //$NON-NLS-1$<br>	public static final String ROTATION_ANGLE_PROP = "rotationAngle"; //$NON-NLS-1$<br><br>	private ExtendedItemHandle modelHandle;<br><br>	RotatedTextItem( ExtendedItemHandle modelHandle )<br>	{<br>		this.modelHandle = modelHandle;<br>	}<br><br>	public String getText( )<br>	{<br>		return modelHandle.getStringProperty( TEXT_PROP );<br>	}<br><br>	public int getRotationAngle( )<br>	{<br>		return modelHandle.getIntProperty( ROTATION_ANGLE_PROP );<br>	}<br><br>	public void setText( String value ) throws SemanticException<br>	{<br>		modelHandle.setProperty( TEXT_PROP, value );<br>	}<br><br>	public void setRotationAngle( int value ) throws SemanticException<br>	{<br>		modelHandle.setProperty( ROTATION_ANGLE_PROP, value );<br>	}<br>}<br></pre>

+<p>

+First we need create a &quot;model&quot; element under the extension. This is to bind the Designer extension with the Model extension. To do

+this, we specify the <code>extensionName</code> property as &quot;RotatedText&quot;, which exactly matches the model extension name.</p>

 

-

-

-<p>We can see&nbsp;most of the methods here are just getter/setters. For

-simple extended report item, this is normally already enough.</p>

-

-

-

-<h3>2) org.eclipse.birt.report.designer.ui.reportitemUI</h3>

-

-

-

-<p>This extension point is provided by BIRT Designer, user uses this

-extension point to define the UI behavior for&nbsp;extended report

-items.<br>

-

-

-

-<br>

-

-

-

-<img style="width: 1001px; height: 233px;" alt="" src="images/ui-extension.png"><br>

-

-

-

-<br>

-

-First we need bind the Designer extension with Model extension, to do

-this,&nbsp;we simply specify the extension name as "RotatedText".</p>

-

-

-

-<p>Next step, we specify some&nbsp;settings for this extended report item:</p>

-

-

+<p>The next step, we create some other elements like &quot;palette&quot;, &quot;editor&quot; and &quot;outline&quot; under the extension, and specify the detailed settings for this extended report item as following:</p>

 

 <ul>

-

-

-

-  <li>Palette Settings</li>

-

-

-

-  

-  

+  <li>Palette</li>

   <ul>

-

-

-

-    <li>specify the icon to be shown in Palette view, and the

-palette category as well. If the category is not specified, it will use

-the default "Report Items" category.</li>

-

-

-

-  

-  

+    <li>Specifies the icon to be shown in Palette view, as well as the

+palette category. If the category is not specified, the default &quot;Report Items&quot; category will be used.</li>

   </ul>

-

-

-

 </ul>

 

-

-

 <img style="width: 495px; height: 111px;" alt="" src="images/palette-detail.png"><br>

 

-

-

 <br>

 

-

-

 <ul>

-

-

-

-  <li>Editor Settings</li>

-

-

-

-  

-  

+  <li>Editor</li>

   <ul>

-

-

-

-    <li>specify the report item visibility in different editor pages, and whether&nbsp;resizing control should be enabled.&nbsp;</li>

-

-

-

-  

-  

+    <li>Specifies the report item visibility in different editor pages, and whether the resizing control is enabled.</li>

   </ul>

-

-

-

 </ul>

 

-

-

 <img style="width: 495px; height: 133px;" alt="" src="images/editor-detail.png"><br>

 

-

-

 <br>

 

-

-

 <ul>

+  <li>Outline</li>

 

-

-

-  <li>Outline Settings</li>

-

-

-

-  

-  

   <ul>

-

-

-

-    <li>specify the icon to be shown in Outline view, normally this is the same as in Palette view.</li>

-

-

-

-  

-  

+    <li>Specifies the icon to be shown in Outline view. Normally this is the same as the one in Palette view.</li>

   </ul>

 

-

-

 </ul>

 

-

-

 <img style="width: 497px; height: 90px;" alt="" src="images/icon-detail.png"><br>

 <p>

 

+The last step, we need specify the UI provider for this extended report item.</p>

 

-The last step, specify the implementation class for UI provider:</p>

-

-

-

-<img style="width: 498px; height: 94px;" alt="" src="images/labelui-detail.png"><br>

-

-

-

-<p>The UI provider&nbsp;defines how to display and interact with the

+<p>The UI provider defines how to display and interact with the

 extended report item within the editor. BIRT designer support three types of

 basic UI providers:</p>

 

-

-

 <ul>

 

-

-

   <li>Label UI Provider</li>

-

-

-

-  

-  

   <ul>

-

-

-

-    <li>user implements the&nbsp;IReportItemLabelProvider interface, it simply just requires&nbsp;an text content.</li>

-

-

-

-  

-  

+    <li>The user implements the <code>IReportItemLabelProvider</code> interface, which simply manipulates and displays a text content.</li>

   </ul>

 

-

-

   <li>Image UI Provider</li>

-

-

-

-  

-  

   <ul>

-

-

-

-    <li>user implements the&nbsp;IReportItemImageProvider interface, it simply just requires&nbsp;an image content.</li>

-

-

-

-  

+    <li>The user implements the <code>IReportItemImageProvider</code> interface, which simply manipulates and displays an image content.</li>

   

   </ul>

-

-

-

+  

   <li>Figure UI Provider</li>

-

-

-

-  

-  

   <ul>

-

-

-

-    <li>user implements the IRportItemFigureProvider, This provider uses Figure interface from <a href="http://www.eclipse.org/gef/">GEF</a>, providing more flexibility and interactivity support.</li>

-

-

-

-  

-  

+    <li>The user implements the <code>IRportItemFigureProvider</code>, which uses the Figure interface from <a href="http://www.eclipse.org/gef/">GEF</a>, providing more flexibility and interactivity support.</li>

   </ul>

 

-

-

 </ul>

 

-

 <br>

 

+<p>In this example, we choose to implement the simplest Label UI

+Provider first, in subsequent examples, we will introduce other types of UI providers.</p>

 

-<p>In this example,&nbsp;we choose to implement the simplest Label UI

-Provider first, in consequent examples, we may introduce other type of UI providers.</p>

+<p>To register the Label UI provider, we create a &quot;reportItemLabelUI&quot; element under the extension, and specify the implementor class, which must implement <code>IReportItemLabelProvider</code> interface.</p>

 

+<img style="width: 498px; height: 94px;" alt="" src="images/labelui-detail.png"><br>

 

 <p>

-Our&nbsp;Label UI Provider implementation class is

-"org.eclipse.birt.sample.reportitem.rotatedText.RotatedTextLabelUI",

-the code looks very simple:</p>

+Here our Label UI Provider implementor class is <code>org.eclipse.birt.sample.reportitem.rotatedText.RotatedTextLabelUI</code>,

+the code is very simple:</p>

 

+<pre>public class RotatedTextLabelUI implements IReportItemLabelProvider

+{

+	public String getLabel( ExtendedItemHandle handle )

+	{

+		try

+		{

+			IReportItem item = handle.getReportItem( );

+			if ( item instanceof RotatedTextItem )

+			{

+				return ( (RotatedTextItem) item ).getText( );

+			}

+		}

+		catch ( ExtendedElementException e )

+		{

+			e.printStackTrace( );

+		}

+		return null;

+	}

+}</pre>

 

-

-<pre>public class RotatedTextLabelUI implements IReportItemLabelProvider<br>{<br>	public String getLabel( ExtendedItemHandle handle )<br>	{<br>		try<br>		{<br>			IReportItem item = handle.getReportItem( );<br>			if ( item instanceof RotatedTextItem )<br>			{<br>				return ( (RotatedTextItem) item ).getText( );<br>			}<br>		}<br>		catch ( ExtendedElementException e )<br>		{<br>			e.printStackTrace( );<br>		}<br>		return null;<br>	}<br>}</pre>

-

-

-

-<p>You can see what it does is just reading the property from model and returning a text value.<br>

-

-

+<p>You can see what it really does is just reading the text property value from model and returning as a string.<br>

 

 <br>

 

-

-Once we completed the designer extension, we can run the desginer first and have a glance for&nbsp;what we already have now:<br>

-

-

+After we completed the designer extension, we can run the desginer first and check what we already have now:<br>

 

 <br>

 

-

-

-OK, the Palette view already contains the new RotatedText extended report item.</p>

-

-

+OK, the Palette view now contains the new <code>RotatedText</code> extended report item.</p>

 

 <img style="width: 341px; height: 408px;" alt="" src="images/palette.png"> <br>

 

-

-

-<p>Right-click in the editor, we can see the RotatedText item is also available in the context menu.</p>

-

-

+<p>Right-click anywhere in the editor, we can see the <code>RotatedText</code> item is also available in the &quot;Insert&quot; context menu.</p>

 

 <img style="width: 487px; height: 395px;" alt="" src="images/layout.png"><br>

 

-

-

-<p>Now&nbsp;try insert one RotatedText item to report, in Outline view, we can see the new RotatedText node.<br>

-

-

+<p>Now try insert one RotatedText item in layout, in Outline view, we can see it also appears.<br>

 

 </p>

 

-

-

 <img style="width: 347px; height: 438px;" alt="" src="images/outline.png"><br>

 

-

-

-<p>Select the RotatedText item, open the Properties view, it immediately

+<p>Select the RotatedText item, open the <em>Properties</em> view, it immediately

 lists all the properties that belong to this extended report item. Among

-them, we can see "Rotation Angle" and "Text

-Content" as well as other inherited properties. User can&nbsp;edit the

-property value in this view.

+them, we can see the "Rotation Angle" and "Text

+Content" as well as other inherited properties. By now, the user can edit these

+property values through this view.

 </p>

 

-

-

 <img style="width: 728px; height: 346px;" alt="" src="images/properties.png"><br>

 

+<p>Now the designer extension is done, let's continue to the Report Engine extension.</p>

 

-<p>Now designer extension is done, let's step to the Report Engine extension.</p>

+<h3>org.eclipse.birt.report.engine.reportitemPresentation</h3>

 

-

-

-<h3>3) org.eclipse.birt.report.engine.reportitemPresentation</h3>

-

-

-

-<p>This extension point is provided by BIRT Report Engine, user uses

+<p>This extension point is provided by BIRT Report Engine, the user uses

 this extension point to define the presentation behavior of the

 extended report item.<br>

 

-

-

 </p>

 

-

-

 <div style="text-align: left;"><img style="width: 1003px; height: 166px;" alt="" src="images/engine-extension.png"><br>

 

-

-

-<p>First we also need specify the extension name as "RotatedText" to link it

-with&nbsp;Model extension, and specify the presentation implementation

-class

-as

-"org.eclipse.birt.sample.reportitem.rotatedtext.RotatedTextPresentationImpl".

-The presentation implementation class need implement the

-IReportItemPresentation interface.<br>

-

-

+<p>First we also need bind the engine extension with model extension. To achieve this, we create a &quot;reportItem&quot; element under the engine extension and 

+specify the <code>name</code> property as "RotatedText", also we specify the presentation implementor class

+as <code>org.eclipse.birt.sample.reportitem.rotatedtext.RotatedTextPresentationImpl</code>.

+The presentation implementor class must implement the

+<code>IReportItemPresentation</code> interface.<br>

 

 <br>

 

+Our plan for implementing the rotated text effect is to create an image

+dynamically, in this image, we use <em>Swing</em> graphics API to render the

+rotated text.</p>

 

-Our plan to implement the rotated text effect is to create an image

-dynamically, in this image, we use SWING graphics API to render the

-rotated text.&nbsp;</p>

+<p>Here is the code that we need:</p>

 

-<p>Here is the code that all we need:</p>

+<pre>public class RotatedTextPresentationImpl extends ReportItemPresentationBase

+{

+	private RotatedTextItem textItem;

+	

+	public void setModelObject( ExtendedItemHandle modelHandle )

+	{

+		try

+		{

+			textItem = (RotatedTextItem) modelHandle.getReportItem( );

+		}

+		catch ( ExtendedElementException e )

+		{

+			e.printStackTrace( );

+		}

+	}

+	

+	public int getOutputType( )

+	{

+		return OUTPUT_AS_IMAGE;

+	}

+	

+	public Object onRowSets( IRowSet[] rowSets ) throws BirtException<br>

+	{

+		if ( textItem == null )

+		{

+			return null;

+		}

+		

+		int angle = textItem.getRotationAngle( );

+		String text = textItem.getText( );

+		BufferedImage rotatedImage = SwingGraphicsUtil.createRotatedTextImage( text, angle, new Font( "Default", 0, 12 ) ); //$NON-NLS-1$

+		ByteArrayInputStream bis = null;

+		

+		try

+		{

+			ImageIO.setUseCache( false );

+			ByteArrayOutputStream baos = new ByteArrayOutputStream( );

+			ImageOutputStream ios = ImageIO.createImageOutputStream( baos );

+			ImageIO.write( rotatedImage, "png", ios ); //$NON-NLS-1$

+			ios.flush( );

+			ios.close( );

+			bis = new ByteArrayInputStream( baos.toByteArray( ) );

+		}

+		catch ( IOException e )

+		{

+			e.printStackTrace( );

+		}

+		return bis;

+	}

+}</pre>

 

-

-

-<pre>public class RotatedTextPresentationImpl extends ReportItemPresentationBase<br>{<br>	private RotatedTextItem textItem;<br><br>	public void setModelObject( ExtendedItemHandle modelHandle )<br>	{<br>		try<br>		{<br>			textItem = (RotatedTextItem) modelHandle.getReportItem( );<br>		}<br>		catch ( ExtendedElementException e )<br>		{<br>			e.printStackTrace( );<br>		}<br>	}<br><br>	public int getOutputType( )<br>	{<br>		return OUTPUT_AS_IMAGE;<br>	}<br><br>	public Object onRowSets( IRowSet[] rowSets ) throws BirtException<br>	{<br>		if ( textItem == null )<br>		{<br>			return null;<br>		}<br><br>		int angle = textItem.getRotationAngle( );<br>		String text = textItem.getText( );<br>		BufferedImage rotatedImage = SwingGraphicsUtil.createRotatedTextImage( text, angle, new Font( "Default", 0, 12 ) ); //$NON-NLS-1$<br>		ByteArrayInputStream bis = null;<br><br>		try<br>		{<br>			ImageIO.setUseCache( false );<br>			ByteArrayOutputStream baos = new ByteArrayOutputStream( );<br>			ImageOutputStream ios = ImageIO.createImageOutputStream( baos );<br>			ImageIO.write( rotatedImage, "png", ios ); //$NON-NLS-1$<br>			ios.flush( );<br>			ios.close( );<br>			bis = new ByteArrayInputStream( baos.toByteArray( ) );<br>		}<br>		catch ( IOException e )<br>		{<br>			e.printStackTrace( );<br>		}<br>		return bis;<br>	}<br>}<br></pre>

-

-

-

-<p>The logic is&nbsp;pretty straightforward, the main part is to

-generate an image dynamically in the&nbsp;onRowSets() method. To return

-the image, we simply create an in-memory stream to hold&nbsp;the image

-content.</p>

-

-

+<p>The logic is actually pretty straightforward, the main part is to

+generate an <code>Image</code> dynamically in the <code>onRowSets()</code> method. To return

+the image content, we simply create an in-memory stream and put the image content in it.</p>

 

 <p>Here is the utility class that implements the key rotation rendering algorithm:</p>

 

-

-

-<pre>public class SwingGraphicsUtil<br>{<br>	public static BufferedImage createRotatedTextImage( String text, int angle, Font ft )<br>	{<br>		Graphics2D g2d = null;<br>		try<br>		{<br>			if ( text == null || text.trim( ).length( ) == 0 )<br>			{<br>				return null;<br>			}<br>			BufferedImage stringImage = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_ARGB );<br>			g2d = (Graphics2D) stringImage.getGraphics( );<br>			g2d.setFont( ft );<br>			FontMetrics fm = g2d.getFontMetrics( );<br>			Rectangle2D bounds = fm.getStringBounds( text, g2d );<br>			TextLayout tl = new TextLayout( text, ft, g2d.getFontRenderContext( ) );<br>			g2d.dispose( );<br>			g2d = null;<br>			return createRotatedImage( tl, (int) bounds.getWidth( ), (int) bounds.getHeight( ), angle );<br>		}<br>		catch ( Exception e )<br>		{<br>			e.printStackTrace( );<br>			if ( g2d != null )<br>			{<br>				g2d.dispose( );<br>			}<br>		}<br>		return null;<br>	}<br><br>	private static BufferedImage createRotatedImage( Object src, int width, int height, int angle )<br>	{<br>		angle = angle % 360;<br>		if ( angle &lt; 0 )<br>		{<br>			angle += 360;<br>		}<br>		if ( angle == 0 )<br>		{<br>			return renderRotatedObject( src, 0, width, height, 0, 0 );<br>		}<br>		else if ( angle == 90 )<br>		{<br>			return renderRotatedObject( src, -Math.PI / 2, height, width, -width, 0 );<br>		}<br>		else if ( angle == 180 )<br>		{<br>			return renderRotatedObject( src, Math.PI, width, height, -width, -height );<br>		}<br>		else if ( angle == 270 )<br>		{<br>			return renderRotatedObject( src, Math.PI / 2, height, width, 0, -height );<br>		}<br>		else if ( angle &gt; 0 &amp;&amp; angle &lt; 90 )<br>		{<br>			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );<br>			double cosTheta = Math.abs( Math.cos( angleInRadians ) );<br>			double sineTheta = Math.abs( Math.sin( angleInRadians ) );<br>			int dW = (int) ( width * cosTheta + height * sineTheta );<br>			int dH = (int) ( width * sineTheta + height * cosTheta );<br>			return renderRotatedObject( src, angleInRadians, dW, dH, -width * sineTheta * sineTheta, width * sineTheta * cosTheta );<br>		}<br>		else if ( angle &gt; 90 &amp;&amp; angle &lt; 180 )<br>		{<br>			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );<br>			double cosTheta = Math.abs( Math.cos( angleInRadians ) );<br>			double sineTheta = Math.abs( Math.sin( angleInRadians ) );<br>			int dW = (int) ( width * cosTheta + height * sineTheta );<br>			int dH = (int) ( width * sineTheta + height * cosTheta );<br>			return renderRotatedObject( src, angleInRadians, dW, dH, -( width + height * sineTheta * cosTheta ), -height / 2 );<br>		}<br>		else if ( angle &gt; 180 &amp;&amp; angle &lt; 270 )<br>		{<br>			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );<br>			double cosTheta = Math.abs( Math.cos( angleInRadians ) );<br>			double sineTheta = Math.abs( Math.sin( angleInRadians ) );<br>			int dW = (int) ( width * cosTheta + height * sineTheta );<br>			int dH = (int) ( width * sineTheta + height * cosTheta );<br>			return renderRotatedObject( src, angleInRadians, dW, dH, -( width * cosTheta * cosTheta ), -( height + width * cosTheta * sineTheta ) );<br>		}<br>		else if ( angle &gt; 270 &amp;&amp; angle &lt; 360 )<br>		{<br>			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );<br>			double cosTheta = Math.abs( Math.cos( angleInRadians ) );<br>			double sineTheta = Math.abs( Math.sin( angleInRadians ) );<br>			int dW = (int) ( width * cosTheta + height * sineTheta );<br>			int dH = (int) ( width * sineTheta + height * cosTheta );<br>			return renderRotatedObject( src, angleInRadians, dW, dH, ( height * cosTheta * sineTheta ), -( height * sineTheta * sineTheta ) );<br>		}<br>		return renderRotatedObject( src, 0, width, height, 0, 0 );<br>	}<br><br>	private static BufferedImage renderRotatedObject( Object src, double angle, int width, int height, double tx, double ty )<br>	{<br>		BufferedImage dest = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );<br>		Graphics2D g2d = (Graphics2D) dest.getGraphics( );<br>		g2d.setColor( Color.black );<br>		g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );<br>		g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );<br>		AffineTransform at = AffineTransform.getRotateInstance( angle );<br>		at.translate( tx, ty );<br>		g2d.setTransform( at );<br>		if ( src instanceof TextLayout )<br>		{<br>			TextLayout tl = (TextLayout) src;<br>			tl.draw( g2d, 0, tl.getAscent( ) );<br>		}<br>		else if ( src instanceof Image )<br>		{<br>			g2d.drawImage( (Image) src, 0, 0, null );<br>		}<br>		g2d.dispose( );<br>		return dest;<br>	}<br>}<br></pre>

-

-

+<pre>public class SwingGraphicsUtil

+{

+	public static BufferedImage createRotatedTextImage( String text, int angle, Font ft )

+	{

+		Graphics2D g2d = null;

+		try

+		{

+			if ( text == null || text.trim( ).length( ) == 0 )

+			{

+				return null;

+			}

+			BufferedImage stringImage = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_ARGB );

+			g2d = (Graphics2D) stringImage.getGraphics( );

+			g2d.setFont( ft );

+			FontMetrics fm = g2d.getFontMetrics( );

+			Rectangle2D bounds = fm.getStringBounds( text, g2d );

+			TextLayout tl = new TextLayout( text, ft, g2d.getFontRenderContext( ) );

+			g2d.dispose( );

+			g2d = null;

+			return createRotatedImage( tl, (int) bounds.getWidth( ), (int) bounds.getHeight( ), angle );

+		}

+		catch ( Exception e )

+		{

+			e.printStackTrace( );

+			if ( g2d != null )

+			{

+				g2d.dispose( );

+			}

+		}

+		return null;

+	}

+	

+	private static BufferedImage createRotatedImage( Object src, int width, int height, int angle )

+	{

+		angle = angle % 360;

+		if ( angle &lt; 0 )

+		{

+			angle += 360;

+		}

+		if ( angle == 0 )

+		{

+			return renderRotatedObject( src, 0, width, height, 0, 0 );

+		}

+		else if ( angle == 90 )

+		{

+			return renderRotatedObject( src, -Math.PI / 2, height, width, -width, 0 );

+		}

+		else if ( angle == 180 )

+		{

+			return renderRotatedObject( src, Math.PI, width, height, -width, -height );

+		}

+		else if ( angle == 270 )

+		{

+			return renderRotatedObject( src, Math.PI / 2, height, width, 0, -height );

+		}

+		else if ( angle &gt; 0 &amp;&amp; angle &lt; 90 )

+		{

+			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );

+			double cosTheta = Math.abs( Math.cos( angleInRadians ) );

+			double sineTheta = Math.abs( Math.sin( angleInRadians ) );

+			int dW = (int) ( width * cosTheta + height * sineTheta );

+			int dH = (int) ( width * sineTheta + height * cosTheta );

+			return renderRotatedObject( src, angleInRadians, dW, dH, -width * sineTheta * sineTheta, width * sineTheta * cosTheta );

+		}

+		else if ( angle &gt; 90 &amp;&amp; angle &lt; 180 )

+		{

+			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );

+			double cosTheta = Math.abs( Math.cos( angleInRadians ) );

+			double sineTheta = Math.abs( Math.sin( angleInRadians ) );

+			int dW = (int) ( width * cosTheta + height * sineTheta );

+			int dH = (int) ( width * sineTheta + height * cosTheta );

+			return renderRotatedObject( src, angleInRadians, dW, dH, -( width + height * sineTheta * cosTheta ), -height / 2 );

+		}

+		else if ( angle &gt; 180 &amp;&amp; angle &lt; 270 )

+		{

+			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );

+			double cosTheta = Math.abs( Math.cos( angleInRadians ) );

+			double sineTheta = Math.abs( Math.sin( angleInRadians ) );

+			int dW = (int) ( width * cosTheta + height * sineTheta );

+			int dH = (int) ( width * sineTheta + height * cosTheta );

+			return renderRotatedObject( src, angleInRadians, dW, dH, -( width * cosTheta * cosTheta ), -( height + width * cosTheta * sineTheta ) );

+		}

+		else if ( angle &gt; 270 &amp;&amp; angle &lt; 360 )

+		{

+			double angleInRadians = ( ( -angle * Math.PI ) / 180.0 );

+			double cosTheta = Math.abs( Math.cos( angleInRadians ) );

+			double sineTheta = Math.abs( Math.sin( angleInRadians ) );

+			int dW = (int) ( width * cosTheta + height * sineTheta );

+			int dH = (int) ( width * sineTheta + height * cosTheta );

+			return renderRotatedObject( src, angleInRadians, dW, dH, ( height * cosTheta * sineTheta ), -( height * sineTheta * sineTheta ) );

+		}

+		return renderRotatedObject( src, 0, width, height, 0, 0 );

+	}

+	

+	private static BufferedImage renderRotatedObject( Object src, double angle, int width, int height, double tx, double ty )

+	{

+		BufferedImage dest = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );

+		Graphics2D g2d = (Graphics2D) dest.getGraphics( );

+		g2d.setColor( Color.black );

+		g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );

+		g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );

+		AffineTransform at = AffineTransform.getRotateInstance( angle );

+		at.translate( tx, ty );

+		g2d.setTransform( at );

+		if ( src instanceof TextLayout )

+		{

+			TextLayout tl = (TextLayout) src;

+			tl.draw( g2d, 0, tl.getAscent( ) );

+		}

+		else if ( src instanceof Image )

+		{

+			g2d.drawImage( (Image) src, 0, 0, null );

+		}

+		g2d.dispose( );

+		return dest;

+	}

+}</pre>

 

 <h2>The Result</h2>

 

-

-

-<p>Now all&nbsp;required extension points are done, let's have a test.<br>

-

-

+<p>Now all required extension points are ready, let's have an integrated test.<br>

 

 <br>

 

-

-Create a report that contains some RotatedText items first:<br>

-

-

+Create a report and insert some RotatedText items first:<br>

 

 </p>

 

-

-

 <img style="width: 865px; height: 273px;" alt="" src="images/design-layout.png"><br>

 

-

-

-<p>Here we inserted quite a few RotatedText items&nbsp;with different angle settings.<br>

-

-

+<p>Here we have inserted quite a few RotatedText items that with different angle settings.<br>

 

 <br>

 

-

 Preview the report as HTML, it results like this:<br>

 

-

-

 </p>

 

-

-

 <img style="width: 703px; height: 218px;" alt="" src="images/html-output.png"><br>

 

-

-

 <p>Preview the report as PDF, it results like this:<br>

 

-

-

 </p>

 

-

-

 <img style="width: 757px; height: 482px;" alt="" src="images/pdf-output.png"><br>

 

-

-

 <br>

 

-

-

-<p>Done! So far we've successfully implemented a RotatedText extended

+<p>Done! So far we've successfully implemented a <code>RotatedText</code> extended

 report item for BIRT, and integrated it with Designer and Report Engine.<br>

 

-

-

 </p>

 

-

-

 </div>

 

-

-

 <h2>Summary</h2>

 

-

-

-<p>BIRT&nbsp;provides very good extension mechanism, which allows user

+<p>BIRT provides very good extension mechanism, which allows user

 to create custom reporting features. This article introduced how to write

 a custom RotatedText extended report item for BIRT.</p>

 

-

-

 <h2>Resources</h2>

 

+<p>[1]  <a href="extension-tutorial-1.zip">The complete source code</a>: you can extract and import it into Eclipse workspace as a plugin project directly</p>

 

+<p>[2]  BIRT Official Site: <a href="http://eclipse.org/birt">http://eclipse.org/birt</a></p>

 

-<p>[1] &nbsp;<a href="extension-tutorial-1.zip">The complete source code</a>: you can extract and import it into Eclipse workspace as a plugin project directly</p>

-

-

-

-<p>[2] &nbsp;BIRT Official Site: <a href="http://eclipse.org/birt">http://eclipse.org/birt</a></p>

-

-

-

-<p>[3] &nbsp;How to access Eclipse CVS: <a href="http://wiki.eclipse.org/CVS_Howto">http://wiki.eclipse.org/CVS_Howto</a></p>

-

-

+<p>[3]  How to access Eclipse CVS: <a href="http://wiki.eclipse.org/CVS_Howto">http://wiki.eclipse.org/CVS_Howto</a></p>

 

 <p><br>

 

-

-

 <br>

 

-

-

 </p>

 

-

-

 <br>

 

-

-

 </div>

 

-

-

 </body>

 </html>