March 4, 2010

Spring BlazeDS Integration

Hi to all, in this post I will explain how simple it is to configure an application that requires

- Front-end in Flex
- Back-end in Spring

with the Spring BlazeDS Integration.

To illustrate the integration support of Spring BlazeDS, I've built a sample application with:

Flex 4
Spring 2.5.6
Tomcat 6
MySql 5
Java 6

Data representation

We just represent information about Employee set. Specifically we represent the following fields:

- name
- surname
- address
- email
- category, to simplify we have supposed only 4 category : analyst – consultant – junior - manager

Architecture layers

Front-end

- Flex application that shows data on Employee set.

Back-end, ORM framework JPA

- Spring bean : EmployeeService
- DAO : EmployeeDAO
- Data : Employee

How to configurate Spring BlazeDS Integration

First of all we have to configure the MessageBroker component, core of the Spring BlazeDS Integration, because HTTP messages from the Flex client will be routed through the Spring DispatcherServlet to Spring managed MessageBroker.
Once this step is complete, we will be sure that remoting calls from the flex client reach their destination, so all we have to do is allow Spring to export its beans. To ensure this we must configure the BlazeDS Remoting service and all the necessary remote destinations.

MessageBroker's configuration

We have to configure MessageBroker into app-context.xml file

Add Flex namespace

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:flex="http://www.springframework.org/schema/flex"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/flex
http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">

...
<beans>

Spring provide an XML config namespace for MessageBroker's configuration inside app-context. To use the namespace support we must add the schema location into the Spring XML configuration files. This makes the Spring BlazeDS Integration configuration tags available under the flex namespace into ours configuration files. We have to be sure to refer to the spring-flex-1.0.xsd as every element and attribute is fully documented there.

To complete MessageBroker's configuration we have to add message-broker tag :

<flex:message-broker/>

How to configurate Flex client's mapping towards MessageBroker in three simple steps

1) Definition of the DispatcherServlet in web.xml

The simple request mapping scenario is when the front-end Flex is the only client type for the application. In this case we can just map /messagebroker as top-level path for requests.

<servlet>
<servlet-name>BlazeServlet</servlet-name>
<servletclass>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param>
<param-name>contextConfigLocation</param-name>
<param-value> /WEB-INF/spring/app-context.xml </param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>BlazeServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>

2) HandlerMapping into Spring app-context.xml

We have to configure an HandlerMapping to allow the correct requests mapping towards MessageBroker, but in this case we have to do nothing, because when we use a message-broker tag, there is a bean automatically installed that allows the HandlerMapping. This bean is a SimpleUrlHandlerMapping that maps all the incoming requests from DispathcherServlet to MessageBroker through the MessageBrokerHandlerAdapter. In practice the default settings installed by <flex:message-broker/> tag regard how to include the following configuration:

