changeset 106:396a9fa07672

Added addressbook example. Does not yet compile
author Frank Benoit <benoit@tionex.de>
date Fri, 18 Jan 2008 20:53:49 +0100
parents 34e9dc2642d5
children 5ac0a5d00e19
files .hgignore dsss.conf dwt/dwthelper/ResourceBundle.d dwtexamples/addressbook/AddressBook.d dwtexamples/addressbook/DataEntryDialog.d dwtexamples/addressbook/FindListener.d dwtexamples/addressbook/SearchDialog.d
diffstat 7 files changed, 1348 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Jan 18 19:46:33 2008 +0100
+++ b/.hgignore	Fri Jan 18 20:53:49 2008 +0100
@@ -14,8 +14,8 @@
 ^dwtexamples/helloworld/HelloWorld3$
 ^dwtexamples/helloworld/HelloWorld4$
 ^dwtexamples/helloworld/HelloWorld5$
+^dwtexamples/addressbook/AddressBook$
 
 
 
 
-
--- a/dsss.conf	Fri Jan 18 19:46:33 2008 +0100
+++ b/dsss.conf	Fri Jan 18 20:53:49 2008 +0100
@@ -36,4 +36,5 @@
 [dwtexamples/helloworld/HelloWorld3.d]
 [dwtexamples/helloworld/HelloWorld4.d]
 [dwtexamples/helloworld/HelloWorld5.d]
+[dwtexamples/addressbook/AddressBook.d]
 [t.d]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dwthelper/ResourceBundle.d	Fri Jan 18 20:53:49 2008 +0100
