Sunday, 11 December 2011

Adobe XMP Panel - Improvements

After publishing the original post about creating a custom XMP panel ( see here ), I was contacted via the Resource Space forum about wether it was possible to create multiple sets of check boxes on the panel that related to different XMP fields, ie:

chk1,chk2,chk3 = XMP field 1
chk4,chk5,chk6 = XMP field 2

I posted on the forum that this would be easy to do using multiple handlers, and calling the relevant handler function when a checkbox is ticked.
Now many of you will note that this is not an elegant solution, but it would work, and was easy to explain!
I started thinking about this further, and came up with a more elegant way to achieve the task, that was also much easier to expand upon as there was only one place you needed to add extra code.
So this post will attempt to describe what I've done, and hopefully make it easier for others to reuse the code.

Step 1 - Layout the Panel
The first thing we need to do is layout the panel, as before this is done using the grid control, and using a naming convention for the id's of the checkboxes that relate to the label of the checkbox but without spaces.

<mx:GridItem width="100%" height="100%">
<mx:CheckBox label="Road Haulage"
id="_chkRoadHaulage"    click="updateCats(event,'docTitle')"/>
</mx:GridItem>

The label "Road Haulage" above has an id of "_chkRoadHaulage" so that we can reference it in code easily, as show in the previous article.
The major change to the layout of the checkboxes is the click event. The function that is called now has a second parameter that is the id of the XMP text input that the check box should modify.

<fi:XMPTextInput id="docTitle"
xmpPath="mc:MainCategory
xmpType="Localized"
name="docTitle"
visible="false"
/>

The second set of checkboxes have a different XMP Text Input.

<mx:GridItem width="100%" height="100%">
<mx:CheckBox label="House"
id="_chkHouse"
click="updateCats(event,'docBuilding')"/>
</mx:GridItem>

<fi:XMPTextInput id="docBuilding"
xmpPath="mc:Building
xmpType="Localized"
name="docBuilding"
visible="false"
/>

I'm also setting visible to false as I don't want to give the user the ability to manually edit the field and screw everything up ;)

Step 2 - Code Changes
Next we need to make some changes to the code.
The first thing I thought about is how we handle multiple arrays and reference them easily?
I decided the easiest way to do this was to keep the cats array and store the arrays within that refernced with a key that is the id of the XMP text input.
So the new function that gets called when the panel has completed loading is now very simple.

private function catsReadHandler(event:Event):void
{
/*  This is called once the panel has completed initialising.
        */
// create an array for each xmp field
cats['docTitle'] = new Array();
cats['docBuilding'] = new Array();
//populate the arrays and tick the right boxes
chkBoxes('docTitle');
chkBoxes('docBuilding');
}


All we have to do now is create the sub array for each XMP text input.
The next part calls a new function that reads the text input, populates the array if it contains data and then ticks the boxes that were referenced in the text input. It's basically the same as the previous catsReadHandler function, but I'm using the this[controlID] nomenclature to reference the fields and the checkboxes.
This gets called for each set of checkboxes / XMP field in the panel.

Here's the function:

private function chkBoxes(xmpFieldName: String):void
{
// this takes the name of the xmp field, populates the array, and ticks the checkboxes
var outStr:String;
var catsString: String = this[xmpFieldName].text;
var chkName:String
var catStr:String;
if (catsString.length > 0)
{
// split the text by commas and populate the array
cats[xmpFieldName] = catsString.split(",");
for (var i:int = 0; i < cats[xmpFieldName].length; ++i) 
{
// remove spaces from the cat name and add to _chk to ref the box
chkName = "_chk";
catStr = cats[xmpFieldName][i];
catStr.replace(/s+/g, "");
chkName += catStr;
try {
// tick the box!
this[chkName].selected=true;
} catch (someError:Error)
{
this[xmpFieldName].text=i + " : " + " " + chkName + " " + someError.message;
}
}
}
}

As you can see, it's pretty much the same as before, but putting this in a separate function enables us to simplify the catsReadHandler function and only have to add extra code there.

