Tuesday, October 15, 2013

Flex: XML appending

How to append a new node into a XML object in Flex/as3? Here's a simple example that teaches you how to append a XML node. Here's a guide on how to do it. But do take note that you have to use either _ or a letter for the first character of the name of the new node that you are trying to insert. However if you want to use numbers for the first character, there's a way to do it too. :P Besides for the ways that I have listed in this post, you can use dot notation (.) to append a new node too. :)

Source Code for the main application - 'SimpleXMLManipulation.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      creationComplete="creationCompleteEvt(event)" 
      xmlns:local="*">
 <fx:Declarations>
  <local:SimpleXMLConverter id="converter"/>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import mx.events.FlexEvent;
   
   protected function creationCompleteEvt(e:FlexEvent):void
   {
    converter.init();
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%" 
     verticalAlign="middle" 
     horizontalAlign="center">
  <s:Label text="Original XML"/>
  <s:TextArea text="@{converter.simpleXML}"/>
  <s:Spacer height="10"/>
  <s:HGroup>
   <s:VGroup horizontalAlign="center">
    <s:Label text="Modified XML using appendChild()"/>
    <s:TextArea text="{converter.simpleXML1}" 
       editable="false"
        width="30%" 
       minWidth="300"/>  
   </s:VGroup>
   <s:VGroup horizontalAlign="center">
    <s:Label text="Modified XML using []"/>
    <s:TextArea text="{converter.simpleXML2}"
       editable="false"
       width="30%" 
       minWidth="300"/>   
   </s:VGroup>
  </s:HGroup>
 </s:VGroup>
</s:Application>

Source code for the XML manipulating class
package
{
 import flash.events.Event;
 import flash.events.EventDispatcher;
 
 [Bindable]
 public class SimpleXMLConverter extends EventDispatcher
 {
  //XML String
  private var simpleXMLString:String = "" +
   "";
  
  //XML that contains the above simpleXMLString
  private var _simpleXML:XML;
  
  [Bindable(event="simpleXMLChanged")]
  public function get simpleXML():String
  {
   return _simpleXML;
  }

  public function set simpleXML(value:String):void
  {
   //If the input value isn't a valid XML,
   //we will set it to empty.
   try
   {
    _simpleXML = XML(value);
   }catch(e:Error)
   {
    _simpleXML = new XML();
   }
   
   //Modified XML using appendChild()
   simpleXML1 = XML(_simpleXML.toXMLString());
   if(simpleXML1)
   {
    var dummyXMLNode:XML;
    var dummyXMLNodeStr:String;
    dummyXMLNodeStr = "<" + name1Str + name2Str + ">";
    dummyXMLNodeStr += valueStr;
    dummyXMLNodeStr += "";
    dummyXMLNode = new XML(dummyXMLNodeStr);
    simpleXML1.appendChild(dummyXMLNode);
    if(simpleXML1.level1.length() > 0)
    {
     for(var i:int = 0; i < simpleXML1.level1.length(); i ++)
     {
      simpleXML1.level1[i].appendChild(dummyXMLNode);
     }
    }
   }
   
   //Modified XML using []
   simpleXML2 = XML(_simpleXML.toXMLString());
   if(simpleXML2)
   {
    simpleXML2[name1Str + name2Str] = 
     valueStr;
    if(simpleXML2.level1.length() > 0)
    {
     for(i = 0; i < simpleXML2.level1.length(); i ++)
     {
      simpleXML2.level1[i][name1Str + name2Str] = 
       valueStr;
     }
    }
   }
   
   //dispatching the 8 event to update the
   //respective text area
   dispatchEvent(new Event("simpleXML1Changed", 
    true, true));
   dispatchEvent(new Event("simpleXML2Changed", 
    true, true));
  }
  
  //XML that contains the modified XML based
  //on the above simpleXMLString and appendChild()
  private var _simpleXML1:XML;

  public function get simpleXML1():XML
  {
   return _simpleXML1;
  }

  [Bindable(event="simpleXML1Changed")]
  public function set simpleXML1(value:XML):void
  {
   _simpleXML1 = value;
  }
  
  //XML that contains the modified XML based
  //on the above simpleXMLString and []
  private var _simpleXML2:XML;

  public function get simpleXML2():XML
  {
   return _simpleXML2;
  }
  
  [Bindable(event="simpleXML2Changed")]
  public function set simpleXML2(value:XML):void
  {
   _simpleXML2 = value;
  }
  
  //The name of the empty node - part1
  private var name1Str:String = "empty";
  //The name of the empty node - part2
  private var name2Str:String = "node";
  
  //The value of the empty node
  private var valueStr:String = "dummyValue";
  
  public function init():void
  {
   simpleXML = new XML(simpleXMLString);
   
   //dispatching the event to update the main
   //respective text area
   dispatchEvent(new Event("simpleXMLChanged", 
    true, true));
  }
 }
}
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Saturday, October 5, 2013

Flex 4: Disabling a Button Bar Button...

I was trying to disable one of the buttons that belongs to a 'Button Bar' component that comes with Flex 4. After spending a bit of time debugging and googling, I finally managed to come out with a decent solution to it...

Source Code for the main application - 'SimpleButtonBarEnabling.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      creationComplete="creationCompleteEvent(event)">
 <fx:Script>
  <![CDATA[
   import mx.events.FlexEvent;
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    //We are disabling the 4th button.
    otherInfo.enabled = false;
   }
   
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%"
     verticalAlign="middle" 
     horizontalAlign="center" 
     gap="0">
  <!-- Create a Spark ButtonBar control to navigate 
   the ViewStack container. -->
  <s:ButtonBar dataProvider="{myViewStack}" 
      skinClass="CustomButtonBarSkin"/>
  
  <!-- Define the ViewStack and the three 
   child containers. -->
  <mx:ViewStack id="myViewStack" 
       borderStyle="solid" 
       width="50%"
       paddingBottom="10"
       paddingTop="10"
       paddingLeft="10"
       paddingRight="10">  
   <s:NavigatorContent id="search" 
       label="Search">
    <s:Label text="Search Screen"/>
   </s:NavigatorContent>
  
   <!-- set enabled="false" to disable the button -->
   <s:NavigatorContent id="custInfo" 
       label="Customer Info" 
       enabled="false">
    <s:Label text="Customer Info"/>
   </s:NavigatorContent>
  
   <s:NavigatorContent id="accountInfo" 
       label="Account Info">
    <s:Label text="Account Info"/>
   </s:NavigatorContent>
   
   <s:NavigatorContent id="otherInfo" 
        label="Others">
    <s:Label text="Others"/>
   </s:NavigatorContent>
  </mx:ViewStack>  
 </s:VGroup>
</s:Application>
And here's the custom skin class for the 'Button Bar' component.
<?xml version="1.0" encoding="utf-8"?>

<!--

    ADOBE SYSTEMS INCORPORATED
    Copyright 2008 Adobe Systems Incorporated
    All Rights Reserved.

    NOTICE: Adobe permits you to use, modify, and distribute this file
    in accordance with the terms of the license agreement accompanying it.

-->

<!--- The default skin class for the Spark ButtonBar component. The buttons on the ButtonBar component
    use the ButtonBarLastButtonSkin, ButtonBarFirstButtonSkin and ButtonBarMiddleButtonSkin classes.  
    
      @see spark.components.ButtonBar
      @see spark.components.ButtonBarButton    
        
      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4
-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
        alpha.disabled="0.5">

    <fx:Metadata>
    <![CDATA[ 
       /** 
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("spark.components.ButtonBar")]
    ]]>
    </fx:Metadata> 

    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>
    
    <fx:Declarations>

  <!--- Have removed the first and third button since it's not needed.  -->
  
        <!--- 
            @copy spark.components.ButtonBar#middleButton
            @default spark.skins.spark.ButtonBarMiddleButtonSkin
            @see spark.skins.spark.ButtonBarMiddleButtonSkin
  
   The middle Button will be used as the item renderer for all the
   buttons of this button bar. And we are enabling the buttons
   base on the data passed into this component.
        -->
        <fx:Component id="middleButton" >
            <s:ButtonBarButton enabled="{data.enabled}"/>
        </fx:Component>

    </fx:Declarations>

    <!--- @copy spark.components.SkinnableDataContainer#dataGroup -->
    <s:DataGroup id="dataGroup" width="100%" height="100%">
        <s:layout>
            <s:ButtonBarHorizontalLayout gap="-1"/>
        </s:layout>
    </s:DataGroup>

</s:Skin>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Friday, October 4, 2013

Renaming your recursive files and folder using a batch file.

Initially I was using a 3rd party software to do all the renaming work. But as I proceed, I ended up searching high and low for a method using a batch file (*.bat) to do all the tedious work. Therefore, after playing and modifying the code, I have ended up with this.

@echo off
setlocal enabledelayedexpansion
REM for renaming of recursive folders, sub folders
for /d /r %%f in (*.*) do (
set fn=%%~nxf

REM replace all the . with __ in the folder names (excludes extensions)
if not [!fn!]==[] ( 
if not ["%%~nxf"]==["!fn:.=__!"] ( 
echo ren "%%~f" "!fn:.=__!" 
ren "%%~f" "!fn:.=__!" 
)
)
REM replace all the -interface with nothing in the folder names
REM (excludes extensions) add a I in front of the folder name
if not [!fn!]==[] ( 
if not ["%%~nxf"]==["!fn:-interface=!"] ( 
echo ren "%%~f" "I!fn:-interface=!" 
ren "%%~f" "I!fn:-interface=!" 
)
)
)

REM for renaming of recursive files
for /r %%f in (*.*) do (
set fn=%%~nf

REM replace all the - with __ in the file names (excludes extensions)
if not [!fn!]==[] ( 
if not ["%%~nxf"]==["!fn:-=__!%%~xf"] ( 
echo ren "%%~f" "!fn:-=__!%%~xf" 
ren "%%~f" "!fn:-=__!%%~xf" 
)
)
REM replace all the -interface with nothing in the file names
REM (excludes extensions) add a I in front of the file name
if not [!fn!]==[] ( 
if not ["%%~nxf"]==["!fn:-interface=!%%~xf"] ( 
echo ren "%%~f" "I!fn:-interface=!%%~xf" 
ren "%%~f" "I!fn:-interface=!%%~xf" 
)
)
)
pause

* Click here to download the batch file that I have listed in this posted.
^ Click here to find out more about batch files in Windows.
~ Click here to find out the difference between %% and !! in a batch file.

Thursday, September 26, 2013

Windows: Create a automated action...

Not all software out there allows you to save a series of commands/actions and allows you to run them again without the need of opening the software. Even if it can allow you to do that using command prompt, not all the functionalities will not be provided to you. Luckily there are software like...

'AutoHotkey'
You can script the actions that you would like to perform in a particular
software. On top of that, you can generate the script into a normal
windows executable(.exe) file that allows you to share it with normal
Windows User.

However, I knew that there are numerous software out there that can provide
you with a GUI interface and record all the necessary steps that you would
like to perform over and over again. Ex: winautomation, Do It Again,
RoboTask, etc... But most of them requires a license, and since I'm
performing a easy task, therefore I would rather spend a bit of time
scripting the actions rather than paying for a license.

* Click here to find out more about 'AutoHotkey'.

Thursday, September 19, 2013

Flex 4: Using Ant to create a smaller file size like bin-release

I was trying to create an automation script for some of the projects in Adobe Flex 4 the other day and I realised that the ant build is generating a far more bigger swf file (in terms of the file size)than the ones created using bin-release. After numerous attempts, I finally managed to compress the file size to match the ones that that were generated using bin-release.

<!-- Within the <mxmlc> tag of your ant script, you need to 
 add the following. And take note of the comments below -->
<mxmlc>
 <static-link-runtime-shared-libraries>false</static-link-runtime-shared-libraries>

 <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/textLayout.swc">
  <!-- If you are copying and pasting, do take note that 
   'textLayout_1.0.0.595.swz' isn't in the 'flex/' folder 
   but the 'tlf/' folder under 
   'http://fpdownload.adobe.com/pub/swz/' -->
  <url rsl-url="http://fpdownload.adobe.com/pub/swz/tlf/1.0.0.595/textLayout_1.0.0.595.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
  <url rsl-url="textLayout_1.0.0.595.swz" policy-file-url="" />
 </runtime-shared-library-path>

 <!-- If you are copying and pasting, do take note that 
  'framework.swc' needs to be included before the other 'swz' 
  that belongs to the same 'flex/' folder under 
  'http://fpdownload.adobe.com/pub/swz/', otherwise errors
  will occur when you run the web application. -->
    <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/framework.swc">
        <url rsl-url="http://fpdownload.adobe.com/pub/swz/flex/4.5.0.20967/framework_4.5.0.20967.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
        <url rsl-url="framework_4.0.0.14159.swz" policy-file-url="" />
    </runtime-shared-library-path>

    <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/spark.swc">
  <url rsl-url="http://fpdownload.adobe.com/pub/swz/flex/4.5.0.20967/spark_4.5.0.20967.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
  <url rsl-url="spark_4.0.0.14159.swz" policy-file-url="" />
 </runtime-shared-library-path>

 <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/sparkskins.swc">
  <url rsl-url="http://fpdownload.adobe.com/pub/swz/flex/4.5.0.20967/sparkskins_4.5.0.20967.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
  <url rsl-url="sparkskins_4.0.0.14159.swz" policy-file-url="" />
 </runtime-shared-library-path>

 <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/rpc.swc">
  <url rsl-url="http://fpdownload.adobe.com/pub/swz/flex/4.5.0.20967/rpc_4.5.0.20967.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
  <url rsl-url="rpc_4.0.0.14159.swz" policy-file-url="" />
 </runtime-shared-library-path>

 <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/charts.swc">
  <url rsl-url="http://fpdownload.adobe.com/pub/swz/flex/4.5.0.20967/charts_4.5.0.20967.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
  <url rsl-url="charts_4.5.0.20967.swz" policy-file-url="" />
 </runtime-shared-library-path>

 <!-- If you are copying and pasting, do take note that 'mx.swc'
  isn't in the 'libs/' folder but the 'libs/mx/' folder under 
  '${FLEX_HOME}/frameworks/libs/'  -->
 <runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/mx/mx.swc">
  <url rsl-url="http://fpdownload.adobe.com/pub/swz/flex/4.5.0.20967/mx_4.5.0.20967.swz" 
   policy-file-url="http://fpdownload.adobe.com/pub/swz/crossdomain.xml"/>
  <url rsl-url="mx_4.5.0.20967.swz" policy-file-url="" />
 </runtime-shared-library-path>
</mxmlc>
* Click here for a great guide on creating the ant automation file for your flex 4 project.

Friday, September 13, 2013

Flex: Scrolling to a particular row of data of a Datagrid

I was looking for a much more easier way of scrolling to a particular row of data that belongs to the dataGrid. And I managed to find this.

Source Code for the main application - 'SimpleDataGridScrolling.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" >
 <fx:Declarations>
  <fx:XMLList id="records">
   <record>
    <id>01</id>
    <name>Eric</name>
    <address>3987 Mauris Rd.</address>
   </record>
   <record>
    <id>02</id>
    <name>Bradley</name>
    <address>692-535 Id Street</address>
   </record>
   <record>
    <id>03</id>
    <name>Flynn</name>
    <address>191-491 Ullamcorper Road</address>
   </record>
   <record>
    <id>04</id>
    <name>Akeem</name>
    <address>400-2992 Donec Rd.</address>
   </record>
   <record>
    <id>05</id>
    <name>Shad</name>
    <address>P.O. Box 490, 9377 Lorem, Avenue</address>
   </record>
   <record>
    <id>06</id>
    <name>Brady</name>
    <address>P.O. Box 203, 418 Amet Street</address>
   </record>
   <record>
    <id>07</id>
    <name>Igor</name>
    <address>5584 Ultrices Av.</address>
   </record>
   <record>
    <id>08</id>
    <name>Herman</name>
    <address>Ap #316-3329 Fermentum Avenue</address>
   </record>
   <record>
    <id>09</id>
    <name>Martin</name>
    <address>932-8151 Arcu. Road</address>
   </record>
   <record>
    <id>10</id>
    <name>Micah</name>
    <address>P.O. Box 244, 8472 Lacus. Ave</address>
   </record>
   <record>
    <id>11</id>
    <name>Isaiah</name>
    <address>3798 Risus. Avenue</address>
   </record>
   <record>
    <id>12</id>
    <name>Amos</name>
    <address>Ap #377-2082 Mollis. Road</address>
   </record>
   <record>
    <id>13</id>
    <name>Dominic</name>
    <address>P.O. Box 801, 2289 Malesuada Rd.</address>
   </record>
   <record>
    <id>14</id>
    <name>Ethan</name>
    <address>Ap #509-2519 Non, Avenue</address>
   </record>
   <record>
    <id>15</id>
    <name>Julian</name>
    <address>9373 Ut Avenue</address>
   </record>
   <record>
    <id>16</id>
    <name>Yoshio</name>
    <address>120-7486 Ornare, Av.</address>
   </record>
   <record>
    <id>17</id>
    <name>Harlan</name>
    <address>Ap #821-3336 Velit. Av.</address>
   </record>
   <record>
    <id>18</id>
    <name>Rigel</name>
    <address>Ap #689-7263 Consectetuer Rd.</address>
   </record>
   <record>
    <id>19</id>
    <name>Holmes</name>
    <address>Ap #790-6923 Tincidunt St.</address>
   </record>
   <record>
    <id>20</id>
    <name>Aidan</name>
    <address>948-115 Imperdiet Street</address>
   </record>
   <record>
    <id>21</id>
    <name>Colin</name>
    <address>P.O. Box 454, 9501 Lectus Avenue</address>
   </record>
   <record>
    <id>22</id>
    <name>Palmer</name>
    <address>Ap #402-1566 Varius Road</address>
   </record>
   <record>
    <id>23</id>
    <name>Sylvester</name>
    <address>852-8076 Enim. St.</address>
   </record>
   <record>
    <id>24</id>
    <name>Cole</name>
    <address>876-4551 Ornare Ave</address>
   </record>
   <record>
    <id>25</id>
    <name>Yardley</name>
    <address>P.O. Box 256, 4107 Tempor Rd.</address>
   </record>
   <record>
    <id>26</id>
    <name>Coby</name>
    <address>P.O. Box 467, 7273 Nulla Street</address>
   </record>
   <record>
    <id>27</id>
    <name>Beau</name>
    <address>743-8871 Sem Rd.</address>
   </record>
   <record>
    <id>28</id>
    <name>Kermit</name>
    <address>Ap #183-8772 Magna. St.</address>
   </record>
   <record>
    <id>29</id>
    <name>Josiah</name>
    <address>P.O. Box 645, 453 Ornare, St.</address>
   </record>
   <record>
    <id>30</id>
    <name>Elijah</name>
    <address>537 Turpis Avenue</address>
   </record>
  </fx:XMLList>
  <s:XMLListCollection id="tempXmlCollection" 
        source="{records}"/>
  <s:XMLListCollection id="tempXmlCollection1" 
        source="{records.id}"/>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import mx.events.FlexEvent;
   
   import spark.components.List;
   import spark.events.IndexChangeEvent;
   
   /**
    * Upon changing the selection of the drop down menu,
    * we would need to loop through the data of the
    * datagrid and find the one that matches the 
    * selection from the drop down menu and we would
    * select the row and scroll to that row.
    */
   protected function changeHandler(event:IndexChangeEvent):void
   {
    var tempData:Object = ddId.selectedItem;
    var tempDP:XMLListCollection = 
     gridData.dataProvider as XMLListCollection;
    for(var i:int = 0; i < tempDP.length; i ++)
    {
     if(tempDP.getItemAt(i).id == tempData)
     {
      gridData.selectedIndex = i;
      //This works in Flex 4 Spark Components.
      gridData.grid.verticalScrollPosition = 
       gridData.grid.getCellY(i, 0);
      //This works in Flex 3 Components but not 
      //for Spark Components.
      //gridData.scrollToIndex(i);
      break;
     }
    }
   }
   
  ]]>
 </fx:Script>
 <s:VGroup verticalAlign="middle" 
     horizontalAlign="center" 
     width="100%" 
     height="100%">
  <s:HGroup verticalAlign="middle" 
      horizontalAlign="center" >
   <s:Label text="Select a ID:"/>
   <s:DropDownList id="ddId"
       dataProvider="{tempXmlCollection1}"
       change="changeHandler(event)"/>
  </s:HGroup>
  <s:DataGrid id="gridData" 
     height="200"
      width="500"
     resizableColumns="true"
     dataProvider="{tempXmlCollection}">
   <s:columns>
    <s:ArrayList>
     <s:GridColumn dataField="id" 
          minWidth="50"
          headerText="ID"/>
     <s:GridColumn dataField="name" 
          minWidth="150"
          headerText="Name"/>
     <s:GridColumn dataField="address"  
          minWidth="280" 
          headerText="Address"/>
    </s:ArrayList>
   </s:columns>
  </s:DataGrid>
 </s:VGroup>
</s:Application>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Sunday, September 8, 2013

Kaomoji

Have you used the Japanese Kaomoji(face characters) before? Do you like it? However, if you are going to copy and paste each and every one of them, that's going to be pretty troublesome. But, if you have a Windows PC, you can actually configure it and it is definitely much more faster than the usual Copy and Pasting method. (You can also apply it to a Mac PC, but I don't own one now.)

1) First of all, you will have to download the file over here.

2) You will have to change to the 「Microsoft Japanese IME」 keyboard.

3) Click on the triangular button, follow by the step
of clicking on the 「Show the Language bar」 button.

4) After that, click on the 「Tools」 button, follow by
the step of clicking on the「Dictionary Tool」 button.

5) This will open up the 「Microsoft IME Dictionary Tool」 software.

6) Click on the 「Tool」 button, follow by the step
of clicking on the 「Import from Text File...」 button.

7) Select the file,「kaomoji.txt」, that you have downloaded earlier.

8) Click on the 「Exit」 button, after all the data have been imported successfully.

Congratulations!!!
You have imported all the data successfully.
From today onwards, while typing the Japanese characters 「いい」(Good) using
the 「Microsoft Japanese IME」 keyboard, all sorts of Japanese Kaomoji(face
characters) options will be given to you too. Isn't that great? :D

Friday, September 6, 2013

Beyond Notepad

Since I have been doing a lot of multitasking at my workplace every now and then, therefore opening 10 different notepad applications isn't going to help much. Luckily, there are several options out there that allow us to open multiple text files at 1 go. (I, myself have tried 'TextMate'(Mac), 'e-TextEditor'(Windows), 'Notepad++'(Windows), etc...)

Image taken from 'Notepad++'.
As for now, I think 'Notepad++' itself is strong enough to replace your default
'Notepad' application in Windows. Not only the performance of the application is
very good, it also allows you to open/edit/search through multiple files at one
go. On top of that, it's free and it also supports formatting for some of the
much more common programming languages(HTML, XML, Javascript, etc...).
(However, it would be great if I can also perform a Alt-Tab between the documents
opened using 'Notepad++'. :P)

* Click here to find out more about 'Notepad++'.

Friday, August 30, 2013

Flex: A Simple Slider with a Labeled Button

Time to move back to the easier stuff. In the older versions of Flex, you would need to play around a few properties and create a few components in order to create a similar UI component. However, in the newer versions of Flex, some sophisticated stuff back then have now been simplified. However that doesn't mean that the development time can reduce greatly, it simply means that you don't need to waste too much time figuring out these small little stuff.

The source codes of the main application file - SimpleSliderWithValue.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx">
 <fx:Style source="css/style.css"/>
 <s:HGroup width="100%" 
     height="100%" 
     verticalAlign="middle"
     horizontalAlign="center">
  <s:VSlider minimum="0"
       maximum="100"
       value="50"  
       showDataTip="false" 
       height="200"
       styleName="customSliderV"/>
   <s:HSlider minimum="0"
       maximum="100"
       value="50" 
       showDataTip="false" 
       width="200" 
       styleName="customSliderH"/>
 </s:HGroup>
</s:Application>

Skin Class for the Horizontal Slider - skins/CustomHSliderWithLabel.mxml
<?xml version="1.0" encoding="utf-8"?>

<!--

    ADOBE SYSTEMS INCORPORATED
    Copyright 2008 Adobe Systems Incorporated
    All Rights Reserved.

    NOTICE: Adobe permits you to use, modify, and distribute this file
    in accordance with the terms of the license agreement accompanying it.
-->

<!--- The default skin class for the Spark HSlider component. The thumb and track skins are defined by the
HSliderThumbSkin and HSliderTrackSkin classes, respectively.  

       @see spark.components.HSlider
       @see spark.skins.spark.HSliderThumbSkin
       @see spark.skins.spark.HSliderTrackSkin
                
      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009" minHeight="11" alpha.disabled="0.5">

    <fx:Metadata>
    <![CDATA[ 
        /** 
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("spark.components.HSlider")]
    ]]>
    </fx:Metadata> 
    
    <fx:Script fb:purpose="styling">
        /* Define the skin elements that should not be colorized. 
           For slider, the skin itself is colorized but the individual parts are not. */
        static private const exclusions:Array = ["track", "thumb"];

        /**
         * @private
         */  
        override public function get colorizeExclusions():Array {return exclusions;}
        
        /**
         * @private
         */
        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }
    </fx:Script>
    
    <fx:Script>
        /**
         *  @private
         */  
        override protected function measure() : void
        {
            // Temporarily move the thumb to the left of the Slider so measurement
            // doesn't factor in its x position. This allows resizing the
            // HSlider to less than 100px in width. 
            var thumbPos:Number = thumb.getLayoutBoundsX();
            thumb.setLayoutBoundsPosition(0, thumb.getLayoutBoundsY());
            super.measure();
            thumb.setLayoutBoundsPosition(thumbPos, thumb.getLayoutBoundsY());
        }
    </fx:Script>
    
    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>
    
    <fx:Declarations>
        <!--- The tooltip used in the mx.controls.Slider control. 
               To customize the DataTip's appearance, create a custom HSliderSkin class.-->
        <fx:Component id="dataTip">     
           <s:DataRenderer minHeight="24" minWidth="40" y="-34">  
              <s:Rect top="0" left="0" right="0" bottom="0">
                    <s:fill>
                        <s:SolidColor color="0x000000" alpha=".9"/>
                    </s:fill>
                    <s:filters>
                        <s:DropShadowFilter angle="90" color="0x999999" distance="3"/>
                    </s:filters>
                </s:Rect>
                <s:Label id="labelDisplay" text="{data}"
                         horizontalCenter="0" verticalCenter="1"
                         left="5" right="5" top="5" bottom="5"
                         textAlign="center" verticalAlign="middle"
                         fontWeight="normal" color="white" fontSize="11">
                </s:Label>
            </s:DataRenderer>
       </fx:Component>
    </fx:Declarations>
    
    <!--- 
   The default skin class is HSliderTrackSkin. 
   @copy spark.components.supportClasses.TrackBase#track
   @see spark.skins.spark.HSliderTrackSkin 
 
   We changing the size of the track so that it will
   become very thin.
 -->
    <s:Button id="track" left="0" right="0" top="8" bottom="8" minWidth="33" width="100" 
              tabEnabled="false"
              skinClass="spark.skins.spark.HSliderTrackSkin" />
              
    <!--- 
   The default skin class is HSliderThumbSkin.
         @copy spark.components.supportClasses.TrackBase#thumb 
         @see spark.skins.spark.HSliderThumbSkin
 
   We changing the Button Skin Class to 
   spark.skins.spark.ButtonSkin so that we 
   can bind the label to the thumb.
 -->
    <s:Button id="thumb" top="0" bottom="0" width="45" height="20" 
              tabEnabled="false" styleName="customSliderHThumb" 
     label="{hostComponent.value}" />
</s:SparkSkin>

Skin Class for the Vertical Slider - skins/CustomVSliderWithLabel.mxml
<?xml version="1.0" encoding="utf-8"?>

<!--

    ADOBE SYSTEMS INCORPORATED
    Copyright 2008 Adobe Systems Incorporated
    All Rights Reserved.

    NOTICE: Adobe permits you to use, modify, and distribute this file
    in accordance with the terms of the license agreement accompanying it.
-->

<!--- The default skin class for the Spark VSlider component. The thumb and track skins are defined by the
VSliderThumbSkin and VSliderTrackSkin classes, respectively.  

       @see spark.components.VSlider
       @see spark.skins.spark.VSliderThumbSkin
       @see spark.skins.spark.VSliderTrackSkin
        
      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009" minWidth="11" alpha.disabled="0.5">

    <fx:Metadata>
    <![CDATA[ 
        /** 
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("spark.components.VSlider")]
    ]]>
    </fx:Metadata> 
    
    <fx:Script fb:purpose="styling">
        /* Define the skin elements that should not be colorized. 
           For slider, the skin itself is colorized but the individual parts are not. */
        static private const exclusions:Array = ["track", "thumb"];

        /**
         * @private
         */   
        override public function get colorizeExclusions():Array {return exclusions;}
        
        /**
         * @private
         */
        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }
    </fx:Script>
 
    <fx:Script>
        /**
         *  @private
         */  
        override protected function measure() : void
        {
            // Temporarily move the thumb to the top of the Slider so measurement
            // doesn't factor in its y position. This allows resizing the
            // VSlider to less than 100px in height. 
            var thumbPos:Number = thumb.getLayoutBoundsY();
            thumb.setLayoutBoundsPosition(thumb.getLayoutBoundsX(), 0);
            super.measure();
            thumb.setLayoutBoundsPosition(thumb.getLayoutBoundsX(), thumbPos);
        }
    </fx:Script>
    
    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>
    
    <fx:Declarations>
        <!--- The tooltip used in the mx.controls.Slider control.
              To customize the DataTip's appearance, create a custom VSliderSkin class. -->
        <fx:Component id="dataTip">
            <s:DataRenderer minHeight="24" minWidth="40" x="20"> 
                <s:Rect top="0" left="0" right="0" bottom="0">
                    <s:fill>
                        <s:SolidColor color="0x000000" alpha=".9"/>
                    </s:fill>
                    <s:filters>
                        <s:DropShadowFilter angle="90" color="0x999999" distance="3"/>
                    </s:filters>
                </s:Rect>
                <s:Label id="labelDisplay" text="{data}"
                         horizontalCenter="0" verticalCenter="1"
                         left="5" right="5" top="5" bottom="5"
                         textAlign="center" verticalAlign="middle"
                         fontWeight="normal" color="white" fontSize="11">
                </s:Label>
            </s:DataRenderer>
        </fx:Component>
    </fx:Declarations>
    
    <!--- 
   The default skin class is VSliderTrackSkin.
   @copy spark.components.supportClasses.TrackBase#track 
   @see spark.skins.spark.VSliderTrackSkin 
 
   We changing the size of the track so that it will
   become very thin. 
 -->
    <s:Button id="track" left="17" right="17" top="0" bottom="0" minHeight="33" height="100"
              tabEnabled="false"
              skinClass="spark.skins.spark.VSliderTrackSkin" />
              
    <!--- 
   The default skin class is VSliderThumbSkin. 
   @copy spark.components.supportClasses.TrackBase#thumb
   @see spark.skins.spark.VSliderThumbSkin
   
   We changing the Button Skin Class to 
   spark.skins.spark.ButtonSkin so that we 
   can bind the label to the thumb.
 -->
    <s:Button id="thumb" left="0" right="0" width="36" height="27"
              tabEnabled="false" styleName="customSliderVThumb" 
     label="{hostComponent.value}" />
</s:SparkSkin>

The main CSS file - css/style.css
/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

s|VSlider.customSliderV{
 skinClass: ClassReference("skins.CustomVSliderWithLabel");
}
s|HSlider.customSliderH{
 skinClass: ClassReference("skins.CustomHSliderWithLabel");
}
.customSliderHThumb,.customSliderVThumb{
 skinClass: ClassReference("spark.skins.spark.ButtonSkin");
}
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Thursday, August 22, 2013

In another 2 more weeks...

For all you IT savvy geeks out there, aren't you excited about the upcoming IT Show, which is going to happen at Singapore Expo in another 2 more weeks? Have you listed down all the new gadgets that you wanted to buy or play with? Well, if you have not been doing that, you probably want to start now...

Comex 2013 Details:
  • Date: 5 - 8 September 2013
    Venue: Singapore Expo, Hall 5 & 6
    Time: 12noon - 9pm
* Click here to find out more about 'Comex 2013'.
^ Click here for the Price List and Brochures for 'Comex 2013'.
~ Click here for the 'Facebook' Page of 'Comex 2013'.
# Click here to play the official 'Comex 2013' game and you might be rewarded with a
  21.5" iMAC12, 11" MacBook Air or other awesome tech gadgets!

Wednesday, August 14, 2013

Flex: Generating ASDoc

Rather than searching high and low for a particular function, wouldn't it be much more easier if you can just search through a set of HTML files in case you need to reference some codes that you have writen back then? Therefore, I have created a ant file to auto generated the HTML for the Flex 3 and Flex 4 projects that I have shown on this blog.

Main Ant file - build.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<project basedir="." default="dist.asdocs">
 <!-- project root directory -->
 <property name="APP_ROOT" location="${basedir}/.." />
 <property file="build.properties" />

 <target name="dist.asdocs" description="Create asdocs">
  <cleanAsdocsDir3 />
  <createAsdocs3 />
  <cleanAsdocsDir4 />
  <createAsdocs4 />
 </target>

 <macrodef name="createAsdocs3">
  <sequential>
      <tstamp prefix="dateStamp">
          <format property="date" pattern="MMM/dd/yyyy hh:mm:ss aa" unit="hour" />
      </tstamp>
   <java taskname="asdoc" jar="${FLEX_HOME_3}/lib/asdoc.jar" 
    failonerror="true" fork="true">
    <jvmarg value="-Dapplication.home=${FLEX_HOME_3}"/>
    <!-- Need to assign lots for memory for the ant job -->
    <jvmarg value="-Dsun.io.useCanonCaches=false"/>
    <jvmarg value="-Xms512m"/>
    <jvmarg value="-Xmx1024m"/>
    <jvmarg value="-XX:MaxPermSize=256m"/>

    <arg value="-warnings=false" />
    <!-- Root directory of files -->
    <arg value="-source-path" />
    <arg value="${APP_ROOT}/../AccessingSWFLoaderFunctions/src" />
    <arg value="${APP_ROOT}/../BubbleEventTest/src" />
    <arg value="${APP_ROOT}/../ClippingContent/src" />
    <arg value="${APP_ROOT}/../CustomiseToolTip/src" />
    <arg value="${APP_ROOT}/../DateCheckerApplication/src" />
    <arg value="${APP_ROOT}/../drawingShapes/src" />
    <arg value="${APP_ROOT}/../FlexCustomPreloader/src" />
    <arg value="${APP_ROOT}/../htmlEntity/src" />
    <arg value="${APP_ROOT}/../LinkList/src" />
    <arg value="${APP_ROOT}/../ListDragAndDrop/src" />
    <arg value="${APP_ROOT}/../MeasurePosition/src" />
    <arg value="${APP_ROOT}/../MultipleViewWithAlivePDF/src" />
    <arg value="${APP_ROOT}/../PlayingWithAlivePDF/src" />
    <arg value="${APP_ROOT}/../PlayingWithAlivePDF/fonts" />
    <arg value="${APP_ROOT}/../PlayingWithRegExp/src" />
    <arg value="${APP_ROOT}/../PopUpOverlay/src" />
    <arg value="${APP_ROOT}/../ScreenCaptureView/src" />
    <arg value="${APP_ROOT}/../SimpleChartHorizontalAxis/src" />
    <arg value="${APP_ROOT}/../SimpleSingleton/src" />
    <arg value="${APP_ROOT}/../stopBubbleEventTest/src" />
    <!-- List of files to document -->
    <arg value="-doc-sources" />
    <arg value="${APP_ROOT}/../AccessingSWFLoaderFunctions/src" />
    <arg value="${APP_ROOT}/../BubbleEventTest/src" />
    <arg value="${APP_ROOT}/../ClippingContent/src" />
    <arg value="${APP_ROOT}/../CustomiseToolTip/src" />
    <arg value="${APP_ROOT}/../DateCheckerApplication/src" />
    <arg value="${APP_ROOT}/../drawingShapes/src" />
    <arg value="${APP_ROOT}/../FlexCustomPreloader/src" />
    <arg value="${APP_ROOT}/../htmlEntity/src" />
    <arg value="${APP_ROOT}/../LinkList/src" />
    <arg value="${APP_ROOT}/../ListDragAndDrop/src" />
    <arg value="${APP_ROOT}/../MeasurePosition/src" />
    <arg value="${APP_ROOT}/../MultipleViewWithAlivePDF/src" />
    <arg value="${APP_ROOT}/../PlayingWithAlivePDF/src" />
    <arg value="${APP_ROOT}/../PlayingWithRegExp/src" />
    <arg value="${APP_ROOT}/../PopUpOverlay/src" />
    <arg value="${APP_ROOT}/../ScreenCaptureView/src" />
    <arg value="${APP_ROOT}/../SimpleChartHorizontalAxis/src" />
    <arg value="${APP_ROOT}/../SimpleSingleton/src" />
    <arg value="${APP_ROOT}/../stopBubbleEventTest/src" />
    <!-- Adding a external library, if u are using one -->
    <arg value="-external-library-path" />
    <arg value="${APP_ROOT}/../PlayingWithAlivePDF/libs" />
    <!-- Title of the generated asdoc webpage -->
    <arg value="-window-title" />
    <arg value="Flex 3.5.0 Projects Documentation" />
    <!-- Header shown in the generated asdoc webpage -->
    <arg value="-main-title" />
    <arg value="Flex 3.5.0 Projects Documentation" />
    <!-- Footer shown in the generated asdoc webpage -->
    <arg value="-footer" />
    <arg value="Created on ${dateStamp.date}" />
    <!-- Output folder of the generated asdoc webpage -->
    <arg value="-output" />
    <arg value="${OUTPUT_DOCS_DIR_3}" />
    <!-- If your project requires some TrueType, OpenType fonts -->
    <!--<arg value="-managers" />
    <arg value="flash.fonts.AFEFontManager" />-->
   </java>
  </sequential>
 </macrodef>

 <macrodef name="cleanAsdocsDir3">
  <sequential>
   <echo message="Clean Asdocs Directory" />
   <delete dir="${OUTPUT_DOCS_DIR_3}" failonerror="false" />
   <mkdir dir="${OUTPUT_DOCS_DIR_3}" />
   <echo>Cleaned asdocs output directory</echo>
  </sequential>
 </macrodef>

 <macrodef name="createAsdocs4">
  <sequential>
      <tstamp prefix="dateStamp">
          <format property="date" pattern="MMM/dd/yyyy hh:mm:ss aa" unit="hour" />
      </tstamp>
   <java taskname="asdoc" jar="${FLEX_HOME_4}/lib/asdoc.jar" 
    failonerror="true" fork="true">
    <jvmarg value="-Dapplication.home=${FLEX_HOME_4}"/>
    <!-- Need to assign lots for memory for the ant job -->
    <jvmarg value="-Dsun.io.useCanonCaches=false"/>
    <jvmarg value="-Xms512m"/>
    <jvmarg value="-Xmx1024m"/>
    <jvmarg value="-XX:MaxPermSize=256m"/>

    <arg value="-warnings=false" />
    <!-- Root directory of files -->
    <arg value="-source-path" />
    <arg value="${APP_ROOT}/../AutoresizableTextfield/src" />
    <arg value="${APP_ROOT}/../ImageSourceIssue/src" />
    <arg value="${APP_ROOT}/../NotReallyGlobalTooltip/src" />
    <arg value="${APP_ROOT}/../OpenURLOfHTMLText/src" />
    <arg value="${APP_ROOT}/../Simple2WayBinding/src" />
    <arg value="${APP_ROOT}/../Simple3StateCheckBox/src" />
    <arg value="${APP_ROOT}/../SimpleAreaChartToolTip/src" />
    <arg value="${APP_ROOT}/../SimpleButtonBarSelect/src" />
    <arg value="${APP_ROOT}/../SimpleChartAnimation/src" />
    <arg value="${APP_ROOT}/../SimpleChartDataClick/src" />
    <arg value="${APP_ROOT}/../SimpleChartPositionOfAPoint/src" />
    <arg value="${APP_ROOT}/../SimpleChartVisibility/src" />
    <arg value="${APP_ROOT}/../SimpleCopyingOfObjects/src" />
    <arg value="${APP_ROOT}/../SimpleDataTipBorder/src" />
    <arg value="${APP_ROOT}/../SimpleDoubleClicking/src" />
    <arg value="${APP_ROOT}/../SimpleMouseReleaseOutside/src" />
    <arg value="${APP_ROOT}/../SimpleMouseReleaseOutside/src" />
    <arg value="${APP_ROOT}/../SimplePastingDetection/src" />
    <arg value="${APP_ROOT}/../SimpleStackingColumn/src" />
    <arg value="${APP_ROOT}/../SimpleSudokuGrid/src" />
    <arg value="${APP_ROOT}/../SimpleTabSequence/src" />
    <arg value="${APP_ROOT}/../SimpleTwitterPost/src" />
    <!-- List of files to document -->
    <arg value="-doc-sources" />
    <arg value="${APP_ROOT}/../AutoresizableTextfield/src" />
    <arg value="${APP_ROOT}/../ImageSourceIssue/src" />
    <arg value="${APP_ROOT}/../NotReallyGlobalTooltip/src" />
    <arg value="${APP_ROOT}/../OpenURLOfHTMLText/src" />
    <arg value="${APP_ROOT}/../Simple2WayBinding/src" />
    <arg value="${APP_ROOT}/../Simple3StateCheckBox/src" />
    <arg value="${APP_ROOT}/../SimpleAreaChartToolTip/src" />
    <arg value="${APP_ROOT}/../SimpleButtonBarSelect/src" />
    <arg value="${APP_ROOT}/../SimpleChartAnimation/src" />
    <arg value="${APP_ROOT}/../SimpleChartDataClick/src" />
    <arg value="${APP_ROOT}/../SimpleChartPositionOfAPoint/src" />
    <arg value="${APP_ROOT}/../SimpleChartVisibility/src" />
    <arg value="${APP_ROOT}/../SimpleCopyingOfObjects/src" />
    <arg value="${APP_ROOT}/../SimpleDataTipBorder/src" />
    <arg value="${APP_ROOT}/../SimpleDoubleClicking/src" />
    <arg value="${APP_ROOT}/../SimpleMouseReleaseOutside/src" />
    <arg value="${APP_ROOT}/../SimpleMouseReleaseOutside/src" />
    <arg value="${APP_ROOT}/../SimplePastingDetection/src" />
    <arg value="${APP_ROOT}/../SimpleStackingColumn/src" />
    <arg value="${APP_ROOT}/../SimpleSudokuGrid/src" />
    <arg value="${APP_ROOT}/../SimpleTabSequence/src" />
    <arg value="${APP_ROOT}/../SimpleTwitterPost/src" />
    <!-- Title of the generated asdoc webpage -->
    <arg value="-window-title" />
    <arg value="Flex 4.6.0 Projects Documentation" />
    <!-- Header shown in the generated asdoc webpage -->
    <arg value="-main-title" />
    <arg value="Flex 4.6.0 Projects Documentation" />
    <!-- Footer shown in the generated asdoc webpage -->
    <arg value="-footer" />
    <arg value="Created on ${dateStamp.date}" />
    <!-- Output folder of the generated asdoc webpage -->
    <arg value="-output" />
    <arg value="${OUTPUT_DOCS_DIR_4}" />
    <!-- If your project requires some TrueType, OpenType fonts -->
    <!--<arg value="-managers" />
    <arg value="flash.fonts.AFEFontManager" />-->
   </java>
  </sequential>
 </macrodef>

 <macrodef name="cleanAsdocsDir4">
  <sequential>
   <echo message="Clean Asdocs Directory" />
   <delete dir="${OUTPUT_DOCS_DIR_4}" failonerror="false" />
   <mkdir dir="${OUTPUT_DOCS_DIR_4}" />
   <echo>Cleaned asdocs output directory</echo>
  </sequential>
 </macrodef>
</project>

Main Ant Properties file - build.properties
# change this to your Flex SDK directory path
FLEX_HOME_3=C:/Program Files (x86)/Adobe/Adobe Flash Builder 4.5/sdks/3.6.0
FLEX_HOME_4=C:/Program Files (x86)/Adobe/Adobe Flash Builder 4.5/sdks/4.5.0

# output location for the asdocs for flex 3.6
OUTPUT_DOCS_DIR_3 = ${APP_ROOT}/../asdocs_3.6

# output location for the asdocs for flex 4.5
OUTPUT_DOCS_DIR_4 = ${APP_ROOT}/../asdocs_4.5
* Click here to find out more about ASDoc.
* Click here for the ASDoc that I have generated for my Flex 3 projects.
* Click here for the ASDoc that I have generated for my Flex 4 projects.
* Click here to download the ant build files that I have shown in this post.

Thursday, August 8, 2013

Flex: Creating a Checkbox with 3 states...

There will be situations that requires a list of checkboxes and you are giving the user the option of selecting and unselecting the individual options. However, the normal checkbox might work for the individual selections but it will not work nicely for the header. Therefore...

Main Application Source Code - Simple3StateCheckBox.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      creationComplete="creationCompleteHandler(event)">
 <fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
 </fx:Declarations>
 <fx:Style source="css/style.css"/>
 <fx:Script>
  <![CDATA[
   import events.CustomCheckBoxEvents;
   
   import mx.collections.ArrayCollection;
   import mx.events.FlexEvent;
   
   import object.SingletonObject;
   
   /**
    * We are using a singleton object to store the objects/data.
    */
   private var dataObj:SingletonObject = 
    SingletonObject.getInstance();
   /**
    * Upon creationComplete, we need to add all the Listeners
    * and check the appropriate state that we should be
    * displaying for the header.
    */
   protected function creationCompleteHandler(event:FlexEvent):void
   {
    this.addEventListener(
     CustomCheckBoxEvents.SELECT_ALL_ITEMS,
     checkBoxEvent);
    this.addEventListener(
     CustomCheckBoxEvents.UNSELECT_ALL_ITEMS,
     checkBoxEvent);
    this.addEventListener(
     CustomCheckBoxEvents.SELECT_AN_ITEM,
     checkBoxEvent);
    this.addEventListener(
     CustomCheckBoxEvents.UNSELECT_AN_ITEM,
     checkBoxEvent);
    updateHeaderState();
   }
   
   /**
    * All the events are handled over here.
    */
   private function checkBoxEvent(event:CustomCheckBoxEvents):void
   {
    for each(var item:Object in dataObj.expenses)
    {
     if(event.type == CustomCheckBoxEvents.SELECT_ALL_ITEMS)
     {
      item.selected = true;
     }else if(event.type == CustomCheckBoxEvents.UNSELECT_ALL_ITEMS)
     {
      item.selected = false;
     }else if(item.id == event.data.id)
     {
      if(event.type == 
       CustomCheckBoxEvents.SELECT_AN_ITEM)
      {
       item.selected = true;
      }else if(event.type == 
       CustomCheckBoxEvents.UNSELECT_AN_ITEM)
      {
       item.selected = false;
      }
     }
    }
    dataObj.expenses.refresh();
    updateHeaderState();
   }
   
   /**
    * Function to determine that best state that we are
    * showing for the header.
    */
   private function updateHeaderState():void
   {
    var count:Number = 0;
    var maxCount:Number = 0;
    for each(var item:Object in dataObj.expenses)
    {
     maxCount ++;
     if(item.selected)
     {
      count ++;
     }
    }
    if(count == 0)
    {
     dataObj.selectedState = 0;
    }else if(count == maxCount)
    {
     dataObj.selectedState = 2;
    }else{
     dataObj.selectedState = 1;
    }
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%"
     height="100%" 
     verticalAlign="middle" 
     horizontalAlign="center">
  <s:DataGrid width="50%"
      height="50%" 
     dataProvider="{dataObj.expenses}">
   <s:columns>
    <s:ArrayList>
     <s:GridColumn dataField="selected" 
          width="20"
          headerRenderer="renderers.CustomHeaderCheckBoxRenderer"
          itemRenderer="renderers.CustomCheckBoxRenderer"/>
     <s:GridColumn dataField="amount"/>
    </s:ArrayList>
   </s:columns>
  </s:DataGrid>
 </s:VGroup>
</s:Application>

Event class for the checkbox - events/CustomCheckBoxEvents.as
package events
{
 import flash.events.Event;
 
 public class CustomCheckBoxEvents extends Event
 {
  //All the different event type
  public static const SELECT_ALL_ITEMS:String = 
   "selectAllItems";
  public static const UNSELECT_ALL_ITEMS:String = 
   "unselectAllItems";
  public static const SELECT_AN_ITEM:String = 
   "selectAnItem";
  public static const UNSELECT_AN_ITEM:String = 
   "unselectAnItem";
  
  private var _data:Object = null;

  public function get data():Object
  {
   return _data;
  }

  public function set data(value:Object):void
  {
   _data = value;
  }
  
  public function CustomCheckBoxEvents(type:String, tempData:Object = null, bubbles:Boolean=true, cancelable:Boolean=false)
  {
   super(type, bubbles, cancelable);
   _data = tempData;
  }
  
  override public function clone():Event
  {
   // TODO Auto Generated method stub
   return new CustomCheckBoxEvents(type, data, bubbles, cancelable);
  }
 }
}

Singleton Object class to store the neccessary data - object/SingletonObject.as
package object
{
 import mx.collections.ArrayCollection;

 public class SingletonObject
 {
  private static var _instance:SingletonObject=null;
  
  /**
   * You need the following functions to create a
   * singleton Object. SingletonObject(e:SingletonEnforcer)
   * and getInstance():SingletonObject
   * Rather than using new SingletonObject to create a new
   * object of the class, you need to use
   * SingletonObject.getInstance() to point to the Singleton
   * class.
   */
  public function SingletonObject(e:SingletonEnforcer){
   trace("new singleton object created");
  }

  public static function getInstance():SingletonObject{
   if(_instance==null){
    _instance=new SingletonObject(new SingletonEnforcer);
   }
   return _instance;
  }
  
  /**
   * Here's our data for the DataGrid.
   */
  private var _expenses:ArrayCollection = new ArrayCollection([
   {selected:true, id:0, amount:2000},
   {selected:true, id:1, amount:1000},
   {selected:true, id:2, amount:100},
   {selected:true, id:3, amount:450},
   {selected:true, id:4, amount:100},
   {selected:true, id:5, amount:200}
  ]);
  
  [Bindable]
  public function get expenses():ArrayCollection
  {
   return _expenses;
  }
  
  public function set expenses(value:ArrayCollection):void
  {
   _expenses = value;
  }
  
  private var _selectedState:Number = 0;
  
  [Bindable]
  public function get selectedState():Number
  {
   return _selectedState;
  }

  public function set selectedState(value:Number):void
  {
   _selectedState = value;
  }
 }
}

/**
 * This class is needed in creating a singleton class.
 */
class SingletonEnforcer{
 
}

Renderers class for the header that comes with a custom checkbox with 3 different states - renderers/CustomHeaderCheckBoxRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DefaultGridHeaderRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx" 
        xmlns:component="renderers.component.*" 
        width="100%" click="clickHandler(event)">
 <fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import object.SingletonObject;
   /**
    * We are using a singleton object to store the objects/data.
    */
   private var dataObj:SingletonObject = 
    SingletonObject.getInstance();
   
   protected function clickHandler(event:MouseEvent):void
   {
    event.stopImmediatePropagation();
   }
   
  ]]>
 </fx:Script>
 <s:states>
  <s:State name="normal" />
  <s:State name="hovered" />
  <s:State name="down" />
 </s:states>     
 
 <!-- layer 1: shadow -->
 <!--- @private -->
 <s:Rect id="shadow" left="-1" right="-1" top="-1" bottom="-1" radiusX="2">
  <s:fill>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0x000000" 
         color.down="0xFFFFFF"
         alpha="0.01"
         alpha.down="0" />
    <s:GradientEntry color="0x000000" 
         color.down="0xFFFFFF" 
         alpha="0.07"
         alpha.down="0.5" />
   </s:LinearGradient>
  </s:fill>
 </s:Rect>
 
 <!-- layer 2: fill -->
 <!--- @private -->
 <s:Rect id="fill" left="0" right="0" top="0" bottom="0">
  <s:fill>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0xFFFFFF" 
         color.hovered="0xBBBDBD" 
         color.down="0xAAAAAA" 
         alpha="0.85" />
    <s:GradientEntry color="0xD8D8D8" 
         color.hovered="0x9FA0A1" 
         color.down="0x929496" 
         alpha="0.85" />
   </s:LinearGradient>
  </s:fill>
 </s:Rect>
 
 <!-- layer 3: fill lowlight -->
 <!--- @private -->
 <s:Rect id="lowlight" left="0" right="0" top="0" bottom="0">
  <s:fill>
   <s:LinearGradient rotation="270">
    <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627" />
    <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099" />
    <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0" />
   </s:LinearGradient>
  </s:fill>
 </s:Rect>
 
 <!-- layer 4: fill highlight -->
 <!--- @private -->
 <s:Rect id="highlight" left="0" right="0" top="0" bottom="0">
  <s:fill>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0xFFFFFF"
         ratio="0.0"
         alpha="0.33" 
         alpha.hovered="0.22" 
         alpha.down="0.12"/>
    <s:GradientEntry color="0xFFFFFF"
         ratio="0.48"
         alpha="0.33"
         alpha.hovered="0.22"
         alpha.down="0.12" />
    <s:GradientEntry color="0xFFFFFF"
         ratio="0.48001"
         alpha="0" />
   </s:LinearGradient>
  </s:fill>
 </s:Rect>  
 
 <!-- layer 5: highlight stroke (all states except down) -->
 <!--- @private -->
 <s:Rect id="highlightStroke" left="0" right="0" top="0" bottom="0" excludeFrom="down">
  <s:stroke>
   <s:LinearGradientStroke rotation="90" weight="1">
    <s:GradientEntry color="0xFFFFFF" alpha.hovered="0.22" />
    <s:GradientEntry color="0xD8D8D8" alpha.hovered="0.22" />
   </s:LinearGradientStroke>
  </s:stroke>
 </s:Rect>
 
 <!-- layer 6: highlight stroke (down state only) -->
 <!--- @private -->
 <s:Rect id="hldownstroke1" left="0" right="0" top="0" bottom="0" includeIn="down">
  <s:stroke>
   <s:LinearGradientStroke rotation="90" weight="1">
    <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.0" />
    <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.001" />
    <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.0011" />
    <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.965" />
    <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.9651" />
   </s:LinearGradientStroke>
  </s:stroke>
 </s:Rect>
 <!--- @private -->
 <s:Rect id="hldownstroke2" left="1" right="1" top="1" bottom="1" includeIn="down">
  <s:stroke>
   <s:LinearGradientStroke rotation="90" weight="1">
    <s:GradientEntry color="0x000000" alpha="0.09" ratio="0.0" />
    <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.0001" />
   </s:LinearGradientStroke>
  </s:stroke>
 </s:Rect>
 <s:VGroup verticalAlign="middle" 
     horizontalAlign="center" 
     width="100%"
     height="100%">
  <component:CustomCheckBox styleName="customCheckBox"
          selectedValue="{dataObj.selectedState}"/>
 </s:VGroup>
</s:DefaultGridHeaderRenderer>


Custom checkbox that supports 3 different states - renderers/component/CustomCheckBox.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:CheckBox xmlns:fx="http://ns.adobe.com/mxml/2009" 
   xmlns:s="library://ns.adobe.com/flex/spark" 
   xmlns:mx="library://ns.adobe.com/flex/mx" 
   click="clickHandler(event)" 
   mouseOver="mouseOverHandler(event)" 
   mouseDown="mouseDownHandler(event)" 
   mouseOut="mouseOutHandler(event)">
 <!-- Declaring all the different types of state in this component -->
 <fx:Metadata>
  [SkinState("up")]
  [SkinState("over")]
  [SkinState("down")]
  [SkinState("disabled")]
  [SkinState("upAndSelected")]
  [SkinState("overAndSelected")]
  [SkinState("downAndSelected")]
  [SkinState("disabledAndSelected")]
  [SkinState("upAndSemiSelected")]
  [SkinState("overAndSemiSelected")]
  [SkinState("downAndSemiSelected")]
  [SkinState("disabledAndSemiSelected")]
 </fx:Metadata>
 <fx:Script>
  <![CDATA[
   import events.CustomCheckBoxEvents;
   /**
    * Rather than select and unselected state,
    * we need 3 different states now.
    * 
    * 0 - not selected
    * 1 - semi selected
    * 2 - selected
    * 
    * @default 0
    */
   private var _selectedValue:Number = 0;

   public function get selectedValue():Number
   {
    return _selectedValue;
   }

   public function set selectedValue(value:Number):void
   {
    _selectedValue = value;
    updateState();
   }
   
   /**
    * For storing the component state
    * 
    * 0 - up
    * 1 - over
    * 2 - down
    * 
    * @default 0
    */
   private var currentComponentState:Number = 0;
   
   /**
    * For the skin file to find out the state that it
    * should be displaying.
    */
   override protected function getCurrentSkinState():String
   {
    return this.currentState;
   }
   
   /**
    * Upon clicking on this component, we need to raise
    * a few events.
    */
   override protected function clickHandler(event:MouseEvent):void
   {
    event.stopImmediatePropagation();
    switch (_selectedValue)
    {
     //when unselected
     case 0:
      _selectedValue = 2;
      this.dispatchEvent(
       new CustomCheckBoxEvents(
        CustomCheckBoxEvents.SELECT_ALL_ITEMS));
      break;
     //when semi selected
     case 1:
      _selectedValue = 2;
      this.dispatchEvent(
       new CustomCheckBoxEvents(
        CustomCheckBoxEvents.SELECT_ALL_ITEMS));
      break;
     //when selected
     case 2:
      _selectedValue = 0;
      this.dispatchEvent(
       new CustomCheckBoxEvents(
        CustomCheckBoxEvents.UNSELECT_ALL_ITEMS));
      break;
    }
    updateState();
   }
   
   /**
    * Upon mouse over on this component, we need to update
    * the state.
    */
   protected function mouseOverHandler(event:MouseEvent):void
   {
    event.stopImmediatePropagation();
    currentComponentState = 1;
    updateState();
   }
   
   /**
    * Upon mouse down on this component, we need to update
    * the state.
    */
   protected function mouseDownHandler(event:MouseEvent):void
   {
    event.stopImmediatePropagation();
    currentComponentState = 2;
    updateState();
   }
   
   /**
    * Upon mouse out on this component, we need to update
    * the state.
    */
   protected function mouseOutHandler(event:MouseEvent):void
   {
    event.stopImmediatePropagation();
    currentComponentState = 0;
    updateState();
   }
   
   private function updateState():void
   {
    var tempStr:String = "";
    switch(_selectedValue)
    {
     //when unselected
     case 0:
      tempStr = "";
      break;
     //when semi selected
     case 1:
      tempStr = "AndSemiSelected";
      break;
     //when selected
     case 2:
      tempStr = "AndSelected";
      break;
    }
    if(this.enabled)
    {
     switch(currentComponentState)
     {
      //when mouse out
      case 0:
       tempStr = "up" + tempStr;
       break;
      //when mouse over
      case 1:
       tempStr = "over" + tempStr;
       break;
      //when mouse down
      case 2:
       tempStr = "down" + tempStr;
       break;
     }
    }else{
     tempStr = "disabled" + tempStr;
    }
    this.currentState = tempStr;
   }
  ]]>
 </fx:Script>
 <!-- 
  Upon swaping to these states, we need to call the function
  invalidateSkinState() to update the skin immediately.
 -->
 <s:states>
  <s:State name="up" enterState="invalidateSkinState()"/>
  <s:State name="over" enterState="invalidateSkinState()"/>
  <s:State name="down" enterState="invalidateSkinState()"/>
  <s:State name="disabled" enterState="invalidateSkinState()"/>
  <s:State name="upAndSelected" enterState="invalidateSkinState()"/>
  <s:State name="overAndSelected" enterState="invalidateSkinState()"/>
  <s:State name="downAndSelected" enterState="invalidateSkinState()"/>
  <s:State name="disabledAndSelected" enterState="invalidateSkinState()"/>
  <s:State name="upAndSemiSelected" enterState="invalidateSkinState()"/>
  <s:State name="overAndSemiSelected" enterState="invalidateSkinState()"/>
  <s:State name="downAndSemiSelected" enterState="invalidateSkinState()"/>
  <s:State name="disabledAndSemiSelected" enterState="invalidateSkinState()"/>
 </s:states>
</s:CheckBox>

Skin class for the custom checkbox - skins/CustomCheckBoxSkin.mxml
<?xml version="1.0" encoding="utf-8"?>

<!--

    ADOBE SYSTEMS INCORPORATED
    Copyright 2008 Adobe Systems Incorporated
    All Rights Reserved.

    NOTICE: Adobe permits you to use, modify, and distribute this file
    in accordance with the terms of the license agreement accompanying it.

-->

<!--- The default skin class for the Spark CheckBox component.  

      @see spark.components.CheckBox
        
      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
    alpha.disabledStates="0.5">
 <fx:Metadata>[HostComponent("renderers.component.CustomCheckBox")]</fx:Metadata>

    <fx:Script fb:purpose="styling">
        /* Define the skin elements that should not be colorized. 
           For button, the graphics are colorized but the label is not. */
        static private const exclusions:Array = ["labelDisplay", "check"];

       /** 
        * @private 
        */     
        override public function get colorizeExclusions():Array {return exclusions;}
        
        /* Define the symbol fill items that should be colored by the "symbolColor" style. */
        static private const symbols:Array = ["checkMarkFill", "semiCheckMarkFill"];

       /**
        * @private 
        */
        override public function get symbolItems():Array {return symbols};
        
        /**
         * @private
         */
        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }
    </fx:Script>
    
    <fx:Script>
        <![CDATA[
            /** 
             * @private 
             */     
            private static const focusExclusions:Array = ["labelDisplay"];

            /**
             * @private
             */
            override public function get focusSkinExclusions():Array { return focusExclusions;};
        ]]>
    </fx:Script>
    
 <!--
  All the states of this component.
 -->
    <s:states>
        <s:State name="up" />
        <s:State name="over" stateGroups="overStates" />
        <s:State name="down" stateGroups="downStates" />
        <s:State name="disabled" stateGroups="disabledStates" />
        <s:State name="upAndSelected" stateGroups="selectedStates" />
        <s:State name="overAndSelected" stateGroups="overStates, selectedStates" />
        <s:State name="downAndSelected" stateGroups="downStates, selectedStates" />
        <s:State name="disabledAndSelected" stateGroups="disabledStates, selectedStates" />
  <s:State name="upAndSemiSelected" stateGroups="semiSelectedStates" />
  <s:State name="overAndSemiSelected" stateGroups="overStates, semiSelectedStates" />
  <s:State name="downAndSemiSelected" stateGroups="downStates, semiSelectedStates" />
  <s:State name="disabledAndSemiSelected" stateGroups="disabledStates, semiSelectedStates" />  
    </s:states>
    
    <s:Group verticalCenter="0" width="13" height="13" layoutDirection="ltr">
        <!-- drop shadow -->
        <s:Rect left="-1" top="-1" right="-1" bottom="-1">
            <s:stroke>
                <s:LinearGradientStroke rotation="90" weight="1">
                    <s:GradientEntry color="0x000000" 
                                   color.downStates="0xFFFFFF"
                                   alpha="0.011"
                                   alpha.downStates="0" />
                    <s:GradientEntry color="0x000000" 
                                   color.downStates="0xFFFFFF" 
                                   alpha="0.121"
                                   alpha.downStates="0.57" />
                </s:LinearGradientStroke>
            </s:stroke>
        </s:Rect>
        
        <!-- fill -->
        <s:Rect left="1" top="1" right="1" bottom="1">
            <s:fill>
                <s:LinearGradient rotation="90">
                    <s:GradientEntry color="0xFFFFFF" 
                                   color.overStates="0xBBBDBD" 
                                   color.downStates="0xAAAAAA" 
                                   alpha="0.85" />
                    <s:GradientEntry color="0xD8D8D8" 
                                   color.overStates="0x9FA0A1" 
                                   color.downStates="0x929496" 
                                   alpha="0.85" />
                </s:LinearGradient>
            </s:fill>
        </s:Rect>
        
        <!-- fill highlight -->
        <s:Rect left="1" right="1" top="1" height="5">
            <s:fill>
                <s:SolidColor color="0xFFFFFF" alpha="0.33" alpha.downStates="0" />
            </s:fill>
        </s:Rect>
        
        <!-- layer 6: highlight stroke (all states except down) -->
        <s:Rect left="1" right="1" top="1" bottom="1" excludeFrom="downStates">
            <s:stroke>
                <s:LinearGradientStroke rotation="90" weight="1">
                    <s:GradientEntry color="0xFFFFFF" alpha.overStates="0.33" />
                    <s:GradientEntry color="0xFFFFFF" alpha="0.12" alpha.overStates="0.0396" />
                </s:LinearGradientStroke>
            </s:stroke>
        </s:Rect>
        
        <!-- layer 6: highlight stroke (down state only) -->
        <s:Rect left="1" top="1" bottom="1" width="1" includeIn="downStates">
            <s:fill>
                <s:SolidColor color="0x000000" alpha="0.07" />
            </s:fill>
        </s:Rect>
        <s:Rect right="1" top="1" bottom="1" width="1" includeIn="downStates">
            <s:fill>
                <s:SolidColor color="0x000000" alpha="0.07" />
            </s:fill>
        </s:Rect>
        <s:Rect left="1" top="1" right="1" height="1" includeIn="downStates">
            <s:fill>
                <s:SolidColor color="0x000000" alpha="0.25" />
            </s:fill>
        </s:Rect>
        <s:Rect left="1" top="2" right="1" height="1" includeIn="downStates">
            <s:fill>
                <s:SolidColor color="0x000000" alpha="0.09" />
            </s:fill>
        </s:Rect>
        
        <!-- border - put on top of the fill so it doesn't disappear when scale is less than 1 -->
        <s:Rect left="0" top="0" right="0" bottom="0">
            <s:stroke>
                <s:LinearGradientStroke rotation="90" weight="1">
                    <s:GradientEntry color="0x000000" 
                                   alpha="0.5625"
                                   alpha.downStates="0.6375" />
                    <s:GradientEntry color="0x000000" 
                                   alpha="0.75"
                                   alpha.downStates="0.85" />
                </s:LinearGradientStroke>
            </s:stroke>
        </s:Rect>
    
        <!-- checkmark -->
        <!--- The checkmark in the box for this skin. To create a custom check mark, create a custom skin class. -->
        <s:Path left="2" top="0" includeIn="selectedStates" id="check" itemCreationPolicy="immediate"
                data="M 9.2 0.1 L 4.05 6.55 L 3.15 5.0 L 0.05 5.0 L 4.6 9.7 L 12.05 0.1 L 9.2 0.1">        
            <s:fill>
                <!--- 
                    @private 
                    The solid color fill for the CheckBox's checkmark. The default alpha is .9, and the default fill color is 0x000000. 
                -->
                <s:SolidColor id="checkMarkFill" color="0" alpha="0.8" />
            </s:fill>
        </s:Path>
  
  <!-- semi selected checkmark -->
  <!--- The checkmark in the box for this skin. To create a custom check mark, create a custom skin class. -->
  <s:Path left="2" top="2" includeIn="semiSelectedStates" id="semiCheck" itemCreationPolicy="immediate"
    data="M 1 1 L 10 1 L 10 10 L 1 10 L 1 1">        
   <s:fill>
    <!--- 
    @private 
    The solid color fill for the CheckBox's checkmark. The default alpha is .9, and the default fill color is 0x000000. 
    -->
    <s:SolidColor id="semiCheckMarkFill" color="0" alpha="0.8" />
   </s:fill>
  </s:Path>
    </s:Group>

    <!-- Label -->
    <!--- @copy spark.components.supportClasses.ButtonBase#labelDisplay -->
    <s:Label id="labelDisplay"
             textAlign="start"
             verticalAlign="middle"
             maxDisplayedLines="1"
             left="18" right="0" top="3" bottom="3" 
    verticalCenter="2" visible="false"/>
</s:SparkSkin>

Renderers class for the individual items that comes with a normal checkbox - CustomCheckBoxRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:GridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
     xmlns:s="library://ns.adobe.com/flex/spark" 
     xmlns:mx="library://ns.adobe.com/flex/mx" 
     implements="spark.components.gridClasses.IGridItemRenderer"
     width="100%">
 
 <fx:Script>
  <![CDATA[
   import events.CustomCheckBoxEvents;
   /** 
    * Upon setting the data into the renderer, we need to
    * change the state of the checkbox.
    */
   override public function set data(value:Object):void
   {
    super.data = value;
    chk.selected = data[this.column.dataField]
   } 
   
   /**
    * Upon cliking on the check box, we need to dispatch
    * some events.
    */   
   protected function chk_clickHandler(event:MouseEvent):void
   {
    event.stopImmediatePropagation();
    if(chk.selected)
    {
     this.dispatchEvent(
      new CustomCheckBoxEvents(
       CustomCheckBoxEvents.SELECT_AN_ITEM,
      this.data));
    }else{
     
     this.dispatchEvent(
      new CustomCheckBoxEvents(
       CustomCheckBoxEvents.UNSELECT_AN_ITEM,
      this.data));
    }
   }
   
  ]]>
 </fx:Script>
 <s:VGroup verticalAlign="middle" 
     horizontalAlign="center"
     width="100%" 
     height="100%">
  <s:CheckBox id="chk"
     click="chk_clickHandler(event)"/>
 </s:VGroup>
</s:GridItemRenderer>

CSS file for the application - ../css/style.css
/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

.customCheckBox{
 skinClass: ClassReference("skins.CustomCheckBoxSkin");
}
* Click here for the demo shown in this post.
  (Try changing some of the checkbox to reflect the change of state in the topmost
  checkbox.)
^ Click here for the source files for the demo.

Friday, August 2, 2013

Flex: Creating the Sudoku Base Grid

I have been trying out all sorts of method in creating a Sudoku Grid and I finally managed to do it. The solution was far more easier than I thought ...

Let's take a look at the source code - SimpleSudokuGrid.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      creationComplete="creationCompleteEvent(event)">
 <fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import mx.collections.ArrayCollection;
   import mx.events.FlexEvent;
   
   import spark.components.Button;
   import spark.events.IndexChangeEvent;
   
   /**
    * Holds the data to form a Grid
    */
   private var baseGrid:ArrayCollection;
   
   /**
    * Boolean to determine if there's a need to recreate the grid
    */
   private var needToReset:Boolean = true;
   
   /**
    * Number to count the number of failure in the current
    * grid data forming.
    */
   private var tries:Number = 0;
   
   /**
    * Maximum number of failure before recreate.
    */
   private static const MAX_TRIES:Number = 9;
   
   /**
    * A set of data that will be used to populate the ButtonBar
    */
   [Bindable]
   private var dummyData:ArrayCollection = new ArrayCollection(
    [{label: "1", value:1},
     {label: "2", value:2},
     {label: "3", value:3},
     {label: "4", value:4},
     {label: "5", value:5},
     {label: "6", value:6},
     {label: "7", value:7},
     {label: "8", value:8},
     {label: "9", value:9}]);
   
   /**
    * Upon Create Complete, we will create a Sudoku(9x9) Grid
    */
   protected function creationCompleteEvent(e:FlexEvent):void
   {
    //Will keep recreating the grid if 'needToReset' is
    //true
    while(needToReset)
    {
     //Set 'needToReset' to false
     needToReset = false;
     createGrid();
     createNumbers();
    }
    
    createGridUI();
    btnBar.dispatchEvent(
     new IndexChangeEvent(IndexChangeEvent.CHANGE));
   }
   
   /**
    * Create new (9*9) DataCollection and fill it up with 0.
    */
   private function createGrid():void
   {
    baseGrid = new ArrayCollection();
    
    var tempCol:ArrayCollection;
    for(var i:int = 0; i < 9; i ++)
    {
     tempCol = new ArrayCollection();
     for(var j:int = 0; j < 9; j++)
     {
      tempCol.addItem(0);
     }
     baseGrid.addItem(tempCol);
    }
   }
   
   /**
    * Start populating the numbers from 1 - 9.
    * If 'needToReset' is true, move out of this function.
    */ 
   private function createNumbers():void
   {
    for(var i:int = 1; i < 10; i ++)
    {
     insertNumber(i);
     
     if(needToReset)
     {
      break; 
     }
    }
    
    if(needToReset)
    {
     return; 
    }
    
    printNumbers();
   }
   
   /**
    * Find the empty boxes that you can slot the value
    * @param value a value that you are going to slot in
    */   
   private function insertNumber(value:Number):void
   {
    //Used to store the rows avaliable in a column
    var numbersFree:Array;
    //Is the 1st segment taken?
    var fromSegment1:Boolean = false;
    //Rows that we will need to remove if 1st segment
    //is taken
    var seg1Array:Array = [0,1,2];
    //Is the 2nd segment taken?
    var fromSegment2:Boolean = false;
    //Rows that we will need to remove if 2nd segment
    //is taken
    var seg2Array:Array = [3,4,5];
    //Is the 3rd segment taken?
    var fromSegment3:Boolean = false;
    //Rows that we will need to remove if 3rd segment
    //is taken
    var seg3Array:Array = [6,7,8];
    //Stores the current selected row of a column
    var rand:Number;
    //Stores all the boxes that has the value 
    var tempArray:Array = new Array();
    for(var i:int = 0; i < 9; i ++)
    {
     //In sudoku, it's divided into 9 (3*3) boxes.
     //Each each of this box, the same number can 
     //appear once.
     //Therefore every 3 column, we need to reset
     //these 3 values.
     if(i % 3 == 0)
     {
      fromSegment1 = false;
      fromSegment2 = false;
      fromSegment3 = false;
     }
     //Find the empty slots of the column first
     numbersFree = findEmptySlot(i);
     //Remove the rows based on the previous selections
     if(fromSegment1)
     {
      numbersFree = removeSlot(numbersFree, seg1Array);
     }
     if(fromSegment2)
     {
      numbersFree = removeSlot(numbersFree, seg2Array);
     }
     if(fromSegment3)
     {
      numbersFree = removeSlot(numbersFree, seg3Array);
     }
     //Remove the rows that have been selected already.
     if(tempArray.length > 0)
     {
      numbersFree = removeSlot(numbersFree, tempArray);
     }
     
     //If there are rows left
     if(numbersFree.length > 0)
     {
      //Select one of them
      rand = Math.floor(Math.random() 
       * numbersFree.length);
      rand = numbersFree[rand];
      //Check which Segment the row number is in
      if(rand < 3)
      {
       fromSegment1 = true;
      }else if(rand < 6)
      {
       fromSegment2 = true;
      }else{
       fromSegment3 = true;
      }
      //Add it to the list of boxes with the 
      //same value
      tempArray.push(rand);
      
      //Update the value in the main DataCollection
      insertSlot(i, rand, value);
     }else{
      //else if '0' row is avaliable
      //increase the number of failures/tries
      tries ++;
      //Revert back all the slots
      revertSlots(tempArray);
      tempArray = new Array();
      i = -1;
      //Check if it has reach the Maximum tries/failures
      if(tries == MAX_TRIES)
      {
       //Need to recreate the grid again.
       tries = 0;
       needToReset = true;
       return;
      }
     }
    }
   }
   
   /**
    * Find all the empty rows of a selected Column
    * @param col the selected column index
    * @return Array of rows that currently has a value of '0'
    */
   private function findEmptySlot(col:Number):Array
   {
    var tempArray:Array = new Array();
    var tempArrayCol:ArrayCollection;
    tempArrayCol = ArrayCollection(baseGrid.getItemAt(col));
    for(var i:int = 0; i < tempArrayCol.length; i ++)
    {
     if(Number(tempArrayCol.getItemAt(i)) == 0)
     {
      tempArray.push(i);
     }
    }
    return tempArray;
   }
   
   /**
    * Compare 2 Arrays.
    * @param tempArray1 Array of values
    * @param tempArray2 Array of values
    * @return the Array of values tempArray1 that are different from 
    * tempArray2
    */ 
   private function removeSlot(tempArray1:Array, tempArray2:Array):Array
   {
    var tempArray:Array = new Array();
    for(var i:int = 0; i < tempArray1.length; i ++)
    {
     tempArray.push(tempArray1[i]);
    }
    for(i = 0; i < tempArray.length; i ++)
    {
     for(var j:int = 0; j < tempArray2.length; j ++)
     {
      if(tempArray[i] == tempArray2[j])
      {
       tempArray.splice(i, 1);
       i --;
       break;
      }
     }
    }
    return tempArray;
   }
   
   /**
    * Replace a particular slot with a new value.
    * @param col selected column
    * @param row selected row
    * @param value the new value
    */
   private function insertSlot(col:Number, row:Number, value:Number):void
   {
    var tempArrayCol:ArrayCollection;
    tempArrayCol = ArrayCollection(baseGrid.getItemAt(col));
    tempArrayCol.setItemAt(value, row);
   }
   
   /**
    * This function will change the newly numbers of the same group 
    * back to 0. For example, halfway through the number 7, a problem 
    * has occur, therefore need to replace all the number 7 from the 
    * first box again. Hence, need to reset all the existing number 
    * 7 box to '0' first.
    * @param tempArray1 Boxes that requires the values to be reset to '0'
    */
   private function revertSlots(tempArray1:Array):void
   {
    var tempArrayCol:ArrayCollection;
    for(var i:int = 0; i < tempArray1.length; i ++)
    {
     tempArrayCol = ArrayCollection(baseGrid.getItemAt(i));
     tempArrayCol.setItemAt(0,tempArray1[i])
    }
   }
   
   /**
    * This is merely for debugging purposes. You can use
    * this function to track the valus in the (9x9) DataCollection.
    */
   private function printNumbers():void
   {
    var tempArrayCol:ArrayCollection;
    var tempArray:Array = new Array();
    for(var i:int = 0; i < 9; i ++)
    {
     tempArray.push("");     
    }
    for(var col:int = 0; col < baseGrid.length; col ++)
    {
     tempArrayCol = 
      ArrayCollection(baseGrid.getItemAt(col));
     for(var row:int = 0; row < tempArrayCol.length; row ++)
     {
      tempArray[row] += 
       Number(tempArrayCol.getItemAt(row));
     }
    }
    for(i = 0; i < tempArray.length; i ++)
    {
     trace(tempArray[i]);
    }
   }
   
   /**
    * Create all the buttons base on the values in the ArrayCollection
    */ 
   private function createGridUI():void
   {
    var btn:Button;
    var tempArrayCol:ArrayCollection;
    
    for(var row:int = 0; row < 9; row ++)
    {
     for(var col:int = 0; col < baseGrid.length; col ++)
     {
      tempArrayCol = 
       ArrayCollection(baseGrid.getItemAt(col));
      btn = new Button();
      btn.width = 30;
      btn.height = 30;
      btn.label = 
       Number(tempArrayCol.getItemAt(row)).toString();
      btn.name = "btn_" + row + "_" + col; 
      grpGrid.addElement(btn);
     }
    }
   }
   
   /**
    * Upon clicking on one of the buttons of the ButtonBar, we will
    * show buttons with the same value with a alpha value of 1 and
    * those that are different will have a alpha value of 0.3.
    */
   protected function changeEvent(event:IndexChangeEvent):void
   {
    var tempBar:ButtonBar = ButtonBar(event.target);
    var tempObj:* = tempBar.selectedItem;
    var selectedValue:Number = -1;
    if(tempObj)
    {
     selectedValue = tempObj.value;
    }
    
    var btn:Button;
    for (var i:int = 0; i < grpGrid.numElements; i ++)
    {
     btn = Button(grpGrid.getElementAt(i));
     if(Number(btn.label) == selectedValue)
     {
      btn.alpha = 1;
     }else{
      btn.alpha = 0.3;
     }
    }
   }
  ]]>
 </fx:Script>
 <s:VGroup verticalCenter="0" 
     horizontalCenter="0" 
     horizontalAlign="center">
  <s:Group id="grpGrid" >
   <s:layout>
    <s:TileLayout requestedRowCount="9" 
         requestedColumnCount="9"
         horizontalGap="3" 
         verticalGap="3"/>
   </s:layout>
  </s:Group>
  <s:Label text="Click on the following to show the buttons with the same value."/>
  <s:ButtonBar id="btnBar" 
      dataProvider="{dummyData}"  
      selectedIndex="-1"
      labelField="label"
      change="changeEvent(event)"/>
 </s:VGroup>
</s:Application>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Friday, July 26, 2013

Tour de Flex

I was trying to look for the Style Explorer for Flex 4 but it seems that the closest alternative right now would be...

The contents shown in the above are taken from 'Adobe' website.

You can click on the button shown in the above to download and
install the desktop application 'Tour de Flex' too.

* Click here for the official website for 'Tour de Flex'.
^ Click here for the web version of 'Tour de Flex'.

Thursday, July 18, 2013

One of Windows OS missing component - Rename Multiple Filenames

Sometimes renaming a list of files can be pretty annoying and it gets more and more frustrating when there are a lot of files. And this can be pretty disturbing to the type of people that prefer to rename their filename with something meaningful. Therefore you can consider the following softwares.

  • A.F.5
    • I'm using this in the office. Basically, the interface of this software is pretty simple and although it doesn't come with a lot of features, but it is already more than enough.
  • Bulk Rename Utility
    • As I was browsing through blogs, discussion boards, etc, this seems to be one of the hottest alternative. It can even support filename replacement using Regular Expressions. However, the interface looks kinda squeezy to me. =.=

Friday, July 12, 2013

Creating a custom Service

Well, basically if you are using a Windows server or you are doing a lot of development work, you might be running a lot of services locally. (Ex: Apache, WAMP, etc...) Imagine how much time you can save by creating a Service that will start these programs automatically.

Steps for creating a new Windows Service
Before moving on any further, you will need to grab hold of these 2 files first.
They are instsrv.exe and srvany.exe.

Click here to download the files now.
Click here to download the original package from Microsoft.
(If you are using the package from Microsoft,
you will need to extract the files from the package.)

Step 1 - Open up the Windows Start menu, enter cmd into the
Search programs and files field, Right-Click on the program
cmd.exe and select Run as Administrator.

Step 2 - Enter the following into the Command Prompt window.

"{yourPath}\instsrv.exe" {name} "{yourPath}\srvany.exe"
Replace {yourPath} with the directory that has the files instsrv.exe and srvany.exe.
Replace {name} with the Name of the new Service that you are going to create.

And there you go, you have successfully created a new Empty Service.

Step 3 - Open up the Windows Start menu, enter regedit into the
Search programs and files field and run the program regedit.exe.

Step 4 - Look for the new Service under the following directory.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{name}
Replace {name} with the Name of the new Service that you have created.

Step 5 - After selecting the new Service that you have created, Right-Click and
create a new Key. Rename the new Key as Parameters

Step 6 - Under Parameters add a few new String Value.

Step 7 - Entering some values
NameTypeData
ApplicationREG_SZ{the full path of your application}
Ex: G:\service\run_notepad.bat
AppDirectoryREG_SZ{the path to your application}
Ex: G:\service\

Step 8 - Open up the Windows Start menu, enter services into the
Search programs and files field and run the program Services.

Step 9 - Locate and open up the new Service that you have created.

Step 10 - You can set the Startup Type to either Automatic or
Automatic (Delayed start). (Automatic will start the Service
when Windows boots up. Automatic (Delayed start) will start 2 minutes
after the last Automatic Service has been executed.)

On top of that, some programs will only run smoothly with a particular user
account. That's where the Log On tab comes in. You can specify the
User Account Credentials that you are going to use when you run this Service.

Step Remove - To remove a Service,
type the following command in Command Prompt window.

"{yourPath}\instsrv.exe" {name} REMOVE
Replace {yourPath} with the directory that has the file instsrv.exe.
Replace {name} with the Name of the Service that you are going to delete.

And there you go, you have successfully removed a Service.