Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Archive for November, 2006

Little Things Matter

In case you haven’t discovered this yet, Acrobat 8.0 was released a couple of weeks ago and along with it came a new version of Designer. While the "what’s new" page does a great job at giving an overview of the major new features available in the product (as it’s supposed to do), it doesn’t mention some of the smaller things that can sometimes be just as beneficial — if not more, in certain circumstances — than the larger features.

As a developer, I can say that we certainly wish we would’ve had more time to spend on improving the usability, look and feel and "fun factor" of Designer but some of us did manage to find some time to implement a few changes that we hope you’ll find useful.

Field Editor Overlay

This feature is actually mentioned in the "what’s new" documentation but I thought I would highlight it here again since it was designed to help you accomplish some of the most basic tasks surrounding form design:

This feature isn’t activated by default. You can activate it by selecting the Field Editor command from the View menu and selecting a single object on the canvas.

There are 3 major parts to the Field Editor:

  1. The Name edit box at the top in the tab. It serves two purposes, the first being to display the field’s name and the second being a way for you to edit the field’s name without having to use the Object palette or the Hierarchy palette. To edit the name, just click on the tab to make the in-place edit box appear:

  2. It also provides a Field Type drop down list that let’s you change the field’s type on a whim from, say, a date/time field to a numeric field — in case you initially picked the wrong type of field. To do this, just click on the box in the lower left hand side of the Field Editor:

  3. Last but not least is the fly-out menu button located on the lower right hand side of the Field Editor. This simply gives you quick access to the context menu which would otherwise be displayed if you right-clicked on the field using your mouse either on the canvas or from the Hierarchy palette.

Resizing Check Boxes and Radio Buttons

When I attended the BFMA Symposium last May, a few customers came to me and explained how awkward it was to work with check boxes and radio buttons when resizing them on the canvas. The problem was that resizing these object types would result in a larger content area.

For example, you would start with a check box you just dropped from the Library palette

and you would then use the selection handles to make it wider

The problem with this was that making the check box wider would increase the size of the content area as opposed to the caption area. This is generally a good thing when you’re working with field types such as text fields or numeric fields because making the field wider is usually related to wanting more "space" for the value to fit in the content area. Check boxes and radio buttons, however, are different. Since their content areas are restricted to a box or circle when the check mark or dot appears, their values never take-up more room than that which you see at design-time on the canvas. Therefore, making a check box or radio button wider is usually related to wanting more room in the caption area rather than the content area.

In Designer 8.0, we fixed that so that when you increase or decrease the width of a check box or radio button, you get the following result instead of the old Designer 7.x result (more caption space without increasing the content area space):

From there, you can quickly click into the caption area in order to make the required changes to the caption without having to first resize the caption area after resizing the check box itself.

Library Palette Accordion View

If you installed Designer 8.0 already, you may have noticed something different in the Library palette: We’ve done away with the old row of tabs at the top and have introduced a new layout which I like to call the "Accordion View".

This is how it used to look like in Designer 6.0 – 7.x. This is how it looks now in Designer 8.0 with the new Accordion View.

The biggest difference between the two styles is that the Accordion View now lets you see (or open) more than one tab at the same time. For instance, in the sample above, you can see content from the Standard, Custom and Barcodes tabs concurrently while in the sample from Designer 7.x and earlier, you could only see the Standard tab.

While this may not seem immediately useful for the Library palette, we wanted to try it out to see how our customers would like it. At the very least, I think it gives the Library more of a catalogue feel, which is what we were aiming for in the first place. If the feedback is positive, we may consider applying the concept to other palettes as well. Imagine being able to see the Field, Value and Binding tabs all at once in the Object palette and not having to keep going back and forth between them to remember what you set in a particular property!

Enhanced Selection Borders

Another pain point when working objects on the canvas was the difficulty in selecting various objects depending on how they stacked-up against each other. For example, it was nearly impossible to select a subform that contained a bunch of objects that each touched the borders of the subform.

In order to address this problem, we decided to make the selection borders for container objects (such as subforms, tables, table rows, radio button lists, etc.) a little more sensitive to mouse movement by padding them to make them easier to grab.

