Welcome!

Adobe Flex Authors: Yakov Fain, Keith Swenson, Jacques Durand, Pat Romanski, Liz McMillan

Related Topics: Adobe Flex

Adobe Flex: Article

Double-Clicking A Document

A professional projector makes it easier

Thanks to the extensive range of xtras available, a Director projector can create any type of document and write it to the user's hard disk. In Windows Explorer and the Macintosh Finder, users expect that a double-click on a document icon will launch the program that created it. This article shows you how to associate files with the Director projector that created them. By the end of this article, you will have created a simple word processor application that creates its own document files; double-clicking on the icon of one of these files will open your Director application so that you can edit the document.

There are many situations in which this technique will prove useful. For example, you may want to save the state of a game in progress, a customized slide show presentation, or mark up data for a video sequence.

But recognizing the files created by a projector is not something that Director does naturally. By default, when the user double-clicks on a document created by a Director projector, the operating system prompts the user to select an application to open the file. If the user properly selects your projector, then your projector is launched, but the document still doesn't open.

For my programs, this is unacceptable. I sell programs that are often in direct competition with titles from major software vendors. Something like the double-click may seem trivial, but the little things add up and the less my users have to think about, the more likely they are to purchase the product. I like my projectors to be as professional as possible, complete with robust menus, keyboard shortcuts, user-defined preferences, and standard user-interface elements. In the end, if the user can't tell that the program was created with Director, then I've done my job. This means finding a way to deal with double-clicking on documents.

Thankfully Director has an undocumented feature - a system variable called the commandLine that corresponds to the operating system's command line. When the user double-clicks on a document, the operating system's command line gets updated with the path to the document, and Director's commandLine provides us with this information.

But figuring out which document the user clicked on is only half the battle. The operating system also needs to be told to launch your projector instead of prompting the user, and then your application has to be set up to deal with what happens so the file actually opens. This article will give you step by step instructions for getting this to work for Macintosh OSX and Windows platforms. The commandLine doesn't exist on pre-OSX Macintosh operating systems because those systems don't have a command line at all. So, this technique will not work on OS8 or OS9.

This article assumes you have a basic understanding of Lingo, movie scripts, frame scripts, and working with xtras. You will also need some additional tools besides Director. For Mac OSX, you will need a program called Property List Editor, which can be found on the Developer Tools CD that came with your copy of OSX. If you don't have that, you can get away with just using a text editor, but you'll need to have a basic understanding of XML. You will also need DirectorMX or DirectorMX2004 since those are the only versions of Director that can create projectors for OSX. For Windows, you will need a third-party xtra since we will be editing the Windows Registry. This article uses the BuddyAPI xtra, but any xtra that can modify the Registry will work, such as the Registry xtra and others.

Setting Up Your Application
In order to have a document to double-click, we will need to have an application that can save an open document. In this article, we will create a simple text editor that can save and open documents. It will function like a mini word processor, so I'll call it MiniWord.

Launch Director and create a new document with a white background. It can be any size, but there's no reason to make it huge, so make it fit comfortably on your screen. Next, create a field member by selecting Insert > Control > Field. The field will appear onstage with a cursor in it. Leave it blank for now and find the field cast member in the cast window. Name the cast member "content." Now select the field sprite on the stage and open the Property Inspector. Click on the Field tab and click on the Editable check mark. In the Framing dropdown menu select "Scrolling" and resize the sprite so it fills most of the stage. Leave some room at the bottom for some buttons that we'll create in a moment. Change the Property Inspector to list mode if it isn't already and set the border of the field to 1.

Open the score window if it isn't already and double-click on the script channel for frame 5. This will open the script window with an exitFrame handler filled in for you. Type into the frame to make the movie loop here. We will be adding more to this script later.

The next thing we have to do is set the field member to clear its content when the movie starts so the user is presented with a blank document. You don't absolutely have to do this, but it's easier than trying to remember to manually clear the field member before you publish the movie. There are a couple of ways to do this. You can write a behavior and attach it to the script to clear the cast member on beginSprite. Or, do it on a movie script on prepareMovie that runs every time the movie is run. We'll be using on prepareMovie for some other stuff later so let's use that.

Open the script window and click on the + to insert a new script. Type in:


on prepareMovie

  member("content").text = ""

end

Open the Script tab in the Property Inspector and make sure the Type drop down menu is set to Movie.

Now if you run the movie, you'll be able to type into the field. Then, stop and restart the movie and you'll see the field get cleared, leaving you with a fresh new document.

Save The Document
Now that we have a document, we need to be able to save it. Create a push button by selecting Insert > Control > Push Button. A blank button appears on the stage with a flashing cursor. Type in Save As and move the button to the bottom left area of the stage below the content field. Select the button cast member in the Cast window and click on the little script icon either in the Cast window or in the Member tab of the Property Inspector. This will open the script window and create a script attached to the member with a blank on mouseUp handler. Type in the code from Figure 1.