@@ -0,0 +1,18 @@
+module dwt.dwthelper.ResourceBundle;
+
+class ResourceBundle {
+
+    public this( char[] name ){
+    }
+
+    public char[] getString( char[] key ){
+        return key;
+    }
+
+    public static ResourceBundle getBundle( char[] name ){
+        return new ResourceBundle( name );
+    }
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtexamples/addressbook/AddressBook.d	Fri Jan 18 20:53:49 2008 +0100
@@ -0,0 +1,915 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwtexamples.addressbook.AddressBook;
+
+
+// /* Imports */
+// import java.io.BufferedReader;
+// import java.io.File;
+// import java.io.FileNotFoundException;
+// import java.io.FileReader;
+// import java.io.FileWriter;
+// import java.io.IOException;
+// import java.util.Arrays;
+// import java.util.Comparator;
+// import java.util.ResourceBundle;
+
+
+import dwt.DWT;
+import dwt.events.MenuAdapter;
+import dwt.events.MenuEvent;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.events.ShellAdapter;
+import dwt.events.ShellEvent;
+import dwt.graphics.Cursor;
+import dwt.layout.FillLayout;
+import dwt.widgets.Display;
+import dwt.widgets.FileDialog;
+import dwt.widgets.Menu;
+import dwt.widgets.MenuItem;
+import dwt.widgets.MessageBox;
+import dwt.widgets.Shell;
+import dwt.widgets.Table;
+import dwt.widgets.TableColumn;
+import dwt.widgets.TableItem;
+
+import dwtexamples.addressbook.SearchDialog;
+import dwtexamples.addressbook.DataEntryDialog;
+
+import dwt.dwthelper.ResourceBundle;
+
+void main() {
+    Display display = new Display();
+    AddressBook application = new AddressBook();
+    Shell shell = application.open(display);
+    while(!shell.isDisposed()){
+        if(!display.readAndDispatch())
+            display.sleep();
+    }
+    display.dispose();
+}
+
+/**
+ * AddressBookExample is an example that uses <code>org.eclipse.swt</code>
+ * libraries to implement a simple address book.  This application has
+ * save, load, sorting, and searching functions common
+ * to basic address books.
+ */
+public class AddressBook {
+
+    private static ResourceBundle resAddressBook;
+    private Shell shell;
+
+    private Table table;
+    private SearchDialog searchDialog;
+
+    private File file;
+    private bool isModified;
+
+    private char[][] copyBuffer;
+
+    private int lastSortColumn= -1;
+
+    private static const char[] DELIMITER = "\t";
+    private static char[][] columnNames;
+
+public this(){
+    if( resAddressBook is null ){
+        resAddressBook = ResourceBundle.getBundle("examples_addressbook");
+        columnNames = [
+            resAddressBook.getString("Last_name"),
+            resAddressBook.getString("First_name"),
+            resAddressBook.getString("Business_phone"),
+            resAddressBook.getString("Home_phone"),
+            resAddressBook.getString("Email"),
+            resAddressBook.getString("Fax") ];
+    }
+}
+public Shell open(Display display) {
+    shell = new Shell(display);
+    shell.setLayout(new FillLayout());
+    shell.addShellListener(new class() ShellAdapter {
+        public void shellClosed(ShellEvent e) {
+            e.doit = closeAddressBook();
+        }
+    });
+
+    createMenuBar();
+
+    searchDialog = new SearchDialog(shell);
+    searchDialog.setSearchAreaNames(columnNames);
+    searchDialog.setSearchAreaLabel(resAddressBook.getString("Column"));
+    searchDialog.addFindListener(new class() FindListener {
+        public bool find() {
+            return findEntry();
+        }
+    });
+
+    table = new Table(shell, DWT.SINGLE | DWT.BORDER | DWT.FULL_SELECTION);
+    table.setHeaderVisible(true);
+    table.setMenu(createPopUpMenu());
+    table.addSelectionListener(new class() SelectionAdapter {
+        public void widgetDefaultSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length > 0) editEntry(items[0]);
+        }
+    });
+    for(int i = 0; i < columnNames.length; i++) {
+        TableColumn column = new TableColumn(table, DWT.NONE);
+        column.setText(columnNames[i]);
+        column.setWidth(150);
+        final int columnIndex = i;
+        column.addSelectionListener(new class() SelectionAdapter {
+            public void widgetSelected(SelectionEvent e) {
+                sort(columnIndex);
+            }
+        });
+    }
+
+    newAddressBook();
+
+    shell.setSize(table.computeSize(DWT.DEFAULT, DWT.DEFAULT).x, 300);
+    shell.open();
+    return shell;
+}
+
+private bool closeAddressBook() {
+    if(isModified) {
+        //ask user if they want to save current address book
+        MessageBox box = new MessageBox(shell, DWT.ICON_WARNING | DWT.YES | DWT.NO | DWT.CANCEL);
+        box.setText(shell.getText());
+        box.setMessage(resAddressBook.getString("Close_save"));
+
+        int choice = box.open();
+        if(choice is DWT.CANCEL) {
+            return false;
+        } else if(choice is DWT.YES) {
+            if (!save()) return false;
+        }
+    }
+
+    TableItem[] items = table.getItems();
+    for (int i = 0; i < items.length; i ++) {
+        items[i].dispose();
+    }
+
+    return true;
+}
+/**
+ * Creates the menu at the top of the shell where most
+ * of the programs functionality is accessed.
+ *
+ * @return      The <code>Menu</code> widget that was created
+ */
+private Menu createMenuBar() {
+    Menu menuBar = new Menu(shell, DWT.BAR);
+    shell.setMenuBar(menuBar);
+
+    //create each header and subMenu for the menuBar
+    createFileMenu(menuBar);
+    createEditMenu(menuBar);
+    createSearchMenu(menuBar);
+    createHelpMenu(menuBar);
+
+    return menuBar;
+}
+
+/**
+ * Converts an encoded <code>char[]</code> to a char[] array representing a table entry.
+ */
+private char[][] decodeLine(char[] line) {
+    if(line is null) return null;
+
+    char[][] parsedLine = new char[][table.getColumnCount()];
+    for(int i = 0; i < parsedLine.length - 1; i++) {
+        int index = line.indexOf(DELIMITER);
+        if (index > -1) {
+            parsedLine[i] = line.substring(0, index);
+            line = line.substring(index + DELIMITER.length(), line.length());
+        } else {
+            return null;
+        }
+    }
+
+    if (line.indexOf(DELIMITER) !is -1) return null;
+
+    parsedLine[parsedLine.length - 1] = line;
+
+    return parsedLine;
+}
+private void displayError(char[] msg) {
+    MessageBox box = new MessageBox(shell, DWT.ICON_ERROR);
+    box.setMessage(msg);
+    box.open();
+}
+private void editEntry(TableItem item) {
+    DataEntryDialog dialog = new DataEntryDialog(shell);
+    dialog.setLabels(columnNames);
+    char[][] values = new char[][table.getColumnCount()];
+    for (int i = 0; i < values.length; i++) {
+        values[i] = item.getText(i);
+    }
+    dialog.setValues(values);
+    values = dialog.open();
+    if (values !is null) {
+        item.setText(values);
+        isModified = true;
+    }
+}
+private char[] encodeLine(char[][] tableItems) {
+    char[] line = "";
+    for (int i = 0; i < tableItems.length - 1; i++) {
+        line += tableItems[i] + DELIMITER;
+    }
+    line += tableItems[tableItems.length - 1] + "\n";
+
+    return line;
+}
+private bool findEntry() {
+    Cursor waitCursor = new Cursor(shell.getDisplay(), DWT.CURSOR_WAIT);
+    shell.setCursor(waitCursor);
+
+    bool matchCase = searchDialog.getMatchCase();
+    bool matchWord = searchDialog.getMatchWord();
+    char[] searchString = searchDialog.getSearchString();
+    int column = searchDialog.getSelectedSearchArea();
+
+    searchString = matchCase ? searchString : searchString.toLowerCase();
+
+    bool found = false;
+    if (searchDialog.getSearchDown()) {
+        for(int i = table.getSelectionIndex() + 1; i < table.getItemCount(); i++) {
+            if (found = findMatch(searchString, table.getItem(i), column, matchWord, matchCase)){
+                table.setSelection(i);
+                break;
+            }
+        }
+    } else {
+        for(int i = table.getSelectionIndex() - 1; i > -1; i--) {
+            if (found = findMatch(searchString, table.getItem(i), column, matchWord, matchCase)){
+                table.setSelection(i);
+                break;
+            }
+        }
+    }
+
+    shell.setCursor(null);
+    waitCursor.dispose();
+
+    return found;
+}
+private bool findMatch(char[] searchString, TableItem item, int column, bool matchWord, bool matchCase) {
+
+    char[] tableText = matchCase ? item.getText(column) : item.getText(column).toLowerCase();
+    if (matchWord) {
+        if (tableText !is null && tableText.equals(searchString)) {
+            return true;
+        }
+
+    } else {
+        if(tableText!is null && tableText.indexOf(searchString) !is -1) {
+            return true;
+        }
+    }
+    return false;
+}
+private void newAddressBook() {
+    shell.setText(resAddressBook.getString("Title_bar") + resAddressBook.getString("New_title"));
+    file = null;
+    isModified = false;
+}
+private void newEntry() {
+    DataEntryDialog dialog = new DataEntryDialog(shell);
+    dialog.setLabels(columnNames);
+    char[][] data = dialog.open();
+    if (data !is null) {
+        TableItem item = new TableItem(table, DWT.NONE);
+        item.setText(data);
+        isModified = true;
+    }
+}
+
+private void openAddressBook() {
+    FileDialog fileDialog = new FileDialog(shell, DWT.OPEN);
+
+    fileDialog.setFilterExtensions(["*.adr;", "*.*"]);
+    fileDialog.setFilterNames(new char[][] [resAddressBook.getString("Book_filter_name") + " (*.adr)",
+                                            resAddressBook.getString("All_filter_name") + " (*.*)"]);
+    char[] name = fileDialog.open();
+
+    if(name is null) return;
+    File file = new File(name);
+    if (!file.exists()) {
+        displayError(resAddressBook.getString("File")~file.getName()~" "~resAddressBook.getString("Does_not_exist"));
+        return;
+    }
+
+    Cursor waitCursor = new Cursor(shell.getDisplay(), DWT.CURSOR_WAIT);
+    shell.setCursor(waitCursor);
+
+    FileReader fileReader = null;
+    BufferedReader bufferedReader = null;
+    char[][] data = new char[][0];
+    try {
+        fileReader = new FileReader(file.getAbsolutePath());
+        bufferedReader = new BufferedReader(fileReader);
+        char[] nextLine = bufferedReader.readLine();
+        while (nextLine !is null){
+            char[][] newData = new char[][data.length + 1];
+            System.arraycopy(data, 0, newData, 0, data.length);
+            newData[data.length] = nextLine;
+            data = newData;
+            nextLine = bufferedReader.readLine();
+        }
+    } catch(FileNotFoundException e) {
+        displayError(resAddressBook.getString("File_not_found") ~ "\n" ~ file.getName());
+        return;
+    } catch (IOException e ) {
+        displayError(resAddressBook.getString("IO_error_read") ~ "\n" ~ file.getName());
+        return;
+    } finally {
+
+        shell.setCursor(null);
+        waitCursor.dispose();
+
+        if(fileReader !is null) {
+            try {
+                fileReader.close();
+            } catch(IOException e) {
+                displayError(resAddressBook.getString("IO_error_close") ~ "\n" ~file.getName());
+                return;
+            }
+        }
+    }
+
+    char[][][] tableInfo = new char[][data.length][table.getColumnCount()];
+    int writeIndex = 0;
+    for (int i = 0; i < data.length; i++) {
+        char[][] line = decodeLine(data[i]);
+        if (line !is null) tableInfo[writeIndex++] = line;
+    }
+    if (writeIndex !is data.length) {
+        char[][][] result = new char[][writeIndex][table.getColumnCount()];
+        System.arraycopy(tableInfo, 0, result, 0, writeIndex);
+        tableInfo = result;
+    }
+    Arrays.sort(tableInfo, new RowComparator(0));
+
+    for (int i = 0; i < tableInfo.length; i++) {
+        TableItem item = new TableItem(table, DWT.NONE);
+        item.setText(tableInfo[i]);
+    }
+    shell.setText(resAddressBook.getString("Title_bar")~fileDialog.getFileName());
+    isModified = false;
+    this.file = file;
+}
+private bool save() {
+    if(file is null) return saveAs();
+
+    Cursor waitCursor = new Cursor(shell.getDisplay(), DWT.CURSOR_WAIT);
+    shell.setCursor(waitCursor);
+
+    TableItem[] items = table.getItems();
+    char[][] lines = new char[][items.length];
+    for(int i = 0; i < items.length; i++) {
+        char[][] itemText = new char[][table.getColumnCount()];
+        for (int j = 0; j < itemText.length; j++) {
+            itemText[j] = items[i].getText(j);
+        }
+        lines[i] = encodeLine(itemText);
+    }
+
+    FileWriter fileWriter = null;
+    try {
+        fileWriter = new FileWriter(file.getAbsolutePath(), false);
+        for (int i = 0; i < lines.length; i++) {
+            fileWriter.write(lines[i]);
+        }
+    } catch(FileNotFoundException e) {
+        displayError(resAddressBook.getString("File_not_found") ~ "\n" ~ file.getName());
+        return false;
+    } catch(IOException e ) {
+        displayError(resAddressBook.getString("IO_error_write") ~ "\n" ~ file.getName());
+        return false;
+    } finally {
+        shell.setCursor(null);
+        waitCursor.dispose();
+
+        if(fileWriter !is null) {
+            try {
+                fileWriter.close();
+            } catch(IOException e) {
+                displayError(resAddressBook.getString("IO_error_close") ~ "\n" ~ file.getName());
+                return false;
+            }
+        }
+    }
+
+    shell.setText(resAddressBook.getString("Title_bar")+file.getName());
+    isModified = false;
+    return true;
+}
+private bool saveAs() {
+
+    FileDialog saveDialog = new FileDialog(shell, DWT.SAVE);
+    saveDialog.setFilterExtensions(["*.adr;",  "*.*"]);
+    saveDialog.setFilterNames(["Address Books (*.adr)", "All Files "]);
+
+    saveDialog.open();
+    char[] name = saveDialog.getFileName();
+
+    if(name.equals("")) return false;
+
+    if(name.indexOf(".adr") !is name.length() - 4) {
+        name += ".adr";
+    }
+
+    File file = new File(saveDialog.getFilterPath(), name);
+    if(file.exists()) {
+        MessageBox box = new MessageBox(shell, DWT.ICON_WARNING | DWT.YES | DWT.NO);
+        box.setText(resAddressBook.getString("Save_as_title"));
+        box.setMessage(resAddressBook.getString("File") ~ file.getName()~" "~resAddressBook.getString("Query_overwrite"));
+        if(box.open() !is DWT.YES) {
+            return false;
+        }
+    }
+    this.file = file;
+    return save();
+}
+private void sort(int column) {
+    if(table.getItemCount() <= 1) return;
+
+    TableItem[] items = table.getItems();
+    char[][][] data = new char[][items.length][table.getColumnCount()];
+    for(int i = 0; i < items.length; i++) {
+        for(int j = 0; j < table.getColumnCount(); j++) {
+            data[i][j] = items[i].getText(j);
+        }
+    }
+
+    Arrays.sort(data, new RowComparator(column));
+
+    if (lastSortColumn !is column) {
+        table.setSortColumn(table.getColumn(column));
+        table.setSortDirection(DWT.DOWN);
+        for (int i = 0; i < data.length; i++) {
+            items[i].setText(data[i]);
+        }
+        lastSortColumn = column;
+    } else {
+        // reverse order if the current column is selected again
+        table.setSortDirection(DWT.UP);
+        int j = data.length -1;
+        for (int i = 0; i < data.length; i++) {
+            items[i].setText(data[j--]);
+        }
+        lastSortColumn = -1;
+    }
+
+}
+/**
+ * Creates all the items located in the File submenu and
+ * associate all the menu items with their appropriate
+ * functions.
+ *
+ * @param   menuBar Menu
+ *              the <code>Menu</code> that file contain
+ *              the File submenu.
+ */
+private void createFileMenu(Menu menuBar) {
+    //File menu.
+    MenuItem item = new MenuItem(menuBar, DWT.CASCADE);
+    item.setText(resAddressBook.getString("File_menu_title"));
+    Menu menu = new Menu(shell, DWT.DROP_DOWN);
+    item.setMenu(menu);
+    /**
+     * Adds a listener to handle enabling and disabling
+     * some items in the Edit submenu.
+     */
+    menu.addMenuListener(new class() MenuAdapter {
+        public void menuShown(MenuEvent e) {
+            Menu menu = cast(Menu)e.widget;
+            MenuItem[] items = menu.getItems();
+            items[1].setEnabled(table.getSelectionCount() !is 0); // edit contact
+            items[5].setEnabled((file !is null) && isModified); // save
+            items[6].setEnabled(table.getItemCount() !is 0); // save as
+        }
+    });
+
+
+    //File -> New Contact
+    MenuItem subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("New_contact"));
+    subItem.setAccelerator(DWT.MOD1 + 'N');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            newEntry();
+        }
+    });
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Edit_contact"));
+    subItem.setAccelerator(DWT.MOD1 + 'E');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            editEntry(items[0]);
+        }
+    });
+
+
+    new MenuItem(menu, DWT.SEPARATOR);
+
+    //File -> New Address Book
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("New_address_book"));
+    subItem.setAccelerator(DWT.MOD1 + 'B');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            if (closeAddressBook()) {
+                newAddressBook();
+            }
+        }
+    });
+
+    //File -> Open
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Open_address_book"));
+    subItem.setAccelerator(DWT.MOD1 + 'O');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            if (closeAddressBook()) {
+                openAddressBook();
+            }
+        }
+    });
+
+    //File -> Save.
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Save_address_book"));
+    subItem.setAccelerator(DWT.MOD1 + 'S');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            save();
+        }
+    });
+
+    //File -> Save As.
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Save_book_as"));
+    subItem.setAccelerator(DWT.MOD1 + 'A');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            saveAs();
+        }
+    });
+
+
+    new MenuItem(menu, DWT.SEPARATOR);
+
+    //File -> Exit.
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Exit"));
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            shell.close();
+        }
+    });
+}
+
+/**
+ * Creates all the items located in the Edit submenu and
+ * associate all the menu items with their appropriate
+ * functions.
+ *
+ * @param   menuBar Menu
+ *              the <code>Menu</code> that file contain
+ *              the Edit submenu.
+ *
+ * @see #createSortMenu()
+ */
+private MenuItem createEditMenu(Menu menuBar) {
+    //Edit menu.
+    MenuItem item = new MenuItem(menuBar, DWT.CASCADE);
+    item.setText(resAddressBook.getString("Edit_menu_title"));
+    Menu menu = new Menu(shell, DWT.DROP_DOWN);
+    item.setMenu(menu);
+
+    /**
+     * Add a listener to handle enabling and disabling
+     * some items in the Edit submenu.
+     */
+    menu.addMenuListener(new class() MenuAdapter {
+        public void menuShown(MenuEvent e) {
+            Menu menu = cast(Menu)e.widget;
+            MenuItem[] items = menu.getItems();
+            int count = table.getSelectionCount();
+            items[0].setEnabled(count !is 0); // edit
+            items[1].setEnabled(count !is 0); // copy
+            items[2].setEnabled(copyBuffer !is null); // paste
+            items[3].setEnabled(count !is 0); // delete
+            items[5].setEnabled(table.getItemCount() !is 0); // sort
+        }
+    });
+
+    //Edit -> Edit
+    MenuItem subItem = new MenuItem(menu, DWT.PUSH);
+    subItem.setText(resAddressBook.getString("Edit"));
+    subItem.setAccelerator(DWT.MOD1 + 'E');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            editEntry(items[0]);
+        }
+    });
+
+    //Edit -> Copy
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Copy"));
+    subItem.setAccelerator(DWT.MOD1 + 'C');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            copyBuffer = new char[][table.getColumnCount()];
+            for (int i = 0; i < copyBuffer.length; i++) {
+                copyBuffer[i] = items[0].getText(i);
+            }
+        }
+    });
+
+    //Edit -> Paste
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Paste"));
+    subItem.setAccelerator(DWT.MOD1 + 'V');
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            if (copyBuffer is null) return;
+            TableItem item = new TableItem(table, DWT.NONE);
+            item.setText(copyBuffer);
+            isModified = true;
+        }
+    });
+
+    //Edit -> Delete
+    subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("Delete"));
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            items[0].dispose();
+            isModified = true;      }
+    });
+
+    new MenuItem(menu, DWT.SEPARATOR);
+
+    //Edit -> Sort(Cascade)
+    subItem = new MenuItem(menu, DWT.CASCADE);
+    subItem.setText(resAddressBook.getString("Sort"));
+    Menu submenu = createSortMenu();
+    subItem.setMenu(submenu);
+
+    return item;
+
+}
+
+/**
+ * Creates all the items located in the Sort cascading submenu and
+ * associate all the menu items with their appropriate
+ * functions.
+ *
+ * @return  Menu
+ *          The cascading menu with all the sort menu items on it.
+ */
+private Menu createSortMenu() {
+    Menu submenu = new Menu(shell, DWT.DROP_DOWN);
+    MenuItem subitem;
+    for(int i = 0; i < columnNames.length; i++) {
+        subitem = new MenuItem (submenu, DWT.NONE);
+        subitem.setText(columnNames [i]);
+        final int column = i;
+        subitem.addSelectionListener(new class() SelectionAdapter {
+            public void widgetSelected(SelectionEvent e) {
+                sort(column);
+            }
+        });
+
+    }
+
+    return submenu;
+}
+
+/**
+ * Creates all the items located in the Search submenu and
+ * associate all the menu items with their appropriate
+ * functions.
+ *
+ * @param   menuBar Menu
+ *              the <code>Menu</code> that file contain
+ *              the Search submenu.
+ */
+private void createSearchMenu(Menu menuBar) {
+    //Search menu.
+    MenuItem item = new MenuItem(menuBar, DWT.CASCADE);
+    item.setText(resAddressBook.getString("Search_menu_title"));
+    Menu searchMenu = new Menu(shell, DWT.DROP_DOWN);
+    item.setMenu(searchMenu);
+
+    //Search -> Find...
+    item = new MenuItem(searchMenu, DWT.NONE);
+    item.setText(resAddressBook.getString("Find"));
+    item.setAccelerator(DWT.MOD1 + 'F');
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            searchDialog.setMatchCase(false);
+            searchDialog.setMatchWord(false);
+            searchDialog.setSearchDown(true);
+            searchDialog.setSearchString("");
+            searchDialog.setSelectedSearchArea(0);
+            searchDialog.open();
+        }
+    });
+
+    //Search -> Find Next
+    item = new MenuItem(searchMenu, DWT.NONE);
+    item.setText(resAddressBook.getString("Find_next"));
+    item.setAccelerator(DWT.F3);
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            searchDialog.open();
+        }
+    });
+}
+
+/**
+ * Creates all items located in the popup menu and associates
+ * all the menu items with their appropriate functions.
+ *
+ * @return  Menu
+ *          The created popup menu.
+ */
+private Menu createPopUpMenu() {
+    Menu popUpMenu = new Menu(shell, DWT.POP_UP);
+
+    /**
+     * Adds a listener to handle enabling and disabling
+     * some items in the Edit submenu.
+     */
+    popUpMenu.addMenuListener(new class() MenuAdapter {
+        public void menuShown(MenuEvent e) {
+            Menu menu = cast(Menu)e.widget;
+            MenuItem[] items = menu.getItems();
+            int count = table.getSelectionCount();
+            items[2].setEnabled(count !is 0); // edit
+            items[3].setEnabled(count !is 0); // copy
+            items[4].setEnabled(copyBuffer !is null); // paste
+            items[5].setEnabled(count !is 0); // delete
+            items[7].setEnabled(table.getItemCount() !is 0); // find
+        }
+    });
+
+    //New
+    MenuItem item = new MenuItem(popUpMenu, DWT.PUSH);
+    item.setText(resAddressBook.getString("Pop_up_new"));
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            newEntry();
+        }
+    });
+
+    new MenuItem(popUpMenu, DWT.SEPARATOR);
+
+    //Edit
+    item = new MenuItem(popUpMenu, DWT.PUSH);
+    item.setText(resAddressBook.getString("Pop_up_edit"));
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            editEntry(items[0]);
+        }
+    });
+
+    //Copy
+    item = new MenuItem(popUpMenu, DWT.PUSH);
+    item.setText(resAddressBook.getString("Pop_up_copy"));
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            copyBuffer = new char[][table.getColumnCount()];
+            for (int i = 0; i < copyBuffer.length; i++) {
+                copyBuffer[i] = items[0].getText(i);
+            }
+        }
+    });
+
+    //Paste
+    item = new MenuItem(popUpMenu, DWT.PUSH);
+    item.setText(resAddressBook.getString("Pop_up_paste"));
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            if (copyBuffer is null) return;
+            TableItem item = new TableItem(table, DWT.NONE);
+            item.setText(copyBuffer);
+            isModified = true;
+        }
+    });
+
+    //Delete
+    item = new MenuItem(popUpMenu, DWT.PUSH);
+    item.setText(resAddressBook.getString("Pop_up_delete"));
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            TableItem[] items = table.getSelection();
+            if (items.length is 0) return;
+            items[0].dispose();
+            isModified = true;
+        }
+    });
+
+    new MenuItem(popUpMenu, DWT.SEPARATOR);
+
+    //Find...
+    item = new MenuItem(popUpMenu, DWT.PUSH);
+    item.setText(resAddressBook.getString("Pop_up_find"));
+    item.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            searchDialog.open();
+        }
+    });
+
+    return popUpMenu;
+}
+
+/**
+ * Creates all the items located in the Help submenu and
+ * associate all the menu items with their appropriate
+ * functions.
+ *
+ * @param   menuBar Menu
+ *              the <code>Menu</code> that file contain
+ *              the Help submenu.
+ */
+private void createHelpMenu(Menu menuBar) {
+
+    //Help Menu
+    MenuItem item = new MenuItem(menuBar, DWT.CASCADE);
+    item.setText(resAddressBook.getString("Help_menu_title"));
+    Menu menu = new Menu(shell, DWT.DROP_DOWN);
+    item.setMenu(menu);
+
+    //Help -> About Text Editor
+    MenuItem subItem = new MenuItem(menu, DWT.NONE);
+    subItem.setText(resAddressBook.getString("About"));
+    subItem.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            MessageBox box = new MessageBox(shell, DWT.NONE);
+            box.setText(resAddressBook.getString("About_1") + shell.getText());
+            box.setMessage(shell.getText() + resAddressBook.getString("About_2"));
+            box.open();
+        }
+    });
+}
+
+/**
+ * To compare entries (rows) by the given column
+ */
+private class RowComparator : Comparator {
+    private int column;
+
+    /**
+     * Constructs a RowComparator given the column index
+     * @param col The index (starting at zero) of the column
+     */
+    public this(int col) {
+        column = col;
+    }
+
+    /**
+     * Compares two rows (type char[][]) using the specified
+     * column entry.
+     * @param obj1 First row to compare
+     * @param obj2 Second row to compare
+     * @return negative if obj1 less than obj2, positive if
+     *          obj1 greater than obj2, and zero if equal.
+     */
+    public int compare(Object obj1, Object obj2) {
+        char[][] row1 = cast(char[][])obj1;
+        char[][] row2 = cast(char[][])obj2;
+
+        return row1[column].compareTo(row2[column]);
+    }
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtexamples/addressbook/DataEntryDialog.d	Fri Jan 18 20:53:49 2008 +0100
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwtexamples.addressbook.DataEntryDialog;
+
+import dwt.DWT;
+import dwt.events.ModifyEvent;
+import dwt.events.ModifyListener;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Composite;
+import dwt.widgets.Display;
+import dwt.widgets.Label;
+import dwt.widgets.Shell;
+import dwt.widgets.Text;
+
+import dwt.dwthelper.ResourceBundle;
+
+/**
+ * DataEntryDialog class uses <code>org.eclipse.swt</code>
+ * libraries to implement a dialog that accepts basic personal information that
+ * is added to a <code>Table</code> widget or edits a <code>TableItem</code> entry
+ * to represent the entered data.
+ */
+public class DataEntryDialog {
+
+    private static ResourceBundle resAddressBook;
+
+    Shell shell;
+    char[][] values;
+    char[][] labels;
+
+public this(Shell parent) {
+    if( resAddressBook is null ){
+        resAddressBook = ResourceBundle.getBundle("examples_addressbook");
+    }
+    shell = new Shell(parent, DWT.DIALOG_TRIM | DWT.PRIMARY_MODAL);
+    shell.setLayout(new GridLayout());
+}
+
+private void addTextListener(Text text) {
+    text.addModifyListener(new class(test) ModifyListener {
+        Test text;
+        this( Text text ){ this.text = text; }
+        public void modifyText(ModifyEvent e){
+            Integer index = (Integer)(this.text.getData("index"));
+            values[index.intValue()] = this.text.getText();
+        }
+    });
+}
+private void createControlButtons() {
+    Composite composite = new Composite(shell, DWT.NONE);
+    composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
+    GridLayout layout = new GridLayout();
+    layout.numColumns = 2;
+    composite.setLayout(layout);
+
+    Button okButton = new Button(composite, DWT.PUSH);
+    okButton.setText(resAddressBook.getString("OK"));
+    okButton.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            shell.close();
+        }
+    });
+
+    Button cancelButton = new Button(composite, DWT.PUSH);
+    cancelButton.setText(resAddressBook.getString("Cancel"));
+    cancelButton.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            values = null;
+            shell.close();
+        }
+    });
+
+    shell.setDefaultButton(okButton);
+}
+
+private void createTextWidgets() {
+    if (labels is null) return;
+
+    Composite composite = new Composite(shell, DWT.NONE);
+    composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+    GridLayout layout= new GridLayout();
+    layout.numColumns = 2;
+    composite.setLayout(layout);
+
+    if (values is null)
+        values = new char[][labels.length];
+
+    for (int i = 0; i < labels.length; i++) {
+        Label label = new Label(composite, DWT.RIGHT);
+        label.setText(labels[i]);
+        Text text = new Text(composite, DWT.BORDER);
+        GridData gridData = new GridData();
+        gridData.widthHint = 400;
+        text.setLayoutData(gridData);
+        if (values[i] !is null) {
+            text.setText(values[i]);
+        }
+        text.setData("index", new Integer(i));
+        addTextListener(text);
+    }
+}
+
+public char[][] getLabels() {
+    return labels;
+}
+public char[] getTitle() {
+    return shell.getText();
+}
+/**
+ * Returns the contents of the <code>Text</code> widgets in the dialog in a
+ * <code>char[]</code> array.
+ *
+ * @return  char[][]
+ *          The contents of the text widgets of the dialog.
+ *          May return null if all text widgets are empty.
+ */
+public char[][] getValues() {
+    return values;
+}
+/**
+ * Opens the dialog in the given state.  Sets <code>Text</code> widget contents
+ * and dialog behaviour accordingly.
+ *
+ * @param   dialogState int
+ *                  The state the dialog should be opened in.
+ */
+public char[][] open() {
+    createTextWidgets();
+    createControlButtons();
+    shell.pack();
+    shell.open();
+    Display display = shell.getDisplay();
+    while(!shell.isDisposed()){
+        if(!display.readAndDispatch())
+            display.sleep();
+    }
+
+    return getValues();
+}
+public void setLabels(char[][] labels) {
+    this.labels = labels;
+}
+public void setTitle(char[] title) {
+    shell.setText(title);
+}
+/**
+ * Sets the values of the <code>Text</code> widgets of the dialog to
+ * the values supplied in the parameter array.
+ *
+ * @param   itemInfo    char[][]
+ *                      The values to which the dialog contents will be set.
+ */
+public void setValues(char[][] itemInfo) {
+    if (labels is null) return;
+
+    if (values is null)
+        values = new char[][labels.length];
+
+    int numItems = Math.min(values.length, itemInfo.length);
+    for(int i = 0; i < numItems; i++) {
+        values[i] = itemInfo[i];
+    }
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtexamples/addressbook/FindListener.d	Fri Jan 18 20:53:49 2008 +0100
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwtexamples.addressbook.FindListener;
+
+
+public interface FindListener {
+
+public bool find();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtexamples/addressbook/SearchDialog.d	Fri Jan 18 20:53:49 2008 +0100
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwtexamples.addressbook.SearchDialog;
+
+
+import dwt.DWT;
+import dwt.events.ModifyEvent;
+import dwt.events.ModifyListener;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.events.ShellAdapter;
+import dwt.events.ShellEvent;
+import dwt.layout.FillLayout;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Combo;
+import dwt.widgets.Composite;
+import dwt.widgets.Group;
+import dwt.widgets.Label;
+import dwt.widgets.MessageBox;
+import dwt.widgets.Shell;
+import dwt.widgets.Text;
+
+import dwt.dwthelper.ResourceBundle;
+
+/**
+ * SearchDialog is a simple class that uses <code>org.eclipse.swt</code>
+ * libraries to implement a basic search dialog.
+ */
+public class SearchDialog {
+
+    private static ResourceBundle resAddressBook;
+
+    Shell shell;
+    Text searchText;
+    Combo searchArea;
+    Label searchAreaLabel;
+    Button matchCase;
+    Button matchWord;
+    Button findButton;
+    Button down;
+    FindListener findHandler;
+
+/**
+ * Class constructor that sets the parent shell and the table widget that
+ * the dialog will search.
+ *
+ * @param parent    Shell
+ *          The shell that is the parent of the dialog.
+ */
+public this(Shell parent) {
+    if( resAddressBook is null ){
+        resAddressBook = ResourceBundle.getBundle("examples_addressbook");
+    }
+    shell = new Shell(parent, DWT.CLOSE | DWT.BORDER | DWT.TITLE);
+    GridLayout layout = new GridLayout();
+    layout.numColumns = 2;
+    shell.setLayout(layout);
+    shell.setText(resAddressBook.getString("Search_dialog_title"));
+    shell.addShellListener(new class() ShellAdapter{
+        public void shellClosed(ShellEvent e) {
+            // don't dispose of the shell, just hide it for later use
+            e.doit = false;
+            shell.setVisible(false);
+        }
+    });
+
+    Label label = new Label(shell, DWT.LEFT);
+    label.setText(resAddressBook.getString("Dialog_find_what"));
+    searchText = new Text(shell, DWT.BORDER);
+    GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
+    gridData.widthHint = 200;
+    searchText.setLayoutData(gridData);
+    searchText.addModifyListener(new class() ModifyListener {
+        public void modifyText(ModifyEvent e) {
+            bool enableFind = (searchText.getCharCount() !is 0);
+            findButton.setEnabled(enableFind);
+        }
+    });
+
+    searchAreaLabel = new Label(shell, DWT.LEFT);
+    searchArea = new Combo(shell, DWT.DROP_DOWN | DWT.READ_ONLY);
+    gridData = new GridData(GridData.FILL_HORIZONTAL);
+    gridData.widthHint = 200;
+    searchArea.setLayoutData(gridData);
+
+    matchCase = new Button(shell, DWT.CHECK);
+    matchCase.setText(resAddressBook.getString("Dialog_match_case"));
+    gridData = new GridData();
+    gridData.horizontalSpan = 2;
+    matchCase.setLayoutData(gridData);
+
+    matchWord = new Button(shell, DWT.CHECK);
+    matchWord.setText(resAddressBook.getString("Dialog_match_word"));
+    gridData = new GridData();
+    gridData.horizontalSpan = 2;
+    matchWord.setLayoutData(gridData);
+
+    Group direction = new Group(shell, DWT.NONE);
+    gridData = new GridData();
+    gridData.horizontalSpan = 2;
+    direction.setLayoutData(gridData);
+    direction.setLayout (new FillLayout ());
+    direction.setText(resAddressBook.getString("Dialog_direction"));
+
+    Button up = new Button(direction, DWT.RADIO);
+    up.setText(resAddressBook.getString("Dialog_dir_up"));
+    up.setSelection(false);
+
+    down = new Button(direction, DWT.RADIO);
+    down.setText(resAddressBook.getString("Dialog_dir_down"));
+    down.setSelection(true);
+
+    Composite composite = new Composite(shell, DWT.NONE);
+    gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+    gridData.horizontalSpan = 2;
+    composite.setLayoutData(gridData);
+    layout = new GridLayout();
+    layout.numColumns = 2;
+    layout.makeColumnsEqualWidth = true;
+    composite.setLayout(layout);
+
+    findButton = new Button(composite, DWT.PUSH);
+    findButton.setText(resAddressBook.getString("Dialog_find"));
+    findButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
+    findButton.setEnabled(false);
+    findButton.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            if (!findHandler.find()){
+                MessageBox box = new MessageBox(shell, DWT.ICON_INFORMATION | DWT.OK | DWT.PRIMARY_MODAL);
+                box.setText(shell.getText());
+                box.setMessage(resAddressBook.getString("Cannot_find") + "\"" + searchText.getText() + "\"");
+                box.open();
+            }
+        }
+    });
+
+    Button cancelButton = new Button(composite, DWT.PUSH);
+    cancelButton.setText(resAddressBook.getString("Cancel"));
+    cancelButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+    cancelButton.addSelectionListener(new class() SelectionAdapter {
+        public void widgetSelected(SelectionEvent e) {
+            shell.setVisible(false);
+        }
+    });
+
+    shell.pack();
+}
+public char[] getSearchAreaLabel(char[] label) {
+    return searchAreaLabel.getText();
+}
+
+public char[][] getsearchAreaNames() {
+    return searchArea.getItems();
+}
+public bool getMatchCase() {
+    return matchCase.getSelection();
+}
+public bool getMatchWord() {
+    return matchWord.getSelection();
+}
+public char[] getSearchString() {
+    return searchText.getText();
+}
+public bool getSearchDown(){
+    return down.getSelection();
+}
+public int getSelectedSearchArea() {
+    return searchArea.getSelectionIndex();
+}
+public void open() {
+    if (shell.isVisible()) {
+        shell.setFocus();
+    } else {
+        shell.open();
+    }
+    searchText.setFocus();
+}
+public void setSearchAreaNames(char[][] names) {
+    for (int i = 0; i < names.length; i++) {
+        searchArea.add(names[i]);
+    }
+    searchArea.select(0);
+}
+public void setSearchAreaLabel(char[] label) {
+    searchAreaLabel.setText(label);
+}
+public void setMatchCase(bool match) {
+    matchCase.setSelection(match);
+}
+public void setMatchWord(bool match) {
+    matchWord.setSelection(match);
+}
+public void setSearchDown(bool searchDown){
+    down.setSelection(searchDown);
+}
+public void setSearchString(char[] searchString) {
+    searchText.setText(searchString);
+}
+
+public void setSelectedSearchArea(int index) {
+    searchArea.select(index);
+}
+public void addFindListener(FindListener listener) {
+    this.findHandler = listener;
+}
+public void removeFindListener(FindListener listener) {
+    this.findHandler = null;
+}
+}