I Was a Teenage Thought PolicemanI remember an early database, MacLion, which was a bad port of a DOS application, right down to the 24-by-80 monospaced scrolling text window. Boy, it was ugly. It eventually lost in the marketplace. Apple also spent a lot of time working with major DOS application vendors to get them to “get it” about the graphic user interface. Lotus received a lot of personal attention from Apple for their Jazz product, and later 1-2-3 for Mac.
But the folklore that has come down through the years is that Apple defended the purity of the interface by punishing the developers who built applications that broke the rules. And that’s just not true. The rules were vague; they were revised several times over the first five years; we broke the rules ourselves (starting early, with MacPaint); and to tell you the truth, we were so desperate for software that we even put that ugly, DOSish MacLion on our poster of the first 100 apps.
The truth is that the punishment for inconsistency came from the Mac community itself. Magazine reviewers and pundits were the first to appreciate the consistency and simplicity of Mac applications, especially in contrast with the growing mess in the DOS world. Influential users and purchasers followed suit. Programs with inconsistent interfaces did suffer; but they suffered at the hands of the marketplace, not of a dictatorial Apple.
Eclipse
Azureus
RSSOwl
Mac OS X 10.3 (Panther) or later
Java 1.4.2 or later
swt-3.1-carbon-macosx-ppc.zip which you can get from http://download.eclipse.org/eclipse/downloads/drops/R-3.1-200506271435/index.php#swt
Create a new Java Project and name it XSWT.
Add the SWT jar files to the project's buildpath:
org.eclipse.swt.carbon.macosx.ppc_3.1.0.jar
org.eclipse.swt_3.1.0.jar
These are probably in /Applications/Eclipse/plugins
These instructions are for Eclipse 3.1 final. Details seem to change with each milestone.
Or just import org.eclipse.swt.*
The Macintosh computer sports the most jumbled-up, inconsistent, confusing interface ever made, with the exception of those of all the other computers.Tog on Interface
Run Application
How many things are wrong?
How many things are right?
Menu bar is on top of screen
The Application menu is set up
Command keys use command, not Ctrl
Set Font
Window minimization
Something goes in the dock
Uses the real Mac Save File dialog
About Address Book is in the Help menu, not the Application Menu
The Name in the Application menu is SWT, not "AddressBook"
Generic dock icon
Menu bar disappears when dialog is shown
File/Exit
No Cut menu item
No Undo/Redo
Edit... on top
About Address Book is in the Help menu, not the application
Save is not enabled after first edit
Application closes when last window is closed
Uses ".adr" file extensions to identify file rather than creator and type codes
Shows .DS_Store when opening files
Find Next is F3; should be Command-G
final static boolean thisIsAMac = System.getProperty("mrj.version") != null;
Tog on InterfaceUsers believe in the menu bar. The menu bar tells them where they are: in the safe, protective environment of the Macintosh, where consistency reigns.
The menu bar is the most constant object in the Macintosh. When it disappears, non-computer-oriented users assume they, the users, have moved, navigated, to a different planet, a world where all the rules may have changed. They are no longer within the familiar Macintosh world. And their only known way back, Quit on the menu bar, has been stripped away.
I have seen, during user testing, the very real fear etched on the face of users when the menu bar disappears. I have watched them literally panic as they realize they are trapped in a strange world.
The menu bar goes on top of the screen
Menu Order from left to right:
Apple
Application
File
Edit
...
Help
Typically contains About AppName, Preferences, Services, Hide AppName, Hide Others, Show All, and Quit
Most of this is handled for you by the OS. You do not have to set this menu up yourself.
SWT does not provide Preferences or About hooks though, and there's no Quit Handler :-(
You can plug-in your own code
SWT doesn't make this easy though: http://azureus.aelitis.com/wiki/index.php/PreferencesAndAbout
Apple has hooks for this, but only in Swing and AWT
WordPad Menus:
File:
Edit:
View
Insert
Format:
Help:
TextEdit Menus:
Apple
TextEdit
File
Edit
Format
Window
Help
//File -> Exit.
if (!thisIsAMac) {
new MenuItem(menu, SWT.SEPARATOR);
//File -> Exit.
subItem = new MenuItem(menu, SWT.NULL);
subItem.setText(resAddressBook.getString("Exit"));
subItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
shell.close();
}
});
}
"New" menu item is normally first
It normally doesn't say "New Foo" unless there's also a "New Bar"
Ditto for Open
Normally "File/New" implies a new document and window. New Card should be a separate item.
Command-N implies "File/New" which implies a new document and window.
There should be a separator before the Save
Change "File/Save Address Book" and "File/Save Address Book As..." to "File/Save" and "File/Save As...
This is stored in a resource (good for localization)
Save_address_book = &Save \tCtrl+S
Save_book_as = Save As...\tCtrl+A
Save As... normally doesn't have a command key equivalent
Even if it does Command-A should be reserved for "Select All"
Save_book_as = Save As...\t
The Edit menu always begins like this:
Edit Undo ⌘Z Redo ⇧⌘Z ------------- Cut ⌘X Copy ⌘C Paste ⌘V Delete (or Clear) ------------- Application specific items go here
Necessary fixes:
Add Undo item
Add Cut item
Change "Delete" to "Clear"
Move Edit... after Clear
//Edit -> Undo MenuItem subItem = new MenuItem(menu, SWT.NULL); subItem.setText(resAddressBook.getString("Undo")); subItem.setAccelerator(SWT.MOD1 + 'Z'); new MenuItem(menu, SWT.SEPARATOR); //Edit -> Cut subItem = new MenuItem(menu, SWT.NULL); subItem.setText(resAddressBook.getString("Cut")); subItem.setAccelerator(SWT.MOD1 + 'X'); //Edit -> Copy subItem = new MenuItem(menu, SWT.NULL); subItem.setText(resAddressBook.getString("Copy")); subItem.setAccelerator(SWT.MOD1 + 'C'); subItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { TableItem[] items = table.getSelection(); if (items.length == 0) return; copyBuffer = new String[table.getColumnCount()]; for (int i = 0; i < copyBuffer.length; i++) { copyBuffer[i] = items[0].getText(i); } } }); //Edit -> Paste subItem = new MenuItem(menu, SWT.NULL); subItem.setText(resAddressBook.getString("Paste")); subItem.setAccelerator(SWT.MOD1 + 'V'); subItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (copyBuffer == null) return; TableItem item = new TableItem(table, SWT.NONE); item.setText(copyBuffer); isModified = true; } }); //Edit -> Delete subItem = new MenuItem(menu, SWT.NULL); subItem.setText(resAddressBook.getString("Delete")); subItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { TableItem[] items = table.getSelection(); if (items.length == 0) return; items[0].dispose(); isModified = true; } }); new MenuItem(menu, SWT.SEPARATOR); //Edit -> Edit subItem = new MenuItem(menu, SWT.CASCADE); subItem.setText(resAddressBook.getString("Edit")); subItem.setAccelerator(SWT.MOD1 + 'E'); subItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { TableItem[] items = table.getSelection(); if (items.length == 0) return; editEntry(items[0]); } }); //Edit -> Sort(Cascade) subItem = new MenuItem(menu, SWT.CASCADE); subItem.setText(resAddressBook.getString("Sort")); Menu submenu = createSortMenu(); subItem.setMenu(submenu); return item;
Function keys are very PC specific.
Normally Command-G for Find Next; not F3:
Find_next = Find &Next...\tCtrl+G
About menu goes in the Application menu, not in the Help menu
Help menu should offer help
Help is bound to Help key
Creating a new document should not close the current document.
Opening an existing document should not close the current document.
There should be a File/Close menu item
Closing the last window should not exit the application or hide the menu bar.
Single window applications need different metaphors
Set up a special menu bar to be used when no windows are open.
Add this to your first shell.
Set its size to zero.
Set its location to negative coordinates.
Display the shell.
public Shell openHiddenWindow(Display display) {
createShell(display);
createMenuBar();
shell.setSize(0, 0);
shell.setLocation(-100, -100);
shell.open();
return shell;
}
Be careful if you have any bring to Front/Send to Back/Move Forward/Move backward functionality
Should be set to at least the minimum of the screen size and the smallest size necessary to display the content.
Can be saved with document if user modifies it.
The Hack: Launch from a class in the default package with the right name:
public class MacAddressBook {
public static void main(String[] args) {
com.elharo.swt.examples.AddressBook.main(args);
}
}
The correct way: specified in the Info.plist file
Setup when you export an app from Eclipse.
Demo: Inspect the plist
Command-space bar: Spotlight
Command-tab
Command-option-Esc
Command-control-Eject
Control-Function key
F9, F10, F11: Exposé
F12: Eject/Dashboard
It probably only has one button, but may have more:
Checking for mouse buttons:
public class Mouse {
public static void main(String args[]) {;
System.out.println(java.awt.MouseInfo.getNumberOfButtons());
}
}
Control-click fakes a second mouse button if necessary.
Regardless, don't put anything in a context menu that can't be reached from the regular menus.
Never assume the platform default encoding
Specify the encoding
Prefer UTF-8
Avoid FileWriter
/FileReader
and always specify the encoding for
OutputStreamWriter
/OutputStreamReader
Mac text files tend to end in carriage return (\r) rather than \n or \r\n
When writing a custom, non-text non-XML format don't rely on this.
Never use println()
to output a line break.
Treat .app bundles as files. Don't traverse. Especially don't show their contents to users.
.DS_Store
don't show to user
don't transfer or archive
Avoid hidden files in the home directory (.cvspass, etc.)
Don't store them in the application; multiple users may need them
Put them in ~/Library/ApplicationName directory along with any support files
Or ~/Library/Preferences/ for plist files only
From Java ~ is System.getProperty("user.home")
File/Export... Mac OS X Application Bundle
Choosing a name
Choosing an Icon
Creator Codes:
Four ASCII letters
Not all lower case
Users never see this
Registering a Creator Code: http://developer.apple.com/datatype/creatorcode.html
Mostly designed for Swing/SWT but the non GUI pieces work (or can be copied to work) with SWT
Functionality:
Get and set file types and creator codes.
Find special folders defined by the OS.
Find applications by creator code.
Find resource files in application bundles.
Open URLs in the user's favorite browser.
Handle the Apple events Open Application, Reopen Application, Quit Application, Open Document, and Print Document.
Get the name of the startup disk.
Launch applications as well as open documents, either by the application that created them or by one of your choice.
Stubbed on other non-Mac platforms
Open Source, Artistic License
Mac applications tend to be distributed as disk image files.
Disk images are created with the Disk Utility tool.
Disk images can be compressed; no need for a separate zip step
Demo installing from a disk image
Each disk image contains ideally a single application that can be dragged into the Applications folder.
Demo making a disk image
Apple Installer can do more complicated operations:
Check prerequisites
Show README
Require acceptance of license agreement
Require authorization
Require restart
Run special purpose shell scripts
PackageMaker creates the Install script; /Developer/Applications/Utilities
Free for non-profits/non-commercial/internal enterprise
$250-$1500 for commercial distribution depending on volume
Incompatible with open source licenses
QuickTime and QuickTime for Java are available for Windows and Mac (not Linux)
Handles playback and editing of various media formats (MP3, JPEG, MOV, MPEG, etc.)
But incomplete
Doesn't play well with SWT
Do not use ANY AWT classes in your Swing code or your app will hang when run from inside Eclipse.
Not even classes like java.awt.Font
and java.awt.Color
.
Not even in headless mode. (OK maybe in headless mode in 10.4)
FileMaker | MacLion |
Quark XPress | FrameMaker |
Excel | Lotus 1-2-3 |
Word | WordPerfect |
Microsoft Word 5 | Microsoft Word 6 |
iTunes | WinAmp |
Adobe Illustrator | CorelDraw |
MacroMedia Director-->ShockWave-->Flash | VRML, Java |
This presentation: http://www.cafeaulait.org/slides/eclipseworld2005/macifying/
Apple Human Interface Guidelines: http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/
java-dev mailing list: http://lists.apple.com/mailman/listinfo/java-dev