This handler makes use of the FileIO xtra that comes with Director, which is used to read and write text files with Lingo. Any xtra that reads and writes to the user's hard drive can be used in its place, such as vList, BinaryIO, and others.

The first thing the handler does is create an instance of the FileIO xtra to use. Then it sets the filter mask to only allow the user to work with documents created with our program. It does this by defining our custom document type. Our document, although it will be nothing more than a text file, will be a "MiniWord Document." We can't just use a .txt file since both Macintosh and Windows already have programs to deal with those kinds of documents. So, our documents will have a .minw extension on Windows, and a 'minW' file type on the Macintosh. (More on that in a moment.)

Note that this is platform-specific code, so I have an if...else statement to branch out to whichever platform is hosting the Director movie. This also allows you to code once and publish for both platforms without having to rewrite any of your Lingo. (Syntax note: The _system.environmentproplist.platform call is the new syntax introduced in DirectorMX2004. If you're still using DirectorMX, you will need to replace this item with the platform in order to make the code work.)

Next, the handler calls displaySave, which pulls up the standard OS save dialog box so the user can select where to save the file and what to name it. This function returns the full path to the document the user wants to save, or an empty string (Macintosh) or <Void> (Windows) if the user hits Cancel. The next thing we do is make sure the user didn't hit Cancel. If filePath is not an empty string then we can proceed. We then create the file, open it, store the string we got from the Content member, write to the file, and close it.

On Windows, file types are specified by a file extension such as .txt for text files and .doc for Microsoft Word files. These are tracked by the Windows Registry, which associates these file extensions with the proper application and is why we set the filter mask above. If the user forgets to add .minw to the file name, the system will take care of it, ensuring that the file keeps its program association. We haven't actually edited the Windows Registry yet, so right now the extension is meaningless, but we'll take care of that soon.

On the Macintosh file, types and associations are traditionally marked in the file itself in a section called the Resource Fork. The file will have a four-character identifier called a creator code. It is traditionally written in single quotes and tells the operating system which application it should use to open the document. DirectorMX2004's creator code is "MDO3". (Interesting that it's not "MD04"). You can pick any four-character code for your application. I chose "MnWd" for our MiniWord application. All ASCII characters are acceptable, including spaces and special characters. So, if you want to make your application's code '#$ !' that is perfectly fine.

However, there are some rules, the most important of which is that Apple has reserved all lowercase-only codes for internal use. This is why my application code is "MnWd" and not "mnwd". And although it's not required, Apple suggests that you register your application code with them at their developer site (http://developer.apple.com/datatype/creatorcode.html). This is a good idea to make sure nobody else is already using your code. They used to require that you register your file-type code as well, but they no longer ask for that. The file-type code is the same thing - a four-character code that identifies the kind of file it is. Text files are identified with "TEXT"; JPEG files are marked as "JPEG." This is why JPEGs created with Photoshop will reopen in Photoshop when you double-click on them instead of opening in your Web browser, as they do on Windows. Our MiniWord application will create "minW" files.

Run the movie, type something into the content field, and hit Save to make sure the document saves as expected.

Open The Document
Insert another push button and name this one Open. Drag it down to the lower right area of the stage next to the Save As button. Select the cast member and click on the script icon in either the script window or the Property Inspector. Type in the code as shown in Figure 2.

This code is very similar to the Save As code. The main difference here is that instead of calling displaySave, we call displayOpen, which prompts the user to select a file and returns its path. And again, if the user hits Cancel, the path is an empty string. If not, we open the file specified by the user, read the whole file, store the text we just read in the Content member and close the file. That's it. Here the setFilterMask handler only displays MiniWord files for the user to select. This way your program doesn't try to open Word or Photoshop documents.

The next step is to associate our file format with the application. This has to be done separately for each platform.

