Java tutorial
/* * JBoss, Home of Professional Open Source * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.jboss.as.console.client.search; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.ui.*; import com.google.gwt.view.client.CellPreviewEvent; import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SingleSelectionModel; import com.gwtplatform.mvp.client.proxy.PlaceManager; import com.gwtplatform.mvp.shared.proxy.PlaceRequest; import org.jboss.as.console.client.Console; import org.jboss.as.console.client.widgets.lists.DefaultCellList; import org.jboss.as.console.client.widgets.progress.ProgressElement; import org.jboss.ballroom.client.widgets.window.DefaultWindow; import java.util.*; import static com.google.gwt.dom.client.Style.Unit.PCT; import static com.google.gwt.dom.client.Style.Unit.PX; /** * @author Harald Pehl */ class SearchPopup extends DefaultWindow { private static final TokenGroupTemplate TEMPLATE = GWT.create(TokenGroupTemplate.class); private final Harvest harvest; private final Index index; private final DeckPanel deck; private final ProgressElement progressBar; private final DefaultCellList<TokenGroup> resultList; private final SingleSelectionModel<TokenGroup> resultSelectionModel; private final ListDataProvider<TokenGroup> resultProvider; private final TextBox textBox; private final HTML numberOfResults; private final PlaceManager placeManager; SearchPopup(final Harvest harvest, final Index index, final PlaceManager placeManager) { super("Search"); addStyleName("hal-searchPopup"); this.harvest = harvest; this.index = index; this.placeManager = placeManager; deck = new DeckPanel(); VerticalPanel indexPanel = new VerticalPanel(); indexPanel.setStyleName("fill-layout-width"); indexPanel.getElement().getStyle().setPadding(2, Style.Unit.PX); indexPanel.add(new HTML(Console.MESSAGES.search_index_pending())); progressBar = new ProgressElement(); indexPanel.add(progressBar); deck.add(indexPanel); VerticalPanel searchPanel = new VerticalPanel(); searchPanel.setStyleName("window-content"); searchPanel.add(new HTML("<h3>" + Console.CONSTANTS.search_popup_title() + "</h3>")); searchPanel.add(new Label(Console.MESSAGES.search_popup_description(SearchTool.getShortcut()))); textBox = new TextBox(); textBox.getElement().getStyle().setWidth(66, PCT); textBox.getElement().setAttribute("placeholder", Console.CONSTANTS.search_placeholder()); textBox.getElement().getStyle().setMarginTop(15, PX); textBox.addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent keyUpEvent) { if (keyUpEvent.isDownArrow() && !resultProvider.getList().isEmpty()) { resultList.setFocus(true); } else { executeQuery(); } } }); textBox.setTabIndex(0); searchPanel.add(textBox); numberOfResults = new HTML(); numberOfResults.addStyleName("no-results"); numberOfResults.setVisible(false); searchPanel.add(numberOfResults); resultList = new DefaultCellList<TokenGroup>(new ResultCell()); resultList.addCellPreviewHandler(new CellPreviewEvent.Handler<TokenGroup>() { @Override public void onCellPreview(CellPreviewEvent event) { if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) { resultSelectionModel .setSelected(resultProvider.getList().get(resultList.getKeyboardSelectedRow()), true); } } }); resultSelectionModel = new SingleSelectionModel<TokenGroup>(); resultSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { navigate(); } }); resultList.setSelectionModel(resultSelectionModel); resultList.addStyleName("fill-layout-width"); resultList.addStyleName("search-result"); resultProvider = new ListDataProvider<TokenGroup>(); resultProvider.addDataDisplay(resultList); searchPanel.add(resultList); deck.add(searchPanel); deck.showWidget(1); resultList.setTabIndex(0); setWidget(new ScrollPanel(deck)); } private void navigate() { TokenGroup selection = resultSelectionModel.getSelectedObject(); if (selection != null) { hide(); placeManager.revealPlace(new PlaceRequest.Builder().nameToken(selection.getToken()).build()); } } private void executeQuery() { String query = textBox.getText().trim(); if (query.length() != 0) { // split the query into multiple terms String[] terms = query.split(" "); // collect the hits over all terms into token groups (using disjunction) Map<String, TokenGroup> tokenGroups = new LinkedHashMap<>(); for (String term : terms) { if (term != null && term.trim().length() > 1) { List<Document> hits = index.search(term); for (Document hit : hits) { String token = hit.getToken(); TokenGroup tokenGroup = tokenGroups.get(token); if (tokenGroup == null) { tokenGroup = new TokenGroup(token); tokenGroups.put(token, tokenGroup); } tokenGroup.add(hit); } } } // display token groups ArrayList<TokenGroup> results = new ArrayList<TokenGroup>(tokenGroups.values()); numberOfResults.setVisible(true); if (results.isEmpty()) { numberOfResults.removeStyleName("number-of-results"); numberOfResults.addStyleName("no-results"); numberOfResults.setHTML(Console.CONSTANTS.search_no_results()); } else { numberOfResults.removeStyleName("no-results"); numberOfResults.addStyleName("number-of-results"); numberOfResults.setHTML(Console.MESSAGES.search_n_results(results.size())); } resultProvider.setList(results); resultProvider.refresh(); } else { // clear display numberOfResults.setVisible(false); resultProvider.setList(Collections.<TokenGroup>emptyList()); resultProvider.refresh(); } } void showIndexPage() { deck.showWidget(0); } void index() { harvest.run(new FilterDuplicatesHarvest(index, this), progressBar); } void showSearchPage() { deck.showWidget(1); Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { textBox.setFocus(true); } }); } public class ResultCell extends AbstractCell<TokenGroup> { @Override public void render(Context context, TokenGroup tokenGroup, SafeHtmlBuilder safeHtmlBuilder) { SafeHtmlBuilder descriptions = new SafeHtmlBuilder(); for (String description : tokenGroup.getDescriptions()) { descriptions.append(TEMPLATE.description(description)); } String token = tokenGroup.getToken(); try { // try to find a description for this token token = Console.TOKENS.getString(token.replace('-', '_')); } catch (MissingResourceException e) { System.err.println("No description found for token " + token + ": " + e.getMessage()); } if (tokenGroup.getKeywords().isEmpty()) { safeHtmlBuilder.append(TEMPLATE.tokenGroup(token, descriptions.toSafeHtml())); } else { SafeHtmlBuilder keywords = new SafeHtmlBuilder(); for (String keyword : tokenGroup.getKeywords()) { keywords.append(TEMPLATE.keyword(keyword)); } safeHtmlBuilder .append(TEMPLATE.tokenGroup(token, descriptions.toSafeHtml(), keywords.toSafeHtml())); } } } public interface TokenGroupTemplate extends SafeHtmlTemplates { @Template("<div class=\"search-token-group\">" + "<div class=\"header\"><i class=\"icon-file-alt\"></i> {0}</div>" + "<ul class=\"descriptions\">{1}</ul>" + "</div>") SafeHtml tokenGroup(String header, SafeHtml descriptions); @Template("<div class=\"search-token-group\">" + "<div class=\"header\"><i class=\"icon-file-alt\"></i> {0}</div>" + "<ul class=\"descriptions\">{1}</ul>" + "<div class=\"keywords\">{2}</div>" + "</div>") SafeHtml tokenGroup(String header, SafeHtml descriptions, SafeHtml keywords); @Template("<li>{0}</li>") SafeHtml description(String description); @Template("<span>{0}</span>") SafeHtml keyword(String keyword); } }