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

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

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

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