CCM NG: Current status Admin UIs
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3691 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
63d2f6d51a
commit
01befa0c74
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop;
|
||||
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A link that runs its action listeners when it is clicked. The target of the
|
||||
* link is the {@link Page} in which the action link is contained.
|
||||
*
|
||||
* <p> Typically, an action link is used in the following way:
|
||||
* <pre>
|
||||
* ActionLink l = new ActionLink("Send email to everybody");
|
||||
* l.addActionListener(new ActionListener() {
|
||||
* public void actionPerformed(ActionEvent e) {
|
||||
* System.out.println("Link was clicked.");
|
||||
* ... figure out who everybody is and send them email ...
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* <p>See {@link BaseLink} for a description of all Bebop Link classes
|
||||
* and suggestions for using them.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$ */
|
||||
public class ActionLink extends ControlLink {
|
||||
|
||||
/**
|
||||
* The value for the XML type attribute for an {@link ActionLink}.
|
||||
*/
|
||||
protected final String TYPE_ACTION = "action";
|
||||
|
||||
/**
|
||||
* Constructs a new ActionLink. The link encapsulates
|
||||
* the child component (usually either a label or an image).
|
||||
*
|
||||
* @param child the component to be turned into a link
|
||||
*/
|
||||
public ActionLink(Component child) {
|
||||
super(child);
|
||||
setTypeAttr(TYPE_ACTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ActionLink with the given string label.
|
||||
*
|
||||
* @param label the string label for the link
|
||||
*/
|
||||
public ActionLink(GlobalizedMessage label) {
|
||||
this(new Label(label));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ActionLink with the given string label.
|
||||
*
|
||||
* @param label the string label for the link
|
||||
* @deprecated refactor to use @see ActionLink(GlobalizedMessage label)
|
||||
*/
|
||||
public ActionLink(String label) {
|
||||
this(new Label(label));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the page state's control event. Should be overridden by child
|
||||
* classes. By default, the link does not receive any control events.
|
||||
*
|
||||
* @param s the current page state
|
||||
*/
|
||||
@Override
|
||||
public void setControlEvent(PageState s) {
|
||||
s.setControlEvent(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
||||
/**
|
||||
*
|
||||
* Interface that should be implemented by components that have
|
||||
* state parameters that need to be reset when the component is shown
|
||||
* to the user. The details of when the reset method is called are left
|
||||
* to the application programmer.
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Resettable {
|
||||
|
||||
/**
|
||||
* Resets the state of the component to its original
|
||||
* appearance.
|
||||
*
|
||||
* @param state the page state
|
||||
*/
|
||||
void reset(PageState state);
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
import static com.arsdigita.bebop.util.BebopConstants.*;
|
||||
|
||||
import com.arsdigita.xml.Element;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import com.arsdigita.bebop.util.BebopConstants;
|
||||
|
||||
/**
|
||||
* Generates a list of segments. Each segment consists of a header
|
||||
* (which could be any Bebop component) and a body (which, likewise,
|
||||
* could be any component). The entire <code>SegmentedPanel</code>
|
||||
* look roughly like this:
|
||||
*
|
||||
* <blockquote><pre><code>
|
||||
* ----------------------
|
||||
* Header 1
|
||||
* ----------------------
|
||||
* Body 1
|
||||
* More Body 1
|
||||
* Even more Body 1
|
||||
* ----------------------
|
||||
* Header 2
|
||||
* ----------------------
|
||||
* Body 2
|
||||
* More Body 2
|
||||
* Even more Body 2
|
||||
* </code></pre></blockquote>
|
||||
*
|
||||
* Typically, the body of each segment will be a {@link SimpleContainer}
|
||||
* which contains many other components
|
||||
* <p>
|
||||
* The XML generated by this component looks something like this:
|
||||
* <blockquote><pre><code>
|
||||
* <bebop:segmentedPanel>
|
||||
* <bebop:segment id="foo">
|
||||
* <bebop:segmentHeader>
|
||||
* <aRandomHeaderComponent/>
|
||||
* <anotherRandomHeaderComponent/>
|
||||
* ...
|
||||
* </bebop:segmentHeader>
|
||||
* <bebop:segmentBody>
|
||||
* <aRandomBodyComponent>
|
||||
* <anotherRandomBodyComponent>
|
||||
* ...
|
||||
* </bebop:segmentBody>
|
||||
* </bebop:segment>
|
||||
* ...
|
||||
* </bebop:segmentedPanel>
|
||||
* </code></pre></blockquote>
|
||||
*
|
||||
* @see #generateXML(PageState, Element)
|
||||
*
|
||||
* @author Michael Pih
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SegmentedPanel extends SimpleContainer
|
||||
implements BebopConstants {
|
||||
|
||||
public static final String HEADER_CLASS = "seg-header";
|
||||
|
||||
/**
|
||||
* Construct a new <code>SegmentedPanel</code>
|
||||
*/
|
||||
public SegmentedPanel() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new <code>SegmentedPanel</code>
|
||||
*
|
||||
* @param idAttr the XSL ID attribute for this container
|
||||
* @see SimpleComponent#setIdAttr(String)
|
||||
*/
|
||||
public SegmentedPanel(String idAttr) {
|
||||
this();
|
||||
setIdAttr(idAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a segment to this container
|
||||
*
|
||||
* @param header the component that will act as the header
|
||||
* @param body the component that will act as the body
|
||||
* @return the new segment
|
||||
*/
|
||||
public Segment addSegment(Component header, Component body) {
|
||||
Segment s = new Segment(header, body);
|
||||
add(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a segment to this container.
|
||||
*
|
||||
* @param segmentID the XSL ID attribute for the new segment.
|
||||
* @param header the component that will act as the header.
|
||||
* @param body the component that will act as the body
|
||||
* @return the new segment
|
||||
*/
|
||||
public Segment addSegment(String segmentID, Component header, Component body) {
|
||||
Segment s = addSegment(header, body);
|
||||
s.setIdAttr(segmentID);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a segment to this container.
|
||||
*
|
||||
* @param segmentID the XSL ID attribute for the new segment. The XSL template
|
||||
* for this component will render the correct header based on the ID attribute
|
||||
* @param body the component that will act as the body
|
||||
* @return the new segment
|
||||
*/
|
||||
public Segment addSegment(String segmentID, Component body) {
|
||||
return addSegment(segmentID, null, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add and return a new empty segment.
|
||||
*
|
||||
* @return a new empty segment that is part of the panel.
|
||||
*/
|
||||
public Segment addSegment() {
|
||||
Segment result = new Segment();
|
||||
add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the XML for this component, as described above
|
||||
*
|
||||
* @param state represents the page state for the current request
|
||||
* @param parent the parent XML element
|
||||
*/
|
||||
public void generateXML(PageState state, Element parent) {
|
||||
if ( isVisible(state) ) {
|
||||
Element panel = parent.newChildElement(BEBOP_SEG_PANEL, BEBOP_XML_NS);
|
||||
exportAttributes(panel);
|
||||
super.generateXML(state, panel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single Segment within this container
|
||||
*/
|
||||
public static class Segment extends SimpleContainer {
|
||||
|
||||
private SimpleContainer m_header, m_body;
|
||||
|
||||
/**
|
||||
* Construct an empty <code>Segment</code>
|
||||
*/
|
||||
public Segment() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new <code>Segment</code>
|
||||
*
|
||||
* @param header the component which will act as the header; the XSL
|
||||
* class attribute for the component will be set to {@link #HEADER_CLASS}.
|
||||
* Typically, this component will be a {@link Label}
|
||||
* @param body the component which represents the body of the segment, Typically,
|
||||
* this component will be a {@link SimpleContainer} or a panel of some sort
|
||||
*/
|
||||
public Segment(Component header, Component body) {
|
||||
super();
|
||||
if(header != null) addHeader(header);
|
||||
if(body!= null) add(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new <code>Segment</code> with no header
|
||||
*
|
||||
* @param body the component which represents the body of the segment, Typically,
|
||||
* this component will be a {@link SimpleContainer} or a panel of some sort
|
||||
*/
|
||||
public Segment(Component body) {
|
||||
this(null, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a header component.
|
||||
*
|
||||
* @param c an additional header component
|
||||
*/
|
||||
public void addHeader(Component c) {
|
||||
Assert.isUnlocked(this);
|
||||
if(m_header == null) {
|
||||
m_header = new SimpleContainer(BEBOP_SEG_HEADER, BEBOP_XML_NS);
|
||||
super.add(m_header);
|
||||
}
|
||||
m_header.add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a component to the body of this segment
|
||||
*/
|
||||
public void add(Component c) {
|
||||
Assert.isUnlocked(this);
|
||||
if(m_body == null) {
|
||||
m_body = new SimpleContainer(BEBOP_SEG_BODY, BEBOP_XML_NS);
|
||||
super.add(m_body);
|
||||
}
|
||||
m_body.add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a component to the body of this segment
|
||||
*/
|
||||
public void add(Component c, int constraints) {
|
||||
add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the XML for this segment
|
||||
*
|
||||
* @param state the current page state
|
||||
* @param parent the parent XML element
|
||||
*/
|
||||
public void generateXML(PageState state, Element parent) {
|
||||
if(isVisible(state)) {
|
||||
Element seg = parent.newChildElement(BEBOP_SEGMENT, BEBOP_XML_NS);
|
||||
exportAttributes(seg);
|
||||
super.generateXML(state, seg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
|
||||
import com.arsdigita.bebop.parameters.IntegerParameter;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/* FIXME: Add methods for using images in the tab strip */
|
||||
|
||||
/**
|
||||
* A tabbed pane that lets the user switch between components by
|
||||
* clicking on a given title in the tab strip.
|
||||
* <p>
|
||||
* Tabs (components) are added using the {@link #addTab addTab} method. Each
|
||||
* entry consists of a label (which is a string) and the {@link Component}
|
||||
* that is displayed if the user clicks on the label.
|
||||
* <p>
|
||||
* There is always exactly one component that is currently visible, the component
|
||||
* that is returned by {@link #getCurrentPane}. Without user interaction,
|
||||
* this is the default pane -- that was set by {@link #setDefaultPane} -- or, if
|
||||
* none has been set, the first component that was added to the <code>TabbedPane</code>.
|
||||
* <p>
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @author Stanislav Freidin
|
||||
* @author Uday Mathur
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TabbedPane extends SimpleContainer {
|
||||
|
||||
private static final String CURRENT_PANE = "pane";
|
||||
/**
|
||||
* The name for the event to change the selected pane.
|
||||
* The value is the index of the pane
|
||||
*/
|
||||
private static final String SELECT_EVENT = "select";
|
||||
|
||||
private Pane m_defaultPane;
|
||||
private IntegerParameter m_currentPaneParam;
|
||||
private List m_actionListeners;
|
||||
|
||||
private static final Logger s_log =
|
||||
Logger.getLogger(TabbedPane.class.getName());
|
||||
|
||||
/**
|
||||
* Constructs an empty TabbedPane.
|
||||
*/
|
||||
public TabbedPane() {
|
||||
m_currentPaneParam = new IntegerParameter(CURRENT_PANE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers with the specified root container. Adds a state
|
||||
* parameter to keep track of the visible component to the page.
|
||||
* @param p the root container to register with
|
||||
* @pre p != null
|
||||
*/
|
||||
public void register(Page p) {
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
p.addComponentStateParam(this, m_currentPaneParam);
|
||||
// if there is no default pane, then set it to the first one
|
||||
// in the list
|
||||
Iterator i = children();
|
||||
if (!i.hasNext()) {
|
||||
s_log.warn("TabbedPane registered with no panes");
|
||||
} else if (m_defaultPane == null) {
|
||||
setDefaultPaneIndex(0);
|
||||
}
|
||||
while (i.hasNext()) {
|
||||
Pane pane = (Pane) i.next();
|
||||
p.setVisibleDefault(pane.getComponent(), pane == m_defaultPane);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new pane to the dialog. Assigns a rather unhelpful default label
|
||||
* (the pane number) to the component. Use {@link #addTab addTab}
|
||||
* instead.
|
||||
*
|
||||
* @pre pc != null
|
||||
*/
|
||||
public void add(Component pc) {
|
||||
addTab(String.valueOf(size()), pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new pane with layout constraints to the dialog. Ignores
|
||||
* the constraints. Assigns a rather unhelpful default label
|
||||
* (the pane number) to the component. Use {@link #addTab
|
||||
* addTab} instead.
|
||||
*
|
||||
* @pre pc != null */
|
||||
public void add(Component pc, int constraints) {
|
||||
add(pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tab and its associated component.
|
||||
* @param label the text to display in the tab strip
|
||||
* @param c the component to display when the user clicks on the
|
||||
* <code>label</code> in the tab strip
|
||||
*
|
||||
* @pre label != null && c != null
|
||||
*/
|
||||
public void addTab(Component label, Component c) {
|
||||
Assert.isUnlocked(this);
|
||||
super.add(new Pane(label, c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tab and its associated component.
|
||||
* @param label the text to display in the tab strip
|
||||
* @param c the component to display when the user clicks on the
|
||||
* <code>label</code> in the tab strip
|
||||
*
|
||||
* @pre label != null && c != null
|
||||
*/
|
||||
public void addTab(String label, Component c) {
|
||||
addTab(new Label(label), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an <code>ActionListener</code>, which is run whenever {@link
|
||||
* #respond respond} is called.
|
||||
* @param 1 the action listener
|
||||
*
|
||||
* @pre l != null
|
||||
* @pre ! isLocked()
|
||||
* @see #respond respond
|
||||
*/
|
||||
public void addActionListener(ActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
if ( m_actionListeners == null ) {
|
||||
m_actionListeners = new ArrayList();
|
||||
}
|
||||
m_actionListeners.add(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a previously added <code>ActionListener</code>.
|
||||
* @param 1 the action listener to remove
|
||||
* @see #addActionListener addActionListener
|
||||
*/
|
||||
public void removeActionListener(ActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
if ( m_actionListeners == null ) {
|
||||
return;
|
||||
}
|
||||
m_actionListeners.remove(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires an <code>ActionEvent</code>. All registered
|
||||
* <code>ActionListener</code>s are run. The source of the event is the
|
||||
* <code>TabbedPane</code>.
|
||||
* @param state the current page state
|
||||
* @pre state != null
|
||||
* @see #respond respond
|
||||
*/
|
||||
protected void fireActionEvent(PageState state) {
|
||||
ActionEvent e = null;
|
||||
if (m_actionListeners == null) {
|
||||
return;
|
||||
}
|
||||
for (Iterator i=m_actionListeners.iterator(); i.hasNext(); ) {
|
||||
if ( e == null ) {
|
||||
e = new ActionEvent(this, state);
|
||||
}
|
||||
((ActionListener) i.next()).actionPerformed(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index of the default pane, which is visible until the user
|
||||
* clicks on another label in the tab strip.
|
||||
* @param i the index of the default pane
|
||||
*/
|
||||
protected void setDefaultPaneIndex(int i) {
|
||||
m_currentPaneParam.setDefaultValue(new Integer(i));
|
||||
m_defaultPane = (Pane)get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default pane, which is visible until the user
|
||||
* clicks on another label in the tab strip.
|
||||
* @param pane the component to display as the default pane
|
||||
*
|
||||
* @pre findPane(pane) != -1
|
||||
*/
|
||||
public void setDefaultPane(Component pane)
|
||||
throws IllegalArgumentException {
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
setDefaultPaneIndex(findPaneSafe(pane));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide a particular tab
|
||||
*
|
||||
* @param s the page state
|
||||
* @param i the index of the tab
|
||||
* @param v if true, shows the tab. Otherwise, hides the tab
|
||||
*/
|
||||
public void setTabVisible(PageState s, int i, boolean v) {
|
||||
get(i).setVisible(s, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide a particular tab
|
||||
*
|
||||
* @param s the page state
|
||||
* @param c the body of the tab
|
||||
* @param v if true, shows the tab. Otherwise, hides the tab
|
||||
*/
|
||||
public void setTabVisible(PageState s, Component c, boolean v) {
|
||||
int i = findPaneSafe(c);
|
||||
setTabVisible(s, i, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a particular tab is visible
|
||||
*
|
||||
* @param s the page state
|
||||
* @param i the index of the tab
|
||||
*/
|
||||
public boolean isTabVisible(PageState s, int i) {
|
||||
return get(i).isVisible(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a particular tab is visible
|
||||
*
|
||||
* @param s the page state
|
||||
* @param c the body of the tab
|
||||
*/
|
||||
public boolean isTabVisible(PageState s, Component c) {
|
||||
int i = findPaneSafe(c);
|
||||
return isTabVisible(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the pane whose body is the specified component
|
||||
* @param c the component
|
||||
* @return the pane index on success, -1 if no such pane exists
|
||||
*/
|
||||
protected int findPane(Component c) {
|
||||
int index = 0;
|
||||
for(Iterator i = children(); i.hasNext(); index++) {
|
||||
Pane p = (Pane)i.next();
|
||||
if(p.getComponent() == c)
|
||||
return index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int findPaneSafe(Component c) {
|
||||
int i = findPane(c);
|
||||
if ( i == -1 ) {
|
||||
throw new IllegalArgumentException
|
||||
("Pane not part of this tabbed dialog");
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the default pane. If no default pane has been set explicitly, the
|
||||
* first pane is returned.
|
||||
*
|
||||
* @return the default pane, or <code>null</code> if there are no
|
||||
* panes.
|
||||
*/
|
||||
public Component getDefaultPane() {
|
||||
return m_defaultPane.getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pane with the specified label.
|
||||
* @return the pane with the specified label, or <code>null</code>
|
||||
* if a pane with that label does not exist.
|
||||
*/
|
||||
public Component getPane(Component label) {
|
||||
for (Iterator i = children(); i.hasNext();) {
|
||||
Pane p = (Pane) i.next();
|
||||
if ( p.getLabel().equals(label) ) {
|
||||
return p.getComponent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pane with the specified key in its label.
|
||||
* Returns null if a pane with that label does not exist.
|
||||
* This function exists for backward compatibility.
|
||||
* @return the pane with the specified label, or <code>null</code>
|
||||
* if a pane with that label does not exist.
|
||||
*/
|
||||
public Component getPane(String label) {
|
||||
|
||||
for (Iterator i = children(); i.hasNext();) {
|
||||
Pane p = (Pane) i.next();
|
||||
Component pLabel = p.getLabel();
|
||||
if (pLabel instanceof Label
|
||||
&& ((Label)pLabel).getLabel().equals(label) ) {
|
||||
return p.getComponent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently visible pane.
|
||||
*
|
||||
* @pre data != null
|
||||
*/
|
||||
public Component getCurrentPane(PageState data) {
|
||||
return getCurrent(data).getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently visible <code>Pane</code>, the tab label together
|
||||
* with its component.
|
||||
*/
|
||||
private Pane getCurrent(PageState data) {
|
||||
Integer i = (Integer) data.getValue(m_currentPaneParam);
|
||||
if (i == null) {
|
||||
if (m_defaultPane!=null) {
|
||||
|
||||
return m_defaultPane;
|
||||
} else {
|
||||
return (Pane)get(0);
|
||||
}
|
||||
}
|
||||
return (Pane)get(i.intValue());
|
||||
}
|
||||
|
||||
public void setSelectedIndex(PageState state, int index) {
|
||||
if ( index != getSelectedIndex(state) ) {
|
||||
getCurrentPane(state).setVisible(state, false);
|
||||
state.setValue(m_currentPaneParam, new Integer(index));
|
||||
getCurrentPane(state).setVisible(state, true);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSelectedIndex(PageState state) {
|
||||
Integer current = (Integer) state.getValue(m_currentPaneParam);
|
||||
if ( current == null ) {
|
||||
return -1;
|
||||
}
|
||||
return current.intValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a DOM representing the header for the tab strip. Marks the current pane.
|
||||
*/
|
||||
protected void generateTabs(PageState data, Element parent) {
|
||||
Element strip = parent.newChildElement("bebop:tabStrip", BEBOP_XML_NS);
|
||||
exportAttributes(strip);
|
||||
|
||||
Pane current = getCurrent(data);
|
||||
strip.addAttribute("selected",current.getComponent().getClass().getName());
|
||||
Iterator tabs;
|
||||
int i;
|
||||
for (tabs = children(), i = 0; tabs.hasNext(); i++) {
|
||||
Pane pane = (Pane)tabs.next();
|
||||
// Skip hidden tabs
|
||||
if(!pane.isVisible(data)) continue;
|
||||
|
||||
data.setControlEvent(this, SELECT_EVENT, String.valueOf(i));
|
||||
|
||||
Element tab = strip.newChildElement("bebop:tab", BEBOP_XML_NS);
|
||||
if (pane == current) {
|
||||
tab.addAttribute("current", "t");
|
||||
} else {
|
||||
try {
|
||||
tab.addAttribute("href", data.stateAsURL());
|
||||
} catch (java.io.IOException ioe) {
|
||||
// stateAsURL failed => this node gets neither href nor current
|
||||
//TODO cat.error("cannot get stateAsURL from "+data);
|
||||
}
|
||||
}
|
||||
String key = ((Label) pane.getLabel()).getGlobalizedMessage().getKey();
|
||||
tab.addAttribute("key", key.substring(key.lastIndexOf(".") + 1));
|
||||
pane.getLabel().generateXML(data, tab);
|
||||
}
|
||||
data.clearControlEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Services the request by building a DOM tree with the tabs
|
||||
* themselves and then the included page.
|
||||
* <p>Generates a DOM fragment:
|
||||
* <p><code><pre>
|
||||
* <bebop:tabbedPane>
|
||||
* <bebop:tabStrip>
|
||||
* <bebop:tab [href="..."] [current="t|f"]> .. label .. </bebop:tab>
|
||||
* <bebop:tab [href="..."] [current="t|f"]> .. label .. </bebop:tab>
|
||||
* <bebop:tab [href="..."] [current="t|f"]> .. label .. </bebop:tab>
|
||||
* </bebop:tabStrip>
|
||||
* <bebop:currentPane>
|
||||
* ... contentes ..
|
||||
* </bebop:currentPane>
|
||||
* </bebop:tabbedPane>
|
||||
* </pre></code>
|
||||
*/
|
||||
public void generateXML(PageState state, Element parent) {
|
||||
if ( isVisible(state) && !isEmpty()) {
|
||||
Element tabbed = parent.newChildElement("bebop:tabbedPane", BEBOP_XML_NS);
|
||||
generateTabs(state, tabbed);
|
||||
exportAttributes(tabbed);
|
||||
|
||||
Element pane = tabbed.newChildElement("bebop:currentPane", BEBOP_XML_NS);
|
||||
exportAttributes(pane);
|
||||
getCurrentPane(state).generateXML(state, pane);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the <code>TabbedPane</code> that one of the tabs has been
|
||||
* selected. Changes the currently visible pane and runs all the {@link
|
||||
* ActionListener ActionListeners}.
|
||||
* <p>
|
||||
* The <code>respond</code> method on the now-visible component is
|
||||
* <em>not</em> called.
|
||||
*
|
||||
* @pre state != null
|
||||
*/
|
||||
public void respond(PageState state)
|
||||
throws ServletException
|
||||
{
|
||||
String event = state.getControlEventName();
|
||||
|
||||
if ( SELECT_EVENT.equals(event)) {
|
||||
String value = state.getControlEventValue();
|
||||
setSelectedIndex(state, Integer.parseInt(value));
|
||||
} else {
|
||||
throw new ServletException("Received unknown control event " + event);
|
||||
}
|
||||
fireActionEvent(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a label with the component
|
||||
*/
|
||||
private class Pane extends SimpleContainer {
|
||||
private Component m_label;
|
||||
private Component m_component;
|
||||
|
||||
public Pane(Component label, Component c) {
|
||||
m_label = label;
|
||||
super.add(label);
|
||||
m_component = c;
|
||||
super.add(c);
|
||||
}
|
||||
|
||||
public final Component getLabel() {
|
||||
return m_label;
|
||||
}
|
||||
|
||||
public final Component getComponent() {
|
||||
return m_component;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,896 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
|
||||
import com.arsdigita.bebop.event.EventListenerList;
|
||||
import com.arsdigita.bebop.event.TableActionAdapter;
|
||||
import com.arsdigita.bebop.event.TableActionEvent;
|
||||
import com.arsdigita.bebop.event.TableActionListener;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
|
||||
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
|
||||
import com.arsdigita.bebop.table.DefaultTableColumnModel;
|
||||
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||
import com.arsdigita.bebop.table.TableColumn;
|
||||
import com.arsdigita.bebop.table.TableColumnModel;
|
||||
import com.arsdigita.bebop.table.TableHeader;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.bebop.table.TableModelBuilder;
|
||||
|
||||
import static com.arsdigita.bebop.util.BebopConstants.*;
|
||||
|
||||
import com.arsdigita.bebop.util.BebopConstants;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Displays statically or dynamically generated data in tabular form.
|
||||
* The data is retrieved from a <code>TableModel</code>.
|
||||
*
|
||||
* <p>
|
||||
* This class is similar to the {@link List} class, but it has two dimensions.
|
||||
* The table consists of a {@link TableModelBuilder}, a {@link TableColumnModel},
|
||||
* a {@link TableHeader} and a {@link TableCellRenderer} for each column.
|
||||
* <p>
|
||||
*
|
||||
* A table that represents a static matrix can be created fairly quickly:
|
||||
* <blockquote><pre><code> String[][] data = {
|
||||
* {"Stas", "Freidin"},
|
||||
* {"David", "Lutterkort"}
|
||||
* };
|
||||
*
|
||||
* String[] headers = {"First Name", "Last Name"};
|
||||
*
|
||||
* Table myTable = new Table(data, headers);</code></pre></blockquote>
|
||||
* <p>
|
||||
*
|
||||
* However, tables are most often used to represent database queries, not static
|
||||
* data. For these tables, the {@link TableModelBuilder} class should be used
|
||||
* to supply the <code>Table</code> class with data.
|
||||
* The {@link TableModelBuilder} class will execute the database query and
|
||||
* return a {@link TableModel}, which wraps the query.
|
||||
* <p>
|
||||
*
|
||||
* The content in the cells is rendered by the {@link TableCellRenderer} that
|
||||
* is set for the {@link TableColumn} to which the cell belongs.
|
||||
*
|
||||
* If the <code>TableCellRenderer</code> has not been set, the
|
||||
* <code>TableCellRenderer</code> for the <code>Table</code> is used.
|
||||
* By default, the <code>Table</code> class uses an inactive instance of the
|
||||
* {@link DefaultTableCellRenderer} (cell content is displayed as {@link Label}s).
|
||||
* However, if an active <code>DefaultTableCellRenderer</code> is used, the
|
||||
* cells in the table appear as links. When the user clicks a link, the
|
||||
* <code>Table</code>'s action listeners will be fired.
|
||||
*
|
||||
* <P>
|
||||
* The currently selected cell is represented by two {@link SingleSelectionModel}s -
|
||||
* one model for the row and one model for the column. Typically, the selected
|
||||
* row is identified by a string key and the selected column is identified by
|
||||
* an integer.
|
||||
*
|
||||
* @see TableModel
|
||||
* @see TableColumnModel
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Table extends SimpleComponent {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Table.class);
|
||||
// Names for HTML Attributes
|
||||
private static final String WIDTH = "width";
|
||||
private static final String CELL_SPACING = "cellspacing";
|
||||
private static final String CELL_PADDING = "cellpadding";
|
||||
private static final String BORDER = "border";
|
||||
private static final String SELECTED_ROW = "row";
|
||||
/**
|
||||
* The control event when the user selects one table cell.
|
||||
* This control event will only be used when
|
||||
*/
|
||||
protected static final String CELL_EVENT = "cell";
|
||||
protected static final char SEP = ' ';
|
||||
private TableModelBuilder m_modelBuilder;
|
||||
private TableColumnModel m_columnModel;
|
||||
private TableHeader m_header;
|
||||
private RequestLocal m_tableModel;
|
||||
private SingleSelectionModel m_rowSelectionModel;
|
||||
/**
|
||||
* A listener to forward headSelected events originating from the
|
||||
* TableHeader. This will be null until somebody actually registers a
|
||||
* TableActionListener from the outside.
|
||||
*/
|
||||
private TableActionListener m_headerForward;
|
||||
private EventListenerList m_listeners;
|
||||
private TableCellRenderer m_defaultCellRenderer;
|
||||
private Component m_emptyView;
|
||||
private boolean m_striped = false;
|
||||
|
||||
/**
|
||||
* Constructs a new, empty table.
|
||||
*/
|
||||
public Table() {
|
||||
this(new Object[0][0], new Object[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a static table with the specified column headers,
|
||||
* and pre-fills it with data.
|
||||
*
|
||||
* @param data a matrix of objects that will serve as static data
|
||||
* for the table cells
|
||||
*
|
||||
* @param headers an array of string labels for the table headers
|
||||
*/
|
||||
public Table(Object[][] data, Object[] headers) {
|
||||
this(new MatrixTableModelBuilder(data), headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a table using a {@link TableModelBuilder}. The table
|
||||
* data will be generated dynamically during each request.
|
||||
*
|
||||
* @param b the {@link TableModelBuilder} that is responsible for
|
||||
* instantiating a {@link TableModel} during each request
|
||||
*
|
||||
* @param headers an array of string labels for the table headers
|
||||
*/
|
||||
public Table(TableModelBuilder b, Object[] headers) {
|
||||
this(b, new DefaultTableColumnModel(headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a table using a {@link TableModelBuilder}. The table
|
||||
* data will be generated dynamically during each request. The
|
||||
* table's columns and headers will be provided by a
|
||||
* {@link TableColumnModel}.
|
||||
*
|
||||
* @param b the {@link TableModelBuilder} that is responsible for
|
||||
* instantiating a {@link TableModel} during each request
|
||||
*
|
||||
* @param c the {@link TableColumnModel} that will maintain the
|
||||
* columns and headers for this table
|
||||
*/
|
||||
public Table(TableModelBuilder b, TableColumnModel c) {
|
||||
super();
|
||||
m_modelBuilder = b;
|
||||
m_columnModel = c;
|
||||
setHeader(new TableHeader(m_columnModel));
|
||||
m_rowSelectionModel =
|
||||
new ParameterSingleSelectionModel(new StringParameter(SELECTED_ROW));
|
||||
m_listeners = new EventListenerList();
|
||||
m_defaultCellRenderer = new DefaultTableCellRenderer();
|
||||
initTableModel();
|
||||
}
|
||||
|
||||
// Events and listeners
|
||||
|
||||
/**
|
||||
* Adds a {@link TableActionListener} to the table. The listener is
|
||||
* fired whenever a table cell is clicked.
|
||||
*
|
||||
* @param l the {@link TableActionListener} to be added
|
||||
*/
|
||||
public void addTableActionListener(TableActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
if (m_headerForward == null) {
|
||||
m_headerForward = createTableActionListener();
|
||||
if (m_header != null) {
|
||||
m_header.addTableActionListener(m_headerForward);
|
||||
}
|
||||
}
|
||||
m_listeners.add(TableActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a {@link TableActionListener} from the table.
|
||||
*
|
||||
* @param l the {@link TableActionListener} to be removed
|
||||
*/
|
||||
public void removeTableActionListener(TableActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.remove(TableActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires event listeners to indicate that a new cell has been
|
||||
* selected in the table.
|
||||
*
|
||||
* @param state the page state
|
||||
* @param rowKey the key that identifies the selected row
|
||||
* @param column the integer index of the selected column
|
||||
*/
|
||||
protected void fireCellSelected(PageState state,
|
||||
Object rowKey, Integer column) {
|
||||
Iterator i = m_listeners.getListenerIterator(TableActionListener.class);
|
||||
TableActionEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if (e == null) {
|
||||
e = new TableActionEvent(this, state, rowKey, column);
|
||||
}
|
||||
((TableActionListener) i.next()).cellSelected(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires event listeners to indicate that a new header cell has been
|
||||
* selected in the table.
|
||||
*
|
||||
* @param state the page state
|
||||
* @param rowKey the key that identifies the selected row
|
||||
* @param column the integer index of the selected column
|
||||
*/
|
||||
protected void fireHeadSelected(PageState state,
|
||||
Object rowKey, Integer column) {
|
||||
Iterator i = m_listeners.getListenerIterator(TableActionListener.class);
|
||||
TableActionEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if (e == null) {
|
||||
e = new TableActionEvent(this, state, rowKey, column);
|
||||
}
|
||||
((TableActionListener) i.next()).headSelected(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link TableActionListener} for this table.
|
||||
*
|
||||
* @return a new {@link TableActionListener} that should be used
|
||||
* only for this table.
|
||||
*
|
||||
*/
|
||||
protected TableActionListener createTableActionListener() {
|
||||
return new TableActionAdapter() {
|
||||
@Override
|
||||
public void headSelected(TableActionEvent e) {
|
||||
fireHeadSelected(e.getPageState(), e.getRowKey(), e.getColumn());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TableColumnModel} for this table.
|
||||
*/
|
||||
public final TableColumnModel getColumnModel() {
|
||||
return m_columnModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new {@link TableColumnModel} for the table.
|
||||
*
|
||||
* @param v the new {@link TableColumnModel}
|
||||
*/
|
||||
public void setColumnModel(TableColumnModel v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_columnModel = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TableModelBuilder} for this table.
|
||||
*/
|
||||
public final TableModelBuilder getModelBuilder() {
|
||||
return m_modelBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new {@link TableModelBuilder} for the table.
|
||||
*
|
||||
* @param v the new {@link TableModelBuilder}
|
||||
*/
|
||||
public void setModelBuilder(TableModelBuilder v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_modelBuilder = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TableHeader} for this table. Could return null
|
||||
* if the header is hidden.
|
||||
*/
|
||||
public final TableHeader getHeader() {
|
||||
return m_header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new header for this table.
|
||||
*
|
||||
* @param v the new header for this table. If null, the header will be
|
||||
* hidden.
|
||||
*/
|
||||
public void setHeader(TableHeader v) {
|
||||
Assert.isUnlocked(this);
|
||||
if (m_headerForward != null) {
|
||||
if (m_header != null) {
|
||||
m_header.removeTableActionListener(m_headerForward);
|
||||
}
|
||||
if (v != null) {
|
||||
v.addTableActionListener(m_headerForward);
|
||||
}
|
||||
}
|
||||
m_header = v;
|
||||
if (m_header != null) {
|
||||
m_header.setTable(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i the numerical index of the column
|
||||
* @return the {@link TableColumn} whose index is i.
|
||||
*/
|
||||
public TableColumn getColumn(int i) {
|
||||
return getColumnModel().get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the colulumn at a new numerical index. This method
|
||||
* is normally used to rearrange the order of the columns in the
|
||||
* table.
|
||||
*
|
||||
* @param i the numerical index of the column
|
||||
* @param v the column that is to be mapped at i
|
||||
*/
|
||||
public void setColumn(int i, TableColumn v) {
|
||||
getColumnModel().set(i, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SingleSelectionModel} that is responsible
|
||||
* for selecting the current row.
|
||||
*/
|
||||
public final SingleSelectionModel getRowSelectionModel() {
|
||||
return m_rowSelectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link SingleSelectionModel} that will be responsible
|
||||
* for selecting the current row.
|
||||
*
|
||||
* @param v a {@link SingleSelectionModel}
|
||||
*/
|
||||
public void setRowSelectionModel(SingleSelectionModel v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_rowSelectionModel = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SingleSelectionModel} that is responsible
|
||||
* for selecting the current column.
|
||||
*/
|
||||
public SingleSelectionModel getColumnSelectionModel() {
|
||||
return (getColumnModel() == null) ? null : getColumnModel().
|
||||
getSelectionModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link SingleSelectionModel} that will be responsible
|
||||
* for selecting the current column.
|
||||
*
|
||||
* @param v a {@link SingleSelectionModel}
|
||||
*/
|
||||
public void setColumnSelectionModel(SingleSelectionModel v) {
|
||||
Assert.isUnlocked(this);
|
||||
// TODO: make sure table gets notified of changes
|
||||
getColumnModel().setSelectionModel(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the row and column selection models that the table holds.
|
||||
*
|
||||
* @param s represents the state of the current request
|
||||
* @post ! getRowSelectionModel().isSelected(s)
|
||||
* @post ! getColumnSelectionModel().isSelected(s)
|
||||
*/
|
||||
public void clearSelection(PageState s) {
|
||||
getRowSelectionModel().clearSelection(s);
|
||||
getColumnSelectionModel().clearSelection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default {@link TableCellRenderer}.
|
||||
*/
|
||||
public final TableCellRenderer getDefaultCellRenderer() {
|
||||
return m_defaultCellRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the default cell renderer. This renderer will
|
||||
* be used to render columns that do not specify their own
|
||||
* {@link TableCellRenderer}.
|
||||
*
|
||||
* @param v the default {@link TableCellRenderer}
|
||||
*/
|
||||
public final void setDefaultCellRenderer(TableCellRenderer v) {
|
||||
m_defaultCellRenderer = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the component that will be shown if the table is
|
||||
* empty.
|
||||
*/
|
||||
public final Component getEmptyView() {
|
||||
return m_emptyView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the empty view. The empty view is the component that
|
||||
* is shown if the table is empty. Usually, the component
|
||||
* will be a simple label, such as <code>new Label("The table is empty")</code>.
|
||||
*
|
||||
* @param v a Bebop component
|
||||
*/
|
||||
public final void setEmptyView(Component v) {
|
||||
m_emptyView = v;
|
||||
}
|
||||
|
||||
// Set HTML table attributes
|
||||
/**
|
||||
*
|
||||
* @return the HTML width of the table.
|
||||
*/
|
||||
public String getWidth() {
|
||||
return getAttribute(WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v the HTML width of the table
|
||||
*/
|
||||
public void setWidth(String v) {
|
||||
setAttribute(WIDTH, v);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the HTML border of the table.
|
||||
*/
|
||||
public String getBorder() {
|
||||
return getAttribute(BORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v the HTML border of the table
|
||||
*/
|
||||
public void setBorder(String v) {
|
||||
setAttribute(BORDER, v);
|
||||
}
|
||||
|
||||
public String getCellSpacing() {
|
||||
return getAttribute(CELL_SPACING);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v the HTML width of the table
|
||||
*/
|
||||
public void setCellSpacing(String v) {
|
||||
setAttribute(CELL_SPACING, v);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the HTML cell spacing of the table.
|
||||
*/
|
||||
public String getCellPadding() {
|
||||
return getAttribute(CELL_PADDING);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param v the HTML cell padding of the table
|
||||
*/
|
||||
public void setCellPadding(String v) {
|
||||
setAttribute(CELL_PADDING, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the events for this table. This method will automatically
|
||||
* handle all user input to the table.
|
||||
*
|
||||
* @param s the page state
|
||||
* @throws javax.servlet.ServletException
|
||||
*/
|
||||
@Override
|
||||
public void respond(PageState s) throws ServletException {
|
||||
String event = s.getControlEventName();
|
||||
String rowKey = null;
|
||||
Integer column = null;
|
||||
|
||||
if (CELL_EVENT.equals(event)) {
|
||||
String value = s.getControlEventValue();
|
||||
SingleSelectionModel rowSel = getRowSelectionModel();
|
||||
SingleSelectionModel colSel = getColumnSelectionModel();
|
||||
int split = value.indexOf(SEP);
|
||||
rowKey = value.substring(0, split);
|
||||
column = new Integer(value.substring(split + 1));
|
||||
colSel.setSelectedKey(s, column);
|
||||
rowSel.setSelectedKey(s, rowKey);
|
||||
fireCellSelected(s, rowKey, column);
|
||||
} else {
|
||||
throw new ServletException("Unknown event '" + event + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the table with the containing page. The table will add the
|
||||
* state parameters of the row and column selection models, if they use
|
||||
* them, thus making the selection persist between requests.
|
||||
*
|
||||
* @param p the page that contains this table
|
||||
*/
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
ParameterModel m = getRowSelectionModel() == null ? null
|
||||
: getRowSelectionModel().getStateParameter();
|
||||
if (m != null) {
|
||||
p.addComponentStateParam(this, m);
|
||||
}
|
||||
m = getColumnSelectionModel() == null ? null : getColumnSelectionModel().
|
||||
getStateParameter();
|
||||
if (m != null) {
|
||||
p.addComponentStateParam(this, m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the header and all the columns. If the table
|
||||
* has no header, the iterator lists only the columns.
|
||||
*
|
||||
* @return an iterator over Bebop components.
|
||||
*/
|
||||
@Override
|
||||
public Iterator children() {
|
||||
return new Iterator() {
|
||||
|
||||
int pos = (getHeader() == null) ? -1 : -2;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return pos < getColumnModel().size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object next() {
|
||||
pos += 1;
|
||||
if (pos == -1) {
|
||||
return getHeader();
|
||||
} else {
|
||||
return getColumn(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("Read-only iterator.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a row is seleted.
|
||||
*
|
||||
* @param s the page state
|
||||
* @param rowKey the key that identifies the row
|
||||
* @return <code>true</code> if the row is currently selected;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isSelectedRow(PageState s, Object rowKey) {
|
||||
if (rowKey == null || getRowSelectionModel() == null) {
|
||||
return false;
|
||||
}
|
||||
return getRowSelectionModel().isSelected(s)
|
||||
&& rowKey.toString().equals(
|
||||
getRowSelectionModel().getSelectedKey(s).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a column is selected.
|
||||
*
|
||||
* @param s the page state
|
||||
* @param column a key that identifes the column. Should be consistent
|
||||
* with the type used by the column selection model.
|
||||
* @return <code>true</code> if the column is selected;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isSelectedColumn(PageState s, Object column) {
|
||||
if (column == null || getColumnSelectionModel() == null) {
|
||||
return false;
|
||||
}
|
||||
return getColumnSelectionModel().isSelected(s)
|
||||
&& column.toString().equals(
|
||||
getColumnSelectionModel().getSelectedKey(s).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the cell addressed by the specified row key and
|
||||
* column number is selected in the request represented by the page
|
||||
* state.
|
||||
*
|
||||
* @param s represents the state of the page in the current request
|
||||
* @param rowKey the row key of the cell. The concrete type should agree
|
||||
* with the type used by the row selection model.
|
||||
* @param column the column of the cell. The concrete type should agree
|
||||
* with the type used by the column selection model.
|
||||
* @return <code>true</code> if the cell is selected;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isSelectedCell(PageState s, Object rowKey, Object column) {
|
||||
return isSelectedRow(s, rowKey) && isSelectedColumn(s, column);
|
||||
}
|
||||
|
||||
public void setStriped(boolean striped) {
|
||||
m_striped = striped;
|
||||
}
|
||||
|
||||
public boolean getStriped() {
|
||||
return m_striped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds type-specific XML attributes to the XML element representing
|
||||
* this link. Subclasses should override this method if they introduce
|
||||
* more attributes than the ones {@link #generateXML generateXML}
|
||||
* produces by default.
|
||||
*
|
||||
* @param state represents the current request
|
||||
* @param element the XML element representing this table
|
||||
*/
|
||||
protected void generateExtraXMLAttributes(PageState state,
|
||||
Element element) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the XML representing the table. Gets a new {@link TableModel}
|
||||
* from the {@link TableModelBuilder} and iterates over the model's
|
||||
* rows. The value in each table cell is rendered with the help of the
|
||||
* column's table cell renderer.
|
||||
*
|
||||
* <p> Generates an XML fragment:
|
||||
* <pre>
|
||||
* <bebop:table>
|
||||
* <bebop:thead>
|
||||
* <bebpp:cell>...</cell> ...
|
||||
* </bebop:thead>
|
||||
* <bebop:tbody>
|
||||
* <bebop:trow>
|
||||
* <bebpp:cell>...</cell> ...
|
||||
* </bebop:trow>
|
||||
* ...
|
||||
* </bebop:tbody>
|
||||
* </bebop:table>
|
||||
*
|
||||
* @param s the page state
|
||||
* @param p the parent {@link Element}
|
||||
*/
|
||||
@Override
|
||||
public void generateXML(PageState s, Element p) {
|
||||
TableModel model = getTableModel(s);
|
||||
|
||||
|
||||
final boolean tableIsRegisteredWithPage =
|
||||
s.getPage().stateContains(getControler());
|
||||
|
||||
if (model.nextRow()) {
|
||||
Element table = p.newChildElement(BEBOP_TABLE, BEBOP_XML_NS);
|
||||
exportAttributes(table);
|
||||
generateExtraXMLAttributes(s, table);
|
||||
if (getHeader() != null) {
|
||||
getHeader().generateXML(s, table);
|
||||
}
|
||||
Element tbody = table.newChildElement(BEBOP_TABLEBODY, BEBOP_XML_NS);
|
||||
if (m_striped) {
|
||||
tbody.addAttribute("striped", "true");
|
||||
}
|
||||
|
||||
final int modelSize = getColumnModel().size();
|
||||
int row = 0;
|
||||
|
||||
logger.debug("Creating table rows...");
|
||||
long start = System.currentTimeMillis();
|
||||
do {
|
||||
long rowStart = System.currentTimeMillis();
|
||||
Element trow = tbody.newChildElement(BEBOP_TABLEROW,
|
||||
BEBOP_XML_NS);
|
||||
|
||||
for (int i = 0; i < modelSize; i++) {
|
||||
|
||||
TableColumn tc = getColumn(i);
|
||||
if (tc.isVisible(s)) {
|
||||
TableCellRenderer r = tc.getCellRenderer();
|
||||
if (r == null) {
|
||||
r = m_defaultCellRenderer;
|
||||
}
|
||||
final int modelIndex = tc.getModelIndex();
|
||||
Object key = model.getKeyAt(modelIndex);
|
||||
Object value = model.getElementAt(modelIndex);
|
||||
boolean selected =
|
||||
isSelectedCell(s, key, new Integer(i));
|
||||
if (tableIsRegisteredWithPage) {
|
||||
/*StringBuffer coords = new StringBuffer(40);
|
||||
coords.append(model.getKeyAt(modelIndex)).append(SEP).
|
||||
append(i);
|
||||
s.setControlEvent(getControler(), CELL_EVENT,
|
||||
coords.toString());*/
|
||||
|
||||
s.setControlEvent(getControler(),
|
||||
CELL_EVENT,
|
||||
String.format("%s%s%d",
|
||||
model.getKeyAt(
|
||||
modelIndex),
|
||||
SEP,
|
||||
i));
|
||||
}
|
||||
|
||||
Element cell = trow.newChildElement(BEBOP_CELL,
|
||||
BEBOP_XML_NS);
|
||||
|
||||
tc.exportCellAttributes(cell);
|
||||
long begin = System.currentTimeMillis();
|
||||
r.getComponent(this, s, value, selected, key, row, i).
|
||||
generateXML(s, cell);
|
||||
logger.debug(String.format("until here i needed %d ms",
|
||||
System.currentTimeMillis()
|
||||
- begin));
|
||||
}
|
||||
}
|
||||
row += 1;
|
||||
logger.debug(
|
||||
String.format("Created row in %d ms",
|
||||
System.currentTimeMillis() - rowStart));
|
||||
} while (model.nextRow());
|
||||
logger.debug(String.format("Build table rows in %d ms",
|
||||
System.currentTimeMillis() - start));
|
||||
} else if (m_emptyView != null) {
|
||||
m_emptyView.generateXML(s, p);
|
||||
}
|
||||
if (tableIsRegisteredWithPage) {
|
||||
s.clearControlEvent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Component getControler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table model in effect for the request represented by the
|
||||
* page state.
|
||||
*
|
||||
* @param s represents the state of the page in the current request
|
||||
* @return the table model used for outputting the table.
|
||||
*/
|
||||
public TableModel getTableModel(PageState s) {
|
||||
return (TableModel) m_tableModel.get(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the request local <code>m_tableModel</code> field so that
|
||||
* it is initialized with whatever model the table model builder returns
|
||||
* for the request.
|
||||
*/
|
||||
private void initTableModel() {
|
||||
m_tableModel = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(PageState s) {
|
||||
return m_modelBuilder.makeModel(Table.this, s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the table against further modifications. This also locks all
|
||||
* the associated objects: the model builder, the column model, and the
|
||||
* header components.
|
||||
* @see com.arsdigita.util.Lockable#lock
|
||||
*/
|
||||
@Override
|
||||
public void lock() {
|
||||
getModelBuilder().lock();
|
||||
getColumnModel().lock();
|
||||
if (getHeader() != null) {
|
||||
getHeader().lock();
|
||||
}
|
||||
super.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal class that creates a table model around a set of data given
|
||||
* as a <code>Object[][]</code>. The table models produced by this builder
|
||||
* use row numbers, converted to strings, as the key for each column of a
|
||||
* row.
|
||||
*/
|
||||
public static class MatrixTableModelBuilder
|
||||
extends AbstractTableModelBuilder {
|
||||
|
||||
private final Object[][] m_data;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
public MatrixTableModelBuilder(Object[][] data) {
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableModel makeModel(Table t, PageState s) {
|
||||
return new TableModel() {
|
||||
|
||||
private int row = -1;
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return m_data[0].length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
return (++row < m_data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int j) {
|
||||
return m_data[row][j];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyAt(int j) {
|
||||
return String.valueOf(row);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link TableModel} that has no rows.
|
||||
*/
|
||||
public static final TableModel EMPTY_MODEL = new TableModel() {
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyAt(int column) {
|
||||
throw new IllegalStateException("TableModel is empty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int column) {
|
||||
throw new IllegalStateException("TableModel is empty");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,762 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ChangeEvent;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
import com.arsdigita.bebop.event.EventListenerList;
|
||||
import com.arsdigita.bebop.event.TreeExpansionEvent;
|
||||
import com.arsdigita.bebop.event.TreeExpansionListener;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.tree.DefaultTreeCellRenderer;
|
||||
import com.arsdigita.bebop.tree.TreeCellRenderer;
|
||||
import com.arsdigita.bebop.tree.TreeModel;
|
||||
import com.arsdigita.bebop.tree.TreeModelBuilder;
|
||||
import com.arsdigita.bebop.tree.TreeNode;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Used to print a tree structure. Nodes can be in expanded or
|
||||
* collapsed state. <code>Tree</code> uses the getChildren() and
|
||||
* getRoot() methods from TreeModel and traverses the iterator to get
|
||||
* to all the nodes.
|
||||
*
|
||||
* This class keeps track of which nodes are expanded and collapsed
|
||||
* and the hierarchy of nodes, and displays the tree correspondingly.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @author Stanislav Freidin
|
||||
* @author Tri Tran
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Tree extends SimpleComponent implements Resettable {
|
||||
|
||||
private static final Logger s_log =
|
||||
Logger.getLogger(Tree.class);
|
||||
|
||||
private static final boolean s_selectAttributeEnabled =
|
||||
Bebop.getConfig().treeSelectAttributeEnabled();
|
||||
|
||||
// Any node id in the currentState is equivalent
|
||||
// to that node being expanded. If node id is
|
||||
// NOT in the currentState, then it's collapsed.
|
||||
private static final String CURRENT_STATE = "state";
|
||||
private static final String EXPAND_EVENT = "expand";
|
||||
private static final String COLLAPSE_EVENT = "collapse";
|
||||
private static final String SELECT = "sel";
|
||||
private static final String SELECT_EVENT = "s";
|
||||
|
||||
private static final boolean EXPANDED = true;
|
||||
private static final boolean NOT_EXPANDED = false; // Collapsed
|
||||
private static final boolean LEAF = true;
|
||||
private static final boolean NOT_LEAF = false;
|
||||
|
||||
protected StringParameter m_currentState;
|
||||
|
||||
protected TreeModelBuilder m_builder;
|
||||
private RequestLocal m_model;
|
||||
private TreeModel m_tree;
|
||||
|
||||
private EventListenerList m_listeners;
|
||||
|
||||
private SingleSelectionModel m_selection;
|
||||
|
||||
private ChangeListener m_changeListener;
|
||||
|
||||
private Element treeElement;
|
||||
|
||||
private TreeCellRenderer m_renderer;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>Tree</code> using the specified
|
||||
* {@link TreeModelBuilder}. The {@link TreeModelBuilder} will
|
||||
* instantiate a {@link TreeModel} during each request.
|
||||
*
|
||||
* @param b the {@link TreeModelBuilder}
|
||||
*/
|
||||
public Tree(TreeModelBuilder b) {
|
||||
super();
|
||||
m_currentState = new StringParameter(CURRENT_STATE);
|
||||
m_builder = b;
|
||||
m_renderer = new DefaultTreeCellRenderer();
|
||||
m_selection = new ParameterSingleSelectionModel(new StringParameter(SELECT));
|
||||
m_listeners = new EventListenerList();
|
||||
|
||||
m_model = new RequestLocal() {
|
||||
protected Object initialValue(PageState s) {
|
||||
return getModelBuilder().makeModel(Tree.this, s);
|
||||
}
|
||||
};
|
||||
|
||||
m_tree = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated constructor that takes a default {@link TreeModel}
|
||||
* and wraps it in a dummy TreeModelBuilder.
|
||||
*
|
||||
* @param t the TreeModel
|
||||
* @deprecated This constructor has been deprecated in favor of
|
||||
* <code>Tree(TreeModelBuilder b)</code>. It is not practical
|
||||
* to hardwire the <code>TreeModel</code> into the <code>Tree</code>,
|
||||
* since the model may change during each request. It is possible
|
||||
* to write the model-instantiation code in
|
||||
* {@link TreeModel#getRoot(PageState)}, but the
|
||||
* {@link TreeModelBuilder} fits better into the pattern which has
|
||||
* already been established by {@link List} and {@link Table}
|
||||
*/
|
||||
public Tree(TreeModel t) {
|
||||
this(new WrapperModelBuilder());
|
||||
m_tree = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the two parameters to the page.
|
||||
*/
|
||||
public void register(Page p) {
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
p.addComponent(this);
|
||||
p.addComponentStateParam(this, m_currentState);
|
||||
p.addComponentStateParam(this, getSelectionModel().getStateParameter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the request state of the tree.
|
||||
*/
|
||||
public void reset(final PageState state) {
|
||||
clearSelection(state);
|
||||
clearExpansionState(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tree model used for this tree.
|
||||
*
|
||||
* @return a <code>TreeModel</code>.
|
||||
* @see #setTreeModel setTreeModel
|
||||
* @see TreeModel
|
||||
* @deprecated Use {@link #getTreeModel(PageState)} instead
|
||||
*/
|
||||
public final TreeModel getTreeModel() {
|
||||
return m_tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TreeModel} used by the tree for the current
|
||||
* request.
|
||||
*
|
||||
* @param s the page state
|
||||
*/
|
||||
public TreeModel getTreeModel(PageState s) {
|
||||
return (TreeModel)m_model.get(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TreeModelBuilder} used to build the tree model
|
||||
* for this tree.
|
||||
*/
|
||||
public final TreeModelBuilder getModelBuilder() {
|
||||
return m_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param b the new {@link TreeModelBuilder} for the tree
|
||||
*/
|
||||
public void setModelBuilder(TreeModelBuilder b) {
|
||||
Assert.isUnlocked(this);
|
||||
m_builder = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tree model used for this tree.
|
||||
*
|
||||
* @return a <code>TreeModel</code>.
|
||||
* @see #setTreeModel setTreeModel
|
||||
* @see TreeModel
|
||||
*/
|
||||
public void setTreeModel(TreeModel m) {
|
||||
Assert.isUnlocked(this);
|
||||
m_tree = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection model, which keeps track of which node is
|
||||
* currently selected. It can be used to manipulate the selection
|
||||
* programmatically.
|
||||
*
|
||||
* @param m the new selection model
|
||||
*/
|
||||
public void setSelectionModel(SingleSelectionModel m) {
|
||||
Assert.isUnlocked(this);
|
||||
m_selection = m;
|
||||
s_log.debug("New model: " + m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selection model, which keeps track of which node is
|
||||
* currently selected. It can be used to manipulate the selection
|
||||
* programmatically.
|
||||
*
|
||||
* @return the model used by the tree to keep track of the selected node.
|
||||
*/
|
||||
public final SingleSelectionModel getSelectionModel() {
|
||||
return m_selection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key for the selected node. This will only be a valid key
|
||||
* if {@link #isSelected isSelected} is <code>true</code>.
|
||||
*
|
||||
* @param state represents the state of the current request
|
||||
* @return the key for the selected node.
|
||||
* @pre isSelected(state)
|
||||
*/
|
||||
public Object getSelectedKey(PageState state) {
|
||||
return m_selection.getSelectedKey(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection to the one with the specified key. If
|
||||
* <code>key</code> was not selected already, fires the {@link
|
||||
* ChangeEvent}.
|
||||
*
|
||||
* @param state represents the state of the current request
|
||||
* @param key the key for the selected node
|
||||
* @see #fireStateChanged fireStateChanged
|
||||
*/
|
||||
public void setSelectedKey(PageState state, Object key) {
|
||||
m_selection.setSelectedKey(state, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if one of the nodes is currently selected.
|
||||
*
|
||||
* @param state represents the state of the current request
|
||||
* @return <code>true</code> if one of the nodes is selected;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isSelected(PageState state) {
|
||||
return m_selection.isSelected(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the selection in the request represented by <code>state</code>.
|
||||
*
|
||||
* @param state represents the state of the current request
|
||||
* @post ! isSelected(state)
|
||||
*/
|
||||
public void clearSelection(PageState state) {
|
||||
m_selection.clearSelection(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the tree has state on the request for tree node
|
||||
* expansion.
|
||||
*/
|
||||
public final boolean hasExpansionState(final PageState state) {
|
||||
return state.getValue(m_currentState) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any tree node expansion state on the request.
|
||||
*/
|
||||
public final void clearExpansionState(final PageState state) {
|
||||
state.setValue(m_currentState, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the change listener used for forwarding change events fired by
|
||||
* the selection model to change listeners registered with the tree. The
|
||||
* returned change listener refires the event with the tree,
|
||||
* rather than the selection model, as source.
|
||||
*
|
||||
* @return the change listener used internally by the tree.
|
||||
*/
|
||||
protected ChangeListener createChangeListener() {
|
||||
return new ChangeListener() {
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
fireStateChanged(e.getPageState());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a change listener. A change event is fired whenever the selected
|
||||
* tree node changes during the processing of a request. The change event
|
||||
* that listeners receive names the tree as the source.
|
||||
*
|
||||
* @param l the change listener to run when the selected item changes in
|
||||
* a request
|
||||
* @pre ! isLocked()
|
||||
*/
|
||||
public void addChangeListener(ChangeListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
if ( m_changeListener == null ) {
|
||||
m_changeListener = createChangeListener();
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Adding listener " + l + " to " + this);
|
||||
}
|
||||
|
||||
m_selection.addChangeListener(m_changeListener);
|
||||
}
|
||||
m_listeners.add(ChangeListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a change listener. The listener should have been previously
|
||||
* added with {@link #addChangeListener addChangeListener}, although no
|
||||
* error is signalled if the change listener is not found among the
|
||||
* tree's listeners.
|
||||
*
|
||||
* @param l the change listener to remove from the tree
|
||||
*/
|
||||
public void removeChangeListener(ChangeListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Removing listener " + l + " from " + this);
|
||||
}
|
||||
|
||||
m_listeners.remove(ChangeListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a change event to signal that the selected list item has changed
|
||||
* in the request represented by <code>state</code>. The source of the
|
||||
* event is the tree.
|
||||
*
|
||||
* @param state represents the state of the current request
|
||||
*/
|
||||
protected void fireStateChanged(PageState state) {
|
||||
Iterator
|
||||
i=m_listeners.getListenerIterator(ChangeListener.class);
|
||||
ChangeEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if ( e == null ) {
|
||||
e = new ChangeEvent(this, state);
|
||||
}
|
||||
((ChangeListener) i.next()).stateChanged(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener that is notified whenever a user clicks on any part
|
||||
* of the tree, either to expand or collapse a node, or to select a
|
||||
* node. The listener is run whenever {@link #respond respond} is
|
||||
* called.
|
||||
*
|
||||
* @pre l != null
|
||||
* @pre ! isLocked()
|
||||
*/
|
||||
public void addActionListener(ActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.add(ActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a previously added <code>ActionListener</code>.
|
||||
* @see #addActionListener addActionListener
|
||||
*/
|
||||
public void removeActionListener(ActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.remove(ActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies listeners that some part of the tree was clicked by the
|
||||
* user. The source of the event is the tree.
|
||||
*
|
||||
* @pre data != null
|
||||
* @see #respond respond
|
||||
*/
|
||||
protected void fireActionEvent(PageState data) {
|
||||
Iterator
|
||||
i=m_listeners.getListenerIterator(ActionListener.class);
|
||||
ActionEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if ( e == null ) {
|
||||
e = new ActionEvent(this, data);
|
||||
}
|
||||
((ActionListener) i.next()).actionPerformed(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener that is notified whenever a tree node is expanded or
|
||||
* collpased, either by a user's click or by explicit calls to {@link
|
||||
* #expand expand} or {@link #collapse collapse}.
|
||||
*
|
||||
* @pre l != null
|
||||
* @pre ! isLocked()
|
||||
*/
|
||||
public void addTreeExpansionListener(TreeExpansionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.add(TreeExpansionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a previously added <code>TreeExpansionListener</code>.
|
||||
*
|
||||
* @pre ! isLocked()
|
||||
* @see #addTreeExpansionListener addTreeExpansionListener
|
||||
*/
|
||||
public void removeTreeExpansionListener(TreeExpansionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.remove(TreeExpansionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered {@link
|
||||
* com.arsdigita.bebop.event.TreeExpansionListener
|
||||
* TreeExpansionListeners} that a node in the tree has been expanded.
|
||||
*
|
||||
* @pre state != null
|
||||
* @pre nodeKey != null
|
||||
*/
|
||||
protected void fireTreeExpanded(PageState state, Object nodeKey) {
|
||||
Iterator i =
|
||||
m_listeners.getListenerIterator(TreeExpansionListener.class);
|
||||
TreeExpansionEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if ( e == null ) {
|
||||
e = new TreeExpansionEvent(this, state, nodeKey);
|
||||
}
|
||||
((TreeExpansionListener) i.next()).treeExpanded(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered {@link
|
||||
* com.arsdigita.bebop.event.TreeExpansionListener
|
||||
* TreeExpansionListeners} that a node in the tree has been collapsed.
|
||||
*
|
||||
* @pre state != null
|
||||
* @pre nodeKey != null
|
||||
*/
|
||||
protected void fireTreeCollapsed(PageState state, Object nodeKey) {
|
||||
Iterator i =
|
||||
m_listeners.getListenerIterator(TreeExpansionListener.class);
|
||||
TreeExpansionEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if ( e == null ) {
|
||||
e = new TreeExpansionEvent(this, state, nodeKey);
|
||||
}
|
||||
((TreeExpansionListener) i.next()).treeCollapsed(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the <code>Tree</code> that a node has been selected.
|
||||
* Changes the currently selected tree component.
|
||||
*/
|
||||
public void respond(PageState data) throws javax.servlet.ServletException {
|
||||
String action = data.getControlEventName();
|
||||
String node = data.getControlEventValue();
|
||||
|
||||
if (EXPAND_EVENT.equals(action)) {
|
||||
expand(node, data);
|
||||
} else if (COLLAPSE_EVENT.equals(action)) {
|
||||
collapse(node, data);
|
||||
} else if ( SELECT_EVENT.equals(action) ) {
|
||||
setSelectedKey(data, data.getControlEventValue());
|
||||
} else {
|
||||
throw new javax.servlet.ServletException("Unknown event '" + action + "'");
|
||||
}
|
||||
fireActionEvent(data);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// MANAGE TREE'S NODE STATE //
|
||||
//////////////////////////////
|
||||
|
||||
/**
|
||||
* Determines whether the node at the specified display row is collapsed.
|
||||
* @return <code>true</code> if the node at the specified display row is collapsed;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isCollapsed(String nodeKey, PageState data) {
|
||||
String stateString = (String) data.getValue(m_currentState);
|
||||
String spaceId = " " + nodeKey + " ";
|
||||
int idIndex;
|
||||
|
||||
if (stateString == null) {
|
||||
return true;
|
||||
} else {
|
||||
idIndex = stateString.indexOf(spaceId);
|
||||
}
|
||||
|
||||
// == -1 means it's not found in current state, thus it's collapsed
|
||||
return (idIndex == -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapses a node in the tree and makes its children visible.
|
||||
*
|
||||
* @param nodeKey the key that the tree model uses to identify the
|
||||
* node
|
||||
* @param data represents the current request
|
||||
*
|
||||
* @pre nodeKey != null
|
||||
* @pre data != null
|
||||
*/
|
||||
public void collapse(String nodeKey, PageState data) {
|
||||
Assert.exists(nodeKey);
|
||||
Assert.exists(data);
|
||||
|
||||
StringBuffer newCurrentState = new StringBuffer("");
|
||||
String stateString = (String) data.getValue(m_currentState);
|
||||
int idIndex;
|
||||
String spaceId = " " + nodeKey + " ";
|
||||
int idLength = spaceId.length();
|
||||
|
||||
if (stateString != null) {
|
||||
idIndex = stateString.indexOf(spaceId);
|
||||
// Found it; it should currently be expanded, so collapse it
|
||||
if (idIndex != -1) {
|
||||
newCurrentState
|
||||
.append(stateString.substring(0,idIndex))
|
||||
.append(" ");
|
||||
if (stateString.length() > (idIndex + idLength)) {
|
||||
newCurrentState.append(stateString.substring(idIndex+idLength));
|
||||
}
|
||||
data.setValue(m_currentState, newCurrentState.toString());
|
||||
fireTreeCollapsed(data, nodeKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands a node in the tree and makes its children visible.
|
||||
*
|
||||
* @param nodeKey the key that the tree model uses to identify the
|
||||
* node
|
||||
* @param data represents the current request
|
||||
*
|
||||
* @pre nodeKey != null
|
||||
* @pre data != null
|
||||
*/
|
||||
public void expand(String nodeKey, PageState data) {
|
||||
Assert.exists(nodeKey);
|
||||
Assert.exists(data);
|
||||
|
||||
String stateString = (String) data.getValue(m_currentState);
|
||||
String spaceId = " " + nodeKey + " ";
|
||||
StringBuffer newCurrentState = new StringBuffer("");
|
||||
|
||||
if (stateString != null) {
|
||||
// Can't find it; it should currently be collapsed, so expand it
|
||||
if ((stateString.indexOf(spaceId)) == -1) {
|
||||
// Start with existing stateString...
|
||||
newCurrentState.append(stateString);
|
||||
// Add to newCurrentState string the new node Id
|
||||
newCurrentState.append(spaceId);
|
||||
// Set the value of the current state
|
||||
data.setValue(m_currentState, newCurrentState.toString());
|
||||
fireTreeExpanded(data, nodeKey);
|
||||
}
|
||||
} else {
|
||||
// Add to newCurrentState string the new node Id
|
||||
newCurrentState.append(spaceId);
|
||||
// Set the value of the current state
|
||||
data.setValue(m_currentState, newCurrentState.toString());
|
||||
fireTreeExpanded(data, nodeKey);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// PRINT THE TREE DIRECTLY OR GENERATE DOM //
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns the renderer currently used to render tree nodes.
|
||||
*
|
||||
* @return the current tree node renderer.
|
||||
*/
|
||||
public final TreeCellRenderer getCellRenderer() {
|
||||
return m_renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell renderer to be used when generating output with
|
||||
* {@link #generateXML generateXML}.
|
||||
*
|
||||
* @param r a <code>TreeCellRenderer</code> value
|
||||
*/
|
||||
public void setCellRenderer(TreeCellRenderer r) {
|
||||
Assert.isUnlocked(this);
|
||||
m_renderer = r;
|
||||
}
|
||||
|
||||
private boolean hasSelectedChild(TreeModel tree, TreeNode node, PageState data, Object selKey) {
|
||||
String nodeKey = (String) node.getKey();
|
||||
if ( (selKey != null) && (selKey.equals(nodeKey) || selKey.toString().equals(nodeKey)) ) {
|
||||
return true;
|
||||
}
|
||||
Iterator i = tree.getChildren(node, data);
|
||||
while (i.hasNext()) {
|
||||
TreeNode child = (TreeNode) i.next();
|
||||
if (hasSelectedChild(tree, child, data, selKey)) {
|
||||
// At this point we should close the opened DataQuery pointed to by Iterator (i).
|
||||
// Since the data query is wrapped within DataQueryIterator, we don't have
|
||||
// access to it directly, so this looks like the only viable option ...
|
||||
while (i.hasNext()) { }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a DOM representing the tree.
|
||||
*
|
||||
*/
|
||||
protected void generateTree(PageState data, Element parent, TreeNode node,
|
||||
TreeModel tree) {
|
||||
|
||||
Element t_node = parent.newChildElement ("bebop:t_node", BEBOP_XML_NS);
|
||||
|
||||
String nodeKey = (String) node.getKey();
|
||||
Object selKey = getSelectedKey(data);
|
||||
boolean isSelected = (selKey != null)
|
||||
&& (selKey.equals(nodeKey) || selKey.toString().equals(nodeKey));
|
||||
|
||||
boolean hasChildren = tree.hasChildren(node, data);
|
||||
if (s_selectAttributeEnabled) {
|
||||
boolean hasSelectedChild = false;
|
||||
if (!isSelected && hasChildren) {
|
||||
hasSelectedChild = hasSelectedChild(tree, node, data, selKey);
|
||||
}
|
||||
t_node.addAttribute("isSelected", String.valueOf(isSelected | hasSelectedChild));
|
||||
}
|
||||
|
||||
if (hasChildren) {
|
||||
boolean collapsed = isCollapsed(nodeKey,data);
|
||||
data.setControlEvent(this, collapsed ? EXPAND_EVENT : COLLAPSE_EVENT, nodeKey);
|
||||
try {
|
||||
t_node.addAttribute("href", data.stateAsURL());
|
||||
} catch (java.io.IOException ioe) {
|
||||
// TODO: stateAsURL failed
|
||||
}
|
||||
data.clearControlEvent();
|
||||
if ( collapsed ) {
|
||||
// Collapsed
|
||||
t_node.addAttribute("collapsed", "t");
|
||||
data.setControlEvent(this, SELECT_EVENT, nodeKey);
|
||||
Component c = getCellRenderer().getComponent(this, data,
|
||||
node.getElement(), isSelected, NOT_EXPANDED, NOT_LEAF,
|
||||
nodeKey);
|
||||
c.generateXML(data, t_node);
|
||||
} else {
|
||||
// Expanded
|
||||
t_node.addAttribute("expanded", "t");
|
||||
data.setControlEvent(this, SELECT_EVENT, nodeKey);
|
||||
Component c = getCellRenderer().getComponent(this, data,
|
||||
node.getElement(), isSelected, EXPANDED, NOT_LEAF,
|
||||
nodeKey);
|
||||
c.generateXML(data, t_node);
|
||||
t_node.addAttribute("indentStart", "t");
|
||||
for(Iterator i = tree.getChildren(node,data); i.hasNext(); ) {
|
||||
generateTree(data, t_node, (TreeNode) i.next(), tree);
|
||||
}
|
||||
t_node.addAttribute("indentClose", "t");
|
||||
}
|
||||
} else {
|
||||
// No children, no need for link...
|
||||
t_node.addAttribute("childless", "t");
|
||||
data.setControlEvent(this, SELECT_EVENT, nodeKey);
|
||||
Component c = getCellRenderer().getComponent(this, data,
|
||||
node.getElement(), isSelected, NOT_EXPANDED, LEAF, nodeKey);
|
||||
c.generateXML(data, t_node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Services the request by building a DOM tree with the nodes
|
||||
* first and then the included page.
|
||||
*/
|
||||
public void generateXML(PageState data, Element parent) {
|
||||
|
||||
TreeModel tree = getTreeModel(data);
|
||||
|
||||
if ( ! isVisible(data) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
treeElement = parent.newChildElement ("bebop:tree", BEBOP_XML_NS);
|
||||
exportAttributes(treeElement);
|
||||
|
||||
TreeNode _rootNode = tree.getRoot(data);
|
||||
generateTree(data, treeElement, _rootNode, tree);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the selected item by manipulating the state parameter.
|
||||
*
|
||||
* @deprecated The {@link ParameterSingleSelectionModel} contains
|
||||
* all the functionality of this class
|
||||
*/
|
||||
public static class TreeSingleSelectionModel
|
||||
extends ParameterSingleSelectionModel {
|
||||
public TreeSingleSelectionModel(ParameterModel m) {
|
||||
super(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the <code>Tree</code> and prohibits further modifications.
|
||||
*/
|
||||
public void lock() {
|
||||
getModelBuilder().lock();
|
||||
super.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tree model of the tree. A wrapper class to make
|
||||
* deprecated constructor work.
|
||||
*/
|
||||
private static class WrapperModelBuilder extends LockableImpl
|
||||
implements TreeModelBuilder {
|
||||
|
||||
public WrapperModelBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TreeModel makeModel(Tree t, PageState s) {
|
||||
return t.getTreeModel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
|
||||
/**
|
||||
* A convenience for implementing <code>TableModelBuilder</code>s. This
|
||||
* class provides a default implementation of the methods demanded by
|
||||
* <code>Lockable</code>, so that implementors of
|
||||
* <code>TableModelBuilder</code> only need to override the
|
||||
* <code>makeModel</code> method.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @see TableModelBuilder
|
||||
* @see com.arsdigita.util.Lockable
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractTableModelBuilder extends LockableImpl
|
||||
implements TableModelBuilder {
|
||||
|
||||
/**
|
||||
* Return a table model for the request represented by
|
||||
* <code>s</code>. The table model contains all the data that is to be
|
||||
* displayed in a table. The returned table model is used only during
|
||||
* the duration of that request.
|
||||
*
|
||||
* @param t the table which will use this table model
|
||||
* @param s represents the current request
|
||||
* @return the data to be displayed in the table
|
||||
*/
|
||||
public abstract TableModel makeModel(Table t, PageState s);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
|
||||
import com.arsdigita.bebop.util.GlobalizationUtil ;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
|
||||
/**
|
||||
* The default renderer for table cells. This renderer is used by the
|
||||
* {@link com.arsdigita.bebop.Table} component for rendering the table
|
||||
* headers and cells if no other renderer is specified.
|
||||
*
|
||||
* <p> This renderer can operate in two different modes: <em>active</em>
|
||||
* and <em>inactive</em> mode. In inactive mode, all objects are rendered
|
||||
* by converting them to a string and enclosing that string in a {@link
|
||||
* com.arsdigita.bebop.Label}. If the renderer is in active mode, this
|
||||
* label is further enclosed in a control link. When the user clicks on
|
||||
* this link, the table will fire an <code>TableActionEvent</code> whose
|
||||
* <code>getKey()</code> and <code>getColumn()</code> method return the
|
||||
* values of the <code>key</code> and <code>column</code> parameters that
|
||||
* were passed into {@link #getComponent getComponent}.
|
||||
*
|
||||
* <p> In a nutshell, an active renderer will let the user click a link
|
||||
* that causes a <code>TableActionEvent</code> for the corresponding cell,
|
||||
* while an inactive renderer will display the values just as strings, thus
|
||||
* making it impossible for the user to cause such an event.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @see com.arsdigita.bebop.Table
|
||||
* @see com.arsdigita.bebop.event.TableActionEvent
|
||||
*
|
||||
* @version $Id$ */
|
||||
public class DefaultTableCellRenderer extends LockableImpl
|
||||
implements TableCellRenderer {
|
||||
|
||||
private boolean m_active;
|
||||
private ThreadLocal m_label;
|
||||
private ThreadLocal m_controlLink;
|
||||
|
||||
/**
|
||||
* Creates a new table cell renderer. The table cell renderer is in
|
||||
* inactive mode.
|
||||
*/
|
||||
public DefaultTableCellRenderer() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table cell renderer. The <code>active</code> argument
|
||||
* specifies whether the renderer should be active or not.
|
||||
*
|
||||
* @param active <code>true</code> if the renderer should generate links
|
||||
* instead of just static labels.
|
||||
*/
|
||||
public DefaultTableCellRenderer(boolean active) {
|
||||
m_active = active;
|
||||
m_label = new ThreadLocal() {
|
||||
protected Object initialValue() {
|
||||
return new Label("");
|
||||
}
|
||||
};
|
||||
m_controlLink = new ThreadLocal() {
|
||||
protected Object initialValue() {
|
||||
return new ControlLink((Label) m_label.get());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the renderer is in active mode. A
|
||||
* rendererin active mode will enclose the objects it renders in links
|
||||
* that, when clicked, will cause the containing table to fire a
|
||||
* <code>TableActionEvent</code>.
|
||||
*
|
||||
* @return <code>true</code> if the renderer is in active mode.
|
||||
*/
|
||||
public final boolean isActive() {
|
||||
return m_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the renderer to active or inactive mode.
|
||||
*
|
||||
* @param v <code>true</code> if the renderer should operate in active
|
||||
* mode.
|
||||
* @pre ! isLocked()
|
||||
*/
|
||||
public void setActive(boolean v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_active = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the component that should be used to render the given
|
||||
* <code>value</code>. Returns a {@link com.arsdigita.bebop.Label} if the
|
||||
* renderer is active, and a {@link com.arsdigita.bebop.ControlLink} if
|
||||
* the renderer is inactive.
|
||||
*
|
||||
* @pre table == null || table != null
|
||||
*/
|
||||
public Component getComponent(Table table, PageState state, Object value,
|
||||
boolean isSelected, Object key,
|
||||
int row, int column)
|
||||
{
|
||||
if ( ! isLocked() && table != null && table.isLocked() ) {
|
||||
lock();
|
||||
}
|
||||
|
||||
Label l;
|
||||
if ( value instanceof com.arsdigita.bebop.Component ) {
|
||||
return (com.arsdigita.bebop.Component) value;
|
||||
} else if(value instanceof GlobalizedMessage) {
|
||||
l = (Label) m_label.get();
|
||||
l.setLabel((GlobalizedMessage) value);
|
||||
} else {
|
||||
l = (Label) m_label.get();
|
||||
|
||||
if ( value == null ) {
|
||||
l.setLabel( (String) GlobalizationUtil.globalize("bebop.table.").localize());
|
||||
l.setOutputEscaping(false);
|
||||
} else {
|
||||
l.setLabel(value.toString());
|
||||
l.setOutputEscaping(true);
|
||||
}
|
||||
}
|
||||
l.setFontWeight( (isSelected && m_active) ? Label.BOLD : null );
|
||||
if (m_active && ! isSelected) {
|
||||
return (ControlLink) m_controlLink.get();
|
||||
} else {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||
import com.arsdigita.bebop.parameters.IntegerParameter;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
/**
|
||||
* Describe interface <code>TableColumnModel</code> here.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DefaultTableColumnModel implements TableColumnModel {
|
||||
|
||||
private static final String SELECTED_COLUMN="col";
|
||||
|
||||
private boolean m_locked;
|
||||
|
||||
private ArrayList m_columns;
|
||||
|
||||
private SingleSelectionModel m_selection;
|
||||
|
||||
public DefaultTableColumnModel() {
|
||||
this(new Object[0]);
|
||||
}
|
||||
|
||||
public DefaultTableColumnModel(SingleSelectionModel sel) {
|
||||
this(new Object[0], sel);
|
||||
}
|
||||
|
||||
public DefaultTableColumnModel(Object[] headers) {
|
||||
this(headers,
|
||||
new ParameterSingleSelectionModel(new IntegerParameter(SELECTED_COLUMN)) );
|
||||
}
|
||||
|
||||
public DefaultTableColumnModel(Object[] headers, SingleSelectionModel sel) {
|
||||
m_columns = new ArrayList();
|
||||
m_selection = sel;
|
||||
|
||||
for (int i=0; i < headers.length; i++) {
|
||||
add(new TableColumn(i, headers[i], new Integer(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void add(TableColumn column) {
|
||||
Assert.isUnlocked(this);
|
||||
m_columns.add(column);
|
||||
}
|
||||
|
||||
public void add(int columnIndex, TableColumn column) {
|
||||
Assert.isUnlocked(this);
|
||||
m_columns.add(columnIndex, column);
|
||||
}
|
||||
|
||||
public TableColumn get(int columnIndex) {
|
||||
return (TableColumn) m_columns.get(columnIndex);
|
||||
}
|
||||
|
||||
public void set(int columnIndex, TableColumn v) {
|
||||
m_columns.set(columnIndex, v);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return m_columns.size();
|
||||
}
|
||||
|
||||
public int getIndex(Object key) {
|
||||
if ( key == null ) {
|
||||
return -1;
|
||||
}
|
||||
for (int i=0; i<size(); i++) {
|
||||
TableColumn t = get(i);
|
||||
if ( key.equals(t.getHeaderKey()) ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Iterator columns() {
|
||||
return m_columns.iterator();
|
||||
}
|
||||
|
||||
public void remove(TableColumn column) {
|
||||
Assert.isUnlocked(this);
|
||||
m_columns.remove(column);
|
||||
}
|
||||
|
||||
public final SingleSelectionModel getSelectionModel() {
|
||||
return m_selection;
|
||||
}
|
||||
|
||||
public void setSelectionModel(SingleSelectionModel model) {
|
||||
Assert.isUnlocked(this);
|
||||
m_selection = model;
|
||||
}
|
||||
|
||||
public final void lock() {
|
||||
m_locked = true;
|
||||
}
|
||||
|
||||
public final boolean isLocked() {
|
||||
return m_locked;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
|
||||
import com.arsdigita.bebop.util.GlobalizationUtil ;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Table;
|
||||
|
||||
/**
|
||||
* Render one cell in a table. The renderer returns a component whose
|
||||
* {@link com.arsdigita.bebop.Component#generateXML generateXML} method
|
||||
* will be called by the table to include the data for the cell in the
|
||||
* table's output.
|
||||
*
|
||||
* <p> The table uses the returned component only until it calls the cell
|
||||
* renderer again, so that cell renderers may reuse the same object in
|
||||
* subsequent calls to {@link #getComponent getComponent}.
|
||||
*
|
||||
* <p> As an example, consider the following implementation of a table cell
|
||||
* renderer, which simply converts the passed in <code>value</code> to a
|
||||
* string and encloses it in a label. The cell renderer converts the passed
|
||||
* in value to a string and uses that to set the text to display for a
|
||||
* label. If the value is selected, the label is bolded. As an added twist,
|
||||
* the table cell renderer uses only one label for each thread from which
|
||||
* it is accessed (rather than creating a new <code>Label</code> for each
|
||||
* call) by storing the label in a <code>ThreadLocal</code> variable.
|
||||
*
|
||||
* <pre>
|
||||
* public class MyTableCellRenderer implements TableCellRenderer {
|
||||
*
|
||||
* private ThreadLocal m_label;
|
||||
*
|
||||
* public MyTableCellRenderer() {
|
||||
* m_label = new ThreadLocal() {
|
||||
* protected Object initialValue() {
|
||||
* return new Label("");
|
||||
* }
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* public Component getComponent(Table table, PageState state, Object value,
|
||||
* boolean isSelected, Object key,
|
||||
* int row, int column) {
|
||||
* Label l = (Label) m_label.get();
|
||||
* l.setLabel(value.toString());
|
||||
* l.setFontWeight( isSelected ? Label.BOLD : null );
|
||||
* return l;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @see com.arsdigita.bebop.Table Table
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface TableCellRenderer {
|
||||
|
||||
/**
|
||||
* Return a component with the visual representation for the passed in
|
||||
* <code>key</code> and <code>value</code>.
|
||||
*
|
||||
* <p> The table sets the control event prior to calling this method, so
|
||||
* that any control link returned as the component will, when clicked,
|
||||
* cause the table to fire a <code>TableActionEvent</code> whose
|
||||
* <code>getRowKey()</code> and <code>getColumn()</code> return the
|
||||
* values of <code>key</code> and <code>column</code>. A simple cell
|
||||
* renderer that achieves this would implement this method in the
|
||||
* following way:
|
||||
* <pre>
|
||||
* public Component getComponent(Table table, PageState state, Object value,
|
||||
* boolean isSelected, Object key,
|
||||
* int row, int column) {
|
||||
* return new ControlLink(value.toString());
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p> The <code>column</code> refers to a column in the table's {@link
|
||||
* TableColumnModel}, i.e. the visual column on the screen, and not the
|
||||
* table's representation of the underlying data in the {@link
|
||||
* TableModel}.
|
||||
*
|
||||
* @param table the table requesting the rendering.
|
||||
* @param state represents the state of the current request.
|
||||
* @param value the data element to render as returned by the table
|
||||
* model's {@link TableModel#getElementAt getElementAt(column)}.
|
||||
* @param isSelected true if this item is selected.
|
||||
* @param key the key identifying this row (and possibly column) as
|
||||
* returned by the table model's {@link TableModel#getKeyAt
|
||||
* getKeyAt(column)}
|
||||
* @param row the number of the row in the table, the first row has
|
||||
* number <code>0</code>.
|
||||
* @param column the number of the table column.
|
||||
* @return the component that should be used to render the
|
||||
* <code>value</code>.
|
||||
* @pre table != null
|
||||
* @pre state != null
|
||||
* @pre value != null
|
||||
* @pre key != null
|
||||
* @pre row >= 0
|
||||
* @pre column >= 0 && column < table.getColumnModel().size()
|
||||
* @post return != null
|
||||
* @see TableColumnModel
|
||||
*/
|
||||
Component getComponent(Table table, PageState state, Object value,
|
||||
boolean isSelected, Object key,
|
||||
int row, int column);
|
||||
}
|
||||
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.bebop.util.Attributes;
|
||||
import com.arsdigita.util.Lockable;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
/**
|
||||
* One column in a table. The <code>TableColumn</code> stores important
|
||||
* display-related information about a table column, such as the column
|
||||
* header, the renderers for the column header and ordinary cells in this
|
||||
* column and from which column in the table model values should be taken
|
||||
* when rendering table cells. The set of table columns for a table is
|
||||
* maintained by a {@link TableColumnModel}.
|
||||
*
|
||||
* <p> <code>TableColumn</code> allows the column ordering to be different
|
||||
* between the underlying {@link TableModel} and the view presented by the
|
||||
* <code>Table</code>: each column contains a <code>modelIndex</code>
|
||||
* property. This is the column that is retrieved from the
|
||||
* <code>TableModel</code> when the values are displayed, regardless of the
|
||||
* position of the <code>TableColumn</code> in the
|
||||
* <code>TableColumnModel</code>. This makes it possible to display the
|
||||
* same table model in several tables with reordered or omitted columns.
|
||||
*
|
||||
* <p> The <code>TableColumn</code> stores also the value and key used for
|
||||
* the header of the column. These objects are passed to the header cell
|
||||
* renderer when the header of the table is rendered. The value is usually
|
||||
* used to generate the visible information for the table header, and is
|
||||
* often a string. The key is usually used to identify the underlying
|
||||
* object, or to just identify the column, and can be any object whose
|
||||
* <code>toString()</code> method returns a representation that can be
|
||||
* included in a URL. In the simplest case, this may just be an
|
||||
* <code>Integer</code> containing the index of the column in the column
|
||||
* model.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @see com.arsdigita.bebop.Table
|
||||
* @see TableColumnModel
|
||||
*
|
||||
* @version $Id$ */
|
||||
public class TableColumn extends SimpleComponent
|
||||
implements Lockable {
|
||||
|
||||
|
||||
/**
|
||||
* The name of the width attribute used in the XML.
|
||||
*/
|
||||
private static final String WIDTH_ATTR = "width";
|
||||
|
||||
/**
|
||||
* The name of the align attribute used in the XML.
|
||||
*/
|
||||
private static final String ALIGN_ATTR = "align";
|
||||
|
||||
/**
|
||||
* The name of the valign attribute used in the XML.
|
||||
*/
|
||||
private static final String VALIGN_ATTR = "valign";
|
||||
|
||||
/**
|
||||
* The number of the column in the table model from which to get values.
|
||||
*/
|
||||
private int m_modelIndex;
|
||||
|
||||
/**
|
||||
* The renderer used for ordinary cells in this column. Null by default,
|
||||
* which instructs the <code>Table</code> to use its default renderer.
|
||||
*/
|
||||
private TableCellRenderer m_cellRenderer;
|
||||
|
||||
/**
|
||||
* The renderer used for the header of the column. Null by default, which
|
||||
* instructs the <code>TableHeader</code> to use its default renderer.
|
||||
*/
|
||||
private TableCellRenderer m_headerRenderer;
|
||||
|
||||
/**
|
||||
* The key for identifying the header. Will be passed to the header cell
|
||||
* renderer.
|
||||
*/
|
||||
private Object m_headerKey;
|
||||
|
||||
/**
|
||||
* The display value for identifying the header. Will be passed to the
|
||||
* header cell renderer.
|
||||
* Usually this will be a {@link Label} passed in by a pattern like
|
||||
* {@code new Label(GlobalizedMessage)}. But it could be any object,
|
||||
* e.g.an image as well. The use of a string is possible but strongly
|
||||
* discouraged because it results in non-localizable UI.
|
||||
*/
|
||||
private Object m_headerValue;
|
||||
|
||||
/**
|
||||
* The display attributes for each cell in this column
|
||||
*/
|
||||
private Attributes m_cellAttrs;
|
||||
|
||||
/**
|
||||
* Creates a new table column with <code>modelIndex</code> 0 and header
|
||||
* value and key equal to <code>null</code>.
|
||||
*/
|
||||
public TableColumn() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table column with the given <code>modelIndex</code> and
|
||||
* header value and key equal to <code>null</code>.
|
||||
*
|
||||
* @param modelIndex the index of the column in the table model from
|
||||
* which to retrieve values
|
||||
* @pre modelIndex >= 0
|
||||
*/
|
||||
public TableColumn(int modelIndex) {
|
||||
this(modelIndex, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table column with the given <code>modelIndex</code> and
|
||||
* header value. The header key is equal to <code>null</code>.
|
||||
*
|
||||
* @param modelIndex the index of the column in the table model from
|
||||
* which to retrieve values.
|
||||
* @param value the value for the column header.
|
||||
* @pre modelIndex >= 0
|
||||
*/
|
||||
public TableColumn(int modelIndex, Object value) {
|
||||
this(modelIndex, value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table column with the given <code>modelIndex</code> and
|
||||
* header value and key.
|
||||
*
|
||||
* @param modelIndex the index of the column in the table model from
|
||||
* which to retrieve values.
|
||||
* @param value the value for the column header.
|
||||
* @param key the key for the column header.
|
||||
* @pre modelIndex >= 0
|
||||
*/
|
||||
public TableColumn(int modelIndex, Object value, Object key) {
|
||||
super();
|
||||
m_modelIndex = modelIndex;
|
||||
m_headerValue = value;
|
||||
m_headerKey = key;
|
||||
|
||||
m_cellAttrs = new Attributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the renderer used for the column header. This is
|
||||
* <code>null</code> by default, in which case the default renderer for
|
||||
* the {@link TableHeader} of the table to which this column belongs is
|
||||
* used.
|
||||
*
|
||||
* @return the renderer used for the column header.
|
||||
*/
|
||||
public final TableCellRenderer getHeaderRenderer() {
|
||||
return m_headerRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the renderer used for the column header. The header key and value
|
||||
* objects are passed to the renderer when the column header will be
|
||||
* rendererd.
|
||||
*
|
||||
* @param v the new renderer for the column header.
|
||||
* @see #getHeaderRenderer
|
||||
* @see #getCellRenderer
|
||||
*/
|
||||
public void setHeaderRenderer(TableCellRenderer v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_headerRenderer = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the renderer used for the cells in this column. This is
|
||||
* <code>null</code> by default, in which case the default renderer of
|
||||
* the {@link com.arsdigita.bebop.Table#getDefaultCellRenderer() table} to which this column
|
||||
* belongs is used.
|
||||
*
|
||||
* @return the renderer used for the cells in this column.
|
||||
*/
|
||||
public final TableCellRenderer getCellRenderer() {
|
||||
return m_cellRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the renderer used for cells in this column.
|
||||
*
|
||||
* @param v the new renderer for the cells in this column.
|
||||
* @see #getCellRenderer
|
||||
* @see #getHeaderRenderer
|
||||
*/
|
||||
public void setCellRenderer(TableCellRenderer v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_cellRenderer = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display value used for the header. This is the object that is
|
||||
* passed to the renderer. Usually this will be a {@link Label} previously
|
||||
* passed in by a pattern like {@code new Label(GlobalizedMessage)}.
|
||||
* The use of a string is possible but strongly discouraged.
|
||||
*
|
||||
* @return the display value for the header.
|
||||
*/
|
||||
public final Object getHeaderValue() {
|
||||
return m_headerValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the display value for the header. This object is passed through to
|
||||
* the header renderer without any modifications.
|
||||
* Usually this will be a {@link Label} passed in by a pattern like
|
||||
* {@code new Label(GlobalizedMessage)}. The use of a string is possible
|
||||
* but strongly discouraged because it results in non-localizable UI.
|
||||
*
|
||||
* @param value the new display value for the header.
|
||||
* @see #getHeaderValue
|
||||
*/
|
||||
public void setHeaderValue(Object value) {
|
||||
Assert.isUnlocked(this);
|
||||
m_headerValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key used to identify the header of this column. In the
|
||||
* simplest case, this is an <code>Integer</code> containing the index of
|
||||
* the column.
|
||||
*
|
||||
* @return the key used to identify the header of this column.
|
||||
*/
|
||||
public final Object getHeaderKey() {
|
||||
return m_headerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key used to identify the header of this column.
|
||||
*
|
||||
* @param key the new key for identifying the header of this column.
|
||||
* @see #getHeaderKey
|
||||
*/
|
||||
public void setHeaderKey(Object key) {
|
||||
Assert.isUnlocked(this);
|
||||
m_headerKey = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the column from which values are taken in the {@link
|
||||
* TableModel}.
|
||||
*
|
||||
* @return the index of the column in the table model from which values
|
||||
* are taken.
|
||||
* @see #setModelIndex setModelIndex
|
||||
*/
|
||||
public final int getModelIndex() {
|
||||
return m_modelIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index of the column in the {@link TableModel} from which the
|
||||
* values are taken when this column is rendered.
|
||||
*
|
||||
* @param v the new index of the column in the table model from which to
|
||||
* take values.
|
||||
*/
|
||||
public void setModelIndex(int v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_modelIndex = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width for this column.
|
||||
*
|
||||
* @return the width of this column.
|
||||
* @see #setWidth setWidth
|
||||
*/
|
||||
public String getWidth() {
|
||||
return getAttribute(WIDTH_ATTR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of this column. The string <code>v</code> is added as an
|
||||
* attribute to the XML element for this column in the table header.
|
||||
*
|
||||
* @param v the width of this column
|
||||
*/
|
||||
public void setWidth(String v) {
|
||||
Assert.isUnlocked(this);
|
||||
setAttribute(WIDTH_ATTR, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the horizontal alignment this column. The string <code>v</code>
|
||||
* is added as an attribute to the XML element for each cell in this column
|
||||
*
|
||||
* @param v the width of this column
|
||||
*/
|
||||
public void setAlign(String v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_cellAttrs.setAttribute(ALIGN_ATTR, v);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the horizontal alignment this column's header. The string
|
||||
* <code>v</code> is added as an attribute to the XML element for
|
||||
* the column's header cell.
|
||||
*
|
||||
* @param v the width of this column */
|
||||
public void setHeadAlign(String v) {
|
||||
Assert.isUnlocked(this);
|
||||
setAttribute(ALIGN_ATTR, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the vertical alignment this column. The string <code>v</code>
|
||||
* is added as an attribute to the XML element for each cell in this column
|
||||
*
|
||||
* @param v the width of this column
|
||||
*/
|
||||
public void setVAlign(String v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_cellAttrs.setAttribute(VALIGN_ATTR, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the vertical alignment this column's header. The string
|
||||
* <code>v</code> is added as an attribute to the XML element for
|
||||
* this column's header cell.
|
||||
*
|
||||
* @param v the width of this column */
|
||||
public void setHeadVAlign(String v) {
|
||||
Assert.isUnlocked(this);
|
||||
setAttribute(VALIGN_ATTR, v);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the style attribute for the column's
|
||||
* cells. <code>style</code> should be a valid CSS style, since
|
||||
* its value will be copied verbatim to the output and appear as a
|
||||
* <tt>style</tt> attribute in the top level XML or HTML output
|
||||
* element.
|
||||
*
|
||||
* @param style a valid CSS style description for use in the
|
||||
* <tt>style</tt> attribute of an HTML tag
|
||||
* @see <a href="#standard">Standard Attributes</a> */
|
||||
public void setStyleAttr(String style) {
|
||||
Assert.isUnlocked(this);
|
||||
m_cellAttrs.setAttribute(STYLE, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the style attribute for the column's header
|
||||
* cell. <code>style</code> should be a valid CSS style, since its
|
||||
* value will be copied verbatim to the output and appear as a
|
||||
* <tt>style</tt> attribute in the top level XML or HTML output
|
||||
* element.
|
||||
*
|
||||
* @param style a valid CSS style description for use in the
|
||||
* <tt>style</tt> attribute of an HTML tag
|
||||
* @see <a href="#standard">Standard Attributes</a> */
|
||||
public void setHeadStyleAttr(String style) {
|
||||
Assert.isUnlocked(this);
|
||||
setAttribute(STYLE, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class attribute for the column's
|
||||
* cells. <code>style</code> should be the name of a defined CSS
|
||||
* class, since its value will be copied verbatim to the output
|
||||
* and appear as a <tt>class</tt> attribute in the top level XML
|
||||
* or HTML output element.
|
||||
*
|
||||
* @param style a valid CSS style description for use in the
|
||||
* <tt>style</tt> attribute of an HTML tag
|
||||
* @see <a href="#standard">Standard Attributes</a> */
|
||||
public void setClassAttr(String c) {
|
||||
Assert.isUnlocked(this);
|
||||
m_cellAttrs.setAttribute(CLASS, c);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the class attribute for the column's header
|
||||
* cell. <code>style</code> should be the name of a defined CSS
|
||||
* class, since its value will be copied verbatim to the output
|
||||
* and appear as a <tt>class</tt> attribute in the top level XML
|
||||
* or HTML output element.
|
||||
*
|
||||
* @param style a valid CSS style description for use in the
|
||||
* <tt>style</tt> attribute of an HTML tag
|
||||
* @see <a href="#standard">Standard Attributes</a> */
|
||||
public void setHeadClassAttr(String c) {
|
||||
Assert.isUnlocked(this);
|
||||
setAttribute(CLASS, c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add all the XML attributes for this column.
|
||||
*
|
||||
* @param e the XML element to which attributes will be added.
|
||||
*/
|
||||
public void exportCellAttributes(Element e) {
|
||||
m_cellAttrs.exportAttributes(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the XML attributes for this column to this
|
||||
* element. Package-friendly since it is only used by {@link
|
||||
* TableHeader}.
|
||||
*
|
||||
* @param e the XML element to which attributes will be added.
|
||||
*/
|
||||
final void exportHeadAttributes(Element e) {
|
||||
super.exportAttributes(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an <code>UnsupportedOperationException</code>. This method can
|
||||
* only be called if the table column is not properly contained in a
|
||||
* table.
|
||||
*
|
||||
* @param s represents the current request
|
||||
* @param e the parent element
|
||||
*/
|
||||
public void generateXML(PageState s, Element e) {
|
||||
throw new UnsupportedOperationException("TableColumn used outside of a Table");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
import com.arsdigita.util.Lockable;
|
||||
|
||||
/**
|
||||
* Describe interface <code>TableColumnModel</code> here.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface TableColumnModel extends Lockable {
|
||||
|
||||
|
||||
void add(TableColumn column);
|
||||
|
||||
TableColumn get(int columnIndex);
|
||||
|
||||
/**
|
||||
* Insert a column at the given index. The columns from
|
||||
* <code>columnIndex</code> on are shifted one up.
|
||||
*
|
||||
* @param columnIndex the index for the new column.
|
||||
* @param column the table column to add to the model.
|
||||
* @pre 0 <= columnIndex && columnIndex <= size()
|
||||
*/
|
||||
void add(int columnIndex, TableColumn column);
|
||||
|
||||
void set(int columnIndex, TableColumn v);
|
||||
|
||||
int size();
|
||||
|
||||
int getIndex(Object columnIdentifier);
|
||||
|
||||
Iterator columns();
|
||||
|
||||
void remove(TableColumn column);
|
||||
|
||||
SingleSelectionModel getSelectionModel();
|
||||
|
||||
void setSelectionModel(SingleSelectionModel model);
|
||||
}
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.event.EventListenerList;
|
||||
import com.arsdigita.bebop.event.TableActionEvent;
|
||||
import com.arsdigita.bebop.event.TableActionListener;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
/**
|
||||
* This class is used by {@link Table} in order to maintain its headers.
|
||||
*
|
||||
* <code>TableHeader</code> is responsible for setting the control event
|
||||
* in order to notify the {@link Table} when one of the column headers
|
||||
* is clicked.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TableHeader extends SimpleComponent {
|
||||
|
||||
|
||||
/**
|
||||
* The control event when the user clicks on a column header.
|
||||
*/
|
||||
public static final String HEAD_EVENT = "head";
|
||||
|
||||
private TableCellRenderer m_defaultRenderer;
|
||||
|
||||
private TableColumnModel m_columnModel;
|
||||
|
||||
private Table m_table;
|
||||
|
||||
private EventListenerList m_listeners;
|
||||
|
||||
/**
|
||||
* Create a new <code>TableHeader</code>
|
||||
*/
|
||||
public TableHeader() {
|
||||
this(new DefaultTableColumnModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>TableHeader</code>
|
||||
*
|
||||
* @param model the {@link TableColumnModel} that the header
|
||||
* will use in order to generate and maintain the
|
||||
* column headers.
|
||||
*/
|
||||
public TableHeader(TableColumnModel model) {
|
||||
m_columnModel = model;
|
||||
m_defaultRenderer = new DefaultTableCellRenderer();
|
||||
m_listeners = new EventListenerList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an {@link TableActionListener} to the header.
|
||||
* The listener will be fired whenever this header is
|
||||
* selected by the user.
|
||||
*
|
||||
* @param l the {@link TableActionListener} to add
|
||||
*/
|
||||
public void addTableActionListener(TableActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.add(TableActionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a {@link TableActionListener} from the header
|
||||
*
|
||||
*@param l the {@link TableActionListener} to remove
|
||||
*/
|
||||
public void removeTableActionListener(TableActionListener l) {
|
||||
Assert.isUnlocked(this);
|
||||
m_listeners.remove(TableActionListener.class, l);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify all listeners that the header was selected
|
||||
*
|
||||
* @param state the page state
|
||||
* @param rowKey the key of the selected row, as returned by
|
||||
* <code>Table.getRowSelectionModel().getSelectedKey(state)</code>.
|
||||
* this key may be null.
|
||||
* @param column The index of the selected column
|
||||
*
|
||||
*/
|
||||
protected void fireHeadSelected(PageState state,
|
||||
Object rowKey, Integer column) {
|
||||
Iterator
|
||||
i=m_listeners.getListenerIterator(TableActionListener.class);
|
||||
TableActionEvent e = null;
|
||||
|
||||
while (i.hasNext()) {
|
||||
if ( e == null ) {
|
||||
e = new TableActionEvent(this, state, rowKey, column);
|
||||
}
|
||||
((TableActionListener) i.next()).headSelected(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Respond to the current event by selecting the current
|
||||
* column
|
||||
*
|
||||
* @param s the page state
|
||||
*/
|
||||
public void respond(PageState s) throws ServletException {
|
||||
String event = s.getControlEventName();
|
||||
if ( HEAD_EVENT.equals(event) ) {
|
||||
String value = s.getControlEventValue();
|
||||
// FIXME: ParameterData allows its value to be set to anything, even
|
||||
// if it isn't compatible with the ParameterModel
|
||||
// We need to change ParameterModel/Data to fail earlier on bad data
|
||||
Integer col = new Integer(value);
|
||||
getColumnModel().getSelectionModel().setSelectedKey(s, col);
|
||||
fireHeadSelected(s, null, col);
|
||||
} else {
|
||||
throw new ServletException("Unknown event '" + event + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parent {@link Table}
|
||||
*/
|
||||
public final Table getTable() {
|
||||
return m_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent {@link Table}
|
||||
*
|
||||
* @param v the parent table
|
||||
*/
|
||||
public void setTable(Table v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_table = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TableColumnModel} which maintains the headers
|
||||
*/
|
||||
public final TableColumnModel getColumnModel() {
|
||||
return m_columnModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link TableColumnModel} which will maintain the headers
|
||||
*
|
||||
* @param v the new {@link TableColumnModel}
|
||||
*/
|
||||
public void setColumnModel(TableColumnModel v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_columnModel = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default {@link TableCellRenderer} for this header
|
||||
*/
|
||||
public final TableCellRenderer getDefaultRenderer() {
|
||||
return m_defaultRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default {@link TableCellRenderer} for this header.
|
||||
* Header cells will be rendered with this renderer unless
|
||||
* the column model specifies an alternative renderer.
|
||||
*
|
||||
* @param v the new default renderer
|
||||
*/
|
||||
public void setDefaultRenderer(TableCellRenderer v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_defaultRenderer = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the XML for this header. The XML will be of the form
|
||||
* <blockquote><pre><code>
|
||||
* <bebop:thead>
|
||||
* <bebop:cell>...</bebop:cell>
|
||||
* ...
|
||||
* </bebop:thead>
|
||||
* </code><pre></blockquote>
|
||||
*
|
||||
* @param s the page state
|
||||
* @param p the parent element
|
||||
*/
|
||||
public void generateXML(PageState s, Element p) {
|
||||
if ( isVisible(s) ) {
|
||||
Element thead = p.newChildElement("bebop:thead", BEBOP_XML_NS);
|
||||
exportAttributes(thead);
|
||||
|
||||
for (int i=0; i < m_columnModel.size(); i++) {
|
||||
TableColumn t = m_columnModel.get(i);
|
||||
|
||||
if ( t.isVisible(s) ) {
|
||||
TableCellRenderer r = t.getHeaderRenderer();
|
||||
|
||||
if ( r == null ) {
|
||||
r = getDefaultRenderer();
|
||||
}
|
||||
|
||||
boolean isSel = isSelected(s, t.getHeaderKey(), i);
|
||||
|
||||
Component c = r.getComponent(getTable(), s, t.getHeaderValue(), isSel,
|
||||
t.getHeaderKey(), -1, i);
|
||||
|
||||
if (c != null) {
|
||||
// supports having a table header disappear
|
||||
// completely, mainly useful for the odd special case
|
||||
// where a second-row element is being displayed.
|
||||
|
||||
Element cell = thead.newChildElement("bebop:cell", BEBOP_XML_NS);
|
||||
t.exportHeadAttributes(cell);
|
||||
|
||||
// Mark the cell as selected if it is selected
|
||||
if(isSel) {
|
||||
cell.addAttribute("selected", "1");
|
||||
}
|
||||
|
||||
// I added this check so that a table which is not
|
||||
// added to the Page can still be used to render
|
||||
// table XML.
|
||||
|
||||
boolean tableIsRegisteredWithPage =
|
||||
s.getPage().stateContains(getControler());
|
||||
|
||||
if (tableIsRegisteredWithPage) {
|
||||
s.setControlEvent(getControler(), HEAD_EVENT,
|
||||
String.valueOf(i));
|
||||
}
|
||||
|
||||
c.generateXML(s, cell);
|
||||
|
||||
if (tableIsRegisteredWithPage) {
|
||||
s.clearControlEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Component getControler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given column is selected. This information
|
||||
* will be passed to the {@link TableCellRenderer} for this header.
|
||||
*
|
||||
* @param s the page state
|
||||
* @param key the header key for the column as returned by
|
||||
* <code>TableColumn.getHeaderKey()</code>
|
||||
* @param column the index of the column to test
|
||||
*/
|
||||
protected boolean isSelected(PageState s, Object key, int column) {
|
||||
if (getTable().getColumnSelectionModel() == null) {
|
||||
return false;
|
||||
}
|
||||
Object sel = getTable()
|
||||
.getColumnSelectionModel().getSelectedKey(s);
|
||||
if(sel == null) {
|
||||
return false;
|
||||
}
|
||||
return (column == ((Integer)sel).intValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
/**
|
||||
* The <code>TableModel</code> is the abstraction a {@link
|
||||
* com.arsdigita.bebop.Table Table} uses to access the data it
|
||||
* displays. The table will ask its {@link TableModelBuilder} to
|
||||
* instantiate a new table model once for each request it processes.
|
||||
*
|
||||
* <p> The table will request each element in the model at most once per
|
||||
* request, moving through the rows with successive calls to {@link
|
||||
* #nextRow}. For each row, the table retrieves the values and keys in each
|
||||
* column with calls to {@link #getElementAt} and {@link #getKeyAt}.
|
||||
*
|
||||
* <p> The table data is accessed by the table by moving through the rows
|
||||
* of the table model with calls to {@link #nextRow}. The data for each
|
||||
* column in a row is represented by two objects: the data element which
|
||||
* usually contains display information for that column and can be as
|
||||
* simple as a string, and the key, which is used to identify the
|
||||
* column. The key is usually a suitable representation of the primary key
|
||||
* of the underlying object in the database. The key needs to be unique
|
||||
* amongst all <em>rows</em> in the table model, but doesn't need to
|
||||
* uniquely identify the row <em>and</em> column for that data item -
|
||||
* all calls to {@link #getKeyAt} can return the same value for one row in
|
||||
* the table model.
|
||||
*
|
||||
* @see com.arsdigita.bebop.Table Table
|
||||
* @see TableModelBuilder
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$ */
|
||||
public interface TableModel {
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of columns this table model has.
|
||||
*
|
||||
* @return the number of columns in the table model
|
||||
* @post return >= 0
|
||||
*/
|
||||
int getColumnCount();
|
||||
|
||||
/**
|
||||
* Move to the next row and return true if the model is now positioned on
|
||||
* a valid row. Initially, the table model is positioned before the first
|
||||
* row. The table will call this method before it retrieves the data for
|
||||
* the row with calls to {@link #getElementAt getElementAt} and {@link
|
||||
* #getKeyAt getKeyAt}.
|
||||
*
|
||||
* <p> If this method returns <code>true</code>, subsequent calls to
|
||||
* {@link #getElementAt getElementAt} and {@link #getKeyAt getKeyAt} have
|
||||
* to succeed and return non-null objects. If this method returns
|
||||
* <code>false</code>, the table assumes that it has traversed all the
|
||||
* data contained in this model.
|
||||
*
|
||||
* @return <code>true</code> if the model is positioned on a valid row
|
||||
*/
|
||||
boolean nextRow();
|
||||
|
||||
/**
|
||||
* Return the data element for the given column and the current row. The
|
||||
* returned object will be passed to the table cell renderer as the
|
||||
* <code>value</code> argument without modifications.
|
||||
*
|
||||
* @param columnIndex the number of the column for which to get data
|
||||
* @return the object to pass to the table cell renderer for display
|
||||
* @pre columnIndex >= 0 && columnIndex < getColumnCount()
|
||||
* @post return != null
|
||||
* @see TableCellRenderer
|
||||
*/
|
||||
Object getElementAt(int columnIndex);
|
||||
|
||||
/**
|
||||
* Return the key for the given column and the current row. The key has
|
||||
* to be unique for each <em>row</em> in the table model, but does not
|
||||
* need to be unique for each row <em>and</em> column, though it may.
|
||||
* The key is passed to the table cell renderer as the <code>key</code>
|
||||
* argument.
|
||||
*
|
||||
* @param columnIndex the number of the column for which to get data
|
||||
* @return the key for the given column and the current row.
|
||||
* @pre columnIndex >= 0 && columnIndex < getColumnCount()
|
||||
* @post return != null
|
||||
* @see TableCellRenderer
|
||||
*/
|
||||
Object getKeyAt(int columnIndex);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.table;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.util.Lockable;
|
||||
|
||||
/**
|
||||
* Builds the request-specific table models. A table retrieves the data it
|
||||
* displays by asking the table model builder for a table model. This is
|
||||
* done for each request; the table does not cahce table models across
|
||||
* requests. If such caching is desired, it has to be performed by the
|
||||
* table model builder.
|
||||
*
|
||||
* <p> Typically, the table model builder will run a database query based
|
||||
* on the information contained in the page state and return the result of
|
||||
* the database query by wrapping it in a table model. The table will then
|
||||
* traverse the table model during rendering.
|
||||
*
|
||||
* <p> The table model builder is automatically locked by the table to
|
||||
* which it was added either through one of the {@link
|
||||
* com.arsdigita.bebop.Table Table} constructors or with a call to {@link
|
||||
* com.arsdigita.bebop.Table#setModelBuilder}.
|
||||
*
|
||||
* @see com.arsdigita.bebop.Table Table
|
||||
* @see TableModel
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface TableModelBuilder extends Lockable {
|
||||
|
||||
|
||||
/**
|
||||
* Return a table model for the request represented by
|
||||
* <code>s</code>. The table model contains all the data that is to be
|
||||
* displayed in a table. The returned table model is used only during
|
||||
* the duration of that request.
|
||||
*
|
||||
* @param t the table which will use this table model
|
||||
* @param s represents the current request
|
||||
* @return the data to be displayed in the table
|
||||
* @pre t != null
|
||||
* @pre s != null
|
||||
* @post return != null
|
||||
*/
|
||||
TableModel makeModel(Table t, PageState s);
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.tree;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
|
||||
/**
|
||||
* The interface
|
||||
* describes how a tree node (component) can be rendered.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @author Tri Tran
|
||||
*
|
||||
* @see TreeModel
|
||||
* @see TreeNode
|
||||
* @see Tree
|
||||
* @version $Id$ */
|
||||
public class DefaultTreeCellRenderer implements TreeCellRenderer {
|
||||
|
||||
/**
|
||||
* Returns node component to be displayed. The component's
|
||||
* <code>generateXML</code> or <code>print</code> is called
|
||||
* to render the node.
|
||||
*
|
||||
* @param tree the <code>Tree</code> in which this node is being displayed
|
||||
* @param state represents the state of the current request
|
||||
* @param value the object returned by the TreeModel for that node,
|
||||
* such as pretty name
|
||||
* @param isSelected true if the node is selected
|
||||
* @param isExpanded true if the node is expanded (not collapsed)
|
||||
* @param isLeaf true if the node is a leaf node (no children)
|
||||
* @param key the object uniquely identify that node (primary key)
|
||||
* @return the component used to generate the output for the node item
|
||||
*/
|
||||
public Component getComponent (Tree tree, PageState state, Object value,
|
||||
boolean isSelected, boolean isExpanded,
|
||||
boolean isLeaf, Object key) {
|
||||
Label l = new Label(value.toString());
|
||||
// Bold if selected
|
||||
if (isSelected) {
|
||||
l.setFontWeight(Label.BOLD);
|
||||
return l;
|
||||
}
|
||||
// Currently, we are not doing anything special here for
|
||||
// collapsed/expanded node, or leaf node... Also not doing anything
|
||||
// fancy with node's key. We are leaving this to Tree.java for now
|
||||
// to set the appropriate attributes...
|
||||
return new ControlLink(l);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.tree;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
|
||||
/**
|
||||
* The interface
|
||||
* describes how a tree node (component) can be rendered.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @author Tri Tran
|
||||
*
|
||||
* @see TreeModel
|
||||
* @see TreeNode
|
||||
* @see Tree
|
||||
* @version $Id$ */
|
||||
public interface TreeCellRenderer {
|
||||
|
||||
/**
|
||||
* Returns node component to be displayed. The component's
|
||||
* <code>generateXML</code> or <code>print</code> is called
|
||||
* to render the node.
|
||||
*
|
||||
* @param tree the <code>Tree</code> in which this node is being displayed
|
||||
* @param state represents the state of the current request
|
||||
* @param value the object returned by the TreeModel for that node
|
||||
* @param isSelected true if the node is selected
|
||||
* @param isExpanded true if the node is expanded (not collapsed)
|
||||
* @param isLeaf true if the node is a leaf node (no children)
|
||||
* @param key the object uniquely identify that node (primary key)
|
||||
* @return the component used to generate the output for the node item
|
||||
*/
|
||||
Component getComponent (Tree tree, PageState state, Object value,
|
||||
boolean isSelected, boolean isExpanded,
|
||||
boolean isLeaf, Object key);
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.tree;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* The interface
|
||||
* describes a model for a tree structure.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @author Stanislav Freidin
|
||||
* @author Tri Tran
|
||||
*
|
||||
* @version $Id$ */
|
||||
public interface TreeModel {
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the root node of the tree, passing
|
||||
* in PageState for permissioning purposes
|
||||
*/
|
||||
TreeNode getRoot(PageState data);
|
||||
|
||||
/**
|
||||
* Check whether the node has children
|
||||
*/
|
||||
boolean hasChildren(TreeNode n, PageState data);
|
||||
|
||||
/**
|
||||
* Check whether a given node has children, passing
|
||||
* in PageState for permissioning purposes
|
||||
*/
|
||||
Iterator getChildren(TreeNode n, PageState data);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.tree;
|
||||
|
||||
import com.arsdigita.bebop.Tree;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.util.Lockable;
|
||||
|
||||
/**
|
||||
* The interface builds a
|
||||
* {@link TreeModel} for a {@link Tree}.
|
||||
*
|
||||
* @author Stanislav Freidin
|
||||
*
|
||||
* @version $Id$ */
|
||||
public interface TreeModelBuilder extends Lockable {
|
||||
|
||||
|
||||
/**
|
||||
* Builds a {@link TreeModel} to be used in the current request
|
||||
*
|
||||
* @param t The {@link Tree} that will use the model
|
||||
* @param s The page state
|
||||
*/
|
||||
TreeModel makeModel(Tree t, PageState s);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.tree;
|
||||
|
||||
/**
|
||||
* The interface
|
||||
* describes a node for a tree.
|
||||
*
|
||||
* @author David Lutterkort
|
||||
* @author Stanislav Freidin
|
||||
* @author Tri Tran
|
||||
*
|
||||
* @version $Id$ */
|
||||
public interface TreeNode {
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a unique ID representing the node
|
||||
*/
|
||||
Object getKey();
|
||||
|
||||
/**
|
||||
* Get the element of the tree node. The concrete type
|
||||
* of the object returned is specific to each implementation
|
||||
* of the <code>TreeModel</code> and should be documented
|
||||
* there.
|
||||
*
|
||||
* @return the element for the tree node
|
||||
*/
|
||||
Object getElement();
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.dispatcher;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
* <tt>AccessDeniedException</tt> is the runtime exception that is thrown
|
||||
* whenever the current user does not have access to the requested resources.
|
||||
*
|
||||
* @author Michael Pih
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AccessDeniedException extends RuntimeException {
|
||||
|
||||
|
||||
public final static String ACCESS_DENIED =
|
||||
"com.arsdigita.cms.dispatcher.AccessDeniedException";
|
||||
|
||||
|
||||
// The default error detail message.
|
||||
private final static String ERROR_MSG = "Access Denied";
|
||||
|
||||
// The URL where the AccessDeniedException is thrown.
|
||||
private String m_url;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an AccessDeniedException with the default detail message.
|
||||
*/
|
||||
public AccessDeniedException() {
|
||||
this(ERROR_MSG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AccessDeniedException with the specified detail message.
|
||||
*
|
||||
* @param msg The error detail message
|
||||
*/
|
||||
public AccessDeniedException(String msg) {
|
||||
super(msg);
|
||||
|
||||
// Try and fetch the current request URL.
|
||||
HttpServletRequest request = DispatcherHelper.getRequest();
|
||||
if ( request != null ) {
|
||||
m_url = DispatcherHelper.getRequest().getRequestURI();
|
||||
request.setAttribute(ACCESS_DENIED, m_url);
|
||||
} else {
|
||||
m_url = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the URL where the AccessDeniedException originated.
|
||||
*
|
||||
* @return The original URL
|
||||
*/
|
||||
public String getOriginalURL() {
|
||||
return m_url;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.toolbox.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.SequentialMap;
|
||||
import com.arsdigita.xml.Element;
|
||||
import java.util.Iterator;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class ComponentMap extends SimpleComponent
|
||||
implements Resettable {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(ComponentMap.class);
|
||||
|
||||
private final SequentialMap m_components;
|
||||
|
||||
public ComponentMap() {
|
||||
m_components = new SequentialMap();
|
||||
}
|
||||
|
||||
public final Iterator children() {
|
||||
return m_components.values().iterator();
|
||||
}
|
||||
|
||||
public void reset(final PageState state) {
|
||||
s_log.debug("Resetting my children");
|
||||
|
||||
final Iterator iter = children();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final Object component = iter.next();
|
||||
|
||||
if (component instanceof Resettable) {
|
||||
((Resettable) component).reset(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void put(final Object key, final Component component) {
|
||||
Assert.isUnlocked(this);
|
||||
Assert.exists(key, Object.class);
|
||||
|
||||
m_components.put(key, component);
|
||||
}
|
||||
|
||||
public final Component get(final Object key) {
|
||||
return (Component) m_components.get(key);
|
||||
}
|
||||
|
||||
public final boolean containsKey(final Object key) {
|
||||
return m_components.containsKey(key);
|
||||
}
|
||||
|
||||
public final boolean containsValue(final Component component) {
|
||||
return m_components.containsValue(component);
|
||||
}
|
||||
|
||||
public abstract void generateXML(final PageState state,
|
||||
final Element parent);
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.toolbox.ui;
|
||||
|
||||
import static com.arsdigita.bebop.Component.*;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* <p>A simple layout panel with top, bottom, left, right, and body
|
||||
* sections.</p>
|
||||
*
|
||||
* @author Justin Ross <jross@redhat.com>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LayoutPanel extends ComponentMap {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(LayoutPanel.class);
|
||||
|
||||
public final void setTop(final Component top) {
|
||||
put("top", top);
|
||||
}
|
||||
|
||||
public final void setLeft(final Component left) {
|
||||
put("left", left);
|
||||
}
|
||||
|
||||
public final void setBody(final Component body) {
|
||||
put("body", body);
|
||||
}
|
||||
|
||||
public final void setRight(final Component right) {
|
||||
put("right", right);
|
||||
}
|
||||
|
||||
public final void setBottom(final Component bottom) {
|
||||
put("bottom", bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
if (isVisible(state)) {
|
||||
final Element layout = parent.newChildElement
|
||||
("bebop:layoutPanel", BEBOP_XML_NS);
|
||||
|
||||
section(state, layout, "top");
|
||||
section(state, layout, "left");
|
||||
section(state, layout, "body");
|
||||
section(state, layout, "right");
|
||||
section(state, layout, "bottom");
|
||||
}
|
||||
}
|
||||
|
||||
private void section(final PageState state,
|
||||
final Element parent,
|
||||
final String key) {
|
||||
final Component section = get(key);
|
||||
|
||||
if (section != null) {
|
||||
final Element elem = parent.newChildElement
|
||||
("bebop:" + key, BEBOP_XML_NS);
|
||||
|
||||
section.generateXML(state, elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
/**
|
||||
* Centralize place for all constants used in the admin UI.
|
||||
*
|
||||
* @author David Dao
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
interface AdminConstants {
|
||||
|
||||
/**
|
||||
* The XML namespace used by admin components.
|
||||
*/
|
||||
String ADMIN_XML_NS = "http://www.arsdigita.com/admin-ui/1.0";
|
||||
|
||||
/**
|
||||
* Globalization resource for admin ui.
|
||||
*/
|
||||
String BUNDLE_NAME = "com.arsdigita.ui.admin.AdminResources";
|
||||
|
||||
/**
|
||||
* Navigational dimension bar labels.
|
||||
*/
|
||||
// Label MY_WORKSPACE_LABEL = new Label
|
||||
// (new GlobalizedMessage("ui.admin.nav.workspace",
|
||||
// BUNDLE_NAME));
|
||||
// Label LOG_OUT_LABEL = new Label
|
||||
// (new GlobalizedMessage("ui.admin.nav.logout",
|
||||
// BUNDLE_NAME));
|
||||
/**
|
||||
* Administration page title
|
||||
*/
|
||||
Label PAGE_TITLE_LABEL = new Label(new GlobalizedMessage("ui.admin.dispatcher.title",
|
||||
BUNDLE_NAME));
|
||||
|
||||
/**
|
||||
* Administration main tab names.
|
||||
*/
|
||||
Label USER_TAB_TITLE = new Label(new GlobalizedMessage("ui.admin.tab.user",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label GROUP_TAB_TITLE = new Label(new GlobalizedMessage("ui.admin.tab.group",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label APPLICATIONS_TAB_TITLE = new Label(new GlobalizedMessage("ui.admin.tab.applications",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label SYSINFO_TAB_TITLE = new Label(new GlobalizedMessage("ui.admin.tab.sysinfo.title", BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage USER_NAVBAR_TITLE = new GlobalizedMessage("ui.admin.tab.user.navbartitle",
|
||||
BUNDLE_NAME);
|
||||
|
||||
/**
|
||||
* Tabbed pane indices
|
||||
*/
|
||||
int USER_TAB_INDEX = 2;
|
||||
int GROUP_TAB_INDEX = 3;
|
||||
|
||||
/**
|
||||
* User tab name
|
||||
*/
|
||||
Label USER_TAB_SUMMARY = new Label(new GlobalizedMessage("ui.admin.tab.user.summary",
|
||||
BUNDLE_NAME));
|
||||
Label USER_TAB_BROWSE = new Label(new GlobalizedMessage("ui.admin.tab.user.browse",
|
||||
BUNDLE_NAME));
|
||||
Label USER_TAB_SEARCH = new Label(new GlobalizedMessage("ui.admin.tab.user.search",
|
||||
BUNDLE_NAME));
|
||||
Label USER_TAB_CREATE_USER = new Label(new GlobalizedMessage("ui.admin.tab.user.createuser",
|
||||
BUNDLE_NAME));
|
||||
|
||||
int USER_TAB_SUMMARY_INDEX = 0;
|
||||
int USER_TAB_BROWSE_INDEX = 1;
|
||||
int USER_TAB_SEARCH_INDEX = 2;
|
||||
int USER_TAB_CREATE_USER_INDEX = 3;
|
||||
|
||||
/**
|
||||
* Global state parameters.
|
||||
*/
|
||||
BigDecimalParameter GROUP_ID_PARAM = new BigDecimalParameter("group_id");
|
||||
|
||||
BigDecimalParameter APPLICATIONS_ID_PARAM = new BigDecimalParameter("application_id");
|
||||
|
||||
BigDecimalParameter USER_ID_PARAM = new BigDecimalParameter("user_id");
|
||||
|
||||
/**
|
||||
* User summary panel.
|
||||
*/
|
||||
Label SUMMARY_PANEL_HEADER = new Label(
|
||||
new GlobalizedMessage("ui.admin.user.summarypanel.header", BUNDLE_NAME));
|
||||
|
||||
Label CREATE_USER_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.summarypanel.createUser", BUNDLE_NAME));
|
||||
|
||||
Label TOTAL_USERS_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.summarypanel.totalusers", BUNDLE_NAME));
|
||||
|
||||
/**
|
||||
* User browse panel.
|
||||
*/
|
||||
Label BROWSE_USER_PANEL_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.browsepanel.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_INFO_LABEL = new Label(new GlobalizedMessage("ui.admin.user.userinfo.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_EDIT_PANEL_HEADER = new Label(new GlobalizedMessage("ui.admin.user.useredit.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_GROUP_PANEL_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.groupmembership.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_DELETE_FAILED_PANEL_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.action.delete.failed.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_PASSWORD_PANEL_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.password.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_ACTION_PANEL_HEADER = new Label(new GlobalizedMessage("ui.admin.user.action.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_ACTION_CONTINUE = new Label(new GlobalizedMessage("ui.admin.user.action.continue",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_DELETE_LABEL = new Label(new GlobalizedMessage("ui.admin.user.delete.label",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_BAN_LABEL = new Label(new GlobalizedMessage("ui.admin.user.ban.label",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_UNBAN_LABEL = new Label(new GlobalizedMessage("ui.admin.user.unban.label",
|
||||
BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage USER_DELETE_CONFIRMATION = new GlobalizedMessage(
|
||||
"ui.admin.user.delete.confirm", BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_BAN_CONFIRMATION = new GlobalizedMessage("ui.admin.user.ban.confirm",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_UNBAN_CONFIRMATION = new GlobalizedMessage("ui.admin.user.unban.confirm",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_DELETE_FAILED_MSG = new GlobalizedMessage(
|
||||
"ui.admin.user.delete.failed.label", BUNDLE_NAME);
|
||||
|
||||
Label USER_TAB_EXTREME_ACTION_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.browsepanel.extremeaction",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label UPDATE_USER_PASSWORD_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.browsepanel.updatePassword",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label BECOME_USER_LABEL = new Label(
|
||||
new GlobalizedMessage("ui.admin.user.browsepanel.becomeUser",
|
||||
BUNDLE_NAME));
|
||||
|
||||
/**
|
||||
* Create new user panel.
|
||||
*/
|
||||
Label CREATE_USER_PANEL_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.createpanel.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
/**
|
||||
* User search panel.
|
||||
*/
|
||||
Label SEARCH_PANEL_HEADER = new Label(new GlobalizedMessage("ui.admin.user.search.header",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label PASSWORD_FORM_LABEL_PASSWORD = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userpasswordform.passwordlabel",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label PASSWORD_FORM_LABEL_CONFIRMATION_PASSWORD = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userpasswordform.confirmpasswordlabel",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label PASSWORD_FORM_LABEL_QUESTION = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userpasswordform.question",
|
||||
BUNDLE_NAME), false);
|
||||
|
||||
Label PASSWORD_FORM_LABEL_ANSWER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userpasswordform.answer",
|
||||
BUNDLE_NAME), false);
|
||||
|
||||
GlobalizedMessage PASSWORD_FORM_SUBMIT = new GlobalizedMessage(
|
||||
"ui.admin.user.userpasswordform.submit",
|
||||
BUNDLE_NAME);
|
||||
|
||||
/**
|
||||
* Constants for user add/edit form.
|
||||
*/
|
||||
String USER_FORM_ADD = "user-add-form";
|
||||
String USER_FORM_EDIT = "user-edit-form";
|
||||
String USER_FORM_INPUT_FIRST_NAME = "firstname";
|
||||
String USER_FORM_INPUT_LAST_NAME = "lastname";
|
||||
String USER_FORM_INPUT_PASSWORD = "password";
|
||||
String USER_FORM_INPUT_PASSWORD_CONFIRMATION = "password_confirmation";
|
||||
String USER_FORM_INPUT_QUESTION = "question";
|
||||
String USER_FORM_INPUT_ANSWER = "answer";
|
||||
String USER_FORM_INPUT_PRIMARY_EMAIL = "email";
|
||||
String USER_FORM_INPUT_ADDITIONAL_EMAIL = "additional_email";
|
||||
String USER_FORM_INPUT_SCREEN_NAME = "screenname";
|
||||
String USER_FORM_INPUT_SSO = "sso_login";
|
||||
String USER_FORM_INPUT_URL = "url";
|
||||
String USER_FORM_INPUT_URL_DEFAULT = "http://";
|
||||
|
||||
Label USER_FORM_LABEL_FIRST_NAME = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.firstname",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_LAST_NAME = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.lastname",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_PASSWORD = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.password",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_PASSWORD_CONFIRMATION = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.confirmation",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_QUESTION = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.question",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_ANSWER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.answer",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_PRIMARY_EMAIL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.primaryemail",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_ADDITIONAL_EMAIL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.additionalemail",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_ADDITIONAL_EMAIL_LIST = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.additionalemaillist",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_SCREEN_NAME = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.screenname",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_SSO = new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.ssologinname",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_LABEL_URL = new Label(new GlobalizedMessage("ui.admin.user.addeditform.url",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label USER_FORM_DELETE_ADDITIONAL_EMAIL = new Label(
|
||||
new GlobalizedMessage("ui.admin.user.addeditform.deleteemail",
|
||||
BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage USER_FORM_SUBMIT = new GlobalizedMessage("ui.admin.user.addeditform.submit",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_FORM_ERROR_SCREEN_NAME_NOT_UNIQUE = new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.error.screenname.notunique",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_FORM_ERROR_PRIMARY_EMAIL_NOT_UNIQUE = new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.error.primaryemail.notunique",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_FORM_ERROR_PASSWORD_NOT_MATCH = new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.error.password.notmatch",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_FORM_ERROR_ANSWER_NULL = new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.error.answer.null",
|
||||
BUNDLE_NAME);
|
||||
|
||||
GlobalizedMessage USER_FORM_ERROR_ANSWER_WHITESPACE = new GlobalizedMessage(
|
||||
"ui.admin.user.addeditform.error.answer.whitespace",
|
||||
BUNDLE_NAME);
|
||||
|
||||
/**
|
||||
* Constants for group add/edit form.
|
||||
*/
|
||||
String GROUP_FORM_ADD = "group-add-form";
|
||||
String GROUP_FORM_EDIT = "group-edit-form";
|
||||
String GROUP_FORM_INPUT_NAME = "name";
|
||||
String GROUP_FORM_INPUT_PRIMARY_EMAIL = "email";
|
||||
|
||||
Label GROUP_FORM_LABEL_NAME = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.addeditform.namelabel",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label GROUP_FORM_LABEL_PRIMARY_EMAIL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.addeditform.primaryemaillabel",
|
||||
BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage GROUP_FORM_SUBMIT
|
||||
= new GlobalizedMessage("ui.admin.groups.addeditform.submit", BUNDLE_NAME);
|
||||
|
||||
/**
|
||||
* Constants for group administration tab.
|
||||
*/
|
||||
Label GROUP_ACTION_CONTINUE = new Label(new GlobalizedMessage("ui.admin.groups.actioncontinue",
|
||||
BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage GROUP_DELETE_FAILED_MSG = new GlobalizedMessage(
|
||||
"ui.admin.groups.groupdeletefailed",
|
||||
BUNDLE_NAME);
|
||||
|
||||
Label GROUP_INFORMATION_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.groupinformation",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label SUBGROUP_HEADER = new Label(new GlobalizedMessage("ui.admin.groups.subgroups",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label GROUP_EDIT_HEADER = new Label(new GlobalizedMessage("ui.admin.groups.groupedit",
|
||||
BUNDLE_NAME));
|
||||
Label ADD_SUBGROUP_LABEL = new Label(new GlobalizedMessage("ui.admin.groups.add",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label SUBMEMBER_HEADER = new Label(new GlobalizedMessage("ui.admin.groups.submembers",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label DELETE_GROUP_LABEL = new Label(new GlobalizedMessage("ui.admin.groups.delete",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label GROUP_EXTREME_ACTIONS_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.extremeaction",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label GROUP_DELETE_FAILED_HEADER = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.deletefailed",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label ADD_GROUP_LABEL = new Label(new GlobalizedMessage("ui.admin.groups.addgrouplabel",
|
||||
BUNDLE_NAME));
|
||||
Label EDIT_GROUP_LABEL = new Label(new GlobalizedMessage("ui.admin.groups.edit",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label SUBGROUP_COUNT_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.subgroupcountlabel",
|
||||
BUNDLE_NAME));
|
||||
String GROUP_DELETE_CONFIRMATION = "Are you sure you want to delete this group?";
|
||||
|
||||
Label ADD_SUBMEMBER_LABEL = new Label(new GlobalizedMessage("ui.admin.groups.addsubmemberlabel",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label REMOVE_SUBMEMBER_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.removesubmemberlabel",
|
||||
BUNDLE_NAME));
|
||||
Label ADD_EXISTING_GROUP_TO_SUBGROUPS_LABEL = new Label(new GlobalizedMessage(
|
||||
"ui.admin.groups.addExisting",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label REMOVE_SUBGROUP_LABEL = new Label(new GlobalizedMessage("ui.admin.groups.removeExisting",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label GROUP_SEARCH_LABEL = new Label(
|
||||
new GlobalizedMessage("ui.admin.groups.search", BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage SEARCH_BUTTON = new GlobalizedMessage("ui.admin.groups.button.search",
|
||||
BUNDLE_NAME);
|
||||
|
||||
Label GROUP_NO_RESULTS = new Label(new GlobalizedMessage("ui.admin.groups.searchForm.noResults",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label FOUND_GROUPS_TITLE = new Label(new GlobalizedMessage("ui.admin.groups.found.title",
|
||||
BUNDLE_NAME));
|
||||
|
||||
Label PICK_GROUPS = new Label(new GlobalizedMessage("ui.admin.groups.select.explanation",
|
||||
BUNDLE_NAME));
|
||||
|
||||
GlobalizedMessage SAVE_BUTTON = new GlobalizedMessage("ui.admin.save", BUNDLE_NAME);
|
||||
|
||||
String SEARCH_QUERY = "query";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Peter Boy <pb@zes.uni-bremen.de> All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageFactory;
|
||||
import com.arsdigita.bebop.TabbedPane;
|
||||
import com.arsdigita.dispatcher.AccessDeniedException;
|
||||
import com.arsdigita.dispatcher.DispatcherHelper;
|
||||
import com.arsdigita.templating.Templating;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
import com.arsdigita.web.BaseApplicationServlet;
|
||||
import com.arsdigita.web.LoginSignal;
|
||||
import com.arsdigita.xml.Document;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.CcmSessionContext;
|
||||
import org.libreccm.core.PermissionManager;
|
||||
import org.libreccm.core.Privilege;
|
||||
import org.libreccm.core.PrivilegeRepository;
|
||||
import org.libreccm.core.Subject;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Web Developer Support Application Servlet class, central entry point to
|
||||
* create and process the applications UI.
|
||||
*
|
||||
* We should have subclassed BebopApplicationServlet but couldn't overwrite
|
||||
* doService() method to add permission checking. So we use our own page
|
||||
* mapping. The general logic is the same as for BebopApplicationServlet.
|
||||
*
|
||||
* {
|
||||
*
|
||||
* @see com.arsdigita.bebop.page.BebopApplicationServlet}
|
||||
*
|
||||
* @author Jens Pelzetter
|
||||
* @author pb
|
||||
*/
|
||||
public class AdminServlet extends BaseApplicationServlet implements
|
||||
AdminConstants {
|
||||
|
||||
private static final long serialVersionUID = -3912367600768871630L;
|
||||
/**
|
||||
* Logger instance for debugging
|
||||
*/
|
||||
//private static final Logger LOGGER = Logger.getLogger(AdminServlet.class.getName());
|
||||
/**
|
||||
* URL (pathinfo) -> Page object mapping. Based on it (and the http request
|
||||
* url) the doService method to selects a page to display
|
||||
*/
|
||||
private final Map<String, Page> pages = new HashMap<String, Page>();
|
||||
|
||||
/**
|
||||
* User extension point, overwrite this method to setup a URL - page mapping
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void doInit() throws ServletException {
|
||||
addPage("/", buildAdminIndexPage()); // index page at address ~/ds
|
||||
// addPage("/index.jsp", buildIndexPage()); // index page at address ~/ds
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Central service method, checks for required permission, determines the
|
||||
* requested page and passes the page object to PresentationManager.
|
||||
*
|
||||
* @param sreq
|
||||
* @param sresp
|
||||
* @param app
|
||||
*
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public final void doService(final HttpServletRequest sreq,
|
||||
final HttpServletResponse sresp,
|
||||
final CcmApplication app) throws
|
||||
ServletException, IOException {
|
||||
// /////// Some preparational steps ///////////////
|
||||
/* Determine access privilege: only logged in users may access DS */
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final CcmSessionContext sessionContext;
|
||||
try {
|
||||
sessionContext = cdiUtil.findBean(
|
||||
CcmSessionContext.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup session context", ex);
|
||||
}
|
||||
final Subject subject = sessionContext.getCurrentSubject();
|
||||
if (subject == null) {
|
||||
throw new LoginSignal(sreq);
|
||||
}
|
||||
|
||||
final PrivilegeRepository privilegeRepository;
|
||||
try {
|
||||
privilegeRepository = cdiUtil.findBean(PrivilegeRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup PrivilegeRepository", ex);
|
||||
}
|
||||
final Privilege adminPrivilege = privilegeRepository.retrievePrivilege(
|
||||
"admin");
|
||||
|
||||
final PermissionManager permissionManager;
|
||||
try {
|
||||
permissionManager = cdiUtil.findBean(PermissionManager.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to look up PermissionManager", ex);
|
||||
}
|
||||
|
||||
if (!permissionManager.isPermitted(adminPrivilege, null, subject)) {
|
||||
throw new AccessDeniedException("User is not an administrator");
|
||||
}
|
||||
|
||||
/* Want admin to always show the latest stuff... */
|
||||
DispatcherHelper.cacheDisable(sresp);
|
||||
|
||||
// /////// Everything OK here - DO IT ///////////////
|
||||
String pathInfo = sreq.getPathInfo();
|
||||
Assert.exists(pathInfo, "String pathInfo");
|
||||
if (pathInfo.length() > 1 && pathInfo.endsWith("/")) {
|
||||
/* NOTE: ServletAPI specifies, pathInfo may be empty or will
|
||||
* start with a '/' character. It currently carries a
|
||||
* trailing '/' if a "virtual" page, i.e. not a real jsp, but
|
||||
* result of a servlet mapping. But Application requires url
|
||||
* NOT to end with a trailing '/' for legacy free applications. */
|
||||
pathInfo = pathInfo.substring(0, pathInfo.length() - 1);
|
||||
}
|
||||
|
||||
final Page page = pages.get(pathInfo);
|
||||
if (page == null) {
|
||||
sresp.sendError(404, "No such page for path " + pathInfo);
|
||||
} else {
|
||||
final Document doc = page.buildDocument(sreq, sresp);
|
||||
Templating.getPresentationManager().servePage(doc, sreq, sresp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one pair of Url - Page to the internal hash map, used as a cache.
|
||||
*
|
||||
* @param pathInfo url stub for a page to display
|
||||
* @param page Page object to display
|
||||
*/
|
||||
private void addPage(final String pathInfo, final Page page) {
|
||||
Assert.exists(pathInfo, String.class);
|
||||
Assert.exists(page, Page.class);
|
||||
// Current Implementation requires pathInfo to start with a leading '/'
|
||||
// SUN Servlet API specifies: "PathInfo *may be empty* or will start
|
||||
// with a '/' character."
|
||||
Assert.isTrue(pathInfo.charAt(0) == '/', "path starts not with '/'");
|
||||
|
||||
pages.put(pathInfo, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index page for the admin section
|
||||
*/
|
||||
private Page buildAdminIndexPage() {
|
||||
|
||||
final Page page = PageFactory.buildPage("admin", PAGE_TITLE_LABEL);
|
||||
page.addGlobalStateParam(USER_ID_PARAM);
|
||||
page.addGlobalStateParam(GROUP_ID_PARAM);
|
||||
page.addGlobalStateParam(APPLICATIONS_ID_PARAM);
|
||||
|
||||
/*
|
||||
* Create User split panel.
|
||||
* Note: Will change soon.
|
||||
*/
|
||||
//final AdminSplitPanel userSplitPanel = new AdminSplitPanel(USER_NAVBAR_TITLE);
|
||||
// final UserBrowsePane browsePane = new UserBrowsePane();
|
||||
// userSplitPanel.addTab(USER_TAB_SUMMARY, new UserSummaryPane(userSplitPanel, browsePane));
|
||||
// userSplitPanel.addTab(USER_TAB_BROWSE, browsePane);
|
||||
// userSplitPanel.addTab(USER_TAB_SEARCH, new UserSearchPane(userSplitPanel, browsePane));
|
||||
// userSplitPanel.addTab(USER_TAB_CREATE_USER, new CreateUserPane(userSplitPanel));
|
||||
// Create the Admin's page tab bar
|
||||
final TabbedPane tabbedPane = new TabbedPane();
|
||||
tabbedPane.setIdAttr("page-body");
|
||||
|
||||
/**
|
||||
* Create and add info tab
|
||||
*/
|
||||
//tabbedPane.addTab(INFO_TAB_TITLE, new AdminInfoTab());
|
||||
/*
|
||||
* Create and add the user and group tabs.
|
||||
*/
|
||||
//tabbedPane.addTab(USER_TAB_TITLE, userSplitPanel);
|
||||
final GroupAdministrationTab groupAdminTab
|
||||
= new GroupAdministrationTab();
|
||||
tabbedPane.addTab(USER_TAB_TITLE, new UserAdministrationTab(tabbedPane,
|
||||
groupAdminTab));
|
||||
tabbedPane.addTab(GROUP_TAB_TITLE, groupAdminTab);
|
||||
|
||||
/*
|
||||
* Create application administration panel
|
||||
*/
|
||||
// ToDo tabbedPane.addTab(APPLICATIONS_TAB_TITLE,
|
||||
// ToDo new ApplicationsAdministrationTab());
|
||||
|
||||
// browsePane.setTabbedPane(tabbedPane);
|
||||
// browsePane.setGroupAdministrationTab(groupAdminTab);
|
||||
//Add System information tab
|
||||
// ToDo tabbedPane.addTab(SYSINFO_TAB_TITLE, new SystemInformationTab());
|
||||
|
||||
page.add(tabbedPane);
|
||||
page.lock();
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.list.ListCellRenderer;
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.EmailAddress;
|
||||
import org.libreccm.core.User;
|
||||
import org.libreccm.core.UserRepository;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to display and manage the list of additional email addresses
|
||||
* for a user.
|
||||
*/
|
||||
|
||||
class EmailList extends List
|
||||
implements ListCellRenderer,
|
||||
AdminConstants,
|
||||
ActionListener
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public EmailList() {
|
||||
setModelBuilder(new EmailListModelBuilder());
|
||||
setCellRenderer(this);
|
||||
addActionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param list
|
||||
* @param state
|
||||
* @param value
|
||||
* @param key
|
||||
* @param index
|
||||
* @param isSelected
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Component getComponent(List list,
|
||||
PageState state,
|
||||
Object value,
|
||||
String key,
|
||||
int index,
|
||||
boolean isSelected)
|
||||
{
|
||||
SimpleContainer c = new SimpleContainer();
|
||||
|
||||
if (value != null) {
|
||||
ControlLink link =
|
||||
new ControlLink(USER_FORM_DELETE_ADDITIONAL_EMAIL);
|
||||
link.setClassAttr("deleteLink");
|
||||
|
||||
c.add(new Label(value.toString()));
|
||||
c.add(link);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* This actionlister is executed when the user clicks the "delete"
|
||||
* link next to an email address.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed (final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final Long userId = (Long) state.getValue(USER_ID_PARAM);
|
||||
if (userId != null) {
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
final User user = userRepository.findById(userId);
|
||||
if (user == null) {
|
||||
return;
|
||||
} else {
|
||||
final String email = (String) getSelectedKey(state);
|
||||
|
||||
for(EmailAddress addr : user.getEmailAddresses()) {
|
||||
if (addr.getAddress().equals(email)) {
|
||||
user.removeEmailAddress(addr);
|
||||
}
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class EmailListModelBuilder extends LockableImpl
|
||||
implements ListModelBuilder,
|
||||
AdminConstants
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private class EmailListModel implements ListModel {
|
||||
private Iterator m_emails;
|
||||
private EmailAddress m_currentEmail;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param emails
|
||||
*/
|
||||
public EmailListModel(Iterator emails) {
|
||||
m_emails = emails;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean next() {
|
||||
if (m_emails.hasNext()) {
|
||||
m_currentEmail = (EmailAddress) m_emails.next();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getKey() {
|
||||
return m_currentEmail.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElement() {
|
||||
return m_currentEmail.getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param l
|
||||
* @param state
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ListModel makeModel(List l, PageState state) {
|
||||
|
||||
final Long userId = (Long) state.getValue(USER_ID_PARAM);
|
||||
if (userId == null) {
|
||||
return null;
|
||||
} else {
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
final User user = userRepository.findById(userId);
|
||||
|
||||
return new EmailListModel(user.getEmailAddresses().iterator());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
package com.arsdigita.ui.admin;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.bebop.SegmentedPanel;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
/**
|
||||
* Series of screens required for adding existing groups as subgroups - based on
|
||||
* existing functionality for adding permissions to a folder in content/admin
|
||||
*
|
||||
* @version $Id: ExistingGroupAddPane.java,v 1.4 2004/06/21 11:34:03 cgyg9330
|
||||
* Exp $
|
||||
*/
|
||||
public class ExistingGroupAddPane extends SimpleContainer implements
|
||||
AdminConstants {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(
|
||||
ExistingGroupAddPane.class);
|
||||
|
||||
private ParameterModel searchString = new StringParameter(SEARCH_QUERY);
|
||||
|
||||
private GroupSearchForm groupSearchForm;
|
||||
private SimpleContainer selectGroupsPanel;
|
||||
private SimpleContainer noResultsPanel;
|
||||
private Tree groupTree;
|
||||
private GroupAdministrationTab parentPage;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private RequestLocal parentGroup = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(final PageState ps) {
|
||||
String key = (String) groupTree.getSelectedKey(ps);
|
||||
|
||||
Group group = null;
|
||||
|
||||
if (key != null) {
|
||||
final Long id = new Long(key);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
|
||||
group = groupRepository.findById(id);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param groupTree
|
||||
* @param parentPage
|
||||
*/
|
||||
public ExistingGroupAddPane(Tree groupTree,
|
||||
GroupAdministrationTab parentPage) {
|
||||
this.groupTree = groupTree;
|
||||
this.parentPage = parentPage;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param p
|
||||
*/
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
super.register(p);
|
||||
add(getGroupSearchForm());
|
||||
add(getSelectGroupsPanel());
|
||||
add(getNoSearchResultPanel());
|
||||
|
||||
// set initial visibility of components
|
||||
p.setVisibleDefault(getGroupSearchForm(), true);
|
||||
p.setVisibleDefault(getSelectGroupsPanel(), false);
|
||||
p.setVisibleDefault(getNoSearchResultPanel(), false);
|
||||
|
||||
p.addGlobalStateParam(searchString);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GroupSearchForm getGroupSearchForm() {
|
||||
|
||||
if (groupSearchForm == null) {
|
||||
groupSearchForm = new GroupSearchForm(this);
|
||||
}
|
||||
return groupSearchForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a panel with a set of checkboxes for groups fulfilling search
|
||||
* criteria
|
||||
*/
|
||||
public SimpleContainer getSelectGroupsPanel() {
|
||||
if (selectGroupsPanel == null) {
|
||||
SelectGroups selectGroups = new SelectGroups(this,
|
||||
getGroupSearchForm());
|
||||
selectGroupsPanel = selectGroups.getPanel();
|
||||
}
|
||||
return selectGroupsPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bebop panel indicating that the user search yielded no results.
|
||||
*/
|
||||
public SimpleContainer getNoSearchResultPanel() {
|
||||
if (noResultsPanel == null) {
|
||||
Label errorMsg = GROUP_NO_RESULTS;
|
||||
errorMsg.setClassAttr("errorBullet");
|
||||
BoxPanel bp = new BoxPanel();
|
||||
bp.add(errorMsg);
|
||||
bp.add(new GroupSearchForm(this));
|
||||
noResultsPanel = new SegmentedPanel().addSegment(new Label(" "), bp);
|
||||
}
|
||||
return noResultsPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows panel with no results to user search.
|
||||
*/
|
||||
public void showNoResults(PageState s) {
|
||||
getGroupSearchForm().setVisible(s, false);
|
||||
getSelectGroupsPanel().setVisible(s, false);
|
||||
getNoSearchResultPanel().setVisible(s, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the select groups to add as subgroups panel
|
||||
*/
|
||||
public void showGroups(PageState s) {
|
||||
getGroupSearchForm().setVisible(s, false);
|
||||
getSelectGroupsPanel().setVisible(s, true);
|
||||
getNoSearchResultPanel().setVisible(s, false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* show the search form
|
||||
*/
|
||||
public void showSearch(PageState s) {
|
||||
getGroupSearchForm().setVisible(s, true);
|
||||
getSelectGroupsPanel().setVisible(s, false);
|
||||
getNoSearchResultPanel().setVisible(s, false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ParameterModel getSearchString() {
|
||||
return searchString;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GroupAdministrationTab getParentPage() {
|
||||
return parentPage;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ps
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Group getParentGroup(PageState ps) {
|
||||
return (Group) parentGroup.get(ps);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jens Pelzetter
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
/**
|
||||
* Globalization Util for admin classes
|
||||
*
|
||||
* @author Jens Pelzetter <jens@jp-digital.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GlobalizationUtil {
|
||||
|
||||
private static final String BUNDLE_NAME = "com.arsdigita.ui.admin.AdminResources";
|
||||
|
||||
public static GlobalizedMessage globalize(final String key) {
|
||||
return new GlobalizedMessage(key, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
public static GlobalizedMessage globalize(final String key, final Object[] args) {
|
||||
return new GlobalizedMessage(key, BUNDLE_NAME, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
/**
|
||||
* Add group form.
|
||||
*
|
||||
* @author David Dao
|
||||
* @version $Id$
|
||||
*/
|
||||
class GroupAddForm extends GroupForm implements FormProcessListener {
|
||||
|
||||
private Tree m_groupTree;
|
||||
private GroupAdministrationTab m_groupTab;
|
||||
|
||||
public GroupAddForm(final Tree groupTree,
|
||||
final GroupAdministrationTab tab) {
|
||||
super(GROUP_FORM_ADD);
|
||||
addProcessListener(this);
|
||||
m_groupTree = groupTree;
|
||||
m_groupTab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the form.
|
||||
*/
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
PageState ps = event.getPageState();
|
||||
|
||||
// Get super parent group.
|
||||
String key = (String) m_groupTree.getSelectedKey(ps);
|
||||
|
||||
final Group parentGroup = null;
|
||||
// if (key != null) {
|
||||
// BigDecimal parentID = new BigDecimal(key);
|
||||
//
|
||||
// try {
|
||||
// parentGroup = new Group(parentID);
|
||||
// } catch (DataObjectNotFoundException exc) {
|
||||
// // Parent group does not exist.
|
||||
// // This is normal behavior with the new group
|
||||
// // been add with no parent.
|
||||
// }
|
||||
// }
|
||||
|
||||
final Group group = new Group();
|
||||
|
||||
String name = (String) m_name.getValue(ps);
|
||||
group.setName(name);
|
||||
|
||||
// Workaround for bug #189720: there is no way to remove a
|
||||
// Party's primary email address, so we set it directly to
|
||||
// null if it's value on the form is null.
|
||||
// InternetAddress email = (InternetAddress) m_email.getValue(ps);
|
||||
// if (email != null) {
|
||||
// group.setPrimaryEmail(new EmailAddress(email.getAddress()));
|
||||
// } else {
|
||||
// //group.set("primaryEmail", null);
|
||||
// group.setPrimaryEmail(null);
|
||||
// }
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
groupRepository.save(group);
|
||||
|
||||
// if (parentGroup != null) {
|
||||
// parentGroup.addSubgroup(group);
|
||||
// parentGroup.save();
|
||||
// }
|
||||
if (m_groupTab != null) {
|
||||
m_groupTab.setGroup(ps, group);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,685 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.ActionLink;
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.bebop.SegmentedPanel;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ChangeEvent;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.list.ListCellRenderer;
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
|
||||
/**
|
||||
* Constructs the panel for administration of groups.
|
||||
*
|
||||
* @author David Dao
|
||||
*
|
||||
*/
|
||||
class GroupAdministrationTab extends LayoutPanel implements AdminConstants,
|
||||
ChangeListener {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(
|
||||
GroupAdministrationTab.class);
|
||||
private final Tree groupTree;
|
||||
private SearchAndList subMemberSearch;
|
||||
private ActionLink addSubmemberLink;
|
||||
private final Component groupInfoPanel;
|
||||
private final Component subGroupPanel;
|
||||
private final Component subMemberPanel;
|
||||
private final Component extremeActionPanel;
|
||||
private final Component groupAddPanel;
|
||||
private final Component groupEditPanel;
|
||||
private final Component groupDeleteFailedPanel;
|
||||
private final Component existingGroupAddPanel;
|
||||
private ExistingGroupAddPane m_existingGroupAdd;
|
||||
private final java.util.List<Component> panelList
|
||||
= new ArrayList<Component>();
|
||||
private final RequestLocal requestLocalGroup;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param page
|
||||
*/
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
for (int i = 0; i < panelList.size(); i++) {
|
||||
page.setVisibleDefault(panelList.get(i), false);
|
||||
}
|
||||
|
||||
page.setVisibleDefault(groupAddPanel, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param state
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Group getGroup(final PageState state) {
|
||||
return (Group) requestLocalGroup.get(state);
|
||||
}
|
||||
|
||||
public void setGroup(final PageState state, final Group group) {
|
||||
final String groupId = Long.toString(group.getSubjectId());
|
||||
requestLocalGroup.set(state, group);
|
||||
groupTree.setSelectedKey(state, groupId);
|
||||
|
||||
if (!"-1".equals(groupId)) {
|
||||
expandGroups(state, group);
|
||||
groupTree.expand("-1", state);
|
||||
}
|
||||
}
|
||||
|
||||
private void expandGroups(final PageState state, final Group group) {
|
||||
// groupTree.expand(Long.toString(group.getSubjectId()), state);
|
||||
//
|
||||
// final List< superGroups = group.getSupergroups();
|
||||
// Group superGroup;
|
||||
// while (superGroups.next()) {
|
||||
// superGroup = (Group) superGroups.getDomainObject();
|
||||
// expandGroups(state, superGroup);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public GroupAdministrationTab() {
|
||||
super();
|
||||
|
||||
setClassAttr("sidebarNavPanel");
|
||||
setAttribute("navbar-title", "Groups");
|
||||
|
||||
requestLocalGroup = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(final PageState state) {
|
||||
String key = (String) groupTree.getSelectedKey(state);
|
||||
|
||||
Group group;
|
||||
if (key != null) {
|
||||
final long id = Long.parseLong(key);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil
|
||||
.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
|
||||
group = groupRepository.findById(id);
|
||||
|
||||
return group;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
setClassAttr("navbar");
|
||||
|
||||
groupTree = new Tree(new GroupTreeModelBuilder());
|
||||
groupTree.addChangeListener(this);
|
||||
setLeft(groupTree);
|
||||
|
||||
final SegmentedPanel body = new SegmentedPanel();
|
||||
body.setClassAttr("main");
|
||||
|
||||
groupInfoPanel = buildGroupInfoPanel(body);
|
||||
panelList.add(groupInfoPanel);
|
||||
|
||||
groupEditPanel = buildGroupEditPanel(body);
|
||||
panelList.add(groupEditPanel);
|
||||
|
||||
subGroupPanel = buildSubGroupPanel(body);
|
||||
panelList.add(subGroupPanel);
|
||||
|
||||
groupAddPanel = buildGroupAddPanel(body);
|
||||
panelList.add(groupAddPanel);
|
||||
|
||||
existingGroupAddPanel = buildExistingGroupAddPanel(body);
|
||||
panelList.add(existingGroupAddPanel);
|
||||
|
||||
subMemberPanel = buildMemberListPanel(body);
|
||||
panelList.add(subMemberPanel);
|
||||
|
||||
extremeActionPanel = buildExtremeActionPanel(body);
|
||||
panelList.add(extremeActionPanel);
|
||||
|
||||
groupDeleteFailedPanel = buildGroupDeleteFailedPanel(body);
|
||||
panelList.add(groupDeleteFailedPanel);
|
||||
|
||||
setBody(body);
|
||||
}
|
||||
|
||||
public void displayAddGroupPanel(final PageState state) {
|
||||
hideAll(state);
|
||||
groupAddPanel.setVisible(state, true);
|
||||
}
|
||||
|
||||
private void displayAddExistingGroupPanel(final PageState state) {
|
||||
hideAll(state);
|
||||
existingGroupAddPanel.setVisible(state, true);
|
||||
}
|
||||
|
||||
public void displayEditPanel(final PageState state) {
|
||||
hideAll(state);
|
||||
groupEditPanel.setVisible(state, true);
|
||||
}
|
||||
|
||||
public void displayGroupInfoPanel(final PageState state) {
|
||||
showAll(state);
|
||||
groupEditPanel.setVisible(state, false);
|
||||
groupAddPanel.setVisible(state, false);
|
||||
groupDeleteFailedPanel.setVisible(state, false);
|
||||
existingGroupAddPanel.setVisible(state, false);
|
||||
}
|
||||
|
||||
public void displayDeleteFailedPanel(final PageState state) {
|
||||
hideAll(state);
|
||||
groupDeleteFailedPanel.setVisible(state, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void stateChanged(final ChangeEvent event) {
|
||||
|
||||
final PageState ps = event.getPageState();
|
||||
final String key = (String) groupTree.getSelectedKey(ps);
|
||||
// added cg - reset existing group add panel to the search screen
|
||||
// when a new group is selected from the tree
|
||||
m_existingGroupAdd.showSearch(ps);
|
||||
if (key == null || key.equals("-1")) {
|
||||
/**
|
||||
* If root node is selected then display add panel only.
|
||||
*/
|
||||
displayAddGroupPanel(ps);
|
||||
} else {
|
||||
displayGroupInfoPanel(ps);
|
||||
}
|
||||
ps.setValue(GROUP_ID_PARAM, new BigDecimal(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a panel to display group basic information.
|
||||
*/
|
||||
private Component buildGroupInfoPanel(final SegmentedPanel main) {
|
||||
final BoxPanel body = new BoxPanel();
|
||||
|
||||
//body.add(new GroupInfo(this));
|
||||
final ColumnPanel infoPanel = new ColumnPanel(2);
|
||||
|
||||
infoPanel.add(new Label(new GlobalizedMessage("ui.admin.groups.name",
|
||||
BUNDLE_NAME)));
|
||||
final Label nameLabel = new Label();
|
||||
nameLabel.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final Label target = (Label) event.getTarget();
|
||||
final PageState state = event.getPageState();
|
||||
final Group group = getGroup(state);
|
||||
|
||||
target.setLabel(group.getName());
|
||||
}
|
||||
|
||||
});
|
||||
infoPanel.add(nameLabel);
|
||||
body.add(infoPanel);
|
||||
|
||||
ActionLink link = new ActionLink(EDIT_GROUP_LABEL);
|
||||
link.setClassAttr("actionLink");
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState ps = e.getPageState();
|
||||
displayEditPanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
body.add(link);
|
||||
|
||||
return main.addSegment(GROUP_INFORMATION_HEADER, body);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build group edit form.
|
||||
*/
|
||||
private Component buildGroupEditPanel(final SegmentedPanel main) {
|
||||
return main.addSegment(GROUP_EDIT_HEADER, new GroupEditForm(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build panel to display direct subgroup information.
|
||||
*/
|
||||
private Component buildSubGroupPanel(final SegmentedPanel main) {
|
||||
final BoxPanel body = new BoxPanel();
|
||||
final BoxPanel labelStatus = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||
labelStatus.add(SUBGROUP_COUNT_LABEL);
|
||||
|
||||
final Label countLabel = new Label("");
|
||||
countLabel.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
// final PageState ps = event.getPageState();
|
||||
//
|
||||
// final Label target = (Label) event.getTarget();
|
||||
// Group g = getGroup(ps);
|
||||
// if (g != null) {
|
||||
// target.setLabel(String.valueOf(g.countSubgroups()));
|
||||
// }
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
final ActionLink status = new ActionLink(countLabel);
|
||||
status.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
PageState ps = event.getPageState();
|
||||
String key = (String) groupTree.getSelectedKey(ps);
|
||||
groupTree.expand(key, ps);
|
||||
}
|
||||
|
||||
});
|
||||
labelStatus.add(status);
|
||||
|
||||
body.add(labelStatus);
|
||||
|
||||
final List subGroupList = new List(new SubGroupListModelBuilder(this));
|
||||
subGroupList.setCellRenderer(new ListCellRenderer() {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final List list,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
final String key,
|
||||
final int index,
|
||||
final boolean isSelected) {
|
||||
final BoxPanel b = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||
b.add(new Label(((Group) value).getName()));
|
||||
final ControlLink removeLink = new ControlLink(
|
||||
REMOVE_SUBGROUP_LABEL);
|
||||
removeLink.setClassAttr("actionLink");
|
||||
b.add(removeLink);
|
||||
return b;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
subGroupList.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final String key = (String) ((List) event.getSource())
|
||||
.getSelectedKey(state);
|
||||
|
||||
if (key != null) {
|
||||
final Long groupId = Long.parseLong(key);
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil
|
||||
.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
|
||||
final Group group = groupRepository.findById(groupId);
|
||||
final Group parent = getGroup(state);
|
||||
if (parent != null) {
|
||||
groupRepository.save(parent);
|
||||
}
|
||||
|
||||
final BigDecimal groupID = new BigDecimal(key);
|
||||
// try {
|
||||
// final Group group = new Group(groupID);
|
||||
// final Group parent = getGroup(state);
|
||||
// if (parent != null) {
|
||||
// parent.removeSubgroup(group);
|
||||
// parent.save();
|
||||
// }
|
||||
// } catch (DataObjectNotFoundException exc) {
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
body.add(subGroupList);
|
||||
|
||||
final ActionLink addLink = new ActionLink(ADD_SUBGROUP_LABEL);
|
||||
addLink.setClassAttr("actionLink");
|
||||
addLink.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
PageState ps = event.getPageState();
|
||||
|
||||
displayAddGroupPanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
body.add(addLink);
|
||||
|
||||
// new actionlink and anonymous ActionListener class added cg
|
||||
final ActionLink addExistingLink = new ActionLink(
|
||||
ADD_EXISTING_GROUP_TO_SUBGROUPS_LABEL);
|
||||
addExistingLink.setClassAttr("actionLink");
|
||||
addExistingLink.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
LOGGER.debug("Add existing group link pressed");
|
||||
PageState ps = event.getPageState();
|
||||
displayAddExistingGroupPanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
body.add(addExistingLink);
|
||||
return main.addSegment(SUBGROUP_HEADER, body);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build group add form.
|
||||
*/
|
||||
private Component buildGroupAddPanel(final SegmentedPanel main) {
|
||||
|
||||
return main.addSegment(ADD_GROUP_LABEL,
|
||||
new GroupAddForm(groupTree, this));
|
||||
}
|
||||
|
||||
private Component buildExistingGroupAddPanel(final SegmentedPanel main) {
|
||||
m_existingGroupAdd = new ExistingGroupAddPane(groupTree, this);
|
||||
return main.addSegment(ADD_EXISTING_GROUP_TO_SUBGROUPS_LABEL,
|
||||
m_existingGroupAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build group's member panel.
|
||||
*/
|
||||
private Component buildMemberListPanel(final SegmentedPanel main) {
|
||||
|
||||
BoxPanel body = new BoxPanel() {
|
||||
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
page.setVisibleDefault(subMemberSearch, false);
|
||||
}
|
||||
|
||||
};
|
||||
// body.add(new SubMemberPanel(this));
|
||||
//
|
||||
// addSubmemberLink = new ActionLink(ADD_SUBMEMBER_LABEL);
|
||||
// addSubmemberLink.setClassAttr("actionLink");
|
||||
// addSubmemberLink.addActionListener(new ActionListener() {
|
||||
//
|
||||
// @Override
|
||||
// public void actionPerformed(final ActionEvent event) {
|
||||
// PageState ps = event.getPageState();
|
||||
// addSubmemberLink.setVisible(ps, false);
|
||||
// subMemberSearch.setVisible(ps, true);
|
||||
// }
|
||||
//
|
||||
// });
|
||||
//
|
||||
// subMemberSearch = new SearchAndList("searchsubmember");
|
||||
// subMemberSearch.setListModel(new UserSearchAndListModel());
|
||||
// subMemberSearch.addChangeListener(new ChangeListener() {
|
||||
//
|
||||
// @Override
|
||||
// public void stateChanged(final ChangeEvent event) {
|
||||
// PageState ps = event.getPageState();
|
||||
//
|
||||
// String key = (String) subMemberSearch.getSelectedKey(ps);
|
||||
// if (key != null) {
|
||||
// final BigDecimal userID = new BigDecimal(key);
|
||||
//
|
||||
// final Group group = getGroup(ps);
|
||||
//
|
||||
// if (group != null) {
|
||||
// try {
|
||||
// User user = User.retrieve(userID);
|
||||
// group.addMember(user);
|
||||
// group.save();
|
||||
// } catch (DataObjectNotFoundException exc) {
|
||||
// // Ignore if user id is not valid
|
||||
// } catch (PersistenceException pexc) {
|
||||
// // Display error message that user
|
||||
// // already existed in group.
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// subMemberSearch.reset(ps);
|
||||
// subMemberSearch.setVisible(ps, false);
|
||||
// addSubmemberLink.setVisible(ps, true);
|
||||
// }
|
||||
//
|
||||
// });
|
||||
//
|
||||
// body.add(subMemberSearch);
|
||||
// body.add(addSubmemberLink);
|
||||
return main.addSegment(SUBMEMBER_HEADER, body);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build extreme action panel.
|
||||
*/
|
||||
private Component buildExtremeActionPanel(final SegmentedPanel main) {
|
||||
final BoxPanel body = new BoxPanel();
|
||||
|
||||
final ActionLink deleteLink = new ActionLink(DELETE_GROUP_LABEL);
|
||||
deleteLink.setClassAttr("actionLink");
|
||||
deleteLink.setConfirmation(GROUP_DELETE_CONFIRMATION);
|
||||
deleteLink.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
|
||||
PageState ps = event.getPageState();
|
||||
|
||||
final Group group = (Group) requestLocalGroup.get(ps);
|
||||
if (group != null) {
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
groupRepository.delete(group);
|
||||
|
||||
// try {
|
||||
// group.delete();
|
||||
// groupTree.setSelectedKey(ps, "-1");
|
||||
// } catch (PersistenceException exc) {
|
||||
// LOGGER.warn("Error deleting subgroup", exc);
|
||||
// displayDeleteFailedPanel(ps);
|
||||
// }
|
||||
}
|
||||
// Select root node
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
body.add(deleteLink);
|
||||
return main.addSegment(GROUP_EXTREME_ACTIONS_HEADER,
|
||||
body);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a panel to display an error message when unable to delete group.
|
||||
*/
|
||||
private Component buildGroupDeleteFailedPanel(final SegmentedPanel main) {
|
||||
final ActionLink link = new ActionLink(GROUP_ACTION_CONTINUE);
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
PageState ps = event.getPageState();
|
||||
displayGroupInfoPanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
link.setClassAttr("actionLink");
|
||||
|
||||
final Label label = new Label(GROUP_DELETE_FAILED_MSG);
|
||||
label.setClassAttr("deleteFailedMessage");
|
||||
|
||||
final BoxPanel panel = new BoxPanel();
|
||||
panel.add(label);
|
||||
panel.add(link);
|
||||
|
||||
return main.addSegment(GROUP_DELETE_FAILED_HEADER, panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides all components of the in preparation for turning selected
|
||||
* components back on.
|
||||
*/
|
||||
private void hideAll(final PageState state) {
|
||||
for (int i = 0; i < panelList.size(); i++) {
|
||||
((Component) panelList.get(i)).setVisible(state, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all components of the in preparation for turning visibility of
|
||||
* selected components off .
|
||||
*/
|
||||
private void showAll(final PageState state) {
|
||||
for (int i = 0; i < panelList.size(); i++) {
|
||||
((Component) panelList.get(i)).setVisible(state, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SubGroupListModelBuilder extends LockableImpl implements ListModelBuilder {
|
||||
|
||||
private final GroupAdministrationTab parent;
|
||||
|
||||
public SubGroupListModelBuilder(final GroupAdministrationTab parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public ListModel makeModel(final List list, final PageState state) {
|
||||
final Group group = parent.getGroup(state);
|
||||
|
||||
// if (group != null) {
|
||||
// return new SubGroupListModel(group.getSubgroups());
|
||||
// }
|
||||
|
||||
return new SubGroupListModel(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* CLASS
|
||||
*
|
||||
*/
|
||||
class SubGroupListModel implements ListModel {
|
||||
|
||||
// private GroupCollection m_coll;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param collection
|
||||
*/
|
||||
public SubGroupListModel(final Object collection) {
|
||||
// m_coll = collection;
|
||||
// m_coll.addOrder("lower(" + Group.DISPLAY_NAME + ") asc");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Object getElement() {
|
||||
// return m_coll.getGroup();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getKey() {
|
||||
// return m_coll.getID().toString();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean next() {
|
||||
// if (m_coll != null) {
|
||||
// return m_coll.next();
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
/**
|
||||
* Edit group form.
|
||||
*
|
||||
* @author David Dao
|
||||
* @version $Id$
|
||||
*/
|
||||
class GroupEditForm extends GroupForm implements FormInitListener,
|
||||
FormProcessListener {
|
||||
|
||||
private GroupAdministrationTab m_parent;
|
||||
|
||||
public GroupEditForm() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public GroupEditForm(final GroupAdministrationTab parent) {
|
||||
super(GROUP_FORM_EDIT);
|
||||
addInitListener(this);
|
||||
addProcessListener(this);
|
||||
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes form elements by retrieving their values from the database.
|
||||
*/
|
||||
@Override
|
||||
public void init(final FormSectionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final Long id = (Long) state.getValue(USER_ID_PARAM);
|
||||
|
||||
if (id != null) {
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(
|
||||
GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
|
||||
final Group group = groupRepository.findById(id);
|
||||
|
||||
m_name.setValue(state, group.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the form.
|
||||
*/
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
final Long id = (Long) state.getValue(GROUP_ID_PARAM);
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
throw new FormProcessException(GlobalizationUtil.globalize(
|
||||
"ui.admin.groups.ID_is_null"));
|
||||
}
|
||||
|
||||
final Group group = groupRepository.findById(id);
|
||||
if (group == null) {
|
||||
throw new FormProcessException(GlobalizationUtil.globalize(
|
||||
"ui.admin.groups.couldnt_find_specified_group"));
|
||||
}
|
||||
|
||||
|
||||
final String name = (String) m_name.getValue(state);
|
||||
group.setName(name);
|
||||
|
||||
groupRepository.save(group);
|
||||
|
||||
if (m_parent != null) {
|
||||
m_parent.displayGroupInfoPanel(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.parameters.EmailParameter;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
/**
|
||||
* Base form for add/edit group.
|
||||
*
|
||||
* @author David Dao
|
||||
* @version $Id$
|
||||
*/
|
||||
class GroupForm extends Form {
|
||||
|
||||
protected TextField m_name;
|
||||
// protected TextField m_email;
|
||||
|
||||
public GroupForm(String formName) {
|
||||
super(formName);
|
||||
|
||||
m_name = new TextField(new StringParameter(GROUP_FORM_INPUT_NAME));
|
||||
m_name.setMaxLength(200);
|
||||
m_name.addValidationListener(new NotEmptyValidationListener());
|
||||
m_name.addValidationListener(new StringLengthValidationListener (200));
|
||||
|
||||
|
||||
add(GROUP_FORM_LABEL_NAME);
|
||||
add(m_name);
|
||||
|
||||
// m_email = new TextField(new EmailParameter(GROUP_FORM_INPUT_PRIMARY_EMAIL));
|
||||
// m_email.setMaxLength(100);
|
||||
// add(GROUP_FORM_LABEL_PRIMARY_EMAIL);
|
||||
// add(m_email);
|
||||
|
||||
// Submit button
|
||||
add(new Submit(GROUP_FORM_SUBMIT), ColumnPanel.CENTER |
|
||||
ColumnPanel.FULL_WIDTH);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Chris Gilbert. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author cgyg9330
|
||||
*
|
||||
* Search for groups to add as subgroups. Text entered by user is put into a
|
||||
* groupName like '%......%' query, which also excludes problematic results
|
||||
* (groups that are already supergroups or subgroups of the current group
|
||||
*
|
||||
*/
|
||||
public class GroupSearchForm extends Form implements FormProcessListener,
|
||||
AdminConstants {
|
||||
|
||||
private ExistingGroupAddPane parentPane;
|
||||
private TextField m_search;
|
||||
private List<Group> results = null;
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(GroupSearchForm.class);
|
||||
|
||||
public GroupSearchForm(ExistingGroupAddPane parent) {
|
||||
super("SearchGroups", new SimpleContainer());
|
||||
|
||||
parentPane = parent;
|
||||
setMethod(Form.POST);
|
||||
|
||||
addProcessListener(this);
|
||||
|
||||
add(GROUP_SEARCH_LABEL);
|
||||
add(new Label(" ", false));
|
||||
|
||||
StringParameter searchParam = new StringParameter(SEARCH_QUERY);
|
||||
m_search = new TextField(searchParam);
|
||||
m_search.addValidationListener(new NotEmptyValidationListener());
|
||||
m_search.setSize(20);
|
||||
add(m_search, ColumnPanel.RIGHT);
|
||||
|
||||
Submit submit = new Submit("submit");
|
||||
submit.setButtonLabel(SEARCH_BUTTON);
|
||||
add(submit, ColumnPanel.LEFT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
PageState state = event.getPageState();
|
||||
|
||||
Group parent = parentPane.getParentGroup(state);
|
||||
String search = (String) m_search.getValue(state);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
results = groupRepository.searchGroupByName(search);
|
||||
|
||||
|
||||
if (results.isEmpty()) {
|
||||
parentPane.showNoResults(state);
|
||||
} else {
|
||||
// put search string into Page
|
||||
state.setValue(getSearchString(), m_search.getValue(state));
|
||||
parentPane.showGroups(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* allow other classes to get hold of the results, to avoid constructing the
|
||||
* same query in several places
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<Group> getResults() {
|
||||
return Collections.unmodifiableList(results);
|
||||
}
|
||||
|
||||
private ParameterModel getSearchString() {
|
||||
return parentPane.getSearchString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
||||
import com.arsdigita.bebop.tree.TreeModel;
|
||||
import com.arsdigita.bebop.tree.TreeNode;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author David Dao
|
||||
*
|
||||
*/
|
||||
public class GroupTreeModel implements TreeModel {
|
||||
|
||||
// private class GroupIterator implements Iterator {
|
||||
//
|
||||
// private List< m_coll;
|
||||
//
|
||||
// public GroupIterator(ACSObjectCollection coll) {
|
||||
// m_coll = coll;
|
||||
// }
|
||||
//
|
||||
// public boolean hasNext() {
|
||||
// return m_coll.next();
|
||||
// }
|
||||
//
|
||||
// public Object next() {
|
||||
// return new GroupTreeNode(m_coll.getACSObject());
|
||||
// }
|
||||
//
|
||||
// public void remove() {
|
||||
// throw new UnsupportedOperationException();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
/**
|
||||
* Obtain the root folder of the tree
|
||||
*
|
||||
* @param state
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TreeNode getRoot(final PageState state) {
|
||||
return new RootTreeNode();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given node has children
|
||||
*
|
||||
* @param node
|
||||
* @param state
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean hasChildren(final TreeNode node, final PageState state) {
|
||||
|
||||
if (node instanceof RootTreeNode) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get direct children in this node.
|
||||
*
|
||||
* @param node
|
||||
* @param state
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Group> getChildren(final TreeNode node,
|
||||
final PageState state) {
|
||||
|
||||
if (node instanceof RootTreeNode) {
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(
|
||||
"Failed to lookup GroupRepository", ex);
|
||||
}
|
||||
final List<Group> groups = groupRepository.findAll();
|
||||
|
||||
return groups.iterator();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RootTreeNode implements TreeNode {
|
||||
|
||||
@Override
|
||||
public Object getKey() {
|
||||
return "-1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElement() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GroupTreeNode implements TreeNode {
|
||||
|
||||
private String m_key;
|
||||
private String m_name;
|
||||
|
||||
public GroupTreeNode(Group group) {
|
||||
m_key = Long.toString(group.getSubjectId());
|
||||
m_name = group.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKey() {
|
||||
return m_key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElement() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jens Pelzetter
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
import com.arsdigita.bebop.tree.TreeModel;
|
||||
import com.arsdigita.bebop.tree.TreeModelBuilder;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jens Pelzetter <jens@jp-digital.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GroupTreeModelBuilder extends LockableImpl implements TreeModelBuilder {
|
||||
|
||||
public TreeModel makeModel(final Tree tree, final PageState state) {
|
||||
tree.expand("-1", state);
|
||||
return new GroupTreeModel();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
|
||||
import org.libreccm.core.Subject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
class PartyListModel implements ListModel {
|
||||
|
||||
private final List<Subject> m_parties;
|
||||
private Subject m_currentParty = null;
|
||||
private int index = 0;
|
||||
|
||||
/**
|
||||
* Constructor for the list
|
||||
* Builds the list of party list model for parties
|
||||
*
|
||||
* @param partys the partyCollection
|
||||
**/
|
||||
public PartyListModel(final List<Subject> parties) {
|
||||
m_parties = parties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether is an another party
|
||||
*
|
||||
* @return true if another party exist, false otherwise
|
||||
**/
|
||||
@Override
|
||||
public boolean next() {
|
||||
if (index < m_parties.size()) {
|
||||
index++;
|
||||
m_currentParty = m_parties.get(index);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unqiue ID string for current Party
|
||||
*
|
||||
* @return the unqiue ID string for current Party
|
||||
**/
|
||||
@Override
|
||||
public String getKey() {
|
||||
return Long.toString(m_currentParty.getSubjectId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Party
|
||||
*
|
||||
* @return the current Party
|
||||
**/
|
||||
@Override
|
||||
public Object getElement() {
|
||||
return m_currentParty.getSubjectId();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.ActionLink;
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.list.ListCellRenderer;
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David Dao
|
||||
*/
|
||||
class SearchAndList extends SimpleContainer
|
||||
implements AdminConstants,
|
||||
Resettable {
|
||||
|
||||
/**
|
||||
* String catalog.
|
||||
*/
|
||||
private static final String FORM_INPUT_NAME = "query";
|
||||
|
||||
private static final GlobalizedMessage LABEL_SUBMIT = new GlobalizedMessage(
|
||||
"ui.admin.searchAndList.submit",
|
||||
BUNDLE_NAME);
|
||||
private static final GlobalizedMessage SEARCH_AGAIN = new GlobalizedMessage(
|
||||
"ui.admin.searchAndList.submitAgain",
|
||||
BUNDLE_NAME);
|
||||
|
||||
private Form m_searchForm;
|
||||
|
||||
private List m_searchResultList;
|
||||
|
||||
private ParameterModel m_queryModel;
|
||||
|
||||
private SearchAndListModel m_listModel;
|
||||
|
||||
private SimpleContainer m_searchResultContainer;
|
||||
|
||||
private class SearchListModelBuilder extends LockableImpl
|
||||
implements ListModelBuilder {
|
||||
|
||||
public ListModel makeModel(List l, PageState state) {
|
||||
return m_listModel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ListModelBuilder m_listModelBuilder = new SearchListModelBuilder();
|
||||
|
||||
private FormProcessListener m_formProcessListener
|
||||
= new FormProcessListener() {
|
||||
|
||||
public void process(FormSectionEvent e) throws FormProcessException {
|
||||
|
||||
FormData data = e.getFormData();
|
||||
PageState state = e.getPageState();
|
||||
String query = (String) data.get(FORM_INPUT_NAME);
|
||||
|
||||
boolean visible = false;
|
||||
if (query == null || query.equals("")) {
|
||||
visible = true;
|
||||
} else {
|
||||
visible = false;
|
||||
}
|
||||
|
||||
m_listModel.setQuery(query);
|
||||
m_searchForm.setVisible(state, visible);
|
||||
m_searchResultContainer.setVisible(state, !visible);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public SearchAndList(String name) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* Create a search form.
|
||||
*/
|
||||
m_searchForm = new Form(name, new BoxPanel(BoxPanel.HORIZONTAL));
|
||||
m_queryModel = new StringParameter(FORM_INPUT_NAME);
|
||||
TextField query = new TextField(m_queryModel);
|
||||
query.addValidationListener(new NotNullValidationListener());
|
||||
m_searchForm.add(query);
|
||||
m_searchForm.add(new Submit(LABEL_SUBMIT));
|
||||
m_searchForm.addProcessListener(m_formProcessListener);
|
||||
add(m_searchForm);
|
||||
|
||||
/**
|
||||
* Create a search result container.
|
||||
*/
|
||||
m_searchResultContainer = new SimpleContainer();
|
||||
add(m_searchResultContainer);
|
||||
|
||||
m_searchResultList = new List();
|
||||
m_searchResultList.setClassAttr("SearchResultList");
|
||||
m_searchResultList.setModelBuilder(m_listModelBuilder);
|
||||
|
||||
ActionLink link = new ActionLink(new Label(SEARCH_AGAIN));
|
||||
link.setClassAttr("actionLink");
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState state = e.getPageState();
|
||||
m_searchForm.setVisible(state, true);
|
||||
m_searchResultContainer.setVisible(state, false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
m_searchResultContainer.add(m_searchResultList);
|
||||
m_searchResultContainer.add(link);
|
||||
}
|
||||
|
||||
public void addChangeListener(ChangeListener l) {
|
||||
m_searchResultList.addChangeListener(l);
|
||||
}
|
||||
|
||||
public Object getSelectedKey(PageState ps) {
|
||||
return m_searchResultList.getSelectedKey(ps);
|
||||
}
|
||||
|
||||
public void clearSelection(PageState ps) {
|
||||
m_searchResultList.clearSelection(ps);
|
||||
}
|
||||
|
||||
public void setListModel(SearchAndListModel model) {
|
||||
m_listModel = model;
|
||||
}
|
||||
|
||||
public void setResultCellRenderer(ListCellRenderer r) {
|
||||
m_searchResultList.setCellRenderer(r);
|
||||
}
|
||||
|
||||
public void register(Page p) {
|
||||
p.setVisibleDefault(m_searchForm, true);
|
||||
p.setVisibleDefault(m_searchResultContainer, false);
|
||||
|
||||
}
|
||||
|
||||
public void reset(PageState ps) {
|
||||
m_searchResultContainer.setVisible(ps, false);
|
||||
m_searchForm.setVisible(ps, true);
|
||||
clearSelection(ps);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author David Dao
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
public interface SearchAndListModel extends ListModel {
|
||||
|
||||
/**
|
||||
* Specify the user's search.
|
||||
*/
|
||||
|
||||
public void setQuery (String query);
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Chris Gilbert. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.form.CheckboxGroup;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.OptionGroup;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
|
||||
import org.libreccm.core.Group;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
/**
|
||||
* @author cgyg9330
|
||||
*
|
||||
* contains a form that allows the user to select desired groups to be added as
|
||||
* subgroups to the currently selected group
|
||||
*
|
||||
* NB could be improved with cancel button - currently need to use browser back
|
||||
* button
|
||||
*/
|
||||
public class SelectGroups {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(SelectGroups.class);
|
||||
private static final String GROUPS_CBG = "groups_cbg";
|
||||
private BoxPanel groupPanel;
|
||||
private CheckboxGroup groups;
|
||||
private Form form;
|
||||
private Submit save;
|
||||
private ExistingGroupAddPane parentPane;
|
||||
private GroupSearchForm searchForm;
|
||||
|
||||
public SelectGroups(ExistingGroupAddPane parent, GroupSearchForm searchForm) {
|
||||
parentPane = parent;
|
||||
makeForm();
|
||||
groupPanel = new BoxPanel();
|
||||
groupPanel.add(form);
|
||||
this.searchForm = searchForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the form used to select groups.
|
||||
*/
|
||||
private void makeForm() {
|
||||
form = new Form("ChooseGroups", new BoxPanel());
|
||||
form.setMethod(Form.POST);
|
||||
form.addSubmissionListener(new AddGroupsSubmissionListener());
|
||||
form.add(PICK_GROUPS);
|
||||
groups = new CheckboxGroup(GROUPS_CBG);
|
||||
groups.setClassAttr("vertical");
|
||||
|
||||
try {
|
||||
groups.addPrintListener(new GroupSearchPrintListener());
|
||||
} catch (TooManyListenersException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
form.add(groups);
|
||||
|
||||
save = new Submit("save", SAVE_BUTTON);
|
||||
form.add(save);
|
||||
}
|
||||
|
||||
public BoxPanel getPanel() {
|
||||
return groupPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* FormSubmissionListener that sets selected groups to be subgroups of the
|
||||
* currently selected group
|
||||
*
|
||||
*/
|
||||
private class AddGroupsSubmissionListener
|
||||
implements FormSubmissionListener {
|
||||
|
||||
public void submitted(FormSectionEvent e) throws FormProcessException {
|
||||
PageState state = e.getPageState();
|
||||
FormData data = e.getFormData();
|
||||
String[] selectedGroups = (String[]) data.get(GROUPS_CBG);
|
||||
BigDecimal groupID = null;
|
||||
Group child = null;
|
||||
// if (selectedGroups != null) {
|
||||
// Group parent = parentPane.getParentGroup(state);
|
||||
// for (int i = 0; i < selectedGroups.length; i++) {
|
||||
// groupID = new BigDecimal(selectedGroups[i]);
|
||||
// try {
|
||||
// child = new Group(groupID);
|
||||
// } catch (DataObjectNotFoundException e2) {
|
||||
// s_log.warn("Non existant Group " + child
|
||||
// + " selected to be child of " + parent);
|
||||
// }
|
||||
// parent.addSubgroup(child);
|
||||
// parent.save();
|
||||
// }
|
||||
// }
|
||||
|
||||
parentPane.showSearch(state);
|
||||
parentPane.getParentPage().displayGroupInfoPanel(state);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @author cgyg9330
|
||||
*
|
||||
* Printlistener retrieves query results from the groupsearch form and uses
|
||||
* them as the entries on the checkbox group
|
||||
*/
|
||||
private class GroupSearchPrintListener implements PrintListener {
|
||||
|
||||
public void prepare(PrintEvent e) {
|
||||
PageState state = e.getPageState();
|
||||
OptionGroup cbg = (CheckboxGroup) e.getTarget();
|
||||
|
||||
List<Group> results = searchForm.getResults();
|
||||
|
||||
String groupID;
|
||||
String groupName;
|
||||
Group child;
|
||||
|
||||
for(Group group : results) {
|
||||
child = group;
|
||||
groupID = Long.toString(child.getSubjectId());
|
||||
groupName = child.getName();
|
||||
cbg.addOption(new Option(groupID, groupName));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.list.ListCellRenderer;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupManager;
|
||||
import org.libreccm.core.GroupMembership;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
import org.libreccm.core.User;
|
||||
import org.libreccm.core.UserRepository;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author David Dao
|
||||
*
|
||||
*/
|
||||
class SubMemberPanel extends BoxPanel {
|
||||
|
||||
private List m_memberList;
|
||||
|
||||
|
||||
private GroupAdministrationTab m_mainTab;
|
||||
|
||||
public SubMemberPanel(final GroupAdministrationTab tab) {
|
||||
m_mainTab = tab;
|
||||
m_memberList = new List(new SubMemberListModelBuilder(tab));
|
||||
m_memberList.setCellRenderer(new ListCellRenderer() {
|
||||
@Override
|
||||
public Component getComponent(final List list,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
final String key,
|
||||
final int index,
|
||||
final boolean isSelected) {
|
||||
|
||||
final BoxPanel panel = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||
|
||||
Label label = new Label(((User) value).getScreenName());
|
||||
panel.add(label);
|
||||
|
||||
ControlLink removeLink = new ControlLink(REMOVE_SUBMEMBER_LABEL);
|
||||
removeLink.setClassAttr("actionLink");
|
||||
|
||||
panel.add(removeLink);
|
||||
return panel;
|
||||
}
|
||||
});
|
||||
m_memberList.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
final String key = (String) m_memberList.getSelectedKey(state);
|
||||
|
||||
if (key != null) {
|
||||
final Long userID = new Long(key);
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
final GroupManager groupManager;
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
groupManager = cdiUtil.findBean(GroupManager.class);
|
||||
groupRepository = cdiUtil.findBean(GroupRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
final User user = userRepository.findById(userID);
|
||||
final Group group = m_mainTab.getGroup(state);
|
||||
if (group != null) {
|
||||
groupManager.removeUserFromGroup(user, group);
|
||||
groupRepository.save(group);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
add(m_memberList);
|
||||
}
|
||||
}
|
||||
|
||||
class SubMemberListModelBuilder extends LockableImpl
|
||||
implements ListModelBuilder {
|
||||
|
||||
private GroupAdministrationTab m_mainTab;
|
||||
public SubMemberListModelBuilder(final GroupAdministrationTab tab) {
|
||||
m_mainTab = tab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListModel makeModel(final List list, final PageState state) {
|
||||
|
||||
final Group group = m_mainTab.getGroup(state);
|
||||
final java.util.List<GroupMembership> members;
|
||||
if (group == null) {
|
||||
members = null;
|
||||
} else {
|
||||
members = group.getMembers();
|
||||
}
|
||||
|
||||
return new SubMemberListModel(members);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class SubMemberListModel implements ListModel {
|
||||
|
||||
private final java.util.List<GroupMembership> members;
|
||||
private int index;
|
||||
|
||||
|
||||
public SubMemberListModel(final java.util.List<GroupMembership> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElement() {
|
||||
return members.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return Long.toString(members.get(index).getMembershipId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean next() {
|
||||
if (index < members.size()) {
|
||||
index++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jens Pelzetter
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.TabbedPane;
|
||||
import com.arsdigita.bebop.event.ChangeEvent;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jens Pelzetter <jens@jp-digital.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
class UserAdministrationTab extends LayoutPanel {
|
||||
|
||||
private final List sections;
|
||||
private final java.util.List<Component> components = new ArrayList<Component>();
|
||||
private final java.util.List<Label> keys = new ArrayList<Label>();
|
||||
private final GlobalizedMessage title = USER_NAVBAR_TITLE;
|
||||
|
||||
public UserAdministrationTab(final TabbedPane parent, final GroupAdministrationTab groupAdminTab) {
|
||||
super();
|
||||
|
||||
setClassAttr("sidebarNavPanel");
|
||||
|
||||
sections = new List(new GlobalizedTabModelBuilder());
|
||||
sections.addChangeListener(new SectionChangeListener());
|
||||
sections.setClassAttr("navbar");
|
||||
setLeft(sections);
|
||||
|
||||
final UserBrowsePane browsePane = new UserBrowsePane();
|
||||
// ToDo final UserSummarySection summarySection = new UserSummarySection(this, browsePane);
|
||||
// ToDo final UserSearchSection searchSection = new UserSearchSection(this, browsePane);
|
||||
// ToDo final UserCreateSection createSection = new UserCreateSection(this);
|
||||
|
||||
browsePane.setTabbedPane(parent);
|
||||
browsePane.setGroupAdministrationTab(groupAdminTab);
|
||||
|
||||
final BoxPanel body = new BoxPanel();
|
||||
// ToDo addSection(USER_TAB_SUMMARY, summarySection, body);
|
||||
addSection(USER_TAB_BROWSE, browsePane, body);
|
||||
// ToDo addSection(USER_TAB_SEARCH, searchSection, body);
|
||||
// ToDo addSection(USER_TAB_CREATE_USER, createSection, body);
|
||||
|
||||
setBody(body);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @pre label != null && c != null
|
||||
*/
|
||||
private void addSection(final Label label, final Component component, final BoxPanel panel) {
|
||||
Assert.isUnlocked(this);
|
||||
components.add(component);
|
||||
component.setClassAttr("main");
|
||||
panel.add(component);
|
||||
keys.add(label);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param page
|
||||
*/
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
page.setVisibleDefault(components.get(i), false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSection(final int index, final PageState state) {
|
||||
sections.setSelectedKey(state, String.valueOf(index));
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
if (i == index) {
|
||||
(components.get(i)).setVisible(state, true);
|
||||
((Resettable) components.get(i)).reset(state);
|
||||
} else {
|
||||
(components.get(i)).setVisible(state, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
super.generateXML(state, parent);
|
||||
|
||||
/**
|
||||
* Globalized navbar title.
|
||||
* Why did I override generateXML method to globalize the title?
|
||||
* Because CMS put title bar as an attribute of element. This
|
||||
* is the only method I could come up with.
|
||||
*/
|
||||
final Element child = (Element) parent.getChildren().get(0);
|
||||
child.addAttribute("navbar-title",
|
||||
(String) title.localize(state.getRequest()));
|
||||
}
|
||||
|
||||
private class SectionChangeListener implements ChangeListener {
|
||||
|
||||
public SectionChangeListener() {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(final ChangeEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final int selectedIndex = Integer.parseInt((String) sections.getSelectedKey(state));
|
||||
setSection(selectedIndex, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GlobalizedTabModelBuilder extends LockableImpl implements ListModelBuilder {
|
||||
|
||||
public GlobalizedTabModelBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListModel makeModel(final List list, final PageState state) {
|
||||
return new TabNameListModel(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TabNameListModel implements ListModel {
|
||||
|
||||
private int index = -1;
|
||||
private final PageState pageState;
|
||||
|
||||
public TabNameListModel(final PageState state) {
|
||||
pageState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElement() {
|
||||
return keys.get(index).getLabel(pageState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return String.valueOf(index);
|
||||
}
|
||||
|
||||
public boolean next() {
|
||||
final boolean result = (index < keys.size() - 1);
|
||||
//return (index++ < keys.size() - 1);
|
||||
index++;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,783 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.ActionLink;
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.List;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SegmentedPanel;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.TabbedPane;
|
||||
// import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
// import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ChangeEvent;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.event.TableActionEvent;
|
||||
import com.arsdigita.bebop.event.TableActionListener;
|
||||
import com.arsdigita.bebop.list.ListModel;
|
||||
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.bebop.table.TableModelBuilder;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.ui.UI;
|
||||
import com.arsdigita.web.URL;
|
||||
import com.arsdigita.web.RedirectSignal;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.CcmSessionContext;
|
||||
import org.libreccm.core.Group;
|
||||
import org.libreccm.core.GroupMembership;
|
||||
import org.libreccm.core.GroupRepository;
|
||||
import org.libreccm.core.Subject;
|
||||
import org.libreccm.core.User;
|
||||
import org.libreccm.core.UserRepository;
|
||||
|
||||
/**
|
||||
* This pane contains three main segmented panel which only one is visible at
|
||||
* any given time. The first panel is a table listing all available users in the
|
||||
* system. The second panel displays read only user information. And the third
|
||||
* panel is edit form.
|
||||
*
|
||||
* @author David Dao
|
||||
* @author Ron Henderson
|
||||
* @version $Id$
|
||||
*/
|
||||
class UserBrowsePane extends SegmentedPanel
|
||||
implements TableCellRenderer,
|
||||
TableActionListener,
|
||||
Resettable,
|
||||
ActionListener,
|
||||
ChangeListener {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(UserBrowsePane.class);
|
||||
|
||||
private Component m_userBrowsePanel;
|
||||
private Component m_userInfoPanel;
|
||||
private Component m_userEditPanel;
|
||||
private Component m_userPasswordPanel;
|
||||
private Component m_groupMembershipPanel;
|
||||
private Component m_actionPanel;
|
||||
private Component m_extremeActionPanel;
|
||||
private Component m_userDeleteFailedPanel;
|
||||
private GroupAdministrationTab m_groupAdministrationTab;
|
||||
private TabbedPane m_tabbedPane;
|
||||
|
||||
private List m_groupList = null;
|
||||
|
||||
private ArrayList m_panelList = new ArrayList();
|
||||
|
||||
private RequestLocal m_user;
|
||||
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
for (int i = 0; i < m_panelList.size(); i++) {
|
||||
p.setVisibleDefault((Component) m_panelList.get(i), false);
|
||||
}
|
||||
|
||||
p.setVisibleDefault(m_userBrowsePanel, true);
|
||||
p.addActionListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final CcmSessionContext sessionContext;
|
||||
try {
|
||||
sessionContext = cdiUtil.findBean(CcmSessionContext.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
final Subject subject = sessionContext.getCurrentSubject();
|
||||
|
||||
final Long userID = (Long) state.getValue(USER_ID_PARAM);
|
||||
|
||||
// Bug #167607 remove link for current user
|
||||
if (m_userInfoPanel.isVisible(state)) {
|
||||
if (subject.getSubjectId() == userID) {
|
||||
m_extremeActionPanel.setVisible(state, false);
|
||||
} else {
|
||||
m_extremeActionPanel.setVisible(state, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UserBrowsePane with multiple panels to help manage various
|
||||
* aspects of a user's account.
|
||||
*/
|
||||
public UserBrowsePane() {
|
||||
m_user = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(final PageState state) {
|
||||
final Long id = (Long) state.getValue(USER_ID_PARAM);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
final User user = userRepository.findById(id);
|
||||
if (user == null) {
|
||||
throw new UncheckedWrapperException(String.format(
|
||||
"Failed to retrieve user: %d", id));
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
m_userBrowsePanel = buildUserBrowsePanel();
|
||||
m_panelList.add(m_userBrowsePanel);
|
||||
|
||||
m_userInfoPanel = buildUserInfoPanel();
|
||||
m_panelList.add(m_userInfoPanel);
|
||||
|
||||
m_userEditPanel = buildUserEditPanel();
|
||||
m_panelList.add(m_userEditPanel);
|
||||
|
||||
m_userPasswordPanel = buildUserPasswordPanel();
|
||||
m_panelList.add(m_userPasswordPanel);
|
||||
|
||||
m_groupMembershipPanel = buildGroupMembershipPanel();
|
||||
m_panelList.add(m_groupMembershipPanel);
|
||||
|
||||
m_actionPanel = buildActionPanel();
|
||||
m_panelList.add(m_actionPanel);
|
||||
|
||||
m_extremeActionPanel = buildExtremeActionPanel();
|
||||
m_panelList.add(m_extremeActionPanel);
|
||||
|
||||
m_userDeleteFailedPanel = buildUserDeleteFailedPanel();
|
||||
m_panelList.add(m_userDeleteFailedPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user object for this request.
|
||||
*/
|
||||
public User getUser(PageState ps) {
|
||||
return (User) m_user.get(ps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the User Information panel
|
||||
*/
|
||||
private Component buildUserInfoPanel() {
|
||||
// Edit user link
|
||||
|
||||
ActionLink link = new ActionLink(new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.editlink",
|
||||
BUNDLE_NAME)));
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState ps = e.getPageState();
|
||||
displayEditPanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
link.setClassAttr("actionLink");
|
||||
|
||||
BoxPanel panel = new BoxPanel();
|
||||
|
||||
// panel.add(new UserInfo(this));
|
||||
final ColumnPanel colPanel = new ColumnPanel(2);
|
||||
|
||||
colPanel.add(new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userinfo.name", BUNDLE_NAME)));
|
||||
final Label userName = new Label();
|
||||
userName.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final Label target = (Label) event.getTarget();
|
||||
final PageState state = event.getPageState();
|
||||
final User user = getUser(state);
|
||||
|
||||
target.setLabel(user.getScreenName());
|
||||
}
|
||||
|
||||
});
|
||||
colPanel.add(userName);
|
||||
|
||||
colPanel.add(new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userinfo.screenname",
|
||||
BUNDLE_NAME)));
|
||||
final Label userScreenname = new Label();
|
||||
userScreenname.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final Label target = (Label) event.getTarget();
|
||||
final PageState state = event.getPageState();
|
||||
final User user = getUser(state);
|
||||
|
||||
target.setLabel(user.getScreenName());
|
||||
}
|
||||
|
||||
});
|
||||
colPanel.add(userScreenname);
|
||||
|
||||
colPanel.add(new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.userinfo.primaryemail",
|
||||
BUNDLE_NAME)));
|
||||
final Label userEmail = new Label();
|
||||
userEmail.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final Label target = (Label) event.getTarget();
|
||||
final PageState state = event.getPageState();
|
||||
final User user = getUser(state);
|
||||
|
||||
target.setLabel(user.getEmailAddresses().get(0).getAddress());
|
||||
}
|
||||
|
||||
});
|
||||
colPanel.add(userEmail);
|
||||
|
||||
panel.add(colPanel);
|
||||
panel.add(link);
|
||||
|
||||
return addSegment(USER_INFO_LABEL, panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the User Edit panel
|
||||
*/
|
||||
private Component buildUserEditPanel() {
|
||||
return addSegment(USER_EDIT_PANEL_HEADER, new UserEditForm(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the User Password Update panel
|
||||
*/
|
||||
private Component buildUserPasswordPanel() {
|
||||
BoxPanel p = new BoxPanel();
|
||||
p.add(new UserPasswordForm(this));
|
||||
p.add(new SimpleContainer("admin:PasswordNote", ADMIN_XML_NS));
|
||||
|
||||
return addSegment(USER_PASSWORD_PANEL_HEADER, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Group Membership panel
|
||||
*/
|
||||
private Component buildGroupMembershipPanel() {
|
||||
m_groupList = new List();
|
||||
m_groupList.setClassAttr("UserGroupsResultList");
|
||||
m_groupList.setModelBuilder(new GroupsModelBuilder());
|
||||
m_groupList.addChangeListener(this);
|
||||
|
||||
return addSegment(USER_GROUP_PANEL_HEADER, m_groupList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Action panel
|
||||
*/
|
||||
private Component buildActionPanel() {
|
||||
BoxPanel p = new BoxPanel();
|
||||
|
||||
// Update password link
|
||||
ActionLink link = new ActionLink(UPDATE_USER_PASSWORD_LABEL);
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState ps = e.getPageState();
|
||||
displayUserPasswordPanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
link.setClassAttr("actionLink");
|
||||
p.add(link);
|
||||
|
||||
// Become user link
|
||||
// This will not be shown when the user is banned to prevent security issues
|
||||
link = new ActionLink(BECOME_USER_LABEL) {
|
||||
|
||||
public boolean isVisible(PageState s) {
|
||||
if (!super.isVisible(s)) {
|
||||
return false;
|
||||
}
|
||||
User u = getUser(s);
|
||||
return (!u.isBanned());
|
||||
}
|
||||
|
||||
};
|
||||
link.setClassAttr("actionLink");
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
// final BigDecimal id = (BigDecimal) state.getValue(USER_ID_PARAM);
|
||||
//
|
||||
// final CdiUtil cdiUtil = new CdiUtil();
|
||||
// final LoginManager loginManager;
|
||||
// try {
|
||||
// loginManager = cdiUtil.findBean(
|
||||
// LoginManager.class);
|
||||
// } catch(CdiLookupException ex) {
|
||||
// throw new UncheckedWrapperException(ex);
|
||||
// }
|
||||
//
|
||||
// loginManager.login(CLASS, CLASS);
|
||||
//
|
||||
// try {
|
||||
// UserContext uc = Web.getUserContext();
|
||||
// uc.login(id);
|
||||
// } catch (javax.security.auth.login.LoginException ex) {
|
||||
// throw new UncheckedWrapperException("access denied", ex);
|
||||
// }
|
||||
|
||||
// Redirect to workspace URL
|
||||
final String path = UI.getUserRedirectURL(state.getRequest());
|
||||
|
||||
final URL url = URL.there(state.getRequest(), path);
|
||||
|
||||
throw new RedirectSignal(url, true);
|
||||
}
|
||||
|
||||
});
|
||||
p.add(link);
|
||||
|
||||
// Show all users
|
||||
link = new ActionLink(new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.browselink",
|
||||
BUNDLE_NAME)));
|
||||
link.setClassAttr("actionLink");
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState ps = e.getPageState();
|
||||
displayUserBrowsePanel(ps);
|
||||
}
|
||||
|
||||
});
|
||||
p.add(link);
|
||||
|
||||
return addSegment(USER_ACTION_PANEL_HEADER, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Extreme Action panel
|
||||
*/
|
||||
private Component buildExtremeActionPanel() {
|
||||
|
||||
ActionLink deleteLink = new ActionLink(USER_DELETE_LABEL) {
|
||||
|
||||
@Override
|
||||
public boolean isVisible(PageState s) {
|
||||
if (!super.isVisible(s)) {
|
||||
return false;
|
||||
}
|
||||
// We show the delete link if the user has never published an item
|
||||
// This implicitly checks whether the user is banned - if they
|
||||
// are deletable they cannot ever have been banned
|
||||
User u = getUser(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
deleteLink.setClassAttr("actionLink");
|
||||
deleteLink.setConfirmation(USER_DELETE_CONFIRMATION.localize()
|
||||
.toString());
|
||||
deleteLink.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final User user = getUser(state);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
userRepository.delete(user);
|
||||
|
||||
displayUserBrowsePanel(state);
|
||||
|
||||
} // End ActionPerformed method
|
||||
|
||||
} // End of new ActionListener definition
|
||||
);
|
||||
|
||||
// Add link inside a BoxPanel for correct alignment with other
|
||||
// page elements.
|
||||
ActionLink banLink = new ActionLink(USER_BAN_LABEL) {
|
||||
|
||||
@Override
|
||||
public boolean isVisible(PageState s) {
|
||||
if (!super.isVisible(s)) {
|
||||
return false;
|
||||
}
|
||||
// We show the ban link if the user is not already banned and has never published
|
||||
// an item
|
||||
User u = getUser(s);
|
||||
return (!u.isBanned());
|
||||
}
|
||||
|
||||
};
|
||||
banLink.setClassAttr("actionLink");
|
||||
banLink.setConfirmation(USER_BAN_CONFIRMATION.localize().toString());
|
||||
banLink.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState state = e.getPageState();
|
||||
User user = getUser(state);
|
||||
user.setBanned(true);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
userRepository.save(user);
|
||||
} // End ActionPerformed method
|
||||
|
||||
} // End of new ActionListener definition
|
||||
);
|
||||
|
||||
ActionLink unbanLink = new ActionLink(USER_UNBAN_LABEL) {
|
||||
|
||||
public boolean isVisible(PageState s) {
|
||||
if (!super.isVisible(s)) {
|
||||
return false;
|
||||
}
|
||||
PageState state = s.getPageState();
|
||||
User user = getUser(state);
|
||||
return user.isBanned();
|
||||
}
|
||||
|
||||
};
|
||||
unbanLink.setClassAttr("actionLink");
|
||||
unbanLink.setConfirmation(USER_UNBAN_CONFIRMATION.localize().toString());
|
||||
unbanLink.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState state = e.getPageState();
|
||||
User user = getUser(state);
|
||||
user.setBanned(false);
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
userRepository.save(user);
|
||||
} // End ActionPerformed method
|
||||
|
||||
} // End of new ActionListener definition
|
||||
);
|
||||
|
||||
// Add link inside a BoxPanel for correct alignment with other
|
||||
// page elements.
|
||||
BoxPanel p = new BoxPanel();
|
||||
p.add(deleteLink);
|
||||
p.add(banLink);
|
||||
p.add(unbanLink);
|
||||
return addSegment(USER_TAB_EXTREME_ACTION_LABEL, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a panel to display an error message when unable to delete a user.
|
||||
*/
|
||||
private Component buildUserDeleteFailedPanel() {
|
||||
ActionLink link = new ActionLink(USER_ACTION_CONTINUE);
|
||||
link.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PageState state = e.getPageState();
|
||||
displayUserInfoPanel(state);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Label label = new Label(USER_DELETE_FAILED_MSG);
|
||||
label.setClassAttr("deleteFailedMessage");
|
||||
|
||||
BoxPanel p = new BoxPanel();
|
||||
p.add(label);
|
||||
p.add(link);
|
||||
|
||||
return addSegment(USER_DELETE_FAILED_PANEL_HEADER, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Browse User panel. Displays a list of all registered users.
|
||||
*/
|
||||
private Component buildUserBrowsePanel() {
|
||||
String headers[] = new String[]{
|
||||
"ID", "Name", "Screen Name", "Email", "SSO login"
|
||||
};
|
||||
|
||||
Table table = new Table(new UserTableModelBuilder(), headers);
|
||||
table.setClassAttr("AlternateTable");
|
||||
table.setDefaultCellRenderer(this);
|
||||
table.addTableActionListener(this);
|
||||
|
||||
return addSegment(BROWSE_USER_PANEL_HEADER, table);
|
||||
}
|
||||
|
||||
private class GroupsModelBuilder extends LockableImpl
|
||||
implements ListModelBuilder {
|
||||
|
||||
@Override
|
||||
public ListModel makeModel(final List list, final PageState state) {
|
||||
final User user = getUser(state);
|
||||
final java.util.List<GroupMembership> memberships = user
|
||||
.getGroupMemberships();
|
||||
final java.util.List<Subject> groups = new ArrayList<>();
|
||||
for (GroupMembership membership : memberships) {
|
||||
groups.add(membership.getGroup());
|
||||
}
|
||||
|
||||
return new PartyListModel(groups);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void displayUserInfoPanel(PageState ps) {
|
||||
hideAll(ps);
|
||||
m_userInfoPanel.setVisible(ps, true);
|
||||
m_groupMembershipPanel.setVisible(ps, true);
|
||||
m_actionPanel.setVisible(ps, true);
|
||||
m_extremeActionPanel.setVisible(ps, true);
|
||||
}
|
||||
|
||||
void displayEditPanel(PageState ps) {
|
||||
hideAll(ps);
|
||||
m_userEditPanel.setVisible(ps, true);
|
||||
}
|
||||
|
||||
public void displayUserBrowsePanel(PageState ps) {
|
||||
hideAll(ps);
|
||||
m_userBrowsePanel.setVisible(ps, true);
|
||||
}
|
||||
|
||||
public void displayUserPasswordPanel(PageState ps) {
|
||||
hideAll(ps);
|
||||
m_userPasswordPanel.setVisible(ps, true);
|
||||
}
|
||||
|
||||
public void displayUserDeleteFailedPanel(PageState ps) {
|
||||
hideAll(ps);
|
||||
m_userDeleteFailedPanel.setVisible(ps, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides all components of the UserBrowsePane in preparation for turning
|
||||
* selected components back on.
|
||||
*/
|
||||
private void hideAll(PageState ps) {
|
||||
for (int i = 0; i < m_panelList.size(); i++) {
|
||||
((Component) m_panelList.get(i)).setVisible(ps, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent(Table table, PageState state, Object value,
|
||||
boolean isSelected, Object key, int row,
|
||||
int col) {
|
||||
if (col == 0) {
|
||||
ControlLink link = new ControlLink(value.toString());
|
||||
return link;
|
||||
} else {
|
||||
if (value != null) {
|
||||
return new Label(value.toString());
|
||||
} else {
|
||||
return new Label(" ", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cellSelected(TableActionEvent e) {
|
||||
PageState ps = e.getPageState();
|
||||
|
||||
ps.setValue(USER_ID_PARAM, new BigDecimal((String) e.getRowKey()));
|
||||
displayUserInfoPanel(ps);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void headSelected(TableActionEvent e) {
|
||||
// Empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(PageState ps) {
|
||||
displayUserBrowsePanel(ps);
|
||||
}
|
||||
|
||||
public void setTabbedPane(TabbedPane tabbedPane) {
|
||||
m_tabbedPane = tabbedPane;
|
||||
}
|
||||
|
||||
public void setGroupAdministrationTab(
|
||||
GroupAdministrationTab groupAdministrationTab) {
|
||||
m_groupAdministrationTab = groupAdministrationTab;
|
||||
}
|
||||
|
||||
// // This is how we check if a user is banned or not
|
||||
// private boolean hasUserPublishedItems(User user) {
|
||||
// DataQuery query = user.getSession().retrieveQuery(
|
||||
// "com.arsdigita.versioning.UserPublications");
|
||||
// query.setParameter("value", new Integer(user.getID().intValue()));
|
||||
// query.next();
|
||||
// Integer count = (Integer) query.get("theCount");
|
||||
// query.close();
|
||||
// return count.intValue() != 0;
|
||||
// }
|
||||
/**
|
||||
* Display group information panel when a group name is clicked.
|
||||
*/
|
||||
@Override
|
||||
public void stateChanged(final ChangeEvent event) {
|
||||
if (event.getSource() == m_groupList) {
|
||||
if (m_tabbedPane != null && m_groupAdministrationTab != null) {
|
||||
PageState ps = event.getPageState();
|
||||
String id = (String) m_groupList.getSelectedKey(ps);
|
||||
if (id != null) {
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final GroupRepository groupRepository;
|
||||
try {
|
||||
groupRepository = cdiUtil
|
||||
.findBean(GroupRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
final Group group = groupRepository.findById(Long.parseLong(
|
||||
id));
|
||||
m_groupAdministrationTab.setGroup(ps, group);
|
||||
m_groupAdministrationTab.displayGroupInfoPanel(ps);
|
||||
m_tabbedPane.setSelectedIndex(ps, GROUP_TAB_INDEX);
|
||||
} else {
|
||||
reset(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UserTableModelBuilder extends LockableImpl implements TableModelBuilder {
|
||||
|
||||
public TableModel makeModel(Table t, PageState s) {
|
||||
return new UserTableModel();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UserTableModel implements TableModel {
|
||||
|
||||
private final java.util.List<User> users;
|
||||
private int index = 0;
|
||||
|
||||
public UserTableModel() {
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
users = userRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(final int columnIndex) {
|
||||
final User user = users.get(index);
|
||||
|
||||
if (columnIndex == 0) {
|
||||
return user.getSubjectId();
|
||||
} else if (columnIndex == 1) {
|
||||
return String.format("%s %s",
|
||||
user.getName().getGivenName(),
|
||||
user.getName().getFamilyName());
|
||||
} else if (columnIndex == 2) {
|
||||
return user.getScreenName();
|
||||
} else if (columnIndex == 3) {
|
||||
return user.getEmailAddresses().get(0).getAddress();
|
||||
} else if (columnIndex == 4) {
|
||||
return user.getSsoLogin();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyAt(final int columnIndex) {
|
||||
return users.get(index).getSubjectId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
index++;
|
||||
return index < users.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.EmailAddress;
|
||||
import org.libreccm.core.PersonName;
|
||||
import org.libreccm.core.User;
|
||||
import org.libreccm.core.UserRepository;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
|
||||
/**
|
||||
* Form used to edit the information for a user.
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
class UserEditForm extends UserForm
|
||||
implements FormInitListener,
|
||||
FormProcessListener {
|
||||
// Logging
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(UserEditForm.class);
|
||||
|
||||
private UserBrowsePane m_browsePane;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public UserEditForm(UserBrowsePane browsePane) {
|
||||
super(USER_FORM_EDIT);
|
||||
m_browsePane = browsePane;
|
||||
|
||||
addInitListener(this);
|
||||
addProcessListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form
|
||||
*/
|
||||
public void init(FormSectionEvent e) {
|
||||
|
||||
PageState state = e.getPageState();
|
||||
|
||||
hideSecurityInfo(state);
|
||||
|
||||
final User user = m_browsePane.getUser(state);
|
||||
|
||||
final PersonName name = user.getName();
|
||||
m_firstName.setValue(state, name.getGivenName());
|
||||
m_lastName.setValue(state, name.getFamilyName());
|
||||
|
||||
m_primaryEmail.setValue(state, user.getEmailAddresses().get(
|
||||
0).getAddress());
|
||||
|
||||
m_screenName.setValue(state, user.getScreenName());
|
||||
|
||||
USER_FORM_LABEL_ADDITIONAL_EMAIL_LIST.setVisible(state, true);
|
||||
m_emailList.setVisible(state, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the form
|
||||
*/
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final User user = m_browsePane.getUser(state);
|
||||
|
||||
final PersonName name = user.getName();
|
||||
name.setGivenName((String) m_firstName.getValue(state));
|
||||
name.setFamilyName((String) m_lastName.getValue(state));
|
||||
|
||||
user.setScreenName((String) m_screenName.getValue(state));
|
||||
|
||||
InternetAddress additional = (InternetAddress) m_additionalEmail
|
||||
.getValue(state);
|
||||
if (additional != null) {
|
||||
final EmailAddress additionalEmail = new EmailAddress();
|
||||
additional.setAddress(additional.getAddress());
|
||||
user.addEmailAddress(additionalEmail);
|
||||
}
|
||||
|
||||
// Check to see if the primary email address has changed, and
|
||||
// if so set it to the new value and delete the association
|
||||
// with the old. If it hasn't change don't do anything.
|
||||
final EmailAddress oaddr = user.getEmailAddresses().get(0);
|
||||
final EmailAddress naddr = new EmailAddress();
|
||||
naddr.setAddress((String) m_primaryEmail.getValue(state));
|
||||
|
||||
if (!oaddr.equals(naddr)) {
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Changing primary email " + oaddr + " to " + naddr);
|
||||
}
|
||||
|
||||
user.addEmailAddress(naddr);
|
||||
user.removeEmailAddress(oaddr);
|
||||
}
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
|
||||
m_browsePane.displayUserInfoPanel(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormValidationListener;
|
||||
import com.arsdigita.bebop.event.ParameterEvent;
|
||||
import com.arsdigita.bebop.form.Password;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.EmailParameter;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.parameters.URLParameter;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
import com.arsdigita.kernel.security.SecurityConfig;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import com.arsdigita.ui.login.PasswordValidationListener;
|
||||
import com.arsdigita.util.StringUtils;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.User;
|
||||
import org.libreccm.core.UserRepository;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Generic form for adding and editting user.
|
||||
*
|
||||
* @author David Dao
|
||||
* @version $Id$
|
||||
*/
|
||||
class UserForm extends Form implements FormValidationListener, AdminConstants {
|
||||
|
||||
protected TextField m_firstName;
|
||||
protected TextField m_lastName;
|
||||
protected TextField m_primaryEmail;
|
||||
protected TextField m_additionalEmail;
|
||||
protected Password m_password;
|
||||
protected Password m_confirmPassword;
|
||||
protected TextField m_question;
|
||||
protected TextField m_answer;
|
||||
protected TextField m_screenName;
|
||||
protected EmailList m_emailList;
|
||||
private final PasswordValidationListener m_pwListener;
|
||||
private final NotEmptyValidationListener m_notNullListener;
|
||||
private final SecurityConfig securityConfig = SecurityConfig.getConfig();
|
||||
|
||||
public UserForm(String formName) {
|
||||
super(formName);
|
||||
|
||||
m_pwListener = new PasswordValidationListener();
|
||||
m_notNullListener = new NotEmptyValidationListener();
|
||||
|
||||
addValidationListener(this);
|
||||
|
||||
// Bug #163373 add length checking for first/last names. We
|
||||
// do this with both maximum length parameters in the user/add
|
||||
// form and with validation of the value that come in for
|
||||
// processing.
|
||||
int max = 60;
|
||||
|
||||
m_firstName = new TextField(
|
||||
new StringParameter(USER_FORM_INPUT_FIRST_NAME));
|
||||
m_firstName.setMaxLength(max);
|
||||
m_firstName.setSize(20);
|
||||
m_firstName.addValidationListener(new NotEmptyValidationListener());
|
||||
m_firstName.addValidationListener(
|
||||
new StringLengthValidationListener(max));
|
||||
|
||||
add(USER_FORM_LABEL_FIRST_NAME);
|
||||
add(m_firstName);
|
||||
|
||||
m_lastName = new TextField(
|
||||
new StringParameter(USER_FORM_INPUT_LAST_NAME));
|
||||
m_lastName.setMaxLength(max);
|
||||
m_lastName.setSize(25);
|
||||
m_lastName.addValidationListener(new NotEmptyValidationListener());
|
||||
m_lastName
|
||||
.addValidationListener(new StringLengthValidationListener(max));
|
||||
|
||||
add(USER_FORM_LABEL_LAST_NAME);
|
||||
add(m_lastName);
|
||||
|
||||
// Password
|
||||
m_password = new Password(new StringParameter(USER_FORM_INPUT_PASSWORD));
|
||||
add(USER_FORM_LABEL_PASSWORD);
|
||||
add(m_password);
|
||||
|
||||
// Password confirmation
|
||||
m_confirmPassword = new Password(new StringParameter(
|
||||
USER_FORM_INPUT_PASSWORD_CONFIRMATION));
|
||||
|
||||
add(USER_FORM_LABEL_PASSWORD_CONFIRMATION);
|
||||
add(m_confirmPassword);
|
||||
|
||||
// Password question
|
||||
m_question
|
||||
= new TextField(new StringParameter(USER_FORM_INPUT_QUESTION));
|
||||
m_question.setSize(50);
|
||||
|
||||
if (securityConfig.getEnableQuestion()) {
|
||||
add(USER_FORM_LABEL_QUESTION);
|
||||
add(m_question);
|
||||
}
|
||||
|
||||
// Password answer
|
||||
m_answer = new TextField(new StringParameter(USER_FORM_INPUT_ANSWER));
|
||||
m_answer.setSize(50);
|
||||
|
||||
if (securityConfig.getEnableQuestion()) {
|
||||
add(USER_FORM_LABEL_ANSWER);
|
||||
add(m_answer);
|
||||
}
|
||||
|
||||
// Primary email address
|
||||
m_primaryEmail = new TextField(new EmailParameter(
|
||||
USER_FORM_INPUT_PRIMARY_EMAIL));
|
||||
m_primaryEmail.addValidationListener(new NotEmptyValidationListener());
|
||||
m_primaryEmail.setSize(50);
|
||||
add(USER_FORM_LABEL_PRIMARY_EMAIL);
|
||||
add(m_primaryEmail);
|
||||
|
||||
// Additional email addresses
|
||||
m_emailList = new EmailList();
|
||||
add(USER_FORM_LABEL_ADDITIONAL_EMAIL_LIST);
|
||||
add(m_emailList);
|
||||
|
||||
m_additionalEmail = new TextField(new EmailParameter(
|
||||
USER_FORM_INPUT_ADDITIONAL_EMAIL));
|
||||
m_additionalEmail.setSize(50);
|
||||
add(USER_FORM_LABEL_ADDITIONAL_EMAIL);
|
||||
add(m_additionalEmail);
|
||||
|
||||
// Screen name
|
||||
m_screenName = new TextField(new StringParameter(
|
||||
USER_FORM_INPUT_SCREEN_NAME));
|
||||
if (KernelConfig.getConfig().screenNameIsPrimaryIdentifier()) {
|
||||
m_screenName.addValidationListener(new NotEmptyValidationListener());
|
||||
}
|
||||
add(USER_FORM_LABEL_SCREEN_NAME);
|
||||
add(m_screenName);
|
||||
|
||||
// Submit
|
||||
add(new Label(""));
|
||||
add(new Submit(USER_FORM_SUBMIT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the form. Verifies that the password and password-confirm fields
|
||||
* match. If not it adds an error to the password-confirm field. Also
|
||||
* verifies that primary email address and screen name are unique amoung all
|
||||
* users.
|
||||
*/
|
||||
@Override
|
||||
public void validate(FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
PageState ps = event.getPageState();
|
||||
FormData data = event.getFormData();
|
||||
HttpServletRequest req = ps.getRequest();
|
||||
|
||||
// UserID will be null if this is an add form.
|
||||
BigDecimal userID = (BigDecimal) ps.getValue(USER_ID_PARAM);
|
||||
|
||||
/**
|
||||
* Verify that password and confirmation match.
|
||||
*/
|
||||
if (userID == null) {
|
||||
|
||||
m_pwListener.validate(
|
||||
new ParameterEvent(event.getSource(),
|
||||
data.getParameter(
|
||||
USER_FORM_INPUT_PASSWORD)));
|
||||
m_notNullListener.validate(
|
||||
new ParameterEvent(event.getSource(),
|
||||
data.getParameter(
|
||||
USER_FORM_INPUT_PASSWORD_CONFIRMATION)));
|
||||
String password = (String) m_password.getValue(ps);
|
||||
String confirm = (String) m_confirmPassword.getValue(ps);
|
||||
|
||||
if (!StringUtils.emptyString(password) && !StringUtils.emptyString(
|
||||
confirm)) {
|
||||
if (!password.equals(confirm)) {
|
||||
data.addError(USER_FORM_INPUT_PASSWORD_CONFIRMATION,
|
||||
(String) USER_FORM_ERROR_PASSWORD_NOT_MATCH.
|
||||
localize(req));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (securityConfig.getEnableQuestion()) {
|
||||
// If the password answer is anything but null, make sure it
|
||||
// contains some non-whitespace characters
|
||||
String answer = (String) m_answer.getValue(ps);
|
||||
if (userID == null) {
|
||||
// Check for add form.
|
||||
if (answer == null || answer.trim().length() == 0) {
|
||||
data.addError(USER_FORM_INPUT_ANSWER,
|
||||
(String) USER_FORM_ERROR_ANSWER_NULL.localize(
|
||||
req));
|
||||
}
|
||||
} else {
|
||||
// Check for edit form
|
||||
if (answer != null && answer.length() > 0 && answer.trim().
|
||||
length()
|
||||
== 0) {
|
||||
data.addError(USER_FORM_INPUT_ANSWER,
|
||||
(String) USER_FORM_ERROR_ANSWER_NULL.localize(
|
||||
req));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that primary email and screen name are unique
|
||||
*/
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch (CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
final String screenName = (String) m_screenName.getValue(ps);
|
||||
final User userByScreenname = userRepository.findByScreenName(
|
||||
screenName);
|
||||
final String email;
|
||||
if (m_primaryEmail.getValue(ps) != null) {
|
||||
email = ((InternetAddress) m_primaryEmail.getValue(ps)).getAddress();
|
||||
} else {
|
||||
email = null;
|
||||
}
|
||||
final User userByEmail = userRepository.findByEmailAddress(email);
|
||||
|
||||
if (userByScreenname != null && screenName != null && screenName.equals(
|
||||
userByScreenname.getScreenName())) {
|
||||
data.addError(USER_FORM_INPUT_SCREEN_NAME,
|
||||
USER_FORM_ERROR_SCREEN_NAME_NOT_UNIQUE);
|
||||
}
|
||||
|
||||
if (userByEmail != null
|
||||
&& email != null
|
||||
&& email.equals(userByEmail.getEmailAddresses().get(0).getAddress())) {
|
||||
data.addError(USER_FORM_INPUT_PRIMARY_EMAIL,
|
||||
USER_FORM_ERROR_PRIMARY_EMAIL_NOT_UNIQUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide all security-related components
|
||||
*/
|
||||
protected void hideSecurityInfo(PageState state) {
|
||||
setSecurityInfo(state, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all security-related components
|
||||
*/
|
||||
protected void showSecurityInfo(PageState state) {
|
||||
setSecurityInfo(state, true);
|
||||
}
|
||||
|
||||
private void setSecurityInfo(PageState state, boolean isVisible) {
|
||||
|
||||
USER_FORM_LABEL_PASSWORD.setVisible(state, isVisible);
|
||||
USER_FORM_LABEL_PASSWORD_CONFIRMATION.setVisible(state, isVisible);
|
||||
if (securityConfig.getEnableQuestion()) {
|
||||
USER_FORM_LABEL_QUESTION.setVisible(state, isVisible);
|
||||
USER_FORM_LABEL_ANSWER.setVisible(state, isVisible);
|
||||
}
|
||||
|
||||
m_password.setVisible(state, isVisible);
|
||||
m_confirmPassword.setVisible(state, isVisible);
|
||||
if (securityConfig.getEnableQuestion()) {
|
||||
m_question.setVisible(state, isVisible);
|
||||
m_answer.setVisible(state, isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.ui.admin;
|
||||
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormValidationListener;
|
||||
import com.arsdigita.bebop.form.Password;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.mail.Mail;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminConstants.*;
|
||||
|
||||
import com.arsdigita.ui.login.PasswordValidationListener;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiLookupException;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.User;
|
||||
import org.libreccm.core.UserManager;
|
||||
import org.libreccm.core.UserRepository;
|
||||
|
||||
/**
|
||||
* Form used to update a user's password. It just provides form elements to
|
||||
* enter the new password and confirm it. If the user doesn't have an
|
||||
* authentication record, it will be created as part of setting the new value of
|
||||
* the password.
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
class UserPasswordForm extends Form
|
||||
implements FormInitListener,
|
||||
FormProcessListener,
|
||||
FormValidationListener {
|
||||
|
||||
// Logging
|
||||
private static final Logger s_log = Logger.getLogger(UserPasswordForm.class
|
||||
.getName());
|
||||
|
||||
// Constants
|
||||
final static String PASSWORD_FORM_NAME = "password-update";
|
||||
final static String NEW_PASSWORD_PARAM_NAME = "password-new";
|
||||
final static String CONFIRM_PASSWORD_PARAM_NAME = "password-confirm";
|
||||
|
||||
private UserBrowsePane m_userBrowsePane;
|
||||
|
||||
private TextField m_question;
|
||||
private TextField m_answer;
|
||||
private TextField m_ssoLogin;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public UserPasswordForm(UserBrowsePane pane) {
|
||||
super(PASSWORD_FORM_NAME);
|
||||
|
||||
m_userBrowsePane = pane;
|
||||
|
||||
setMethod(Form.POST);
|
||||
|
||||
addInitListener(this);
|
||||
addValidationListener(this);
|
||||
addProcessListener(this);
|
||||
|
||||
// Password
|
||||
Password newPassword = new Password(NEW_PASSWORD_PARAM_NAME);
|
||||
newPassword.addValidationListener(new PasswordValidationListener());
|
||||
add(PASSWORD_FORM_LABEL_PASSWORD);
|
||||
add(newPassword);
|
||||
|
||||
// Password confirmation
|
||||
Password confirmPassword = new Password(CONFIRM_PASSWORD_PARAM_NAME);
|
||||
confirmPassword.addValidationListener(new NotNullValidationListener());
|
||||
add(PASSWORD_FORM_LABEL_CONFIRMATION_PASSWORD);
|
||||
add(confirmPassword);
|
||||
|
||||
// Password question
|
||||
m_question
|
||||
= new TextField(new StringParameter(USER_FORM_INPUT_QUESTION));
|
||||
m_question.setSize(50);
|
||||
m_question.addValidationListener(new NotEmptyValidationListener());
|
||||
add(PASSWORD_FORM_LABEL_QUESTION);
|
||||
add(m_question);
|
||||
|
||||
// Password answer
|
||||
m_answer = new TextField(new StringParameter(USER_FORM_INPUT_ANSWER));
|
||||
m_answer.setSize(50);
|
||||
add(PASSWORD_FORM_LABEL_ANSWER);
|
||||
add(m_answer);
|
||||
|
||||
m_ssoLogin = new TextField(new StringParameter(USER_FORM_INPUT_SSO));
|
||||
m_ssoLogin.setSize(50);
|
||||
add(USER_FORM_LABEL_SSO);
|
||||
add(m_ssoLogin);
|
||||
|
||||
// submit button
|
||||
add(new Label(""));
|
||||
add(new Submit(PASSWORD_FORM_SUBMIT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the form
|
||||
*/
|
||||
@Override
|
||||
public void init(final FormSectionEvent event) {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
final User user = userRepository.findById((Long) state.getValue(
|
||||
USER_ID_PARAM));
|
||||
|
||||
|
||||
m_question.setValue(state, user.getPasswordQuestion());
|
||||
m_ssoLogin.setValue(state, user.getSsoLogin());
|
||||
|
||||
m_answer.setValue(state, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the form input.
|
||||
*/
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
PageState state = event.getPageState();
|
||||
FormData data = event.getFormData();
|
||||
HttpServletRequest req = state.getRequest();
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
final User user = userRepository.findById((Long) state.getValue(
|
||||
USER_ID_PARAM));
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// get parameter values
|
||||
String newPassword = (String) data.get(NEW_PASSWORD_PARAM_NAME);
|
||||
String confirmPassword = (String) data.get(
|
||||
CONFIRM_PASSWORD_PARAM_NAME);
|
||||
|
||||
// check new password
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
data.addError(CONFIRM_PASSWORD_PARAM_NAME,
|
||||
(String) USER_FORM_ERROR_PASSWORD_NOT_MATCH
|
||||
.localize(req));
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
if (!data.isValid()) {
|
||||
// clear passwords from form data
|
||||
data.put(NEW_PASSWORD_PARAM_NAME, "");
|
||||
data.put(CONFIRM_PASSWORD_PARAM_NAME, "");
|
||||
}
|
||||
}
|
||||
|
||||
// If the password answer is anything but null, make sure it
|
||||
// contains some non-whitespace characters
|
||||
String answer = (String) m_answer.getValue(state);
|
||||
if (answer != null && answer.length() > 0 && answer.trim().length() == 0) {
|
||||
data.addError(USER_FORM_INPUT_ANSWER,
|
||||
(String) USER_FORM_ERROR_ANSWER_NULL.localize(req));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the form
|
||||
*/
|
||||
public void process(FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
final FormData data = event.getFormData();
|
||||
|
||||
final CdiUtil cdiUtil = new CdiUtil();
|
||||
final UserRepository userRepository;
|
||||
final UserManager userManager;
|
||||
try {
|
||||
userRepository = cdiUtil.findBean(UserRepository.class);
|
||||
userManager = cdiUtil.findBean(UserManager.class);
|
||||
} catch(CdiLookupException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
final User user = userRepository.findById((Long) state.getValue(
|
||||
USER_ID_PARAM));
|
||||
if (user == null) {
|
||||
throw new FormProcessException(GlobalizationUtil.globalize(
|
||||
"ui.admin.user.userpasswordform.retrieving_user_failed"));
|
||||
}
|
||||
|
||||
userManager.updatePassword(user, (String) data.get(NEW_PASSWORD_PARAM_NAME));
|
||||
user.setPasswordQuestion((String) m_question.getValue(state));
|
||||
final String answer = (String) m_answer.getValue(state);
|
||||
if (answer != null && answer.length() > 0) {
|
||||
user.setPasswordAnswer(answer);
|
||||
}
|
||||
user.setSsoLogin((String) m_ssoLogin.getValue(state));
|
||||
|
||||
userRepository.save(user);
|
||||
|
||||
BigDecimal id = (BigDecimal) state.getValue(USER_ID_PARAM);
|
||||
|
||||
s_log.debug("Committed password change");
|
||||
|
||||
notifyUser(user);
|
||||
m_userBrowsePane.displayUserInfoPanel(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify user of the change to their password.
|
||||
*
|
||||
* TODO:
|
||||
* <ol>
|
||||
* <li>Message should be from the syadmin</li>
|
||||
* <li>Globalize the subject and content</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param user is the User who's password was just changed.
|
||||
*/
|
||||
private void notifyUser(final User user) {
|
||||
String to = user.getEmailAddresses().get(0).getAddress();
|
||||
String from = to;
|
||||
String subject = "Your password has been changed";
|
||||
String nl = System.getProperty("line.separator");
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("Dear ");
|
||||
sb.append(user.getName().getGivenName());
|
||||
sb.append(":");
|
||||
sb.append(nl).append(nl);
|
||||
sb.append("Your password has been changed by the ");
|
||||
sb.append("system administrator.");
|
||||
sb.append(nl);
|
||||
|
||||
try {
|
||||
Mail.send(to, from, subject, sb.toString());
|
||||
} catch (javax.mail.MessagingException e) {
|
||||
s_log.error("Failed to notify user of password change");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
package org.libreccm.core;
|
||||
|
||||
import static org.libreccm.core.CoreConstants.*;
|
||||
import static org.libreccm.core.CoreConstants.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -42,14 +42,17 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
|
||||
/**
|
||||
* A {@code Group} is collection of {@link User}s.
|
||||
*
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "CCM_GROUPS", schema = DB_SCHEMA)
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "Group.findGroupByName",
|
||||
query = "SELECT g FROM Group g WHERE g.name = :groupName")
|
||||
@NamedQuery(name = "Group.findGroupByName",
|
||||
query = "SELECT g FROM Group g WHERE g.name = :groupName"),
|
||||
@NamedQuery(name = "Group.searchGroupByName",
|
||||
query = "SELECT g FROM Group g "
|
||||
+ "WHERE LOWER(g.name) LIKE '%:groupName%'")
|
||||
})
|
||||
@XmlRootElement(name = "user-group", namespace = CORE_XML_NS)
|
||||
public class Group extends Subject implements Serializable {
|
||||
|
|
@ -69,11 +72,11 @@ public class Group extends Subject implements Serializable {
|
|||
*/
|
||||
@OneToMany(mappedBy = "sourceGroup")
|
||||
@XmlElementWrapper(name = "roles", namespace = CORE_XML_NS)
|
||||
@XmlElement(name ="role", namespace = CORE_XML_NS)
|
||||
@XmlElement(name = "role", namespace = CORE_XML_NS)
|
||||
private List<Role> roles;
|
||||
|
||||
/**
|
||||
* The members of the group. For adding or removing members the methods
|
||||
* The members of the group. For adding or removing members the methods
|
||||
* provided by the {@link GroupManager} should be used.
|
||||
*/
|
||||
@OneToMany(mappedBy = "group")
|
||||
|
|
@ -160,7 +163,7 @@ public class Group extends Subject implements Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(this.name, other.getName());
|
||||
return Objects.equals(this.name, other.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -66,5 +66,13 @@ public class GroupRepository extends AbstractEntityRepository<Long, Group> {
|
|||
return result.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Group> searchGroupByName(final String groupName) {
|
||||
final TypedQuery<Group> query = entityManager.createNamedQuery(
|
||||
"Group.searchGroupByName", Group.class);
|
||||
query.setParameter("groupName", groupName);
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
ui.admin.dispatcher.accessDenied=Access Denied
|
||||
ui.admin.dispatcher.contextTitle=Index
|
||||
ui.admin.dispatcher.groupsLabel=Groups
|
||||
ui.admin.dispatcher.title=Administration
|
||||
ui.admin.dispatcher.usersLabel=Users
|
||||
ui.admin.groups.actioncontinue=Continue
|
||||
ui.admin.groups.groupdeletefailed=Unable to delete group
|
||||
ui.admin.groups.add=Create new subgroup
|
||||
ui.admin.groups.addeditform.namelabel=Name:
|
||||
ui.admin.groups.addeditform.primaryemaillabel=Primary email:
|
||||
ui.admin.groups.addeditform.submit=Save
|
||||
ui.admin.groups.addgrouplabel=Add new group
|
||||
ui.admin.groups.addsubmemberlabel=Add member
|
||||
ui.admin.groups.delete=Delete group
|
||||
ui.admin.groups.deletefailed=Error message
|
||||
ui.admin.groups.edit=Edit
|
||||
ui.admin.groups.groupedit=Edit Group
|
||||
ui.admin.groups.extremeaction=Extreme Action
|
||||
ui.admin.groups.groupinformation=Basic Information
|
||||
ui.admin.groups.removesubmemberlabel=Remove
|
||||
ui.admin.groups.subgroupcountlabel=Sub groups:
|
||||
ui.admin.groups.subgroups=Subgroup Information
|
||||
ui.admin.groups.submembers=Member Information
|
||||
# new labels added - cg 15/6/04
|
||||
ui.admin.groups.addExisting=Add existing group as subgroup
|
||||
ui.admin.groups.removeExisting=Remove as subgroup
|
||||
ui.admin.groups.search=Search for groups to add as subgroups
|
||||
ui.admin.groups.button.search=Search
|
||||
ui.admin.groups.searchForm.noResults=Your search matches no valid groups (groups that cause circular references are excluded). Search again
|
||||
ui.admin.groups.found.title=Select groups
|
||||
ui.admin.groups.select.explanation=Select the groups:
|
||||
ui.admin.save=Save
|
||||
ui.admin.nav.logout=Log out
|
||||
ui.admin.nav.workspace=Workspace
|
||||
ui.admin.searchAndList.submit=Search
|
||||
ui.admin.searchAndList.submitAgain=Search Again
|
||||
ui.admin.tab.group=Groups
|
||||
ui.admin.tab.user.browse=Browse
|
||||
ui.admin.tab.user.createuser=Create new user
|
||||
ui.admin.tab.user.navbartitle=User Administration
|
||||
ui.admin.tab.user.search=Search
|
||||
ui.admin.tab.user.summary=Summary
|
||||
ui.admin.tab.user=Users
|
||||
ui.admin.user.action.continue=Continue
|
||||
ui.admin.user.action.delete.failed.header=Unable to delete user
|
||||
ui.admin.user.action.header=Actions
|
||||
ui.admin.user.addeditform.additionalemail=Additional Email Address:
|
||||
ui.admin.user.addeditform.additionalemaillist=Additional Email
|
||||
ui.admin.user.addeditform.answer=Answer:
|
||||
ui.admin.user.addeditform.confirmation=Password Confirmation:
|
||||
ui.admin.user.addeditform.deleteemail=Delete
|
||||
ui.admin.user.addeditform.error.answer.null=This parameter is required.
|
||||
ui.admin.user.addeditform.error.answer.whitespace=Answer must be empty or contain non-whitespace characters
|
||||
ui.admin.user.addeditform.error.password.notmatch=Passwords do not match
|
||||
ui.admin.user.addeditform.error.primaryemail.notunique=Primary email is not unique
|
||||
ui.admin.user.addeditform.error.screenname.notunique=Screen name is not unique
|
||||
ui.admin.user.addeditform.firstname=First Name:
|
||||
ui.admin.user.addeditform.lastname=Last Name:
|
||||
ui.admin.user.addeditform.password=Password:
|
||||
ui.admin.user.addeditform.primaryemail=Primary Email Address:
|
||||
ui.admin.user.addeditform.question=Question:
|
||||
ui.admin.user.addeditform.screenname=Screen Name:
|
||||
ui.admin.user.addeditform.ssologinname=External Login:
|
||||
ui.admin.user.addeditform.submit=Save
|
||||
ui.admin.user.addeditform.url=URL:
|
||||
ui.admin.user.browselink=Show All
|
||||
ui.admin.user.browsepanel.becomeUser=Become this user
|
||||
ui.admin.user.browsepanel.extremeaction=Extreme Actions
|
||||
ui.admin.user.browsepanel.header=All Registered Users
|
||||
ui.admin.user.browsepanel.updatePassword=Update Password
|
||||
ui.admin.user.createpanel.header=Create new user
|
||||
ui.admin.user.delete.confirm=Are you sure you want to delete this user?
|
||||
ui.admin.user.ban.confirm=Are you sure you want to ban this user?
|
||||
ui.admin.user.unban.confirm=Are you sure you want to unban this user?
|
||||
ui.admin.user.ban.label=Ban user
|
||||
ui.admin.user.unban.label=Unban user
|
||||
ui.admin.user.delete.failed.label=User Delete Failed
|
||||
ui.admin.user.delete.label=Delete user
|
||||
ui.admin.user.editlink=Edit
|
||||
ui.admin.user.groupmembership.header=Group Membership
|
||||
ui.admin.user.password.header=Update Security Information
|
||||
ui.admin.user.search.header=Search
|
||||
ui.admin.user.summarypanel.createUser=Create new user
|
||||
ui.admin.user.summarypanel.header=Summary
|
||||
ui.admin.user.summarypanel.totalusers=Total users:
|
||||
ui.admin.user.useredit.header=Edit User Information
|
||||
ui.admin.user.userinfo.header=User Information
|
||||
ui.admin.user.userpasswordform.answer=Answer:<br>(<font size="-1">Leave blank to retain current answer</font>)
|
||||
ui.admin.user.userpasswordform.confirmpasswordlabel=Confirm password:
|
||||
ui.admin.user.userpasswordform.passwordlabel=Password:
|
||||
ui.admin.user.userpasswordform.question=Question:
|
||||
ui.admin.user.userpasswordform.submit=Change
|
||||
ui.admin.tab.applications=Applications
|
||||
ui.admin.applications.tree.heading=Applications
|
||||
ui.admin.applications.url.validation.not_blank=The URL of an application instance can is mandatory.
|
||||
ui.admin.applications.url.valiation.minmaxlength=The length of an URL of an application instance must be between 1 and 100 characters.
|
||||
ui.admin.applications.title.validation.not_blank=Title is mandatory for an application instance.
|
||||
ui.admin.applications.title.valiation.minmaxlength=The minimum length of the title of an applicatio instance is one character, the maximum length are 200 characters
|
||||
ui.admin.applications.desc.valiation.minmaxlength=The maximum length of a descrption of an application instance are 4000 characters.
|
||||
ui.admin.applications.url.label=URL
|
||||
ui.admin.applications.title.label=Title
|
||||
ui.admin.applications.desc.label=Description
|
||||
ui.admin.applications.url.validation.url_already_in_use=The provided URL is already in use
|
||||
ui.admin.applications.url.validation.no_slash_allowed=The URL fragement may not contain slashes
|
||||
ui.admin.applications.ApplicationInstancePane.title.label=Title of the instance
|
||||
ui.admin.applications.ApplicationInstancePane.parent_app.label=Parent application
|
||||
ui.admin.applications.ApplicationInstancePane.path.label=Path of the application
|
||||
ui.admin.applications.ApplicationInstancePane.desc.label=Description
|
||||
ui.admin.applications.ApplicationInstancePane.info.heading=Instance data
|
||||
ui.admin.MultiInstanceApplicationPane.manage.heading=Edit instance specific settings
|
||||
ui.admin.MultiInstancePane.manage.no_instance_admin_pane_found=No instance admin pane for instances of the application type '{0]' found. Maybe it is not implemented yet.
|
||||
ui.admin.applications.ApplicationInfoSection.title.label=Title
|
||||
ui.admin.applications.ApplicationInfoSection.app_class.label=Application Class
|
||||
ui.admin.applications.ApplicationInfoSection.singleton.label=Singleton
|
||||
ui.admin.applications.ApplicationInfoSection.singleton.yes=Yes
|
||||
ui.admin.applications.ApplicationInfoSection.singleton.no=No
|
||||
ui.admin.applications.ApplicationInfoSection.singleton_instance.path.label=Path of the singleton instance
|
||||
ui.admin.applications.ApplicationInfoSection.singleton_instance.no_instance_found=No instance found
|
||||
ui.admin.applications.ApplicationInfoSection.heading=Application information
|
||||
ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_title.header=Title
|
||||
ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_url.header=Path
|
||||
ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_desc.header=Description
|
||||
ui.admin.MultiInstanceApplicationPane.instances=Instances
|
||||
ui.admin.MultiInstanceApplicationPane.manage_instances.heading=Manage instances
|
||||
ui.admin.MultiInstancePane.manage.no_create_form_found=No form for manageing instances of type '{0}' found.
|
||||
ui.admin.MultiInstanceApplicationPane.create_instance=Create new instance
|
||||
ui.admin.SingletonApplicationPane.manage.heading=Edit settings
|
||||
ui.admin.SingletonApplicationPane.manage.no_admin_pane_found=No admin pane for applications of type '{0}' found.
|
||||
ui.admin.applications.ApplicationInfoSection.desc.label=Description
|
||||
ui.admin.applications.no_settings=This application has no settings (yet).
|
||||
ui.admin.applications.form_not_compatible_now=This application administration form is not yet compatible with this application pane. Please use the applications own administration form.
|
||||
ui.admin.applications.ApplicationInstancePane.manage.heading=Instance specific settings
|
||||
ui.admin.applications.parent.label=Select parent application
|
||||
ui.admin.user.userinfo.name=Name:
|
||||
ui.admin.user.userinfo.screenname=Username:
|
||||
ui.admin.user.userinfo.primaryemail=Email:
|
||||
ui.admin.groups.name=Name:
|
||||
ui.admin.applications.placeholder=There is no administration panel for instances of this application type yet.
|
||||
ui.admin.cancel=Cancel
|
||||
ui.admin.cancel_msg=Submission cancelled
|
||||
ui.admin.tab.sysinfo.title=System information
|
||||
ui.admin.sysinfo.appinfo=About
|
||||
ui.admin.sysinfo.java_system_properties=Java system properties
|
||||
ui.admin.sysinfo.xml_transformer_factory=XML Transformer Factory
|
||||
ui.admin.sysinfo.xml_transformer=XML Transformer
|
||||
ui.admin.sysinfo.xml_document_builder_factory=XML Document Builder Factory
|
||||
ui.admin.sysinfo.xml_document_builder=XML Document Builder
|
||||
ui.admin.sysinfo.sax_parser_factory=SAX Parser Factory
|
||||
ui.admin.sysinfo.sax_parser=SAX Parser
|
||||
ui.admin.sysinfo.xml_config=XML config
|
||||
#ID ist null
|
||||
ui.admin.groups.ID_is_null=ID is null
|
||||
ui.admin.user.userpasswordform.retrieving_user_failed=Failed to retrieve user
|
||||
ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
ui.admin.dispatcher.accessDenied=Zugang abgelehnt
|
||||
ui.admin.dispatcher.contextTitle=Index
|
||||
ui.admin.dispatcher.groupsLabel=Gruppen
|
||||
ui.admin.dispatcher.title=Administration
|
||||
ui.admin.dispatcher.usersLabel=Benutzer
|
||||
ui.admin.groups.actioncontinue=Fortsetzen
|
||||
ui.admin.groups.groupdeletefailed=Gruppe nicht zu l\u00f6schbar
|
||||
ui.admin.groups.add=Neue Untergruppe erstellen
|
||||
ui.admin.groups.addeditform.namelabel=Name:
|
||||
ui.admin.groups.addeditform.primaryemaillabel=Prim\u00e4re E-Mail\:
|
||||
ui.admin.groups.addeditform.submit=Sichern
|
||||
ui.admin.groups.addgrouplabel=Neue Gruppe hinzuf\u00fcgen
|
||||
ui.admin.groups.addsubmemberlabel=Mitglied hinzuf\u00fcgen
|
||||
ui.admin.groups.delete=Gruppe l\u00f6schen
|
||||
ui.admin.groups.deletefailed=Fehlermeldung
|
||||
ui.admin.groups.edit=Edit
|
||||
ui.admin.groups.groupedit=Edit Group
|
||||
ui.admin.groups.extremeaction=Extreme Action
|
||||
ui.admin.groups.groupinformation=Basisinformationen
|
||||
ui.admin.groups.removesubmemberlabel=Entfernen
|
||||
ui.admin.groups.subgroupcountlabel=Untergruppen\:
|
||||
ui.admin.groups.subgroups=Untergruppen Information
|
||||
ui.admin.groups.submembers=Mitgliedsinformation
|
||||
# new labels added - cg 15/6/04
|
||||
ui.admin.groups.addExisting=Add existing group as subgroup
|
||||
ui.admin.groups.removeExisting=Als Subgruppe entfernen
|
||||
ui.admin.groups.search=Search for groups to add as subgroups
|
||||
ui.admin.groups.button.search=Suche
|
||||
ui.admin.groups.searchForm.noResults=Your search matches no valid groups (groups that cause circular references are excluded). Search again
|
||||
ui.admin.groups.found.title=Gruppen ausw\u00e4hlen
|
||||
ui.admin.groups.select.explanation=Gruppen ausw\u00e4hlen\:
|
||||
ui.admin.save=Sichern
|
||||
ui.admin.nav.logout=Abmelden
|
||||
ui.admin.nav.workspace=Workspace
|
||||
ui.admin.searchAndList.submit=Suchen
|
||||
ui.admin.searchAndList.submitAgain=Erneut suchen
|
||||
ui.admin.tab.group=Gruppen
|
||||
ui.admin.tab.user.browse=Bl\u00e4ttern
|
||||
ui.admin.tab.user.createuser=Neuen Benutzer erstellen
|
||||
ui.admin.tab.user.navbartitle=Benutzerverwaltung
|
||||
ui.admin.tab.user.search=Suche
|
||||
ui.admin.tab.user.summary=Zusammenfassung
|
||||
ui.admin.tab.user=Benutzer
|
||||
ui.admin.user.action.continue=Fortfahren
|
||||
ui.admin.user.action.delete.failed.header=Benutzer kann nicht gel\u00f6scht werden
|
||||
ui.admin.user.action.header=Aktionen
|
||||
ui.admin.user.addeditform.additionalemail=Weitere E-Mail Adresse\:
|
||||
ui.admin.user.addeditform.additionalemaillist=Weitere E-Mail
|
||||
ui.admin.user.addeditform.answer=Antwort\:
|
||||
ui.admin.user.addeditform.confirmation=Password Confirmation:
|
||||
ui.admin.user.addeditform.deleteemail=Entfernen
|
||||
ui.admin.user.addeditform.error.answer.null=This parameter is required.
|
||||
ui.admin.user.addeditform.error.answer.whitespace=Answer must be empty or contain non-whitespace characters
|
||||
ui.admin.user.addeditform.error.password.notmatch=Passworte stimmen nicht \u00fcberein
|
||||
ui.admin.user.addeditform.error.primaryemail.notunique=Primary email is not unique
|
||||
ui.admin.user.addeditform.error.screenname.notunique=Benutzername ist nicht eindeutig
|
||||
ui.admin.user.addeditform.firstname=Vorname\:
|
||||
ui.admin.user.addeditform.lastname=Nachname\:
|
||||
ui.admin.user.addeditform.password=Password:
|
||||
ui.admin.user.addeditform.primaryemail=Primary Email Address:
|
||||
ui.admin.user.addeditform.question=Frage\:
|
||||
ui.admin.user.addeditform.screenname=Benutzername\:
|
||||
ui.admin.user.addeditform.ssologinname=External Login:
|
||||
ui.admin.user.addeditform.submit=Sichern
|
||||
ui.admin.user.addeditform.url=URL:
|
||||
ui.admin.user.browselink=Show All
|
||||
ui.admin.user.browsepanel.becomeUser=Become this user
|
||||
ui.admin.user.browsepanel.extremeaction=Extreme Actions
|
||||
ui.admin.user.browsepanel.header=Alle registrierten Benutzer
|
||||
ui.admin.user.browsepanel.updatePassword=Update Password
|
||||
ui.admin.user.createpanel.header=Neuen Benutzer erstellen
|
||||
ui.admin.user.delete.confirm=Are you sure you want to delete this user?
|
||||
ui.admin.user.ban.confirm=Are you sure you want to ban this user?
|
||||
ui.admin.user.unban.confirm=Are you sure you want to unban this user?
|
||||
ui.admin.user.ban.label=Ban user
|
||||
ui.admin.user.unban.label=Unban user
|
||||
ui.admin.user.delete.failed.label=L\u00f6schen des Benutzers fehlgeschlagen
|
||||
ui.admin.user.delete.label=Benutzer l\u00f6schen
|
||||
ui.admin.user.editlink=Editieren
|
||||
ui.admin.user.groupmembership.header=Group Membership
|
||||
ui.admin.user.password.header=Update Security Information
|
||||
ui.admin.user.search.header=Search
|
||||
ui.admin.user.summarypanel.createUser=Create new user
|
||||
ui.admin.user.summarypanel.header=Summary
|
||||
ui.admin.user.summarypanel.totalusers=Total users:
|
||||
ui.admin.user.useredit.header=Edit User Information
|
||||
ui.admin.user.userinfo.header=Benutzerinformation
|
||||
ui.admin.user.userpasswordform.answer=Antwort\:<br>(<font size\="-1">Leerlassen um aktuelle Antwort beizubehalten</font>)
|
||||
ui.admin.user.userpasswordform.confirmpasswordlabel=Passwort best\u00e4tigen\:
|
||||
ui.admin.user.userpasswordform.passwordlabel=Passwort\:
|
||||
ui.admin.user.userpasswordform.question=Frage\:
|
||||
ui.admin.user.userpasswordform.submit=\u00c4ndern
|
||||
ui.admin.tab.applications=Applikationen
|
||||
ui.admin.applications.tree.heading=Applikationen
|
||||
ui.admin.applications.url.validation.not_blank=Die Angabe einer URL ist erforderlich
|
||||
ui.admin.applications.url.valiation.minmaxlength=Die URL einer Applikations-Instanz muss zwischen einem und 100 Zeichen lang sein
|
||||
ui.admin.applications.title.validation.not_blank=Der Titel ist f\u00fcr das Anlegen einer Applikations-Instanz erforderlich
|
||||
ui.admin.applications.title.valiation.minmaxlength=Der Titel einer Applikations-Instanz muss zwischen einem und 200 Zeichen lang sein.
|
||||
ui.admin.applications.desc.valiation.minmaxlength=Die Beschreibung einer Applikations-Instanz darf max. 4000 Zeichen lang sein
|
||||
ui.admin.applications.url.label=URL
|
||||
ui.admin.applications.title.label=Bezeichnung
|
||||
ui.admin.applications.desc.label=Beschreibung
|
||||
ui.admin.applications.url.validation.url_already_in_use=Der angegebene URL wird bereits verwendet
|
||||
ui.admin.applications.url.validation.no_slash_allowed=Das URL-Fragment darf keine Schr\u00e4gstriche enthalten
|
||||
ui.admin.applications.ApplicationInstancePane.title.label=Titel der Instanz
|
||||
ui.admin.applications.ApplicationInstancePane.parent_app.label=\u00dcbergeordnete Applikation
|
||||
ui.admin.applications.ApplicationInstancePane.path.label=Pfad der Applikation
|
||||
ui.admin.applications.ApplicationInstancePane.desc.label=Beschreibung
|
||||
ui.admin.applications.ApplicationInstancePane.info.heading=Daten der Instanz
|
||||
ui.admin.MultiInstanceApplicationPane.manage.heading=Einstellungen der Instanz bearbeiten
|
||||
ui.admin.MultiInstancePane.manage.no_instance_admin_pane_found=Kein Administrationsformular f\u00fcr Instanzen des Applikationstyps {0} gefunden. M\u00f6glicherweise noch nicht implementiert.
|
||||
ui.admin.applications.ApplicationInfoSection.title.label=Titel
|
||||
ui.admin.applications.ApplicationInfoSection.app_class.label=Applikationsklasse
|
||||
ui.admin.applications.ApplicationInfoSection.singleton.label=Singleton
|
||||
ui.admin.applications.ApplicationInfoSection.singleton.yes=Ja
|
||||
ui.admin.applications.ApplicationInfoSection.singleton.no=Nein
|
||||
ui.admin.applications.ApplicationInfoSection.singleton_instance.path.label=Pfad der Singleton Instanz
|
||||
ui.admin.applications.ApplicationInfoSection.singleton_instance.no_instance_found=Keine Instanz gefunden
|
||||
ui.admin.applications.ApplicationInfoSection.heading=Applikationsinformationen
|
||||
ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_title.header=Titel
|
||||
ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_url.header=Pfad
|
||||
ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_desc.header=Beschreibung
|
||||
ui.admin.MultiInstanceApplicationPane.instances=Instanzen
|
||||
ui.admin.MultiInstanceApplicationPane.manage_instances.heading=Instanzen verwalten
|
||||
ui.admin.MultiInstancePane.manage.no_create_form_found=Keine Formular zum verwalten von Applikationen des Types {0} gefunden.
|
||||
ui.admin.MultiInstanceApplicationPane.create_instance=Neue instanz anlegen
|
||||
ui.admin.SingletonApplicationPane.manage.heading=Eigenschaften bearbeiten
|
||||
ui.admin.SingletonApplicationPane.manage.no_admin_pane_found=Keine Admin-Formular f\u00fcr Applikationen des Types {0} gefunden
|
||||
ui.admin.applications.ApplicationInfoSection.desc.label=Beschreibung
|
||||
ui.admin.applications.no_settings=Diese Applikation hat (noch) keine Einstellungen.
|
||||
ui.admin.applications.form_not_compatible_now=Das Formular zur Verwaltung dieser Application ist derzeit noch nicht kompatibel mit dieser Administrationsoberfl\u00e4che. Bitte nutzen Sie den Administrationsoberfl\u00e4che der Application.
|
||||
ui.admin.applications.ApplicationInstancePane.manage.heading=Einstellungen der Instanz
|
||||
ui.admin.applications.parent.label=W\u00e4hlen Sie die \u00fcbergeordnete Applikation
|
||||
ui.admin.user.userinfo.name=Name:
|
||||
ui.admin.user.userinfo.screenname=Benutzername:
|
||||
ui.admin.user.userinfo.primaryemail=E-Mail:
|
||||
ui.admin.groups.name=Name:
|
||||
ui.admin.applications.placeholder=F\u00fcr Applikationen dieses Typs gibt es noch keine Verwaltungsoberfl\u00e4che.
|
||||
ui.admin.cancel=Abbrechen
|
||||
ui.admin.cancel_msg=Bearbeitung abgebrochen
|
||||
ui.admin.tab.sysinfo.title=Systeminformationen
|
||||
ui.admin.sysinfo.appinfo=\u00dcber
|
||||
ui.admin.sysinfo.java_system_properties=Java System Properties
|
||||
ui.admin.sysinfo.xml_transformer_factory=XML Transformer Factory
|
||||
ui.admin.sysinfo.xml_transformer=XML Transformer
|
||||
ui.admin.sysinfo.xml_document_builder_factory=XML Document Builder Factory
|
||||
ui.admin.sysinfo.xml_document_builder=XML Document Builder
|
||||
ui.admin.sysinfo.sax_parser_factory=SAX Parser Factory
|
||||
ui.admin.sysinfo.sax_parser=SAX Parser
|
||||
ui.admin.sysinfo.xml_config=XML Konfiguration
|
||||
#ID ist null
|
||||
ui.admin.groups.ID_is_null=ID is null
|
||||
ui.admin.user.userpasswordform.retrieving_user_failed=Konnte Benutzer nicht abrufen
|
||||
ui.admin.groups.couldnt_find_specified_group=Konnte die spezifische Gruppe nicht finden
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
ui.admin.dispatcher.accessDenied=Access Denied
|
||||
ui.admin.dispatcher.contextTitle=Index
|
||||
ui.admin.dispatcher.groupsLabel=Groups
|
||||
ui.admin.dispatcher.title=Administration
|
||||
ui.admin.dispatcher.usersLabel=Users
|
||||
ui.admin.groups.actioncontinue=Continue
|
||||
ui.admin.groups.groupdeletefailed=Unable to delete group
|
||||
ui.admin.groups.add=Create new subgroup
|
||||
ui.admin.groups.addeditform.namelabel=Name:
|
||||
ui.admin.groups.addeditform.primaryemaillabel=Primary email:
|
||||
ui.admin.groups.addeditform.submit=Save
|
||||
ui.admin.groups.addgrouplabel=Add new group
|
||||
ui.admin.groups.addsubmemberlabel=Add member
|
||||
ui.admin.groups.delete=Delete group
|
||||
ui.admin.groups.deletefailed=Error message
|
||||
ui.admin.groups.edit=Edit
|
||||
ui.admin.groups.groupedit=Edit Group
|
||||
ui.admin.groups.extremeaction=Extreme Action
|
||||
ui.admin.groups.groupinformation=Basic Information
|
||||
ui.admin.groups.removesubmemberlabel=Remove
|
||||
ui.admin.groups.subgroupcountlabel=Sub groups:
|
||||
ui.admin.groups.subgroups=Subgroup Information
|
||||
ui.admin.groups.submembers=Member Information
|
||||
# new labels added - cg 15/6/04
|
||||
ui.admin.groups.addExisting=Add existing group as subgroup
|
||||
ui.admin.groups.removeExisting=Remove as subgroup
|
||||
ui.admin.groups.search=Search for groups to add as subgroups
|
||||
ui.admin.groups.button.search=Search
|
||||
ui.admin.groups.searchForm.noResults=Your search matches no valid groups (groups that cause circular references are excluded). Search again
|
||||
ui.admin.groups.found.title=Select groups
|
||||
ui.admin.groups.select.explanation=Select the groups:
|
||||
ui.admin.save=Save
|
||||
ui.admin.nav.logout=Log out
|
||||
ui.admin.nav.workspace=Workspace
|
||||
ui.admin.searchAndList.submit=Search
|
||||
ui.admin.searchAndList.submitAgain=Search Again
|
||||
ui.admin.tab.group=Groups
|
||||
ui.admin.tab.user.browse=Browse
|
||||
ui.admin.tab.user.createuser=Create new user
|
||||
ui.admin.tab.user.navbartitle=User Administration
|
||||
ui.admin.tab.user.search=Search
|
||||
ui.admin.tab.user.summary=Summary
|
||||
ui.admin.tab.user=Users
|
||||
ui.admin.user.action.continue=Continue
|
||||
ui.admin.user.action.delete.failed.header=Unable to delete user
|
||||
ui.admin.user.action.header=Actions
|
||||
ui.admin.user.addeditform.additionalemail=Additional Email Address:
|
||||
ui.admin.user.addeditform.additionalemaillist=Additional Email
|
||||
ui.admin.user.addeditform.answer=Answer:
|
||||
ui.admin.user.addeditform.confirmation=Password Confirmation:
|
||||
ui.admin.user.addeditform.deleteemail=Delete
|
||||
ui.admin.user.addeditform.error.answer.null=This parameter is required.
|
||||
ui.admin.user.addeditform.error.answer.whitespace=Answer must be empty or contain non-whitespace characters
|
||||
ui.admin.user.addeditform.error.password.notmatch=Passwords do not match
|
||||
ui.admin.user.addeditform.error.primaryemail.notunique=Primary email is not unique
|
||||
ui.admin.user.addeditform.error.screenname.notunique=Screen name is not unique
|
||||
ui.admin.user.addeditform.firstname=First Name:
|
||||
ui.admin.user.addeditform.lastname=Last Name:
|
||||
ui.admin.user.addeditform.password=Password:
|
||||
ui.admin.user.addeditform.primaryemail=Primary Email Address:
|
||||
ui.admin.user.addeditform.question=Question:
|
||||
ui.admin.user.addeditform.screenname=Screen Name:
|
||||
ui.admin.user.addeditform.ssologinname=External Login:
|
||||
ui.admin.user.addeditform.submit=Save
|
||||
ui.admin.user.addeditform.url=URL:
|
||||
ui.admin.user.browselink=Show All
|
||||
ui.admin.user.browsepanel.becomeUser=Become this user
|
||||
ui.admin.user.browsepanel.extremeaction=Extreme Actions
|
||||
ui.admin.user.browsepanel.header=All Registered Users
|
||||
ui.admin.user.browsepanel.updatePassword=Update Password
|
||||
ui.admin.user.createpanel.header=Create new user
|
||||
ui.admin.user.delete.confirm=Are you sure you want to delete this user?
|
||||
ui.admin.user.ban.confirm=Are you sure you want to ban this user?
|
||||
ui.admin.user.unban.confirm=Are you sure you want to unban this user?
|
||||
ui.admin.user.ban.label=Ban user
|
||||
ui.admin.user.unban.label=Unban user
|
||||
ui.admin.user.delete.failed.label=User Delete Failed
|
||||
ui.admin.user.delete.label=Delete user
|
||||
ui.admin.user.editlink=Edit
|
||||
ui.admin.user.groupmembership.header=Group Membership
|
||||
ui.admin.user.password.header=Update Security Information
|
||||
ui.admin.user.search.header=Search
|
||||
ui.admin.user.summarypanel.createUser=Create new user
|
||||
ui.admin.user.summarypanel.header=Summary
|
||||
ui.admin.user.summarypanel.totalusers=Total users:
|
||||
ui.admin.user.useredit.header=Edit User Information
|
||||
ui.admin.user.userinfo.header=User Information
|
||||
ui.admin.user.userpasswordform.answer=Answer:<br>(<font size="-1">Leave blank to retain current answer</font>)
|
||||
ui.admin.user.userpasswordform.confirmpasswordlabel=Confirm password:
|
||||
ui.admin.user.userpasswordform.passwordlabel=Password:
|
||||
ui.admin.user.userpasswordform.question=Question:
|
||||
ui.admin.user.userpasswordform.submit=Change
|
||||
ui.admin.tab.applications=Applications
|
||||
ui.admin.applications.tree.heading=Applications
|
||||
ui.admin.applications.url.validation.not_blank=The URL of an application instance can is mandatory.
|
||||
ui.admin.applications.url.valiation.minmaxlength=The length of an URL of an application instance must be between 1 and 100 characters.
|
||||
ui.admin.applications.title.validation.not_blank=Title is mandatory for an application instance.
|
||||
ui.admin.applications.title.valiation.minmaxlength=The minimum length of the title of an applicatio instance is one character, the maximum length are 200 characters
|
||||
ui.admin.applications.desc.valiation.minmaxlength=The maximum length of a descrption of an application instance are 4000 characters.
|
||||
ui.admin.applications.url.label=URL
|
||||
ui.admin.applications.title.label=Title
|
||||
ui.admin.applications.desc.label=Description
|
||||
ui.admin.applications.url.validation.url_already_in_use=The provided URL is already in use
|
||||
ui.admin.applications.url.validation.no_slash_allowed=The URL fragement may not contain slashes
|
||||
ui.admin.applications.ApplicationInstancePane.title.label=Title of the instance
|
||||
ui.admin.applications.ApplicationInstancePane.parent_app.label=Parent application
|
||||
ui.admin.cancel=Cancel
|
||||
ui.admin.cancel_msg=Submission cancelled
|
||||
#ID ist null
|
||||
ui.admin.groups.ID_is_null=ID is null
|
||||
ui.admin.user.userpasswordform.retrieving_user_failed=Failed to retrieve user
|
||||
ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
ui.admin.dispatcher.accessDenied=Acc\u00e8s refus\u00e9
|
||||
ui.admin.dispatcher.contextTitle=Index
|
||||
ui.admin.dispatcher.groupsLabel=Groupes
|
||||
ui.admin.dispatcher.title=Administration
|
||||
ui.admin.dispatcher.usersLabel=Utilisateurs
|
||||
ui.admin.groups.actioncontinue=Continuer
|
||||
ui.admin.groups.groupdeletefailed=Impossible de supprimer le groupe
|
||||
ui.admin.groups.add=Ajouter un sous-groupe
|
||||
ui.admin.groups.addeditform.namelabel=Nom:
|
||||
ui.admin.groups.addeditform.primaryemaillabel=e-mail principal:
|
||||
ui.admin.groups.addeditform.submit=Enregistrer
|
||||
ui.admin.groups.addgrouplabel=Ajouter un nouveau group
|
||||
ui.admin.groups.addsubmemberlabel=Ajouter un membre
|
||||
ui.admin.groups.delete=Effacer un groupe
|
||||
ui.admin.groups.deletefailed=Message d'erreur
|
||||
ui.admin.groups.edit=Modifier
|
||||
ui.admin.groups.groupedit=Modifier le groupe
|
||||
ui.admin.groups.extremeaction=Action dangereuse
|
||||
ui.admin.groups.groupinformation=Information de base
|
||||
ui.admin.groups.removesubmemberlabel=Retirer
|
||||
ui.admin.groups.subgroupcountlabel=Sous-groupes:
|
||||
ui.admin.groups.subgroups=Information sur le sous-groupe
|
||||
ui.admin.groups.submembers=Information sur le membre
|
||||
ui.admin.nav.logout=D\u00e9connexion
|
||||
ui.admin.nav.workspace=Espace de travail
|
||||
ui.admin.searchAndList.submit=Rechercher
|
||||
ui.admin.searchAndList.submitAgain=Rechercher suivant
|
||||
ui.admin.tab.group=Groupe
|
||||
ui.admin.tab.user.browse=Parcourir
|
||||
ui.admin.tab.user.createuser=Cr\u00e9er un nouvel utilisateur
|
||||
ui.admin.tab.user.navbartitle=Gestion de l'utilisateur
|
||||
ui.admin.tab.user.search=Rechercher
|
||||
ui.admin.tab.user.summary=Table des mati\u00e8res
|
||||
ui.admin.tab.user=Utilisateurs
|
||||
ui.admin.user.action.continue=Continuer
|
||||
ui.admin.user.action.delete.failed.header=Impossible de supprimer l'utiisateur
|
||||
ui.admin.user.action.header=Actions
|
||||
ui.admin.user.addeditform.additionalemail=Adresse e-mail secondaire:
|
||||
ui.admin.user.addeditform.additionalemaillist=Autre e-mail
|
||||
ui.admin.user.addeditform.answer=R\u00e9ponse:
|
||||
ui.admin.user.addeditform.confirmation=Confirmation du mot de passe:
|
||||
ui.admin.user.addeditform.deleteemail=Supprimer
|
||||
ui.admin.user.addeditform.error.answer.null=Ce param\u00e8tre est obligatoire.
|
||||
ui.admin.user.addeditform.error.answer.whitespace=La r\u00e9ponse doit \u00eatre vide ou ne pas contenir d'espace
|
||||
ui.admin.user.addeditform.error.password.notmatch=Les mots de passe sont diff\u00e9rents
|
||||
ui.admin.user.addeditform.error.primaryemail.notunique=L'e-mail principal n'est pas unique
|
||||
ui.admin.user.addeditform.error.screenname.notunique=Screen name n'est pas unique
|
||||
ui.admin.user.addeditform.firstname=Pr\u00e9nom:
|
||||
ui.admin.user.addeditform.lastname=Nom:
|
||||
ui.admin.user.addeditform.password=Mot de passe:
|
||||
ui.admin.user.addeditform.primaryemail=e-mail principal:
|
||||
ui.admin.user.addeditform.question=Question:
|
||||
ui.admin.user.addeditform.screenname=Screen Name:
|
||||
ui.admin.user.addeditform.submit=Enregistrer
|
||||
ui.admin.user.addeditform.url=URL:
|
||||
ui.admin.user.browselink=Montrer tout
|
||||
ui.admin.user.browsepanel.becomeUser=Devenir cet utilisateur
|
||||
ui.admin.user.browsepanel.extremeaction=Action dangereuse
|
||||
ui.admin.user.browsepanel.header=Tous les utilisateurs enregistr\u00e9s
|
||||
ui.admin.user.browsepanel.updatePassword=Mettre \u00e0 jour le mot de passe
|
||||
ui.admin.user.createpanel.header=Cr\u00e9er un nouvel utilisateur
|
||||
ui.admin.user.delete.confirm=Etes vous s\u00fbr de vouloir supprimer cet utilisateur?
|
||||
ui.admin.user.delete.failed.label=La suppression de l'utilisateur a \u00e9chou\u00e9
|
||||
ui.admin.user.delete.label=Supprimer cet utilisateur
|
||||
ui.admin.user.editlink=Modifier
|
||||
ui.admin.user.groupmembership.header=Groupe(s) d'appartenance
|
||||
ui.admin.user.password.header=Mise \u00e0 jour des informations de s\u00e9curit\u00e9
|
||||
ui.admin.user.search.header=Rechercher
|
||||
ui.admin.user.summarypanel.createUser=Cr\u00e9er un nouvel utilisateur
|
||||
ui.admin.user.summarypanel.header=Table des mati\u00e8res
|
||||
ui.admin.user.summarypanel.totalusers=Total des utilisateurs:
|
||||
ui.admin.user.useredit.header=Modifier les informations de l'utilisateur
|
||||
ui.admin.user.userinfo.header=Informations de l'utilisateur
|
||||
ui.admin.user.userpasswordform.answer=R\u00e9ponse:<br>(<font size "-1">Ne pas remplir pour conserver la r\u00e9ponse actuelle</font>)
|
||||
ui.admin.user.userpasswordform.confirmpasswordlabel=Confirmer le mot de passe:
|
||||
ui.admin.user.userpasswordform.passwordlabel=Mot de passe:
|
||||
ui.admin.user.userpasswordform.question=Question:
|
||||
ui.admin.user.userpasswordform.submit=Changer
|
||||
ui.admin.tab.applications=
|
||||
ui.admin.applications.tree.heading=
|
||||
ui.admin.applications.url.validation.not_blank=The URL of an application instance can is mandatory.
|
||||
ui.admin.applications.url.valiation.minmaxlength=The length of an URL of an application instance must be between 1 and 100 characters.
|
||||
ui.admin.applications.title.validation.not_blank=Title is mandatory for an application instance.
|
||||
ui.admin.applications.title.valiation.minmaxlength=The minimum length of the title of an applicatio instance is one character, the maximum length are 200 characters
|
||||
ui.admin.applications.desc.valiation.minmaxlength=The maximum length of a descrption of an application instance are 4000 characters.
|
||||
ui.admin.applications.url.label=URL
|
||||
ui.admin.applications.title.label=Title
|
||||
ui.admin.applications.desc.label=Description
|
||||
ui.admin.applications.url.validation.url_already_in_use=DescriptionThe provided URL is already in use
|
||||
ui.admin.applications.url.validation.no_slash_allowed=The URL fragement may not contain slashes
|
||||
ui.admin.applications.ApplicationInstancePane.title.label=Title of the instance
|
||||
ui.admin.applications.ApplicationInstancePane.parent_app.label=Parent application
|
||||
ui.admin.cancel=Cancel
|
||||
ui.admin.cancel_msg=Submission cancelled
|
||||
ui.admin.groups.ID_is_null=
|
||||
ui.admin.user.userpasswordform.retrieving_user_failed=Impossible de retrouver l'utilisateur
|
||||
ui.admin.groups.couldnt_find_specified_group=Impossible de trouver le groupe sp\u00e9cifi\u00e9
|
||||
Loading…
Reference in New Issue