Use Ext, Aptana, and AIR to build desktop applications

Learn to create a contact management utility

While Rich Internet Applications and Web 2.0 have been all the rage, the latest wave of emerging technologies are focusing on not only giving Web applications a desktop-like feel but actually bringing them to the desktop. The Adobe Integrated Runtime (AIR) has led the way, allowing Web application developers to leverage their existing knowledge of HTML, CSS, JavaScript, Flash, and Flex to build powerful desktop applications. In this tutorial, you will use the open source Aptana Studio IDE, the Adobe AIR plug-in for Aptana, and the open-source JavaScript framework Ext.

Joe Lennon, Software developer, 软通动力信息技术有限公司

Joe Lennon graduated from University College Cork in 2007 with a degree in business information systems. He currently works as a software developer for Core International, based in Cork, Ireland, and has worked as a systems analyst for Fidelity Investments in Marlborough, Mass.



22 July 2008

Also available in Portuguese

Before you start

This tutorial is for Web developers who are looking to create Web applications that run on the desktop seamlessly. Familiarity with Web development technologies, such as HTML, CSS, and JavaScript, are required to follow along. Although not required, experience with the Ext framework would be helpful.

About this tutorial

This tutorial will provide you with a foundation in developing Adobe Integrated Runtime (AIR) applications using Aptana Studio and the Ext framework. We begin by introducing each of these technologies and how, combined, they provide the power required to create fully functional desktop applications. We then show you how to install the Aptana Studio IDE (which includes Ext), the Adobe AIR for Aptana Plug-in, and the Adobe AIR Runtime. Next, we create a new AIR project in Aptana, walking through the basics of running and debugging an application in Aptana. Finally, we build our sample application, a basic contact management utility.

The licensing question

The technologies discussed here each have different licensing models. First, you have Aptana Studio, the Community Edition of which is a free, open source IDE, available under a "dual-licensing" model, which basically means that the user can choose to use the software under the GNU General Public License(GPL) or under the Aptana Public License (also referred to as the APL).

Ext is also available on a dual-license model, with open source and commercial options. Its open source license has changed several times in its short history. The version of Ext bundled with Aptana is made available under the Ext license, which is a modified version of the GNU LGPL. The latest version (V2.1) has moved over to a less confusing GPL V3 model.

Unlike Aptana and Ext, Adobe AIR is not an open source platform. While certain components of AIR use open source technologies, such as parts of ActionScript JIT, the runtime itself is not distributed on an open source license. The consequence of this is that Adobe AIR applications will only run on systems that Adobe supports, as the runtime cannot be modified by the open source community. With that in mind, the runtime is available free of charge, and developers can request a free distribution license from Adobe to bundle the AIR installer with their own applications, which provides a more-than-ample means for us to dabble in AIR application development.

System requirements

You'll need the following tools to follow along.

Aptana Studio V1.1 Community Edition
Download the version of Aptana Studio for your operating system from Aptana.com.
Adobe AIR Plug-in for Aptana
Download the Aptana Studio Start Page (covered later in the tutorial).
Adobe AIR Runtime
Install from within Aptana Studio (Help > Install Adobe AIR Runtime) or from Adobe Systems (see Resources for links to production and beta versions of AIR).

Introduction to AIR

In this section, we take a look at the major components involved in implementing an AIR application. We introduce the concepts behind AIR, the Ext framework and Aptana Studio, and how the technologies can be combined to create a desktop application.

What is AIR?

AIR is a runtime environment developed by Adobe Inc. used to deploy desktop applications using technologies that have, up until now, almost exclusively been used in the development of Web applications. As of this writing, AIR is available on the Microsoft® Windows® and Mac OS X, with an alpha version available for Linux®.

AIR works with a host of different Web application development technologies, such as Adobe Flash and Flex, HTML, CSS, JavaScript, and Ajax. This allows highly skilled Web application developers to develop fully functional desktop applications, without having to learn new programming languages. The support for JavaScript means you can now employ powerful JavaScript frameworks, such as Ext, Prototype, and jQuery, in desktop applications.

In addition to simply supporting Web development technologies, AIR also provides access to the local file system, allowing applications to store data on the user's computer, rather than on a central database server. AIR can also store data on a remote server via Web services. This support for local and remote storage allows AIR developers to create applications that can work offline, saving data to the local file system, which will then be synchronized and uploaded to a central server when an Internet connection becomes available.

AIR's local storage options include an encrypted local store and a SQLite database, both bundled with AIR. Data can also be stored in a local XML file.

Other advantages AIR has over traditional browser-based Web applications include the ability to run applications in the background and access to the operating system's clipboard and drag-and-drop events. AIR applications can even be minimized to the system tray.

