##### Flylib.com

This program, the Garage Editor, is a simple text editor that allows users to open files, save their file, copy and paste, and display help information.

This is a terrific little application because it demonstrates a number of concepts important in the creation of real Java programs.

#### Demonstrates

Creating a basic GUI window, creating scrollbars on demand, creating a toolbar containing menus that contain menu items, how to use the JFileChooser to save and open files, cleanly closing an open document, exiting from an application, displaying informational messages to the user (like JavaScript alerts or Visual Basic MsgBox), using keyboard mnemonics (using key combinations such as Ctrl+S for Save), and using the preferences API to save user-specific preference data regarding how the application is run. In general, this is a pretty tight application, and does all its work in one file.

## LUHN ALGORITHM FOR VALIDATING CREDIT CARDS

The LUHN (or MOD 10) algorithm used for validating credit card numbers is widely known and accepted. Here is how it works:

1. Start at the second digit from the right. Double each alternating digit. (Leave the last digit on the right alone since it is the check).

2. Add each individual digit comprising the products from step 1 to each of the unaffected digits.

3. If the product of step 2 ends in 0 (that is, can be divided by 10 with no remainder), the number is valid.

For example, using 4111111111111111 (the common credit card test number):

number: 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

multiply: 2 2 2 2 2 2 2 2

product: 8 2 2 2 2 2 2 2

Add them up (products are in parens):

(8) + 1 + (2) + 1 + (2) + 1 + (2) + 1 + (2) + 1 + (2) + 1 + (2) + 1 + (2) + 1 = 30

Divide by 10: 30/10 = 3. The number is good. (Because 30 MOD 10) = 0

Running the application and entering some text looks something like what you see in Figure 35.1.

##### Figure 35-1. The running text editor.

This looks like a lot of code, but there are also a lot of comments explaining what's going on.

##### GarageEditor.java

