changeset 66:79f8e9296892

jface.Librarian example
author Frank Benoit <benoit@tionex.de>
date Fri, 11 Apr 2008 23:15:51 +0200
parents a84ba4d1820f
children 224fe05ea3af
files .hgignore dsss.conf jface/Librarian.d res/jface.librarian.about.gif res/jface.librarian.addBook.gif res/jface.librarian.checked.gif res/jface.librarian.count.gif res/jface.librarian.disabledAbout.gif res/jface.librarian.disabledAddBook.gif res/jface.librarian.disabledCount.gif res/jface.librarian.disabledNew.gif res/jface.librarian.disabledOpen.gif res/jface.librarian.disabledRemoveBook.gif res/jface.librarian.disabledSave.gif res/jface.librarian.disabledSaveAs.gif res/jface.librarian.new.gif res/jface.librarian.open.gif res/jface.librarian.removeBook.gif res/jface.librarian.rightArrow.gif res/jface.librarian.save.gif res/jface.librarian.saveAs.gif res/jface.librarian.unchecked.gif
diffstat 22 files changed, 1213 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Apr 11 21:15:36 2008 +0200
+++ b/.hgignore	Fri Apr 11 23:15:51 2008 +0200
@@ -26,4 +26,5 @@
 ^jface/FileTreeViewer$
 ^jface/ShowPrefs$
 ^jface/ShowFieldPrefs$
+^jface/Librarian$
 
--- a/dsss.conf	Fri Apr 11 21:15:36 2008 +0200
+++ b/dsss.conf	Fri Apr 11 23:15:51 2008 +0200
@@ -82,6 +82,7 @@
     [jface/FileTreeViewer.d]
     [jface/ShowPrefs.d]
     [jface/ShowFieldPrefs.d]
+    [jface/Librarian.d]
 }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jface/Librarian.d	Fri Apr 11 23:15:51 2008 +0200