Because of the nature of AIR applications (desktop applications built with Web technologies), they are vulnerable to security attacks, such as SQL Injection and Cross-site Scripting. To try and reduce the threat of dangerous applications being installed, all AIR applications must be signed with a digital certificate. These certificates can be untrusted self-signed or trusted certificates purchased from a certification authority, such as Verisign or Thawte. To protect applications from being hijacked by fake updates, all updates must use the same certificate as previous versions of the application, or the update will fail.

Support for AIR is increasing rapidly. Several large corporations like eBay, AOL, NASDAQ, and Nickelodeon have all developed powerful applications on the platform.

What is Ext JS?

Ext JS is an advanced JavaScript library that Jack Slocum developed in 2006. In this tutorial we refer to Ext JS as Ext, since that seems common. Keep in mind, however, that there is also a Java version of Ext called Ext GWS, which you do not need to complete this tutorial.

Ext allows Web application developers to create rich Internet applications that look and feel like a desktop application. It does this by providing a large set of controls, which are similar in functionality to the tools found in a visual Integrated Development Environment (IDE). These UI controls are created using JavaScript code (much like Swing controls are created in the Java™ language).

Many of Ext's controls are extended feature-rich versions of standard HTML form controls, such as text fields, text areas, combo boxes, radio buttons, and checkboxes. Others offer functionality that would otherwise be difficult and time-consuming to develop, such as grid controls (which feature inline editing, sorting, pagination, and filtering), progress bars, tabbed panels, drag and drop, and date pickers.

What is Aptana?

Aptana Studio Community Edition is an open source IDE for Web application development. It is based on the Eclipse IDE and can be installed as a stand-alone package or as an Eclipse plug-in. The stand-alone version of Aptana is available on Windows, Mac OS X, and Linux, and the Eclipse plug-in version can be installed on any system that supports Eclipse.

Aptana's strength lies in its powerful JavaScript support that provides features, such as debugging (in Firefox only; Internet Explorer support is included in the commercial Professional Edition of Aptana), code assist, and code outlining. This support is also available for HTML and CSS code.

Aptana also features built-in support and code assistance for a host of JavaScript frameworks that empower developers who want to develop Web 2.0 applications. These frameworks, which include Ext, jQuery, Prototype, script.aculo.us, Dojo, Mootools, and others, can be added to any Aptana project easily.

Aptana can be extended to support technologies that are not available out of the box currently, such as PHP, Ruby on Rails, and, of course, AIR. There's even a plug-in available to help create Web applications for the Apple iPhone.

We will use Aptana to develop the sample application. We have chosen it over alternatives like Adobe Dreamweaver CS3 for a number of reasons, most notably because the Community Edition is available for download free of charge on an open source license and because Aptana has excellent support for Ext and AIR.


Setting up the development environment

To best introduce you to the development of AIR applications that employ the Ext framework, we are going to develop a sample application. We need to have a suitable development environment set up. This section will guide you through the process of installing Aptana, adding the Adobe AIR plug-in to Aptana, and installing the Adobe AIR Runtime.

Installing Aptana Studio

For the purpose of this tutorial, we will install Aptana Studio on Microsoft Windows, but you can install this on a machine running Mac OS X or Linux. Download it from the Aptana Web site (see System requirements). We will use the full installer, but if you are comfortable doing so, you can also install Aptana manually from the ZIP file option. The installer weighs in at just under 100 MB, so it's preferable to download the file on a high-speed connection. The download will generally take less than 15 minutes on an average broadband connection.

Once the download has completed, open the installer file (Aptana_Studio_Setup.exe on Windows), which will unpack the installer to your hard disk and start the installation application, which should look like Figure 1.

Figure 1. Aptana Studio Installer -- Welcome screen
Aptana Studio Installer - Welcome screen

On this screen, click Next to move on to the License Agreement screen and agree to the terms to continue with installation. You will be asked to select an installation destination folder (see Figure 2).

Figure 2. Select installation folder screen
Select installation folder screen

The default (on Windows) is C:\Program Files\Aptana\Aptana Studio. To install the software in a different location, use Browse to navigate to the location of your choice, then click Next to move on to the next step.

The next screen (see Figure 3) allows you to select the Start Menu folder to add shortcuts to the application. Simply accept the default value here and press Next to continue.

Figure 3. File-type associations screen
File-type associations screen

On this screen (shown in Figure 4), you will be presented with the opportunity to associated file types with Aptana Studio. This tells the operating system to open files of these types with Aptana Studio. If you use another application for day-to-day Web development and are simply trying out Aptana, I recommend you uncheck all of these boxes so these file types continue to be associated with your current editor/IDE. Once you are happy with your selections here, click Next. The screen that follows informs you that setup now has all the information it requires, and the installation routine will begin as soon as you click Install.

Figure 4. Aptana Studio Installer -- Copying-files screen
Aptana Studio Installer -- Copying-files screen

