The focus of this article from a development perspective is to show you how to add the necessary code to your navigator to make it actually do something interesting with the content of the PDF Portfolio you attach it to. To begin, I need to cover a few basic concepts that are essential to understanding why exactly you are adding what can seem like superfluous code. There are four concepts you'll need to understand and some code that goes with each.
Files versus Folders:
When you are looking at a particular set of items in the PDF Portfolio collection through the Acrobat ActionScript API, a file and a folder are both IAttachments. If the "isFolder" property of the IAttachment is true, then the IAttachment is a folder and has an IList of additional IAttachments as it's children. A file, obviously, has no children. All of the Adobe supplied navigators treat folders and files the same for display purposes in that folders are listed right along side files and both are sorted together. You "activate" an item by double-clicking. Double-clicking on a file will preview that file and double-clicking on a folder will open that folder and display it's contents.This is a pretty intuitive approach since it mimics how people interact with files and folders in their operating system. In the example project for this article, I'll be using that same metaphore but you don't necessarily need to with navigators that you develop. You'll see a little later in this article how I use the itemDoubleClick event of my DataGrid to activate an item and then branch my code accordingly if the isFolder property is true or false.
Folder Navigation:
Along with the folder concept, you'll need to figure out how you want to allow users to navigate through the folder hierarchy. In the Adobe supplied navigators, folder navigation is provided through a "breadcrumbs" metaphore. Folder names and your path through the folders are displayed in the upper left of the navigator window. I won't actually be using this metaphore, instead, I'll simply add an "up" button to return to the parent of the current folder and deactivate the button when the user is at the root of the PDF Portfolio. Obviously, once you understand the underlying code, you can program your navigator to use whatever UI metaphore you like. This is where the binding statement I discussed in the previous article really comes in handy. You'll see in the example project that I simply set the dataSource property of the DataGrid to the currentItems object. The binding statement adjusts the contents of the currentItems object anytime the folder changes.
Preview vs Open:
The PDF Portfolio concept was developed to provide an easy way to deliver a collection of files in a compact, easy to navigate package. One of the features of the PDF Portfolio navigator window is the ability to "Preview" a file. When you are previewing a PDF file, all of the interactive features, like forms fields, links, and multimedia, are fully functional but you don't see the full set of Acrobat or Reader tool bars; all there see is a clean UI that's perfectly suited to navigating the file. From this preview mode, you can optionally "Open" the file into a normal Acrobat window if you need to do additional work on the file like comment, redact, do form authoring or use the touch up tools. For security reasons, a navigator can only preview files, it cannot open them. However, your navigator can detect if a file that is part of your PDF Portfolio is opened in a regular Acrobat window (see image to the right).
Next and Previous:
When your navigator causes a file to preview, you'll also want to set the next and previous properties of Acrobat. When either the selection or the sort order changes, the navigator's definition of what the next and previous files should be may change. You'll need to add some code so that the next and previous buttons in the upper left of the preview window function properly.
To begin, I'll create the functions that do the heavy lifting every time an item is double clicked.
"Preview" is one of three commands that you can execute on an IAttachment. As I mentioned earlier, a navigator can't directly interact with any of the PDF Portfolio attachments. To preview a file you need to go through the ICommand interface. This interface provides functions used to request and execute commands. A command is a request that Acrobat perform an action on the navigator's behalf. Normally the navigator cannot perform the action directly because it requires access to secure data that is either not available to it or it must display user interface elements, such as dialogs or context menus. The "host.requestCommands" method requests a set of named ICommand instances. The requested ICommand instances will be added to the commands property which lets you actually use the command. While that may seem a little convoluded, in practice, it's just a little code that you can write once and then simply copy from project to project.
I'll begin by adding the "preview" ICommand to the commands property of the host object. Look at the example project to see this code in context.
_host.requestCommands([CommandType.PREVIEW]);
Then I'll add a "preview" function so that previewing a file is easier and all I need to do is pass an IAttachment to the function. A file must be selected before it can be previewed so I need to set the selection property of the _host object. I'll discuss the "updatePrevNext()" function a little later in this article.
public function preview(attachment:IAttachment):void
{
if(_host.commands.hasOwnProperty(CommandType.PREVIEW))
{
var previewCommand:ICommand = _host.commands[CommandType.PREVIEW];
_host.selection = [attachment];
updatePrevNext();
previewCommand.execute(attachment);
}
}
Next, I'll add the code that branches based on whether it was a folder or a file that was double-clicked. If the item is a folder, I can simply set the currentFolder property of _host object and my magic binding statement does the rest.
import mx.events.ListEvent;
public function itemDoubleClicked(event:ListEvent):void
{
var itemIndex:int = event.rowIndex;
var item:IAttachment = IAttachment(currentItems.getItemAt(itemIndex));
if (item.isFolder)
{
_host.currentFolder = item;
}
else
{
preview(IAttachment(currentItems.getItemAt(itemIndex)));
}
}
So, I just added a way for the users to navigate into a folder. Now I need a way to let them get back out. I use the fact that the "currentFolder" property of the root of the PDF Portfolio is null to set the "enabled" property on the button. Then the "upFolder" function simply sets the currentFolder property of the _host object to be the parent of whatever the currentFolder is.
<mx:Button label="Up Folder" enabled="{Boolean(_host.currentFolder)}" click="upFolder()"/>
private function upFolder():void
{
if (_host.currentFolder)
{
var item:IAttachment = _host.currentFolder.parent;
_host.currentFolder = item;
}
}
Finally, I add the "updatePrevNext" function. It's more code than is usefull to show on this page. Instead, you can take a look at it in context in the example project. The important part is that in order for the next and previous buttons to continue to work after a user moves off of the file that you preview, you need to add a "selectionChanged" event listener to the _host object. In my example, the "selectionChanged" event listener function just calls the updatePrevNext function.
_host.addEventListener("selectionChanged", selectionChangedHandler);
private function selectionChangedHandler(event:Event):void
{
updatePrevNext();
}
Detecting and showing which files are open needs to occur independently of any user action in your navigator because a file could have been opened when the user was in the list view or when another navigator was being used. In order to detect when a file has been opened, you need to listen for an "isOpenChanged" event. In my DataGrid for this example project, I added a second column that will display true when a file is open or false when it's not. Basically, I'm just using the string value of the isOpen boolean property of an IAttachment. My labelFunction for that column is the isItOpen function which also adds the listener for that item. When the listener gets triggered because a file has been opened, the DataGrid properties need to be updated. In this way, my DataGrid will display which files are open when it starts up and can respond to events while it is running.
private function isItOpen(item:Object, column:DataGridColumn):String
{
IAttachment(item).addEventListener("isOpenChanged", refreshOpenedFiles)
return IAttachment(item).isOpen.toString();
}
private function refreshOpenedFiles(event:Event):void
{
itemList.invalidateList();
itemList.validateNow();
}
And that's it. You've now got the basics of previewing files and navigating folders. The DataGrid is the simplest of controls but the basics of this navigator can easily be applied to just about any data driven control. In Part 4, I'll discuss how to add thumbnails for the various attachments. You can download and install the example project. Compile the SWF, build and install the .NAV using the instructions in Part 2.
Files:
The Acrobat 9 ActionScript SDK
The Previewing Files and Navigating Folders Project