For example, consider the address block you can get from the Library’s Custom tab: It comes pre-wrapped in a subform. Have you ever tried to select just the subform in Designer 6 or 7.x without lasso-ing all the fields (which can be difficult if you have a lot of other fields on the canvas) or using the Hierarchy palette to select the subform? I don’t think you could actually do it. This is how the selection border on the subform looks like in Designer 8.0:

Notice the semi-transparent fill between the anchor points (it looks like a purple-ish color in the image above). That’s the padding area that activates the selection of the subform whether it’s selected or not (note that this fill doesn’t appear when the object isn’t selected). Try it yourself and see how it works!

Here it is again, this time on a radio button list that contains three radio buttons:

Eye Candy

Of course, we managed to add a few treats in the package as well since all these usability enhancements are nice but they can be a little dry too and who says a form design application can’t be nice to look at or fun to play with?

Library Accordion View Animation

When you click on a tab in the Library’s new Accordion View, you might notice that it rolls-downs and rolls-up when you open it and close it, respectively. Both actions are actually slowing down as they approach their final dimensions.

Canvas Fading

Try adding or deleting objects on the canvas. You can also see it when you move an object from one location to another or when you undo an action you just did.

What’s changed from Designer 7.1 is that these actions on the canvas all result in fade-ins for objects coming on to the canvas and fade-outs for objects going off the canvas. It’s very subtle but it just makes it a little less jarring (i.e. the actions aren’t so sudden anymore) to manipulate the objects on the canvas.

Shaded Page Backgrounds

Designer 8.0 also added two small modifications to the page (canvas) background. If you create a new form with a single page and set the zoom factor to 25%, you’ll get a nice feel for what I’m describing here:

This is what the page background used to look like in Designer 7.1. In Designer 8.0, you can see that the page gets a nice shadow on its right and bottom borders and the background is now a subtle gradient going from dark to light.

These minor changes may seem insignificant but when you add them all together, they can make a significant impact. Hopefully you enjoy these enhancements as much as we enjoyed putting them into our product and please feel free to test-drive them yourself.


Posted by Stefan Cameron on November 23rd, 2006
Filed under Designer

LiveCycle Blog and Google Group

I just got word of two excellent new resources for those of you interested in Designer and LiveCycle, whether you use LiveCycle Designer specifically or the Designer that ships with Acrobat:


Posted by Stefan Cameron on November 14th, 2006
Filed under Designer,General

Instance Manager Object Reference

It seems lately a lot of my posts and a lot of the comments that you’ve posted had something to do with the Instance Manager: The object available only on repeatable (dynamic) subforms which allows you to manage that subform’s instances (add, remove, etc.).

Since it’s at the core of repeatable subforms which are necessary when designing flowable (dynamic) forms that, say, display one row per record in a table connected to a database, I thought it would be useful to give a quick overview of the Instance Manager Object’s properties and methods.

Accessing the Instance Manager

Before we get to the properties and methods, here’s a refresher on how to get at the Instance Manager for a particular subform (or table row).

Repeatable Subform Required

First, you must make the subform repeatable. To make it repeatable, it must be placed in a flowed container — that is, another subform whose Content type (found on the Object palette’s Subform tab) is set to flowed.

Side Note: The simplest case is a report-style form that simply displays records from a database where each record’s information is displayed in separate fields within a subform. So you have a subform with fields in it that are bound to data nodes in some data connection and the subform itself is bound to a repeating data section in that same data connection. For this scenario, you’ll find it much easier to place your fields on the first page and then shrink the page (which is a subform) such that it’s snug against the fields you placed on it and looks more like a row rather than a page. This is because the page subforms are, by definition, subforms parented to the root subform (named "form1" by default on new forms — check it out at the top of the Hierarchy palette) and the root subform is, by definition, flowed. By using the page subform as your repeatable subform for your data records, you’ll find it much easier to quickly get to a state where all records show-up on your form and new pages get added when previous ones are full (can’t fit any more rows).

Once the subform is placed in a flowed container (parent subform), you must then specify that it’s a repeatable subform by going to the Binding tab on the Object palette and checking the "Repeat subform for each data item" box.

After these two easy steps are complete, you’ll then automagically get an Instance Manager object on the repeatable subform you just defined.

Script Access

It’s nice to have a repeatable subform but unless you’re just using the default behaviour (which may very well be just fine in most cases), you’ll need to write scripts that use it’s Instance Manager’s properties and methods and you’ll need to know how to access the Instance Manager in your scripts.

