Java tutorial
/** * Copyright (c) 2015 Bosch Software Innovations GmbH and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.hawkbit.ui.dd.client.criteria; import static org.eclipse.hawkbit.ui.dd.criteria.AcceptCriteriaConstants.DROP_AREA_CONFIG; import static org.eclipse.hawkbit.ui.dd.criteria.AcceptCriteriaConstants.DROP_AREA_CONFIG_COUNT; import static org.eclipse.hawkbit.ui.dd.criteria.AcceptCriteriaConstants.ERROR_MESSAGE; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.hawkbit.ui.dd.criteria.ServerViewClientCriterion; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.HeadElement; import com.google.gwt.dom.client.StyleElement; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Event.NativePreviewHandler; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.UIDL; import com.vaadin.client.ui.VNotification; import com.vaadin.client.ui.VScrollTable; import com.vaadin.client.ui.dd.VAcceptCallback; import com.vaadin.client.ui.dd.VAcceptCriteria; import com.vaadin.client.ui.dd.VAcceptCriterion; import com.vaadin.client.ui.dd.VDragEvent; import com.vaadin.shared.Position; import com.vaadin.shared.ui.dd.AcceptCriterion; /** * Client part for the client-side accept criterion.<br> * This class represents a composite for * <code>ViewComponentClientCriterion</code> elements.<br> * The criterion is not only responsible to check if the current drop location * is a valid drop target, but also concerns about: * <ul> * <li>Hide drop hints when drop operation is finished or aborted.</li> * <li>Show error message (via message box) if the drop location is not a valid * drop target.</li> * <li>In case of multi-row selection: Decorate the drag element with the number * of dragged elements.</li> * </ul> */ @AcceptCriterion(ServerViewClientCriterion.class) public final class ViewClientCriterion extends VAcceptCriterion implements VAcceptCallback { private static final Logger LOGGER = Logger.getLogger(ViewClientCriterion.class.getName()); static final String SP_DRAG_COUNT = "sp-drag-count"; private boolean accepted; private ViewCriterionTemplates multiRowSelectStyle; private VDragEvent previousDragEvent; private HandlerRegistration nativeEventHandlerRegistration; private String errorMessage; /** * This interface is used to compile string templates in the GWT context (as * other approaches like <code>MessageFormat</code> would fail). */ interface ViewCriterionTemplates extends SafeHtmlTemplates { /** * @param theme * the current UI schema * @param rowCount * the amount of selected rows * @return compiled template */ @Template(".{0} tbody.v-drag-element tr:after{ content:\"{1}\"; } " + ".{0} tr.v-drag-element:after{ content:\"{1}\"; } " + ".{0} table.v-drag-element:after{ content:\"{1}\"; } ") SafeHtml multiSelectionStyle(String theme, String rowCount); /** * @param msg * the message to style * @return compiled style template */ @Template("<p class=\"v-Notification-description\"><span class=\"v-icon\" style=\"font-family: FontAwesome;\"></span> {0}</p>") SafeHtml notificationMsg(String msg); } private static VAcceptCriterion getCriteria(final UIDL configuration, final int i) { final UIDL childUIDL = configuration.getChildUIDL(i); return VAcceptCriteria.get(childUIDL.getStringAttribute("name")); } /** * Lazy compile the string templates. * * @return templates */ private ViewCriterionTemplates getDraggableTemplate() { // no need to synchronize, JavaScript in the browser is single-threaded if (multiRowSelectStyle == null) { multiRowSelectStyle = GWT.create(ViewCriterionTemplates.class); } return multiRowSelectStyle; } @Override // Exception squid:S1604 - GWT 2.7 does not support Java 8 @SuppressWarnings("squid:S1604") public void accept(final VDragEvent drag, final UIDL configuration, final VAcceptCallback callback) { if (isDragStarting(drag)) { final NativePreviewHandler nativeEventHandler = new NativePreviewHandler() { @Override public void onPreviewNativeEvent(final NativePreviewEvent event) { if (isEscKey(event) || isMouseUp(event)) { try { hideDropTargetHints(configuration); } finally { nativeEventHandlerRegistration.removeHandler(); } } } }; nativeEventHandlerRegistration = Event.addNativePreviewHandler(nativeEventHandler); setMultiRowDragDecoration(drag); } final int childCount = configuration.getChildCount(); accepted = false; for (int childIndex = 0; childIndex < childCount; childIndex++) { final VAcceptCriterion crit = getCriteria(configuration, childIndex); crit.accept(drag, configuration.getChildUIDL(childIndex), this); if (Boolean.TRUE.equals(accepted)) { callback.accepted(drag); return; } } // if no VAcceptCriterion accepts and the mouse is release, an error // message is shown if (Event.ONMOUSEUP == Event.getTypeInt(drag.getCurrentGwtEvent().getType())) { showErrorNotification(drag); } errorMessage = configuration.getStringAttribute(ERROR_MESSAGE); } @Override public boolean needsServerSideCheck(final VDragEvent drag, final UIDL criterioUIDL) { return false; } @Override protected boolean accept(final VDragEvent drag, final UIDL configuration) { // not used here: return false; } @Override public void accepted(final VDragEvent event) { accepted = true; } /** * Styles a multi-row selection with the number of elements. * * @param drag * the current drag event holding the context. */ void setMultiRowDragDecoration(final VDragEvent drag) { final Widget widget = drag.getTransferable().getDragSource().getWidget(); if (widget instanceof VScrollTable) { final VScrollTable table = (VScrollTable) widget; final int rowCount = table.selectedRowKeys.size(); Element dragCountElement = Document.get().getElementById(SP_DRAG_COUNT); if (rowCount > 1 && table.selectedRowKeys.contains(table.focusedRow.getKey())) { if (dragCountElement == null) { dragCountElement = Document.get().createStyleElement(); dragCountElement.setId(SP_DRAG_COUNT); final HeadElement head = HeadElement .as(Document.get().getElementsByTagName(HeadElement.TAG).getItem(0)); head.appendChild(dragCountElement); } final SafeHtml formattedCssStyle = getDraggableTemplate() .multiSelectionStyle(determineActiveTheme(drag), String.valueOf(rowCount)); final StyleElement dragCountStyleElement = StyleElement.as(dragCountElement); dragCountStyleElement.setInnerSafeHtml(formattedCssStyle); } else if (dragCountElement != null) { dragCountElement.removeFromParent(); } } } /** * Checks if the origin of the given event is a pressed ESC key. * * @param event * the event to analyze * @return <code>true</code> if the origin of the event is a pressed ESC * key, otherwise <code>false</code>. */ private static boolean isEscKey(final NativePreviewEvent event) { final int typeInt = event.getTypeInt(); if (typeInt == Event.ONKEYDOWN) { final int keyCode = event.getNativeEvent().getKeyCode(); if (KeyCodes.KEY_ESCAPE == keyCode) { return true; } } return false; } /** * Checks if the given event is of type <code>Event.ONMOUSEUP</code>. * * @param event * the event to analyze * @return <code>true</code> if the given event is of type * <code>Event.ONMOUSEUP</code>, otherwise <code>false</code>. */ private static boolean isMouseUp(final NativePreviewEvent event) { return Event.ONMOUSEUP == Event.getTypeInt(event.getNativeEvent().getType()); } /** * Hides the highlighted drop target hints. * * @param configuration * for the accept criterion to retrieve the drop target hints. */ // Exception squid:S1166 - Hide origin exception // Exception squid:S2221 - This code is trans-coded to JavaScript, hence // Exception semantics changes @SuppressWarnings({ "squid:S1166", "squid:S2221" }) void hideDropTargetHints(final UIDL configuration) { final int totalDropTargetHintsCount = configuration.getIntAttribute(DROP_AREA_CONFIG_COUNT); for (int dropAreaIndex = 0; dropAreaIndex < totalDropTargetHintsCount; dropAreaIndex++) { try { final String dropArea = configuration.getStringAttribute(DROP_AREA_CONFIG + dropAreaIndex); final Element hideHintFor = Document.get().getElementById(dropArea); if (hideHintFor != null) { hideHintFor.removeClassName(ViewComponentClientCriterion.HINT_AREA_STYLE); } } catch (final Exception e) { // log and continue LOGGER.log(Level.SEVERE, "Error highlighting valid drop targets: " + e.getLocalizedMessage()); } } } /** * Displays a message box telling that the action is not allowed. * * @param drag * the current drag event holding the context. */ private void showErrorNotification(final VDragEvent drag) { final VNotification n = VNotification.createNotification(SPUILabelDefinitions.SP_DELAY, drag.getTransferable().getDragSource().getWidget()); n.show(getDraggableTemplate().notificationMsg(errorMessage).asString(), Position.BOTTOM_RIGHT, SPUIStyleDefinitions.SP_NOTIFICATION_ERROR_MESSAGE_STYLE); } /** * Determines the active UI theme for a given event. * * @param drag * the event the UI theme is retrieved for. * @return the active theme (e.g. "hawkbit"). */ private static String determineActiveTheme(final VDragEvent drag) { return drag.getTransferable().getDragSource().getConnection().getUIConnector().getActiveTheme(); } /** * Tests whether this drag operation has just started or if it is just * proceeded. * * @param drag * the event that indicates if this is a starting drag operation * or a proceeding one. * @return <code>true</code> if the drag operation is starting, otherwise * <code>false</code> */ private boolean isDragStarting(final VDragEvent drag) { boolean result = false; if (!drag.equals(previousDragEvent)) { result = true; previousDragEvent = drag; } return result; } }