Archive for February, 2010

Adding CheckBox instances to a DataGrid column

Thursday, February 11th, 2010

Once in a while somebody wants to add an icon or more often a component in the DataGrid component. This seemed to be easier with AS2 components and there are some tutorials. However, this is different with AS3 components. Adobe has a nice article about manipulating the DataGrid. One of the tutorials on that site shows how to add images to the DataGrid using the UILoader component. In the following we want to add CheckBox instances to cells of one column.

Extending the CheckBox class – implementing the ICellRenderer interface

I will show two ways, but the aim is different. In the first part we add a CheckBox and clicking a DataGrid row will select the CheckBox as shown in this movie. We first create a Documnent class where we add the DataGrid. We associate a CellRenderer to the row, where we want to show CheckBox instances. Clicking another row will select the CheckBox in that row and unselect the previous CheckBox.

_check.cellRenderer = SpriteCellRenderer_1;

We then write the class SpriteCellRenderer_1. This class extends the CheckBox class and implements the ICellRenderer class. We need to add some functions to this class, which basically stay empty. This is because the ICellRenderer interface has certain properties and methods. Some of these overlap with the CheckBox class but some not and those are the ones we add. If you test movie at this stage you will see CheckBox instances added but without label. So in the constructor of this class just add this line

label = "Check it out";

and that is all.

Using the CheckBox in the DataGrid to select items for a shopping cart

That was quite simple, however, there is no real functionality of the CheckBox. In the next example we select CheckBox instances and the items associated with them will be added to a shopping cart list. The Document class is very similar as previously except for some important differences, which I will explain. We extend the Document class to a new Abstract class, which we have to write. This is because we need to communicate from outside the Document class. I have documented this in a separate blog article. Another change is of course that data which we receive from the CheckBox selection will be monitored and stored in an array, which is the listener function when a row is pressed.

So now let’s have a look at the SpriteCellRenderer class, which is equivalent to the SpriteCellRenderer_1 class from the previous movie. The SpriteCellRenderer class this time extends the Sprite class and also implements the ICellRenderer interface. Our strategy is to create a Sprite instance and then using addChild we add a CheckBox instance, which is independent from the DataGrid row MouseEvent. We need to add all the methods from the ICellRenderer interface, since the Sprite class does not share any of those. In order to add the CheckBox to the DataGrid we create a Sprite in the fla and name it “MyIcon”. This Sprite is associated with its own class. If you go back and look at the Document class of this movie you should look at the place where we add items to columns.

dp.addItem ({no:"1",item:"Apples",price:"$1,50",data:"MyIcon"});

The last part is the “_check” column with “data” as the variable. We place a Sprite instance in the DataGrid by adding this script to the function “set data” in the SpriteCellRenderer class.

public function set data (value:Object):void
{
	_data = value;
	if (!wasSelected)
	{
		var ClassReference:Class = getDefinitionByName(_data.data) as Class;
		var instance:Object = new ClassReference();
		addChild (DisplayObject(instance));
		wasSelected = true;
	}
}

The Boolean “wasSelected” is to prevent that every time a DataGrid row is selected more instances are added to the Displaylist. We have now achieved to add an instance of MyIcon to a row of the DataGrid.

Next we need to add the CheckBox. We do that using the MyIcon class. Go through the script and you see where. The last task is to communicate with the Document class to manipulate which items the user wants to select. If you look at the “MyIcon” class you see that it also extends the Abstract class and so shares properties and methods with the Document class. So we use the the set_Message method to send a message to the Document class. The nice thing here is that when we select the CheckBox we also trigger the DataGrid CLICK event and by using the get_message method know what is the selection status. Finally, we add our selection to an array or delete it again if we decide to unselect it. Check the scripts, which have a lot of additional comments. You can download all files here.

Flash AS3: PDF attachment with email

Monday, February 1st, 2010

For Flash

I recently had to get into email attachments using Flash. So I found the nice alivePDF library, with which one can create PDFs in Flash and Flex. I searched for tutorials and found this. As you can see in this example one can download a PDF file by opening a new browser page. I wanted to convert this to attach the PDF to an email. That was not difficult, although I had to struggle a bit with the PHP file. However, again the problem was that a new page was opened, which I did not like. My goal was to have everything done within the Flex or Flash file as shown below. No email will be sent in this movie to avoid misuse. However, enter an email in the text input and press the save button. You will see that no new window is opened but a message appears.
To create this movie I followed the example for the Model View Controller for Flash.