It turns out there are two ways of doing this:

  1. instanceManager Property: As long as you have at least one existing instance of the repeatable subform, you can access its instanceManager object directly like you would any other property: RepeatableSubform.instanceManager. Note, however, that this property will only be accessible if at least one instance of the RepeatableSubform object exists (which could be a problem if you’ve specified that its minimum allowed number of instances is zero and its initial instance count is zero as well).
  2. Underscore Prefix: The other recommended way to access a repeatable subform’s Instance Manager is to use, for lack of a better term, "the underscore-prefixed repeatable subform name" object. That is, whenever a subform becomes repeatable, its Instance Manager is added to the Script Object Model as a child of the subform’s parent container (remember, that’s the flowed subform from earlier) and is given a name that is the repeatable subform’s name with a "_" prefix. Therefore, if your subform was named "RepeatableSubform", its Instance Manager would get a name of "_RepeatableSubform" and you would access it as a property of the flowed container subform like this: FlowedContainerSubform._RepeatableSubform. The nice thing about accessing it this way is that you always have access to it — even if no instances of the RepeatableSubform object currently exist.

Properties and Methods

Now that you know how to make a subform repeatable and get access to its Instance Manager object when writing scripts, here are the various properties and methods that you have access to:

Properties

  • count: Returns the number of instances that currently exist. This is very useful when writing loops that do something to each instance.
  • min: Returns the minimum allowed number of instances. When removing instances, you’ll get a scripting error if the resulting number of instances is less than the minimum and the minimum number of instances will still remain (even if you meant to remove them). This can be set using the Min property on the Binding tab of the Object palette or my accessing the subform’s "occur" element and setting its min property: RepeatableSubform.occur.min = "value".
  • max: Returns the maximum allowed number of instances. When adding instances, you’ll get a scripting error if the resulting number of instances is more than the maximum and no additional instances will be added. You can modify this in the Object palette’s Binding tab or with the following property: RepeatableSubform.occur.max = "value".
  • occur: This is a reference to the pertaining subform’s <occur> element which lets you modify its minimum (min), maximum (max) and initial (initial) number of instances.
  • name: This property sets the name of the Instance Manager object itself. I doubt this would ever really be useful but it’s a property nonetheless. Be forewarned, however, that it’ll affect all subsequent scripts. For example, if you were to write "FlowedContainer._RepeatableSubform.name = ‘myIM’;" and then write "FlowedContainer._RepeatableSubform.addInstance(0);", you would get a an error stating that "_RepeatableSubform" doesn’t exist. That’s because you’ve changed its name to "myIM" and therefore should write "FlowedContainer.myIM.addInstance(0);".

Methods

  • addInstance(bool merge): Adds a new instance of the repeatable subform and returns a reference to the new instance (or null if no instance was added) . Setting merge to 1 will cause any additional data to be merged with the new instance. Also, don’t forget that new instances aren’t automatically added to the form’s calculation dependencies. Also, be careful not to add more than the maximum number of allowed instances (see the max property).
  • removeInstance(int index): Removes the instance with the specified zero-based index. [A/R 7.x] You may need to call xfa.form.remerge() after removing an instance. Also, be careful not to remove more than the minimum number of allowed instance (see the min property). [A/R 8.1+] If there’s anything else you need to do (any other script statements) along with removing an instance, make sure that the instance is removed once all other statements have been executed. The new Direct Rendering engine in A/R 8.1 removes the instance, and all objects that it contains, immediately (as opposed to removing it on the next rendering pass as in previous versions) which means that any subsequent statements are not executed.
  • moveInstance(int fromIndex, int toIndex): Moves the instance at the zero-based fromIndex such that it becomes the instance at the zero-based toIndex (and other instance in between are shifted up/down as necessary).
  • insertInstance(int position [, bool merge = 0]): [New in A/R 8.0] Inserts a new instance at the zero-based position specified and returns a reference to the new instance (or null if no instance was added). You may optionally specify 0 or 1 for the merge property which, if set to 1, will merge any additional data with the new instance. The same rules and gotchas apply for this method as they do for the addInstance method described above.
  • setInstances(int count): Adds or removes instances to/from the end of the set depending on the difference between the current instance count and the specified instance count. In other words, if there are currently 4 instances and you call "setInstances(6)", two new instances will be added to the end of the set. Conversely, if 3 instances exist and you call "setInstances(2)" the last instance in the set will be removed. Note that this method abides by the currently-specified min and max restrictions.