<!-- Maps request paths at /* to the BlazeDS MessageBroker -->
<bean
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/*=_messageBroker
</value>
</property>
</bean>

<!-- Dispatches requests mapped to a MessageBroker -->
<bean class="org.springframework.flex.servlet.MessageBrokerHandlerAdapter"/>

So HandlerMapping configuration in the spring app-contex.xml is how to include the message-broker tag.

3) Channel definition in the BlazeDS services-config.xml

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/ {context.root}/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

To complete the correct requests mapping towards MessageBroker we have to define a channel to secure communication from client to server. In this way flex client can send and receive data correctly. Channel definition is in the services-config.xml file and must correspond to the chosen mapping.

Exporting Spring beans for Flex Remoting

1) Remoting Service config

To configure the BlazeDS RemotingService we have to include remoting-config.xml file in the BlazeDS configuration, but with the Spring BlazeDS Integration this configuration file can be left out completely as the inclusion of the message-broker tag in the Spring configuration will cause the RemotingService to be configured with sensible defaults if none already exists at startup time. The end result is essentially equivalent to including the following minimal remoting-config.xml in the BlazeDS configuration.

<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service" class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object"
class="flex.messaging.services.remoting.adapters.JavaAdapter"
default="true"/>
</adapters>
</service>

We have just set a default channel in the service-config.xml

<services>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
</services>

2) Remoting destination tag

It allows to export existing Spring-managed services for direct remoting from a Flex client. Given the following Spring bean definition for a employeeService bean :

<!-- Bean employeeService -->
<bean id="employeeService" class="service.EmployeeService">
<constructor-arg ref="employeeDAO" />
</bean>

and assuming the existance of a Spring-managed MessageBroker configured via the message-broker tag, the following remoting-destination tag will expose the service for remoting to Flex client as a remote service destination called employeeService:

<!-- REMOTING DESTINATION TAG -->
<flex:remoting-destination ref="employeeService" />

We have seen that with few steps is possible to build an application that support a front-end in Flex and a back-end in Spring through the Spring BlazeDS Integration which focuses on a single main component : MessageBroker.

At this link you'll find the official Spring BlazeDS Integration reference.

February 26, 2010

New Pantaste feature - Column constrained dashboard

A new feature have been implemented to the Pantaste library. Now you can create a dashboard and constrain the movement of the panels or block only along the defined columns.

How can i implement this?
Simply by placing the <DashBlock> components inside the <DashPanelContainer>. And then placing all your <DashPanel> components inside the desired <DashBlock> this will be the first configuration and after launching your application you will be able to move the panels only along the defined DashBlocks.

So download the latest source and use the following code to create your first column constrained dashboard:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="horizontal"
xmlns:components="com.comtaste.pantaste.components.*">

<mx:Style source="/assets/style.css"/>

<components:DashPanelContainer width="100%"
height="100%"
backgroundColor="#EEEEEE">

<mx:HBox width="630" backgroundColor="#EEE"
height="30">
<mx:Text fontSize="30"
text="PANTASTE COLUMN EXAMPLE" fontWeight="bold"/>
</mx:HBox>

<components:DashBlock width="300"
y="50"
height="100%">
<components:DashPanel backgroundAlpha="1"
width="300"
title="Styled panel 1"
showTitleText="true"
titleBarHeight="35"
backgroundColor="#CCCCCC"/>
</components:DashBlock>

<components:DashBlock x="330"
y="50"
width="300"
height="100%">
<components:DashPanel backgroundAlpha="1"
width="300"
title="Styled panel 2"
showTitleText="true"
titleBarHeight="35"
backgroundColor="#CCCCCC">
<mx:TextArea text="Blocco 2 "/>
</components:DashPanel>
<components:DashPanel backgroundAlpha="1"
title="Styled panel 3"
width="300"
showTitleText="true"
titleBarHeight="35"
backgroundColor="#CCCCCC">
<mx:TextArea text="Blocco 4 "/>
</components:DashPanel>
</components:DashBlock>


<components:DashBlock x="660"
width="300"
height="100%">
<components:DashPanel width="300"
title="Styled panel 4"
showTitleText="true"
titleBarHeight="35"
backgroundAlpha="1"
backgroundColor="#CCCCCC">
<mx:TextArea text="Blocco 3 "/>
</components:DashPanel>
<components:DashPanel width="300"
title="Styled panel 5"
showTitleText="true"
titleBarHeight="35"
backgroundAlpha="1"
backgroundColor="#CCCCCC">
<mx:TextArea text="Blocco 5 "/>
</components:DashPanel>
</components:DashBlock>

</components:DashPanelContainer>

</mx:Application>

February 19, 2010

Filtering nested elements of a Tree data provider

Rich Internet applications developed with Flex benefit of many of the built-in functionality already provided by this framework. One of such enhancement is the filterFunction, that can be applied to instances of class ListCollectionView (and extending ones, such as the more commonly used ArrayCollection) and allows for fast and easy to implement filtering of data. This feature, used with advanced visualization controls as DataGrid or List, provides a rich environment for the end user, that can fully control the data he/she is working with.

The filter function is best suited with visualization controls that do not consider hierarchical data, but there may be cases in which the filter should be applied to hierarchical objects, displayed, for example, into a Tree component. If we apply the filterFunction to the data provider of a Tree component, the filter will only be applied to the first elements in the hierarchy and will not be applied to nested children. This may appear as an unwanted feature of the Tree, but it was actually meant to be that way, as the Tree control strives to be as independent as possible from the underlying displayed data and allows for personalization through it's descriptor.

In order to filter all nodes of a Flex Tree component, the solution is to apply the filter function to each nested element of the data provider. This can be accomplished by creating a new hierarchical structure, already filtered (can be rather expensive), or using dynamic filtering over the Tree's default descriptor, as shown below.

I extended the DefaultDataDescriptor used by the Tree, into a FilteredDataDescriptor, that has an additional field, namely filterFunction, which is applied as filter to each element of the nested structure:

private var _filterFunction:Function;

public function get filterFunction():Function {
  return _filterFunction;
}

/**
* Applies this filter function to the children of every node.
* @param value
*/
public function set filterFunction(value:Function):void {
  _filterFunction = value;
}

