Java tutorial
/* * Copyright 2011 Corpuslinguistic working group Humboldt University Berlin. * * 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 annis.gui.paging; import annis.gui.AnnisUI; import annis.gui.ShareQueryReferenceWindow; import annis.gui.util.ANNISFontIcon; import annis.libgui.Helper; import com.vaadin.data.Validator; import com.vaadin.data.validator.AbstractStringValidator; import com.vaadin.event.Action; import com.vaadin.event.ShortcutAction; import com.vaadin.server.FontAwesome; import com.vaadin.server.Resource; import com.vaadin.shared.ui.MarginInfo; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.TextField; import com.vaadin.ui.themes.ChameleonTheme; import com.vaadin.ui.themes.ValoTheme; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang3.StringEscapeUtils; import org.slf4j.LoggerFactory; /** * * @author thomas */ public class PagingComponent extends Panel implements Button.ClickListener { private static final org.slf4j.Logger log = LoggerFactory.getLogger(PagingComponent.class); public static final Resource LEFT_ARROW = ANNISFontIcon.LEFT_ARROW; public static final Resource RIGHT_ARROW = ANNISFontIcon.RIGHT_ARROW; public static final Resource FIRST = ANNISFontIcon.FIRST; public static final Resource LAST = ANNISFontIcon.LAST; private HorizontalLayout layout; private Button btFirst; private Button btLast; private Button btNext; private Button btPrevious; private TextField txtPage; private Label lblMaxPages; private Label lblStatus; private Set<PagingCallback> callbacks; private AtomicInteger count; private int pageSize; private long currentPage; private Label lblInfo; private final Button btShareQuery; public PagingComponent() { this(0, 0); } public PagingComponent(int count, int pageSize) { if (pageSize <= 0) { pageSize = 1; } if (count < 0) { count = 0; } currentPage = 1; this.count = new AtomicInteger(pageSize); this.pageSize = pageSize; setWidth("100%"); setHeight("-1px"); addStyleName("toolbar"); callbacks = new HashSet<>(); layout = new HorizontalLayout(); layout.setSpacing(true); layout.setMargin(new MarginInfo(false, true, false, true)); setContent(layout); addStyleName(ChameleonTheme.PANEL_LIGHT); lblInfo = new Label(); lblInfo.setContentMode(ContentMode.HTML); lblInfo.addStyleName("right-aligned-text"); btShareQuery = new Button(FontAwesome.SHARE_ALT); btShareQuery.setDescription("Share query reference link"); btShareQuery.addStyleName(ValoTheme.BUTTON_BORDERLESS); layout.setWidth("100%"); layout.setHeight("-1px"); btFirst = new Button(); btFirst.setIcon(FIRST); btFirst.setDescription("jump to first page"); btFirst.addClickListener((Button.ClickListener) this); btFirst.addStyleName(ChameleonTheme.BUTTON_ICON_ONLY); btFirst.addStyleName(ChameleonTheme.BUTTON_SMALL); btFirst.setDisableOnClick(true); btLast = new Button(); btLast.setIcon(LAST); btLast.setDescription("jump to last page"); btLast.addClickListener((Button.ClickListener) this); btLast.addStyleName(ChameleonTheme.BUTTON_ICON_ONLY); btLast.addStyleName(ChameleonTheme.BUTTON_SMALL); btLast.setDisableOnClick(true); btNext = new Button(); btNext.setIcon(RIGHT_ARROW); btNext.setDescription("jump to next page"); btNext.addClickListener((Button.ClickListener) this); btNext.addStyleName(ChameleonTheme.BUTTON_ICON_ONLY); btNext.addStyleName(ChameleonTheme.BUTTON_SMALL); btNext.setDisableOnClick(true); btPrevious = new Button(); btPrevious.setIcon(LEFT_ARROW); btPrevious.setDescription("jump to previous page"); btPrevious.addClickListener((Button.ClickListener) this); btPrevious.addStyleName(ChameleonTheme.BUTTON_ICON_ONLY); btPrevious.addStyleName(ChameleonTheme.BUTTON_SMALL); btPrevious.setDisableOnClick(true); txtPage = new TextField(); txtPage.setDescription("current page"); txtPage.setHeight("-1px"); txtPage.setWidth(5.f, UNITS_EM); Validator pageValidator = new PageValidator("must be an integer greater than zero"); txtPage.addValidator(pageValidator); addActionHandler(new EnterHandler(txtPage)); lblMaxPages = new Label(); lblMaxPages.setDescription("maximal pages"); lblMaxPages.setSizeUndefined(); lblStatus = new Label(); lblStatus.setSizeUndefined(); layout.addComponent(btFirst); layout.addComponent(btPrevious); layout.addComponent(txtPage); layout.addComponent(lblMaxPages); layout.addComponent(btNext); layout.addComponent(btLast); layout.addComponent(lblStatus); layout.addComponent(lblInfo); layout.addComponent(btShareQuery); layout.setComponentAlignment(btFirst, Alignment.MIDDLE_LEFT); layout.setComponentAlignment(btPrevious, Alignment.MIDDLE_LEFT); layout.setComponentAlignment(lblStatus, Alignment.MIDDLE_LEFT); layout.setComponentAlignment(lblMaxPages, Alignment.MIDDLE_CENTER); layout.setComponentAlignment(txtPage, Alignment.MIDDLE_RIGHT); layout.setComponentAlignment(btNext, Alignment.MIDDLE_RIGHT); layout.setComponentAlignment(btLast, Alignment.MIDDLE_RIGHT); layout.setExpandRatio(lblStatus, 1.0f); layout.setComponentAlignment(lblInfo, Alignment.MIDDLE_RIGHT); layout.setExpandRatio(lblInfo, 10.0f); update(false); } @Override public void attach() { super.attach(); if (getUI() instanceof AnnisUI) { btShareQuery.addClickListener(new QueryReferenceLinkHandler((AnnisUI) getUI())); } else { btShareQuery.setVisible(false); } } private void update(boolean informCallbacks) { int myCount = count.get(); txtPage.setValue("" + currentPage); lblMaxPages.setValue("/ " + getMaxPage()); lblStatus.setValue("Displaying Results " + (getStartNumber() + 1) + " - " + Math.min(getStartNumber() + pageSize, myCount) + " of " + myCount); btFirst.setEnabled(currentPage > 1); btPrevious.setEnabled(currentPage > 1); btLast.setEnabled(currentPage < getMaxPage()); btNext.setEnabled(currentPage < getMaxPage()); if (informCallbacks) { for (PagingCallback c : callbacks) { c.switchPage(getStartNumber(), pageSize); } } } public void addCallback(PagingCallback callback) { callbacks.add(callback); } public boolean removeCallback(PagingCallback callback) { return callbacks.remove(callback); } public int getMaxPage() { int mycount = Math.max(0, count.get() - 1); return (1 + (mycount / pageSize)); } public long getStartNumber() { return (currentPage - 1) * pageSize; } public void setStartNumber(long startNumber) { currentPage = (startNumber / pageSize) + 1; update(false); } public int getCount() { return count.get(); } public void setCount(int count, boolean update) { if (count < 0) { count = 0; } this.count.set(count); update(update); } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize, boolean informCallback) { if (pageSize <= 0) { pageSize = 1; } this.pageSize = pageSize; update(informCallback); } @Override public void buttonClick(ClickEvent event) { btFirst.setEnabled(true); btLast.setEnabled(true); btNext.setEnabled(true); btPrevious.setEnabled(true); if (event.getButton() == btFirst) { currentPage = 1; } else if (event.getButton() == btLast) { currentPage = getMaxPage(); } else if (event.getButton() == btNext) { currentPage++; } else if (event.getButton() == btPrevious) { currentPage--; } // sanitize currentPage = sanitizePage(currentPage); update(true); } private long sanitizePage(long page) { long val = Math.max(1, page); val = Math.min(1 + (count.get() / pageSize), val); return val; } private class QueryReferenceLinkHandler implements Button.ClickListener { private final AnnisUI ui; public QueryReferenceLinkHandler(AnnisUI ui) { this.ui = ui; } @Override public void buttonClick(ClickEvent event) { ShareQueryReferenceWindow w = new ShareQueryReferenceWindow(ui.getQueryController().getSearchQuery(), !Helper.isKickstarter(getSession())); getUI().addWindow(w); w.center(); } } private class EnterHandler implements Action.Handler { private final Action enterKeyShortcutAction = new ShortcutAction(null, ShortcutAction.KeyCode.ENTER, null); private final Object registeredTarget; public EnterHandler(Object registeredTarget) { this.registeredTarget = registeredTarget; } @Override public Action[] getActions(Object target, Object sender) { return new Action[] { enterKeyShortcutAction }; } @Override public void handleAction(Action action, Object sender, Object target) { if (action == enterKeyShortcutAction && target == registeredTarget) { try { int newPage = Integer.parseInt((String) txtPage.getValue()); currentPage = sanitizePage(newPage); update(true); } catch (NumberFormatException ex) { log.error(null, ex); } } } } /** * Cuts off long queries. Actually they are restricted to 50 characters. The * full query is available with descriptions (tooltip in gui) * * @param text the query to display in the result view panel */ public void setInfo(String text) { if (text != null && text.length() > 0) { String prefix = "Result for: <span class=\"" + Helper.CORPUS_FONT_FORCE + "\">"; lblInfo.setDescription(prefix + text.replaceAll("\n", " ") + "</span>"); lblInfo.setValue( text.length() < 50 ? prefix + StringEscapeUtils.escapeHtml4(text.substring(0, text.length())) : prefix + StringEscapeUtils.escapeHtml4(text.substring(0, 50)) + " ... </span>"); } } private static class PageValidator extends AbstractStringValidator { public PageValidator(String errorMessage) { super(errorMessage); } @Override protected boolean isValidValue(String value) { try { int v = Integer.parseInt(value); if (v > 0) { return true; } else { return false; } } catch (Exception ex) { return false; } } } }