Java tutorial
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.LineNumberReader; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.StringTokenizer; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.CoolBarManager; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.action.StatusLineManager; import org.eclipse.jface.action.ToolBarManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.operation.ModalContext; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckboxCellEditor; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.ApplicationWindow; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; /** * This class keeps track of you library, and who you've loaned books to */ public class Librarian extends ApplicationWindow { // A static instance to the running application private static Librarian APP; // Table column names/properties public static final String TITLE = "Title"; public static final String CHECKED_OUT = "?"; public static final String WHO = "By Whom"; public static final 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 final Librarian getApp() { return APP; } /** * Librarian constructor */ public Librarian() { 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(SWT.NONE); 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, SWT.NONE); composite.setLayout(new GridLayout(1, false)); viewer = new TableViewer(composite, SWT.FULL_SELECTION | SWT.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(new 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, SWT.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 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(SWT.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 = (Book) ((IStructuredSelection) viewer.getSelection()).getFirstElement(); if (book != null) library.remove(book); refreshView(); } /** * Opens a file * * @param fileName * the file name */ public void openFile(final 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 IRunnableWithProgress() { public void run(IProgressMonitor progressMonitor) { try { progressMonitor.beginTask("Loading", IProgressMonitor.UNKNOWN); library.load(fileName); progressMonitor.done(); viewer.setInput(library); refreshView(); } catch (IOException e) { showError("Can't load file " + fileName + "\r" + e.getMessage()); } } }, 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 == 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(final String fileName) { // Disable the actions, so user can't change file while it's saving enableActions(false); try { // Launch the Save runnable ModalContext.run(new IRunnableWithProgress() { public void run(IProgressMonitor progressMonitor) { try { progressMonitor.beginTask("Saving", IProgressMonitor.UNKNOWN); library.save(fileName); progressMonitor.done(); } catch (IOException e) { showError("Can't save file " + library.getFileName() + "\r" + e.getMessage()); } } }, true, getStatusLineManager().getProgressMonitor(), getShell().getDisplay()); } catch (InterruptedException e) { } catch (InvocationTargetException e) { } finally { // Enable the actions enableActions(true); } } /** * 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() ? "Book Count: " + library.getBooks().size() : ""); } /** * Checks the current file for unsaved changes. If it has unsaved changes, * confirms that user wants to overwrite * * @return boolean */ public boolean checkOverwrite() { boolean 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 boolean close() { if (checkOverwrite()) return super.close(); return false; } /** * Enables or disables the actions * * @param enable * true to enable, false to disable */ private void enableActions(boolean 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); } /** * The application entry point * * @param args * the command line arguments */ public static void main(String[] args) { new Librarian().run(); } } /** * This class holds all the books in a library. It also handles loading from and * saving to disk */ class Library { private static final String SEP = "|"; // The filename private String filename; // The books private Collection books; // The dirty flag private boolean dirty; /** * Library constructor Note the signature :-) */ public Library() { books = new LinkedList(); } /** * Loads the library from a file * * @param filename * the filename * @throws IOException */ public void load(String filename) throws IOException { BufferedReader in = new BufferedReader(new LineNumberReader(new FileReader(filename))); String line; while ((line = in.readLine()) != null) { StringTokenizer st = new StringTokenizer(line, SEP); Book book = null; if (st.hasMoreTokens()) book = new Book(st.nextToken()); if (st.hasMoreTokens()) book.checkOut(st.nextToken()); if (book != null) add(book); } in.close(); this.filename = filename; dirty = false; } /** * Saves the library to a file * * @param filename * the filename * @throws IOException */ public void save(String filename) throws IOException { BufferedWriter out = new BufferedWriter(new FileWriter(filename)); for (Iterator itr = books.iterator(); itr.hasNext();) { Book book = (Book) itr.next(); out.write(book.getTitle()); out.write('|'); out.write(book.getCheckedOutTo() == null ? "" : book.getCheckedOutTo()); out.write('\r'); } out.close(); this.filename = filename; dirty = false; } /** * Adds a book * * @param book * the book to add * @return boolean */ public boolean add(Book book) { boolean added = books.add(book); if (added) setDirty(); return added; } /** * Removes a book * * @param book * the book to remove */ public void remove(Book book) { books.remove(book); setDirty(); } /** * Gets the books * * @return Collection */ public Collection getBooks() { return Collections.unmodifiableCollection(books); } /** * Gets the file name * * @return String */ public String getFileName() { return filename; } /** * Gets whether this file is dirty * * @return boolean */ public boolean isDirty() { return dirty; } /** * Sets this file as dirty */ public void setDirty() { dirty = true; } } /** * This action class deletes a book */ class RemoveBookAction extends Action { /** * RemoveBookAction constructor */ public RemoveBookAction() { super("&Remove Book@Ctrl+X", ImageDescriptor.createFromFile(RemoveBookAction.class, "/images/removeBook.gif")); setDisabledImageDescriptor( ImageDescriptor.createFromFile(RemoveBookAction.class, "/images/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 responds to requests open a file */ class OpenAction extends Action { /** * OpenAction constructor */ public OpenAction() { super("&Open...@Ctrl+O", ImageDescriptor.createFromFile(OpenAction.class, "/images/open.gif")); setDisabledImageDescriptor(ImageDescriptor.createFromFile(OpenAction.class, "/images/disabledOpen.gif")); setToolTipText("Open"); } /** * Opens an existing file */ public void run() { // Use the file dialog FileDialog dlg = new FileDialog(Librarian.getApp().getShell(), SWT.OPEN); String fileName = dlg.open(); if (fileName != null) { Librarian.getApp().openFile(fileName); } } } /** * This action class adds a book */ class AddBookAction extends Action { /** * AddBookAction constructor */ public AddBookAction() { super("&Add Book@Ctrl+B", ImageDescriptor.createFromFile(AddBookAction.class, "/images/addBook.gif")); setDisabledImageDescriptor( ImageDescriptor.createFromFile(AddBookAction.class, "/images/disabledAddBook.gif")); setToolTipText("Add"); } /** * Adds a book to the current library */ public void run() { Librarian.getApp().addBook(); } } /** * This action class exits the application */ class ExitAction extends Action { /** * ExitAction constructor */ public ExitAction() { super("E&xit@Alt+F4"); setToolTipText("Exit"); } /** * Exits the application */ public void run() { Librarian.getApp().close(); } } /** * This action class reponds to requests for a new file */ class NewAction extends Action { /** * NewAction constructor */ public NewAction() { super("&New@Ctrl+N", ImageDescriptor.createFromFile(NewAction.class, "/images/new.gif")); setDisabledImageDescriptor(ImageDescriptor.createFromFile(NewAction.class, "/images/disabledNew.gif")); setToolTipText("New"); } /** * Creates a new file */ public void run() { Librarian.getApp().newFile(); } } /** * This action class responds to requests to save a file */ class SaveAction extends Action { /** * SaveAction constructor */ public SaveAction() { super("&Save@Ctrl+S", ImageDescriptor.createFromFile(SaveAction.class, "/images/save.gif")); setDisabledImageDescriptor(ImageDescriptor.createFromFile(SaveAction.class, "/images/disabledSave.gif")); setToolTipText("Save"); } /** * Saves the file */ public void run() { Librarian.getApp().saveFile(); } } /** * This action class responds to requests to save a file as . . . */ class SaveAsAction extends Action { /** * SaveAsAction constructor */ public SaveAsAction() { super("Save As...", ImageDescriptor.createFromFile(SaveAsAction.class, "/images/saveAs.gif")); setDisabledImageDescriptor( ImageDescriptor.createFromFile(SaveAsAction.class, "/images/disabledSaveAs.gif")); setToolTipText("Save As"); } /** * Saves the file */ public void run() { SafeSaveDialog dlg = new SafeSaveDialog(Librarian.getApp().getShell()); String fileName = dlg.open(); if (fileName != null) { Librarian.getApp().saveFileAs(fileName); } } } /** * This action class determines whether to show the book count */ class ShowBookCountAction extends Action { public ShowBookCountAction() { super("&Show Book Count@Ctrl+C", IAction.AS_CHECK_BOX); setChecked(true); setImageDescriptor(ImageDescriptor.createFromFile(ShowBookCountAction.class, "/images/count.gif")); setDisabledImageDescriptor( ImageDescriptor.createFromFile(ShowBookCountAction.class, "/images/disabledCount.gif")); } } /** * This action class shows an About box */ class AboutAction extends Action { /** * AboutAction constructor */ public AboutAction() { super("&About@Ctrl+A", ImageDescriptor.createFromFile(AboutAction.class, "/images/about.gif")); setDisabledImageDescriptor(ImageDescriptor.createFromFile(AboutAction.class, "/images/disabledAbout.gif")); setToolTipText("About"); } /** * Shows an about box */ public void run() { MessageDialog.openInformation(Librarian.getApp().getShell(), "About", "Librarian--to manage your books"); } } /** * This class provides a facade for the "save" FileDialog class. If the selected * file already exists, the user is asked to confirm before overwriting. */ class SafeSaveDialog { // The wrapped FileDialog private FileDialog dlg; /** * SafeSaveDialog constructor * * @param shell * the parent shell */ public SafeSaveDialog(Shell shell) { dlg = new FileDialog(shell, SWT.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 boolean done = false; while (!done) { // Open the File Dialog fileName = dlg.open(); if (fileName == null) { // User has cancelled, so quit and return done = true; } else { // User has selected a file; see if it already exists File file = new File(fileName); if (file.exists()) { // The file already exists; asks for confirmation MessageBox mb = new MessageBox(dlg.getParent(), SWT.ICON_WARNING | SWT.YES | SWT.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() == SWT.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 represents a book */ class Book { private String title; private String checkedOutTo; /** * Book constructor * * @param title * the title */ public Book(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() == 0) checkedOutTo = null; } public boolean isCheckedOut() { return checkedOutTo != 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 the labels for the library table */ class LibraryLabelProvider implements ITableLabelProvider { private Image checked; private Image unchecked; /** * LibraryLabelProvider constructor */ public LibraryLabelProvider() { // Create the check mark images checked = new Image(null, LibraryLabelProvider.class.getResourceAsStream("/images/checked.gif")); unchecked = new Image(null, LibraryLabelProvider.class.getResourceAsStream("/images/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 == 1) return ((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 = (Book) element; String text = null; switch (columnIndex) { case 0: text = book.getTitle(); break; case 2: text = book.getCheckedOutTo(); break; } return text == null ? "" : text; } /** * Adds a listener */ public void addListener(ILabelProviderListener listener) { // Ignore } /** * Disposes any resources */ public void dispose() { if (checked != null) checked.dispose(); if (unchecked != null) unchecked.dispose(); } /** * Gets whether this is a label property * * @param element * the book * @param property * the property * @return boolean */ public boolean isLabelProperty(Object element, String property) { return false; } /** * Removes a listener * * @param listener * the listener */ public void removeListener(ILabelProviderListener listener) { // Ignore } } /** * This class provides the content for the library table */ class LibraryContentProvider implements IStructuredContentProvider { /** * Gets the books * * @param inputElement * the library * @return Object[] */ public Object[] getElements(Object inputElement) { return ((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 is the cell modifier for the Librarian program */ class LibraryCellModifier implements ICellModifier { /** * Gets whether the specified property can be modified * * @param element * the book * @param property * the property * @return boolean */ public boolean 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 = (Book) element; if (Librarian.TITLE.equals(property)) return book.getTitle(); else if (Librarian.CHECKED_OUT.equals(property)) return Boolean.valueOf(book.isCheckedOut()); else if (Librarian.WHO.equals(property)) return book.getCheckedOutTo() == 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 (element instanceof Item) element = ((Item) element).getData(); Book book = (Book) element; if (Librarian.TITLE.equals(property)) book.setTitle((String) value); else if (Librarian.CHECKED_OUT.equals(property)) { boolean b = ((Boolean) value).booleanValue(); if (b) book.checkOut("[Enter Name]"); else book.checkIn(); } else if (Librarian.WHO.equals(property)) book.checkOut((String) value); // Refresh the view Librarian.getApp().refreshView(); // Set the library dirty Librarian.getApp().setLibraryDirty(); } }