In order to apply the filter to the children of the data provider we can override getChildren() and, before returning the collection of children, apply the filter function:

override public function getChildren(node:Object, model:Object=null):ICollectionView {
  var collection:ICollectionView = super.getChildren(node, model);
  if (collection && (collection is ListCollectionView)) {
    (collection as ListCollectionView).filterFunction = _filterFunction;
  }
  return collection;
}

Note that this will work only for classes extending ListCollectionView (obviously Array is out o the picture) and that we also do not need to specifically call refresh() on the children collection, as it will be called later by the framework itself. All that's left now is to assign the newly created tree descriptor to a Tree and pass it the proper filter function(s).

February 11, 2010

How to test upload bandwidth to a FMS

How the download bandwidth check works

Flash Media Server has a native method to check download bandwitdh of the client, a feature that becomes very useful when you are going to stream multi bitrate content.
In a fresh installation of a Flash Media Server you can find a couple of default applications: live and vod, both come with a main.far containing the server side Actionscript code. To get a readable version you can grab the files from your FMS_ROOT/samples/applications/. Unless you have a Flash Media Interactive Server you are not authorized to substitute the original main.far with your own version, your server would throw an error; anyway you have a complete freedom in modifying and/or adding new applications if you use a developer edition (with its inbound connection limit).

Going back to the main.asc file, we can check the last lines of application.onConnect


function( p_client, p_autoSenseBW )
{
  ...
  if (p_autoSenseBW)
    p_client.checkBandwidth();
  else
    p_client.call("onBWDone");
}

application.onConnect is unsurprisingly a function called when a client connects to a FMS, the last if-block checks for the p_autoSenseBW flag; if it's present and true, a routine that checks the client bandwidth is called and does a callback on onBWDone when finished, otherwise onBWDone is called directly.
The bandwidth check can be called programmatically as well:


nc.call("checkBandwidth", null);

where nc is our NetConnection after a successful connection to the server.

Why you can need to check the upload

Sometimes you can need a bandwidth check from client to server, i.e. the upload bandwidth a client has toward the server. The most common scenario is a streaming from a client webcam. Via Actionscript we are able to adjust the camera quality affecting directly the amount of data transferred from the client, the best we can do is to get the best stream quality using all the bandwidth at our disposal; this will result in a smooth and good quality flv.

We can use the same approach used in Flash Media Server for the download bandwidth check. Basically the server starts sending chunks of data bigger and bigger until a size limit specified in the configuration or a timeout is reached. More info here http://www.adobe.com/livedocs/flashmediaserver/3.0/docs/help.html?content=08_xmlref_057.html#216930

Server side code

We can just do thinks the other way round, so the first thing we need server side is a function that accepts data from the client and subsequently calls a callback:


Client.prototype.recData = function(data)
{
  trace('recData('+data.size+')')
  var s = this.getStats();
  this.call("ack", 0, s.ping_rtt);
};

This server side code makes available to all clients a method called "recData" that takes as input generic data and calls a client side method "ack" passing the round trip time between client and server.

Client side code


The client will call the "recData" function on the server until a certain condition is met


startUploadTime=new Date().time;
_netConn.call("recData", new Responder(onRecDataResult, onRecDataFault), data);

we are calling the server side function passing a responder (not used) and the data. The data can be a simple string filled with a cycle (es. 4096 chars for 4KB). The "ack" method can be something like this:


