package scrum.client.common; import ilarkesto.core.logging.Log; import ilarkesto.gwt.client.Gwt; import scrum.client.ScrumScopeManager; import scrum.client.dnd.BlockDndMarkerWidget; import scrum.client.workspace.BlockCollapsedEvent; import scrum.client.workspace.BlockExpandedEvent; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; /** * Base class for a block widget, which can be added to a <code>BlockWidgetList</code>. * */ @SuppressWarnings("unchecked") public abstract class ABlockWidget<O> extends AScrumWidget { private O object; private boolean extended; private BlockListWidget<O> list; private BlockHeaderWidget header; private FlowPanel outerPanel; private FlowPanel preHeaderPanel; private FlowPanel panel; private SimplePanel bodyWrapper; private BlockDndMarkerWidget dndMarkerTop = new BlockDndMarkerWidget(); private boolean initializingExtension; private boolean initializedExtension; private Widget body; protected abstract void onInitializationHeader(BlockHeaderWidget header); protected abstract void onUpdateHeader(BlockHeaderWidget header); protected abstract Widget onExtendedInitialization(); public ABlockWidget() {} @Override protected final Widget onInitialization() { header = new BlockHeaderWidget(); header.initialize(); if (ScrumScopeManager.isProjectScope() && getObject() instanceof AScrumGwtEntity) { header.appendCell(new UsersOnBlockWidget((AScrumGwtEntity) getObject()), null, false, false, null); } if (list.dndManager != null) list.dndManager.makeDraggable(this, header.getDragHandle()); panel = Gwt.createFlowPanel("ABlockWidget", null, header); panel.add(header); outerPanel = Gwt.createFlowPanel("ABlockWidget-outer", null, dndMarkerTop, panel); dndMarkerTop.setActive(false); onInitializationHeader(header); header.addClickHandler(new SelectionClickHandler()); return outerPanel; } @Override protected final void onUpdate() { onUpdateHeader(header); header.update(); if (isExtended()) { ensureExtendedInitialized(); onUpdateBody(); if (bodyWrapper == null) { bodyWrapper = Gwt.createDiv("ABlockWidget-body", body); panel.add(bodyWrapper); } } else { if (bodyWrapper != null) { panel.remove(bodyWrapper); bodyWrapper = null; } } Gwt.update(preHeaderPanel); } protected void onUpdateBody() { Gwt.update(body); } private void ensureExtendedInitialized() { if (initializingExtension) throw new RuntimeException("Extension initializing. Don't call update() within onInitailization(): " + toString()); if (!initializedExtension) { if (initializingExtension) throw new RuntimeException("Extension already initializing: " + toString()); initializingExtension = true; Log.DEBUG("Initializing extension: " + toString()); body = onExtendedInitialization(); initializedExtension = true; initializingExtension = false; } } protected final void setObject(O object) { assert this.object == null; assert object != null; this.object = object; } protected final O getObject() { return object; } // public Widget getBorderPanel() { // return panel; // } public void deactivateDndMarkers() { dndMarkerTop.setActive(false); } public void activateDndMarkerTop() { dndMarkerTop.setActive(true); } public final BlockListWidget<O> getList() { return list; } final void setList(BlockListWidget list) { this.list = list; } /** * Indicates if the block is in extended-mode. This method should be called within the * <code>build()</code>-method. */ public final boolean isExtended() { return extended; } /** * This method is only called by BlockListWidget. To select a block on a BlockListWidget call * <code>BlockListWidget.selectBlock(B block)</code> instead. */ final void setExtended(boolean extended) { if (this.extended == extended) return; this.extended = extended; if (extended) { new BlockExpandedEvent(getObject()).fireInCurrentScope(); panel.addStyleName("ABlockWidget-extended"); } else { new BlockCollapsedEvent(getObject()).fireInCurrentScope(); panel.removeStyleName("ABlockWidget-extended"); } update(); } final void activate() { onActivation(); scrollIntoView(); } public void scrollIntoView() { getElement().scrollIntoView(); header.getDragHandle().getElement().scrollIntoView(); } protected void onActivation() {} @Override protected void onLoad() { super.onLoad(); if (getList().isDndSorting()) { getList().dndManager.registerDropTarget(this); } if (extended) new BlockExpandedEvent(getObject()).fireInCurrentScope(); } @Override protected void onUnload() { if (extended) new BlockCollapsedEvent(getObject()).fireInCurrentScope(); if (list.dndManager != null) list.dndManager.unregisterDropTarget(this); super.onUnload(); } public FlowPanel getPreHeaderPanel() { if (preHeaderPanel == null) { preHeaderPanel = new FlowPanel(); outerPanel.insert(preHeaderPanel, 0); } return preHeaderPanel; } private class SelectionClickHandler implements ClickHandler { @Override public void onClick(ClickEvent event) { NativeEvent nativeEvent = event.getNativeEvent(); boolean modifierDown = nativeEvent.getCtrlKey() || nativeEvent.getShiftKey() || nativeEvent.getAltKey(); list.toggleExtension(getObject(), !modifierDown); event.stopPropagation(); } } @Override public String toString() { return "[" + object + "]"; } }