Java tutorial
/* * Copyright 2018 NEOautus Ltd. (http://neoautus.com) * * 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 org.lucidj.browser; import com.google.gwt.safehtml.shared.SafeHtmlUtils; import org.lucidj.api.stddef.Aggregate; import org.lucidj.api.core.ComponentDescriptor; import org.lucidj.api.core.ComponentInterface; import org.lucidj.api.core.ComponentState; import org.lucidj.api.vui.EditorInterface; import org.lucidj.api.vui.ObjectRenderer; import org.lucidj.api.vui.RendererFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.event.LayoutEvents; import com.vaadin.event.Transferable; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.DropTarget; import com.vaadin.event.dd.TargetDetails; import com.vaadin.event.dd.acceptcriteria.AcceptAll; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.server.FontAwesome; import com.vaadin.server.Sizeable; import com.vaadin.shared.ui.dd.VerticalDropLocation; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.ui.AbstractLayout; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.DragAndDropWrapper; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.UI; public abstract class AbstractCell implements DropHandler, LayoutEvents.LayoutClickListener, ComponentState.ChangeListener { private final static Logger log = LoggerFactory.getLogger(AbstractCell.class); private Object source_object; private ObjectRenderer object_renderer; private DragAndDropWrapper cell_wrap; private CssLayout left_panel; private CssLayout right_panel; private HorizontalLayout decorated_cell; private int task_state; private Label running; private Label component_icon; public AbstractCell(RendererFactory rendererFactory, Object object) { Component rendered_object; log.info("Cell: object = {}", object); if (object != null) { // Register and render the source object source_object = object; rendered_object = object_renderer = rendererFactory.newRenderer(source_object); } else { rendered_object = build_insert_here(); } log.info("Cell: rendered_object = {}", rendered_object); // Create and set drag and drop wrapper cell_wrap = new DragAndDropWrapper(rendered_object); cell_wrap.addStyleName("component-cell-wrapper"); if (object == null) // Insert here cell { cell_wrap.addStyleName("no-horizontal-drag-hints"); cell_wrap.addStyleName("no-vertical-drag-hints"); } else // Normal cell { cell_wrap.addStyleName("no-horizontal-drag-hints"); cell_wrap.addStyleName("no-box-drag-hints"); } // Setup DD handlers for component insertion cell_wrap.setData(this); cell_wrap.setDropHandler(this); decorated_cell = new HorizontalLayout(); decorated_cell.setWidth(100, Sizeable.Unit.PERCENTAGE); // Left panel decorated_cell.addComponent(build_left_panel()); // TODO: NOTIFY ObjectRenderer COMPONENT SWAP SO WE CAN UPDATE LISTENERS! decorated_cell.addComponent(cell_wrap); decorated_cell.setExpandRatio(cell_wrap, 1.0f); // Right panel decorated_cell.addComponent(build_right_panel()); // Uses clicks to set where the focus is decorated_cell.addLayoutClickListener(this); } private Component build_insert_here() { Label message = new Label("Drag or double-click any component to add one or more here"); // TODO: FIX WRONG TEXT-WRAPPING WHEN CELL TOO NARROW message.addStyleName("formula-insert-here"); message.setHeight(64, Sizeable.Unit.PIXELS); message.setWidth(100, Sizeable.Unit.PERCENTAGE); return (message); } private Component build_left_panel() { left_panel = new CssLayout(); left_panel.setWidth(32, Sizeable.Unit.PIXELS); left_panel.addStyleName("cell-panel-left"); left_panel.setHeight(100, Sizeable.Unit.PERCENTAGE); String icon_url = "/VAADIN/~/formulas/impossible.png"; String icon_title = "The Unknown"; ComponentInterface component_interface = Aggregate.adapt(ComponentInterface.class, source_object); if (component_interface != null) { // If it is a valid component, displays its icon on the top left corner of the cell ComponentDescriptor descriptor = (ComponentDescriptor) component_interface .getProperty(ComponentDescriptor.DESCRIPTOR); if (descriptor != null) { icon_url = descriptor.getIconUrl(); icon_title = descriptor.getIconTitle(); } } String component_icon_html = "<img class='component-icon' src='" + icon_url + "' title='" + SafeHtmlUtils.htmlEscape(icon_title) + "'/>"; component_icon = new Label(component_icon_html, ContentMode.HTML); left_panel.addComponent(component_icon); // Put the component in a D&D wrapper and allow dragging it final DragAndDropWrapper panel_dd_wrap = new DragAndDropWrapper(left_panel); panel_dd_wrap.setDragStartMode(DragAndDropWrapper.DragStartMode.COMPONENT_OTHER); panel_dd_wrap.setDragImageComponent(component_icon); panel_dd_wrap.addStyleName("no-horizontal-drag-hints"); panel_dd_wrap.addStyleName("no-box-drag-hints"); // Set the wrapper to wrap tightly around the component panel_dd_wrap.setHeight(100, Sizeable.Unit.PERCENTAGE); panel_dd_wrap.setWidthUndefined(); panel_dd_wrap.setId("test"); // Setup DD handlers for component insertion panel_dd_wrap.setData(this); panel_dd_wrap.setDropHandler(this); // While left_panel is kept in order to be customized, here we return D&D wrapper return (panel_dd_wrap); } private CssLayout build_right_panel() { right_panel = new CssLayout(); right_panel.addStyleName("cell-panel-right"); right_panel.setHeight(100, Sizeable.Unit.PERCENTAGE); right_panel.setWidth(32, Sizeable.Unit.PIXELS); String running_html = "*"; //"<img src='/VAADIN/formulas/running.gif'/>"; running = new Label(running_html, ContentMode.HTML); running.addStyleName("component-task-state"); running.setWidth(32, Sizeable.Unit.PIXELS); running.setVisible(false); right_panel.addComponent(running); ComponentState source_state = Aggregate.adapt(ComponentState.class, source_object); if (source_state != null) { source_state.addStateListener(this); setRunning(true, source_state); } else { setRunning(true, null); } return (right_panel); } public void setRunning(boolean visible, ComponentState state) { if (visible) { if (state != null) { task_state = state.getState(); if (task_state == ComponentState.ACTIVE || task_state == ComponentState.TERMINATED) { // Ready to run visible only with hover or selection running.removeStyleName("component-task-state-visible"); } else { // All other states are always visible running.addStyleName("component-task-state-visible"); } String color = "inherit"; String html = "S" + String.valueOf(state.getState()); String title = "State " + String.valueOf(state.getState()); switch (task_state) // Also record the rendered state { case ComponentState.INIT: { html = FontAwesome.CLOCK_O.getHtml(); title = "Task awaiting initialization"; break; } case ComponentState.ABORTED: { color = "red"; html = "<span class='component-task-runnable'>" + FontAwesome.WARNING.getHtml() + "</span>"; title = "Task aborted, can try to run"; break; } case ComponentState.ACTIVE: { color = "green"; html = FontAwesome.PLAY.getHtml(); title = "Run task"; break; } case ComponentState.TERMINATED: { color = "green"; html = FontAwesome.PLAY.getHtml(); title = "Task finished, can run again"; break; } case ComponentState.INTERRUPTED: { color = "blue"; html = "<span class='component-task-runnable'>" + FontAwesome.PAUSE.getHtml() + "</span>"; title = "Task interrupted by user, can run again"; break; } case ComponentState.RUNNING: { color = "red"; html = FontAwesome.STOP.getHtml(); title = "Task running"; break; } } running.setValue("<span style='color:" + color + ";' title='" + title + "'>" + html + "</span>"); } else { running.setValue(""); } } running.setVisible(visible); } @Override public void stateChanged(ComponentState ref) { setRunning(true, ref); } public Component getDecoratedCell() { return (decorated_cell); } public Object getSourceObject() { return (source_object); } public void scrollIntoView() { EditorInterface ei = object_renderer.adapt(EditorInterface.class); if (ei != null && ei.getFocusComponent() != null) { // TODO: BETTER HANDLING OF SCROLL INTO ei.getFocusComponent().focus(); UI.getCurrent().scrollIntoView(ei.getFocusComponent()); } } public void setFocus() { EditorInterface ei = object_renderer.adapt(EditorInterface.class); if (ei != null) { setToolbar(ei.toolbar()); } else // No toolbar interface { setToolbar(null); } cell_wrap.addStyleName("component-cell-wrapper-selected"); //rendered_object left_panel.addStyleName("cell-panel-selected"); right_panel.addStyleName("cell-panel-selected"); } public void removeFocus() { cell_wrap.removeStyleName("component-cell-wrapper-selected"); left_panel.removeStyleName("cell-panel-selected"); right_panel.removeStyleName("cell-panel-selected"); } @Override // DropHandler public void drop(DragAndDropEvent dragAndDropEvent) { log.info("**** DROP! {}", dragAndDropEvent); final Transferable transferable = dragAndDropEvent.getTransferable(); final Component sourceComponent = transferable.getSourceComponent(); log.info("sourceComponent = {}", sourceComponent); final TargetDetails dropTargetData = dragAndDropEvent.getTargetDetails(); final DropTarget target = dropTargetData.getTarget(); log.info("DROP: source={} target={}", sourceComponent, target); String pos = (String) dropTargetData.getData("verticalLocation"); String canonical_name = sourceComponent.getId(); Object source_cell = ((DragAndDropWrapper) sourceComponent).getData(); Object source_object = (source_cell instanceof AbstractCell) ? ((AbstractCell) source_cell).getSourceObject() : null; Object target_cell = ((DragAndDropWrapper) target).getData(); Object target_object = (target_cell instanceof AbstractCell) ? ((AbstractCell) target_cell).getSourceObject() : null; log.info("D&D: source=[{}, {}] => target=[{}, {}]", source_cell, source_object, target_cell, target_object); if (target_object == null) { insertNewObjectBefore(canonical_name, null); } else if (pos.equals(VerticalDropLocation.BOTTOM.toString())) { if (source_cell instanceof AbstractCell) { if (source_object != target_object) { log.info("Move AFTER component #{}: {} {}", target_object, source_cell, canonical_name); moveObjectAfter(source_object, target_object); } } else { log.info("Drop AFTER component #{}: {} {}", target_object, source_cell, canonical_name); insertNewObjectAfter(canonical_name, target_object); } } else if (pos.equals(VerticalDropLocation.TOP.toString())) { if (source_cell instanceof AbstractCell) { if (source_object != target_object) { log.info("Move BEFORE component #{}: {} {}", target_object, source_cell, canonical_name); moveObjectBefore(source_object, target_object); } } else { log.info("Drop BEFORE component #{}: {} {}", target_object, source_cell, canonical_name); insertNewObjectBefore(canonical_name, target_object); } } } @Override // DropHandler public AcceptCriterion getAcceptCriterion() { return (AcceptAll.get()); } @Override // LayoutEvents.LayoutClickListener public void layoutClick(LayoutEvents.LayoutClickEvent layoutClickEvent) { Component clicked = layoutClickEvent.getClickedComponent(); log.info("{} component={}", layoutClickEvent.isDoubleClick() ? "layoutDoubleClick" : "layoutClick", clicked); if (clicked != null) { if (layoutClickEvent.isDoubleClick()) { layoutDoubleClick(layoutClickEvent.getClickedComponent()); } else { if (layoutClickEvent.getClickedComponent() == running) { taskStateClick(task_state); } else { layoutClick(layoutClickEvent.getClickedComponent()); } } } } public abstract Object insertNewObjectBefore(String obj_canonical_name, Object ref_obj); public abstract Object insertNewObjectAfter(String obj_canonical_name, Object ref_obj); public abstract void moveObjectBefore(Object source_object, Object target_object); public abstract void moveObjectAfter(Object source_object, Object target_object); public abstract void taskStateClick(int task_state); public abstract void layoutClick(Component component); public abstract void layoutDoubleClick(Component component); public abstract void setToolbar(AbstractLayout toolbar); } // EOF