| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <title>Lucene Powered Swing Data Models</title> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| </head> |
| <body> |
| <h1><strong> Lucene Powered Swing Data Models </strong></h1> |
| <p><strong>by Jonathan Simon </strong></p> |
| <p> </p> |
| <p><strong>What it is.</strong></p> |
| <p>This package contains classes that help you easily integrate Lucene based searching |
| into your Swing components. Currently there are classes to index and search |
| JTables and JLists. This is done using model decorators rather than custom models |
| to make it easier to search current models as well as new ones. </p> |
| <p><em>These models do not actually contain any data</em>. Rather, the ListModel |
| decorator (ListSearcher) and the TableModel decorator (TableSearcher) take a |
| model in the constructor and delegate all calls to it (after a little alteration, |
| but we'll get to that). That said, these are not full fledged models themselves. |
| You still have to have another model to decorate with the searching models. |
| If you are adding searching to a pre-existing model, you can use your pre-existing |
| model directly. Otherwise, you can implement a model from scratch or use a pre-existing |
| one to get started. </p> |
| <p><strong>What it isn't. </strong></p> |
| <p>A complete component: These are just models. They are not complete components |
| with search fields and buttons laid out like a searchable interface. You still |
| have to build that since the UI changes drastically between applciations.</p> |
| <p>A complete model: There are just model decorators. You can't just set the model |
| of a JList or JTable to one of these models, and you can't add data directly |
| to these models. </p> |
| <p>A front end for a lucene index: In other words, you can't use these classes |
| to point a JTable directly to a Lucene index. Although that's interesting in |
| its own right, this is not that. </p> |
| <p><strong>Usage: </strong></p> |
| <p>Coding to both models nearly identical. They both take the model to decorate |
| at construction time. Here is the code from the demo to decorate a JTable model |
| with the TableSearcher and set it as the table model. </p> |
| <pre><code>//make a new JTable |
| JTable table = new JTable(); |
| //make my base model, the model with the data |
| BaseTableModel tableModel = new BaseTableModel(DataStore.getRestaurants()); |
| //decorate the tableModel with the TableSearcher |
| TableSearcher searchTableModel = new TableSearcher(tableModel); |
| //set the TableModel in the table to the TableSearcher |
| table.setModel(searchTableModel); |
| </code></pre> |
| <p>Initially, you won't notice a difference. This is because there is no active |
| search which displays all data from the underlying model. You search by calling |
| the <code>search</code>() method passing a search string. This filters the data |
| set down without changing the underlying data model -- one of the main reasons |
| for decorating in the first place. Any valid Lucene search string should work |
| (see notes for more info on this). You'll probaby have some code somewhere like |
| this in your app to connect a text field and search button to the model. </p> |
| <pre><code>//create components |
| final JTextField searchField = new JTextField(); |
| JButton searchButton = new JButton("Go"); |
| |
| //make an action listener |
| ActionListener searchListener = new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| searchTableModel.search(searchField.getText().trim().toLowerCase()); |
| } |
| }; |
| |
| //register listeners |
| searchButton.addActionListener(searchListener); |
| searchField.addActionListener(searchListener);</code></pre> |
| <p>You also might want to have a clear search button, working the same way. But |
| to keep things simple, if you search will a <code>null </code>String or an empty |
| String, the search clears and you will once again see all of your data. </p> |
| <p><strong>Demo notes:</strong> </p> |
| <p>The list demo does real time searching. In other words, as you type, searches |
| run and the result set updates. The table demo has a search button, and only |
| searches when the button is clicked. They both work, I just implemented them |
| this way to show the different UI metaphors and that they both work.</p> |
| <p><strong>Implementation notes: </strong></p> |
| <p>This code started as a proof of concept so it's not a <em>fully</em> featured |
| model. Don't get me wrong, it <em>fully</em> works, but it could use some improvement |
| that it will hopefully get over time. I just wanted to get it out there and |
| get people using it. I'm also trying to keep everything as simple as possible. |
| Here are some of the issues. </p> |
| <ul> |
| <li>You can't change the model after the Searcher is constructed. </li> |
| <li>The search model decorators <em>do</em> update when the decorated model |
| is updated, but not in a very efficient way. The whole search model is reindexed |
| when anything changes. This is a definite scaling issue. </li> |
| <li>The indexing and searching logic needs to be generally more configurable |
| to allow custom tailoring of searched and indexing. </li> |
| <li>The TableSearcher uses column names to index column values. This could be |
| an issue with multiple word column names. </li> |
| <li>The ListSearcher uses MultiFieldQueryParser even though its not really indexing |
| multiple fields. </li> |
| </ul> |
| <p> </p> |
| <p> </p> |
| </body> |
| </html> |