public function ack(result:*):void
{
  finishUploadTime=new Date().time;
  var rtt:Number=new Number(result);
  // calculate time considering round trip time
  var totalTime:Number=(finishUploadTime - startUploadTime - rtt) / 1000;
  // calculate current bandwidth, current data size is base size * attempt number
  var bw:Number=UPLOAD_DATA_SIZE*(current_try+1) / totalTime;

  // check the attempts limit
  if (current_try < UPLOAD_BANDWIDTH_REPEATS)
  {
     // use a sum to make a final average
    bw_sum+=bw;
    // check the timeout limit
    if(totalTime>MAX_WAIT) {
       // set the bandwidth calculated so far
       if (Camera.getCamera())
         Camera.getCamera().setQuality(int(bw_sum / (current_try)), 0);

       uploadTestFinished = true;
       return;
     }

     // increase data size
     current_data += data;
     current_try++;
     startUploadTime=new Date().time;
     // recall the server side method
     _netConn.call("recData", new Responder(onRecDataResult, onRecDataFault), current_data);
     return ;
  }

  // Attempts limit reached, calculated the bw
  if (Camera.getCamera())
     Camera.getCamera().setQuality(int(bw_sum / (current_try)), 0);
}

Use the result to set up camera quality

ActionScript gives us a useful method to set up the camera quality: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/Camera.html#setQuality()
In our case we will set the bandwidth limit as found with our routine and set the quality to 0, i.e. the best quality supported by the current bandwidth.

February 4, 2010

Axis2, Spring and Annotations

Axis2 is a Web Services, SOAP, WSDL engine which current release, 1.5.1, comes with many interesting features among which there is the Spring Framework support.
Axis2 documentation offers some good example of Spring integration, such as the How to create a Spring-based POJO Web Service guide or the Axis2 Integration with the Spring Framework, but there's no mention of the use of Spring annotations.
Spring annotations work like a charm in Axis2 if you follow exactly the steps of the previous guide, but my tip is to build your service structure without using annotations in a first stage (unless you are already skilled in this field), then incrementally simplify your code adding Spring annotations.
Here is an example of a simplified application-config.xml when using Spring annotations with Axis:

<beans>

  <bean id="applicationContext" class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />
  <context:component-scan base-package="service"/>
  <context:component-scan base-package="bean"/>
</beans>

Now all your beans inside the packages 'service' and 'bean' will be deployed on Spring application context start or refresh. To annotate a class as Spring bean just use the @Component annotation on your class.
If you want to initialize your service on deployment time, add the @PostConstruct annotation on your initialization method. If your bean needs to access another bean, just use the @Autowired annotation on your class field.
Here a simple example:

@Component
public class MyService{

@Autowired
private MyBean bean;

@PostConstruct
protected void init() {
//init operations
}

Don't forget to add the SpringBeanName parameter in your services.xml:

<parameter name="SpringBeanName" >myService</parameter>

Annotations simplify your life reducing time spent configuring every bean you need in your application and using them in Axis allows you to build complex WebServices with less code.
Have fun.

January 25, 2010

Fields Validation with LiveCycle Designer 8 for XDP or Dynamic PDF files

One of the most important problem in the creation of Dynamical Pdf is the validation of data inserted by user. We know that LiveCycle Designer support us in validating with the following events:

