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

Last change on this file since 26180 was 26180, checked in by ak19, 12 years ago
  1. Fixed the democlient to work with the new GS3 again: lots of small things had got broken (such as image display, since the metadata being stored was different). 2. Updating the jar files and democlient distribution zip files with the latest working version of this.
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
329 this.docContentEditPane.setText(docContent);
330 this.docContentEditPane.setCaretPosition(0); // set 'cursor' at top
331 }
332
333 // If the user had clicked on any docNode - leaf or otherwise
334 // - in the docStructureTree panel:
335 else if(e.getSource() == this.docStructureTree) {
336 // First ensure the metadata for the docNode is set
337 client.retrieveAllMetadataFor(docNode);
338 // now metadata for the document is set
339
340 // Display the metadata for this document node:
341 Displays.showMeta(docNode, metanames, metavalues);
342
343 // if the document has NoText set to 1 (doc has no text), then it
344 // has an image - display this by default
345 if(docNode.hasNoText() && node.isLeaf() /*&& docNode.canBeImage()*/) {
346 this.docContentEditPane.setText(
347 Displays.getImgUrlEnclosedInHtml(client.getBaseURL(), docNode.getImgURL()));
348 this.docContentEditPane.setCaretPosition(0);
349 }
350 else { // now we know that the document must have text:
351 // make the client retrieve the content for the docNode
352 // that's clicked on, and display it in the docContentEditPane
353 client.retrieveContentFor(docNode);
354 // Java's htmlpane does not recognise justified alignment.
355 // It displays them all centred. So replace all ALIGN="JUSTIFY"
356 // with ALIGN="LEFT" here. (Not in the DocumentNodeData class,
357 // because our nodeContent should not be transformed: it will
358 // display properly in browsers and other html displays).
359 String docContent = docNode.getContent();
360 if(docContent != null) {
361 docContent = docContent.replaceAll(
362 "ALIGN=\"JUSTIFY\"", "ALIGN=\"LEFT\"");
363 }
364
365 // set the baseURL for digital libraries that use relative paths
366 // to images and don't take care of base paths themselves
367 // (GS3 uses the _httpdocimg_ macro to resolve relative urls)
368 String baseURL = client.getBaseURL();
369 // TODO: make the docNode itself workout its URL by passing
370 // baseURL to the docNode?
371 if(!baseURL.equals("") && docNode.getRoot() != null) {
372 // "" is the case where dlAPIA = gs3
373 // where the _httpdocimg_ macro will deal with
374 // resolving the relative urls into their full ones
375 // We don't want to set the base and meddle with macro
376 // for those cases.
377 // For Fedora's case:
378 HTMLDocument doc
379 = (HTMLDocument)this.docContentEditPane.getDocument();
380 try{
381 URL url = new URL(baseURL+docNode.getRoot().nodeID+"/");
382 //System.err.println("url: " + url.toString());
383 doc.setBase(url);
384 //docContent = docContent.replaceAll("_httpdocimg_/", "");
385 LOG.debug(docContent);
386 }catch(MalformedURLException mex) {
387 ; //nothing to be done, leave the base as it is
388 }
389 }
390 this.docContentEditPane.setText(docContent);
391 // make sure 'cursor' (actually caret) is at the top
392 // Don't want it to autoscroll to the bottom of the contentPane
393 this.docContentEditPane.setCaretPosition(0);
394 }
395 }
396 c.setCursor(Cursor.getDefaultCursor());
397 }
398}
Note: See TracBrowser for help on using the repository browser.