The final piece of the puzzle is the function that gets called when a user checks / un-checks a box.
This now takes the id of the XMP text input to update, and so we can reference that directly without having to write a special function for each set of check boxes & XMP fields.

private function updateCats(event: Event,fieldName: String):void
{
//we use event.target to identify the control that triggered the function :)
var catName:String = event.target.label;
var outStr:String;
var cName:String;
var delItem:Boolean;
var localArray:Array;
// copy the main array so we can manipulate it.
localArray = cats[fieldName];
if (localArray.length == 0)
{
localArray.push(catName);
} else {
for (var i:int = 0; i < localArray.length; ++i) {
if (localArray[i] == catName)
{
localArray.splice(i,1);
delItem = true;
}
}
if (!delItem)
{
localArray.push(catName);
}
}
cats[fieldName]=localArray;
outStr = cats[fieldName].toString();
this[fieldName].text = outStr;
this[fieldName].dispatchEvent(new Event(Event.CHANGE));
} 

One of the major changes here apart from calling the function with the field id is that I'm copying the array before manipulating it and then copying it back to the main array after the manipulation is done.
I know in theory I shouldn't need to do this, but I was having issues manipulating the main array directly, so I chose this method because I couldn't be bothered to debug it any further than I already had ;)

The complete file can be found here, feel free to play around with it.




7 comments:

  1. Great post and thanks for sharing your improvements. What versions of Flash Builder and XMP Toolkit SDK did you use? I've struggled with Flex Builder 3 and XMP SDK 3.1 (?) in the past with some success, but never had any luck with Flash Builder 4.5 and any XMP SDK version...

    ReplyDelete
  2. Thanks for your comment, I'm using Flash Builder 4.5 and the 4.5.1 XMP SDK.

    ReplyDelete
  3. Thanks very much for the info - now I'm confused by the "4.5.1"! Are you building custom "file info" metadata panels that show up in the file info dialogue in Bridge and/or Photoshop (along with the other panels such as IPTC, Camera Data, Origin, etc.)? Or are you coding metadata side panels which only show up in Bridge under the "METADATA" tab?

    If you are building custom file info panels, this is what I did in Flex Builder 3.0.2 using Flex SDK 3.2.0, XMP FileInfo SDK 4.4.2 and Ant View 2.2.9.

    I've tried Flash Builder 4.5 with different combinations of Flex SDKs and XMP FileInfo SDKs (with Ant View 2.2.9) but have not any success generating any panels.

    As far as I know, the only versions of the XMP FileInfo SDKs I've seen over the past few years were 4.4.2 and 5.1.2 - perhaps is the "4.5.1" you mentioned the "Flex SDK" version used by Flash Builder? If so, what is the version of your "XMP FileInfo SDK"? If you are indeed using XMP FileInfo SDK 4.5.1, where was that obtained?

    Any help appreciated, as it would be great if I could get Flash Builder 4.5 to work the way Flex 3 did, and I'm getting more confused!

    In other words, for your configuration:

    Flash Builder 4.5
    Flex SDK: version?
    XMP FileInfo SDK: version?
    Ant View: version?

    Thanks so much for your time...

    ReplyDelete
  4. Ooops, sorry you are correct.
    The Flex SDK is 4.5.1
    The XMP SDK is 5.1.2
    I also installed the CS Extension Builder 1.5
    Ant is listed as:
    1.7.1_v20100518-1145

    This is for File Info panels that appear in the File Info Dialog.

    ReplyDelete
  5. Many thanks for the information - it is greatly appreciated. Does this mean you are building your panels with CS Extension Builder? I've not explored this yet and it looks like a powerful tool, though different to the way I have created my panels.

    Always learning...

    ReplyDelete
  6. No problem. I'm not using CS Extension builder, just the normal way of File->New->XMP FileInfo Panel Project.
    I thought I'd better mention Extension Builder in case it installs something that is required for this to work!

    ReplyDelete
  7. Extension Builder does look powerful, but from my very limited playing it does not seem possible to create advanced panels with code manipulation. I could be wrong, and as you so rightly said...

    "Always learning"

    ReplyDelete