  • prePrint: dispatched when the user starts to Print the document
  • preSave: dispatched when the user starts to Save the Document
  • preSubmit: dispatched when the user starts to Submit the Document
  • preExecute: dispatched when the user starts a data connection inside the Document

and we have also the possibility to change the status of a field to 'Required' (the default status of a designer object is 'Optional').
But if we put a control inside one of the events above, we can't stop the user action (view the Adobe Documentation for more!) if validation fails. For this reason we have the possibility to add to our XFA Application (version 2.5) an object called Validation Object.
Unfortunately we can't add it into the Design Model but we have to insert this object into the XML Source of our Application, so we have to find the following tags:

<config xmlns="http://www.xfa.org/schema/xci/1.0/">
<agent name="designer">
...
</agent>

<present>

<!-- [0..n] -->
...

and put the <validate> element into the <present> element:

<config xmlns="http://www.xfa.org/schema/xci/1.0/">
<agent name="designer">
...
</agent>
<present>
<!-- [0..n] -->
<validate>prePrint preSubmit </validate>
...

When you are done making the change, click on the Design View tab and make sure you say “yes” to have your changes applied.

With the release of XFA 2.8 and Acrobat/Reader 9.0, the <validate> element is now located under the <acrobat> element in the Source XML:

<config>
...
<acrobat>
...
<validate>prePrint </validate>
...
</acrobat>
...
</config>

With this Validation Object we can stop only Print, Submit and Execute actions. The Save action can not be stopped by the Validation Object (I think because an user would like to save a Pdf without filling all the fields and complete them in a second time).

Here are two examples: the first does not have the validation object in XML Source (here) while the second has this object built for the prePrint and preSubmit events (here).

Enjoy

November 23, 2009

The new Spring 3.0 and the integration with Flex 3 and BlazeDS

SpringSource and Comtaste have organized a free event where the new Spring 3.0 will be presented for the very first time in Italy and the integration with Flex and BlazeDS will be explored (all the detailed info here).
The event has been scheduled on Monday, November 30, 2009 from 2:45 PM - 6:00 PM (GMT+01h). The location is the awesome Link Campus - University of Malta, via Nomentana, 335 - Rome, Italy 00162.

The agenda will see two different sessions presented by SpringSource and Comtaste:

Session 1 (english) - Spring 3.0 and the new REST support, Speaker: Rossen Stoyanchev (SpringSource)

One of the major new themes of Spring 3.0 is the support for REST in Spring MVC. This talk will investigate these features from the perspective of a web application developer and discuss them in the context of JAX-RS, the Java Standard for RESTfulWeb Services. If you're familiar with JAX-RS you can relate your knowledge to Spring MVC. If you're an existing Spring MVC user can learn about major developments in the areas of data binding, validation, and type conversion as well as how Spring MVC compares to JAX-RS, a topic that's likely to come up in your organization.

Session 2 (in lingua italiana) - Integrare Spring con Flex 3, Speaker: Marco Casario (Comtaste)

SpringSource announced Spring BlazeDS Integration, a new open source project to provide tight integration between Spring and Adobe BlazeDS, Adobe’s open source server-based Java remoting and Web messaging technology.

This open source project will make it easy for Java and Spring developers to create enterprise-class rich Internet applications (RIAs) using Adobe Flex software, a cornerstone of the Adobe Flash Platform, and Spring, the de facto standard for enterprise Java.

The partecipation is free but you need to register in order to get the ticket.

November 20, 2009

LiveCycle Data Services ES2 version 3 is now available

According to the Adobe's definition, LiveCycle Data Services ES2 module is a scalable and optimized framework that abstracts the complexity of creating easy-to-use, personalized, and interactive applications. It includes a rich set of features that streamline the development, integration, and deployment of rich Internet applications (RIAs).

Adobe LiveCycle Data Services 3 provides significant new capabilities, including the following:

- Support for model-driven development of Flash applications, which make application development better, faster, and easier
- Secure and scalable connectivity across the DMZ with the Edge Server.
- New capabilities for developers to control and measure the quality of service of enterprise applications.

All the documentation is ready and available online:
LiveCycle Data Services ES2 version 3 Docs

You can download the LiveCycle Data Services ES2 free developer edition.

modal.jpg

November 16, 2009

Flash Catalyst's overview eSeminar recorded

Last week I've presented an eSeminar via Connect about Flash Catalyst.
Flash Catalyst will change the way designers and developers will work together to create Rich Interactive applications.

You can find the URL of the recorded event here: Overview on Flash Catalyst.

In this eSeminar you'll learn key features of the latest version of Flash Catalyst as well as the technologies behind the tool such as the FXG format and the Flex SDK 4.
You'll discover how to work with products such as Photoshop and Illustrator to create the look and feel and the user experience of a RIA, while automatically generating the necessary code in the background.

You can download Flash Catalyst beta 2 on the Adobe Labs.

June 11, 2009

Example of implementation of the Pantaste Library

Let's have a look to the Pantaste Library, exploring her feature trough examples, divided by interests:

HelloWorld
Switching dashed, snapped or free
Tile and Cascade panels in a container
Manual control panels ( minimize, maximize, restore )
Listen containers change
Apply constraint to Panels
Styling panels
Freeze panels

