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

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

Added several improvements to the code such as the ability to remove places if they from the text and map if they should not be places

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