// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.search.awesomebox;
import com.google.collide.client.editor.Editor;
import com.google.collide.client.search.awesomebox.AwesomeBox.Resources;
import com.google.collide.client.util.Elements;
import com.google.collide.client.util.ViewListController;
import com.google.collide.client.workspace.outline.OutlineModel;
import com.google.collide.client.workspace.outline.OutlineNode;
import com.google.collide.json.shared.JsonArray;
import com.google.collide.mvp.CompositeView;
import com.google.collide.mvp.HasView;
import com.google.collide.shared.util.StringUtils;
import com.google.common.base.Preconditions;
import elemental.html.Element;
import elemental.html.SpanElement;
/**
* An awesome box section which displays the classes/functions/variables in your file.
*
*/
public class OutlineViewAwesomeBoxSection
extends AbstractAwesomeBoxSection<OutlineViewAwesomeBoxSection.OutlineItem> {
/**
* An item in the awesomebox which displays an OutlineNode.
*/
public static class OutlineItem extends AbstractAwesomeBoxSection.ActionItem
implements HasView<OutlineItem.View> {
/** A handler called when a node is selected */
public interface SelectedHandler {
void onSelected(OutlineNode node);
}
/** A factory which can create an {@link OutlineItem} */
public static class OutlineItemFactory implements ViewListController.Factory<OutlineItem> {
private final Resources res;
private final SelectedHandler handler;
public OutlineItemFactory(Resources res, SelectedHandler handler) {
this.res = res;
this.handler = handler;
}
@Override
public OutlineItem create(Element container) {
View v = new View(res);
container.appendChild(v.getElement());
return new OutlineItem(res, v, handler);
}
}
public static class View extends CompositeView<Void> {
private final SpanElement name;
private final SpanElement type;
public View(Resources res) {
super(AwesomeBoxUtils.createSectionItem(res));
name = Elements.createSpanElement();
type = Elements.createSpanElement();
type.getStyle().setColor("#AAA");
getElement().appendChild(name);
getElement().appendChild(type);
}
}
private final View view;
private final SelectedHandler handler;
private OutlineNode node;
private OutlineItem(Resources res, View view, SelectedHandler handler) {
super(res, view.getElement());
Preconditions.checkNotNull(handler, "Handle for outline element cannot be null");
this.view = view;
this.handler = handler;
}
public void setOutlineNode(OutlineNode node) {
this.node = node;
view.name.setTextContent(node.getName());
view.type.setTextContent(" - " + node.getType().toString().toLowerCase());
}
@Override
public String completeQuery() {
return node.getName();
}
@Override
public ActionResult doAction(ActionSource source) {
handler.onSelected(node);
return ActionResult.CLOSE;
}
@Override
public View getView() {
return view;
}
}
/** The maximum number of results to display */
private static final int MAX_RESULTS = 6;
/** A prefix which can be used to force the awesomebox to show only outline results */
private static final String QUERY_PREFIX = "@";
private final ViewListController<OutlineItem> listController;
private OutlineModel model;
private Editor editor;
public OutlineViewAwesomeBoxSection(Resources res) {
super(res);
sectionElement = AwesomeBoxUtils.createSectionContainer(res);
this.listController = new ViewListController<OutlineItem>(
sectionElement, listItems.asJsonArray(),
new OutlineItem.OutlineItemFactory(res, new OutlineItem.SelectedHandler() {
@Override
public void onSelected(OutlineNode node) {
if (editor != null) {
editor.scrollTo(node.getLineNumber(), node.getColumn());
editor.getFocusManager().focus();
}
}
}));
}
@Override
public boolean onQueryChanged(String query) {
listController.reset();
if (!StringUtils.isNullOrWhitespace(query) && !query.equals(QUERY_PREFIX) && model != null) {
traverseNode(model.getRoot(), query.startsWith(QUERY_PREFIX) ? query.substring(1) : query);
}
listController.prune();
return listController.size() > 0;
}
@Override
public boolean onShowing(AwesomeBox awesomeBox) {
return false;
}
public void setOutlineModelAndEditor(OutlineModel model, Editor editor) {
this.model = model;
this.editor = editor;
}
private void traverseNode(OutlineNode parent, String query) {
if (listController.size() >= MAX_RESULTS || parent == null) {
return;
}
JsonArray<OutlineNode> children = parent.getChildren();
for (int i = 0; listController.size() < MAX_RESULTS && i < children.size(); i++) {
OutlineNode node = children.get(i);
if (node.getName().contains(query)) {
OutlineItem item = listController.next();
item.setOutlineNode(node);
}
traverseNode(children.get(i), query);
}
}
}