  • HelloWorld

This first example show how to implement a simple Panel and the relative container:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:components="com.comtaste.pantaste.components.*"

layout="vertical">

<components:DashPanelContainer width="100%" height="100%">

<components:DashPanel

title="HelloWorld"

titleBarHeight="30"

backgroundAlpha="1"

backgroundColor="#CCCCCC">

<mx:VBox

backgroundAlpha="1"

backgroundColor="#FFFFFF" >

<mx:Label text="Hello World from Pantaste Panel!" />

</mx:VBox>

</components:DashPanel>

</components:DashPanelContainer>

</mx:Application>

 

  • Switching dashed, snapped or free

 

Now let’s look how to switch the container type, between dashed, snapped or free to move:

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:components="com.comtaste.pantaste.components.*"

layout="vertical">

<mx:Script>

<![CDATA[

import com.comtaste.pantaste.components.DashDock;

]]>

</mx:Script>

<mx:HBox>

<mx:NumericStepper

id="snapSizer"

minimum="1"

maximum="500"

change="dashContainer.snapSize = snapSizer.value;"

visible="{dashContainer.snapped}" />

<mx:Button

toggle="true"

label="Snap"

click="dashContainer.snapped = !dashContainer.snapped;"

selected="{dashContainer.snapped}" />

<mx:Button

toggle="true"

label="Dash"

click="dashContainer.dashed = !dashContainer.dashed;"

selected="{dashContainer.dashed}" />

<mx:Button

toggle="true"

label="Free"

click="dashContainer.dashed = false; dashContainer.snapped = false;"

selected="{!dashContainer.snapped &amp;&amp; !dashContainer.dashed }" />

</mx:HBox>

<components:DashPanelContainer

id="dashContainer" width="100%" height="100%">

<components:DashPanel

title="Panel 1"

titleBarHeight="30"

backgroundAlpha="1"

backgroundColor="#CCCCCC">

<mx:VBox

backgroundAlpha="1"

backgroundColor="#FFFFFF" >

<mx:Label text="Here the content!" />

</mx:VBox>

</components:DashPanel>

<components:DashPanel

title="Panel 2"

titleBarHeight="30"

backgroundAlpha="1"

backgroundColor="#CCCCCC">

<mx:VBox width="100%" height="100%"

backgroundAlpha="1"

backgroundColor="#FFF000" >

<mx:Label text="Content 2!" />

</mx:VBox>

</components:DashPanel>

</components:DashPanelContainer>

</mx:Application>

 

  • Tile and Cascade panels in a container

 

It’s also possible to manual control panels on a container, like tile or cascade all panels. To do this we need to use the DashLayoutManager, a multiTon class that maps containers trough container id’s.

 

To use the DashLayoutManager of a specific container you have to reference to it trough the id:

DashLayoutManager.getManager( containerID ).

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"

layout="vertical"

xmlns:blocks="blocks.*">

<mx:Script>

<![CDATA[

import com.comtaste.pantaste.manager.DashLayoutManager;

private function tile( containerId:String ) : void

{

DashLayoutManager.getManager( containerId ).tile( );

}

private function cascade( containerId:String ) : void

{

DashLayoutManager.getManager( containerId ).cascade( );

}

]]>

</mx:Script>

<mx:HBox>

<mx:Button label="Tile Container 1" click="tile( dashContainer1.id );" />

<mx:Button label="Tile Container 2" click="tile( dashContainer2.id );" />

<mx:Spacer width="100" />

<mx:Button label="Cascade Container 1" click="cascade( dashContainer1.id );" />

<mx:Button label="Cascade Container 2" click="cascade( dashContainer2.id );" />

</mx:HBox>

<blocks:TwoPanels id="dashContainer1" />

<blocks:TwoPanels id="dashContainer2" />

</mx:Application>

 

  • Manual control panels ( minimize, maximize, restore )

 

Now let’s see how to control every panel programmatically, to maximize, minimize and restore its. To do this we have to use the DashPanelEvent class. So we don’t have any api to control, but we must use events.

 

First define the event:

  • Maximize:

var minimizeEvent:DashPanelEvent = new DashPanelEvent( DashPanelEvent.MINIMIZE, myPanel );

  • Minimize:

var maximizeEvent:DashPanelEvent = new DashPanelEvent( DashPanelEvent.MAXIMIZE, myPanel );

