source: gs3-extensions/atlas-src/trunk/src/org/greenstone/client/GS3MapLibrary.java@ 22272

Last change on this file since 22272 was 22272, checked in by sjm84, 14 years ago

Initial version of ATLAS as an extension

File size: 79.6 KB
Line 
1package org.greenstone.client;
2
3import com.google.gwt.core.client.EntryPoint;
4import com.google.gwt.core.client.GWT;
5import com.google.gwt.core.client.JsArray;
6import com.google.gwt.user.client.DOM;
7import com.google.gwt.user.client.Element;
8import com.google.gwt.user.client.Window;
9import com.google.gwt.event.dom.client.ChangeEvent;
10import com.google.gwt.event.dom.client.ChangeHandler;
11import com.google.gwt.event.dom.client.ClickEvent;
12import com.google.gwt.event.dom.client.ClickHandler;
13import com.google.gwt.event.dom.client.MouseDownEvent;
14import com.google.gwt.event.dom.client.MouseDownHandler;
15import com.google.gwt.event.dom.client.MouseEvent;
16import com.google.gwt.event.dom.client.MouseMoveEvent;
17import com.google.gwt.event.dom.client.MouseMoveHandler;
18import com.google.gwt.event.dom.client.MouseOutEvent;
19import com.google.gwt.event.dom.client.MouseOutHandler;
20import com.google.gwt.event.dom.client.MouseOverEvent;
21import com.google.gwt.event.dom.client.MouseOverHandler;
22import com.google.gwt.event.dom.client.MouseUpEvent;
23import com.google.gwt.event.dom.client.MouseUpHandler;
24import com.google.gwt.event.logical.shared.ValueChangeEvent;
25import com.google.gwt.event.logical.shared.ValueChangeHandler;
26import com.google.gwt.event.shared.HandlerRegistration;
27import com.google.gwt.http.client.Request;
28import com.google.gwt.http.client.Response;
29import com.google.gwt.http.client.RequestBuilder;
30import com.google.gwt.http.client.RequestCallback;
31import com.google.gwt.maps.client.InfoWindow;
32import com.google.gwt.maps.client.InfoWindowContent;
33import com.google.gwt.maps.client.MapWidget;
34import com.google.gwt.maps.client.control.ControlAnchor;
35import com.google.gwt.maps.client.control.ControlPosition;
36import com.google.gwt.maps.client.control.LargeMapControl;
37import com.google.gwt.maps.client.control.MapTypeControl;
38import com.google.gwt.maps.client.control.Control.CustomControl;
39import com.google.gwt.maps.client.event.MapClickHandler;
40import com.google.gwt.maps.client.event.MapMoveHandler;
41import com.google.gwt.maps.client.event.PolygonClickHandler;
42import com.google.gwt.maps.client.geocode.Geocoder;
43import com.google.gwt.maps.client.geocode.LatLngCallback;
44import com.google.gwt.maps.client.geom.LatLng;
45import com.google.gwt.maps.client.overlay.Marker;
46import com.google.gwt.maps.client.overlay.MarkerOptions;
47import com.google.gwt.maps.client.overlay.Polygon;
48import com.google.gwt.maps.client.overlay.Polyline;
49import com.google.gwt.maps.client.overlay.PolylineOptions;
50import com.google.gwt.user.client.Timer;
51import com.google.gwt.user.client.rpc.AsyncCallback;
52import com.google.gwt.user.client.rpc.ServiceDefTarget;
53import com.google.gwt.user.client.ui.Button;
54import com.google.gwt.user.client.ui.CheckBox;
55import com.google.gwt.user.client.ui.FlowPanel;
56import com.google.gwt.user.client.ui.FormPanel;
57import com.google.gwt.user.client.ui.Frame;
58import com.google.gwt.user.client.ui.HTML;
59import com.google.gwt.user.client.ui.Hidden;
60import com.google.gwt.user.client.ui.HorizontalPanel;
61import com.google.gwt.user.client.ui.Label;
62import com.google.gwt.user.client.ui.ListBox;
63import com.google.gwt.user.client.ui.RootPanel;
64import com.google.gwt.user.client.ui.VerticalPanel;
65import com.google.gwt.user.client.ui.Widget;
66import com.google.gwt.dom.client.FormElement;
67import com.google.gwt.dom.client.InputElement;
68import com.google.gwt.dom.client.NativeEvent;
69import com.google.gwt.dom.client.NodeCollection;
70import com.google.gwt.dom.client.NodeList;
71import com.google.gwt.dom.client.OptionElement;
72import com.google.gwt.dom.client.SelectElement;
73import com.google.gwt.dom.client.TextAreaElement;
74
75import java.util.ArrayList;
76import java.util.HashMap;
77
78public class GS3MapLibrary implements EntryPoint
79{
80 protected MapWidget _map;
81
82 protected VerticalPanel _containerPanel = new VerticalPanel();
83 protected VerticalPanel _scoreAdjustPanel = new VerticalPanel();
84 protected VerticalPanel _headerDiv = new VerticalPanel();
85 protected HorizontalPanel _viewPanel = new HorizontalPanel();
86
87 protected Frame _gsTempFrame = new Frame();
88
89 protected StatusBar _statusBar = new StatusBar();
90
91 protected HTML _gsPanel = new HTML();
92 protected HTML _columnViewBox = new HTML();
93
94 protected HorizontalPanel _contentDiv = new HorizontalPanel();
95 protected HorizontalPanel _footerDiv = new HorizontalPanel();
96
97 protected Menu _currentDocumentMenu = null;
98 protected Menu _lastCreatedPlaceMenu = null;
99
100 protected FlowPanel _radioPanel = new FlowPanel();
101 protected FlowPanel _checkBoxPanel = new FlowPanel();
102
103 protected Label _loadingBox = new Label("");
104 protected Label _mapLoadingLabel = new Label("Loading map content");
105
106 protected ListBox _textViewSelector = new ListBox();
107
108 protected Button _geoQueryButton = new Button("Specify Search Square");
109
110 protected Timer _loadingTimer = null;
111 protected Timer _resizeCheckTimer = null;
112 protected Timer _scrollCheckTimer = null;
113 protected Timer _placeMouseOverTimer = null;
114 protected Timer _documentMouseOverTimer = null;
115 protected Timer _menuOverTimer = null;
116 protected Timer _menuOutTimer = null;
117
118 protected Geocoder _geocoder = null;
119
120 protected static FindPlaceServiceAsync _findPlaceService = GWT.create(FindPlaceService.class);
121
122 protected ArrayList<Place> _currentPlaces = null;
123 protected ArrayList<String> _highlightedPlaces = new ArrayList<String>();
124 protected ArrayList<String> _highlightedTextPlaces = new ArrayList<String>();
125 protected ArrayList<com.google.gwt.dom.client.Element> _mainLinks = new ArrayList<com.google.gwt.dom.client.Element>();
126 protected ArrayList<com.google.gwt.dom.client.Element> _mainScripts = new ArrayList<com.google.gwt.dom.client.Element>();
127 protected ArrayList<Boolean> _visiblePlaceSets = new ArrayList<Boolean>();
128 protected ArrayList<LatLng> _areaPoints = new ArrayList<LatLng>();
129
130 protected ArrayList<ArrayList<Place>> _currentMultiPlaces = null;
131
132 protected HashMap<String, Place> _chosenPlaces = new HashMap<String, Place>();
133
134 protected HandlerRegistration _fishEyeHandlerReg = null;
135 protected HandlerRegistration _columnViewHandlerReg = null;
136
137 protected MapMoveHandler _mapMoveHandler = null;
138 protected MapClickHandler _spatialSearchClickHandler = null;
139 protected SpatialSearchControls _searchControls = null;
140
141 protected final int _MAXVISIBLEMARKERS = 500;
142 protected int _currentZoomLevel = 2;
143 protected int _loadingCount = 0;
144 protected int _currentBrowserPixelWidth = 0;
145 protected int _currentBrowserPixelHeight = 0;
146 protected int _currentScrollTopValue = 0;
147
148 protected boolean _updatingMap = false;
149 protected boolean _gazetteerLoaded = false;
150 protected boolean _redraw = false;
151 protected boolean _resize = false;
152 protected boolean _mapVisible = false;
153 protected boolean _gsVisible = true;
154 protected boolean _frameLoaded = false;
155 protected boolean _initialised = false;
156 protected boolean _showAllPlaces = false;
157 protected boolean _mouseEventPause = false;
158 protected boolean _mapMoveHandlerOn = true;
159 protected boolean _searchResultsPage = false;
160
161 protected String _selectedPlaceName = "";
162 protected String _currentCollection = "";
163 protected String _currentURL = "";
164 protected final String _GREENSTONEURL = "http://localhost:8080/greenstone3";
165 protected final String _GREENSTONEDEVURL = _GREENSTONEURL + "/dev";
166
167 /**
168 * GWT module entry point
169 */
170 public void onModuleLoad()
171 {
172 //Get a Google geocoder to help find places that the Gazetteer does not know the coordinates for
173 _geocoder = new Geocoder();
174
175 ((ServiceDefTarget) _findPlaceService).setServiceEntryPoint("http://localhost:8080/GS3MapLibrary/gs3maplibrary/findPlace");
176
177 //Setup native Javascript functions
178 setUpLoadPageFromUrl(this);
179 setUpLoadPageFromForm(this);
180 setUpLoadSpatialSearchPage(this);
181
182 //Setup the map
183 setUpMap();
184
185 //Make the Firebug console so that browsers that don't have it don't break
186 setUpConsole();
187
188 //Set up the invisible frame that temporarily stores pages as they load
189 setUpTempFrame();
190
191 //Set up the list box that stores the text view options
192 setUpTextViewSelector();
193
194 //Load the Greenstone home page
195 loadPageFromUrl(_GREENSTONEDEVURL);
196 }
197
198 /**
199 * Sets up the invisible frame that temporarily stores pages as they load
200 */
201 public void setUpTempFrame()
202 {
203 //Get the frame for the web page
204 _gsTempFrame.getElement().setId("tempFrame");
205
206 //Make the frame have no size
207 _gsTempFrame.setSize("0px", "0px");
208
209 //Make the frame have no border
210 _gsTempFrame.getElement().getStyle().setProperty("border", "0px");
211
212 //Add the frame to the main frame
213 RootPanel.get("mainFrame").add(_gsTempFrame);
214 }
215
216 /**
217 * Adds the three options to the text view selector
218 */
219 public void setUpTextViewSelector()
220 {
221 _textViewSelector.addItem("Normal");
222 _textViewSelector.addItem("Fisheye");
223 _textViewSelector.addItem("Column");
224 }
225
226 /**
227 * Loads the page at the given URL
228 * @param url is the url to load
229 */
230 public void loadPageFromUrl(final String url)
231 {
232 //Make sure a url was given
233 if(url == null)
234 {
235 return;
236 }
237
238 //Save the given url for later use
239 _currentURL = url;
240
241 //Set Greenstone to be visible
242 _gsVisible = true;
243
244 //Clear the map
245 _map.clearOverlays();
246
247 updateHandlers();
248 clearStatusUpdates();
249
250 //Check if the page being loaded is a search page
251 if (url.contains("s1.query="))
252 {
253 //Load the search page
254 loadSearchPageFromUrl(url);
255 }
256 else
257 {
258 //This page is not a search page
259 _searchResultsPage = false;
260 }
261
262 //If the url contains a collection name
263 if (url.contains("&c="))
264 {
265 //logToConsole("url contains collection");
266 //Store the collection name
267 _currentCollection = getCollectionFromURL(url);
268 }
269
270 //Add the "Page loading" update to the status bar"
271 _statusBar.addUpdate("Loading new page", "LoadPage");
272
273 //Start loading the given url
274 _gsTempFrame.setUrl(url);
275
276 //Create and start the timer that checks if the page is loaded
277 Timer _checkLoadedTimer = getLoadedTimer();
278 _checkLoadedTimer.scheduleRepeating(500);
279 }
280
281 public void loadPageWithoutUrl()
282 {
283 //Set the current url to be empty
284 _currentURL = "";
285
286 //Set Greenstone to be visible
287 _gsVisible = true;
288
289 //Clear the map
290 _map.clearOverlays();
291
292 updateHandlers();
293 clearStatusUpdates();
294
295 //Add the "Page loading" update to the status bar"
296 _statusBar.addUpdate("Loading new page", "LoadPage");
297
298 //Create and start the timer that checks if the page is loaded
299 Timer _checkLoadedTimer = getLoadedTimer();
300 _checkLoadedTimer.scheduleRepeating(500);
301 }
302
303 /**
304 * Clears several of the status updates that should not persist across pages
305 */
306 public void clearStatusUpdates()
307 {
308 _statusBar.removeUpdate("DisPlaces");
309 _statusBar.removeUpdate("SearchLoad");
310 _statusBar.removeUpdate("TextSearch");
311 }
312
313 /**
314 * Gets a collection name from a given url
315 * @param url the url to search for a collection in
316 * @return the collection name
317 */
318 public String getCollectionFromURL(String url)
319 {
320 int start = (url.indexOf("&c=") + 3);
321 int end = -1;
322 if (url.indexOf("&", (url.indexOf("&c=") + 1)) == -1)
323 {
324 end = url.length();
325 }
326 else
327 {
328 end = url.indexOf("&", (url.indexOf("&c=") + 1));
329 }
330 return url.substring(start, end);
331 }
332
333 /**
334 * Sets up various handlers for a new page
335 */
336 public void updateHandlers()
337 {
338 if (_fishEyeHandlerReg != null)
339 {
340 _fishEyeHandlerReg.removeHandler();
341 _fishEyeHandlerReg = null;
342 }
343
344 if (!_mapMoveHandlerOn)
345 {
346 _mapMoveHandlerOn = true;
347 _map.addMapMoveHandler(_mapMoveHandler);
348 }
349
350 if (_searchControls != null)
351 {
352 _map.removeControl(_searchControls);
353 _searchControls = null;
354 }
355
356 if (_spatialSearchClickHandler != null)
357 {
358 _map.removeMapClickHandler(_spatialSearchClickHandler);
359 _spatialSearchClickHandler = null;
360 }
361 }
362
363 /**
364 * Gets the timer than checks for when the pages is loaded and then loads the page
365 * @param url is the url being loaded
366 * @return the timer
367 */
368 public Timer getLoadedTimer()
369 {
370 return new Timer()
371 {
372 int timercount = 0;
373
374 public void run()
375 {
376 //Check to see if we should timeout yet
377 if (timercount++ > 50)
378 {
379 logToConsole("Failed to load page after 50 attempts");
380 this.cancel();
381 return;
382 }
383
384 //Check to see if the page is loaded
385 if (tempFrameGetElementById("banner") != null && tempFrameGetElementById("content") != null && tempFrameGetElementById("footer") != null)
386 {
387 this.cancel();
388 showLoadedPage();
389 }
390 }
391 };
392 }
393
394 /**
395 * Moves the loaded page from the temporary frame to the main page
396 */
397 private void showLoadedPage()
398 {
399 //If ATLAS has not yet been initialised then do so
400 if (!_initialised)
401 {
402 //Fix webpage elements so that they point to the correct address
403 fixForms();
404 fixAnchors();
405 fixImages();
406
407 initialiseATLAS();
408
409 //Add <link> and <script> elements to <head>
410 changeCSSLinksAndScripts();
411 }
412 else
413 {
414 //Add <link> and <script> elements to <head>
415 changeCSSLinksAndScripts();
416
417 //Fix webpage elements so that they point to the correct address
418 fixForms();
419 fixAnchors();
420 fixImages();
421
422 //Swap the current banner with the new banner
423 Element oldBanner = getElementById("banner");
424 Element newBanner = tempFrameGetElementById("banner");
425 oldBanner.getParentElement().removeChild(oldBanner);
426 _headerDiv.insert(HTML.wrap(newBanner), 0);
427
428 //If the content div was in column view mode then reset it
429 if (_contentDiv.getWidget(0).getElement().getId().equals("columnBox"))
430 {
431 _contentDiv.clear();
432 _contentDiv.add(_gsPanel);
433 _contentDiv.add(_map);
434 }
435
436 //Swap the current Greenstone content with the new Greenstone content
437 _gsPanel.setHTML(HTML.wrap(tempFrameGetElementById("content")).getHTML());
438 }
439
440 //If the page is a collection home page then add spatial search to the list of options
441 if (_currentURL.contains("sa=about"))
442 {
443 addSpatialSearchLinkToAboutPage();
444 }
445
446 //The page has now finished being updated
447 _statusBar.removeUpdate("LoadPage");
448
449 //Do an initial resize of the page elements
450 Timer tempResizeTimer = new Timer()
451 {
452 public void run()
453 {
454 resizeElements();
455 }
456 };
457 tempResizeTimer.schedule(500);
458
459 //Check the document's text for places
460 checkDocText();
461 }
462
463 /**
464 * Add a link to spatial searching on the current page
465 */
466 private void addSpatialSearchLinkToAboutPage()
467 {
468 //Get the list to add the link to
469 Element list = getElementById("servicelist");
470
471 //If the list does not exist then stop
472 if(list == null)
473 {
474 return;
475 }
476
477 //Create the div for the link and explanation
478 Element linkLabel = DOM.createDiv();
479 list.appendChild(linkLabel);
480 linkLabel.setClassName("paramLabel");
481
482 //Create the link and append it to the div
483 Element spatialLink = DOM.createAnchor();
484 linkLabel.appendChild(spatialLink);
485 spatialLink.setAttribute("href", "javascript:loadSpatialSearchPageJS()");
486 spatialLink.setInnerText("Spatial Search");
487
488 //Create the explanation div and add to the parent div
489 Element explainationDiv = DOM.createDiv();
490 list.appendChild(explainationDiv);
491 explainationDiv.setClassName("paramLabel");
492 explainationDiv.setInnerText("Search for documents mentioning places from a certain area");
493
494 Element br = DOM.createElement("br");
495 list.appendChild(br);
496 br.setClassName("clear");
497 }
498
499 /**
500 * Initialise the webpage elements for ATLAS
501 */
502 public void initialiseATLAS()
503 {
504 //Get the head section of the HTML page
505 Element head = getDocumentHead();
506
507 //Get all of the <link> elements from the HTML header
508 logToConsole("Saving links");
509 NodeList<com.google.gwt.dom.client.Element> linksToSave = head.getElementsByTagName("link");
510
511 for(int i = 0; i < linksToSave.getLength(); i++)
512 {
513 logToConsole("Link save = " + linksToSave.getItem(i).getAttribute("href"));
514 _mainLinks.add(linksToSave.getItem(i));
515 }
516
517 //Get all of the <script> elements from the HTML header
518 logToConsole("Saving scripts");
519 NodeList<com.google.gwt.dom.client.Element> scriptsToSave = head.getElementsByTagName("script");
520
521 for(int i = 0; i < scriptsToSave.getLength(); i++)
522 {
523 logToConsole("Script save = " + scriptsToSave.getItem(i).getAttribute("src"));
524 _mainScripts.add(scriptsToSave.getItem(i));
525 }
526
527 //Reload the page when the view type is changed
528 _textViewSelector.addChangeHandler(new ChangeHandler()
529 {
530 public void onChange(ChangeEvent event)
531 {
532 if (getDocTextElement() != null)
533 {
534 loadPageFromUrl(_gsTempFrame.getUrl());
535 }
536 }
537 });
538
539 //Set up content
540 _containerPanel.add(_headerDiv);
541 _containerPanel.add(_statusBar.getStatusBarDiv());
542 _containerPanel.add(_contentDiv);
543 _containerPanel.add(_footerDiv);
544
545 _viewPanel.add(new Label("View: "));
546 _viewPanel.add(_textViewSelector);
547 _viewPanel.setVisible(false);
548
549 // Add header
550 _headerDiv.add(HTML.wrap(tempFrameGetElementById("banner")));
551 _headerDiv.add(_viewPanel);
552 _headerDiv.setWidth("100%");
553 _headerDiv.getElement().setId("GSHeader");
554
555 _gsPanel.getElement().getStyle().setProperty("overflow", "auto");
556
557 _contentDiv.setWidth("100%");
558 _contentDiv.getElement().getStyle().setProperty("backgroundColor", "#FFFFFF");
559 _contentDiv.getElement().setId("GSContent");
560
561 // Add content
562 Element contentElement = tempFrameGetElementById("content");
563 _gsPanel = HTML.wrap(contentElement);
564 _contentDiv.add(_gsPanel);
565 _contentDiv.add(_map);
566
567 // Add footer
568 _footerDiv.add(HTML.wrap(tempFrameGetElementById("footer")));
569 _footerDiv.setWidth("100%");
570 _footerDiv.getElement().setId("GSFooter");
571
572 RootPanel.get("mainFrame").add(_containerPanel);
573
574 setUpBrowserResizeCheckTimer();
575
576 // Make the call to check if the Gazetteer is loaded
577 _findPlaceService.isGazetteerLoaded(setUpCheckGazetteerCallback());
578 _initialised = true;
579 }
580
581 /**
582 * Loads a Greenstone search page from a url
583 * @param url is the url to load
584 */
585 public void loadSearchPageFromUrl(String url)
586 {
587 _searchResultsPage = true;
588
589 //Set up the request to get returned documents from the xml
590 RequestBuilder xmlRequest = new RequestBuilder(RequestBuilder.GET, url);
591 try
592 {
593 //Make the request
594 xmlRequest.sendRequest(null, new RequestCallback()
595 {
596 public void onError(Request request, Throwable exception)
597 {
598 logToConsole("xml Request Error -> " + exception.getMessage());
599 }
600
601 public void onResponseReceived(Request request, Response response)
602 {
603 processResponse(response);
604 }
605 });
606 }
607 catch (Exception ex)
608 {
609 ex.printStackTrace();
610 }
611 }
612
613 public void processResponse(Response response)
614 {
615 //If the status code is not the page loaded code then stop
616 if(response.getStatusCode() != 200)
617 {
618 return;
619 }
620
621 //Add the status update that indicates that the system is searching for places in the result document
622 _statusBar.addUpdate("Finding places in result documents", "SearchLoad");
623
624 //Get the response text
625 String text = response.getText();
626
627 //Get the hash codes for the documents
628 ArrayList<String> docURLs = getDocURLsFromResponse(text);
629
630 TemporaryFrame.setCurrentFrameIndex(getNumberOfFrames() - 1);
631 //Load each search result in a temporary frame
632 final ArrayList<TemporaryFrame> tempFrames = new ArrayList<TemporaryFrame>();
633 for (int j = 0; j < docURLs.size(); j++)
634 {
635 //Create the url of the search result
636 String url = _GREENSTONEURL + "/" + docURLs.get(j);
637
638 //Create the temporary frame
639 TemporaryFrame currentFrame = new TemporaryFrame(url);
640
641 //Add the frame to the footer of the page
642 _footerDiv.add(currentFrame.getFrame());
643
644 //Begin loading the page
645 currentFrame.loadPage();
646
647 //Store the frame
648 tempFrames.add(currentFrame);
649 }
650
651 //Create a timer that periodically checks if all the frames have finished loading
652 Timer docsReadyTimer = new Timer()
653 {
654 public void run()
655 {
656 //Check to see if all of the frames have finished loading
657 boolean allDone = true;
658 for (int i = 0; i < tempFrames.size(); i++)
659 {
660 if (!tempFrames.get(i).isFinishedLoading())
661 {
662 logToConsole(i + " has NOT finished loading");
663 allDone = false;
664 }
665 else
666 {
667 logToConsole(i + " has finished loading");
668 }
669 }
670
671 //If all the frames have finished loading
672 if (allDone && _gazetteerLoaded)
673 {
674 this.cancel();
675
676 //Get all of the texts from the frames
677 ArrayList<String> texts = new ArrayList<String>();
678 while (tempFrames.size() > 0)
679 {
680 texts.add(tempFrames.get(0).getText());
681 tempFrames.get(0).removeFromParent();
682 tempFrames.remove(0);
683 }
684
685 findPlacesInTexts(texts);
686 }
687 else
688 {
689 logToConsole("Still getting doc text...");
690 }
691 }
692 };
693 docsReadyTimer.scheduleRepeating(2000);
694 }
695
696 /**
697 * Makes a call to the server to look through multiple places for places
698 * @param texts is a list of texts from different documents
699 */
700 private void findPlacesInTexts(ArrayList<String> texts)
701 {
702 logToConsole("Finished gettings doc text and gazetteer loaded!");
703
704 //Make the call to the server that finds the places
705 _findPlaceService.findPlacesInMultipleTexts(texts, setUpFindMultiplePlacesCallback());
706
707 //Set up the map for viewing multiple places
708 _map.clearOverlays();
709 _mapVisible = true;
710 _map.setVisible(true);
711 _contentDiv.add(_mapLoadingLabel);
712
713 _mapLoadingLabel.getElement().getStyle().setProperty("left", ((int) (_headerDiv.getOffsetWidth() * (3.0 / 4.0) - _mapLoadingLabel.getOffsetWidth() / 2)) + "px");
714 _mapLoadingLabel.getElement().getStyle().setProperty("top", (_headerDiv.getOffsetHeight() + _contentDiv.getOffsetHeight() / 3) + "px");
715
716 _map.getElement().getStyle().setProperty("left", (Window.getClientWidth() / 2 + 8) + "px");
717 _map.getElement().getStyle().setProperty("top", (_headerDiv.getOffsetHeight() + 28 + Window.getScrollTop()) + "px");
718
719 _resize = true;
720 }
721
722 /**
723 * Takes Greenstone search response xml text and extracts the document hashes from it
724 * @param text is the xml to use
725 * @return a list of document hashes
726 */
727 private ArrayList<String> getDocURLsFromResponse(String text)
728 {
729 ArrayList<String> docURLs = new ArrayList<String>();
730
731 int index = text.indexOf("<ul id=\"results\"");
732 int endIndex = text.indexOf("</ul>", index);
733 while ((index = text.indexOf("<a href=\"", index)) != -1 && index < endIndex)
734 {
735 int urlStart = index + "<a href=\"".length();
736 int urlEnd = text.indexOf("\"", urlStart + 1);
737
738 docURLs.add(text.substring(urlStart, urlEnd));
739
740 index++;
741 }
742
743 return docURLs;
744 }
745
746 /**
747 * Creates and shows a spatial search page
748 */
749 public void loadSpatialSearchPage()
750 {
751 //Clear the Greenstone panel
752 _gsPanel.setHTML((new HTML()).getHTML());
753
754 //Turn off the map move handler if it is on
755 if (_mapMoveHandlerOn)
756 {
757 _mapMoveHandlerOn = false;
758 _map.removeMapMoveHandler(_mapMoveHandler);
759 }
760
761 //Set up the page
762 _map.clearOverlays();
763 _mapVisible = true;
764 _gsVisible = false;
765 _map.setVisible(true);
766
767 //Create a new list that will store the points that the user clicks on
768 _areaPoints = new ArrayList<LatLng>();
769
770 //If the map does not currently have a spatial search handler
771 if (_spatialSearchClickHandler == null)
772 {
773 //Create a new map spatial search handler
774 _spatialSearchClickHandler = new MapClickHandler()
775 {
776 public void onClick(MapClickEvent event)
777 {
778 //Take the point that has been clicked and add it to the list
779 LatLng point = event.getLatLng();
780 _areaPoints.add(point);
781
782 //Create a marker at the clicked point
783 MarkerOptions mo = MarkerOptions.newInstance();
784 mo.setClickable(false);
785 Marker marker = new Marker(point, mo);
786 _map.addOverlay(marker);
787
788 //If this is not the first point then add a line between this and the previous point
789 logToConsole("Points array size = " + _areaPoints.size());
790 if (_areaPoints.size() > 1)
791 {
792 PolylineOptions po = PolylineOptions.newInstance();
793 po.setClickable(false);
794
795 Polyline line = new Polyline(new LatLng[] { point, _areaPoints.get(_areaPoints.size() - 2) }, "#FFFFFF", 3, 1, po);
796 logToConsole("Adding line");
797 _map.addOverlay(line);
798 }
799 }
800 };
801 }
802 _map.addMapClickHandler(_spatialSearchClickHandler);
803
804 //If the map does not have search controls then add them
805 if (_searchControls == null)
806 {
807 _searchControls = new SpatialSearchControls(new ControlPosition(ControlAnchor.BOTTOM_RIGHT, 0, 0));
808 }
809 _map.addControl(_searchControls);
810
811 _resize = true;
812 }
813
814 /**
815 * Takes an HTML form element and loads a page using its content
816 * @param form is the form to use
817 */
818 public void loadPageFromForm(Element form)
819 {
820 //Get the top level url
821 StringBuilder url = new StringBuilder(_GREENSTONEDEVURL);
822
823 //Get the elements from the form
824 FormElement formElement = FormElement.as(form);
825 NodeCollection<com.google.gwt.dom.client.Element> elements = formElement.getElements();
826
827 //Go through each element
828 for (int i = 0; i < elements.getLength(); i++)
829 {
830 Element currentItem = (Element) elements.getItem(i);
831
832 //If the element is an input element
833 if (currentItem.getTagName().equals("INPUT"))
834 {
835 InputElement input = InputElement.as(currentItem);
836
837 //If the element is a text or hidden element
838 if (input.getType().equals("text") || input.getType().equals("hidden"))
839 {
840 //Append the name and value of this element to the url
841 url.append("&" + input.getName() + "=" + input.getValue());
842 }
843 //If the element is a radio or checkbox element
844 else if (input.getType().equals("radio") || input.getType().equals("checkbox"))
845 {
846 //If the element has been checked
847 if (input.isChecked())
848 {
849 //Append the name and value of this element to the url
850 url.append("&" + input.getName() + "=" + input.getAttribute("value"));
851 }
852 }
853 }
854 //If the element is a select element (drop down box)
855 else if (currentItem.getTagName().equals("SELECT"))
856 {
857 SelectElement select = SelectElement.as(currentItem);
858 NodeList<OptionElement> options = select.getOptions();
859
860 //Append the name of the element and the value of the currently selected index to the url
861 url.append("&" + select.getName() + "=" + options.getItem(select.getSelectedIndex()).getAttribute("value"));
862 }
863 //If the element is a text area element
864 else if (currentItem.getTagName().equals("TEXTAREA"))
865 {
866 TextAreaElement text = TextAreaElement.as(currentItem);
867
868 //Append the name and value of the text area to the url
869 url.append("&" + text.getName() + "=" + text.getValue());
870 }
871 }
872 //Replace the first & with a ?
873 url.replace(url.indexOf("&"), url.indexOf("&") + 1, "?");
874
875 //Load the page with the created url
876 loadPageFromUrl(url.toString());
877 }
878
879 /**
880 * Remove old CSS links from the page and add new ones, the href attributes are also corrected
881 */
882 public void changeCSSLinksAndScripts()
883 {
884 //Get the head section of the HTML page
885 Element head = getDocumentHead();
886
887 //Get all of the <link> elements from the HTML header
888 NodeList<com.google.gwt.dom.client.Element> currentLinks = head.getElementsByTagName("link");
889
890 //Get all of the <script> elements from the HTML header
891 NodeList<com.google.gwt.dom.client.Element> currentScripts = head.getElementsByTagName("script");
892
893 //Remove all of the old links on the page
894 for(int i = 0; i < currentLinks.getLength(); i++)
895 {
896 currentLinks.getItem(i).getParentElement().removeChild(currentLinks.getItem(i));
897 }
898
899 //Remove all of the old scripts on the page
900 for(int i = 0; i < currentScripts.getLength(); i++)
901 {
902 currentScripts.getItem(i).getParentElement().removeChild(currentScripts.getItem(i));
903 }
904
905 //Add the links present in every page
906 for (int i = 0; i < _mainLinks.size(); i++)
907 {
908 Element e = (Element) _mainLinks.get(i);
909 if(!e.getAttribute("href").startsWith("http://"))
910 {
911 e.setAttribute("href", _GREENSTONEURL + "/" + e.getAttribute("href"));
912 }
913 head.appendChild(e);
914 }
915
916 //Add the scripts present in every page
917 for (int i = 0; i < _mainScripts.size(); i++)
918 {
919 Element e = (Element) _mainScripts.get(i);
920 if(!e.getAttribute("src").startsWith("http://"))
921 {
922 e.setAttribute("src", _GREENSTONEURL + "/" + e.getAttribute("src"));
923 }
924 head.appendChild(e);
925 }
926
927 //Add the new links
928 JsArray<Element> newLinks = tempFrameGetElementsByTagName("link");
929 for (int i = 0; i < newLinks.length(); i++)
930 {
931 Element e = newLinks.get(i);
932 if(!e.getAttribute("href").startsWith("http://"))
933 {
934 e.setAttribute("href", _GREENSTONEURL + "/" + e.getAttribute("href"));
935 }
936 head.appendChild(e);
937 }
938
939 //Add the new scripts on the page
940 JsArray<Element> scripts = tempFrameGetElementsByTagName("script");
941 for (int i = 0; i < scripts.length(); i++)
942 {
943 Element e = scripts.get(i);
944 if(!e.getAttribute("src").startsWith("http://"))
945 {
946 e.setAttribute("src", _GREENSTONEURL + "/" + e.getAttribute("src"));
947 }
948 head.appendChild(e);
949 }
950 }
951
952 /**
953 * Go through each form on the page and add a javascript function in place of its action attribute
954 */
955 public void fixForms()
956 {
957 JsArray<Element> forms = tempFrameGetElementsByTagName("form");
958 for (int i = 0; i < forms.length(); i++)
959 {
960 Element e = forms.get(i);
961 e.setAttribute("id", "form" + i);
962
963 if (!e.getAttribute("action").startsWith("http://"))
964 {
965 e.setAttribute("action", "javascript:loadPageFromFormJS(document.getElementById('form" + i + "'))");
966 }
967 }
968 }
969
970 /**
971 * Go through each anchor on the page and add a javascript function in place of the href attribute
972 */
973 public void fixAnchors()
974 {
975 JsArray<Element> anchors = tempFrameGetElementsByTagName("a");
976 for (int i = 0; i < anchors.length(); i++)
977 {
978 Element e = anchors.get(i);
979
980 if (!e.getAttribute("href").startsWith("http://"))
981 {
982 e.setAttribute("href", _GREENSTONEURL + "/" + e.getAttribute("href"));
983 e.setAttribute("onClick", "loadPageFromUrlJS('" + e.getAttribute("href") + "'); return false;");
984 }
985 }
986 }
987
988 /**
989 * Go through each image on the page and correct its src attribute
990 */
991 public void fixImages()
992 {
993 JsArray<Element> images = tempFrameGetElementsByTagName("img");
994 for (int i = 0; i < images.length(); i++)
995 {
996 Element e = images.get(i);
997 if (!e.getAttribute("src").startsWith("http://"))
998 {
999 e.setAttribute("src", _GREENSTONEURL + "/" + e.getAttribute("src"));
1000 }
1001 }
1002 }
1003
1004 /**
1005 * Makes calls to console.log harmless on browsers that do not have Firebug
1006 */
1007 public static native void setUpConsole()
1008 /*-{
1009 if (! ("console" in $wnd) || !("firebug" in console))
1010 {
1011 var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
1012 $wnd.console = {};
1013 for (var i = 0; i < names.length; ++i) $wnd.console[names[i]] = function() {};
1014 }
1015 }-*/;
1016
1017 /**
1018 * Creates the javascript function that calls the loadPageFromForm GWT function
1019 * @param ml is the instance of the GS3MapLibrary class that you wish to attach this function to
1020 */
1021 public static native void setUpLoadPageFromForm(GS3MapLibrary ml)
1022 /*-{
1023 $wnd.loadPageFromFormJS = function(form)
1024 {
1025 [email protected]::loadPageFromForm(Lcom/google/gwt/user/client/Element;) (form);
1026 };
1027 }-*/;
1028
1029 /**
1030 * Creates the javascript function that calls the loadPageFromURL GWT function
1031 * @param ml is the instance of the GS3MapLibrary class that you wish to attach this function to
1032 */
1033 public static native void setUpLoadPageFromUrl(GS3MapLibrary ml)
1034 /*-{
1035 $wnd.loadPageFromUrlJS = function(url)
1036 {
1037 [email protected]::loadPageFromUrl(Ljava/lang/String;) (url);
1038 };
1039 }-*/;
1040
1041 /**
1042 * Creates the javascript function that calls the loadSpatialSearchPage GWT function
1043 * @param ml is the instance of the GS3MapLibrary class that you wish to attach this function to
1044 */
1045 public static native void setUpLoadSpatialSearchPage(GS3MapLibrary ml)
1046 /*-{
1047 $wnd.loadSpatialSearchPageJS = function()
1048 {
1049 [email protected]::loadSpatialSearchPage() ();
1050 };
1051 }-*/;
1052
1053 /**
1054 * Gets all of the specified type of element in the given frame
1055 * @param frameIndex is the index of the frame to search in
1056 * @param tagname is the specific tag type to get
1057 * @return the list of elements with that tag name
1058 */
1059 public static native JsArray<Element> tempFrameGetElementsByTagName(int frameIndex, String tagname)
1060 /*-{
1061 return $wnd.frames[frameIndex].document.getElementsByTagName(tagname);
1062 }-*/;
1063
1064 /**
1065 * Gets a element specifed by a given id in the specified frame
1066 * @param frameIndex is the index of the frame to search in
1067 * @param id is the id of the element to find
1068 * @return the specified element
1069 */
1070 public static native Element tempFrameGetElementById(int frameIndex, String id)
1071 /*-{
1072 return $wnd.frames[frameIndex].document.getElementById(id);
1073 }-*/;
1074
1075 /**
1076 * Gets the total number of frames in the webpage
1077 * @return the total number of frames
1078 */
1079 public static native int getNumberOfFrames()
1080 /*-{
1081 return $wnd.frames.length;
1082 }-*/;
1083
1084 /**
1085 * Gets an element specified the given id in the intermediate frame
1086 * @param id is the id of the element to find
1087 * @return the specified element
1088 */
1089 public static native Element tempFrameGetElementById(String id)
1090 /*-{
1091 return $wnd.frames[2].document.getElementById(id);
1092 }-*/;
1093
1094 /**
1095 * Gets all of the specified type of element in the intermediate frame
1096 * @param tagname is the specific tag type to get
1097 * @return the list of elements with that tag name
1098 */
1099 public static native JsArray<Element> tempFrameGetElementsByTagName(String tagname)
1100 /*-{
1101 return $wnd.frames[2].document.getElementsByTagName(tagname);
1102 }-*/;
1103
1104 /**
1105 * Prints a given message to the Firebug console
1106 * @param msg is the message to print
1107 */
1108 public static native void logToConsole(String msg)
1109 /*-{
1110 console.log(msg);
1111 }-*/;
1112
1113 /**
1114 * Gets the <head> element of the <html>
1115 * @return the head element
1116 */
1117 public static native Element getDocumentHead()
1118 /*-{
1119 return $doc.getElementsByTagName("head")[0];
1120 }-*/;
1121
1122 /**
1123 * Gets an element specified by the given id in the document
1124 * @param id the id of the element to find
1125 * @return the specified element
1126 */
1127 public static native Element getElementById(String id)
1128 /*-{
1129 return $doc.getElementById(id);
1130 }-*/;
1131
1132 /**
1133 * Gets all of the elements specified by the given tag name
1134 * @param tagName is the tag name of the elements to find
1135 * @return the list of elements specified by the given tag name
1136 */
1137 public static native JsArray<Element> getElementsByTagName(String tagName)
1138 /*-{
1139 return $doc.getElementsByTagName(tagName);
1140 }-*/;
1141
1142 /**
1143 * Calls the method the initialises the fisheye viewing
1144 */
1145 public static native void setUpFishEye()
1146 /*-{
1147 console.log("Fish eye set up");
1148 $wnd.fishEyeSetUp();
1149 }-*/;
1150
1151 /**
1152 * Passes the mouse y coordinates from the GWT handler to the fisheye handler
1153 * @param y is the mouse y coordinate
1154 */
1155 public static native void passMouseCoordsToFishEye(int y)
1156 /*-{
1157 $wnd.checkMousePos(y);
1158 }-*/;
1159
1160 /**
1161 * Sets up the timer that checks periodically whether or not the elements in the page need to be resized
1162 */
1163 public void setUpBrowserResizeCheckTimer()
1164 {
1165 _resizeCheckTimer = new Timer()
1166 {
1167 public void run()
1168 {
1169 if (_currentBrowserPixelHeight != Window.getClientHeight() || _currentBrowserPixelWidth != Window.getClientWidth() || _resize)
1170 {
1171 _resize = false;
1172 resizeElements();
1173 _currentBrowserPixelHeight = Window.getClientHeight();
1174 _currentBrowserPixelWidth = Window.getClientWidth();
1175 }
1176 }
1177 };
1178 _resizeCheckTimer.scheduleRepeating(500);
1179 }
1180
1181 /**
1182 * Resizes elements based on the current width and height of the browser window
1183 */
1184 public void resizeElements()
1185 {
1186 //Get the width and height we want to use for the content div
1187 int cwidth = Window.getClientWidth() - 45;
1188 int cheight = (int) (Window.getClientHeight() - _headerDiv.getOffsetHeight() - _footerDiv.getOffsetHeight() - 70);
1189
1190 //If the height is less than 300 then set it to 300
1191 if (cheight < 300)
1192 {
1193 cheight = 300;
1194 }
1195
1196 //Set the widths of the header and footer divs
1197 _headerDiv.setWidth(cwidth + "px");
1198 _footerDiv.setWidth(cwidth + "px");
1199
1200 //Set the size of the content div
1201 _contentDiv.setSize(cwidth + "px", (cheight + 50) + "px");
1202
1203 //Set up the style of the Greenstone panel
1204 _gsPanel.getElement().getStyle().setProperty("position", "absolute");
1205 _gsPanel.getElement().getStyle().setProperty("overflow", "auto");
1206
1207 //Set up the style of the Map panel
1208 _map.getElement().getStyle().setProperty("position", "absolute");
1209 _map.getElement().getStyle().setProperty("top", _contentDiv.getAbsoluteTop() + "px");
1210
1211 //If the map is visible and the Greenstone panel is visible
1212 if (_mapVisible && _gsVisible)
1213 {
1214 _map.setSize((cwidth / 2 - 60) + "px", cheight + "px");
1215 _map.getElement().getStyle().setProperty("left", (cwidth / 2 + 50) + "px");
1216 _gsPanel.setSize((cwidth / 2) + "px", cheight + "px");
1217 }
1218
1219 //If the map is visible and the Greenstone panel is not visible
1220 if (_mapVisible && !_gsVisible)
1221 {
1222 _gsPanel.setSize("0px", "0px");
1223 _map.setSize((cwidth - 40) + "px", cheight + "px");
1224 _map.getElement().getStyle().setProperty("left", _gsPanel.getAbsoluteLeft() + "px");
1225 }
1226
1227 //If the map is not visible and the Greenstone panel is visible
1228 if (!_mapVisible && _gsVisible)
1229 {
1230 _gsPanel.setSize(cwidth + "px", cheight + "px");
1231 _map.setSize("0px", "0px");
1232 }
1233
1234 //If neither panel is visible
1235 if (!_mapVisible && !_gsVisible)
1236 {
1237 _gsPanel.setSize("0px", "0px");
1238 _map.setSize("0px", "0px");
1239 }
1240 }
1241
1242 /**
1243 * Initialises the Google Map view
1244 */
1245 public void setUpMap()
1246 {
1247 //Set up the map size, style, starting point and zoom level
1248 LatLng startPoint = LatLng.newInstance(0, 0);
1249 _map = new MapWidget(startPoint, _currentZoomLevel);
1250 _map.setSize(Window.getClientWidth() / 2 + "px", "600px");
1251 _map.getElement().getStyle().setProperty("margin", "5px");
1252 _map.setStyleName("map");
1253
1254 //Store the default map move handler
1255 _mapMoveHandler = new MapMoveHandler()
1256 {
1257 public void onMove(MapMoveEvent event)
1258 {
1259 if (_map.getZoomLevel() != _currentZoomLevel)
1260 {
1261 _currentZoomLevel = _map.getZoomLevel();
1262 _map.clearOverlays();
1263
1264 //If this is not a search page then there is only one place set
1265 if(!_searchResultsPage)
1266 {
1267 addPlacesToMap(_currentPlaces, "#FFFFFF", "#00FF00", _searchResultsPage);
1268 }
1269 //If this is a search page then there are likely to be multiple place sets
1270 else
1271 {
1272 displayMultiplePlaceSets();
1273 }
1274 }
1275 }
1276 };
1277 _map.addMapMoveHandler(_mapMoveHandler);
1278
1279 // Add some controls for the zoom level
1280 _map.addControl(new LargeMapControl());
1281 _map.addControl(new MapTypeControl());
1282
1283 //Add the map loading label
1284 _mapLoadingLabel.setStyleName("mapLoadingLabel");
1285 _mapLoadingLabel.getElement().getStyle().setProperty("left", ((int) (_headerDiv.getOffsetWidth() * (3.0 / 4.0) - _mapLoadingLabel.getOffsetWidth() / 2)) + "px");
1286 _mapLoadingLabel.getElement().getStyle().setProperty("top", (_headerDiv.getOffsetHeight() + _contentDiv.getOffsetHeight() / 3) + "px");
1287
1288 //Make the map initially invisible
1289 _map.setVisible(false);
1290 }
1291
1292 /**
1293 * Creates a marker at the given point
1294 * @param p is the place to create a marker for
1295 * @param point is the point to place the marker at (if this is null the place will be used to provide the coordinates)
1296 * @param borderColour is the colour of the border to use
1297 * @param fillColour is the colour to use to fill the marker
1298 * @param colourInfo stores whether or not to show a coloured rectangle in the information box that is shown when the marker is clicked
1299 * @return the marker
1300 */
1301 public Polygon createMarkerAtPoint(Place p, LatLng point, String borderColour, String fillColour, Boolean colourInfo)
1302 {
1303 float lat = 0.0f;
1304 float lng = 0.0f;
1305
1306 //Get the coordinates
1307 if (point == null)
1308 {
1309 lat = p.getLatitude();
1310 lng = p.getLongitude();
1311 }
1312 else
1313 {
1314 lat = (float) point.getLatitude();
1315 lng = (float) point.getLongitude();
1316 }
1317
1318 LatLng newPoint = ((point == null) ? LatLng.newInstance(lat, lng) : point);
1319
1320 //Work out the size of the new marker based on the current zoom level
1321 double size = 4.0 / (_map.getZoomLevel() * (_map.getZoomLevel() / 2));
1322
1323 //Create the corner of the polygon
1324 LatLng tl = LatLng.newInstance(lat - size, lng + size);
1325 LatLng tr = LatLng.newInstance(lat + size, lng + size);
1326 LatLng br = LatLng.newInstance(lat + size, lng - size);
1327 LatLng bl = LatLng.newInstance(lat - size, lng - size);
1328
1329 //If the user has chosen to highlight this place then make the marker red
1330 Polygon newMarker = null;
1331 if (_highlightedPlaces.contains(p.getName()))
1332 {
1333 newMarker = new Polygon(new LatLng[] { tl, tr, br, bl, tl }, borderColour, 1, 1, "#FF0000", 0.75);
1334 }
1335 //Otherwise make it the normal colour
1336 else
1337 {
1338 newMarker = new Polygon(new LatLng[] { tl, tr, br, bl, tl }, borderColour, 1, 1, fillColour, 0.75);
1339 }
1340
1341 // When the marker is clicked it will show its address in a info box
1342 newMarker.addPolygonClickHandler(new MarkerClickHandler(fillColour, p, newPoint, colourInfo));
1343
1344 return newMarker;
1345 }
1346
1347 /**
1348 * Shows an info box above the marker when the marker is clicked
1349 */
1350 public class MarkerClickHandler implements PolygonClickHandler
1351 {
1352 String _fillColour = "";
1353 Boolean _colourInfo = false;
1354 LatLng _point = null;
1355 Place _place = null;
1356
1357 public MarkerClickHandler(String fillColour, Place place, LatLng point, Boolean colourInfo)
1358 {
1359 _fillColour = fillColour;
1360 _place = place;
1361 _point = point;
1362 _colourInfo = colourInfo;
1363 }
1364
1365 public void onClick(PolygonClickEvent event)
1366 {
1367 InfoWindow info = _map.getInfoWindow();
1368 if (_colourInfo)
1369 {
1370 info.open(_point, new InfoWindowContent(createPlaceInformationString(_place)));
1371 }
1372 else
1373 {
1374 info.open(_point, new InfoWindowContent("<span style=\"background: " + _fillColour + "; color: " + _fillColour + ";\">...</span> " + createPlaceInformationString(_place)));
1375 }
1376 }
1377 }
1378
1379 /**
1380 * Takes a place object and creates a string with information about that place
1381 * @param p is the place to make an information string from
1382 * @return the information string
1383 */
1384 public String createPlaceInformationString(Place p)
1385 {
1386 //If we do not have a valid place then stop
1387 if(p == null)
1388 {
1389 return null;
1390 }
1391
1392 //Add the place name to the string
1393 StringBuilder s = new StringBuilder(p.getName());
1394
1395 //Add the full parent name to the string
1396 if (p.getParentPlaceName() != null)
1397 {
1398 s.append(" in " + p.getParentPlaceName());
1399 }
1400
1401 //If we have population information then add it to the string
1402 if (p.getPopulation() > 0)
1403 {
1404 StringBuilder pop = new StringBuilder(Long.toString(p.getPopulation()));
1405
1406 //Insert commas into long numbers
1407 for (int i = pop.length() - 3; i > 0; i -= 3)
1408 {
1409 pop.insert(i, ',');
1410 }
1411
1412 s.append("<br/>Population: " + pop);
1413 }
1414
1415 //If we have coordinates then add those to the string as well
1416 if (p.getLongitude() != null && p.getLatitude() != null)
1417 {
1418 StringBuilder lat = new StringBuilder(Float.toString(p.getLatitude()));
1419 StringBuilder lng = new StringBuilder(Float.toString(p.getLongitude()));
1420
1421 //Shorten coordinates to 3 decimal places
1422 int i = 0;
1423 while (lat.charAt(i++) != '.');
1424 int j = 0;
1425 while (lng.charAt(j++) != '.');
1426
1427 if ((i + 3) < lat.length())
1428 {
1429 lat.delete(i + 3, lat.length());
1430 }
1431
1432 if ((j + 3) < lng.length())
1433 {
1434 lng.delete(j + 3, lng.length());
1435 }
1436
1437 s.append("<br/>Coordinates: " + lat + ", " + lng);
1438 }
1439
1440 return s.toString();
1441 }
1442
1443 /**
1444 * Make a call to the server that gets places that match the given criteria
1445 */
1446 public void updateCurrentPlaces()
1447 {
1448 _findPlaceService.getPlaces(0, 100, 0, true, true, true, _MAXVISIBLEMARKERS, setUpGetPlacesCallback());
1449 }
1450
1451 /**
1452 * Displays all of the place sets created from a text search
1453 */
1454 public void displayMultiplePlaceSets()
1455 {
1456 //Clear the map
1457 _map.clearOverlays();
1458
1459 //Go through each place set and if it has been marked visible then add it
1460 for (int j = 0; j < _currentMultiPlaces.size(); j++)
1461 {
1462 logToConsole("Adding set " + j + " to the map");
1463 if (_visiblePlaceSets.get(j))
1464 {
1465 addPlacesToMap(_currentMultiPlaces.get(j), "#FFFFFF", numToColour(j, _currentMultiPlaces.size(), 100, 255), true);
1466 }
1467 }
1468 _statusBar.removeUpdate("DisPlaces");
1469 }
1470
1471 /**
1472 * Creates a colour from the given parameters
1473 * @param num is the specified index
1474 * @param max is the total number of indexes
1475 * @param cmin is the minimum colour
1476 * @param cmax is the maximum colour
1477 * @return the colour string (e.g. #F35A22)
1478 */
1479 public String numToColour(int num, int max, int cmin, int cmax)
1480 {
1481 logToConsole("num = " + num + ", max = " + max + ", cmin = " + cmin + ", cmax = " + cmax);
1482 //Make sure num and max are good numbers
1483 if(num < 0){num = 0;}
1484 if(max <= 0){return "#000000";}
1485 if(max > 255){max = 255;}
1486 if(num > max){num = max;}
1487
1488 //Work out where this colour will lie in the spectrum
1489 int colourNum = (int) ((((float) num) / ((float) max)) * ((cmax - cmin) * 8));
1490
1491 String red = null;
1492 String green = null;
1493 String blue = null;
1494
1495 //If the colour is in the first section then make it a mix between red and green
1496 if (colourNum <= (cmax - cmin) * 2)
1497 {
1498 if (colourNum <= (cmax - cmin))
1499 {
1500 red = Integer.toHexString(colourNum + cmin);
1501 green = "00";
1502 blue = "00";
1503 }
1504 else
1505 {
1506 colourNum -= (cmax - cmin);
1507 red = Integer.toHexString(cmax);
1508 green = Integer.toHexString(colourNum + cmin);
1509 blue = "00";
1510 }
1511 }
1512 //If the colour is in the second section then make it a mix between green and blue
1513 else if (colourNum <= (cmax - cmin) * 4)
1514 {
1515 colourNum -= ((cmax - cmin) * 2);
1516 if (colourNum <= (cmax - cmin))
1517 {
1518 red = "00";
1519 green = Integer.toHexString(colourNum + cmin);
1520 blue = "00";
1521 }
1522 else
1523 {
1524 colourNum -= (cmax - cmin);
1525 red = "00";
1526 green = Integer.toHexString(cmax);
1527 blue = Integer.toHexString(colourNum + cmin);
1528 }
1529 }
1530 //If the colour is in the third section then make it a mix between red and blue
1531 else if (colourNum <= (cmax - cmin) * 6)
1532 {
1533 colourNum -= ((cmax - cmin) * 4);
1534 if (colourNum <= (cmax - cmin))
1535 {
1536 red = "00";
1537 green = "00";
1538 blue = Integer.toHexString(colourNum + cmin);
1539 }
1540 else
1541 {
1542 colourNum -= (cmax - cmin);
1543 red = Integer.toHexString(colourNum + cmin);
1544 green = "00";
1545 blue = Integer.toHexString(cmax);
1546 }
1547 }
1548 //If the colour is in the fourth section then make it a mix between all colours
1549 else
1550 {
1551 colourNum -= ((cmax - cmin) * 6);
1552 colourNum /= 2;
1553
1554 red = Integer.toHexString(colourNum + cmin);
1555 green = Integer.toHexString(colourNum + cmin);
1556 blue = Integer.toHexString(colourNum + cmin);
1557 }
1558
1559 //If the hex strings are only one character long then add a zero the the front
1560 if (red.length() < 2){red = "0" + red;}
1561 if (green.length() < 2){green = "0" + green;}
1562 if (blue.length() < 2){blue = "0" + blue;}
1563
1564 logToConsole("#" + red + green + blue);
1565 return "#" + red + green + blue;
1566 }
1567
1568 /**
1569 * Takes an array of places and displays them on the map
1570 * @param places is the list of places to display
1571 * @param borderColour is the colour of the marker borders
1572 * @param fillColour is the main colour of the marker
1573 * @param colourInfo is whether or not to display a coloured box in the information box of the marker
1574 */
1575 public void addPlacesToMap(ArrayList<Place> places, String borderColour, String fillColour, boolean colourInfo)
1576 {
1577 //If we do not have a valid set of places then stop
1578 if(places == null || places.size() == 0)
1579 {
1580 return;
1581 }
1582
1583 ArrayList<Place> placesSeen = new ArrayList<Place>();
1584
1585 // Make the best places visible
1586 for (Place p : places)
1587 {
1588 if (!_showAllPlaces)
1589 {
1590 //If the place is not directly referenced then don't use it
1591 if (!p.isDirectlyReferenced())
1592 {
1593 continue;
1594 }
1595
1596 //If a different place with this name has been chosen then don't use it
1597 if (_chosenPlaces.containsKey(p.getName()) && !_chosenPlaces.get(p.getName()).equals(p))
1598 {
1599 continue;
1600 }
1601
1602 //Make sure we only add the place once
1603 boolean found = false;
1604 for (Place q : placesSeen)
1605 {
1606 if (p.getName().equals(q.getName()))
1607 {
1608 found = true;
1609 }
1610 }
1611
1612 if (found)
1613 {
1614 continue;
1615 }
1616 placesSeen.add(p);
1617 }
1618
1619 // If there is no latitude and longitude provided for this place
1620 if (p.getLatitude() == null)
1621 {
1622 // Use Google's geocoder to find the place
1623 findAndMarkAddress(p, borderColour, fillColour, colourInfo);
1624 }
1625 // Latitude and longitude are provided in the address
1626 else
1627 {
1628 Polygon marker = createMarkerAtPoint(p, null, borderColour, fillColour, colourInfo);
1629 // Add the marker to the map
1630 _map.addOverlay(marker);
1631 }
1632 }
1633 }
1634
1635 /**
1636 * Finds and puts a marker at the given address using Google's geocoder service
1637 * @param address is the address to find and mark (e.g. Hamilton, Waikato, New Zealand)
1638 * @param index is where in the list of place locations this is to be added
1639 */
1640 private void findAndMarkAddress(final Place place, final String borderColour, final String fillColour, final boolean colourInfo)
1641 {
1642 String address = null;
1643
1644 if (place.getParentPlaceName() != null)
1645 {
1646 address = place.getName() + ", " + place.getParentPlaceName();
1647 }
1648 else
1649 {
1650 address = place.getName();
1651 }
1652
1653 // Make the call to the geocoder service
1654 _geocoder.getLatLng(address, new LatLngCallback()
1655 {
1656 // Ignore the place if it is not valid
1657 public void onFailure()
1658 {
1659 // LogToConsole("Failed");
1660 }
1661
1662 // If the geocoder service found the place
1663 public void onSuccess(final LatLng point)
1664 {
1665 // LogToConsole("Found");
1666 Polygon marker = createMarkerAtPoint(place, point, borderColour, fillColour, colourInfo);
1667
1668 place.setLatitude((float) point.getLatitude());
1669 place.setLongitude((float) point.getLongitude());
1670
1671 // Add the marker to the map
1672 _map.addOverlay(marker);
1673 }
1674 });
1675 }
1676
1677 public AsyncCallback<ArrayList<Place>> setUpGetPlacesCallback()
1678 {
1679 AsyncCallback<ArrayList<Place>> callback = new AsyncCallback<ArrayList<Place>>()
1680 {
1681 public void onFailure(Throwable caught)
1682 {
1683 logToConsole("Get Places FAIL" + caught.getMessage());
1684 }
1685
1686 // This is called when a successful call to findAllPlaces() is
1687 // completed
1688 public void onSuccess(ArrayList<Place> places)
1689 {
1690 logToConsole("Get Places Success!");
1691 _currentPlaces = places;
1692
1693 addPlacesToMap(places, "#FFFFFF", "#00FF00", _searchResultsPage);
1694 _updatingMap = false;
1695 }
1696 };
1697
1698 return callback;
1699 }
1700
1701 /**
1702 * Creates the callback object that is used when the call to the server returns
1703 * @return the callback object
1704 */
1705 public AsyncCallback<Boolean> setUpFindPlacesCallback()
1706 {
1707 return new AsyncCallback<Boolean>()
1708 {
1709 /**
1710 * This is called when the call to the server fails
1711 */
1712 public void onFailure(Throwable caught)
1713 {
1714 _statusBar.removeUpdate("TextSearch");
1715 logToConsole("Find places fail" + caught.getMessage());
1716 }
1717
1718 /**
1719 * This is called when the call to the server succeeds
1720 * @param result is a dummy variable that does not do anything
1721 */
1722 public void onSuccess(Boolean result)
1723 {
1724 //Remove the "searching for places" status bar message
1725 _statusBar.removeUpdate("TextSearch");
1726
1727 logToConsole("Find Places success!");
1728
1729 //Get the marked up text from the server
1730 _findPlaceService.getMarkedUpText(setUpGetMarkedUpTextCallback());
1731
1732 //Get the found places from the server
1733 updateCurrentPlaces();
1734
1735 //Clear the map
1736 _map.clearOverlays();
1737
1738 //Add the new places to the map
1739 addPlacesToMap(_currentPlaces, "#FFFFFF", "#00FF00", _searchResultsPage);
1740
1741 //Remove the "map loading" message from the map
1742 _mapLoadingLabel.removeFromParent();
1743 }
1744 };
1745 }
1746
1747 public AsyncCallback<ArrayList<ArrayList<Place>>> setUpFindMultiplePlacesCallback()
1748 {
1749 AsyncCallback<ArrayList<ArrayList<Place>>> callback = new AsyncCallback<ArrayList<ArrayList<Place>>>()
1750 {
1751 public void onFailure(Throwable caught)
1752 {
1753 logToConsole("Find multi places fail" + caught.getMessage());
1754 }
1755
1756 public void onSuccess(ArrayList<ArrayList<Place>> places)
1757 {
1758 _statusBar.removeUpdate("SearchLoad");
1759 _statusBar.addUpdate("Displaying places", "DisPlaces");
1760
1761 logToConsole("Find multi places success");
1762 _currentMultiPlaces = places;
1763 _visiblePlaceSets = new ArrayList<Boolean>();
1764 for (int i = 0; i < _currentMultiPlaces.size(); i++)
1765 {
1766 _visiblePlaceSets.add(true);
1767 }
1768
1769 _mapLoadingLabel.removeFromParent();
1770 displayMultiplePlaceSets();
1771 addElementsToSearchResults(places);
1772 }
1773 };
1774 return callback;
1775 }
1776
1777 public AsyncCallback<Boolean> setUpCheckGazetteerCallback()
1778 {
1779 AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>()
1780 {
1781 public void onFailure(Throwable caught)
1782 {
1783 logToConsole("Check Gazetteer fail " + caught.getMessage());
1784 }
1785
1786 public void onSuccess(Boolean result)
1787 {
1788 if (!result)
1789 {
1790 _statusBar.addUpdate("Server is loading gazetteer", "GazLoad");
1791
1792 _findPlaceService.loadGazetteer(setUpLoadGazetteerCallback());
1793 }
1794 else
1795 {
1796 logToConsole("Gazetteer Already Loaded!");
1797 _gazetteerLoaded = true;
1798 }
1799 }
1800 };
1801 return callback;
1802 }
1803
1804 /**
1805 * Checks to see if the current page has text from a document so that it can be checked for places
1806 */
1807 public void checkDocText()
1808 {
1809 //Get the document text element if it exists
1810 Element documentText = getDocTextElement();
1811
1812 //If it does not exist then stop
1813 if (documentText == null)
1814 {
1815 logToConsole("document text div not found");
1816 if (_mapVisible)
1817 {
1818 _map.setVisible(false);
1819 _mapVisible = false;
1820 }
1821 _viewPanel.setVisible(false);
1822 return;
1823 }
1824
1825 logToConsole("Document text found!");
1826
1827 //Allow the user to change the method they wish to use view the text
1828 _viewPanel.setVisible(true);
1829
1830 //If the view type is not set to normal then remove the TOC
1831 if (_textViewSelector.getSelectedIndex() > 0)
1832 {
1833 HTML.wrap(getElementById("rightSidebar")).setVisible(false);
1834 }
1835
1836 //Create the document menu if we have not already done so
1837 if (_currentDocumentMenu == null)
1838 {
1839 createDocumentMenu();
1840 }
1841
1842 //Create the timer that closes the document menu when it is not in focus
1843 _menuOutTimer = new Timer()
1844 {
1845 public void run()
1846 {
1847 _currentDocumentMenu.hideMenu();
1848 }
1849 };
1850
1851 //Let the user know that the system is searching for places
1852 _statusBar.addUpdate("Searching text for places", "TextSearch");
1853
1854 //Clear the map
1855 _map.clearOverlays();
1856
1857 //Make the map visible
1858 _mapVisible = true;
1859 _map.setVisible(true);
1860
1861 //Add the "Loading" message to the map
1862 _contentDiv.add(_mapLoadingLabel);
1863
1864 _mapLoadingLabel.getElement().getStyle().setProperty("left", ((int) (_headerDiv.getOffsetWidth() * (3.0 / 4.0) - _mapLoadingLabel.getOffsetWidth() / 2)) + "px");
1865 _mapLoadingLabel.getElement().getStyle().setProperty("top", (_headerDiv.getOffsetHeight() + _contentDiv.getOffsetHeight() / 3) + "px");
1866
1867 //Resize the page elemens
1868 _resize = true;
1869
1870 //Send the document text to the server to be checked for places
1871 final Element finalDocumentText = documentText;
1872 Timer checkLoadTimer = new Timer()
1873 {
1874 public void run()
1875 {
1876 if (_gazetteerLoaded)
1877 {
1878 this.cancel();
1879 _findPlaceService.findPlacesInText(finalDocumentText.getInnerText(), finalDocumentText.getInnerHTML(), setUpFindPlacesCallback());
1880 }
1881 }
1882 };
1883 checkLoadTimer.scheduleRepeating(1000);
1884 }
1885
1886 /**
1887 * Creates and returns the callback object used when the call to the server returns
1888 * @return the callback object
1889 */
1890 public AsyncCallback<String> setUpGetMarkedUpTextCallback()
1891 {
1892 return new AsyncCallback<String>()
1893 {
1894 /**
1895 * This is called when the call to the server fails
1896 */
1897 public void onFailure(Throwable caught)
1898 {
1899 logToConsole("Mark up text failed -> " + caught.getMessage());
1900 }
1901
1902 /**
1903 * This is called when the call the to server succeeds
1904 * @param markedUpText is the text (marked up with place names) returned from the server
1905 */
1906 public void onSuccess(String markedUpText)
1907 {
1908 logToConsole("Mark up text success");
1909
1910 //Get the unmodified document text element from the web page
1911 Element documentText = getDocTextElement();
1912
1913 //Set the document text HTML to be the marked up text
1914 documentText.setInnerHTML(markedUpText);
1915
1916 //Get the spans in the marked up text that are place names
1917 JsArray<Element> textPlaces = getElementsByTagName("span");
1918 ArrayList<Element> placeElements = new ArrayList<Element>();
1919
1920 //Add the place spans to the array
1921 for (int j = 0; j < textPlaces.length(); j++)
1922 {
1923 logToConsole("Attempting to match " + textPlaces.get(j).getAttribute("class") + " with place");
1924 if (textPlaces.get(j).getAttribute("class").equals("place"))
1925 {
1926 placeElements.add(textPlaces.get(j));
1927 }
1928 }
1929
1930 logToConsole("Adding events to " + placeElements.size() + " place spans");
1931
1932 //Add mouse over and mouse out handlers to each span
1933 for (Element e : placeElements)
1934 {
1935 Label newLabel = Label.wrap(e);
1936 newLabel.addMouseOverHandler(new PlaceMouseOverHandler());
1937 newLabel.addMouseOutHandler(new PlaceMouseOutHandler());
1938 newLabel.addMouseUpHandler(new PlaceMouseUpHandler());
1939 }
1940
1941 //If Fisheye view is selected in the list box then use it
1942 if (_textViewSelector.getSelectedIndex() == 1)
1943 {
1944 _statusBar.addUpdate("Loading fisheye view", "FishLoad");
1945 setUpFishEye();
1946 _statusBar.removeUpdate("FishLoad");
1947 _fishEyeHandlerReg = _gsPanel.addMouseMoveHandler(new FishEyeMouseMoveHandler());
1948 }
1949
1950 //If Column view is selected in the list box then use it
1951 if (_textViewSelector.getSelectedIndex() == 2)
1952 {
1953 setUpColumnView(documentText);
1954 }
1955 }
1956 };
1957 }
1958
1959 public void setUpColumnView(Element documentText)
1960 {
1961 _statusBar.addUpdate("Loading column view", "ColLoad");
1962
1963 logToConsole("Wrapping doc text");
1964 HTML docText = HTML.wrap(documentText);
1965 int width = docText.getOffsetWidth();
1966 String html = docText.getHTML();
1967 ArrayList<String> words = new ArrayList<String>();
1968
1969 int inTag = 0;
1970 boolean inWord = false;
1971
1972 StringBuilder currentWord = new StringBuilder();
1973
1974 for (int i = 0; i < html.length(); i++)
1975 {
1976 boolean add = true;
1977 char c = html.charAt(i);
1978
1979 if (inTag > 0 && c == '>')
1980 {
1981 inTag--;
1982
1983 if (inTag == 0)
1984 {
1985 words.add(currentWord.toString() + ">");
1986 currentWord = new StringBuilder();
1987 add = false;
1988 }
1989 }
1990 else if (c == '<')
1991 {
1992 inTag++;
1993
1994 if (inWord)
1995 {
1996 inWord = false;
1997 words.add(currentWord.toString());
1998 currentWord = new StringBuilder();
1999 }
2000 }
2001 else if (("" + c).matches("\\s"))
2002 {
2003 if (inTag == 0)
2004 {
2005 add = false;
2006 }
2007
2008 if (inWord)
2009 {
2010 inWord = false;
2011 words.add(currentWord.toString());
2012 currentWord = new StringBuilder();
2013 }
2014 }
2015 else
2016 {
2017 if (inTag == 0 && !inWord)
2018 {
2019 inWord = true;
2020 }
2021 }
2022
2023 if (add)
2024 {
2025 currentWord.append(c);
2026 }
2027 }
2028
2029 docText.setHTML("");
2030
2031 HorizontalPanel columns = new HorizontalPanel();
2032 ArrayList<Label> labels = new ArrayList<Label>();
2033 logToConsole("Adding columns to panel");
2034
2035 if (_contentDiv.getWidget(0).getElement().getId() == "content")
2036 {
2037 VerticalPanel newDocTextPanel = new VerticalPanel();
2038 newDocTextPanel.add(columns);
2039 newDocTextPanel.add(_contentDiv.getWidget(0));
2040 newDocTextPanel.getElement().setId("columnBox");
2041 _contentDiv.insert(newDocTextPanel, 0);
2042 }
2043 else
2044 {
2045 ((VerticalPanel) (_contentDiv.getWidget(0))).remove(0);
2046 ((VerticalPanel) (_contentDiv.getWidget(0))).insert(columns, 0);
2047 }
2048
2049 float fontSize = 12;
2050 do
2051 {
2052 logToConsole("Looping");
2053 Label l = new Label();
2054 labels.add(l);
2055 columns.add(l);
2056
2057 for (int j = 0; j < labels.size(); j++)
2058 {
2059 StringBuilder labelText = new StringBuilder();
2060 for (int i = (words.size() / labels.size()) * j; i < ((j < (labels.size() - 1)) ? (((words.size() / labels.size()) * (j + 1)) - 1) : (words.size())); i++)
2061 {
2062 labelText.append(words.get(i) + " ");
2063 }
2064
2065 labels.get(j).getElement().setInnerHTML(labelText.toString());
2066 labels.get(j).setWidth((width / labels.size()) + "px");
2067 labels.get(j).getElement().getStyle().setProperty("fontSize", fontSize + "px");
2068 }
2069 fontSize *= 0.85;
2070
2071 logToConsole("Font size = " + fontSize);
2072 } while (columns.getOffsetHeight() > (Window.getClientHeight() - _headerDiv.getOffsetHeight() - _footerDiv.getOffsetHeight() - 70));
2073
2074 for (int i = 0; i < labels.size(); i++)
2075 {
2076 ArrayList<String> subList = new ArrayList<String>();
2077 for (int j = (words.size() / labels.size()) * i; j < ((i < (labels.size() - 1)) ? (((words.size() / labels.size()) * (i + 1)) - 1) : (words.size())); j++)
2078 {
2079 subList.add(words.get(j));
2080 }
2081 labels.get(i).addMouseMoveHandler(new ColumnViewMouseMoveHandler(labels.get(i), subList));
2082 }
2083
2084 columns.add(_columnViewBox);
2085 _columnViewBox.getElement().getStyle().setProperty("position", "absolute");
2086 _columnViewBox.getElement().getStyle().setProperty("border", "2px solid");
2087 _columnViewBox.getElement().getStyle().setProperty("background", "#FFFFFF");
2088 _columnViewBox.getElement().getStyle().setProperty("fontSize", "10px");
2089 _columnViewBox.setPixelSize(250, 100);
2090 _columnViewBox.setVisible(false);
2091
2092 _statusBar.removeUpdate("ColLoad");
2093 }
2094
2095 class ColumnViewMouseMoveHandler implements MouseMoveHandler
2096 {
2097 Label _label = null;
2098 ArrayList<String> _words = null;
2099
2100 public ColumnViewMouseMoveHandler(Label label, ArrayList<String> words)
2101 {
2102 _label = label;
2103 _words = words;
2104 }
2105
2106 public void onMouseOut(MouseOutEvent event)
2107 {
2108 _columnViewBox.setVisible(false);
2109 }
2110
2111 public void onMouseOver(MouseOverEvent event)
2112 {
2113 _columnViewBox.setVisible(true);
2114 }
2115
2116 public void onMouseMove(MouseMoveEvent event)
2117 {
2118 _columnViewBox.setVisible(true);
2119
2120 JsArray<Element> divs = getElementsByTagName("div");
2121 Element documentText = null;
2122 for (int i = 0; i < divs.length(); i++)
2123 {
2124 if (divs.get(i).getAttribute("class").equals("documenttext"))
2125 {
2126 documentText = divs.get(i);
2127 break;
2128 }
2129 }
2130
2131 if (event.getY() < 125)
2132 {
2133 logToConsole("1");
2134 _columnViewBox.getElement().getStyle().setProperty("top", (event.getY() + _label.getAbsoluteTop() + 25) + "px");
2135 }
2136 else
2137 {
2138 logToConsole("2");
2139 _columnViewBox.getElement().getStyle().setProperty("top", (event.getY() + _label.getAbsoluteTop() - 125) + "px");
2140 }
2141
2142 if (event.getX() + _label.getAbsoluteLeft() - 125 < documentText.getAbsoluteLeft())
2143 {
2144 _columnViewBox.getElement().getStyle().setProperty("left", documentText.getAbsoluteLeft() + "px");
2145 }
2146 else if (event.getX() + _label.getAbsoluteLeft() + 125 > documentText.getOffsetWidth() + documentText.getAbsoluteLeft())
2147 {
2148 _columnViewBox.getElement().getStyle().setProperty("left", documentText.getOffsetWidth() + documentText.getAbsoluteLeft() - 250 + "px");
2149 }
2150 else
2151 {
2152 _columnViewBox.getElement().getStyle().setProperty("left", (event.getX() + _label.getAbsoluteLeft() - 125) + "px");
2153 }
2154
2155 int midWordIndex = (int) (((float) (event.getY()) / ((_label.getAbsoluteTop() + _label.getOffsetHeight()) - _label.getAbsoluteTop())) * _words.size());
2156 int topWord = midWordIndex - 25;
2157 int botWord = midWordIndex + 25;
2158
2159 if (_words.size() < 50)
2160 {
2161 topWord = 0;
2162 botWord = _words.size();
2163 }
2164 else
2165 {
2166 if (topWord < 0)
2167 {
2168 topWord = 0;
2169 }
2170 else if (topWord > _words.size() - 50)
2171 {
2172 topWord = _words.size() - 50;
2173 }
2174
2175 if (botWord > _words.size())
2176 {
2177 botWord = _words.size();
2178 }
2179 else if (botWord < 50)
2180 {
2181 botWord = 50;
2182 }
2183 }
2184
2185 StringBuilder s = new StringBuilder();
2186
2187 for (int i = topWord; i < botWord; i++)
2188 {
2189 s.append(_words.get(i) + " ");
2190 }
2191
2192 _columnViewBox.getElement().setInnerHTML(s.toString());
2193 }
2194 }
2195
2196 public AsyncCallback<Boolean> setUpLoadGazetteerCallback()
2197 {
2198 AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>()
2199 {
2200 public void onFailure(Throwable caught)
2201 {
2202 logToConsole("Loading Gazetteer failed ->" + caught.getMessage());
2203 }
2204
2205 public void onSuccess(Boolean success)
2206 {
2207 logToConsole("Loading Gazetteer success!");
2208 _statusBar.removeUpdate("GazLoad");
2209 _gazetteerLoaded = true;
2210 }
2211 };
2212
2213 return callback;
2214 }
2215
2216 public void createDocumentMenu()
2217 {
2218 // Menu
2219 final Menu documentMenu = new Menu(_footerDiv.getElement(), new MouseOverHandler()
2220 {
2221 public void onMouseOver(MouseOverEvent event)
2222 {
2223 if(_menuOverTimer != null)
2224 {
2225 _menuOverTimer.cancel();
2226 _menuOverTimer = null;
2227 }
2228 Label item = (Label) event.getSource();
2229 item.getElement().getStyle().setProperty("background", "#0000FF");
2230 item.getElement().getStyle().setProperty("color", "#FFFFFF");
2231 item.getElement().getStyle().setProperty("border", "1px solid");
2232 if (_menuOutTimer != null)
2233 {
2234 _menuOutTimer.cancel();
2235 _menuOutTimer = null;
2236 }
2237 }
2238 }, new MouseOutHandler()
2239 {
2240 public void onMouseOut(MouseOutEvent event)
2241 {
2242 // logToConsole("MENU OUT!");
2243 Label item = (Label) event.getSource();
2244 item.getElement().getStyle().setProperty("background", "#FFFFFF");
2245 item.getElement().getStyle().setProperty("color", "#000000");
2246 item.getElement().getStyle().setProperty("border", "1px solid");
2247
2248 _menuOutTimer = new Timer()
2249 {
2250 public void run()
2251 {
2252 _currentDocumentMenu.hideMenu();
2253 }
2254 };
2255
2256 _menuOutTimer.schedule(500);
2257 }
2258 });
2259
2260 // Menu items
2261 ArrayList<MenuItem> menuItems = new ArrayList<MenuItem>();
2262 menuItems.add(new MenuItem("Centre this place on the map", new ClickHandler()
2263 {
2264 public void onClick(ClickEvent event)
2265 {
2266 Place place = null;
2267
2268 logToConsole("Center clicked, selected place name = " + _selectedPlaceName);
2269
2270 if ((place = _chosenPlaces.get(_selectedPlaceName)) == null)
2271 {
2272 for (int i = 0; i < _currentPlaces.size(); i++)
2273 {
2274 if (_currentPlaces.get(i).getName().equals(_selectedPlaceName))
2275 {
2276 place = _currentPlaces.get(i);
2277 break;
2278 }
2279 }
2280 }
2281
2282 if (place != null && place.getLatitude() != null && place.getLongitude() != null)
2283 {
2284 logToConsole("Centering map");
2285 _map.setCenter(LatLng.newInstance(place.getLatitude(), place.getLongitude()));
2286 }
2287
2288 _currentDocumentMenu.hideMenu();
2289 }
2290 }));
2291
2292 menuItems.add(new MenuItem("Highlight this place on the map", new ClickHandler()
2293 {
2294 public void onClick(ClickEvent event)
2295 {
2296 _highlightedPlaces.add(_selectedPlaceName);
2297 _map.clearOverlays();
2298 logToConsole("Overlays cleared");
2299 addPlacesToMap(_currentPlaces, "#FFFFFF", "#00FF00", false);
2300 logToConsole("Places added");
2301
2302 _currentDocumentMenu.hideMenu();
2303 }
2304 }));
2305
2306 menuItems.add(new MenuItem("Highlight this place in the text", new ClickHandler()
2307 {
2308 public void onClick(ClickEvent event)
2309 {
2310 _highlightedTextPlaces.add(_selectedPlaceName);
2311
2312 JsArray<Element> places = getElementsByTagName("span");
2313
2314 for (int i = 0; i < places.length(); i++)
2315 {
2316 Element e = places.get(i);
2317
2318 if (e.getClassName() == "place" && e.getInnerText() == _selectedPlaceName)
2319 {
2320 e.getStyle().setProperty("background", "#FF0000");
2321 }
2322 }
2323
2324 _currentDocumentMenu.hideMenu();
2325 }
2326 }));
2327
2328 final MenuItem prevMenuItem = new MenuItem("Remove all highlights", new ClickHandler()
2329 {
2330 public void onClick(ClickEvent event)
2331 {
2332 _highlightedPlaces.clear();
2333
2334 _map.clearOverlays();
2335 addPlacesToMap(_currentPlaces, "#FFFFFF", "#00FF00", false);
2336
2337 JsArray<Element> places = getElementsByTagName("span");
2338
2339 for (int i = 0; i < places.length(); i++)
2340 {
2341 Element e = places.get(i);
2342
2343 if (e.getClassName() == "place" && _highlightedTextPlaces.contains(e.getInnerText()))
2344 {
2345 e.getStyle().setProperty("background", "#FFFF00");
2346 }
2347 }
2348 _highlightedTextPlaces.clear();
2349
2350 _currentDocumentMenu.hideMenu();
2351 }
2352 });
2353 menuItems.add(prevMenuItem);
2354
2355 menuItems.add(new MenuItem("Choose correct place >", new ClickHandler()
2356 {
2357 public void onClick(ClickEvent event)
2358 {
2359 logToConsole("MARKER!");
2360 ArrayList<MenuItem> places = new ArrayList<MenuItem>();
2361 ArrayList<Place> matchingPlaces = new ArrayList<Place>();
2362
2363 for (Place p : _currentPlaces)
2364 {
2365 if (p.getName().equals(_selectedPlaceName))
2366 {
2367 matchingPlaces.add(p);
2368 }
2369 }
2370
2371 for (final Place p : matchingPlaces)
2372 {
2373 places.add(new MenuItem(p.getName() + ((p.getParentPlaceName() != null) ? (", " + p.getParentPlaceName()) : (" (Country)")), new ClickHandler()
2374 {
2375 public void onClick(ClickEvent e)
2376 {
2377 _chosenPlaces.put(_selectedPlaceName, p);
2378
2379 _map.clearOverlays();
2380 logToConsole("Chose a new place!!!");
2381 addPlacesToMap(_currentPlaces, "#FFFFFF", "#00FF00", false);
2382 logToConsole("Places added!!!");
2383
2384 _currentDocumentMenu.hideMenu();
2385 }
2386 }));
2387 }
2388
2389 Menu placeMenu = new Menu(_footerDiv.getElement(), new MouseOverHandler()
2390 {
2391 public void onMouseOver(MouseOverEvent event)
2392 {
2393 Label item = (Label) event.getSource();
2394 item.getElement().getStyle().setProperty("background", "#0000FF");
2395 item.getElement().getStyle().setProperty("color", "#FFFFFF");
2396 if (_menuOutTimer != null)
2397 {
2398 _menuOutTimer.cancel();
2399 _menuOutTimer = null;
2400 }
2401 }
2402 }, new MouseOutHandler()
2403 {
2404 public void onMouseOut(MouseOutEvent event)
2405 {
2406 Label item = (Label) event.getSource();
2407 item.getElement().getStyle().setProperty("background", "#FFFFFF");
2408 item.getElement().getStyle().setProperty("color", "#000000");
2409
2410 _menuOutTimer = new Timer()
2411 {
2412 public void run()
2413 {
2414 _currentDocumentMenu.hideMenu();
2415 }
2416 };
2417
2418 _menuOutTimer.schedule(500);
2419 }
2420 });
2421
2422 documentMenu.addChildMenu(placeMenu);
2423 placeMenu.addMenuItems(places);
2424 placeMenu.moveMenu(_currentDocumentMenu.getMenuDiv().getAbsoluteLeft() + _currentDocumentMenu.getMenuDiv().getOffsetWidth(), prevMenuItem.getMenuElement().getAbsoluteTop() + prevMenuItem.getMenuElement().getOffsetHeight() - 2);
2425 placeMenu.showMenu();
2426 }
2427 }));
2428
2429 documentMenu.addMenuItems(menuItems);
2430 documentMenu.hideMenu();
2431 _currentDocumentMenu = documentMenu;
2432 }
2433
2434 public void startDocumentMouseOverTimer(final int x, final int y)
2435 {
2436 _documentMouseOverTimer = new Timer()
2437 {
2438 public void run()
2439 {
2440 _currentDocumentMenu.moveMenu(x, y);
2441 _currentDocumentMenu.showMenu();
2442
2443 _documentMouseOverTimer = null;
2444 }
2445 };
2446
2447 _documentMouseOverTimer.schedule(1000);
2448 }
2449
2450 /**
2451 * Gets the document text element from the web page
2452 * @return the document text element
2453 */
2454 public Element getDocTextElement()
2455 {
2456 JsArray<Element> divs = getElementsByTagName("div");
2457
2458 Element documentText = null;
2459 for (int i = 0; i < divs.length(); i++)
2460 {
2461 if (divs.get(i).getAttribute("class").equals("documenttext"))
2462 {
2463 documentText = divs.get(i);
2464 break;
2465 }
2466 }
2467
2468 return documentText;
2469 }
2470
2471 public void addElementsToSearchResults(ArrayList<ArrayList<Place>> places)
2472 {
2473 JsArray<Element> elements = getElementsByTagName("li");
2474 ArrayList<Element> listElements = new ArrayList<Element>();
2475
2476 for (int i = 0; i < elements.length(); i++)
2477 {
2478 if (elements.get(i).getAttribute("class").equals("document"))
2479 {
2480 listElements.add(elements.get(i));
2481 }
2482 }
2483
2484 for (int i = 0; i < listElements.size(); i++)
2485 {
2486 Element span = DOM.createSpan();
2487 listElements.get(i).insertBefore(span, listElements.get(i).getFirstChild());
2488 span.getStyle().setBackgroundColor(numToColour(i, listElements.size(), 100, 255));
2489 span.getStyle().setColor(numToColour(i, listElements.size(), 100, 255));
2490 span.setInnerText("...");
2491
2492 Element checkBoxSpan = DOM.createSpan();
2493 listElements.get(i).insertBefore(checkBoxSpan, listElements.get(i).getFirstChild());
2494 checkBoxSpan.setId("Result" + i);
2495
2496 CheckBox c = new CheckBox();
2497 c.setValue(true);
2498 c.addValueChangeHandler(new SearchResultsCheckBoxChangeHandler(i));
2499 RootPanel.get("Result" + i).add(c);
2500 }
2501 }
2502
2503 public class SearchResultsCheckBoxChangeHandler implements ValueChangeHandler<Boolean>
2504 {
2505 int _index = -1;
2506
2507 public SearchResultsCheckBoxChangeHandler(int index)
2508 {
2509 _index = index;
2510 }
2511
2512 public void onValueChange(ValueChangeEvent<Boolean> event)
2513 {
2514 if (event.getValue())
2515 {
2516 _visiblePlaceSets.set(_index, true);
2517 }
2518 else
2519 {
2520 _visiblePlaceSets.set(_index, false);
2521 }
2522
2523 _map.clearOverlays();
2524 displayMultiplePlaceSets();
2525 }
2526 }
2527
2528 public class DocumentOverHandler implements MouseOverHandler
2529 {
2530 int _index = -1;
2531
2532 public DocumentOverHandler(int index)
2533 {
2534 _index = index;
2535 }
2536
2537 public void onMouseOver(MouseOverEvent event)
2538 {
2539 Label currentLabel = (Label) event.getSource();
2540 currentLabel.setStyleName("placeOver");
2541
2542 startDocumentMouseOverTimer(event.getX() + currentLabel.getAbsoluteLeft(), event.getY() + currentLabel.getAbsoluteTop());
2543 }
2544 }
2545
2546 public class PlaceMouseOverHandler implements MouseOverHandler
2547 {
2548 public void onMouseOver(MouseOverEvent event)
2549 {
2550 Label currentLabel = (Label) event.getSource();
2551 currentLabel.setStyleName("placeOver");
2552
2553 _selectedPlaceName = currentLabel.getElement().getInnerText();
2554
2555 startPlaceMouseOverTimer(event.getX() + currentLabel.getAbsoluteLeft(), event.getY() + currentLabel.getAbsoluteTop());
2556 }
2557 }
2558
2559 public class PlaceMouseOutHandler implements MouseOutHandler
2560 {
2561 public void onMouseOut(MouseOutEvent event)
2562 {
2563 Label currentLabel = (Label) event.getSource();
2564 currentLabel.setStyleName("place");
2565
2566 if (_placeMouseOverTimer != null)
2567 {
2568 _placeMouseOverTimer.cancel();
2569 _placeMouseOverTimer = null;
2570 }
2571 }
2572 }
2573
2574 public class PlaceMouseUpHandler implements MouseUpHandler
2575 {
2576 public void onMouseUp(MouseUpEvent event)
2577 {
2578 Label currentLabel = (Label) event.getSource();
2579 currentLabel.setStyleName("place");
2580 if(event.getNativeButton() == NativeEvent.BUTTON_LEFT)
2581 {
2582 String placeName = currentLabel.getText();
2583 Place place = _chosenPlaces.get(placeName);
2584
2585 if(place == null)
2586 {
2587 for(Place p : _currentPlaces)
2588 {
2589 if(p.getName().equals(placeName))
2590 {
2591 place = p;
2592 break;
2593 }
2594 }
2595 }
2596
2597 if(place != null && place.getLatitude() != null && place.getLongitude() != null)
2598 {
2599 _map.setCenter(LatLng.newInstance(place.getLatitude(), place.getLongitude()));
2600 }
2601 }
2602 /*
2603 else if(event.getNativeButton() == NativeEvent.BUTTON_RIGHT)
2604 {
2605 _currentDocumentMenu.moveMenu(event.getX() + currentLabel.getAbsoluteLeft(), event.getY() + currentLabel.getAbsoluteTop());
2606 _currentDocumentMenu.showMenu();
2607 }
2608 */
2609 }
2610 }
2611
2612 public void startPlaceMouseOverTimer(final int x, final int y)
2613 {
2614 _placeMouseOverTimer = new Timer()
2615 {
2616 public void run()
2617 {
2618 _currentDocumentMenu.moveMenu(x, y);
2619 _currentDocumentMenu.showMenu();
2620
2621 _menuOverTimer = new Timer()
2622 {
2623 public void run()
2624 {
2625 _menuOverTimer = null;
2626 _currentDocumentMenu.hideMenu();
2627 }
2628 };
2629 _menuOverTimer.schedule(4000);
2630
2631 _placeMouseOverTimer = null;
2632 }
2633 };
2634
2635 _placeMouseOverTimer.schedule(1000);
2636 }
2637
2638 public class FishEyeMouseMoveHandler implements MouseMoveHandler
2639 {
2640 public void onMouseMove(MouseMoveEvent e)
2641 {
2642 if (!_mouseEventPause)
2643 {
2644 _mouseEventPause = true;
2645 passMouseCoordsToFishEye(e.getY());
2646 Timer pauseTimer = new Timer()
2647 {
2648 public void run()
2649 {
2650 _mouseEventPause = false;
2651 }
2652 };
2653 pauseTimer.schedule(50);
2654 }
2655 }
2656 }
2657
2658 /**
2659 * This class contains methods that initialise and control the spatial search controls present on the map during a spatial search
2660 */
2661 public class SpatialSearchControls extends CustomControl
2662 {
2663 /**
2664 * Inherited parent constructor
2665 */
2666 protected SpatialSearchControls(ControlPosition arg0)
2667 {
2668 super(arg0);
2669 }
2670
2671 /**
2672 * Second inherited parent constructor
2673 */
2674 protected SpatialSearchControls(ControlPosition arg0, boolean arg1, boolean arg2)
2675 {
2676 super(arg0, arg1, arg2);
2677 }
2678
2679 /**
2680 * Initialises the control buttons
2681 */
2682 protected Widget initialize(MapWidget map)
2683 {
2684 //Create the panel to store the buttons
2685 HorizontalPanel panel = new HorizontalPanel();
2686
2687 //Create the button that clears the user's currently created points
2688 Button clearButton = new Button("Clear Points", new ClickHandler()
2689 {
2690 public void onClick(ClickEvent event)
2691 {
2692 _areaPoints.clear();
2693 _map.clearOverlays();
2694 }
2695 });
2696
2697 //Create the button the performs the spatial search
2698 Button performSearch = new Button("Search Area", new ClickHandler()
2699 {
2700 public void onClick(ClickEvent event)
2701 {
2702 //If the users has marked less than 3 points on the map then we cannot perform a spatial search
2703 if (_areaPoints.size() < 3)
2704 {
2705 //Show an error message on the status bar
2706 _statusBar.removeUpdate("SpatialWarn");
2707 _statusBar.addUpdate("A minimum of 3 points is needed on the map to perform a spatial search", "SpatialWarn");
2708
2709 //Remove the message after 5 seconds
2710 Timer warningRemoveTimer = new Timer()
2711 {
2712 public void run()
2713 {
2714 _statusBar.removeUpdate("SpatialWarn");
2715 }
2716 };
2717 warningRemoveTimer.schedule(5000);
2718
2719 return;
2720 }
2721
2722 ArrayList<Float[]> points = new ArrayList<Float[]>();
2723
2724 //Turn the points into a list of float arrays
2725 for (LatLng point : _areaPoints)
2726 {
2727 points.add(new Float[] { (float) point.getLatitude(), (float) point.getLongitude() });
2728 }
2729
2730 //Ask the server to perform the spatial search
2731 _findPlaceService.spatialSearch(points, getSpatialSearchCallback());
2732 }
2733 });
2734
2735 //Add the two buttons to the panel
2736 panel.add(clearButton);
2737 panel.add(performSearch);
2738
2739 return panel;
2740 }
2741
2742 /**
2743 * Creates and returns the callback necessary to perform a spatial search on the server
2744 * @return the callback object
2745 */
2746 public AsyncCallback<ArrayList<String>> getSpatialSearchCallback()
2747 {
2748 return new AsyncCallback<ArrayList<String>>()
2749 {
2750 /**
2751 * If the call to the server failed then this is called
2752 * @see com.google.gwt.user.client.rpc.AsyncCallback#onFailure(java.lang.Throwable)
2753 */
2754 public void onFailure(Throwable arg0)
2755 {
2756 logToConsole("Spatial search FAIL!");
2757 }
2758
2759 /**
2760 * If the call to the server succeeded then this is called
2761 * @param placeNames is the places found within the spatial search polygon
2762 */
2763 public void onSuccess(ArrayList<String> placeNames)
2764 {
2765 logToConsole("Spatial search Success!");
2766
2767 //Create the query to pass to Greenstone
2768 StringBuffer query = new StringBuffer();
2769 for (int j = 0; j < placeNames.size() && j < 20; j++)
2770 {
2771 if (j == 0)
2772 {
2773 query.append(placeNames.get(j).replaceAll(" ", "+").replaceAll("-", "+"));
2774 }
2775 else
2776 {
2777 query.append("+" + placeNames.get(j).replaceAll(" ", "+").replaceAll("-", "+"));
2778 }
2779 }
2780
2781 logToConsole("Query -> " + query);
2782 logToConsole("Collection -> " + _currentCollection);
2783
2784 //Create an invisible form
2785 FormPanel form = new FormPanel();
2786 form.setAction(_GREENSTONEDEVURL);
2787 form.setMethod(FormPanel.METHOD_POST);
2788 form.getElement().setAttribute("target", "_self");
2789
2790 VerticalPanel tempForm = new VerticalPanel();
2791 form.setWidget(tempForm);
2792
2793 tempFrameGetElementsByTagName("body").get(0).appendChild(form.getElement());
2794
2795 logToConsole("Adding hidden form elements");
2796
2797 Hidden a = new Hidden("a", "q");
2798 tempForm.add(a);
2799 Hidden sa = new Hidden("sa");
2800 tempForm.add(sa);
2801 Hidden rt = new Hidden("rt", "rd");
2802 tempForm.add(rt);
2803 Hidden s = new Hidden("s", "TextQuery");
2804 tempForm.add(s);
2805 Hidden c = new Hidden("c", _currentCollection);
2806 tempForm.add(c);
2807 Hidden startPage = new Hidden("startPage", "1");
2808 tempForm.add(startPage);
2809 Hidden s1level = new Hidden("s1.level", "Sec");
2810 tempForm.add(s1level);
2811 Hidden s1case = new Hidden("s1.case", "1");
2812 tempForm.add(s1case);
2813 Hidden s1stem = new Hidden("s1.stem", "0");
2814 tempForm.add(s1stem);
2815 Hidden s1accent = new Hidden("s1.accent", "0");
2816 tempForm.add(s1accent);
2817 Hidden s1matchMode = new Hidden("s1.matchMode", "some");
2818 tempForm.add(s1matchMode);
2819 Hidden s1sort = new Hidden("s1.sortBy", "1");
2820 tempForm.add(s1sort);
2821 Hidden s1index = new Hidden("s1.index", "ZZ");
2822 tempForm.add(s1index);
2823 Hidden s1maxDocs = new Hidden("s1.maxDocs", "100");
2824 tempForm.add(s1maxDocs);
2825 Hidden s1query = new Hidden("s1.query", query.toString());
2826 tempForm.add(s1query);
2827
2828 logToConsole("Submitting");
2829
2830 form.submit();
2831
2832 logToConsole("Loading results page");
2833
2834 loadPageWithoutUrl();
2835 }
2836 };
2837 }
2838
2839 public boolean isSelectable()
2840 {
2841 return false;
2842 }
2843 }
2844
2845 public static FindPlaceServiceAsync getServerConnection()
2846 {
2847 return _findPlaceService;
2848 }
2849}
Note: See TracBrowser for help on using the repository browser.