The installer will copy the relevant files to your hard disk. The procedure should only take 2 minutes or less to complete. As soon as it has completed, click Next. The installer will confirm that Aptana has been installed. On this screen, click Close. You will now be asked whether to "Configure my Windows Firewall to enable this Aptana product not to show warnings." Unless you have any good reason not to, leave this checkbox ticked on and click Close to exit the Aptana installer.

You can now start the Aptana application, which can be found in the Start menu (Programs > Aptana > Aptana Studio).

Figure 5. Aptana Workspace launcher
Aptana Workspace launcher

When you run Aptana Studio, it will ask you to select a workspace in which your projects will be stored. On Windows, the default location of this workspace will be in a folder called "Aptana Studio," which can be found in your My Documents folder. You can change this to something else if you wish. To stop Aptana asking you to do this every time it launches, check the option for "Use this as the default and do not ask again" and when you're ready, click OK.

That is all there is to installing Aptana Studio. To develop AIR applications in this IDE, however, there are a couple of other things we need to do.

Installing the AIR plug-in for Aptana

To develop AIR applications using Aptana Studio, we will need to install the AIR plug-in for Aptana. This basically incorporates the AIR SDK into Aptana and provides us with features such as code assist, graphical configuration of the application.xml file, and a simple way to create the digital certificates required to deploy AIR applications.

Figure 6. Aptana start page
Aptana start page

On the Aptana start page, as highlighted in Figure 6, the center column should contain various plug-ins available for Aptana. If you scroll through this column you should find a section that describes how to install the AIR plug-in for Aptana. The first thing you need to do here is click on the Download and install link in step 1 of the "Adobe AIR" section of the plug-ins column (see Figure 7).

Figure 7. Install plug-in screen
Install plugin screen

This should cause a window to pop up that will allow you to install the AIR plug-in. In this window, simply check the box for "Adobe AIR Support" and click Next. You will be asked to review the license agreement for the plug-in. When you are done, select "I accept the terms in the license agreement" and click Next to continue. On the screen that follows, click Finish and the plug-in will be downloaded.

Figure 8. Download Adobe AIR plug-in screen
Download Adobe AIR plug-in screen

When the plug-in files have been downloaded, you will be informed that you are about to install an unsigned feature. You can safely ignore this warning message and click the Install All button, which will install the plug-in. Once the installation is complete, you will be advised to restart Aptana before continuing. Click Yes to do so. Aptana will close and restart automatically.

The final step before we're ready to develop AIR applications in Aptana is to install the Adobe AIR Runtime. Although you can download this independently from Adobe's Web site, Aptana has a simple and convenient alternative.

Installing Adobe AIR Runtime

To install the Adobe AIR Runtime, we can download the installation package directly from Adobe or use a useful menu option in Aptana to make the process even easier. In Aptana, click Help > Install Adobe AIR Runtime to start the AIR setup program.

Figure 9. Install Adobe AIR Runtime option
Install Adobe AIR Runtime option

Installing the AIR Runtime is very simple. You will be presented with a license agreement for the software, as shown in Figure 10. Once you have read the agreement and are ready to install, click I Agree.

Figure 10. License-agreement screen
License-agreement screen

The installation should only take seconds, and once it is finished, you should see a screen similar to that in Figure 11.

Figure 11. Installation completed
Installation completed

Click Finish to close the setup program. That's it! You now have a development environment that can be used to create AIR applications in Aptana Studio. Ext comes bundled with Aptana, so there's no need to install it separately. To download the latest version, feel free to download it from the Ext Web site (see Resources).

In the next section, we will get started with the basics of Aptana: creating AIR projects and running/debugging AIR applications in Aptana.


Creating your first AIR project

Before we start developing the sample application, it's important that you are comfortable with the Aptana development environment, and are aware of the process of creating projects and running and debugging AIR applications. In this section, we will create our first AIR project, which will simply output "Hello World" inside an AIR desktop application window. In the process of doing so, we will explore the configuration options for AIR applications, including changing the application's title-bar icon and choosing the appropriate sandbox for development.

Creating an AIR project in Aptana Studio

Let's get started by creating our AIR project in Aptana Studio. In the main Aptana window, navigate to File > New > Project, which will open the New Project wizard, shown below.

Figure 12. Aptana New Project wizard
Aptana New Project wizard

On this screen, select Adobe AIR Project from the Aptana Projects folder (see Figure 12 above) and Next to continue. We now need to provide a project name, which by default will also determine where our project files will be stored.

Figure 13. Project-name screen
Project-name screen

Enter Hello World into the field for project name. This will set the location automatically. You can change this by unchecking the "Use default location" box and clicking Browse to find the folder to store your project in. For this example, we are going to accept the default location. The Main HTML file application option will also default to HelloWorld.html, which is fine. Don't worry about the rest of the options on this screen; you can accept the default options safely. The next screen (shown below) allows you to configure the application.xml file for your AIR application.

