aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Windsor <mbw500@student.cs.york.ac.uk>2011-02-21 23:01:01 +0000
committerMatt Windsor <mbw500@student.cs.york.ac.uk>2011-02-21 23:01:01 +0000
commitaf1013959f6ab36ed9f2ff603c08116ee1b55c57 (patch)
tree330aaa14e50e50da5d6b31ffb82ba6ab3913d87a
parenta69830990c285b98701cec9d9ef0e12dc8e045b2 (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.java18
-rw-r--r--src/uk/org/ury/library/exceptions/EmptySearchException.java49
-rw-r--r--src/uk/org/ury/library/viewer/LibraryViewer.java11
-rw-r--r--src/uk/org/ury/library/viewer/LibraryViewerPanel.java153
-rw-r--r--src/uk/org/ury/library/viewer/library_viewer_gui.xml7
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)">