@@ -0,0 +1,1211 @@
+module jface.Librarian;
+
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.jface.action.MenuManager;
+import dwtx.jface.action.StatusLineManager;
+import dwtx.jface.action.ToolBarManager;
+import dwtx.jface.action.CoolBarManager;
+import dwtx.jface.action.Action;
+import dwtx.jface.action.IAction;
+import dwtx.jface.dialogs.MessageDialog;
+import dwtx.jface.operation.IRunnableWithProgress;
+import dwtx.jface.operation.ModalContext;
+import dwtx.jface.util.IPropertyChangeListener;
+import dwtx.jface.util.PropertyChangeEvent;
+import dwtx.jface.viewers.TableViewer;
+import dwtx.jface.viewers.Viewer;
+import dwtx.jface.viewers.ITableLabelProvider;
+import dwtx.jface.viewers.IStructuredContentProvider;
+import dwtx.jface.viewers.ICellModifier;
+import dwtx.jface.viewers.ILabelProviderListener;
+import dwtx.jface.viewers.TextCellEditor;
+import dwtx.jface.viewers.CellEditor;
+import dwtx.jface.viewers.CheckboxCellEditor;
+import dwtx.jface.action.Separator;
+import dwtx.jface.viewers.IStructuredSelection;
+import dwtx.jface.window.ApplicationWindow;
+import dwtx.jface.resource.ImageDescriptor;
+
+import dwt.DWT;
+
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Display;
+import dwt.widgets.FileDialog;
+import dwt.widgets.MessageBox;
+import dwt.widgets.Shell;
+import dwt.widgets.Table;
+import dwt.widgets.TableColumn;
+import dwt.widgets.Control;
+import dwt.widgets.Composite;
+import dwt.widgets.Item;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.ByteArrayInputStream;
+
+import tango.text.convert.Format;
+import tango.util.collection.LinkSeq;
+import tango.io.FilePath;
+import tango.io.File;
+import tango.io.Print;
+import tango.io.stream.FileStream;
+import tango.text.Util;
+import tango.text.stream.LineIterator;
+import tango.util.log.Trace;
+
+/++
+    Known Problem:
+        Blocks in Save Method
+        Not prepared for windows.
+++/
+
+/**
+ * The application entry point
+ *
+ * @param args the command line arguments
+ */
+void main() {
+    (new Librarian()).run();
+}
+
+
+/**
+ * This class keeps track of you library, and who you've loaned books to
+ */
+public class Librarian : ApplicationWindow {
+    // A static instance to the running application
+    private static Librarian APP;
+
+    // Table column names/properties
+    public static const String TITLE = "Title";
+    public static const String CHECKED_OUT = "?";
+    public static const String WHO = "By Whom";
+    public static const String[] PROPS = [ TITLE, CHECKED_OUT, WHO ];
+
+    // The viewer
+    private TableViewer viewer;
+
+    // The current library
+    private Library library;
+
+    // The actions
+    private NewAction newAction;
+    private OpenAction openAction;
+    private SaveAction saveAction;
+    private SaveAsAction saveAsAction;
+    private ExitAction exitAction;
+    private AddBookAction addBookAction;
+    private RemoveBookAction removeBookAction;
+    private AboutAction aboutAction;
+    private ShowBookCountAction showBookCountAction;
+
+    /**
+    * Gets the running application
+    */
+    public static Librarian getApp() {
+        return APP;
+    }
+
+    /**
+    * Librarian constructor
+    */
+    public this() {
+        super(null);
+
+        APP = this;
+
+        // Create the data model
+        library = new Library();
+
+        // Create the actions
+        newAction = new NewAction();
+        openAction = new OpenAction();
+        saveAction = new SaveAction();
+        saveAsAction = new SaveAsAction();
+        exitAction = new ExitAction();
+        addBookAction = new AddBookAction();
+        removeBookAction = new RemoveBookAction();
+        aboutAction = new AboutAction();
+        showBookCountAction = new ShowBookCountAction();
+
+        addMenuBar();
+        //addCoolBar(DWT.NONE);
+        addToolBar(DWT.FLAT);
+        addStatusLine();
+    }
+
+    /**
+    * Runs the application
+    */
+    public void run() {
+        // Don't return from open() until window closes
+        setBlockOnOpen(true);
+
+        // Open the main window
+        open();
+
+        // Dispose the display
+        Display.getCurrent().dispose();
+    }
+
+    /**
+    * Configures the shell
+    *
+    * @param shell the shell
+    */
+    protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+
+        // Set the title bar text
+        shell.setText("Librarian");
+    }
+
+    /**
+    * Creates the main window's contents
+    *
+    * @param parent the main window
+    * @return Control
+    */
+    protected Control createContents(Composite parent) {
+        Composite composite = new Composite(parent, DWT.NONE);
+        composite.setLayout(new GridLayout(1, false));
+
+        viewer = new TableViewer(composite, DWT.FULL_SELECTION | DWT.BORDER);
+        Table table = viewer.getTable();
+        table.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+        // Set up the viewer
+        viewer.setContentProvider(new LibraryContentProvider());
+        viewer.setLabelProvider(new LibraryLabelProvider());
+        viewer.setInput(library);
+        viewer.setColumnProperties(PROPS);
+        viewer.setCellEditors( [ cast(CellEditor) new TextCellEditor(table),
+            new CheckboxCellEditor(table), new TextCellEditor(table)]);
+        viewer.setCellModifier(new LibraryCellModifier());
+
+        // Set up the table
+        for (int i = 0, n = PROPS.length; i < n; i++)
+        (new TableColumn(table, DWT.LEFT)).setText(PROPS[i]);
+        table.setHeaderVisible(true);
+        table.setLinesVisible(true);
+
+        // Add code to hide or display the book count based on the action
+        showBookCountAction.addPropertyChangeListener(new class IPropertyChangeListener {
+            public void propertyChange(PropertyChangeEvent event) {
+                // The value has changed; refresh the view
+                refreshView();
+            }
+        });
+
+        // Rfresh the view to get the columns right-sized
+        refreshView();
+
+        return composite;
+    }
+
+    /**
+    * Creates the menu for the application
+    *
+    * @return MenuManager
+    */
+    protected MenuManager createMenuManager() {
+        // Create the main menu
+        MenuManager mm = new MenuManager();
+
+        // Create the File menu
+        MenuManager fileMenu = new MenuManager("File");
+        mm.add(fileMenu);
+
+        // Add the actions to the File menu
+        fileMenu.add(newAction);
+        fileMenu.add(openAction);
+        fileMenu.add(saveAction);
+        fileMenu.add(saveAsAction);
+        fileMenu.add(new Separator());
+        fileMenu.add(exitAction);
+
+        // Create the Book menu
+        MenuManager bookMenu = new MenuManager("Book");
+        mm.add(bookMenu);
+
+        // Add the actions to the Book menu
+        bookMenu.add(addBookAction);
+        bookMenu.add(removeBookAction);
+
+        // Create the View menu
+        MenuManager viewMenu = new MenuManager("View");
+        mm.add(viewMenu);
+
+        // Add the actions to the View menu
+        viewMenu.add(showBookCountAction);
+
+        // Create the Help menu
+        MenuManager helpMenu = new MenuManager("Help");
+        mm.add(helpMenu);
+
+        // Add the actions to the Help menu
+        helpMenu.add(aboutAction);
+
+        return mm;
+    }
+
+    /**
+    * Creates the toolbar for the application
+    */
+    protected ToolBarManager createToolBarManager(int style) {
+        // Create the toolbar manager
+        ToolBarManager tbm = new ToolBarManager(style);
+
+        // Add the file actions
+        tbm.add(newAction);
+        tbm.add(openAction);
+        tbm.add(saveAction);
+        tbm.add(saveAsAction);
+
+        // Add a separator
+        tbm.add(new Separator());
+
+        // Add the book actions
+        tbm.add(addBookAction);
+        tbm.add(removeBookAction);
+
+        // Add a separator
+        tbm.add(new Separator());
+
+        // Add the show book count, which will appear as a toggle button
+        tbm.add(showBookCountAction);
+
+        // Add a separator
+        tbm.add(new Separator());
+
+        // Add the about action
+        tbm.add(aboutAction);
+
+        return tbm;
+    }
+/+
+    /**
+     * Creates the coolbar for the application
+     */
+    protected CoolBarManager createCoolBarManager(int style) {
+        // Create the coolbar manager
+        CoolBarManager cbm = new CoolBarManager(style);
+
+        // Add the toolbar
+        cbm.add(createToolBarManager(DWT.FLAT));
+
+        return cbm;
+    }
++/
+    /**
+     * Creates the status line manager
+     */
+    protected StatusLineManager createStatusLineManager() {
+        return new StatusLineManager();
+    }
+
+    /**
+     * Adds a book
+     */
+    public void addBook() {
+        library.add(new Book("[Enter Title]"));
+        refreshView();
+    }
+
+    /**
+    * Removes the selected book
+    */
+    public void removeSelectedBook() {
+        Book book = cast(Book) (cast(IStructuredSelection) viewer.getSelection())
+            .getFirstElement();
+        if (book !is null) library.remove(book);
+        refreshView();
+    }
+
+    /**
+    * Opens a file
+    *
+    * @param fileName the file name
+    */
+    public void openFile(String fileName) {
+        if (checkOverwrite()) {
+            // Disable the actions, so user can't change library while loading
+            enableActions(false);
+
+            library = new Library();
+            try {
+                // Launch the Open runnable
+                ModalContext.run(new class(fileName) IRunnableWithProgress {
+                    String fileName_;
+                    this(String a){
+                        fileName_=a;
+                    }
+                    public void run(IProgressMonitor progressMonitor) {
+                        try {
+                            progressMonitor.beginTask("Loading", IProgressMonitor.UNKNOWN);
+                            library.load(fileName_);
+                            progressMonitor.done();
+                            viewer.setInput(library);
+                            refreshView();
+                        } catch (IOException e) {
+                            showError( Format("Can't load file {}\r{}", fileName_, e.msg));
+                        }
+                    }
+                }, true, getStatusLineManager().getProgressMonitor(), getShell()
+                    .getDisplay());
+            } catch (InterruptedException e) {
+            } catch (InvocationTargetException e) {
+            } finally {
+                // Enable actions
+                enableActions(true);
+            }
+        }
+    }
+
+    /**
+    * Creates a new file
+    */
+    public void newFile() {
+        if (checkOverwrite()) {
+        library = new Library();
+        viewer.setInput(library);
+        }
+    }
+
+    /**
+    * Saves the current file
+    */
+    public void saveFile() {
+        String fileName = library.getFileName();
+        if (fileName is null) {
+            fileName = (new SafeSaveDialog(getShell())).open();
+        }
+        saveFileAs(fileName);
+    }
+
+    /**
+    * Saves the current file using the specified file name
+    *
+    * @param fileName the file name
+    */
+    public void saveFileAs(String fileName) {
+        // Disable the actions, so user can't change file while it's saving
+        enableActions(false);
+Trace.formatln( "trc {}",__LINE__ );
+        try {
+            // Launch the Save runnable
+            ModalContext.run(new class(fileName) IRunnableWithProgress {
+                String filename_;
+                this(String a){
+Trace.formatln( "trc {}",__LINE__ );
+                    filename_=a;
+                }
+                public void run(IProgressMonitor progressMonitor) {
+Trace.formatln( "trc {}",__LINE__ );
+                    try {
+                        progressMonitor.beginTask("Saving", IProgressMonitor.UNKNOWN);
+                        library.save(filename_);
+                        progressMonitor.done();
+                    } catch (IOException e) {
+Trace.formatln( "trc {}",__LINE__ );
+                        showError(Format("Can't save file {}\r{}", library.getFileName(), e.msg ));
+                    }
+Trace.formatln( "trc {}",__LINE__ );
+                }
+            }, true, getStatusLineManager().getProgressMonitor(), getShell()
+            .getDisplay());
+Trace.formatln( "trc {}",__LINE__ );
+        } catch (InterruptedException e) {
+        } catch (InvocationTargetException e) {
+        } finally {
+Trace.formatln( "trc {}",__LINE__ );
+            // Enable the actions
+            enableActions(true);
+        }
+Trace.formatln( "trc {}",__LINE__ );
+    }
+
+    /**
+    * Shows an error
+    *
+    * @param msg the error
+    */
+    public void showError(String msg) {
+        MessageDialog.openError(getShell(), "Error", msg);
+    }
+
+    /**
+    * Refreshes the view
+    */
+    public void refreshView() {
+        // Refresh the view
+        viewer.refresh();
+
+        // Repack the columns
+        for (int i = 0, n = viewer.getTable().getColumnCount(); i < n; i++) {
+        viewer.getTable().getColumn(i).pack();
+        }
+
+        getStatusLineManager().setMessage(
+            showBookCountAction.isChecked() ? Format( "Book Count: {}",
+                library.getBooks().size()) : "");
+    }
+
+    /**
+    * Checks the current file for unsaved changes. If it has unsaved changes,
+    * confirms that user wants to overwrite
+    *
+    * @return bool
+    */
+    public bool checkOverwrite() {
+        bool proceed = true;
+        if (library.isDirty()) {
+        proceed = MessageDialog.openConfirm(getShell(), "Are you sure?",
+            "You have unsaved changes--are you sure you want to lose them?");
+        }
+        return proceed;
+    }
+
+    /**
+    * Sets the current library dirty
+    */
+    public void setLibraryDirty() {
+        library.setDirty();
+    }
+
+    /**
+    * Closes the application
+    */
+    public bool close() {
+        if (checkOverwrite()) return super.close();
+        return false;
+    }
+
+    /**
+    * Enables or disables the actions
+    *
+    * @param enable true to enable, false to disable
+    */
+    private void enableActions(bool enable) {
+        newAction.setEnabled(enable);
+        openAction.setEnabled(enable);
+        saveAction.setEnabled(enable);
+        saveAsAction.setEnabled(enable);
+        exitAction.setEnabled(enable);
+        addBookAction.setEnabled(enable);
+        removeBookAction.setEnabled(enable);
+        aboutAction.setEnabled(enable);
+        showBookCountAction.setEnabled(enable);
+    }
+}
+
+
+/**
+ * This action class responds to requests to save a file
+ */
+public class SaveAction : Action {
+    /**
+    * SaveAction constructor
+    */
+    public this() {
+        super("&Save@Ctrl+S", ImageDescriptor.createFromFile( getImportData!("jface.librarian.save.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledSave.gif")));
+        setToolTipText("Save");
+    }
+
+    /**
+    * Saves the file
+    */
+    public void run() {
+        Librarian.getApp().saveFile();
+    }
+}
+
+
+
+
+/**
+ * This action class responds to requests open a file
+ */
+public class OpenAction : Action {
+    /**
+    * OpenAction constructor
+    */
+    public this() {
+        super("&Open...@Ctrl+O", ImageDescriptor.createFromFile(getImportData!("jface.librarian.open.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledOpen.gif")));
+        setToolTipText("Open");
+    }
+
+    /**
+    * Opens an existing file
+    */
+    public void run() {
+        // Use the file dialog
+        FileDialog dlg = new FileDialog(Librarian.getApp().getShell(), DWT.OPEN);
+        String fileName = dlg.open();
+        if (fileName !is null) {
+            Librarian.getApp().openFile(fileName);
+        }
+    }
+}
+
+/**
+ * This action class reponds to requests for a new file
+ */
+public class NewAction : Action {
+    /**
+    * NewAction constructor
+    */
+    public this() {
+        super("&New@Ctrl+N", ImageDescriptor.createFromFile(getImportData!("jface.librarian.new.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledNew.gif")));
+        setToolTipText("New");
+    }
+
+    /**
+    * Creates a new file
+    */
+    public void run() {
+        Librarian.getApp().newFile();
+    }
+}
+
+/**
+ * This action class responds to requests to save a file as . . .
+ */
+public class SaveAsAction : Action {
+    /**
+    * SaveAsAction constructor
+    */
+    public this() {
+        super("Save As...", ImageDescriptor.createFromFile(getImportData!("jface.librarian.saveAs.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledSaveAs.gif")));
+        setToolTipText("Save As");
+    }
+
+    /**
+    * Saves the file
+    */
+    public void run() {
+        SafeSaveDialog dlg = new SafeSaveDialog(Librarian.getApp().getShell());
+        String fileName = dlg.open();
+        if (fileName !is null) {
+        Librarian.getApp().saveFileAs(fileName);
+        }
+    }
+}
+
+
+/**
+ * This action class deletes a book
+ */
+public class RemoveBookAction : Action {
+    /**
+    * RemoveBookAction constructor
+    */
+    public this() {
+        super("&Remove Book@Ctrl+X", ImageDescriptor.createFromFile(getImportData!("jface.librarian.removeBook.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledRemoveBook.gif")));
+        setToolTipText("Remove");
+    }
+
+    /**
+    * Removes the selected book after confirming
+    */
+    public void run() {
+        if (MessageDialog.openConfirm(Librarian.getApp().getShell(), "Are you sure?",
+            "Are you sure you want to remove the selected book?")) {
+        Librarian.getApp().removeSelectedBook();
+        }
+    }
+}
+
+
+/**
+ * This action class adds a book
+ */
+public class AddBookAction : Action {
+    /**
+    * AddBookAction constructor
+    */
+    public this() {
+        super("&Add Book@Ctrl+B", ImageDescriptor.createFromFile(getImportData!("jface.librarian.addBook.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledAddBook.gif")));
+        setToolTipText("Add");
+    }
+
+    /**
+    * Adds a book to the current library
+    */
+    public void run() {
+        Librarian.getApp().addBook();
+    }
+}
+
+/**
+ * This action class exits the application
+ */
+public class ExitAction : Action {
+    /**
+    * ExitAction constructor
+    */
+    public this() {
+        super("E&xit@Alt+F4");
+        setToolTipText("Exit");
+    }
+
+    /**
+    * Exits the application
+    */
+    public void run() {
+        Librarian.getApp().close();
+    }
+}
+
+/**
+ * This action class shows an About box
+ */
+public class AboutAction : Action {
+    /**
+    * AboutAction constructor
+    */
+    public this() {
+        super("&About@Ctrl+A", ImageDescriptor.createFromFile(getImportData!("jface.librarian.about.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledAbout.gif")));
+        setToolTipText("About");
+    }
+
+    /**
+    * Shows an about box
+    */
+    public void run() {
+        MessageDialog.openInformation(Librarian.getApp().getShell(), "About",
+            "Librarian--to manage your books");
+    }
+}
+
+
+
+/**
+ * This action class determines whether to show the book count
+ */
+public class ShowBookCountAction : Action {
+    public this() {
+        super("&Show Book Count@Ctrl+C", IAction.AS_CHECK_BOX);
+        setChecked(true);
+        setImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.count.gif")));
+        setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledCount.gif")));
+    }
+}
+
+/**
+ * This class represents a book
+ */
+public class Book {
+    private String title;
+    private String checkedOutTo;
+
+    /**
+    * Book constructor
+    * @param title the title
+    */
+    public this(String title) {
+        setTitle(title);
+    }
+
+    /**
+    * Sets the title
+    * @param title the title
+    */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+    * Gets the title
+    * @return String
+    */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+    * Check out
+    * @param who the person checking this book out
+    */
+    public void checkOut(String who) {
+        checkedOutTo = who;
+        if (checkedOutTo.length is 0) checkedOutTo = null;
+    }
+
+    public bool isCheckedOut() {
+        return checkedOutTo !is null && checkedOutTo.length > 0;
+    }
+
+    public void checkIn() {
+        checkedOutTo = null;
+    }
+
+    /**
+    * Gets who this book is checked out to
+    * @return String
+    */
+    public String getCheckedOutTo() {
+        return checkedOutTo;
+    }
+}
+
+
+/**
+ * This class provides a facade for the "save"
+ * FileDialog class. If the selected file already
+ * exists, the user is asked to confirm before
+ * overwriting.
+ */
+public class SafeSaveDialog
+{
+  // The wrapped FileDialog
+  private FileDialog dlg;
+
+    /**
+    * SafeSaveDialog constructor
+    * @param shell the parent shell
+    */
+    public this(Shell shell)
+    {
+        dlg = new FileDialog(shell, DWT.SAVE);
+    }
+
+    public String open()
+    {
+        // We store the selected file name in fileName
+        String fileName = null;
+
+        // The user has finished when one of the
+        // following happens:
+        // 1) The user dismisses the dialog by pressing Cancel
+        // 2) The selected file name does not exist
+        // 3) The user agrees to overwrite existing file
+        bool done = false;
+
+        while (!done)
+        {
+        // Open the File Dialog
+        fileName = dlg.open();
+        if (fileName is null)
+        {
+            // User has cancelled, so quit and return
+            done = true;
+        }
+        else
+        {
+            // User has selected a file; see if it already exists
+            FilePath file = new FilePath(fileName);
+            if (file.exists())
+            {
+                // The file already exists; asks for confirmation
+                MessageBox mb = new MessageBox(dlg.getParent(),
+                    DWT.ICON_WARNING | DWT.YES | DWT.NO);
+
+                // We really should read this string from a
+                // resource bundle
+                mb.setMessage(fileName ~ " already exists. Do you want to replace it?");
+
+                // If they click Yes, we're done and we drop out. If
+                // they click No, we redisplay the File Dialog
+                done = mb.open() is DWT.YES;
+            }
+            else
+            {
+                // File does not exist, so drop out
+                done = true;
+            }
+        }
+        }
+        return fileName;
+    }
+
+    public String getFileName()
+    {
+        return dlg.getFileName();
+    }
+
+    public String[] getFileNames()
+    {
+        return dlg.getFileNames();
+    }
+
+    public String[] getFilterExtensions()
+    {
+        return dlg.getFilterExtensions();
+    }
+
+    public String[] getFilterNames()
+    {
+        return dlg.getFilterNames();
+    }
+
+    public String getFilterPath()
+    {
+        return dlg.getFilterPath();
+    }
+
+    public void setFileName(String string)
+    {
+        dlg.setFileName(string);
+    }
+
+    public void setFilterExtensions(String[] extensions)
+    {
+        dlg.setFilterExtensions(extensions);
+    }
+
+    public void setFilterNames(String[] names)
+    {
+        dlg.setFilterNames(names);
+    }
+
+    public void setFilterPath(String string)
+    {
+        dlg.setFilterPath(string);
+    }
+
+    public Shell getParent()
+    {
+        return dlg.getParent();
+    }
+
+    public int getStyle()
+    {
+        return dlg.getStyle();
+    }
+
+    public String getText()
+    {
+        return dlg.getText();
+    }
+
+    public void setText(String string)
+    {
+        dlg.setText(string);
+    }
+}
+
+
+/**
+ * This class is the cell modifier for the Librarian program
+ */
+public class LibraryCellModifier : ICellModifier {
+    /**
+    * Gets whether the specified property can be modified
+    *
+    * @param element the book
+    * @param property the property
+    * @return bool
+    */
+    public bool canModify(Object element, String property) {
+        return true;
+    }
+
+    /**
+    * Gets the value for the property
+    *
+    * @param element the book
+    * @param property the property
+    * @return Object
+    */
+    public Object getValue(Object element, String property) {
+        Book book = cast(Book) element;
+        if (Librarian.TITLE.equals(property))
+            return stringcast(book.getTitle());
+        else if (Librarian.CHECKED_OUT.equals(property))
+            return Boolean.valueOf(book.isCheckedOut());
+        else if (Librarian.WHO.equals(property))
+            return stringcast( book.getCheckedOutTo() is null ? "" : book.getCheckedOutTo());
+        else
+            return null;
+    }
+
+    /**
+    * Modifies the element
+    *
+    * @param element the book
+    * @param property the property
+    * @param value the new value
+    */
+    public void modify(Object element, String property, Object value) {
+        if ( auto item = cast(Item)element ){
+            element = item.getData();
+        }
+
+        Book book = cast(Book) element;
+        if (Librarian.TITLE.equals(property))
+        book.setTitle(stringcast(value));
+        else if (Librarian.CHECKED_OUT.equals(property)) {
+            bool b = (cast(Boolean) value).booleanValue();
+            if (b)
+                book.checkOut("[Enter Name]");
+            else
+                book.checkIn();
+        } else if (Librarian.WHO.equals(property))
+            book.checkOut(stringcast(value));
+
+        // Refresh the view
+        Librarian.getApp().refreshView();
+
+        // Set the library dirty
+        Librarian.getApp().setLibraryDirty();
+    }
+}
+
+/**
+ * This class holds all the books in a library. It also handles loading from and
+ * saving to disk
+ */
+public class Library {
+    private static const String SEP = "|";
+
+    // The filename
+    private String filename;
+
+    // The books
+    private LinkSeq!(Book) books;
+
+    // The dirty flag
+    private bool dirty;
+
+    /**
+    * Library constructor Note the signature :-)
+    */
+    public this() {
+        books = new LinkSeq!(Book);
+    }
+
+    /**
+     * Loads the library from a file
+     *
+     * @param filename the filename
+     * @throws IOException
+     */
+    public void load(String filename) {
+        auto istr = (new FileInput(filename)).input;
+        auto lines = new LineIterator!(char)(istr);
+        String line;
+        foreach (line; lines ) {
+            auto tokens = tango.text.Util.delimit(line, SEP);
+            Book book = null;
+            if ( tokens.length > 0 ) book = new Book( tokens[0].dup );
+            if (tokens.length > 1) book.checkOut(tokens[1].dup );
+            if (book !is null) add(book);
+        }
+        istr.close();
+        this.filename = filename;
+        dirty = false;
+    }
+
+    /**
+     * Saves the library to a file
+     *
+     * @param filename the filename
+     * @throws IOException
+     */
+    public void save(String filename) {
+        scope ostr = (new FileOutput(filename)).output;
+        scope printer = new Print!(char)( Format, ostr );
+        foreach ( book; books ) {
+            printer.formatln( "{}|{}",book.getTitle(), (book.getCheckedOutTo() is null ? "" : book.getCheckedOutTo()));
+        }
+        ostr.close();
+        this.filename = filename;
+        dirty = false;
+    }
+
+    /**
+    * Adds a book
+    *
+    * @param book the book to add
+    * @return bool
+    */
+    public bool add(Book book) {
+        books.append(book);
+        setDirty();
+        return true;
+    }
+
+    /**
+    * Removes a book
+    *
+    * @param book the book to remove
+    */
+    public void remove(Book book) {
+        books.remove(book);
+        setDirty();
+    }
+
+    /**
+    * Gets the books
+    *
+    * @return Collection
+    */
+    public LinkSeq!(Book) getBooks() {
+        return books;
+    }
+
+    /**
+    * Gets the file name
+    *
+    * @return String
+    */
+    public String getFileName() {
+        return filename;
+    }
+
+    /**
+    * Gets whether this file is dirty
+    *
+    * @return bool
+    */
+    public bool isDirty() {
+        return dirty;
+    }
+
+    /**
+    * Sets this file as dirty
+    */
+    public void setDirty() {
+        dirty = true;
+    }
+}
+
+
+/**
+ * This class provides the content for the library table
+ */
+public class LibraryContentProvider : IStructuredContentProvider {
+    /**
+     * Gets the books
+     *
+     * @param inputElement the library
+     * @return Object[]
+     */
+    public Object[] getElements(Object inputElement) {
+        return (cast(Library) inputElement).getBooks().toArray();
+    }
+
+    /**
+     * Disposes any resources
+     */
+    public void dispose() {
+        // Do nothing
+    }
+
+    /**
+     * Called when the input changes
+     *
+     * @param viewer the viewer
+     * @param oldInput the old library
+     * @param newInput the new library
+     */
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        // Ignore
+    }
+}
+
+
+/**
+ * This class provides the labels for the library table
+ */
+public class LibraryLabelProvider : ITableLabelProvider {
+    private Image checked;
+    private Image unchecked;
+
+    /**
+     * LibraryLabelProvider constructor
+     */
+    public this() {
+        // Create the check mark images
+        checked = new Image(null, new ImageData( new ByteArrayInputStream( cast(byte[])import("jface.librarian.checked.gif"))));
+        unchecked = new Image(null,new ImageData( new ByteArrayInputStream( cast(byte[])import("jface.librarian.unchecked.gif"))));
+    }
+
+    /**
+     * Gets the column image
+     *
+     * @param element the book
+     * @param columnIndex the column index
+     * @return Image
+     */
+    public Image getColumnImage(Object element, int columnIndex) {
+        // For the "Checked Out" column, return the check mark
+        // if the book is checked out
+        if (columnIndex is 1)
+            return (cast(Book) element).isCheckedOut() ? checked : unchecked;
+        return null;
+    }
+
+    /**
+     * Gets the column text
+     *
+     * @param element the book
+     * @param columnIndex the column index
+     * @return String
+     */
+    public String getColumnText(Object element, int columnIndex) {
+        Book book = cast(Book) element;
+        String text = null;
+        switch (columnIndex) {
+            case 0:
+                text = book.getTitle();
+                break;
+            case 2:
+                text = book.getCheckedOutTo();
+                break;
+            default:
+        }
+        return text is null ? "" : text;
+    }
+
+    /**
+     * Adds a listener
+     */
+    public void addListener(ILabelProviderListener listener) {
+    // Ignore
+    }
+
+    /**
+     * Disposes any resources
+     */
+    public void dispose() {
+        if (checked !is null) checked.dispose();
+        if (unchecked !is null) unchecked.dispose();
+    }
+
+    /**
+     * Gets whether this is a label property
+     *
+     * @param element the book
+     * @param property the property
+     * @return bool
+     */
+    public bool isLabelProperty(Object element, String property) {
+        return false;
+    }
+
+    /**
+     * Removes a listener
+     *
+     * @param listener the listener
+     */
+    public void removeListener(ILabelProviderListener listener) {
+        // Ignore
+    }
+}
+
+
+
+
+
+
Binary file res/jface.librarian.about.gif has changed
Binary file res/jface.librarian.addBook.gif has changed
Binary file res/jface.librarian.checked.gif has changed
Binary file res/jface.librarian.count.gif has changed
Binary file res/jface.librarian.disabledAbout.gif has changed
Binary file res/jface.librarian.disabledAddBook.gif has changed
Binary file res/jface.librarian.disabledCount.gif has changed
Binary file res/jface.librarian.disabledNew.gif has changed
Binary file res/jface.librarian.disabledOpen.gif has changed
Binary file res/jface.librarian.disabledRemoveBook.gif has changed
Binary file res/jface.librarian.disabledSave.gif has changed
Binary file res/jface.librarian.disabledSaveAs.gif has changed
Binary file res/jface.librarian.new.gif has changed
Binary file res/jface.librarian.open.gif has changed
Binary file res/jface.librarian.removeBook.gif has changed
Binary file res/jface.librarian.rightArrow.gif has changed
Binary file res/jface.librarian.save.gif has changed
Binary file res/jface.librarian.saveAs.gif has changed
Binary file res/jface.librarian.unchecked.gif has changed