source: other-projects/gs3-webservices-java-client/trunk/src/GS3DemoClient/org/greenstone/gs3client/Displays.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: 16.2 KB
Line 
1/**
2 *#########################################################################
3 * Displays.java - part of the demo-client for Greenstone 3, of the
4 * Greenstone digital library suite from the New Zealand Digital Library
5 * 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 org.greenstone.gs3client.data.Pair;
24import java.awt.event.ActionEvent;
25import java.awt.event.ActionListener;
26import java.awt.event.MouseAdapter;
27import java.awt.event.MouseEvent;
28import java.util.Collections;
29import java.util.Comparator;
30import java.util.Iterator;
31import java.util.Map;
32import java.util.Vector;
33import java.util.Map.Entry;
34
35import javax.swing.JEditorPane;
36import javax.swing.JList;
37import javax.swing.JMenuItem;
38import javax.swing.JPopupMenu;
39import javax.swing.JTree;
40import javax.swing.tree.DefaultMutableTreeNode;
41import javax.swing.tree.TreePath;
42
43import org.greenstone.gs3client.data.DocumentNodeData;
44import org.greenstone.gs3client.data.ClassifierNodeData;
45import org.greenstone.gs3client.data.NodeData;
46
47/**
48 * Class containing static methods, static variables and inner classes that
49 * are used by both SearchResultsDisplay and BrowseDisplay.
50 * @author ak19
51*/
52public class Displays {
53 /** Static Comparator object for Pair objects of (name, value) Metadata */
54 protected static final MetadataComparator comparator = new MetadataComparator();
55
56 /* Static methods. */
57 /** Recursion to add all descendent docnodes into the tree.
58 * @param docNode - the documentNodeData object for whose children treenodes
59 * need to be created.
60 * @param treeNode - the treeNode associated with the docNode parameter. */
61 public static void createNodesForChildren(DocumentNodeData docNode,
62 DefaultMutableTreeNode treeNode)
63 {
64 if(docNode == null)
65 return;
66 DocumentNodeData[] children = docNode.getDescendents();
67 if(children == null)
68 return; // base case, the child was a leaf
69
70 for(int i = 0; i < children.length; i++) {
71 DefaultMutableTreeNode childTreeNode
72 = new DefaultMutableTreeNode(children[i]);
73 treeNode.add(childTreeNode);
74
75 // recursion step to add this child node's children to
76 // the treeNode representing it
77 createNodesForChildren(children[i], childTreeNode);
78 }
79 }
80
81 /** JEditorPane cannot deal with &lt;img src="" /&gt;. It can only handle
82 * it without ending slash: &lt;img src="" &gt;.
83 * This method constructs complete html (with html, head and body tags) where
84 * the parameter imgURL is enclosed inside an img src tag.
85 * @param imgURL - src URL for a (web) image
86 * @return the imgURL parameter enclosed in complete html */
87 public static String getImgUrlEnclosedInHtml(String baseURL, String imgURL)
88 {
89 //return "<html><head></head><body><img src=" + imgURL + "></body></html>"; // old Greenstone3
90
91 String htmlStr = "<html><head></head><body>";
92 int index = imgURL.indexOf("<img src=");
93 if(index != -1) { // if it already contains an image tag
94 // check if it's a relative url
95 index = imgURL.indexOf("://", index + "<img src=".length());
96 if(index == -1) { // relative, so doesn't have a file:// or http(s):// prefix
97 imgURL = imgURL.replace("<img src=\"", "<img src=\""+baseURL);
98 }
99 htmlStr += imgURL;
100 }
101 else { // Old GS3: doesn't yet contain an image tag, embed url in img tag
102 htmlStr = htmlStr + "<img src=" + imgURL + ">";
103 }
104 htmlStr += "</body></html>";
105 return htmlStr;
106
107 }
108
109 /** Sorts the metadata of the docNode into the required order and displays
110 * metadata names in the JList metanames and the associated metadata values
111 * in the JList metavalues.
112 * The order is based on metanames: first come all the official metadata
113 * sets which are recognised by the existence of a period in the metaname
114 * (eg. dc.creator, dls.title). These are arranged alphabetically.
115 * Next come all the metadata names that start with a capital letter -
116 * arranged alphabetically;
117 * the remainder are organised alphabetically as well, with the last ones
118 * being those metadata whose names do not start with a letter
119 * (e.g. "/srclink").
120 * @param nodeData is the NodeData object (classifierNodeData or
121 * documentNodeData)
122 * whose metadata is to be displayed in the metanames and metavalues components.
123 * @param metanames - a JList to display all the metadata names of nodeData
124 * @param metavalues - a JList to display all the metadata values of nodeData */
125 public static void showMeta(NodeData nodeData, JList metanames, JList metavalues)
126 {
127 // get the metadata names and values, put them
128 // into separate arrays and set the contents of
129 // JLists metanames and metavalues to these arrays.
130 Map metadata = nodeData.getMetadataList();
131 if(metadata != null && metadata.size() > 0) {
132 Iterator i = metadata.entrySet().iterator();
133 Vector nameValuePairs = new Vector(metadata.size());
134 while(i.hasNext()) {
135 Entry entry = (Entry)i.next();
136 String name = (String)entry.getKey();
137 Vector values = (Vector)entry.getValue();
138 for(int j = 0; j < values.size(); j++) {
139 nameValuePairs.add(new Pair(name, (String)values.get(j)));
140 }
141 }
142 // first sort the Vectors with our comparator:
143 // see http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html
144 // method Collections.sort(List l, Comparator c)
145 // and see http://java.sun.com/j2se/1.4.2/docs/api/java/util/Comparator.html
146
147 // Need to sort the nameValuePairs based on the ordering of the
148 // *names* portion of each Pair.
149 // This ordering is defined by the MetadataComparator object
150 // comparator
151 // OLD: This ordering is defined by the Comparable interface implemented
152 // by the vector contents. No comparator was passed into
153 // Collections.sort(List l) because the vector's contents were Pairs
154 // which implemented Comparable and therefore the elements were sorted
155 // based on their "natural ordering".
156 // see http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Comparable.html
157 // Collections.sort(nameValuePairs);
158 Collections.sort(nameValuePairs, comparator);
159 metanames.setListData(Pair.getFirst(nameValuePairs));
160 metavalues.setListData(Pair.getSecond(nameValuePairs));
161
162 nameValuePairs.clear();
163 nameValuePairs = null;
164 }
165 }
166
167 /** Handles rightclicks on a treeview of documentNodeData objects by showing
168 * the popupMenu with associated files that, when selected, can be displayed
169 * in the htmlPane. Listens to rightclick events, but also handles clicks on
170 * popup menu items.
171 * @see <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/menu.html">Java tutorial on menus</a>
172 */
173 static class PopupListener extends MouseAdapter implements ActionListener
174 {
175 /** Handle to the running GS3JavaClient object to have access to its
176 * methods */
177 final GS3JavaClient client;
178 /** A popup component */
179 final JPopupMenu popupMenu;
180 /** The treeView component on which the rightclicks occurred */
181 final JTree tree;
182 /** The htmlPane wherein associated files are to be displayed */
183 final JEditorPane htmlArea;
184
185 /** Package access inner class. Not static, so it depends on outer class'
186 * PopupListener instance.
187 * Represents a popup MenuItem that appears on rightclick and contains the
188 * name(s) of associated files which will be displayed - if any are selected
189 * - in the main htmlpane. */
190 class AssocFilePopupItem extends JMenuItem {
191 /** The documentNodeData that was rightclicked upon */
192 final DocumentNodeData docNode;
193
194 /** Constructor that creates an AssocFilePopupItem (popup menu item)
195 * instance for each associated file of a documentNodeData that's been
196 * rightclicked on. This popupitem displays the name of the associated
197 * file as a menu item of the popup.
198 * The outer PopupListener object is set to listen to mouseEvents on
199 * this PopupMenuItem. It will listen to clicks on this menuItem to
200 * then display the image. */
201 public AssocFilePopupItem(DocumentNodeData docNode, String name)
202 {
203 super(name);
204 this.docNode = docNode;
205 // PopupListener will also process clicks on this shortcut menuitem
206 this.addActionListener(PopupListener.this);
207 }
208 }
209
210 /** Constructor for the PopupListener.
211 * @param popupMenu - the JPopupMenu object this PopupListener
212 * will handle mouseEvents for
213 * @param tree - the JTree object whose documentNodeData was clicked
214 * @param client - handle to the running GS3JavaClient instance
215 * @param htmlArea - the html editor pane in which to display the
216 * associated file chosen from the popupMenu. */
217 public PopupListener(JPopupMenu popupMenu, JTree tree,
218 GS3JavaClient client, JEditorPane htmlArea)
219 {
220 this.client = client;
221 this.popupMenu = popupMenu;
222 this.tree = tree;
223 this.htmlArea = htmlArea;
224 }
225
226 /** Called when one of the popup's menuItems was clicked.
227 * The associated file represented by the menuItem is displayed in the
228 * html editor pane. */
229 public void actionPerformed(ActionEvent e) {
230 // TODO: later, when all gsdlassocfiles are available for each docNode,
231 // need to change the setText below to make use of imageName and
232 // the docNode's root's assocFilePath
233 AssocFilePopupItem menuItem = (AssocFilePopupItem)e.getSource();
234 DocumentNodeData docNode = menuItem.docNode;
235
236 if(docNode.canBeImage())
237 htmlArea.setText(
238 getImgUrlEnclosedInHtml(client.getBaseURL(), docNode.getImgURL()));
239 // JEditorPane does not understand <img />! So use only <img>
240 else {
241 String filename = menuItem.getText();
242 String filepath = client.getFilePath(docNode);
243 // for the latest exported greenstone colllections
244 // into fedora, Greenstone prefixes FG in front of image name...
245 htmlArea.setText(getImgUrlEnclosedInHtml(client.getBaseURL(), filepath+filename));
246 }
247
248 htmlArea.setCaretPosition(0);
249 popupMenu.removeAll();
250 }
251
252 /** Possibly a popupEvent */
253 public void mouseReleased(MouseEvent e) {
254 // for some reason the popup is visible in miniature, make it
255 // invisible, then decide whether it needs to be shown again
256 popupMenu.setVisible(false);
257 maybeShowPopup(e);
258 }
259
260 /** Possibly a popupEvent */
261 public void mousePressed(MouseEvent e) {
262 maybeShowPopup(e);
263 }
264
265 /** If the mouseEvent was a trigger (rightclick), displays the popup
266 * context menu. */
267 protected void maybeShowPopup(MouseEvent e) {
268 // For some reason e.isPopupTrigger() does not work. (Probably
269 // because the rightclick sometimes happens on the tiny popup
270 // which is visible but too small to see.)
271 // The rightclick appears to only be registered on the popup:
272 // and popup.isPopupTrigger(e) responds even when the popup
273 // is already visible
274 if(popupMenu.isPopupTrigger(e)) {
275 // remove old rightclick menu items
276 popupMenu.removeAll();
277
278 // get the closest node in the docStructureTree to that which
279 // was rightclicked
280 TreePath path = tree.getClosestPathForLocation(
281 e.getX(), e.getY());
282 // the following line will select this nearest node and trigger
283 // TreeSelectionListener by calling valueChanged(), which will
284 // retrieve the structure and display the metadata:
285 (tree.getSelectionModel()).setSelectionPath(path);
286 DefaultMutableTreeNode node
287 = (DefaultMutableTreeNode)path.getLastPathComponent();
288 if(node.getUserObject() instanceof ClassifierNodeData) //
289 return; //
290 DocumentNodeData docNode = (DocumentNodeData)node.getUserObject();
291 // We need the root and the image url part of the metadata, so
292 // ensure we have that:
293 if(docNode.getRoot() == null) //
294 client.retrieveTitledStructureFor(docNode); //
295
296 Vector v = docNode.getAssociatedFileNames();
297 if(v.size() > 0) { // there are associated files
298 for(int i = 0; i < v.size(); i++) {
299 Pair p = (Pair)v.get(i);
300 JMenuItem menuItem
301 = new AssocFilePopupItem(docNode, p.first);
302 popupMenu.add(menuItem);
303 }
304 popupMenu.show(e.getComponent(), e.getX(), e.getY());
305 } else if(docNode.canBeImage()) { // add rightclick popup menu that will
306 // display image upon click
307 JMenuItem menuItem = new AssocFilePopupItem(docNode, docNode.getImgName());
308 popupMenu.add(menuItem);
309 popupMenu.show(e.getComponent(), e.getX(), e.getY());
310 }
311 }
312 }
313 }
314
315 /** Static inner class MetadataComparator is a Comparator for the metadata
316 * fields stored as a list of Pair objects (name, values).
317 * We want to display them alphabetised, grouped by prefix (dls.title, dls.x;
318 * dc.title; dc.creator; greenstone's ex metadata does not have a prefix)
319 * and in order of alphabet BUT all those starting with capital letters come
320 * first, then come those starting with lowercase letters.
321 * Those with prefixes come first of all.
322 * @see http://java.sun.com/j2se/1.4.2/docs/api/java/util/Comparator.html
323 * Comparators can be passed to a sort method (such as Collections.sort) to
324 * allow precise control over the sort order. Comparators can also be used to
325 * control the order of certain data structures (such as TreeSet or TreeMap). */
326 public static class MetadataComparator implements Comparator {
327 public int compare(Object nodeID1, Object nodeID2) {
328 if(nodeID1 == null && nodeID2 == null)
329 return 0;
330 if(nodeID1 == null)
331 return 1;
332 if(nodeID2 == null)
333 return -1;
334
335 String metaName1 = ((Pair)nodeID1).first;
336 String metaName2 = ((Pair)nodeID2).first;
337
338 if(metaName1.equals(metaName2))
339 return 0; // same
340
341 if(metaName1.indexOf('.') != -1 && metaName2.indexOf('.') == -1)
342 return -1; // only c1 has a period, so c1 comes before c2
343 if(metaName2.indexOf('.') != -1 && metaName1.indexOf('.') == -1)
344 return 1; // only c2 has a period, so c2 comes before c1
345
346 // we're going to inspect the first letters, so store these
347 char c1 = metaName1.charAt(0);
348 char c2 = metaName2.charAt(0);
349
350 if(Character.isUpperCase(c1) && Character.isLowerCase(c2))
351 return -1; // only c1 starts with uppercase, so c1 comes before c2
352 if(Character.isUpperCase(c2) && Character.isLowerCase(c1))
353 return 1; // only c2 starts with uppercase, so c2 comes before c1
354
355 // we want metadatanames like "/srclink" to come at the end, because
356 // they don't start with a letter
357 if(!Character.isLetter(c2) && Character.isLetter(c1))
358 return -1; // if c2 starts with some strange character,
359 // c1 comes before c2 in the ordering
360 if(!Character.isLetter(c1) && Character.isLetter(c2))
361 return 1; // if c1 starts with some strange character,
362 // c2 comes before c1 in the ordering
363
364 // otherwise, all else being equal (both start with
365 // uppercase/lowercase or both contain/don't contain periods or
366 // both start with/don't start with letters): so sort them in
367 // alphabetic order.
368 return metaName1.compareTo(metaName2);
369 }
370
371 //public boolean equals(Object obj) {
372 // return obj.equals(this);
373 //}
374 }
375}
Note: See TracBrowser for help on using the repository browser.