source: other-projects/trunk/gs3-webservices-democlient/src/GS3DemoClient/org/greenstone/gs3client/SearchResultsDisplay.java@ 15222

Last change on this file since 15222 was 15222, checked in by ak19, 16 years ago

Greenstone3 web services demo-clientadded to GS3's other-projects

File size: 17.0 KB
Line 
1/**
2 *#########################################################################
3 * SearchResultsDisplay.java - part of the demo-client for Greenstone 3,
4 * of the Greenstone digital library suite from the New Zealand Digital
5 * Library Project at the * University of Waikato, New Zealand.
6 * <BR><BR>
7 * Copyright (C) 2008 New Zealand Digital Library Project
8 * <BR><BR>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 * <BR><BR>
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *########################################################################
19 */
20
21package org.greenstone.gs3client;
22
23import java.awt.Component;
24import java.awt.Container;
25import java.awt.Cursor;
26import java.awt.Dimension;
27import java.awt.BorderLayout;
28import java.awt.FlowLayout;
29
30import javax.swing.JPopupMenu;
31import javax.swing.JPanel;
32import javax.swing.JScrollPane;
33import javax.swing.JSplitPane;
34import javax.swing.JEditorPane;
35import javax.swing.JList;
36import javax.swing.JLabel;
37import javax.swing.JTree;
38import javax.swing.tree.DefaultMutableTreeNode;
39import javax.swing.tree.DefaultTreeModel;
40import javax.swing.tree.TreeSelectionModel;
41import javax.swing.event.TreeSelectionEvent;
42import javax.swing.event.TreeSelectionListener;
43
44import javax.swing.text.html.HTMLDocument;
45
46import org.apache.log4j.Logger;
47import org.greenstone.gs3client.data.DocumentNodeData;
48
49import java.net.URL;
50import java.net.MalformedURLException;
51
52/**
53 * The Search panel inside the Java-client's tab pane that's labelled
54 * "Search Results". This panel contains two tree views:
55 * - one for displaying the list of search results (top-level documents or document
56 * - one for displaying the structure of document nodes selected in the list of
57 * search results.
58 * This panel also contains an area where the selected documentNode's metadata is
59 * displayed, and a text area where the textual or image content of a selected
60 * documentNode is displayed.
61 * @author ak19
62*/
63public class SearchResultsDisplay
64 extends JPanel implements TreeSelectionListener, ColourCombo.ColourChangeable
65{
66 /** The Logger for this class */
67 static Logger LOG = Logger.getLogger(SearchResultsDisplay.class);
68
69 /** Access to the running instance of GS3JavaClient */
70 protected GS3JavaClient client;
71
72 /* GUI items of this SearchResults Panel */
73 protected JTree searchResultsTree, docStructureTree;
74 protected JSplitPane docInfoPane, docInfoWithContent, treeviewSplitPane;
75 protected JEditorPane docContentEditPane;
76 protected JList metanames, metavalues;
77 /** Context menu that pops up when users right click in the browse tree area */
78 protected JPopupMenu popup;
79
80 /** Constructor that creates the Search Panel and its internal GUI items.
81 * @param client is the running instance of the client application through
82 * which its methods can be accessed. */
83 public SearchResultsDisplay(GS3JavaClient client)
84 {
85 super(new FlowLayout(FlowLayout.LEFT));
86 // so the contents of this panel are not centred
87 this.client = client;
88
89 // The panels: searchresults (with a tree), docStructure (also
90 // contains a tree), metadataPanel (with 2 lists for metanames
91 // and metavalues and docContentEditor to show a selected html
92 // document's contents
93 JPanel searchResultsPanel, docStructurePanel, metadataPanel;
94
95 this.docContentEditPane = new JEditorPane();
96 this.docContentEditPane.setEditable(false);
97 this.docContentEditPane.setContentType("text/html");
98 //"text/plain" to view the html markup
99
100 searchResultsPanel = new JPanel(new BorderLayout());
101 docStructurePanel = new JPanel(new BorderLayout());
102 searchResultsPanel.add(
103 new JLabel("Documents returned"), BorderLayout.NORTH);
104 docStructurePanel.add(
105 new JLabel("Document structure"), BorderLayout.NORTH);
106
107 metadataPanel = new JPanel(new BorderLayout());
108 this.metanames = new JList();
109 this.metavalues = new JList();
110 metadataPanel.add(metanames, BorderLayout.WEST);
111 metadataPanel.add(metavalues, BorderLayout.CENTER);
112
113 JPanel metaSuperPanel = new JPanel(new BorderLayout());
114 metaSuperPanel.add(new JLabel("Metadata"), BorderLayout.NORTH);
115 metaSuperPanel.add(
116 new JScrollPane(metadataPanel), BorderLayout.CENTER);
117
118 // Create the searchresults tree and the docStructure tree
119 // (neither of them initialised to any meaningful nodes at present).
120 // Both trees allow only one selection at a time.
121 // Add a listener to both for when their treenode selections change.
122 // Finally add them to their respective JPanels.
123 searchResultsTree = new JTree(new DefaultMutableTreeNode(null));
124 searchResultsTree.getSelectionModel().setSelectionMode(
125 TreeSelectionModel.SINGLE_TREE_SELECTION);
126 searchResultsTree.addTreeSelectionListener(this);
127 searchResultsPanel.add(new JScrollPane(searchResultsTree),
128 BorderLayout.CENTER);
129
130 docStructureTree = new JTree(new DefaultMutableTreeNode(null));
131 docStructureTree.getSelectionModel().setSelectionMode(
132 TreeSelectionModel.SINGLE_TREE_SELECTION);
133 docStructureTree.addTreeSelectionListener(this);
134 docStructurePanel.add(new JScrollPane(docStructureTree),
135 BorderLayout.CENTER);
136 // add a (rightclick) popup menu to the document structure tree:
137 popup = new JPopupMenu();
138 docStructureTree.setComponentPopupMenu(popup);
139 docStructureTree.addMouseListener(new Displays.PopupListener(
140 popup, docStructureTree, client, this.docContentEditPane));
141
142 // Add the docStructure and metadata panels next to each
143 // other within a split pane
144 docInfoPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
145 docInfoPane.setLeftComponent(docStructurePanel);
146 docInfoPane.setRightComponent(metaSuperPanel);
147 docInfoPane.setOneTouchExpandable(true);
148
149 // Add that to the top of the editorpanel showing the contents of
150 // any selected document nodes
151 docInfoWithContent = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
152 docInfoWithContent.setTopComponent(docInfoPane);
153 docInfoWithContent.setBottomComponent(
154 new JScrollPane(this.docContentEditPane));
155 docInfoWithContent.setOneTouchExpandable(true);
156
157 // Add that splitpane to the right of the search results panel
158 // in a new splitpane (horizontal)
159 treeviewSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
160 treeviewSplitPane.setLeftComponent(searchResultsPanel);
161 treeviewSplitPane.setRightComponent(this.docInfoWithContent);
162 treeviewSplitPane.setOneTouchExpandable(true);
163 this.add(treeviewSplitPane);
164
165 // All the scrollviews and the splitpanes will be sized
166 // when getPreferredSize() is called on show()/setVisible()
167 }
168
169 /** Overrode this method to resize the splitpanes within, upon resize.
170 * It calculates the size of this panel, as well as setting those of
171 * the splitpanes it contains based on the size of the parent container.
172 * @return the preferred dimensions of this JPanel. */
173 public Dimension getPreferredSize() {
174 Dimension size = this.getParent().getSize(); //900, 500
175 int x = (int)size.getWidth() / 3;
176 int y = (int)(size.getHeight() / 5 * 2);
177 docInfoPane.setDividerLocation(x);
178 docInfoWithContent.setDividerLocation(y);
179 treeviewSplitPane.setDividerLocation(x);
180 docInfoPane.setPreferredSize(size);
181 docInfoWithContent.setPreferredSize(size);
182 treeviewSplitPane.setPreferredSize(size);
183 return size;
184 }
185
186 /** Changes the colour of the query form and its controls to the
187 * current colours set in class ColourCombo. Specified by
188 * the ColourCombo.ColourChangeable interface. */
189 public void changeUIColour() {
190 Component[] comps = { this, this.docStructureTree,
191 this.searchResultsTree, metanames, metavalues, popup };
192 ColourCombo.changeColor(comps);
193
194 // ensures that the JLabel for "metadata" and the trees
195 // are coloured properly:
196 ColourCombo.changeAncestorColor(metanames);
197 ColourCombo.changeAncestorColor(this.docStructureTree);
198 ColourCombo.changeAncestorColor(this.searchResultsTree);
199 }
200
201 /** Clears the service-specific buttons in the browseBar and the
202 * service-specific display-data. The rest of the GUI (split panes, panels)
203 * remain as they are. Resets the contents of the widgets in this panel. */
204 public void clear() {
205 //searchResultsTree.removeAll();
206 //docStructureTree.removeAll(); // doesn't seem to emtpy tree
207 //this.metanames.removeAll(); //doesn't seem to empty the list values
208 //this.metavalues.removeAll(); //doesn't seem to empty the list values
209
210 // empty the docStructureTree's popup menu too
211 popup.removeAll();
212
213 // empty the trees
214 ((DefaultTreeModel)searchResultsTree.getModel()).setRoot(null);
215 ((DefaultTreeModel)docStructureTree.getModel()).setRoot(null);
216 // empty the metadatalists
217 final String[] empty = {""};
218 this.metanames.setListData(empty);
219 this.metavalues.setListData(empty);
220 // empty the html view area
221 this.docContentEditPane.setText("");
222 }
223
224 /** Restructures the searchResultsTree when another search has been made, so
225 * that the search results contain a new list of documentNodeData objects.
226 * @param resultDocs - the list of (new) DocumentNodeData objects that have
227 * been returned as the results of a query/search operation. */
228 public void setResults(DocumentNodeData[] resultDocs) {
229 // Empty out whatever was in our searchResultsTree and in the
230 // other displays
231 clear();
232
233 // Populate the searchresults tree with each node being a document
234 // that represents a different search result
235 DefaultMutableTreeNode newRoot
236 = new DefaultMutableTreeNode();
237 for(int i = 0; i < resultDocs.length; i++)
238 newRoot.add(new DefaultMutableTreeNode(resultDocs[i]));
239
240 DefaultTreeModel model
241 = (DefaultTreeModel)searchResultsTree.getModel();
242 model.setRoot(newRoot);
243 // We do not want a root, without a root it is perfect for linear
244 // display of search results (a.o.t. hierarchical display)
245 searchResultsTree.setRootVisible(false);
246 // hierarchical display of the first search result (if its root is set)
247 if(resultDocs.length > 0)
248 // array may be empty if there were no resultdocs
249 this.restructureWithNewRoot(resultDocs[0].getRoot());
250 }
251
252 /** Restructures the docStructureTree with a new rootNode when a different
253 * search result has been clicked.
254 * @param rootDocNode - the new root DocumentNodeData whose structure is
255 * to be displayed in the docStructureTree. */
256 protected void restructureWithNewRoot(DocumentNodeData rootDocNode)
257 {
258 DefaultMutableTreeNode root = null;
259 if(rootDocNode != null) {
260 // Create the nodes.
261 root = new DefaultMutableTreeNode(rootDocNode);
262 Displays.createNodesForChildren(rootDocNode, root);
263 }
264 DefaultTreeModel model = (DefaultTreeModel)docStructureTree.getModel();
265
266 docStructureTree.removeAll();
267 model.setRoot(root);
268
269 // empty the contentpane
270 this.docContentEditPane.setText("");
271 }
272
273 /** Part of the TreeSelectionListener interface. When this is called, an item
274 * has been clicked in either the searchResultsTree or the docStructureTree.
275 * This method displays the metadata and textual contents accordingly
276 * of the selected documentNodeData object. */
277 public void valueChanged(TreeSelectionEvent e) {
278 // remove any menuItems in the popup from the previously
279 // selected docNode
280 popup.removeAll();
281
282 DefaultMutableTreeNode node = null;
283 if(e.getSource() == searchResultsTree)
284 node = (DefaultMutableTreeNode)
285 searchResultsTree.getLastSelectedPathComponent();
286 else if(e.getSource() == docStructureTree)
287 node = (DefaultMutableTreeNode)
288 docStructureTree.getLastSelectedPathComponent();
289
290 if(node == null) return;
291 Object nodeInfo = node.getUserObject();
292 // after construction there's nothing in the trees, so check for that:
293 if(nodeInfo == null) return;
294
295 // We need to change to a Wait cursor while we load the documentNode
296 Container c = client.getContentPane();
297 c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
298
299 DocumentNodeData docNode = (DocumentNodeData)nodeInfo;
300
301 // If user had clicked on a searchResult:
302 if(e.getSource() == this.searchResultsTree && node.isLeaf()) {
303 this.client.retrieveTitledStructureFor(docNode);
304 // Now it has set the root and descendents for the
305 // selected docNode
306 DocumentNodeData root = docNode.getRoot();
307 // get the nodestructuredisplay from the client
308 // nodestructure.restructureWithNewRoot(root, docNode);
309 this.restructureWithNewRoot(root);
310
311 // First ensure the metadata for the docNode is set
312 client.retrieveAllMetadataFor(docNode);
313 // now metadata for the document is set
314 // Now, if metadata viewable, then display the metadata
315 // for the root document node:
316 Displays.showMeta(docNode, metanames, metavalues);
317
318 // make the client retrieve the content for the docNode
319 // that's clicked on, and display it in the docContentEditPane
320 client.retrieveContentFor(docNode);
321 // JEditorPane can't handle Justify, it centers such paras
322 // Therefore, left align them instead.
323 String docContent = docNode.getContent();
324 if(docContent != null) {
325 docContent = docContent.replaceAll(
326 "ALIGN=\"JUSTIFY\"", "ALIGN=\"LEFT\"");
327 }
328 this.docContentEditPane.setText(docContent);
329 this.docContentEditPane.setCaretPosition(0); // set 'cursor' at top
330 }
331
332 // If the user had clicked on any docNode - leaf or otherwise
333 // - in the docStructureTree panel:
334 else if(e.getSource() == this.docStructureTree) {
335 // First ensure the metadata for the docNode is set
336 client.retrieveAllMetadataFor(docNode);
337 // now metadata for the document is set
338
339 // Display the metadata for this document node:
340 Displays.showMeta(docNode, metanames, metavalues);
341
342 // if the document has NoText set to 1 (doc has no text), then it
343 // has an image - display this by default
344 if(docNode.hasNoText() && node.isLeaf() /*&& docNode.canBeImage()*/) {
345 this.docContentEditPane.setText(
346 Displays.getImgUrlEnclosedInHtml(docNode.getImgURL()));
347 this.docContentEditPane.setCaretPosition(0);
348 }
349 else { // now we know that the document must have text:
350 // make the client retrieve the content for the docNode
351 // that's clicked on, and display it in the docContentEditPane
352 client.retrieveContentFor(docNode);
353 // Java's htmlpane does not recognise justified alignment.
354 // It displays them all centred. So replace all ALIGN="JUSTIFY"
355 // with ALIGN="LEFT" here. (Not in the DocumentNodeData class,
356 // because our nodeContent should not be transformed: it will
357 // display properly in browsers and other html displays).
358 String docContent = docNode.getContent();
359 if(docContent != null) {
360 docContent = docContent.replaceAll(
361 "ALIGN=\"JUSTIFY\"", "ALIGN=\"LEFT\"");
362 }
363
364 // set the baseURL for digital libraries that use relative paths
365 // to images and don't take care of base paths themselves
366 // (GS3 uses the _httpdocimg_ macro to resolve relative urls)
367 String baseURL = client.getBaseURL();
368 // TODO: make the docNode itself workout its URL by passing
369 // baseURL to the docNode?
370 if(!baseURL.equals("") && docNode.getRoot() != null) {
371 // "" is the case where dlAPIA = gs3
372 // where the _httpdocimg_ macro will deal with
373 // resolving the relative urls into their full ones
374 // We don't want to set the base and meddle with macro
375 // for those cases.
376 // For Fedora's case:
377 HTMLDocument doc
378 = (HTMLDocument)this.docContentEditPane.getDocument();
379 try{
380 URL url = new URL(baseURL+docNode.getRoot().nodeID+"/");
381 //System.err.println("url: " + url.toString());
382 doc.setBase(url);
383 //docContent = docContent.replaceAll("_httpdocimg_/", "");
384 LOG.debug(docContent);
385 }catch(MalformedURLException mex) {
386 ; //nothing to be done, leave the base as it is
387 }
388 }
389 this.docContentEditPane.setText(docContent);
390 // make sure 'cursor' (actually caret) is at the top
391 // Don't want it to autoscroll to the bottom of the contentPane
392 this.docContentEditPane.setCaretPosition(0);
393 }
394 }
395 c.setCursor(Cursor.getDefaultCursor());
396 }
397}
Note: See TracBrowser for help on using the repository browser.