Figure 14. Application XML properties
Application XML properties

This allows you to define fields such as version, description, copyright information, and application icons. Of course, you could also define these in the application.xml file manually, but Aptana makes our lives easier by providing a simple graphical front end for this task. Enter a short description for our sample application if you like and press Next to move on. The application.xml configuration is continued on the next screen.

Figure 15. More application XML properties
More application XML properties

As you can see, you can choose to use the standard system window style (this will vary depending on your operating system) or a custom-built window style. You can also restrict whether the user can minimize, maximize, and resize the application window. We have chosen to prevent the user from maximizing the window. Finally, you can set the dimension options for the project. We have changed the window to be 400x400, with a maximum width of 800x800. Feel free to play around with these settings. Finally, we can choose to import a third-party JavaScript library, such as Ext, jQuery, or Prototype.

Figure 16. Import JavaScript library screen
Import JavaScript library screen

For the purpose of our Hello World application, we don't need the complex functionality provided by these libraries, so we will leave all of these unchecked. When you're ready, press Finish and Aptana will create our AIR project.

As you can see in Figure 17, Aptana will open the main project file when it has finished creating the project (in this case, it will open HelloWorld.html). If you expand the Hello World project folder icon on the Project tab on the left-hand side of the screen, you will see some files Aptana automatically created. Notice how it automatically created the application.xml file for us. If you open this file (double-click on it), you will see the XML markup you would have had to write if Aptana had not provided with its time-saving graphical front end.

Figure 17. The Hello World project environment
The Hello World project environment

Close the application.xml file and you should be looking at the code for HelloWorld.html. We are now going to make a few small adjustments to this code. On line 3, change the content within the <title> tags to Hello World. If you skip down to line 52, insert a line (after the <body> tag) and type in <h1>Hello World</h1>. Before we run our first AIR project, we need to save the changes we made to the HelloWorld.html file. Navigate to File > Save (shortcut: Ctrl+S), and the file will be saved. We are ready to run the application.

Running the application

Running your application from Aptana is easy. Simply click on the Run Hello World button — it looks like a play button — on the main Aptana toolbar (see Figure 18). This will open our application in a new desktop window.

Figure 18. Main Aptana toolbar
Main Aptana toolbar

You should be able to see a window similar to that in Figure 19. As you may have noticed, the text that appears in the title bar of the window is derived from the change we made to the <title> tag in the HelloWorld.html file. You will also notice the level 1 heading we inserted.

Figure 19. Hello World application
Hello World application

There is also a section in the window called Application Sandbox Content. This is sample code that was added to our application by Aptana. In the first list item, you will see a button Read a local file using AIR APIs. Click this and it will pop up an alert window with the contents of the text file LocalFile.txt. Feel free to modify this file and see what happens when you click the button again. This demonstrates how AIR works with the local file system.

If you scroll down through the application window, you will see a doRequest("http://www.adobe.com"); button. If you click on this, the AIR application will pop up another alert box, this time with the HTTP response from Adobe.com. This demonstrates how the XMLHttpRequest object can work with remote Web sites.

You'll notice that the maximize button is disabled, and if you try to decrease the window size, it won't go below 400x400, and if you increase, you will notice it won't stretch out to more than 800x800.

Debugging the application

In Figure 18, you may have noticed the Debug icon. If you click on this, Aptana will display an error message, informing you that the Adobe AIR application debugging is not supported. Luckily, we can use the Adobe AIR Introspector to do some basic debugging on our application. To turn on introspection, simply uncomment line 7 of HelloWorld.html by removing the <!-- from the beginning of the line and the --> from the end of the line. This will include the Introspector in our application.

To see an example of how the Introspector can be used to identify errors and where the source of the problem is, we are going to break our Hello World application. We will simply change the reference to LocalFile.txt on line 15 to LocalFile.txt1. Because this file does not exist, it will cause an error to occur in our application. Once you have made this change, save the HelloWorld.html file and press Run.

The Hello World application should launch once again, and at first, all will appear to be fine. Now, open the Introspector window by pressing F12.

Figure 20. Adobe AIR Introspector -- HelloWorld.html error message
Adobe AIR Introspector -- HelloWorld.html error messag

With the Introspector window open, click on the Read a local file using AIR APIs button in the Hello World application window. An error (3003) should occur, with the message "File or directory does not exist." If you expand the error message by pressing the + icon, you will see a variety of information, such as errorID, getStackTrace, line, sourceURL and more. The most useful item here is the line number, which highlights exactly where the application ran into problems. If you look at the source code for the application, you will see that line 18 is where the program attempts to open a file, f, which is defined on the line we changed a few moments ago. We can fix the error by simply changing the LocalFile.txt1 filename back to LocalFile.txt.