What I have done is I have slightly modifed the PDF.as file and created files in the Model-View-Controller style. You need to download the alivePDF library. Open the PDF.as file in the PDF folder and add the following lines where packages are imported.

/***********************************************************
* Classes need to be imported for saving PDF as attachment.
*/
	import com.flashscriptMVC.AbstractClass;
	import com.flashscriptMVC.IModel;
	import com.flashscriptMVC.Model;
	import com.flashscriptMVC.Controller;
	import com.flashscriptMVC.Mediator;
	
/*********************************************************/

Now we need to modify the save function. I added another parameter for the email and made it null. This does not affect any functionality of other projects, if you have those. Then I initiated a new class, the Mediator class, which serves as a Viewer class, since we cannot use the actual viewer object, which you see in the movie, for this purpose. The modification is shown below. Also we use the Base64 encoded bytearray, since we use that for the attachment later.

/****************************************
* The save function is altered for attaching a pdf to an email. 
* The function has one more parameter.
*****************************************/
public function save ( method:String, url:String='', 
downloadMethod:String='inline', fileName:String='output.pdf', 
frame:String="_blank", myEmail:String = null ):*
{
	dispatcher.dispatchEvent( new ProcessingEvent 
	( ProcessingEvent.STARTED ) );
	var started:Number = getTimer();
	finish();
	dispatcher.dispatchEvent ( new ProcessingEvent 
	( ProcessingEvent.COMPLETE, 
	getTimer() - started ) );
	buffer.position = 0;
	var output:* = null;
			
	switch (method)
	{
		case Method.LOCAL : 
		output = buffer;
		break;	
				
		case Method.BASE_64 : 
		output = Base64.encode64 ( buffer );
					
/*************************************************************************
* To send the PDF file as attachment we use the BASE_64 method and send the
* already converted data to the server. We use the Mediator class as a 
* Pseudo viewer class, whic communicates then with the controller and model 
* class and in the end with the SavePDFView object. Like a regular viewer
* we add eventlisteners.
*/

var model:IModel = new Model();
var controller:IControlHandler = new Controller(model);
if(downloadMethod == "attachment")
{
	if(myEmail == null)
	{
		trace("Don't forget to unnullify the myEmail parameter!")
		return;
	}
	var c:Mediator = new Mediator (model,controller);
	c.pdfHandler (url, output, fileName, myEmail);
	model.addEventListener ("serverResponse", c.update);
	model.addEventListener ("erMSG", c.update);
						
/******************************************************************************/
}
break;

I am not showing all the classes. You need to be familiar with the Model-View-Controller pattern. However, if you are not, then the only class you need to take care of and modify for your purpose is the SavePDFView.as clas, which is the viewer and the SavePDFMain.as class, which is the Document class of the movie. All other classes don’t need to be modified. Some of the labels and urls used in the movie are written in the xml file savepdf.xml and can be changed there.

For Flex

For Flex we can use the same classes except we need to create a MXML file of course and we need to change the Flash viewer class. The MXML file is shown here. It communicates with the former Flash viewer file, which we also need to modify as shown here. All other classes need not be modified.

We need to look at the php file. I found the script part for the attachment from various sources from the internet and modified them for this script. The first part of the script is the important part. There are the parameters from the Flash movie. As you may remember, the buffer, the actual pdf content, is already Base64 encoded. We create a temporary file and write the contents of the buffer variable into the file. At a later point we delete the file using the unlink() function.

<?php

$buffer = $_POST['buffer'];
$name = $_POST['name'];
$email = $_POST['email'];
$tempname = tempnam("/tmp", "PDF");

if ( isset ( $buffer )) 
{
	$files = fopen( $tempname, 'w' );
	$data = fwrite( $files, $buffer );
	fclose( $files );
}  
else 
{
	fail("An error occured encoding.");
}

You can download all files here. You can freely modify these files and use or distribute them as long as it is complient with the rules for the alivePDF library. Don’t forget to add the alivepdf library with the modified PDF.as file where an empty org folder is located.