diff options
author | Matt Windsor <mbw500@student.cs.york.ac.uk> | 2011-02-21 23:01:01 +0000 |
---|---|---|
committer | Matt Windsor <mbw500@student.cs.york.ac.uk> | 2011-02-21 23:01:01 +0000 |
commit | af1013959f6ab36ed9f2ff603c08116ee1b55c57 (patch) | |
tree | 330aaa14e50e50da5d6b31ffb82ba6ab3913d87a | |
parent | a69830990c285b98701cec9d9ef0e12dc8e045b2 (diff) |
LibraryViewer etc.: User interface refinements including feedback when no results are matched or an empty string is provided.
-rw-r--r-- | src/uk/org/ury/library/LibraryUtils.java | 18 | ||||
-rw-r--r-- | src/uk/org/ury/library/exceptions/EmptySearchException.java | 49 | ||||
-rw-r--r-- | src/uk/org/ury/library/viewer/LibraryViewer.java | 11 | ||||
-rw-r--r-- | src/uk/org/ury/library/viewer/LibraryViewerPanel.java | 153 | ||||
-rw-r--r-- | src/uk/org/ury/library/viewer/library_viewer_gui.xml | 7 |
5 files changed, 209 insertions, 29 deletions
diff --git a/src/uk/org/ury/library/LibraryUtils.java b/src/uk/org/ury/library/LibraryUtils.java index 2843efa..fbccd6f 100644 --- a/src/uk/org/ury/library/LibraryUtils.java +++ b/src/uk/org/ury/library/LibraryUtils.java @@ -13,6 +13,7 @@ import uk.org.ury.database.DatabaseDriver; import uk.org.ury.database.exceptions.QueryFailureException; import uk.org.ury.library.LibraryItem.LibraryProperty; +import uk.org.ury.library.exceptions.EmptySearchException; /** @@ -33,33 +34,40 @@ public class LibraryUtils * @param search The search fragment to include in the search. * Can be empty or null. * - * @throws IllegalArgumentException if db, title or artist + * @throws IllegalArgumentException if the search term is * are null. * * @throws QueryFailureException if the database backend * yielded an error while executing the search * query. * + * @throws EmptySearchException if the search term is + * empty (to be handled as a user error). + * * @return a list of LibraryItems matching the search terms. */ public static List<LibraryItem> search (DatabaseDriver db, String search) - throws QueryFailureException + throws QueryFailureException, EmptySearchException { if (db == null) throw new IllegalArgumentException ("Database handle is null."); if (search == null) throw new IllegalArgumentException ("Search string is null."); + + List<LibraryItem> results = new ArrayList<LibraryItem> (); + + + // Return empty set if the search term is null. if (search.equals("")) - //TODO: Be nicer about this - System.exit(1); + throw new EmptySearchException (); ResultSet rs = null; - List<LibraryItem> results = new ArrayList<LibraryItem> (); + Object[] params = {"%" + search + "%", "%" + search + "%", "%" + search + "%"}; try diff --git a/src/uk/org/ury/library/exceptions/EmptySearchException.java b/src/uk/org/ury/library/exceptions/EmptySearchException.java new file mode 100644 index 0000000..9b4691f --- /dev/null +++ b/src/uk/org/ury/library/exceptions/EmptySearchException.java @@ -0,0 +1,49 @@ +/** + * + */ +package uk.org.ury.library.exceptions; + +/** + * Exception thrown when a library search is initiated + * in which the query string is null. + * + * Frontends should handle this nicely. Do NOT treat this + * as a fatal error! + * + * @author Matt Windsor + */ + +public class EmptySearchException extends Exception +{ + + /** + * Change this! ---v + */ + + private static final long serialVersionUID = -397479334359858162L; + + + /** + * Construct a new EmptySearchException with a + * default reason. + */ + + public + EmptySearchException () + { + super ("Query string was empty."); + } + + + /** + * Construct a new EmptySearchException. + * + * @param reason The explanation for the exception. + */ + + public + EmptySearchException (String reason) + { + super (reason); + } +} diff --git a/src/uk/org/ury/library/viewer/LibraryViewer.java b/src/uk/org/ury/library/viewer/LibraryViewer.java index a631e89..19f94fb 100644 --- a/src/uk/org/ury/library/viewer/LibraryViewer.java +++ b/src/uk/org/ury/library/viewer/LibraryViewer.java @@ -19,6 +19,7 @@ import uk.org.ury.frontend.FrontendFrame; import uk.org.ury.library.LibraryItem; import uk.org.ury.library.LibraryUtils; +import uk.org.ury.library.exceptions.EmptySearchException; public class LibraryViewer extends AbstractFrontendModule { @@ -167,15 +168,15 @@ public class LibraryViewer extends AbstractFrontendModule * This will update the library list to reflect the results of the * search. * - * @param title The title fragment to include in the search. - * Can be empty or null. + * @param search The string fragment to use in searches. + * Cannot be empty or null. * - * @param artist The artist fragment to include in the search. - * Can be empty or null. + * @throws EmptySearchException if the search string is + * empty or null (from LibraryUtils.search). */ public void - doSearch (String search) + doSearch (String search) throws EmptySearchException { try { diff --git a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java index d6c2f79..af35149 100644 --- a/src/uk/org/ury/library/viewer/LibraryViewerPanel.java +++ b/src/uk/org/ury/library/viewer/LibraryViewerPanel.java @@ -5,9 +5,15 @@ package uk.org.ury.library.viewer; import java.net.URL; +import java.util.concurrent.ExecutionException; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.SwingWorker; import org.swixml.SwingEngine; @@ -15,6 +21,7 @@ import uk.org.ury.frontend.FrontendError; import uk.org.ury.frontend.FrontendPanel; import uk.org.ury.frontend.HintField; import uk.org.ury.library.LibraryTableModel; +import uk.org.ury.library.exceptions.EmptySearchException; /** @@ -30,32 +37,28 @@ public class LibraryViewerPanel extends FrontendPanel */ private static final long serialVersionUID = -2441616418398056712L; - - /** - * Action method for performing a search, bound by the UI XML - * manifest to the search field and button - */ - - public void - search () - { - // TODO: SwingWorker? - - master.doSearch (searchField.getText ()); - - // This is necessary to force the table to update with the new results. - - resultsTable.setModel (new LibraryTableModel (master.getLibraryList ())); - } - /* Controller of this panel. */ + private LibraryViewer master; + /* Panel widgets exposed by the SwiXML user interface. */ private JTable resultsTable; + private JScrollPane resultsPane; + private JPanel messagePanel; + private JLabel messageLabel; private JTextField searchField; + private JButton searchButton; + + + /* This contains the last search failure message, for use in + * letting the user know what happened. + */ + + private String searchFailureMessage = "ALEX!"; + /** * Construct a new LibraryViewerPanel. @@ -112,4 +115,118 @@ public class LibraryViewerPanel extends FrontendPanel return "Library Viewer Demo"; } + + /** + * Action method for performing a search, bound by the UI XML + * manifest to the search field and button. + */ + + public void + search () + { + /* We can't let the user search while another search is going on, + * but it's not good to let the search "freeze" the UI. + * + * Hence the search function disables all sensitive parts of the + * interface and launches a search as a background process. + * + * We also swap the results table or no-results panel out for a + * panel that says "Searching...", in the interests of + * user-friendliness. + */ + + searchField.setEnabled (false); + searchButton.setEnabled (false); + resultsPane.setVisible (false); + messageLabel.setText ("Searching..."); + messagePanel.setVisible (true); + + + SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void> () + { + /** + * Perform a task in a separate thread from event-dispatch. + * + * In this case, perform a search. + * + * @return whether or not the search was successful. + */ + + @Override + public Boolean + doInBackground () + { + try + { + master.doSearch (searchField.getText ()); + } + catch (EmptySearchException e) + { + searchFailureMessage = "Please type in a search term."; + return false; + } + + return true; + } + + + /** + * Perform post-search cleanup and finalisation. + */ + + @Override + public void + done () + { + // Figure out whether or not the search succeeded. + + boolean hasSucceeded = false; + + try + { + hasSucceeded = this.get (); + } + catch (InterruptedException e) + { + // Ignore + } + catch (ExecutionException e) + { + // Ignore + } + + + // Force table update with new results. + + resultsTable.setModel (new LibraryTableModel (master.getLibraryList ())); + + + /* Re-enable widgets and swap panels according to whether + * or not results were found. + */ + + searchField.setEnabled (true); + searchButton.setEnabled (true); + messagePanel.setVisible (true); + + if (hasSucceeded == false) + { + messageLabel.setText (searchFailureMessage); + } + else if (master.getLibraryList ().size () == 0) + { + messageLabel.setText ("Sorry, but no results were " + + "found for that term."); + } + else + { + messagePanel.setVisible (false); + resultsPane.setVisible (true); + } + } + }; + + + worker.execute (); + } } diff --git a/src/uk/org/ury/library/viewer/library_viewer_gui.xml b/src/uk/org/ury/library/viewer/library_viewer_gui.xml index 2be08b8..60ae0d1 100644 --- a/src/uk/org/ury/library/viewer/library_viewer_gui.xml +++ b/src/uk/org/ury/library/viewer/library_viewer_gui.xml @@ -2,7 +2,7 @@ <panel layout="BorderLayout"> <hbox constraints="BorderLayout.NORTH" border="EmptyBorder(5,5,5,5)" size="640,32"> <label text="Search for:" labelfor="searchField" displayedmnemonic="VK_F" - font="Verdana-BOLD-14" /> + font="Verdana-BOLD-14" /> <hbox border="EmptyBorder(0,5,0,5)"> <textfield id="searchField" mnemonic="VK_F" action="search" /> </hbox> @@ -14,6 +14,11 @@ <scrollpane id="resultsPane" constraints="BorderLayout.CENTER"> <table id="resultsTable" /> </scrollpane> + <panel id="messagePanel" constraints="BorderLayout.CENTER" visible="false" + layout="BorderLayout"> + <label id="messageLabel" text="Searching..." font="Verdana-BOLD-16" + constraints="BorderLayout.CENTER" horizontalalignment="CENTER" /> + </panel> </hbox> <hbox constraints="BorderLayout.SOUTH" border="EmptyBorder(5,5,5,5)"> |