The Introspector also provides useful features like HTML source navigation, which allows you to easily find your way through the areas of the HTML content. It even highlights the section of the application window the content you are exploring when you move your mouse over an item. The Introspector also allows you to browse through the DOM via a tree interface, the assets belonging to the application (any external files linked to from the program and the application's source code).

Now that we have looked at how to create, run and debug AIR applications, we are ready to build our sample application.


Building the sample application

In this section, we will construct the sample application, which is a simple contact-management utility. It will show you how Ext and AIR can be combined to create an attractive application.

End result

As you can see from Figure 21, the application presents a list of contacts in an Ext grid control.

Figure 21. Contact Manager -- The end result
Contact Manager -- The end result

The e-mail addresses are converted to hyperlinks automatically, and the data in the grid can be sorted by simply clicking on a column heading. The File menu has a "New Contact" option that pops up a Window where we can insert a new contact into the grid. There is validation on the e-mail address field and the date of birth field is powered by Ext's powerful DateField control.

The currently selected contact in the grid can be removed by choosing the "Delete Contact" option from the Edit menu or by pressing Delete on your keyboard. The user is asked to confirm whether to delete the contact.

Figure 22. Confirm-delete dialog
Confirm-delete dialog

We also confirm the user wishes to quit the application when they use any method of closing the main application window. The application will minimize to the system tray, where it has a context menu that allows you to open the main application window or exit the application.

Creating the Aptana project

We are going to create a new Aptana project for our sample application. Follow the same directions as described in the previous section for creating a new project. This time around, name the project ContactManager, enter default/minimum window sizes of either 640x480 or 800x600 and make sure you select Ext V2.0.2 from the list of available JavaScript libraries when the wizard asks you to select the libraries you would like to import. When your project has been created, Aptana will open the ContactManager.html file. Before we start, delete the sample code from this file so it is empty. Once you have done this, we are ready to begin developing our application.

Setting up the HTML shell

We are going to create our entire application in the ContactManager.html file. You may be surprised to learn that the application will actually contain very little HTML code. As we will see later, most of our application code will be JavaScript. For now, we are going to create the HTML shell for the application, which will include all the relevant external CSS and JavaScript files we require. The HTML shell can be found in Listing 1.

Listing 1. Application HTML shell
<html>
<head>
            <title>Contact Manager</title>
        
        <!-- Ext Stylesheets -->
<link rel="stylesheet" type="text/css" 
href="lib/ext/resources/css/ext-all.css" />
        <link rel="stylesheet" type="text/css" 
href="lib/ext/air/resources/ext-air.css" />
        <link rel="stylesheet" type="text/css" 
href="lib/ext/resources/css/xtheme-default.css" />
        
<!-- AIR JS files -->
<script type="text/javascript" 
src="AIRIntrospector.js"></script>
<script type="text/javascript" 
src="AIRAliases.js"></script>
        
        <!-- Ext JS files -->
<script type="text/javascript" 
src="lib/ext/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" 
src="lib/ext/ext-all.js"></script>
        <script type="text/javascript" 
src="lib/ext/air/ext-air.js"></script>
<!-- This file must be included or errors will occur -->
<script type="text/javascript" 
src="lib/ext/air/samples/tasks/js/Templates.js">
</script>
            <!-- Our application code will go here -->
<script type="text/javascript">

</script>
</head>

       <body>
            <div style="margin: 5px">
            <div id="contactList"></div>
        </div>
        </body>
</html>

The code is the only HTML we need for our application. We are including various Ext stylesheets required by our program, then the AIR Introspector utility and the relevant Ext JavaScript source files, without which our application will not function. It is important that you include the Templates.js file; otherwise, you will experience Adobe sandbox security errors. It is important that you include all files in the order they are included above or you may get unexpected results.

Setting up the application window

The first part of the application we're going to develop will minimize the program window to the system tray and provide a context menu on the tray icon with options to open the application window or exit (see Listing 2). We will also trap the closing event of the program window and request confirmation that the user wants to exit the application before the window closes.

Listing 2. Minimize to tray
Ext.onReady(function() {
var win = new Ext.air.NativeWindow({
    id: 'mainWindow',
instance: window.nativeWindow,
    //The following set up minimizing to system tray
minimizeToTray: true,
trayIcon: 'icons/AIRApp_16.png',
    trayTip: 'Contact Manager',
    trayMenu: [{
        text: 'Open',
        handler: function() {
            //Activate the main app window
win.activate();
        }
    }, '-', {
        text: 'Exit',
        handler: function() {
            //Activate window to display confirm dialog
win.activate();
            Ext.Msg.show({
                title:'Confirm Exit',
                msg:'Are you sure you wish to exit?',
                buttons:Ext.Msg.YESNO,
                fn: function(btn, text) {
                    if(btn == "yes") {
                        //User clicks yes        
air.NativeApplication.nativeApplication.exit();
                    }
                },
                animEl: 'elId',
                icon: Ext.MessageBox.QUESTION
            });
        }
    }]
});        

//Here we trap the window close event
win.on('closing', function (e) {    
//We need to prevent the default action (i.e. window close)
e.preventDefault();    
    win.activate();            
    Ext.Msg.show({
        title:'Confirm Exit',
        msg:'Are you sure you wish to exit Contact Manager?',
        buttons:Ext.Msg.YESNO,
        fn: function(btn, text) {
            if(btn == "yes") {
            air.NativeApplication.nativeApplication.exit();
            }
        },
        animEl: 'elId',
        icon: Ext.MessageBox.QUESTION
    });
});
});

We create a new Ext NativeWindow object and set the configuration options so it minimizes to the system tray. We also define the context menu and the event handlers for each option. We also trap the closing event of the window and ask the user to confirm before closing the window. It is worth noting the use of the preventDefault() method here, which stops the default action associated with the event from occurring. Without this, the window would close as normal, and the code that follows would not execute.

Creating our data grid

One of the most important features of our application is the Ext grid control, which displays a list of contacts. In this example, we will simply pull these contacts from an array. Of course, the application could be quite easily extended to retrieve contacts from an XML file or a database. Make sure you place the code in Listing 3 just before the last closing statement from Listing 1.

Listing 3. Creating the contacts data grid
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
//JavaScript array with the contacts for the example
var contactData = [
['Edwin van der Sar','edwin@example.com',
'(857) 555-0000','29/10/1970'],
['Gary Neville','gary@example.com',
'(857) 555-9999','18/02/1975'],
     ['Patrice Evra','patrice@example.com',
'(857) 555-2222','15/05/1981'],
    ['Owen Hargreaves','owen@example.com',
'(857) 555-6666','20/01/1981'],
    ['Rio Ferdinand','rio@example.com',
'(857) 555-8888','07/11/1978'],
    ['Wes Brown','wes@example.com',
'(857) 555-1111','13/11/1979'],
    ['Cristiano Ronaldo','cristiano@example.com',
'(857) 555-7777','05/02/1985'],
    ['Anderson','anderson@example.com',
'(857) 555-5555','13/04/1988'],
    ['Louis Saha','louis@example.com',
'(857) 555-3333','08/08/1978'],
    ['Wayne Rooney','wayne@example.com',
'(857) 555-4444','24/11/1985'],
    ['Ryan Giggs','ryan@example.com',
'(857) 555-8800','29/11/1973'],
    ['Ben Foster','ben@example.com',
'(857) 555-3388','03/04/1983'],
    ['Park Ji-Sung','park@example.com',
'(857) 555-4499','25/02/1981'],
    ['Nemanja Vidic','nemanja@example.com',
'(857) 555-9922','21/10/1981'],
    ['Michael Carrick','michael@example.com',
'(857) 555-7746','28/07/1981'],
    ['Nani','nani@example.com',
'(857) 555-8374','17/11/1986'],
    ['Paul Scholes','paul@example.com',
'(857) 555-5732','16/11/1974'],
    ['Gerard Pique','gerard@example.com',
'(857) 555-3243','02/02/1987'],
    ['Ole Gunnar Solskjaer','ole@example.com',
'(857) 555-3235','26/02/1973'],
    ['Dong Fangzhuo','dong@example.com',
'(857) 555-8194','23/01/1985'],
    ['John O\'Shea','john@example.com',
'(857) 555-2432','30/04/1981'],
    ['Jonny Evans','jonny@example.com',
'(857) 555-9437','02/01/1988'],
    ['Darren Fletcher','darren@example.com',
'(857) 555-4634','01/02/1984'],
    ['Danny Simpson','danny@example.com',
'(857) 555-4862','04/01/1987'],
    ['Phil Bardsley','phil@example.com',
'(857) 555-0183','28/06/1985'],
    ['Mikael Silvestre','mikael@example.com',
'(857) 555-3687','09/08/1977']
];

// renderer function to convert emails to hyperlinks
function linkEmail(val){
return '<a href="mailto:' + val + '">' + val + '</a>';
}

// create the data store
var contactStore = new Ext.data.SimpleStore({
fields: [
        {name: 'name'},
        {name: 'email'},
        {name: 'phone'},
        {name: 'dob', type: 'date', dateFormat: 'd/m/Y'}
    ]
});
//Load the contacts from the array into the data store
contactStore.loadData(contactData);

// create the Grid
var contactGrid = new Ext.grid.GridPanel({
    store: contactStore,
columns: [
        {id:'name',header: "Name", width: 120, 
sortable: true, dataIndex: 'name'},
        {header: "Email Address", width: 160, 
sortable: true, renderer: linkEmail, 
dataIndex: 'email'},
        {header: "Phone Number", width: 120, 
sortable: true, dataIndex: 'phone'},
        {header: "Date of Birth", width: 120, 
sortable: true, 
renderer: Ext.util.Format.dateRenderer('d/m/Y'), 
dataIndex: 'dob'}
    ],
    stripeRows: true,
autoExpandColumn: 'name',
    height:420,
    width:620,
    title:'Contact List',
    //The following line stops the user from selecting multiple rows
selModel: new Ext.grid.RowSelectionModel({
        singleSelect: true
    })
});
//Render the Ext Grid to the DIV with ID contactList in our HTML code
contactGrid.render('contactList');
//Select the first row in our grid            
contactGrid.getSelectionModel().selectFirstRow();

We first set up our contacts array, then we create a function called linkEmail, which will take an e-mail address and convert it into an e-mail hyperlink before returning it to the caller. Next, we create a data store, configuring the fields to match our data. Once we have our data store, we load the array data into the store using the loadData method.

Once we have our data set up, we proceed to create a grid. By setting the config option store to contactStore, we are telling our grid to pull the data from the data store we just created. When we have created the code that creates our grid, we tell the grid where it should render on the screen. In this example, we are rendering to the element with the ID contactList.

Adding/deleting contacts

We will now extend the application to allow the user to create a new contact and to delete existing contacts. You need to place the code in Listing 3 between the line shown in Listing 4.

Listing 4. Creating a new contact or deleting existing contacts
Ext.onReady(function() {
//Paste code from Listing 3 here!
var win = new Ext.air.NativeWindow({

Listing 3 - Add/Delete Contact Field Setup
var newForm;
var newWin;
var contactName = new Ext.form.TextField({
    fieldLabel:'Name',
    name:'name',
    anchor:'100%',
    autoShow:true
});
var contactEmail = new Ext.form.TextField({
    fieldLabel:'Email Address',
    name:'email',
    anchor:'100%',
    autoShow:true,
    vtype:'email'
});
var contactPhone = new Ext.form.TextField({
fieldLabel:'Phone Number',
    name:'phone',
    anchor:'100%',
    autoShow:true
});
var contactDOB = new Ext.form.DateField({
    fieldLabel:'Date of Birth',
    name:'dob',
    anchor:'100%',
    format:'d/m/Y',
    autoShow:true
});

Listing 4 doesn't add anything to our application from a visual point of view. It simply creates the variables for our new pop-up "Create New Contact" window, form, and form fields. The code in Listing 4 will take these variables and implement the GUI controls for each. It will also allow the user to delete a contact by selecting the contact and using the Delete menu option (under Edit), as shown in Listing 5. You'll need to add this code after the code that traps the closing event and before the code for the grid.

Listing 5. Add/delete contact functionality
var actions = {
    //Ext Action for creating a new contact
newContact : new Ext.Action({
        text: 'New Contact',
        handler: function() {
            //if window being opened for first time
if (newWin === undefined || newWin == undefined) {
                //create our FormPanel for the new contact
newForm = new Ext.form.FormPanel({
                    baseCls: 'x-plain',
                    labelWidth: 95,
                    defaultType: 'textfield',
                    autoShow: true,
                    items: [contactName, contactEmail,
                         contactPhone, contactDOB]
                });
                //create a new Window for the form
newWin = new Ext.Window({
                    title: 'Create New Contact',
                    resizable: false,
                    width: 300,
                    height: 200,
                    layout: 'fit',
                    bodyStyle: 'padding:5px;',
                    closeAction: 'hide',
                    plain: true,
                    items: newForm,
                    buttons: [{
                        //This button will add a new record
text: 'Submit',
                        handler: function(){
contactStore.insert(0, new Ext.data.Record({
name: contactName.getValue(),
email: contactEmail.getValue(),
phone: contactPhone.getValue(),
                        dob: contactDOB.getValue()
                        }));
                        //hide popup window
newWin.hide();
                        //reset form values
contactName.setRawValue();
                        contactEmail.setRawValue();
                        contactPhone.setRawValue();
                        contactDOB.setRawValue();
contactGrid.getSelectionModel().selectFirstRow();
                        }
                    }, {
                        text: 'Cancel',
                        handler: function(){
                            //hide popup window
newWin.hide();
                        }
                    }]
                });
            }
            newWin.show(this);
        }
    }),
    //action to delete the currently selected contact
deleteContact: new Ext.Action({
        text: 'Delete Contact',
        handler: function() {
            //make sure a contact is currently selected
if (contactGrid.getSelectionModel().getCount() == 1){
                //Ask user to confirm they want to delete
Ext.Msg.show({
                    title: 'Confirm Delete',
                    msg: 'Are you sure you wish to delete this contact?',
                    buttons: Ext.Msg.YESNO,
                    fn: function(btn, text){
                        if (btn == "yes") {
                            //remove the contact
contactStore.remove(contactGrid.getSelectionModel().getSelected());
contactGrid.getSelectionModel().selectFirstRow();
                        }
                    },
                    animEl: 'elId',
                    icon: Ext.MessageBox.QUESTION
                });    
            }
        }
    }),
    quit: new Ext.Action({
        text: 'Exit',
        handler: function() {
            Ext.Msg.show({
                title:'Confirm Exit',
                msg:'Are you sure you wish to exit Contact Manager?',
                buttons:Ext.Msg.YESNO,
                fn: function(btn, text) {
                    if(btn == "yes") {
air.NativeApplication.nativeApplication.exit();
                    }
                },
                animEl: 'elId',
                icon: Ext.MessageBox.QUESTION
            });
        }
    }),
    //Action to popup an about alert box
about: new Ext.Action({
        text: 'About',
        handler: function() {
        Ext.MessageBox.alert('About Contact Manager', 'Contact Manager version 1.0');
        }
    })
};
                
//Here we created the system menu (File, Edit, Help)
var menus = Ext.air.SystemMenu;
menus.add('File', [
    //We add the actions we created previously
actions.newContact,
    '-',
    actions.quit
]);
menus.add('Edit', [
    actions.deleteContact
]);
menus.add('Help', [
actions.about
]);

Let's take the most important sections of Listing 5 and discuss them individually. For each piece of functionality here — creating a new contact, deleting an existing contact, exiting the application and displaying the About box — we have created an action, a piece of code which will perform a particular function and can be used in more than one place. For example, we could extend our application to include a toolbar and reuse the actions here, rather than having to redefine the functions.

The first action we created is the newContact action. This will pop up a window in our application on which will be a form that the user can enter a name, e-mail address, phone number, and date of birth for the contact they wish to add to the grid. The e-mail field will be validated, and if you enter an invalid e-mail address, the e-mail field will be highlighted to indicate that there is an error. Similarly, the date of birth field features date validation (dd/mm/yyyy) and a powerful date-picker control that will allow the user to easily select the date looking for without having to enter it manually. When the user submits the form, a new record is inserted into the data store, and the grid will automatically be updated to reflect the new contact.

The next action we have defined here is the deleteContact action, which will handle the removal of a record from the contact list. The action first checks that a row has been selected in the grid, then asks the user to confirm that he wishes to delete that record. If the user chooses Yes, the record is removed from the data store and will disappear from the grid. The quit action handles the user exiting the application and, similar to the delete action, will request that the user confirm the action before actually going ahead and shutting down.

Finally, the about action will simply pop up an alert box with the name and version of the application. Of course, in a real-world application, you may want to expand the About box to be a window with graphics and more information, such as copyright notices, credits, and more.

Now that we have defined our actions, it's time to provide the user with a way of performing them. To do this, we will use menus. The Ext.air.SystemMenu object allows us to create a typical application menu bar, just like you'd expect from a regular desktop application. Our code creates a new menu bar and adds the following structure to it, associating each menu item with its relevant action:

  • File
    • New Contact
    • Exit
  • Edit
    • Delete Contact
  • Help
    • About

We're almost there! Our final code listing allows the user to use their keyboard to delete records. If they use their cursor keys to highlight the record they wish to remove from the grid, they can simply press Delete on their keyboard, and it will call the deleteContact action.

Listing 6. Handling the Delete-key event
contactGrid.on('keydown', function(e){
if(e.getKey() == e.DELETE && !contactGrid.editing){
        actions.deleteContact.execute();
    }
});

To ensure that this functionality works properly, I suggest placing this code just before the final }); in the application. This code will listen for the key-down event, and if it detects that the Delete button was pressed, it will execute the deleteContact action.

Suggested improvements to the application

Although this sample application provides a lot of functionality you would come to expect from a contact-management application, there are a lot of areas where you can improve it. I suggest that you try to implement some of these features to further enhance your knowledge of the technologies discussed in this tutorial. The following are some examples of enhancements that are possible:

  • Allow users to edit contact (perhaps inline grid editing)
  • Store data to a database/XML file
  • Enforce validation on the add contact form
  • Create new fields and store more information about each contact
  • Import/Export vCard contact files

Summary

In this tutorial, we have discussed the Adobe Integrated Runtime (AIR), a powerful means by which to create desktop applications using Web application development technology. We investigated the feature-rich Web development IDE, Aptana Studio, and discovered that while Aptana is open source, AIR is not. We also looked at the Ext JavaScript library and how its desktop-like UI controls would prove useful in creating a desktop application with frameworks typically more suited to the Web.

We also looked at creating AIR projects in Aptana, and we created a sample application using Ext and AIR together. From this, you should be armed with a basic familiarity of how to create AIR applications and a more than ample foundation on which to build your knowledge on the subject.


Download

DescriptionNameSize
Source codeos-ext-air-ContactManager.zip3100KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=321722
ArticleTitle=Use Ext, Aptana, and AIR to build desktop applications
publish-date=07222008