  • Restore:

var restoreEvent:DashPanelEvent = new DashPanelEvent( DashPanelEvent.RESTORE, myPanel );

 

and then dispatch the event:

myPanel.dispatchEvent( maximizeEvent );

myPanel.dispatchEvent( maximizeEvent);

myPanel.dispatchEvent( restoreEvent);

 

Example:

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:components="com.comtaste.pantaste.components.*">

<mx:Script>

<![CDATA[

import com.comtaste.pantaste.events.DashPanelEvent;

private function manualMinimize( ) : void

{

var minimizeEvent:DashPanelEvent = new DashPanelEvent( DashPanelEvent.MINIMIZE, myPanel );

myPanel.dispatchEvent( minimizeEvent );

}

private function manualMaximize( ) : void

{

var maximizeEvent:DashPanelEvent = new DashPanelEvent( DashPanelEvent.MAXIMIZE, myPanel );

myPanel.dispatchEvent( maximizeEvent );

}

private function manualRestore( ) : void

{

var restoreEvent:DashPanelEvent = new DashPanelEvent( DashPanelEvent.RESTORE, myPanel );

myPanel.dispatchEvent( restoreEvent );

}

]]>

</mx:Script>

<mx:HBox>

<mx:Button label="Maximize" click="manualMaximize();" />

<mx:Button label="Minimize" click="manualMinimize();" />

<mx:Button label="Restore" click="manualRestore();" />

</mx:HBox>

<components:DashPanelContainer width="100%" height="100%">

<components:DashPanel

id="myPanel"

title="My Manual Controlled Panel"

titleBarHeight="30"

backgroundAlpha="1"

backgroundColor="#CCCCCC">

<mx:VBox

backgroundAlpha="1"

backgroundColor="#FFFFFF" >

<mx:Label text="Minimize, maximize and restore me!" />

</mx:VBox>

</components:DashPanel>

</components:DashPanelContainer>

</mx:Application>

 

  • Listen containers change

 

The Pantaste dash container ( DashPanelContainer class ), propagate an event to inform you that something happened. Information that you can obtain is about panels and this is the type:

 

  • Added to the container
  • Removed from the container
  • Maximized
  • Minimized
  • Restored
  • Moved

 

All we have to do is listening on the “pantasteChanged” event defined by the DashPanelContainerEvent class. This class will provide to us the changedTypeEvent, the panel caused the change and the container were is placed.

 

Example:

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:blocks="blocks.*">

<mx:Script>

<![CDATA[

import com.comtaste.pantaste.events.DashPanelContainerEvent;

private function onPantasteChange( event:DashPanelContainerEvent ) : void

{

infoPanel.text += "\n Panel " + event.panel.title + " changed: " + event.changeType + " on container " + event.pantaste.id;

infoPanel.verticalScrollPosition = infoPanel.maxVerticalScrollPosition;

}

]]>

</mx:Script>

<mx:HBox width="100%">

<mx:TextArea width="100%" height="60" id="infoPanel" />

</mx:HBox>

<blocks:TwoPanels id="dashContainer1" pantasteChanged="onPantasteChange( event );" />

<blocks:TwoPanels id="dashContainer2" pantasteChanged="onPantasteChange( event );" />

</mx:Application>

 

  • Apply constraint to Panels

 

Setting constraint to the panels, let you the ability to control some default settings:

  • Closable
  • Movable
  • Resizable
  • Maximizable
  • Minimizable
  • Always in front

 

To implement this you can simply set the correspondent property of the panel.

 

Example:

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:components="com.comtaste.pantaste.components.*">

<mx:HBox>

<mx:Button toggle="true" label="minimizable" click="myPanel.minimizable = event.target.selected" selected="{myPanel.minimizable}" />

<mx:Button toggle="true" label="maximizable" click="myPanel.maximizable = event.target.selected" selected="{myPanel.maximizable}" />

<mx:Button toggle="true" label="resizable" click="myPanel.resizable = event.target.selected" selected="{myPanel.resizable}" />

<mx:Button toggle="true" label="closable" click="myPanel.closable = event.target.selected" selected="{myPanel.closable}" />

<mx:Button toggle="true" label="draggable" click="myPanel.draggable = event.target.selected" selected="{myPanel.draggable}" />

<mx:Button toggle="true" label="always in front" click="myPanel.alwaysInFront = event.target.selected" selected="{myPanel.alwaysInFront}" />

</mx:HBox>

<components:DashPanelContainer width="100%" height="100%">

<components:DashPanel

id="myPanel"

title="My Panel"

titleBarHeight="30"

backgroundAlpha="1"

backgroundColor="#CCCCCC">

<mx:VBox

backgroundAlpha="1"

backgroundColor="#FFFFFF" >

<mx:Label text="{'minimizable:' + myPanel.minimizable}" />

<mx:Label text="maximizable: {myPanel.maximizable}" />

<mx:Label text="resizable: {myPanel.resizable}" />

<mx:Label text="closable: {myPanel.closable}" />

<mx:Label text="draggable: {myPanel.draggable}" />

<mx:Label text="always in front: {myPanel.alwaysInFront}" />

</mx:VBox>

</components:DashPanel>

</components:DashPanelContainer>

</mx:Application>

 

  • Styling panels

 

To style the pantaste components you need to use styles. So create a style.css file and include into your application:

 

<mx:Style source="/assets/style.css" />

 

  • Styling the DashPanel by the global class implementing the backgroundImage:

DashPanel

{

background-image: Embed(source="assets/FlexSkin_FOB.swf", symbol="Panel_smallBase");

background-size: "100%";

}

 

  • Styling the controll buttons:

.minimizeButton

{

upSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_UpMin");

overSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_OverMin");

downSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_DownMin");

disabledSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_DisabledMin");

}

 

.maximizeButton

{

upSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_UpMax");

overSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_OverMax");

downSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_DownMax");

disabledSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_DisabledMax");

}

 

.restoreButton

{

upSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_UpMax");

overSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_OverMax");

downSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_DownMax");

disabledSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_DisabledMax");

}

 

.dockedButton

{

upSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_PanelUp");

overSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_PanelOver");

downSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_PanelDown");

disabledSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_PanelDisabled");

}

 

.closeButton

{

upSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_CloseUp");

overSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_CloseOver");

downSkin: Embed(source="assets/FlexSkin_FOB.swf", symbol="Button_CloseDown");

}

 

.titleBarText

{

fontWeight: bold;

color: #555555;

}

 

  • Setting icon properties:

 

Setting the icon image:

icon='@Embed(source="assets/FlexSkin_FOB.swf", symbol="Icon_music")'

 

Also you can set the x nad y offset position, if you want to change it:

iconXOffset="-8" iconYOffset="-8"

 

  • Control the title bar:

 

You can set the height of the title bar and if you want to show the title:

showTitleText="false"

titleBarHeight="35"

 

Example:

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:components="com.comtaste.pantaste.components.*">

<mx:Style source="/assets/style.css" />

<components:DashPanelContainer width="100%" height="100%">

<components:DashPanel

title="Styled panel" showTitleText="true" titleBarHeight="35"

iconXOffset="-8" iconYOffset="-8"

icon='@Embed(source="assets/FlexSkin_FOB.swf", symbol="Icon_travel")' >

</components:DashPanel>

</components:DashPanelContainer>

</mx:Application>

 

  • Freeze panels

 

An interesting feature of pantaste is that you can freeze panel, showing a loader progress bar, and remove it when you want.

 

Simple you must call myPanel.startLoad( ) to freeze and show the progress bar and myPanel.stopLoad( ) to hide the progressbar and defreeze.

 

Example:

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:components="com.comtaste.pantaste.components.*"

layout="vertical">

<mx:HBox>

<mx:Button label="Start" click="myPanel.startLoad( );" />

<mx:Button label="Stop" click="myPanel.stopLoad( );" />

</mx:HBox>

<components:DashPanelContainer width="100%" height="100%">

<components:DashPanel

id="myPanel"

title="Freeze and defreeze"

titleBarHeight="30"

backgroundAlpha="1"

backgroundColor="#CCCCCC">

<mx:VBox

backgroundAlpha="1"

backgroundColor="#FFFFFF" >

<mx:Label text="Loader panel!" />

</mx:VBox>

</components:DashPanel>

</components:DashPanelContainer>

</mx:Application>