net.sf.wcfart.wcf.changeorder.ChangeOrderMgr Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wcf-art Show documentation
Show all versions of wcf-art Show documentation
jpivot-wcf code used by the ART reporting tool
The newest version!
/*
* ====================================================================
* This software is subject to the terms of the Common Public License
* Agreement, available at the following URL:
* http://www.opensource.org/licenses/cpl.html .
* Copyright (C) 2003-2004 TONBELLER AG.
* All Rights Reserved.
* You must accept the terms of that agreement to use this software.
* ====================================================================
*
*
*/
package net.sf.wcfart.wcf.changeorder;
import org.w3c.dom.Element;
import net.sf.wcfart.tbutils.res.Resources;
import net.sf.wcfart.wcf.component.Form;
import net.sf.wcfart.wcf.component.RenderListener;
import net.sf.wcfart.wcf.controller.Dispatcher;
import net.sf.wcfart.wcf.controller.DispatcherSupport;
import net.sf.wcfart.wcf.controller.RequestContext;
import net.sf.wcfart.wcf.controller.RequestListener;
import net.sf.wcfart.wcf.scroller.Scroller;
import net.sf.wcfart.wcf.utils.DomUtils;
/**
* generates buttons to move objects in a list or tree
*
* @author av
*/
public class ChangeOrderMgr implements RenderListener {
Dispatcher dispatcher = new DispatcherSupport();
ChangeOrderModel model;
/** name of the DOM element */
static final String BUTTON_ELEMENT = "move-button";
/** attribute name of a BUTTON_ELEMENT_NAME element, value is STYLE_xxx */
static final String STYLE_ATTR = "style";
/** value for STYLE_ATTR */
static final String STYLE_FWD = "fwd";
/** value for STYLE_ATTR */
static final String STYLE_BWD = "bwd";
/** value for STYLE_ATTR */
static final String STYLE_CUT = "cut";
/** value for STYLE_ATTR */
static final String STYLE_UNCUT = "uncut";
/** value for STYLE_ATTR */
static final String STYLE_PASTE_BEFORE = "paste-before";
/** value for STYLE_ATTR */
static final String STYLE_PASTE_AFTER = "paste-after";
static final String TITLE_ATTR = "title";
String titleFwd = "";
String titleBwd = "";
String titleCut = "";
String titleUncut = "";
String titlePasteBefore = "";
String titlePasteAfter = "";
Form form;
public ChangeOrderMgr(Dispatcher parentDispatcher, Form form) {
this.form = form;
this.model = new DefaultChangeOrderModel();
parentDispatcher.addRequestListener(null, null, dispatcher);
}
/**
* creates new ChangeOrderMgr
* @param parentDispatcher
* @param form
* @param model null or the model to use
*/
public ChangeOrderMgr(Dispatcher parentDispatcher, Form form, ChangeOrderModel model) {
this.form = form;
this.model = model;
parentDispatcher.addRequestListener(null, null, dispatcher);
}
/**
* appends dom elements "move-button" with attribute "style=fwd|bwd" and "id",
* e.g. <move-button id="wcf.e5f8fbfc" style="bwd"/>
*
* There is one current ButtonRenderer which defines the state of the ChangeOrderMgr
*
* @param elem the parent element to which the "move-button" element is appended as a child
* @param scope defines the valid targets, where node
may be moved. node
* may be moved among other nodes that belong to the same scope. In a tree, the parent is a good choice
* to be the scope of its child nodes.
* @param nodeIndex the index of the the current node
among its siblings
* @param nodeCount number of nodes that belong to scope
.
*/
interface ButtonRenderer extends RenderListener {
void renderButton(Element elem, Object scope, Object node, int nodeIndex, int nodeCount);
}
/**
* creates "move forward" and "move backward" buttons. Allows the user to move a node
* for one position with each click. This is easy for small amount of nodes, but requires
* many clicks for larger amount.
*
* @author av
* @since 12.01.2005
*/
class ForwardBackwardButtonRenderer implements ButtonRenderer {
/** implement ButtonRenderer */
public void renderButton(Element elem, Object scope, Object node, int nodeIndex, int nodeCount) {
if (nodeIndex == 0) {
// first node can move forward only
// leave space for backward button only if there are inner nodes
if (nodeCount > 2)
appendEmptyButton(elem);
appendMoveButton(elem, scope, node, STYLE_FWD, titleFwd, nodeIndex, nodeIndex + 1);
} else if (nodeIndex == nodeCount - 1) {
// last node can move backward only
appendMoveButton(elem, scope, node, STYLE_BWD, titleBwd, nodeIndex, nodeIndex - 1);
// leave space for forward button only if there are inner nodes
if (nodeCount > 2)
appendEmptyButton(elem);
} else {
// inner nodes can move forward and backward
appendMoveButton(elem, scope, node, STYLE_BWD, titleBwd, nodeIndex, nodeIndex - 1);
appendMoveButton(elem, scope, node, STYLE_FWD, titleFwd, nodeIndex, nodeIndex + 1);
}
}
public void startRendering(RequestContext context) {
}
public void stopRendering() {
}
void appendEmptyButton(Element elem) {
Element buttonElem = elem.getOwnerDocument().createElement(BUTTON_ELEMENT);
elem.appendChild(buttonElem);
}
void appendMoveButton(Element elem, Object scope, Object item, String style, String title, int oldIndex,
int newIndex) {
Element buttonElem = elem.getOwnerDocument().createElement(BUTTON_ELEMENT);
elem.appendChild(buttonElem);
buttonElem.setAttribute(STYLE_ATTR, style);
buttonElem.setAttribute(TITLE_ATTR, title);
String id = DomUtils.randomId();
buttonElem.setAttribute("id", id);
dispatcher.addRequestListener(id, null, new ChangeOrderButtonHandler(scope, item, oldIndex,
newIndex));
}
};
/**
* renders a button that allows the user to "cut" a node which means to mark it for move.
* If the user "cut"s a node, the PasteButtonRenderer will become the current renderer to
* render the paste buttons.
* @author av
* @since 12.01.2005
*/
class CutButtonRenderer implements ButtonRenderer {
public void renderButton(Element elem, Object scope, Object item, int nodeIndex, int nodeCount) {
Element buttonElem = elem.getOwnerDocument().createElement(BUTTON_ELEMENT);
elem.appendChild(buttonElem);
buttonElem.setAttribute(STYLE_ATTR, STYLE_CUT);
buttonElem.setAttribute(TITLE_ATTR, titleCut);
String id = DomUtils.randomId();
buttonElem.setAttribute("id", id);
dispatcher.addRequestListener(id, null, new CutButtonHandler(scope, item, nodeIndex));
}
public void startRendering(RequestContext context) {
}
public void stopRendering() {
}
};
/**
* RequestHandler for a "Cut" button. Creates a PasteButtonRenderer for the selected node
* and makes it the current buttonRenderer.
*
* @author av
* @since 12.01.2005
*/
class CutButtonHandler implements RequestListener {
Object scope;
Object item;
int nodeIndex;
CutButtonHandler(Object scope, Object item, int nodeIndex) {
this.scope = scope;
this.item = item;
this.nodeIndex = nodeIndex;
}
public void request(RequestContext context) throws Exception {
Scroller.enableScroller(context);
form.validate(context);
if (model != null)
buttonRenderer = new PasteButtonRenderer(scope, item, nodeIndex);
}
}
/**
* renders paste buttons. When rendering has finished (stopRendering() was called), the
* current buttonRenderer is restored to a CutRenderer. So if the user collapses a tree node
* instead of pasting a previously cutted node, the tree goes back into cut mode automatically.
*
* @author av
* @since 12.01.2005
*/
class PasteButtonRenderer implements ButtonRenderer {
Object scope;
Object item;
int nodeIndex;
PasteButtonRenderer(Object scope, Object item, int nodeIndex) {
this.scope = scope;
this.item = item;
this.nodeIndex = nodeIndex;
}
boolean equals(Object o1, Object o2) {
if (o1 == null)
return o2 == null;
return o1.equals(o2);
}
public void renderButton(Element elem, Object scope, Object item, int nodeIndex, int nodeCount) {
// may not move into another scope
if (!equals(this.scope, scope))
return;
// current item gets an "undo cut" button
Element buttonElem = elem.getOwnerDocument().createElement(BUTTON_ELEMENT);
elem.appendChild(buttonElem);
String id = DomUtils.randomId();
buttonElem.setAttribute("id", id);
if (this.nodeIndex == nodeIndex) {
// create a "undo cut" button
buttonElem.setAttribute(STYLE_ATTR, STYLE_UNCUT);
buttonElem.setAttribute(TITLE_ATTR, titleUncut);
dispatcher.addRequestListener(id, null, new UnCutButtonHandler());
} else if (this.nodeIndex < nodeIndex) {
// create a "paste after" button
buttonElem.setAttribute(STYLE_ATTR, STYLE_PASTE_AFTER);
buttonElem.setAttribute(TITLE_ATTR, titlePasteAfter);
dispatcher.addRequestListener(id, null, new ChangeOrderButtonHandler(scope, item,
this.nodeIndex, nodeIndex));
} else {
// create a "paste before" button
buttonElem.setAttribute(STYLE_ATTR, STYLE_PASTE_BEFORE);
buttonElem.setAttribute(TITLE_ATTR, titlePasteBefore);
dispatcher.addRequestListener(id, null, new ChangeOrderButtonHandler(scope, item,
this.nodeIndex, nodeIndex));
}
}
public void startRendering(RequestContext context) {
}
public void stopRendering() {
buttonRenderer = new CutButtonRenderer();
}
};
/**
* handler for the selected node in "paste mode". If the user clicks on that node again,
* "paste mode" will be reset to "cut mode".
* @author av
* @since 12.01.2005
*/
class UnCutButtonHandler implements RequestListener {
public void request(RequestContext context) throws Exception {
Scroller.enableScroller(context);
form.validate(context);
buttonRenderer = new CutButtonRenderer();
}
}
/**
* button handler that moves a node from one position to another. Used in forward/backward mode as well
* as in paste mode.
* @author av
* @since 12.01.2005
*/
class ChangeOrderButtonHandler implements RequestListener {
Object scope;
Object item;
int oldIndex;
int newIndex;
ChangeOrderButtonHandler(Object scope, Object item, int oldIndex, int newIndex) {
this.scope = scope;
this.item = item;
this.oldIndex = oldIndex;
this.newIndex = newIndex;
}
public void request(RequestContext context) throws Exception {
Scroller.enableScroller(context);
form.validate(context);
if (model != null)
model.move(scope, item, oldIndex, newIndex);
}
}
/**
* the current buttonRenderer, implements some kind of state machine.
*/
ButtonRenderer buttonRenderer = new ForwardBackwardButtonRenderer();
public void renderButton(Element elem, Object scope, Object node, int nodeIndex, int nodeCount) {
if (model == null || !model.mayMove(scope, node))
return;
// a single node can not be moved around
if (nodeCount < 2)
return;
buttonRenderer.renderButton(elem, scope, node, nodeIndex, nodeCount);
}
/**
* called once before rendering of buttons starts
*/
public void startRendering(RequestContext context) {
Resources res = context.getResources(ChangeOrderMgr.class);
titleFwd = res.getString("ChangeOrderMgr.titleFwd");
titleBwd = res.getString("ChangeOrderMgr.titleBwd");
titleCut = res.getString("ChangeOrderMgr.titleCut");
titleUncut = res.getString("ChangeOrderMgr.titleUncut");
titlePasteBefore = res.getString("ChangeOrderMgr.titlePasteBefore");
titlePasteAfter = res.getString("ChangeOrderMgr.titlePasteAfter");
dispatcher.clear();
buttonRenderer.startRendering(context);
}
/**
* called once after rendering of buttons has finished
*/
public void stopRendering() {
buttonRenderer.stopRendering();
}
public ChangeOrderModel getModel() {
return model;
}
public void setModel(ChangeOrderModel model) {
this.model = model;
}
public void setCutPasteMode(boolean b) {
if (b)
buttonRenderer = new CutButtonRenderer();
else
buttonRenderer = new ForwardBackwardButtonRenderer();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy