Author Archive: dloverin

Single Click Cell Editing and More

The Spark DataGrid starts cell editing when a selected cell is clicked. But what if you want your DataGrid to start editing a cell regardless of whether the cell is selected or not? It is pretty easy to do this by adding a few listeners to the DataGrid. In a future release of the Spark DataGrid we will most likely add a property that will allow you to choose which method is used to start an editor session.

Download the project to see how it’s done.

The project also shows show to use the DateField and the ColorPicker as cell editors.

Run the application (required Flash Player 10.2 or greater)

Using Validators with Spark Cell Editors

At some point you will probably want to add a validator to a cell editor. This post shows how to use a validator with Spark cell editors. The Spark DataGrid contains two built-in cell editors, DefaultGridItemEditor and ComboBoxGridItemEditor, both of which extend GridItemEditor. Neither of these editors has a validator so you will want to create your own custom item editor to add validation. As an example I created an editor, NumberGridItemEditor, that uses the Spark number validator to ensure that the entered data is between 0 and 1000, inclusive.

To add a validator to a custom item editor is pretty simple. Just declare the validator and hook it up the input component.


<fx:Declarations>

<s:NumberValidator id="numberValidator" source="{textInput}" property="text"

triggerEvent="keyUp"/>

</fx:Declarations>

Since NumberGridItemEditor subclasses GridItemEditor it picks up some built-in support for validators. When the editor’s data is being saved, the GridItemEditor first checks if the data is valid by calling the validate() method. If the data is not valid then the editor won’t try to save it. If the Enter key is used to end the editor session then the editor will remain displayed so the input may be corrected. But if the user clicks away from the editor then the editor session will be cancelled if the data is not valid and therefore cannot be saved. If the default behavior doesn’t work for you then it can be modified by overriding the validate() and save() methods of GridItemEditor.

Download the project

 

 

Creating Cell Editors for Multiple Data Fields

DataGrid item renderers allow you to display multiple fields in one cell. For example, a name could be displayed in one cell but it may be a combination of two fields, first name and last name. How do you create a matching item editor? The key method to override when writing to multiple data fields is GridItemEditor.save().  Normally the save() method updates the data field specified by the GridColumn’s dataField property. By overriding the save() method you can update as many fields as you want. To see the full source of this editor, Download the project files and take a look at FirstLastNamePopUpGridItemEditor.mxml.

One problem you’ll run into when you create an editor for multiple fields is that the editor no longer fits neatly inside the cell. I think the best way to solve this problem is to put the item editor in a pop up so it is not clipped by the DataGrid. In the FirstLastNamePopUpGridItemEditor component this is done declaratively by using the Spark PopUpAnchor component.

The pop up in the item editor uses the Spark BorderContainer component. This ends up causing the child components in the pop up to get their own FocusManager which implies the focus loop will stay within the pop up. But what I really want is to be able to tab out of the item editor and go to the next item editor, the same way the tab key moves out of any other item editor. This can be done by re-dispatching selective events from the pop up to the item editor.

Another example of using pop ups in an item editor is the TextWithOkCancelGridItemEditor component. This component places OK and Cancel buttons on the right side of the Spark TextArea component. The TextArea component is sized to the cell so the OK and Cancel buttons need be in a pop up to keep them from being clipped by the DataGrid or the DataGrid’s scrollbar. Adding OK and Cancel buttons can be useful if the TextArea component uses the Enter key to insert a newline in the text instead of ending the editing session. That behavior may confuse some users so providing the OK button will give them clear way to end the editing session.

Run the application (requires Flash Player 10.2 or greater)

MultiControlPopUpEditor Project Files

The postings on this site are my own and don’t necessarily represent Adobe’s positions, views, strategies or opinions.

Using Spark Grid Item Editors

This post shows a simple example of using the default item editors in the Spark DataGrid. The example application shows how to use the DefaultGridItemEditor and ComboBoxGridItemEditor.

DefaultGridItemEditor is an editor for text. If you don’t specify an editor for a grid column, this is the one you will get.

The ComboBoxGridItemEditor was designed to provide a two click editing experience. When a cell is clicked to start an editor session, the combo box will be displayed with its drop-down list open. This allows a single click to choose the item in the down-down list that you want. After the down-down is clicked the combo box choice is saved and the editing session is closed. The result is only two clicks to edit a cell and choose a value.

Download the project

New compiler option to support monkey patching RSLs

Setting up the monkey patch RSL took a bit of work. First
you needed to create an externs file from a link report. Then you needed to
figure out the inheritance dependencies and remove them from the externs file.
Wouldn’t it be nice to have the compiler to this for you? The compiler knows
what the inheritance dependencies are, right?

It turns out that writing the prototype for the new compiler option wasn’t all that hard. I called the new compiler option “include-inheritance-dependencies-only”.
It only works with compc and the -include-classes option. Normally compc
will include all the dependences of classes linked into a swc. But when the new
option is used only the inheritance dependences will be linked in. So the
command to build the RSL swc for the mx.collections.ListCollectionView monkey
patch becomes:

compc
-include-classes mx.collections.ListCollectionView -include-inheritance-dependencies-only
-source-path . -output lcv2 -directory

The new option is just a prototype. It may never see the
light of day. If you think this option would be useful please leave a comment
to let me know.

 

Monkey Patching ListCollectionView

The last in this monkey patch series is mx.collections.ListCollectionView.
I was going to skip the write up on monkey patching this class but I had already
said I was going to do it and there was one interesting twist along the way. I
chose to demonstrate this class because there was a real world case of it
being monkey patched. I haven’t actually patched the class myself I’m just going
to demonstrate how to make a patch work when using RSLs.

This monkey patch is going to follow the same pattern as the
previous two. First I’m going to create the RSL and then add the RSL into the
configuration.

Create an RSL

As usual I compile the monkey patched files into a library
and create a link report. The link report becomes the basis of my externs file.
The size of the monkey patch RSL without externalizing any classes is 38,260
bytes.

Next I start removing classes from the externs file. First I
remove ListCollectionView itself. ListCollectionView extends flash.utils.Proxy.
Proxy is already externalized in playerglobal.swc so nothing to do. Next remove
the three classes ListCollectionView implements, ICollectionView, IList, and
IMXMLObject. ICollectionView and IList both implement IEventDispatcher.
IEventDispatcher is also in playerglobals.swc so nothing to do. With all these
classes removed from the externs file, recompile the RSL.

Add the RSL to the configuration

Since we are monkey patching the framework RSL, add the
monkey patch RSL to load before the framework RSL.

At this point I thought I was done and ran the application.
But I got a VerifyError on mx.collections.CursorBookmark. I couldn’t see how
ListCollectionView extended or implemented CursorBookmark so I opened the catalog
in framework.swc to double check. Sure enough CursorBookmark was an inheritance
dependency of ListCollectionView. Inheritance dependencies are in the catalog
as type=”i”.

 

        <dep
id=”mx.collections:CursorBookmark” type=”i” />

I didn’t understand why so I searched ListCollectionView for
CursorBookmark. I found a private class that extends CursorBookmark:

class ListCollectionViewBookmark extends
CursorBookmark

and another private class that implements IViewCursor:

class ListCollectionViewCursor extends EventDispatcher
implements IViewCursor

With the mystery solved I removed CursorBookmark and
IViewCursor from the externs file and recompiled. This time the application loaded
without error although the application does not actually use ListCollectionView.
The final size of the monkey patch RSL was 8,047 bytes.

Download Source

Monkey Patching the Spark Button

This time around I’m going to monkey patch the Spark Button.
Like last time I’ll patch the label property setter. The label property setter
for the Spark Button is in spark.components.supportClasses.ButtonBase, not in
spark.components.Button as you might expect. I’m going to create an RSL
containing the ButtonBase class and its inheritance dependencies and then slide
that RSL into the RSL configuration.

Create an RSL

The ButtonBase class is compiled into spark.swc. I want to externalize
as many classes as possible in my custom RSL so I’ll externalize all the
libraries that spark.swc externalizes. That means I can externalize osmf.swc,
textLayout.swc, and framework.swc. My application is not using any classes from
osmf.swc so I won’t externalize that library and I won’t load that RSL either.

How do you know what libraries spark.swc is dependent on?
One way is to look at the build file for spark.swc and see what libraries are
on the external-library-path. Another way is to use the swcdepends tool. This
tool is helpful in looking at dependencies between swcs and finding out what
classes are causing those dependencies. I usually run it from the command line
like this:

>swcdepends
-locale=

The locale is set empty so that resource bundles are removed
from the output. The swcdepends tool behaves like mxmlc in that it
uses flex-config.xml and accepts the same configuration options. The output is
a list of all the swcs found in dependency order. The swc with the least
dependencies are at the top and the most dependencies are at the bottom. For
each swc in the list, there is an indented list to show the actually swcs it is
dependent on. Here an excerpt from the output showing the entry for spark.swc:

C:\opensource\sdk\branches\4.0.0\frameworks\libs\spark.swc:

      C:\opensource\sdk\branches\4.0.0\frameworks\libs\player\10.0\playerglobal.swc

      C:\opensource\sdk\branches\4.0.0\frameworks\libs\osmf.swc

      C:\opensource\sdk\branches\4.0.0\frameworks\libs\textLayout.swc

      C:\opensource\sdk\branches\4.0.0\frameworks\libs\framework.swc

This shows that spark.swc is dependent on playerglobal.swc,
osmf.swc, textLayout.swc, and framework.swc. If you want to show what classes
are causing spark.swc to be dependent on the other libraries add the
-show-external-classes to the command line.

Creating the custom library for ButtonBase was pretty easy.
First I compiled with a list report and no externs file. The size of the RSL
was 10,801 bytes. This was already much smaller than the mx Button RSL and I
hadn’t even created an externs file yet. I copied the list report to the
externs file and added a “load-externs=externs.xml” to the compc ant task. Next
I edited the externs.xml file with the intent of removing ButtonBase and its
inheritance dependencies. I removed ButtonBase and the SkinnableComponent class
that ButtonBase extends. SkinnableComponent extends UIComponent but UIComponent
is in framework.swc and was already externalized. ButtonBase implements
IFocusManagerComponent which is also in framework.swc and does not need to be
excluded. So were done after removing just two classes.

Compile again and check the link report. The link report
shows just ButtonBase, SkinnableComponent and the root class so we are done.
The custom RSL’s final size is 6,198 bytes.

Add your RSL to the configuration

The custom RSL entry needs to be loaded after the framework
RSL and before the spark RSL. The framework RSL will provide UIComponent and
other classes we excluded. The custom RSL must be loaded before the spark RSL
so the monkey patched class will override the spark class.

Running the application shows that the monkey patched
version of ButtonBase is being used.

Download Source

 

How to Monkey Patch when using Flex RSLs

Monkey patchers run into problems when using Flex RSLs. In this post I’ll explain why monkey patching does not work when using RSLs and provide details of how to make it work. I’ll monkey patch the mx.controls.Button class in this post and ListCollectionView and Spark Button in later posts.

Why doesn’t monkey patching work when using RSLs? To answer this question it is important to understand two things:

  1. The Flash Player has a first-in-wins rule when loading classes.
  2. Flex applications contain two frames. The first frame contains few classes and loads the RSLs. The second frame contains the rest of the application’s classes.

Say you’ve monkey patched mx.controls.Button, which will end up in frame 2 of your application. In frame 1 of the application, the framework RSL will be loaded which contains the mx.controls.Button class. When frame 2 of the application loads the monkey patched version of mx.controls.Button is ignored because of the Flash Player first-in-wins rule.

When you monkey patch a class that is in frame 1, then you are done, you don’t need an RSL.

The basic steps I’ll use to monkey patch are:

  1. Create an RSL with just the monkey-patched file and its inheritance dependencies.
  2. Add your RSL to the configuration to get it loaded.

To demonstrate the process I created a project with a simple application that contains one button.

<mx:Button label=”My Button”/>

The project was developed using a pre-release version of Flex4, build 4.0.0.13672.

 

Create an RSL

My modification of Button is just a change to set label() so I can see if a Button in my application is a real or patched Button. When the Button’s label setter is called I just prepend “Monkey patched ” to the original value.

 

_label = “Monkey patched ” + value;

I started by adding Button.as to my source tree using the same package as Flex, “mx.controls”. Next compile your source into an RSL. From the command line it will look something like this:

>compc -directory -output=button -link-report=link.rpt -include-classes=mx.controls.Button -source-path=.

>optimizer button/library.swf –output -button.swf

–keep-as3-metadata=Bindable,Managed,ChangeEvent,NonCommittingChangeEvent,Transient,SkinPart

>digest button.swf -swc-path=button

After running these commands the size of button.swf is 143,596 bytes. Looking at the link report, there are a lot of classes besides mx.controls.Button that we don’t need. Ideally, all we want in the RSL is mx.controls.Button. But the Flash Player requires classes that Button extends or implements to be defined when the Button class is loaded. Since we are loading this RSL before the framework RSL, we need to also include the classes Button extends and implements in framework.swc. For each additional class we include, we also need to include the classes it extends and implements.

Take the link report from the first compile of Button and copy it to a file we will use as our externs file. The externs file is what we will use to remove classes we don’t want in the RSL. I actually seeded my externs.xml file by copying and pasting the script children from framework.swc’s catalog. My thinking was that I wanted to exclude everything in framework.swc except Button and the classes it extends or implements. But now I can see that the externs file is much larger than it would have been if I had just started with the initial link report.

Next edit the externs file by removing the script elements for mx.controls.Button and all of its inheritance dependencies. After recompiling I was able to get the RSL size down to 35,152 bytes. That is still pretty big but it’s the best we can do because we need UIComponent and UICompoment is big. When monkey patching spark components we will be able to remove UIComponent and get a much smaller RSL.

Add your RSL to the configuration

Now that you have your RSL, you just need to add it to the RSL configuration. I created a local configuration file, main-config.xml, with the RSLs I wanted. You can start by copying the <runtime-shared-library-path> elements from flex-config.xml to your local configuration file. Then add the entry for your RSL before the framework RSL.

<!– monkey patch mx.controls.Button from Framework SWC –>

<runtime-shared-library-path>

<path-element>button</path-element>

<rsl-url>button.swf</rsl-url>

<policy-file-url></policy-file-url>

</runtime-shared-library-path>

The order of the runtime-shared-library-path options is important because it determines the load order of the RSLs. The RSL URLs in my configuration file are all local SWF files so before running the application I will copy the RSLs from my SDK frameworks/RSLs directory to where my application lives.

When the new RSL is loaded for the first time you will mostly encounter verify errors because you missed removing an interface from the externs file. As you encounter a verify error, remove that class from the externs file and try again. Eventually the RSL will contain all the classes it needs and load without errors.

Finally, run the application to verify the monkey patched Button is being used.

The postings on this site are my own and don’t necessarily represent Adobe’s positions, views, strategies or opinions.