Recommended Scripting Language

On a last note, I simply wanted to recommend using JavaScript as opposed to FormCalc when scripting the Instance Manager — especially when adding or removing instances. While FormCalc technically fully supports the Instance Manager, I personally find it’s a little flakey. JavaScript support, however, is quite consistent and stable.

Updated: June 26, 2009


Posted by Stefan Cameron on November 11th, 2006
Filed under Instance Manager,Scripting

Designer 8.0 Now Shipping!

That’s right! The day has finally come. At the moment, Designer 8.0 is only shipping with Acrobat 8.0 Professional. You can download the trial to check it out.

Jeff Stanier, our product manager, has put together a great document detailing what’s new in Designer 8.0. This is a really nice upgrade with lots of really nice brand new features like an integrated spell checker, greatly improved PDF Form importing (as "artwork"), improved digital signature support, test data generation, ability to show all scripts in a container, support for transparency in PNG and GIF image files and much, much more including some nice little usability improvements to make it easier to work with your forms.

In the coming weeks, I’ll be giving more details on these features and I’ll also be transitioning to Designer 8.0 and Acrobat 8.0 for future tutorials, targeting Designer 7.x/Acrobat 7.x only where appropriate.

One of the nice things about Designer 8.0 is that it now supports side-by-side installations along with older versions, making it easy to have Designer 7.1 and Designer 8.0 on the same machine for comparison and testing.


Posted by Stefan Cameron on November 9th, 2006
Filed under Designer

oneOfChild Scripting Property

Sometimes it’s necessary to access the properties contained within a field object’s UI property. For example, you might want to highlight only the content area (the value portion as opposed to the caption portion) of a text field. The problem with doing that is that you need to access the UI property’s one-of property in order to get at the Border object that it contains. The "ui.{one-of property}.border" object controls the appearance of the field’s content area. (Tip: It’s also the object that’s affected when you use the Appearance property on the Field tab in the Object palette).

If you were to look at the XFA specification supported by Designer 7.1, you would find, on page 664, that the UI element contains various one-of properties (which describe a set of properties from which only one may be specified at any given time) which vary depending on the type of field you’ve created on your form. For example, if it’s a text field, it has a

field.ui.#textField

property whereas a drop down list would have a

field.ui.#choiceList

property.

Based on the various definitions of XFA fields, you would have to write the following script to change a text field‘s content area color (shown here in FormCalc):

$.ui.#textField.border.fill.color = "255,0,0"

But what about a drop down list? Because it uses a different UI one-of property ("choiceList" instead of "textField"), you would have to write the following script (shown here in JavaScript) to change its content area color:

this.ui.resolveNode("#choiceList").border.fill.color.value = "255,0,0"

This is all fine as long as you know the type of object on which the script will be executed but what if you wanted to change the content area color of all fields on your form? You might decide to define multiple arrays that contain references to text fields, numeric fields, etc. (one array for each type) but that wouldn’t be very practical because you would have to remember to keep that list up-to-date for every change you made to your form.

A much easier way to do this is simply by using the oneOfChild scripting property: It’s designed to return a reference to the one-of property that has been specified in the Object Model on the object on which it is used. In other words, if you used it on a text field‘s UI property, it would represent the "#textField" property whereas on a drop down list, it would represent the "#choiceList" property.

If we put this in practice, it means you could use the following script to change the content area color of any field object you find on your form (shown here in FormCalc):

FieldObject.ui.oneOfChild.border.fill.color = "255,0,0"

where "FieldObject" would be a variable holding a reference to a field object on your form.

Of course, the use of the oneOfChild property also works because the Border property is common to all UI one-of properties. There are some cases where some properties are specific to a certain "UI type" (like the "#choiceList.textEntry" property). In those cases, you may need to verify that you are, in fact, attempting to access those properties on the right kind of UI one-of property or else you’ll get a scripting runtime exception.


Posted by Stefan Cameron on November 9th, 2006
Filed under Scripting