The Mac Package
A package is simply a folder with a certain hierarchy of sub-folders and files that define how an application works. When the root folder is named with a .app extension the folder takes on the application's icon and acts like the application itself. Since we have to make the package manually the process is fairly involved, so here are step by step instructions for creating your package.

  1. Create a folder called MiniWord Mac. This will be the folder that will act as the application later.
  2. Open the MiniWord Mac folder and create a folder inside it called Contents. The Contents folder will contain four items. The first is a text file that contains the creator code and file type for our application. Applications always have a file type of "APPL." Since our MiniWord application saves files in text format we can just use that to generate this file.
  3. In Director, play the movie and type APPLMnWd into the content field. That is the standard application file type, and our custom creator code. Click Save As, name the file PkgInfo (with no extension), and save it in the Contents folder.
  4. Create a folder in the Contents folder called MacOS.
  5. Create another folder in the Contents folder called Resources. We actually won't use the Resources folder for this demonstration, but it's a good idea to create it anyway. This is where icon files and other related items would go.
  6. Find the Director application icon in the Finder. If you have Director in the dock, you can simply click and hold on the icon and select Show In Finder. Otherwise, navigate through your Applications folder until you find the Director application icon. It's time to take a look at Director's package. Control-click (or right-click if you have a two-button mouse) on the application icon and select Show Package Contents from the pop-up menu that appears. Open the Contents folder and then open the MacOS folder.
  7. Copy the following four files:
    - MacromediaRuntimeLib
    - ProjLib
    - IMLLib
    - DPLib

    and paste them into your MacOS folder. These are the Shockwave library files. In order for your projector to run inside a Package, it must be a Shockwave projector. Shockwave projectors require that the user have the Shockwave plug-in installed on their system in order to run. Placing these files in your MacOS folder (next to where the projector will be) ensures that your projector will run even if the user doesn't have Shockwave installed.

  8. (Optional) In the MacOS folder, create a folder called xtras. Place all the xtras you used in your projector into this folder. You'll need to copy them from the Director application folder. If you don't do this, make sure all the xtras used in your movie are marked to be included in the Projector. You'll need to explicitly add the FileIO xtra to your movie under Modify > Movie > Xtras.
  9. Publish your Director movie. In the Publish Settings window in the Projector tab, make sure that Player Type is set to Shockwave. Save the projector to another folder elsewhere, not into the MiniWord App folder. Once we make this folder into a package, you won't be able to save to it directly and we'll be making more changes to the Director file later. So save it somewhere else, and then move it into the MacOS folder. This way, you'll know exactly where to find it when we publish it again. Be sure to copy your published projector into the MacOS folder.

    In the next step, we will create a file called info.plist. This is an XML file that explains how the application is set up and describes many of its components. The easiest way to create this file is with Apple's Property List Editor application, which you can find on the Developer Tools CD that comes with OSX. If you don't have this, you can use a text editor to create the file, but it's very easy to make mistakes doing it that way, and very difficult to find them to fix them when something doesn't work. A finished info.plist file is shown in Figure 3. If you don't have Property List Editor installed, skip down to the next paragraph and copy the XML data below exactly as you see it using any text editor.

  10. Launch Property List Editor.
    - Click New Root.
    - Turn down the Root arrow and click New Child.
    - Type in CFBundleDocumentType and set the class to an Array. This defines the file type.
    - Turn down the CFBundleDocumentTypes arrow and click New Child. The program automatically inserts an item numbered 0. Change its class to Dictionary.
    - Turn down item 0 and click New Child.
    - Type in CFBundleTypeExtensions and change its class to an array.
    - Turn down the arrow for CFBundleTypeExtensions and click New Child.
    - In the value field for item 0 type in minw, all lower case. This defines the file extension for our documents.
    - Close the CFBundleTypeExtensions arrow and click New Sibling.
    - Type in CFBundleTypeName and in the value field type in MiniWord Document File.
    - Click New Sibling and type in CFBundleTypeOSTypes and set it to an array.
    - Turn down the CFBundleTypeOS-Types arrow and click New Child.
    - In the value for item 0 type minW. This is our actual document type as stored in the Resource Fork.
    - Close the CFBundleDocumentTypes arrow and click New Sibling
    - Type in CFBundleExecutable and in the value field type MiniWord.osx, or whatever you named your projector. Make sure the name matches exactly.
    - Click New Sibling, type in CFBundleName, and in the value field type in MiniWord.
    - Click New Sibling, type in CFBundlePackageType and in the value field type in APPL.
    - Click New Sibling, type in CFBundleSignature, and type in MnWd. This tells the operating system that this is our application's creator code.

    Many other items can be defined here, but this is all that is necessary to make our project work. The final file should look like Figure 1. Make sure it matches, and then save the document as info.plist and place it in the Contents folder.

    If you don't have Property List Editor installed, you can create the file manually with a text editor. Type in the XML exactly as you see it in Figure 4.

  11. Navigate back to the MiniWorld Mac folder and rename it to MiniWorld Mac.app. You will get an alert to warn you about changing the extension. Click Add to add the extension. If everything is set up right, the folder icon will change to a generic application icon. Or, if you published your projector with a custom icon the folder will take on that icon.
At this point, if you double-click on the MiniWorld Mac folder it will no longer open to reveal its contents, but instead will launch your projector. Additionally, if you double-click on a saved document that MiniWord created, it will also launch the projector, but it still won't open the file. We still have to add code to handle that.

