/**
* Copyright (c) 2009, iPlant Collaborative, Texas Advanced Computing Center This software is licensed
* under the CC-GNU GPL version 2.0 or later. License: http://creativecommons.org/licenses/GPL/2.0/
*/
package org.iplantc.phyloviewer.viewer.client;
import org.iplantc.phyloviewer.client.events.DocumentChangeEvent;
import org.iplantc.phyloviewer.client.events.DocumentChangeHandler;
import org.iplantc.phyloviewer.client.events.HasDocument;
import org.iplantc.phyloviewer.client.events.HasNodeSelectionHandlers;
import org.iplantc.phyloviewer.client.events.HighlightSelectionHandler;
import org.iplantc.phyloviewer.client.events.NavigationMode;
import org.iplantc.phyloviewer.client.events.NodeSelectionEvent;
import org.iplantc.phyloviewer.client.events.NodeSelectionHandler;
import org.iplantc.phyloviewer.client.events.SelectionMode;
import org.iplantc.phyloviewer.client.tree.viewer.DetailView;
import org.iplantc.phyloviewer.client.tree.viewer.View;
import org.iplantc.phyloviewer.client.tree.viewer.ViewCircular;
import org.iplantc.phyloviewer.client.tree.viewer.ViewCladogram;
import org.iplantc.phyloviewer.client.tree.viewer.render.HasRenderPreferences;
import org.iplantc.phyloviewer.shared.math.Box2D;
import org.iplantc.phyloviewer.shared.model.IDocument;
import org.iplantc.phyloviewer.shared.render.RenderPreferences;
import org.iplantc.phyloviewer.viewer.client.render.SearchHighlighter;
import org.iplantc.phyloviewer.viewer.client.services.SearchServiceAsyncImpl;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ResizeComposite;
public class TreeWidget extends ResizeComposite implements HasDocument, HasNodeSelectionHandlers,
HasRenderPreferences
{
public RenderPreferences renderPreferences = new RenderPreferences();
public enum ViewType
{
VIEW_TYPE_CLADOGRAM, VIEW_TYPE_RADIAL
}
private LayoutPanel mainPanel = new LayoutPanel();
private View view;
private EventBus eventBus;
private IDocument document;
private SearchHighlighter highlighter;
public TreeWidget(SearchServiceAsyncImpl searchService, EventBus eventBus)
{
this.eventBus = eventBus;
this.highlighter = new SearchHighlighter(searchService);
highlighter.setRenderPreferences(renderPreferences);
this.initWidget(mainPanel);
this.setViewType(ViewType.VIEW_TYPE_CLADOGRAM);
}
@Override
public void setDocument(IDocument document)
{
this.document = document;
renderPreferences.clearAllHighlights();
view.setDocument(document);
view.zoomToFit();
view.requestRender();
eventBus.fireEventFromSource(new DocumentChangeEvent(document), this);
}
@Override
public HandlerRegistration addDocumentChangeHandler(DocumentChangeHandler handler)
{
return eventBus.addHandlerToSource(DocumentChangeEvent.TYPE, this, handler);
}
@Override
public IDocument getDocument()
{
return document;
}
@Override
public HandlerRegistration addSelectionHandler(NodeSelectionHandler handler)
{
return eventBus.addHandlerToSource(NodeSelectionEvent.TYPE, this, handler);
}
public void setViewType(ViewType type)
{
int width = Math.max(10, getOffsetWidth());
int height = Math.max(10, getOffsetHeight());
View newView = createView(type, width, height);
if(null != newView)
{
setView(newView);
}
}
private View createView(ViewType type, int width, int height)
{
View newView = null;
DetailView detail = null;
switch (type)
{
case VIEW_TYPE_CLADOGRAM:
newView = new ViewCladogram(width, height);
detail = ((ViewCladogram)newView).getDetailView();
break;
case VIEW_TYPE_RADIAL:
newView = detail = new ViewCircular(width, height);
break;
default:
throw new IllegalArgumentException("Invalid view type.");
}
newView.setEventBus(this.eventBus);
final SelectionMode selectionMode = new SelectionMode(detail);
selectionMode.getMouseHandler().addSelectionHandler(new HighlightSelectionHandler(detail));
//refire selection events with this TreeWidget as the source.
selectionMode.getMouseHandler().addSelectionHandler(new NodeSelectionHandler()
{
@Override
public void onNodeSelection(NodeSelectionEvent event)
{
eventBus.fireEventFromSource(new NodeSelectionEvent(event.getSelectedNodes()),
TreeWidget.this);
}
});
final NavigationMode navMode = new NavigationMode(detail);
final DetailView dView = detail; //need a final ref to use in the handler
detail.addKeyPressHandler(new KeyPressHandler()
{
@Override
public void onKeyPress(KeyPressEvent event)
{
if(event.getCharCode() == 's')
{
dView.setInteractionMode(selectionMode);
}
else if(event.getCharCode() == 'n')
{
dView.setInteractionMode(navMode);
}
}
});
detail.addMouseOverHandler(new MouseOverHandler()
{
@Override
public void onMouseOver(MouseOverEvent event)
{
dView.setFocus(true);
}
});
//TODO add these two methods to View and get rid of the DetailView references in the rest of createView
detail.setInteractionMode(navMode);
detail.setDrawRenderStats(false);
return newView;
}
private void removeCurrentView()
{
if(highlighter != null)
{
highlighter.clear();
}
if(null != view)
{
mainPanel.remove(this.view);
this.view = null;
}
}
private void setView(View newView)
{
removeCurrentView();
this.view = newView;
newView.setRenderPreferences(renderPreferences);
newView.setDocument(document);
if(highlighter != null)
{
highlighter.setView(newView);
}
// if the document is somehow changed directly in the view, TreeWidget should update and refire
// the event
newView.addDocumentChangeHandler(new DocumentChangeHandler()
{
@Override
public void onDocumentChange(DocumentChangeEvent event)
{
TreeWidget.this.document = event.getDocument();
if(highlighter != null)
{
if(document != null)
{
highlighter.setTree(document.getTree());
}
else
{
highlighter.setTree(null);
}
}
eventBus.fireEventFromSource(new DocumentChangeEvent(document), this);
}
});
// refires selection events from the view, with the TreeWidget as the source
newView.addSelectionHandler(new NodeSelectionHandler()
{
@Override
public void onNodeSelection(NodeSelectionEvent event)
{
eventBus.fireEventFromSource(new NodeSelectionEvent(event.getSelectedNodes()),
TreeWidget.this);
}
});
mainPanel.add(newView);
newView.zoomToFit();
newView.requestRender();
}
public void render()
{
view.render();
}
public String exportImageURL()
{
return this.view.exportImageURL();
}
public View getView()
{
return view;
}
/**
* Make the bounding box fill the viewport.
*
* @param box
*/
public void show(Box2D box)
{
view.zoomToBoundingBox(box);
}
@Override
public RenderPreferences getRenderPreferences()
{
return this.renderPreferences;
}
@Override
public void setRenderPreferences(RenderPreferences rp)
{
this.renderPreferences = rp;
highlighter.setRenderPreferences(rp);
getView().setRenderPreferences(rp);
}
}