Monthly Archives: August 2011

A New Look

My site has a new look!  Since firing up the blog earlier this year, I’ve never taken the time to style my site and make it mine.  I’ve been using the same old, boring, out-of-the-box themes for WordPress.  But this past weekend, I decided to finally open up the hood and get my hands dirty.

I had three major goals in mind for the new design:

  • Simplicity
  • Flexibility
  • My own color scheme

The first point speaks for itself.  But I will say that a nice, simple design allows for better readability and that is important to me.  Regarding the second point, I wanted a flexible design similar to that of phonyx.fm.  No matter which screen resolution used when visiting the site, I wanted the content to render to a viewer’s screen size as best as possible.  (You can test this out by re-sizing your browser window, assuming you are able to.)  Lastly, I wanted my own color scheme.  I didn’t care for much of the palettes of colors I’d seen with much of the themes out there.  I just wanted a set that was straightforward and helped with my first point…keeping it simple.

I think I was able to achieve the goals I was going for and I like how the design ended up.  I might tweak some of the colors here or there down the road, but for the most part, I think the “new look” will remain for a while.

AdvancedDataGrid CSV Export Utility Class

Recently, I needed a way to export data from Adobe Flex’s AdvancedDataGrid control to CSV-formatted files for use in Microsoft Excel.  Since Flex did not provide a native method, I looked into some existing third-party libraries.  Those did not work out, so I ended up building my own AdvancedDataGrid CSV export utility class.

I first experimented with the excellent AlivePDF library.  I had used AlivePDF in the past to…well…create PDFs.  One of the things I remembered from using it was that there was CSV export functionality.  But after spending some time experimenting, I was disappointed to find it required quite a bit of overhead and would not be able to fully satisfy my needs.  Next, I turned my attention towards the AS3XLS library.  From what I could gather, the library seems like what you’d want if you were trying to read & write native Excel files, but it didn’t provide CSV support.

So, I started searching the intertubes for another option.  I found a great  post by Abdul Qabiz, demonstrating a home baked solution he had come up with.  The code he presented was quite dated (it was written for Flex 2, targeting the DataGrid control) and was missing some features I needed.  However, it was exactly what I needed as a starting point.  Learning from what he provided, I rolled my own solution that provided everything I was looking for.

Below is the AdvancedDataGrid CSV export utility class I came up with.  It compiles in Flex 3.5, Flex 3.6 and Flex 4.5, handles grouped column headers, can double-quote values, and is capable of saving the CSV data of any language to a file (through the use of UTF-16 encoding).  I am posting this simple class in case somebody else might find it useful.  If you do, please leave a comment.  Also, let me know if you find ways to improve it! 

Note: The final version of the code uses a tab as the default CSV delimiter.  This is due to a limitation in Excel when dealing with a comma-separated value file in UTF-16/Unicode encoding.  Despite the use of a tab character, the format of the file is still viewed as a “CSV”.  :-)

Download the code.

CSVUtil.as:

package net.onyxmueller.util
{
 import flash.net.FileReference;
 import flash.utils.ByteArray;
 
 import mx.collections.ICollectionView;
 import mx.collections.IViewCursor;
 import mx.controls.AdvancedDataGrid;
 import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
 import mx.controls.advancedDataGridClasses.AdvancedDataGridColumnGroup;
 
 public class CSVUtil
 {
 private var _csvSeparator:String;
 private var _lineSeparator:String;
 private var _doubleQuoteValues:Boolean;
 private var _doubleQuoteRexExPattern:RegExp = /\"/g;
 private var _encoding:String;
 
 public function CSVUtil(csvSeparator:String = "\t", lineSeparator:String = "\n", doubleQuoteValues:Boolean = true)
 {
 _csvSeparator = csvSeparator;
 _lineSeparator = lineSeparator;
 _doubleQuoteValues = doubleQuoteValues;
 }
 
 public function formatAsCSVString(items:Array):String
 {
 if (_doubleQuoteValues)
 {
 // escape any existing double quotes then place double quotes around values
 for (var i:int = 0; i < items.length; i++)
 {
 items[i] = items[i] ? items[i].replace(_doubleQuoteRexExPattern, "\"\"") : "";
 items[i] = "\"" + items[i] + "\"";
 }
 }
 return items.join(_csvSeparator) + _lineSeparator;
 }
 
 public function advancedDataGridToCSVString(dg:AdvancedDataGrid):String
 {
 var headerCSV:String = "";
 var headerItems:Array;
 var dataCSV:String = "";
 var dataItems:Array;
 var columns:Array = dg.groupedColumns ? dg.groupedColumns : dg.columns;
 var column:AdvancedDataGridColumn;
 var headerGenerated:Boolean = false;
 var cursor:IViewCursor = (dg.dataProvider as ICollectionView).createCursor();
 
 // loop through rows
 while (!cursor.afterLast)
 {
 var obj:Object = null;
 obj = cursor.current;
 dataItems = new Array();
 headerItems = new Array();
 // loop through all columns for the row
 for each (column in columns)
 {
 // if the column is not visible or the header text is not defined (e.g., a column used for a graphic),
 // do not include it in the CSV dump
 if (!column.visible || !column.headerText)
 continue;
 
 // depending on whether the current column is a group or not, export the data differently
 if (column is AdvancedDataGridColumnGroup)
 {
 for each (var subColumn:AdvancedDataGridColumn in (column as AdvancedDataGridColumnGroup).children)
 {
 // if the sub-column is not visible or the header text is not defined (e.g., a column used for a graphic),
 // do not include it in the CSV dump
 if (!subColumn.visible || !subColumn.headerText)
 continue;
 dataItems.push(obj ? subColumn.itemToLabel(obj) : "");
 if (!headerGenerated)
 headerItems.push(column.headerText + ": " + subColumn.headerText);
 }
 }
 else
 {
 dataItems.push( obj ? column.itemToLabel(obj) : "");
 if (!headerGenerated)
 headerItems.push(column.headerText); 
 }
 }
 // append a CSV generated line of our data
 dataCSV += formatAsCSVString(dataItems);
 // if our header CSV has not been generated yet, do so; this should only occur once
 if (!headerGenerated)
 {
 headerCSV = formatAsCSVString(headerItems);
 headerGenerated = true;
 }
 // move to our next item
 cursor.moveNext();
 }
 
 // set references to null:
 headerItems = null;
 dataItems = null;
 columns = null;
 column = null;
 cursor = null;
 
 // return combined string
 return headerCSV + dataCSV;
 }
 
 public function saveAdvancedDataGridAsCSVFile(dg:AdvancedDataGrid, fileName:String, encoding:String = "utf-16"):void
 {
 var csvString:String = advancedDataGridToCSVString(dg);
 var bytes:ByteArray = new ByteArray();
 // if using UTF-16, prefix file with BOM (little-endian)
 if (encoding == "utf-16")
 {
 bytes.writeByte(0xFF);
 bytes.writeByte(0xFE);
 bytes.writeMultiByte(csvString, encoding);
 }
 else
 bytes.writeMultiByte(csvString, encoding);
 // prompt the user with a save location
 // note: FileReference requires a minimum flash player version of 10
 var fileReference:FileReference = new FileReference();
 fileReference.save(bytes, fileName);
 fileReference = null;
 }
 }
}