```/**<p>

* Presents a simple editor that allows

* you to create a new file, open a file,

* and save a file.

* <p>

* The chief benefit here is that you can see

* how to interact with a meaningful program

* without getting bogged down by layout manager

* details.

* <p>

* <p>

* Shows how to attach commands to be invoked when

* an item is clicked.

* <p>

* Shows how to use common keystrokes for commands (ie,

* press CTRL+S on the keyboard to Save the file).

* <p>

* Shows how to read files in and out for editing.

* <p>

* Shows how to use OK/Cancel dialogs

* <p>

* Shows how to use user preferences

* </p>

* Could benefit from threading to improve

* responsiveness.

* @author Eben Hewitt

* @see JFrame

* @see JTextArea

* @see JOptionPane

**/

import java.io.*;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import java.util.prefs.*;

public class GarageEditor extends JFrame {

//holds user preferences

private Preferences prefs = null;

//the user will type into this

private JTextArea textArea;

//lets you easily specify where you want

messages to go.

private static final int STDOUT = 0;

private static final int ALERT = 1;

private static final String NEW_CMD = "New";

//default location at which to open window

private static final int DEF_WINDOW_X_LOCATION = 150;

private static final int DEF_WINDOW_Y_LOCATION = 150;

public GarageEditor() {

// window, and show it on the screen. The

// first line of this routine calls the

// constructor from the superclass to specify

// a title for the window. The pack() command

// sets the size of the window to

// be just large enough to hold its contents.

super("Garage Editor");

//put the completed menu bar into

the frame

//create a new JTextArea

//give it some default text and set its size

int rows = 25;

int cols = 35;

textArea = new JTextArea("choose

file...",

rows, cols);

//white by default anyway, but highlights it

textArea.setBackground(Color.WHITE);

textArea.setMargin(new Insets(3,3,3,3));

//make a set of scrolling controls to hold

//the text area

JScrollPane scroller =

new JScrollPane(textArea);

//put the scroller into the content pane

setContentPane(scroller);

//stop app when user closes window

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

pack();

doLocation();

//show the frame

setVisible(true);

}

/**

* Sets up the location of the window using

* preferences data. Opens the editor in the

* last location that the user had it in. If

* not set, use a default value defined in

* class constants above.

*/

private void doLocation() {

//get reference to preferences

Preferences prefs = Preferences.userNodeForPackage(this.getClass());

//retrieve the int. if there is no int stored

//in prefs of the given string name, use the

default

int xLocation = prefs.getInt("WINDOW_X_LOCATION",

DEF_WINDOW_X_LOCATION);

int yLocation = prefs.getInt("WINDOW_Y_LOCATION",

DEF_WINDOW_Y_LOCATION);

//open the window at either the last

//user location, or the default

setLocation(xLocation,yLocation);

}

/**

* @return JMenu containing the New, Open, Save,

* and Exit items

*/

//get the action command from the menu

//to determine what the user wants to do

//and call a separate method to do the

//dirty work

ActionListener listener = new

ActionListener() {

public void actionPerformed(ActionEvent

event) {

String command = event.getActionCommand();

if (command.equals("New")){

doNew();

}

else if(command.equals("Open...")){

doOpen();

}

else if(command.equals("Save...")){

doSave();

}

else if(command.equals("Close")){

doClose();

}

else if (command.equals("Exit")){

doExit();

}

}

};

//NEW

newCmd.setAccelerator(KeyStroke.getKeyStroke

("ctrl N"));

//OPEN

openCmd.setAccelerator(KeyStroke

.            getKeyStroke("ctrl O"));

//SAVE

saveCmd.setAccelerator(KeyStroke

.            getKeyStroke("ctrl S"));

//CLOSE

closeCmd.setAccelerator(KeyStroke

.            getKeyStroke("ctrl L"));

//QUIT

exitCmd.setAccelerator(KeyStroke

.getKeyStroke("ctrl E"));

}

/**

*/

//get the action command from the menu

//to determine what the user wants to do

//and call a separate method to do the

//dirty work

ActionListener listener = new ActionListener() {

public void actionPerformed(ActionEvent event) {

String command = event.getActionCommand();

}

};

(KeyStroke.getKeyStroke("ctrl A"));

}

JOptionPane.showMessageDialog(this,

"Java Garage Hardcore\nWhoever 2004");

}

private void doNew() {

// Carry out the "New" command from the File menu

// by clearing all the text from the JTextArea.

textArea.setText("");

}

private void doSave() {

// Carry out the Save command by letting the user

// specify an output file and writing the text

// from the JTextArea to that file.

File file; // The file that the user wants

to save.

JFileChooser fd; // File dialog that lets the

//user specify the file.

fd = new JFileChooser(new File("."));

fd.setDialogTitle("Save As...");

int action = fd.showSaveDialog(this);

if (action != JFileChooser.APPROVE_OPTION) {

//user cancelled, so quit the dialog

return;

}

file = fd.getSelectedFile();

if (file.exists()) {

before replacing it

action =

JOptionPane.showConfirmDialog(this,

"Replace existing file?");

if (action !=

JOptionPane.YES_OPTION)

return;

}

try {

//Create a PrintWriter for writing to the

//specified file and write the text from

//the window to that stream.

PrintWriter out = new PrintWriter(new

FileWriter(file));

String contents = textArea.getText();

out.print(contents);

if (out.checkError())

throw new IOException("Error while writing to file.");

out.close();

}

catch (IOException e) {

// Some error has occurred while

trying to write.

// Show an error message.

JOptionPane.showMessageDialog(this,

"IO Exception:\n" +

e.getMessage());

}

}

private void doOpen() {

//open the file the user selected by

//printing its contents to the text area

//will hold the user's file

File file;

//creates the complete dialog the user

//needs to select file

JFileChooser fd;

//use the current directory

//(specified as ".")

//as a starting place

fd = new JFileChooser(new File("."));

fd.setDialogTitle("Select a File...");

int action = fd.showOpenDialog(this);

if (action != JFileChooser.APPROVE_OPTION) {

return;

}

//set the file to what the user selected

file = fd.getSelectedFile();

try {

//reset the text area to be blank

textArea.setText("");

String lines = "";

int lineCt = 0;

String str;

while ((str = in.readLine()) != null) {

lines += str + "\n";

}

textArea.setText(lines);

in.close();

} catch (Exception e) {

JOptionPane.showMessageDialog(this,

"Unable to open file:\n" + e.getMessage());

}

}

private void doClose(){

Object[] options = { "OK", "CANCEL" };

int action =

JOptionPane.showOptionDialog(null,

"OK to close without

saving?", "Closing",

JOptionPane.DEFAULT_OPTION,

JOptionPane.WARNING_MESSAGE,

null, options, options[0]);

if (action == JOptionPane.OK_OPTION) {

//reset the text area

textArea.setText("");

return;

} else {

//do nothing and leave their

file alone

return;

}

}

/**

* Exit the application and stop the VM.

*/

private void doExit() {

//store the current location of the window

//as a user preference so we can open it here

//next time

Preferences prefs =

Preferences.userNodeForPackage

(this.getClass());

prefs.putInt("WINDOW_X_LOCATION", getX());

prefs.putInt("WINDOW_Y_LOCATION", getY());

// stop the application

System.exit(0);

}

/**

* Allows you to easily switch logging locations.

* You could add a FILE case here too for moving

* into production.

* @param msg

* @param type

*/

private void log(String msg, int type){

switch (type){

default : //fall through

case STDOUT:

System.out.println(">" + msg);

break;

JOptionPane.showMessageDialog(this, msg);

break;

}

}

public static void main(String[] args) {

//start the application

new GarageEditor();

}

}
```

#### Results

We can enter some text, and then save the file just as you'd expect. Let's do that and then open it in a browser to prove that it works (see Figure 35.2).

##### Figure 35.2. Entering text into the editor is a breeze .

We also use the file chooser to browse to a local file (see Figure 35.3).

##### Figure 35.3. Using the JFileChooser.

If we open an existing file written in XML, such as the Eclipse project file, we see that the program honors the line breaks, tabs, and so forth that were already present in the file (see Figure 35.4).

##### Figure 35.4. The editor honors formatting.

If you choose to close an open document without saving, the app asks if you're sure you know what you're doing. If you choose OK, changes are not saved; if you choose Cancel, you are returned to the editor (see Figure 35.5).

##### Figure 35.5. The JOptionPane at work.

When you perform an action on the editor, you see the toolbar containing the File and Help menus. Choose a menu, and you see its items (see Figure 35.6).