The Windows Registry
Associating our file types with the Windows operating system isn't nearly as involved as it is on the Macintosh. However, it's also not something that can be done natively in Director or with another program. The first time your program runs, it needs to edit the user's Registry file to make everything work. In order to do this, we will need a third party xtra. This example makes use of the BuddyAPI xtra (www.mods.com.au), but any xtra that can work with the user's registry will work. Check the documentation for the specific syntax you'll need with other xtras.

Ideally, your program will only write to the user's Registry once. That means your program would need to keep track of the fact with a preferences file or some similar method. Saving preferences files is beyond the scope of this article so for now we will do all our work on prepareMovie. This will run every time the program is launched, which is not ideal but will do for the purposes of instruction.

In your movie script in the on prepareMovie handler, add a call to a handler called editWindowsRegistry so the whole handler now looks like this:


on prepareMovie

  member("content").text = ""

  editWindowsRegistryEditWindowsRegistry()

end

Now we need to define this handler. Type in the code as shown in Figure 5.

The next time your movie is run, it will modify your Registry to associate the file types with your application. At this point, double-clicking on a saved document will launch your projector but will not open it for the same reason as for the Mac - we haven't yet added the code to handle that.

Opening The Files That Were Double-Clicked
Now that our program is being launched, when the user double-clicks on a file, we need to figure out which file the user clicked on and open it. We can do this with an undocumented system variable called the commandLine. This variable takes the form of an apostrophe-delimited string. The second-to-last item in the string is the path to the file the user clicked on. The string ends with an empty item, which is why we want the second-to-last item.

Not only does the program launch when the user double-clicks on a document, but if the application is already running, it is brought to the front. So our program needs to periodically check the commandLine to see if it has changed. If it has, we need to open the new document. To do this, we'll create a global variable called myCommandLine and initialize it to an empty string. So let's modify our on prepareMovie handler to accommodate this.


global myCommandline

on prepareMovie

  member("content").text = ""

  myCommandline = ""

  editWindowsRegistry

end

If the user launched your program normally, then the commandLine will return an empty string, which matches myCommandline. So all we have to do is see if the commandLine has changed, and since we have to do this periodically, we'll just do it on the exitFrame handler we have running on frame 5.


global myCommandline

on exitFrame me

  -- Check to see if the commandLine has changed.
 if the commandLine <> myCommandline then

  -- Open the file specified by the commandLine.
  openThisDocument()

  end if

  go the frame

end

Checking the status of the commandLine of every frame is usually not necessary. And certainly, if you're authoring a game, you don't want to take a speed hit by doing an unnecessary check every frame. I'd suggest only checking on the title screen or some other relatively calm screen.

The openThisDocument handler will now get called whenever the commandLine changes, which happens whenever a user double-clicks on a saved document that is associated with your application. It's structure is very similar to the code we attached to the Open button, but instead of prompting the user to select a file it simply uses the commandLine to find the file. In the movie script, type in the code from Figure 6.

This code is the same as the open code, except for the section at the top that gets the path from the commandLine. The way that works is that it first saves what the current itemDelimiter is in a local variable so we can restore it later. Then, it sets the itemDelimiter to an apostrophe and reads the entire commandLine. Then, it gets the index number of the second-to-last item in the list and uses that to determine the filepath of the document that was double-clicked. Finally, it restores the itemDelimiter to its default value.

This is the last step in making the program work. Publish your movie again. If you're on a Mac, be sure to place the projector in the MacOS folder in your package. Double-click a saved document and it will launch your projector and open the document. Double-click another file and it will bring your program to the front and open that one.

Conclusion
You have seen how to make your projector behave like a professional application. All you have to do now is apply this technique to your own Director projects, and then sit back and wait for the shareware fees to come rolling in.

More Stories By Tom Rockwell

Tom is the leader of Sudden Death (www.suddendeath.org) and handles most of the group's lyrics, music, and vocals. Tom also runs a shareware company called FIDIM Interactive and programs video games in his spare time. He also enjoys talking about himself in the third person.

Comments (3) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Peter Wolf 07/09/07 07:25:00 PM EDT

The unsupported 'the commandLine' is useful, and also, not very robust. It worked fine on MacOS X/MX2004 until somehow it quit working in my application. Earlier versions of the app still work, as do the example file. Strange behavior.
On Windows note that you'll have to have your publish settings to allow multiple instances of your app; otherwise only the first file you double-click will launch. Note also that it WILL create multiple instances, and not just pass 'the commandline' file path into the currently running instance.

gc 10/31/04 10:12:33 PM EST

Seems to work but is very fickle, esp. on the OSX Mac system. Is there a more detailed approach to this sort of stuff anywhere else or is that it? It would seem that this kind of application preparation is extremely useful for Director developers; being one myself I have been forever looking for ways to apply this kind of approach.

Seth Magee 09/30/04 08:22:20 PM EDT

Wow! MXDJ has great support. Thanks again for the help!